File Coverage

blib/lib/Email/Folder/Exchange/WebDAV.pm
Criterion Covered Total %
statement 21 125 16.8
branch 0 28 0.0
condition 0 25 0.0
subroutine 7 20 35.0
pod 6 7 85.7
total 34 205 16.5


line stmt bran cond sub pod time code
1             package Email::Folder::Exchange::WebDAV;
2 2     2   11 use strict;
  2         4  
  2         105  
3              
4             # vim: ft=perl fdm=marker ts=4 sw=4
5              
6             our $VERSION = '1.10';
7              
8 2     2   10 use base qw(Email::Folder);
  2         4  
  2         164  
9 2     2   9 use Email::Folder;
  2         10  
  2         40  
10 2     2   2331 use URI;
  2         25376  
  2         78  
11 2     2   28 use URI::Escape;
  2         5  
  2         255  
12 2     2   3206 use LWP::UserAgent;
  2         118847  
  2         78  
13              
14 2     2   23 use Carp qw(carp croak);
  2         3  
  2         2709  
15              
16             sub _ua { # {{{
17 0     0     my ($self, $ua) = @_;
18 0 0         $self->{_ua} = $ua if @_ == 2;
19 0           return $self->{_ua};
20             } # }}}
21              
22             sub uri { # {{{
23 0     0 1   my ($self, $uri) = @_;
24 0 0         $self->{uri} = $uri if @_ == 2;
25 0           return $self->{uri};
26             } # }}}
27              
28             sub _login { # {{{
29 0     0     my ($self, $uri, $username, $password) = @_;
30 0           my $scheme = $uri->scheme;
31 0           my $host = $uri->host;
32 0           my $ua = $self->_ua;
33              
34             # login using FBA (forms-based authentication)
35 0           my $auth_uri = $uri->clone;
36 0           $auth_uri->path('exchweb/bin/auth/owaauth.dll');
37 0           my $login_req = HTTP::Request->new(
38             POST => $auth_uri->as_string,
39             );
40 0           $login_req->content_type('application/x-www-form-urlencoded');
41 0           $login_req->content(
42             'destination=' . uri_escape($uri->as_string) .
43             '&username=' . uri_escape($username) .
44             '&password=' . uri_escape($password)
45             );
46              
47 0           my $login_res = $ua->request($login_req);
48 0 0 0       croak $login_res->message if $login_res->code >= 400 and $login_res->code < 500;
49              
50 0           return 1;
51             } # }}}
52              
53             sub new { # {{{
54 0     0 1   my ($self, $class, $url, $username, $password) = ({}, @_);
55 0           bless $self, $class;
56              
57 0 0         croak "URI required" unless $url;
58              
59             # create user agent
60 0           my $ua = LWP::UserAgent->new( keep_alive => 1, cookie_jar => {} );
61 0           $self->_ua($ua);
62              
63             # create uri object
64 0           my $uri = URI->new($url);
65 0           $self->uri($uri);
66              
67             # guess path
68 0 0 0       if(! $uri->path || $uri->path =~ m{^/$}) {
69 0           my $path_user = $username;
70 0           $path_user =~ s/.*\\//;
71              
72 0           $uri->path("/exchange/$path_user/Inbox");
73             }
74              
75              
76             # get credentials from url if specified
77 0           my $credentials = $uri->userinfo;
78 0           $uri->userinfo(undef);
79              
80 0 0 0       if($credentials && !($username || $password)) {
      0        
81 0           ($username, $password) = split(/:/, uri_unescape($credentials), 2);
82             }
83 0 0         croak "Credentials required" unless $username;
84              
85 0           $self->_login($uri, $username, $password);
86            
87 0           return $self;
88             } # }}}
89              
90             sub _message_urls { # {{{
91 0     0     my ($self) = @_;
92 0 0         return $self->{_message_urls} if $self->{_message_urls};
93              
94 0           my $req = HTTP::Request->new(
95             SEARCH => $self->uri->as_string,
96             );
97 0           $req->content_type('text/xml');
98 0           $req->header(Depth => 1);
99              
100              
101 0           my $folder_path = $self->uri->path;
102 0           $req->content(qq{
103            
104            
105             SELECT "DAV:ishidden"
106             FROM scope('shallow traversal of "$folder_path"')
107             WHERE "DAV:ishidden"=False AND "DAV:isfolder"=False
108            
109             });
110              
111 0           my $ua = $self->_ua;
112              
113 0           my @message_urls;
114 0           my $buf = "";
115              
116             my $res = $ua->request($req, sub {
117 0     0     my $chunk = shift;
118 0           $buf .= $chunk;
119              
120 0           while($buf =~ m#(.*?)#g) {
121 0           push @message_urls, $1;
122              
123             }
124 0   0       $buf = substr($buf, (pos $buf || 0));
125 0           });
126 0 0 0       croak $res->message unless $res->code >= 200 and $res->code < 300;
127              
128 0           $self->{_message_urls} = \@message_urls;
129              
130 0           return $self->{_message_urls};
131             } # }}}
132              
133             sub messages { # {{{
134 0     0 1   my $self = shift;
135              
136 0           my @messages;
137 0           while(my $message = $self->next_message) {
138 0           push @messages, $message;
139             }
140              
141 0           return @messages;
142             } # }}}
143            
144             sub next_message { # {{{
145 0     0 1   my $self = shift;
146 0           my $message_url = shift @{ $self->_message_urls };
  0            
147 0 0         return undef unless defined $message_url;
148              
149 0           my $req = HTTP::Request->new( GET => $message_url );
150 0           $req->header(Translate => 'f');
151 0           my $res = $self->_ua->request($req);
152 0 0 0       croak $res->message unless $res->code >= 200 and $res->code < 300;
153              
154 0           return $self->bless_message($res->content);
155             } # }}}
156              
157             sub _folder_urls { # {{{
158 0     0     my ($self) = @_;
159 0 0         return $self->{_folder_urls} if $self->{_folder_urls};
160              
161 0           my $req = HTTP::Request->new(
162             SEARCH => $self->uri->as_string,
163             );
164 0           $req->content_type('text/xml');
165 0           $req->header(Depth => 1);
166              
167 0           my $folder_path = $self->uri->path;
168 0           $req->content(qq{
169            
170            
171             SELECT "DAV:ishidden"
172             FROM scope('shallow traversal of "$folder_path"')
173             WHERE "DAV:ishidden"=False AND "DAV:isfolder"=True
174            
175             });
176              
177 0           my $ua = $self->_ua;
178              
179 0           my @folder_urls;
180 0           my $buf = "";
181              
182             my $res = $ua->request($req, sub {
183 0     0     my $chunk = shift;
184 0           $buf .= $chunk;
185              
186 0           while($buf =~ m#(.*?)#g) {
187 0           push @folder_urls, $1;
188              
189             }
190              
191 0   0       $buf = substr($buf, (pos $buf || 0));
192 0           });
193 0 0 0       croak $res->message unless $res->code >= 200 and $res->code < 300;
194              
195 0           $self->{_folder_urls} = \@folder_urls;
196              
197 0           return $self->{_folder_urls};
198             } # }}}
199              
200             sub folders { # {{{
201 0     0 1   my $self = shift;
202              
203 0           my @folders;
204 0           while(my $folder = $self->next_folder) {
205 0           push @folders, $folder;
206             }
207              
208 0           return @folders;
209             } # }}}
210              
211             sub next_folder { # {{{
212 0     0 1   my $self = shift;
213              
214 0           my $folder_url = shift @{ $self->_folder_urls };
  0            
215 0 0         return unless defined $folder_url;
216              
217 0           my $folder = $self->clone;
218 0           $folder->uri(URI->new($folder_url));
219              
220 0           return $folder;
221             } # }}}
222              
223             sub clone { # {{{
224 0     0 0   my $self = shift;
225              
226 0           my $clone = bless {
227             uri => $self->uri->clone,
228             _ua => $self->_ua->clone,
229             }, ref $self;
230              
231             # copy cookie jar
232 0           $clone->_ua->{cookie_jar} = $self->_ua->{cookie_jar};
233              
234 0           return $clone;
235             } # }}}
236              
237             1;
238             __END__