File Coverage

blib/lib/SharePoint/SOAPHandler.pm
Criterion Covered Total %
statement 16 18 88.8
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 22 24 91.6


line stmt bran cond sub pod time code
1             package SharePoint::SOAPHandler;
2              
3 1     1   41188 use 5.008000;
  1         6  
  1         42  
4 1     1   7 use strict;
  1         2  
  1         376  
5 1     1   8 use warnings;
  1         7  
  1         53  
6              
7             #our @ISA = qw(CopyTree::VendorProof);
8 1     1   6 use base qw(CopyTree::VendorProof);
  1         2  
  1         1651  
9 1     1   54478 use Authen::NTLM qw/ntlmv2/;ntlmv2('sp');
  1         91551  
  1         114  
10             #use base happens at compile time, so we don't get the runtime error from our, saying that
11             #Can't locate package CopyTree::VendorProof for @SharePoint::SOAPHandler::ISA at (eval 8) line 2.
12             our $VERSION = '0.0013';
13 1     1   466 use SOAP::Lite;
  0            
  0            
14             #use SOAP::Data; #included in SOAP::Lite
15             use LWP::UserAgent;
16             use LWP::Debug;
17             use Data::Dumper;
18             use MIME::Base64 ();
19             use Carp ();
20             use File::Basename ();
21              
22             # Preloaded methods go here.
23              
24             sub new{
25             my $class=shift;
26             my %args = @_; #not used, we set default args in bless, then offer option to reset
27             Carp::croak("Options to LWP::UserAgent should be key/value pairs, not hash reference")
28             if ref($_[1]) eq 'HASH';
29             #NOTE: you will get an error "Attempt to bless into a reference at lib/SharePoint/soaphandler.pm line 24" if you (accidentally) called a method that doesn't exist.
30             my $self = bless {
31             sp_creds_uaargs => [(keep_alive=>1)], #requires for NTLM
32             sp_creds_uaagent => 'Mozilla/5.0',
33            
34              
35             }, $class;
36             return $self;
37              
38             }
39              
40              
41             sub sp_creds_uaargs{
42             my $inst = shift;
43             if (@_){
44             #$inst->{'sp_creds_uaargs'}= [@_]; $inst; #mon aug 2
45             $inst->{'sp_creds_uaargs'}= shift; $inst;
46             }
47             else{@{$inst ->{'sp_creds_uaargs'}}}
48             }
49             sub sp_creds_domain{
50             my $inst = shift;
51             if (@_){
52             my $site = shift;
53             if ($site =~/%20/){
54             Carp::carp("Do not use %20 for spaces\n");
55             $site =~s/%20/ /g;
56             }
57             $inst->{'sp_creds_domain'}=$site; $inst;
58             }
59             else{$inst ->{'sp_creds_domain'}}
60              
61              
62             }
63             sub sp_creds_user{
64             my $inst = shift;
65             if (@_){
66             my $domuser = shift;
67             my ($dom, $user)=split /\\/, $domuser;
68             $dom = uc($dom);
69             $domuser = join('\\', $dom, $user);
70             $inst->{'sp_creds_user'}= $domuser; $inst;}
71             else{$inst ->{'sp_creds_user'}}
72             }
73             sub sp_creds_password{
74             my $inst = shift;
75             if (@_){ $inst->{'sp_creds_password'}= shift; $inst;}
76             else{$inst ->{'sp_creds_password'}}
77             }
78             #string, "Mozilla/5.0"
79             sub sp_creds_uaagent{
80             my $inst = shift;
81             if (@_){ $inst->{'sp_creds_uaagent'}= shift; $inst;}
82             else{$inst ->{'sp_creds_uaagent'}}
83             }
84              
85             sub sp_creds_credentials{
86             my $inst = shift;
87             if (@_){ $inst->{'sp_creds_credentials'}= [@_]; $inst;}
88             else{@{$inst ->{'sp_creds_credentials'}}}
89             }
90             #user agent object
91             sub sp_creds_schema_ua{
92             my $inst = shift;
93             if (@_){ $inst ->{'sp_creds_schema_ua'}=shift; $inst;}
94             else{$inst -> {'sp_creds_schema_ua'}}
95             }
96             #sp_authorized root is the root web address just above the Shared Documents link
97             #that the user cred is authorized to post
98             #e.g., https://sharepoint.shit.net/sitelevel/subsitelevel/collaboration
99             sub sp_authorizedroot{
100             my $inst = shift;
101             if (@_){
102             my $site = shift;
103             $site =~s/\/$//; #auto removes trailing slashes
104             if ($site =~/%20/){
105             Carp::carp("Do not use %20 for spaces\n");
106             $site =~s/%20/ /g;
107             }
108             $inst->{'sp_authorizedroot'}=$site; $inst;
109             }
110             else{$inst ->{'sp_authorizedroot'}}
111             }
112             sub slvti{
113             my $inst = shift;
114             if (@_){ $inst->{'slvti'}= shift; $inst;}
115             else{$inst ->{'slvti'}}
116             }
117             sub sluri{
118             my $inst = shift;
119             if (@_){$inst->{'sluri'}= shift;$inst;}
120             else{$inst ->{'sluri'}}
121             }
122             #sitedata lists dirs
123             sub slsitedataobj{
124             my $inst = shift;
125             if (@_){ $inst->{'slsitedataobj'}= shift;
126             $inst->{'slsitedataobj'}->on_action(sub{"$_[0]$_[1]"});
127             $inst;
128             }
129             else{$inst ->{'slsitedataobj'}}
130             }
131             sub slcopyobj{
132             my $inst = shift;
133             if (@_){ $inst->{'slcopyobj'}= shift;
134             $inst->{'slcopyobj'}->on_action(sub{"$_[0]$_[1]"});
135             $inst;
136             }
137             else{$inst ->{'slcopyobj'}}
138             }
139             #dws creates and deletes dirs
140             sub sldwsobj{
141             my $inst = shift;
142             if (@_){ $inst->{'sldwsobj'}= shift;
143             $inst->{'sldwsobj'}->on_action(sub{"$_[0]$_[1]"});
144             $inst;
145             }
146             else{$inst ->{'sldwsobj'}}
147             }
148             #list enables deleting of single files and listing list items, whatever that means for sharepoint
149             sub sllistobj{
150             my $inst = shift;
151             if (@_){ $inst->{'sllistobj'}= shift;
152             $inst->{'sllistobj'}->on_action(sub{"$_[0]$_[1]"});
153             $inst;
154             }
155             else{$inst ->{'sllistobj'}}
156             }
157              
158              
159             #if there are shell env variables to tell anything to go through a proxy server,
160             #this swtich says either to follow(0) or ignore(1) the proxy directions
161             sub sp_creds_proxy{
162             my $inst = shift;
163             if (@_){ $inst->{'sp_creds_proxy'}=[@_] ; $inst;}
164             else{@{$inst ->{'sp_creds_proxy'}}}
165             }
166             sub sp_creds_noproxy{
167             my $inst = shift;
168             if (@_){ $inst->{'sp_creds_noproxy'}= [@_]; $inst;}
169             else{@{$inst ->{'sp_creds_noproxy'}}}
170             }
171             #sp_connect requires two ua's, one for LWP and one for SOAP::Lite operations
172             sub sp_connect_lwp{
173             my $soap_inst = shift;
174             Carp::carp("sp_creds_uaargs not set\n") if (! $soap_inst->sp_creds_uaargs);
175             if (! $soap_inst->sp_creds_domain){
176             Carp::croak("sp_creds_domain not set\n");
177             }
178             elsif ($soap_inst->sp_creds_domain =~m/http/ or $soap_inst->sp_creds_domain =~m/\/\//){
179             Carp::croak("sp_creds_domain should not contain protocol\n".
180             "use 'sharepoint.site:443' instead of 'https://sharepoint.site:443'"
181             );
182             }
183             Carp::carp("sp_creds_user not set\n") if (! $soap_inst->sp_creds_user);
184             Carp::carp("sp_creds_password not set\n") if (! $soap_inst->sp_creds_password);
185             Carp::carp("sp_creds_uaagent not set\n") if (! $soap_inst->sp_creds_uaagent);
186             #skip this sub if LWP shema_ua is already set
187             if (ref $soap_inst ->sp_creds_schema_ua){
188             return $soap_inst;
189             }
190             $soap_inst ->sp_creds_credentials($soap_inst->sp_creds_domain, '', $soap_inst->sp_creds_user, $soap_inst->sp_creds_password);
191             my $sp_schema_ua = LWP::UserAgent->new($soap_inst->sp_creds_uaargs);
192             #LWP wants credentials in an array, not arrayref
193             $sp_schema_ua -> credentials($soap_inst->sp_creds_credentials);
194             $sp_schema_ua ->agent($soap_inst->sp_creds_uaagent);
195             #$sp_schema_ua ->proxy($soap_inst->sp_creds_proxy);
196             #$sp_schema_ua ->no_proxy($soap_inst->sp_creds_noproxy);
197             $soap_inst ->sp_creds_schema_ua($sp_schema_ua);
198              
199             return ($soap_inst);
200             }
201              
202              
203             sub sp_sitedataini{
204             my $soap_inst=shift;
205             return $soap_inst if (ref $soap_inst->slsitedataobj);
206             $soap_inst -> sp_connect_lwp;
207             $soap_inst->slvti($soap_inst->sp_authorizedroot()."/_vti_bin/SiteData.asmx");
208             #remember this uri requires a trailing slash
209             $soap_inst -> sluri("http://schemas.microsoft.com/sharepoint/soap/");
210             #Important. SOAP::Lite-> proxy wants arguments to be in list form; uaargs is the same format
211             #as LWP would prefer;
212             #credentials is NOT the same: LWP wants array; SOAP::Lite::porxy wants array ref
213              
214             $soap_inst -> slsitedataobj ( SOAP::Lite ->proxy ($soap_inst->slvti, $soap_inst ->sp_creds_uaargs, credentials =>[$soap_inst->sp_creds_credentials]) );
215              
216             $soap_inst -> slsitedataobj() -> schema->useragent($soap_inst->sp_creds_schema_ua);
217             #$soap_inst -> slsitedataobj() -> uri($s_uri);
218             $soap_inst -> slsitedataobj() -> uri($soap_inst->sluri);
219             return $soap_inst;#->slsitedataobj;
220             #@$slsitedataobj ->on_action(sub{qq/$_[0]$_[1]/});#now included in sub slsitedataobj
221             #################IMPORTANT#################
222              
223             #=head1 IMPORTANT: Microsoft soap doesn't use header info that SOAP::Lite requires
224             #
225             #i.e. SOAP::Lite uses default schemas.soap.come/#Function (uri#method), while MS uses
226             #shcemas.microsoft.com/soap/Function (urimethod)
227             #
228             #If this is not set properly, you will get soap errors. Took me 3 days printing Dumpers
229             #to everything to discover this stupid error
230             #
231             #This function is now included when setting the obj, i.e. sub slsitedataobj
232             #
233             #=cut
234              
235             }
236             sub carpenvproxy{
237             Carp::carp("_____________________________________________________________\nYou might get a 500 can't connect error (Bad service 'port/')\n\t if your sharepoint is on https, and you have\n\t a https_proxy env var set,\n\t but the sharepoint does NOT require a proxy to connect.\n\t to fix, remove your https_proxy env variable. (in perl, delete \$ENV{'https_proxy'})\n\t".
238             " bug from SOAP::Transport::HTTP, calls for SUPER::env_proxy from LWP::UserAgent, does\n\t".
239             " not know how to deal with https_proxy (no_proxy does not override https_proxy, only http_proxy\n");
240              
241             }
242            
243             sub fdls{
244             my $soap_inst = shift;
245             #my $sp_sitedataobj = shift;
246             Carp::croak("fdls item must be an instance, not a class\n") unless (ref $soap_inst);
247              
248             my $lsoption=shift; #'d', 'f', 'fdarrayrefs' or undef
249             $lsoption ='' if !($lsoption);
250             my $rootsearchfolder =shift;
251             $rootsearchfolder = $soap_inst ->SUPER::path if (!$rootsearchfolder); #'Shared Documents' or 'Shared Documents/something'
252             $rootsearchfolder=~s/\/$//;#removes trailing slashes, should be trouble
253              
254             $soap_inst ->sp_sitedataini if (!ref $soap_inst->slsitedataobj );
255             my $sp_sitedataobj= $soap_inst->slsitedataobj;
256             my $in_strfolderurl=SOAP::Data::name('strFolderUrl'=>$rootsearchfolder);
257             if ($ENV{'https_proxy'}){
258             $soap_inst ->carpenvproxy;
259             }
260             my $enufolderobj=$sp_sitedataobj->EnumerateFolder($in_strfolderurl);
261             #SHAREPOINT BUG STUPID: if only 1 item is returned, we get a hashref;
262             #if more than 1 item is returned, we get an array ref of hashrefs
263             #if no items returned, we get scalar undef
264             #REMEMBER: EnumerateFolder DOES NOT work on files - must test parent dir first
265             my $resultref = $enufolderobj -> body ->{'EnumerateFolderResponse'}{'vUrls'}{'_sFPUrl'};
266             if (ref $resultref eq 'HASH'){#fix stupid SHAREPOINT bug
267             $resultref = [$resultref];
268             }
269            
270             #Carp::carp("resultref is ". print Dumper $resultref);
271             delete $soap_inst->{'sp_sitedataenufolderret'};
272             $soap_inst->{'sp_sitedataenufolderret'}->{'dir'}=[];
273             $soap_inst->{'sp_sitedataenufolderret'}->{'file'}=[];
274             if ($resultref){ #$resultref is undef if no items returned
275             for my $item (@$resultref){
276             if ($item->{'IsFolder'} eq 'true'){
277             #print "[d] ".$item->{'Url'}."\n";# if ($item->{'IsFolder'} eq 'true'); #Url, IsFolder, LastModified
278             push @{$soap_inst->{'sp_sitedataenufolderret'}->{'dir'}}, $item ->{'Url'};
279             }
280             else {
281             #print "[f] ".$item->{'Url'}."\n";
282             push @{$soap_inst->{'sp_sitedataenufolderret'}->{'file'}}, $item ->{'Url'};
283             }
284             }#end for my $item
285             }
286             $soap_inst ->SUPER::fdls_ret ( $lsoption, \@{$soap_inst->{'sp_sitedataenufolderret'}->{'file'}}, \@{$soap_inst->{'sp_sitedataenufolderret'}->{'dir'}} );
287              
288             }
289              
290             sub sp_sitedatagetlistcol{
291             my $soap_inst = shift;
292             $soap_inst ->sp_sitedataini if (!ref $soap_inst->slsitedataobj );
293             my $sp_sitedataobj= $soap_inst->slsitedataobj;
294             if ($ENV{'https_proxy'}){
295             $soap_inst ->carpenvproxy;
296             }
297             my $getlistcolobj=$sp_sitedataobj->GetListCollection();
298            
299             my $resultref = $getlistcolobj -> body->{'GetListCollectionResponse'}{'vLists'}{'_sList'};
300             return $resultref;
301             #the return is an array ref of hash refs of keys and values
302              
303             }
304              
305             sub sp_copyini{
306             my $soap_inst=shift;
307             return $soap_inst if (ref $soap_inst->slcopyobj);
308             $soap_inst -> sp_connect_lwp;
309             $soap_inst->slvti($soap_inst->sp_authorizedroot()."/_vti_bin/Copy.asmx");
310             #remember this uri requires a trailing slash
311             $soap_inst -> sluri("http://schemas.microsoft.com/sharepoint/soap/");
312             #Important. SOAP::Lite-> proxy wants arguments to be in list form; uaargs is the same format
313             #as LWP would prefer;
314             #credentials is NOT the same: LWP wants array; SOAP::Lite::porxy wants array ref
315              
316             $soap_inst -> slcopyobj ( SOAP::Lite ->proxy ($soap_inst->slvti, $soap_inst ->sp_creds_uaargs, credentials =>[$soap_inst->sp_creds_credentials]) );
317              
318             $soap_inst -> slcopyobj() -> schema->useragent($soap_inst->sp_creds_schema_ua);
319             #$soap_inst -> slcopyobj() -> uri($s_uri);
320             $soap_inst -> slcopyobj() -> uri($soap_inst->sluri);
321             return $soap_inst;#->slcopyobj;
322             }
323             #memory is a ref to a scalar, in bin mode
324             sub read_into_memory{
325             my $soap_inst = shift;
326             my $sourcepath =shift; #return obj from sitedataenufolder, e.g., "Shared Documents/index.html"
327             $sourcepath=$soap_inst->SUPER::path if (!$sourcepath);
328              
329             $soap_inst->sp_copyini if (!ref $soap_inst->slcopyobj );
330             my $sp_copyobj= $soap_inst->slcopyobj;
331             if ($ENV{'https_proxy'}){
332             $soap_inst ->carpenvproxy;
333             }
334             my $in_strfileurl=SOAP::Data::name('Url'=>$soap_inst->sp_authorizedroot()."/".$sourcepath);
335             my $getcopy=$sp_copyobj->GetItem($in_strfileurl);
336              
337             my $result_bin=MIME::Base64::decode_base64( $getcopy -> body->{'GetItemResponse'}{'Stream'} );
338             Carp::carp("source file/dir on sharepoint [$sourcepath] does not exit (no stream) - ignoring this entry\n") if (! $result_bin);
339              
340             #IMPORTANT: GetItem returns NO ERROR on files that doesn't exist
341             return (\$result_bin); #I decided to not decode the file in case it's a binary.
342             #will rely on calling program to decode it to make data transfer safe
343             }
344              
345              
346             #memory is a ref to a scalar, in bin mode
347             sub write_from_memory{
348             my $soap_inst = shift;
349             my $binref =shift;
350             my $destinationurl = shift;# in this version, I will only support writeing to one single dest
351             #Shared Documents/something - do not use full path
352             $destinationurl = $soap_inst ->SUPER::path if (!$destinationurl);
353             my $sourceurl='local'; #doesn't do shit, but needs a value for it to work
354             my $fields=[];# = shift; #array ref of field items,
355             #my $stream = ; #array ref of single item byte stream, from slurping in binmode
356              
357             Carp::carp ("no destinationurl in write_from_memory \n") if (! $destinationurl);
358             Carp::carp ("no stream in write_from_memory \n") if (! $$binref);
359             $soap_inst->sp_copyini if (!ref $soap_inst->slcopyobj );
360             my $sp_copyobj= $soap_inst->slcopyobj;
361             if ($ENV{'https_proxy'}){
362             $soap_inst ->carpenvproxy;
363             }
364             my $in_sourceurl=SOAP::Data::name('SourceUrl'=>$sourceurl);
365             #construct full path
366             my $destinationurls = [$destinationurl];
367             for my $destfileurl(@$destinationurls){
368             $destfileurl = $soap_inst->sp_authorizedroot(). "/".$destfileurl;
369             $destfileurl = SOAP::Data::name ('string' => $destfileurl);
370             }
371             my $in_destinationurls=&soaparrayfmt("DestinationUrls", $destinationurls);
372             my $in_fields=&soaparrayfmt("Fields", $fields);
373             my $in_stream = SOAP::Data::name ('Stream' =>MIME::Base64::encode_base64($$binref));
374             my $copyresult = $sp_copyobj ->CopyIntoItems($in_sourceurl, $in_destinationurls, $in_fields, $in_stream);
375             return $copyresult->body; #returns the same msg if file exists vs copy success
376              
377              
378             }
379              
380              
381             sub copy_local_files{
382             my $soap_inst = shift;
383             my $sourceurl=shift;
384             my $destinationurl = shift;# SCALAR now, different from sp_copyremotefiles
385             #Shared Documents/something - do not use full path
386             Carp::carp ("no sourceurl in sp_copypostfile \(copy no source\)\n") if (! $sourceurl);
387             Carp::carp ("no destinationurls in sp_copypostfile \(copy no destination\)\n") if (! $destinationurl);
388             $soap_inst -> sp_copyini if (!ref $soap_inst->slcopyobj );
389             my $sp_copyobj= $soap_inst->slcopyobj;
390             if ($ENV{'https_proxy'}){
391             $soap_inst ->carpenvproxy;
392             }
393             my $in_sourceurl=SOAP::Data::name('SourceUrl'=>$soap_inst->sp_authorizedroot().'/'.$sourceurl);
394             #construct full path
395             my $destinationurls = [$destinationurl];
396             for my $destfileurl(@$destinationurls){
397             $destfileurl = $soap_inst->sp_authorizedroot(). "/".$destfileurl;
398             $destfileurl = SOAP::Data::name ('string' => $destfileurl);
399             }
400            
401             my $in_destinationurls=&soaparrayfmt("DestinationUrls", $destinationurls);
402             my $copyresult = $sp_copyobj ->CopyIntoItemsLocal($in_sourceurl, $in_destinationurls) ->body;
403             return $copyresult;
404              
405             }
406             #not really necessary functionally since write_from_memory and read_to_memory covers this,
407             #but it is more efficient since files are moved within sharepoint
408              
409              
410             sub soaparrayfmt {
411             my $arraytitle = shift;
412             my $arrayref = shift;
413             my $in_arraytitle =SOAP::Data::name($arraytitle =>\SOAP::Data::value(
414             SOAP::Data::name('anonymous' => @$arrayref)
415             )#end value
416             );#end name
417             return $in_arraytitle;
418             }
419              
420              
421             sub sp_dwsini{
422             my $soap_inst=shift;
423             return $soap_inst if (ref $soap_inst->sldwsobj);
424             $soap_inst -> sp_connect_lwp;
425             $soap_inst->slvti($soap_inst->sp_authorizedroot()."/_vti_bin/Dws.asmx");
426             ####dws is the only one where the uri is in a sub dir
427             #remember this uri requires a trailing slash
428             $soap_inst -> sluri("http://schemas.microsoft.com/sharepoint/soap/dws/");
429             #Important. SOAP::Lite-> proxy wants arguments to be in list form; uaargs is the same format
430             #as LWP would prefer;
431             #credentials is NOT the same: LWP wants array; SOAP::Lite::porxy wants array ref
432              
433             $soap_inst -> sldwsobj ( SOAP::Lite ->proxy ($soap_inst->slvti, $soap_inst ->sp_creds_uaargs, credentials =>[$soap_inst->sp_creds_credentials]) );
434              
435             $soap_inst -> sldwsobj() -> schema->useragent($soap_inst->sp_creds_schema_ua);
436             #$soap_inst -> sldwsobj() -> uri($s_uri);
437             $soap_inst -> sldwsobj() -> uri($soap_inst->sluri);
438             return $soap_inst;#->sldwsobj;
439              
440             }
441              
442             sub sp_dws{
443             my $soap_inst = shift;
444             my $dirtomk = shift;
445             my $action=shift;
446             $soap_inst->sp_dwsini if (!ref $soap_inst->sldwsobj );
447             my $sp_dwsobj= $soap_inst->sldwsobj;
448             if ($ENV{'https_proxy'}){
449             $soap_inst ->carpenvproxy;
450             }
451             #url starts with Shared Documents
452             my $in_url=SOAP::Data::name('url'=>$dirtomk);
453             my $dwsret;
454             if ($action eq 'mkdir'){
455             $dwsret = $sp_dwsobj ->CreateFolder($in_url)->body->{'CreateFolderResponse'}{'CreateFolderResult'};
456             #returns "AlreadyExists" if already exists, '' if success
457             }
458             elsif ($action eq 'rmdir'){
459             $dwsret = $sp_dwsobj ->DeleteFolder($in_url)->body->{'DeleteFolderResponse'}{'DeleteFolderResult'};
460             #returns '' if success or folder does not exist
461             }
462             return $dwsret;
463             }
464             sub sp_listini{
465             my $soap_inst=shift;
466             return $soap_inst if (ref $soap_inst->sllistobj);
467             $soap_inst -> sp_connect_lwp;
468             $soap_inst->slvti($soap_inst->sp_authorizedroot()."/_vti_bin/Lists.asmx");
469             ####list is the only one where the uri is in a sub dir
470             #remember this uri requires a trailing slash
471             $soap_inst -> sluri("http://schemas.microsoft.com/sharepoint/soap/");
472             #Important. SOAP::Lite-> proxy wants arguments to be in list form; uaargs is the same format
473             #as LWP would prefer;
474             #credentials is NOT the same: LWP wants array; SOAP::Lite::porxy wants array ref
475              
476             $soap_inst -> sllistobj ( SOAP::Lite ->proxy ($soap_inst->slvti, $soap_inst ->sp_creds_uaargs, credentials =>[$soap_inst->sp_creds_credentials]) );
477              
478             $soap_inst -> sllistobj() -> schema->useragent($soap_inst->sp_creds_schema_ua);
479             #$soap_inst -> sllistobj() -> uri($s_uri);
480             $soap_inst -> sllistobj() -> uri($soap_inst->sluri);
481             return $soap_inst;#->sllistobj;
482              
483             }
484             #returns "AlreadyExists" if already exists, '' if success
485             sub cust_mkdir {
486             my $soap_inst =shift;
487             my $dirtomk = shift;
488             if ($dirtomk eq '/' or $dirtomk eq 'Shared Documents'){
489             Carp::carp('should not be mkdiring a root');
490             }
491             else {
492             $soap_inst ->sp_dws($dirtomk, 'mkdir');
493             }
494              
495             }
496             #returns '' if success or folder does not exist
497             sub cust_rmdir{
498             my $soap_inst =shift;
499             my $dirtomk = shift;
500             if ($dirtomk eq '/' or $dirtomk eq 'Shared Documents'){
501             Carp::carp('should not be rmdiring a root');
502             }
503             elsif ($soap_inst ->is_fd($dirtomk) eq 'd'){
504             $soap_inst ->sp_dws($dirtomk, 'rmdir');
505             }
506             else {
507             Carp::croak("wait. you told me to delete something that's not a dir. I'll stop for your protection");
508             }
509             }
510             sub cust_rmfile{
511             my $soap_inst=shift;
512             my $filepath =shift;
513             Carp::croak ("cannot rmfile a non-file") if ($soap_inst->is_fd($filepath) ne 'f');
514             $soap_inst ->sp_listini if (! ref $soap_inst ->sllistobj);
515             my $sp_listobj = $soap_inst -> sllistobj;
516             if ($ENV{'https_proxy'}){
517             $soap_inst ->carpenvproxy;
518             }
519             #first, we need the shared documents list id to do the delete.
520             my $shareddoclistid =$soap_inst -> {'sllistid'}{'Shared Documents'} ;
521             if (!$shareddoclistid){
522             #the dataof function returns a series of blessed references. These series of refs are not put
523             #in an arrayref. Rather, they are just a series of blessed items. You can put it in @results,
524             #and each item will be a SOAP::Data instance. You CANNOT access these instances through @{blah->dataof('/blah') }
525             #the error msg will say Not an ARRAY reference
526             my @results = $sp_listobj ->GetListCollection() ->dataof('//GetListCollectionResult/Lists/List');
527             for my $data (@results){#{ $sp_listobj ->GetListCollection() ->dataof('//GetListCollectionResult/Lists/List') }){
528             if ($data->attr ->{'Title'} eq "Shared Documents"){
529             $shareddoclistid = $data ->attr ->{'ID'} ;
530             $soap_inst -> {'sllistid'}{'Shared Documents'}=$shareddoclistid;
531             }#end if
532             }#end for my $data
533             }#end if !shareddoclistid
534             my $in_str_listname = SOAP::Data::name('listName' => $shareddoclistid);
535             my $fullqualified = $soap_inst->sp_authorizedroot().'/'.$filepath;
536             my $xml = qq# 3 $fullqualified #;
537             my $in_str_xml_xml = SOAP::Data->type ('xml' =>qq# $xml#);
538             #basically, we want the xml to look like this: (spaces between update tags and $xml will crash the command)
539             #
540             #
541             # $shareddoclistid
542             # $xml
543             #
544             #
545             $sp_listobj ->UpdateListItems($in_str_listname, $in_str_xml_xml);
546              
547             }
548             sub is_fd{
549             my $soap_inst = shift;
550             my $query =shift;
551             if ($query =~m/\/$/){ #if query ends with slash 'someting/'
552             Carp::carp("sharepoint file/dir should not have trailing slashes\n");
553             return 0;
554             }
555             else {
556             my $queryparent = File::Basename::dirname($query);
557             #in sharepoint, you can't really query the root Shared Documents folder.
558             #to do it right, you're supposed to use getlistcollection. more resources -
559             #not doing it.
560             if ($queryparent eq '.'){ #result of no slashes in $query
561             if ($query eq 'Shared Documents'){
562             return 'd';
563             }
564             else {return 0}
565             }
566             my ($testfunderparent, $testdunderparent) = $soap_inst -> fdls('fdarrayrefs' , $queryparent);#only needs to return what's defined as file
567             #my @testparent = $soap_inst -> sp_ls($queryparent, 'f');#only needs to return what's defined as file
568             if ( @$testfunderparent + @$testdunderparent ==0){#$query can not be anything if it's parent is not a dir
569             # Carp::carp("query $query 's parent is not a valid folder..check your path[$query]\n");
570             return 0;
571             }#end if (! @testparent)
572             else{
573             my %trackmatchf;
574             for my $file (@$testfunderparent) {
575             $trackmatchf {$file} ++;
576             }
577             my %trackmatchd;
578             for my $dir (@$testdunderparent){
579             $trackmatchd{$dir} ++;
580             }
581              
582             if ($trackmatchf {$query}){
583             # Carp::carp("query $query is a file through searching parent\n");
584             return 'f';
585             }
586             elsif ($trackmatchd {$query}){
587             return 'd';
588             }
589             else {return 'pd'};
590             }#end else
591             } #end else main test
592              
593             }
594              
595              
596             1;
597             __END__