File Coverage

blib/lib/WebService/weblogUpdates.pm
Criterion Covered Total %
statement 90 217 41.4
branch 23 98 23.4
condition 2 30 6.6
subroutine 21 31 67.7
pod 6 7 85.7
total 142 383 37.0


line stmt bran cond sub pod time code
1             {
2              
3             =head1 NAME
4              
5             WebService::weblogUpdates - methods supported by the UserLand weblogUpdates framework.
6              
7             =head1 SUMMARY
8              
9             use WebService::weblogUpdates;
10              
11             my $weblogs = WebService::weblogUpdates->new(transport=>"SOAP",debug=>0);
12             $weblogs->ping("Perlblog","http://www.nospum.net/perlblog");
13              
14             # Since the 'rssUpdate' method has only been
15             # documented for the XML-RPC transport, we switch
16             # the internal widget.
17              
18             $weblogs->Transport("XMLRPC");
19             $weblogs->rssUpdate("Aaronland","http://www.aaronland.net/weblog/rss");
20              
21             =head1 DESCRIPTION
22              
23             This package implements methods supported by the UserLand weblogUpdates framework,
24             for the weblogs.com website.
25              
26             =head1 ON NAMING THINGS
27              
28             This package was originally named to reflect the class that the original I
29             method lives in, weblogUpdates.
30              
31             Since then, other methods have been added that live in different classes or don't
32             have any parent class at all. I have no idea why, especially since the equivalent
33             serTalk methods live in a 'weblogUpdates' class themselves. [1]
34              
35             So it goes.
36              
37             =cut
38              
39 1     1   98297 use strict;
  1         3  
  1         57  
40             package WebService::weblogUpdates;
41              
42             $WebService::weblogUpdates::VERSION = '0.35';
43              
44 1     1   6 use Carp;
  1         3  
  1         85  
45              
46 1     1   6 use constant HOST => "http://rpc.weblogs.com";
  1         2  
  1         65  
47 1     1   14 use constant RSSHOST => "http://rssrpc.weblogs.com";
  1         2  
  1         48  
48              
49 1     1   5 use constant PATH => "/RPC2";
  1         2  
  1         60  
50 1     1   6 use constant CLASS => "weblogUpdates";
  1         12  
  1         99  
51              
52 1     1   6 use constant PING => "ping";
  1         2  
  1         49  
53 1     1   6 use constant RSSUPDATE => "rssUpdate";
  1         1  
  1         2662  
54              
55             =head1 PACKAGE METHODS
56              
57             =head2 $pkg = __PACKAGE__->new(%args)
58              
59             Valid arguments are
60              
61             =over 4
62              
63             =item *
64              
65             B
66              
67             String. Valid transports are SOAP and XMLRPC and REST. I
68              
69             =item *
70              
71             B
72              
73             Boolean. Enable transport-specific debugging.
74              
75             =back
76              
77             =cut
78              
79             sub new {
80 1     1 1 663 my $pkg = shift;
81            
82 1         2 my $self = {};
83 1         2 bless $self;
84              
85 1 50       4 $self->init(@_) || return undef;
86 1         2 return $self;
87             }
88              
89             sub init {
90 1     1 0 2 my $self = shift;
91 1         4 my $args = { @_ };
92              
93 1 50       5 if (! $args->{'transport'}) {
94 0         0 carp "You must specify a transport.";
95 0         0 return 0;
96             }
97              
98 1 50       4 $self->Transport($args->{'transport'},debug=>$args->{'debug'})
99             || return 0;
100              
101 1         4 return 1;
102             }
103              
104             =head1 OBJECT METHODS
105              
106             =head2 $pkg->ping(\%args)
107              
108             Ping the Userland servers and tell them your weblog has been updated.
109              
110             Valid arguments are a hash reference whose keys are :
111              
112             =over 4
113              
114             =item *
115              
116             B
117              
118             String. The name of your weblog. I
119              
120             =item *
121              
122             B
123              
124             String. The URI of your weblog. I
125              
126             =item *
127              
128             B
129              
130             String.
131              
132             This key may be specified if
133              
134             =over 4
135              
136             =item *
137              
138             The object's transport is REST and the site in question "need two urls, one that we can verify changes for, and the other to be included in changes.xml."
139              
140             =item *
141              
142             You are passing a I key with your ping. In fact, it's required if you're doing that.
143              
144             =back
145              
146             =item *
147              
148             B
149              
150             String.
151              
152             Categories are not supported if the object's transport is REST.
153              
154             =back
155              
156             Returns true or false. This means that, unlike the Userland server itself, a successful ping returns 1 and a failed ping returns 0.
157              
158             =cut
159              
160             sub ping {
161 2     2 1 1247 my $self = shift;
162 2         5 my $args = shift;
163              
164 2         5 delete $self->{'_message'};
165              
166             #
167              
168 2 50 33     13 if ((! $args->{name}) || (! $args->{url})) {
169 0         0 carp "You must specify both a weblog name and url";
170 0         0 return 0;
171             }
172              
173 2         4 my $meth = undef;
174 2         3 my @args = ();
175              
176 2 50       19 if ($self->{'__ima'} eq "Frontier::Client") {
    50          
    50          
    50          
177              
178 0         0 $meth = join(".",CLASS,PING);
179 0         0 @args = (
180             $self->_client()->string($args->{name}),
181             $self->_client()->string($args->{url}),
182             );
183            
184             #
185            
186 0 0 0     0 if (($args->{changesurl}) && ($args->{category})) {
187 0         0 push (@args,
188             $self->_client()->string($args->{changesurl}),
189             $self->_client()->string($args->{category}));
190             }
191             }
192            
193             elsif ($self->{'__ima'} eq "XMLRPC::Lite") {
194 0         0 $meth = join(".",CLASS,PING);
195 0         0 @args = (
196             SOAP::Data->type(string=>$args->{name}),
197             SOAP::Data->type(string=>$args->{url}),
198             );
199              
200 0 0 0     0 if (($args->{changesurl}) && ($args->{category})) {
201 0         0 push (@args,
202             SOAP::Data->type(string=>$args->{changesurl}),
203             SOAP::Data->name(string=>$args->{category}));
204             }
205              
206             }
207              
208             elsif ($self->{'__ima'} eq "SOAP::Lite") {
209 0         0 $meth = PING;
210 0         0 @args = (
211             SOAP::Data->name(weblogname=>$args->{name}),
212             SOAP::Data->name(weblogurl=>$args->{url}),
213             );
214              
215 0 0 0     0 if (($args->{changesurl}) && ($args->{category})) {
216 0         0 push (@args,
217             SOAP::Data->name(changesurl=>$args->{changesurl}),
218             SOAP::Data->name(categoryname=>$args->{category}));
219             }
220              
221             }
222              
223             elsif ($self->{'__ima'} eq "LWP::Simple") {
224 2         4 $meth = PING;
225 2         4 @args = ($args);
226             }
227              
228 2 50       6 if (! $meth) {
229 0         0 carp "Unable to determine transport and method.";
230 0         0 return 0;
231             }
232              
233             my $res = $self->_do($meth,@args)
234 2   33     6 || &{ carp "Returned undef. Not good."; return 0; };
235              
236 2         10948 $self->{'_message'} = $res->{message};
237 2 50       27 (! $res->{'flerror'}) ? return 1 : return 0;
238             }
239              
240             =head2 $pkg->rssUpdate(\%args)
241              
242             Ping the Userland servers and tell them your RSS feed has been updated.
243              
244             Valid arguments are a hash reference whose keys are :
245              
246             =over 4
247              
248             =item *
249              
250             B
251              
252             String. The name of your weblog. I
253              
254             =item *
255              
256             B
257              
258             String. The URI of your weblog. I
259              
260             =back
261              
262             This method is B supported for the SOAP transport, although
263             it will be as soon as it is documented by UserLand.
264              
265             This method is B supported for the REST transport.
266              
267             =cut
268              
269             sub rssUpdate {
270 0     0 1 0 my $self = shift;
271 0         0 my $args = shift;
272              
273 0         0 delete $self->{'_message'};
274              
275             #
276            
277 0 0 0     0 if ((! $args->{name}) || (! $args->{url})) {
278 0         0 carp "You must specify both a weblog name and url";
279 0         0 return 0;
280             }
281            
282 0         0 my $meth = undef;
283 0         0 my @args = ();
284            
285 0 0       0 if ($self->{'__ima'} eq "Frontier::Client") {
    0          
    0          
    0          
286              
287             # grrrrr....
288 0         0 $self->_client()->{'url'} = RSSHOST.PATH;
289 0         0 $self->_client()->{'rq'}->url(RSSHOST.PATH);
290              
291 0         0 $meth = join(".",RSSUPDATE);
292 0         0 @args = (
293             $self->_client()->string($args->{name}),
294             $self->_client()->string($args->{url}),
295             );
296             }
297            
298             elsif ($self->{'__ima'} eq "XMLRPC::Lite") {
299              
300 0         0 $self->_client()->proxy(RSSHOST.PATH);
301 0         0 $meth = join(".",RSSUPDATE);
302 0         0 @args = (
303             SOAP::Data->type(string=>$args->{name}),
304             SOAP::Data->type(string=>$args->{url}),
305             );
306             }
307            
308             elsif ($self->{'__ima'} eq "SOAP::Lite") {
309 0         0 carp "This method will be supported as soon as it is documented by UserLand.\n";
310 0         0 return 0;
311             # $meth = RSSUPDATE;
312             # @args = (
313             # SOAP::Data->name(weblogname=>$args->{name}),
314             # SOAP::Data->name(weblogurl=>$args->{url}),
315             # );
316             }
317            
318             elsif ($self->{'__ima'} eq "LWP::Simple") {
319 0         0 carp "This method is not supported for the REST transport.\n";
320 0         0 return 0;
321             }
322            
323 0 0       0 if (! $meth) {
324 0         0 carp "Unable to determine transport and method.";
325 0         0 return 0;
326             }
327            
328             my $res = $self->_do($meth,@args)
329 0   0     0 || &{ carp "Returned undef. Not good."; return 0; };
330            
331 0         0 $self->{'_message'} = $res->{message};
332 0 0       0 (! $res->{'flerror'}) ? return 1 : return 0;
333             }
334              
335             =head2 $pkg->LastMessage()
336              
337             Return the response message that was sent with your last method call.
338              
339             =cut
340              
341             sub LastMessage {
342 1     1 1 3 my $self = shift;
343 1 50       8 (exists($self->{'_message'})) ? return $self->{'_message'} : return undef;
344             }
345              
346             =head2 $pkg->Transport($transport,%args)
347              
348             Set the transport for use with the package. Valid transports are SOAP, XMLRPC and REST. This field is required.
349              
350             Valid arguments are
351              
352             =over 4
353              
354             =item *
355              
356             B
357              
358             Boolean. Enable transport-specific debugging.
359              
360             =back
361              
362             =cut
363              
364             sub Transport {
365 4     4 1 8 my $self = shift;
366 4         6 my $transport = shift;
367 4         6 my $args = { @_ };
368            
369 4 100       12 if (defined $transport) {
370            
371 1 50       10 if (! $transport =~ /^(xmlrpc|soap|rest)$/i) {
372 0         0 delete $self->{"_transport"};
373 0         0 return undef;
374             }
375            
376 1         7 $self->{"_transport"} = lc $transport;
377            
378 1 50       4 if (! $self->_client(debug=>$args->{'debug'})) {
379 0         0 delete $self->{"_transport"};
380 0         0 return undef;
381             }
382             }
383            
384 4         17 return $self->{"_transport"};
385             }
386              
387             =head1 DEPRECATED METHODS
388              
389             =head2 $pkg->ping_message()
390              
391             B Please use $pkg->LastMessage() instead.
392              
393             =cut
394              
395             sub ping_message {
396 0     0 1 0 my $self = shift;
397 0         0 return $self->LastMessage();
398             }
399              
400             # Private methods
401              
402             sub _do {
403 2     2   4 my $self = shift;
404 2         4 my $meth = shift;
405 2         4 my @args = @_;
406              
407 2 50       22 if ($self->{'__ima'} eq "Frontier::Client") {
    50          
    50          
408 0         0 my $res = undef;
409              
410 0         0 eval { $res = $self->_client()->call($meth,@args); };
  0         0  
411              
412 0 0       0 if ($@) {
413 0         0 carp $@;
414 0         0 return 0;
415             }
416            
417             # Hack.
418 0 0       0 if ($res->{'flerror'}) {
419 0         0 $res->{'flerror'} = $res->{'flerror'}->value();
420             }
421              
422 0         0 return $res;
423             }
424              
425             # We don't bother wrapping this in an eval block
426             # since we've already set a fault method for the
427             # SOAP::Lite object.
428              
429             elsif ($self->{'__ima'} =~ /^(SOAP|XMLRPC)::Lite$/){
430 0         0 return $self->_client()->call($meth,@args)->result();
431             }
432              
433             elsif ($self->{'__ima'} eq "LWP::Simple") {
434 2         6 return $self->_client()->call($meth,@args);
435             }
436              
437             else {
438 0         0 return {flerror=>1,message=>"unknown transport"};
439             }
440             }
441              
442             sub _client {
443 3     3   6 my $self = shift;
444 3         13 my $client = "_".$self->Transport();
445 3         60 return $self->$client(@_);
446             }
447              
448             sub _xmlrpc {
449 0     0   0 my $self = shift;
450 0         0 my $args = { @_ };
451            
452 0 0       0 if (! $self->{"_xmlrpc"}) {
453            
454 0 0       0 if (&_require("Frontier::Client")) {
    0          
455             $self->{"_xmlrpc"} = Frontier::Client->new(url=>HOST.PATH,debug=>$args->{'debug'})
456 0   0     0 || &{ carp $!; return 0; };
457             }
458            
459             elsif (&_require("XMLRPC::Lite")) {
460             my $xmlrpc = XMLRPC::Lite->new()
461 0   0     0 || &{ carp $!; return 0; };
462              
463 0         0 &_setup_soaplite($xmlrpc,$args);
464              
465             #
466              
467 0         0 $xmlrpc->proxy(HOST.PATH);
468 0         0 $self->{"_xmlrpc"} = $xmlrpc;
469             }
470            
471             else {
472 0         0 return 0;
473             }
474              
475 0         0 $self->{'__ima'} = ref($self->{"_xmlrpc"});
476             }
477              
478 0         0 return $self->{"_xmlrpc"};
479             }
480              
481             sub _soap {
482 0     0   0 my $self = shift;
483 0         0 my $args = { @_ };
484            
485 0 0       0 if (! $self->{"_soap"}) {
486            
487 0         0 my $class = "SOAP::Lite";
488 0 0       0 &_require($class) || return 0;
489            
490 0 0       0 if ($SOAP::Lite::VERSION < 0.55) {
491 0         0 carp
492             "SOAP::Lite version is $SOAP::Lite::VERSION\n".
493             "Please upgrade to version 0.55 or higher.\n";
494             }
495            
496             carp
497             my $soap = $class->new() ||
498 0   0     0 &{ carp $!; return 0; };
499            
500 0         0 &_setup_soaplite($soap,$args);
501            
502             #
503            
504 0         0 $soap->proxy(join("/",HOST,CLASS));
505            
506             $soap->on_action(
507             sub{
508 0     0   0 "\"/".CLASS."\""
509             }
510 0         0 );
511            
512 0         0 $self->{"_soap"} = $soap;
513 0         0 $self->{'__ima'} = ref($self->{"_soap"});
514             }
515            
516 0         0 return $self->{"_soap"};
517             }
518              
519             sub _setup_soaplite {
520 0     0   0 my $lite = shift;
521 0         0 my $args = shift;
522              
523             # What if it doesn't work?
524             $lite->on_fault(
525             sub{
526 0     0   0 my ($lite,$res) = @_;
527 0 0       0 carp (ref $res) ? $res->faultstring : $lite->transport->status();
528 0         0 return 0;
529             }
530 0         0 );
531            
532             # Who's on first?
533 0 0       0 if ($args->{'debug'}) {
534 0     0   0 $lite->on_debug(sub { print @_; });
  0         0  
535             }
536             }
537              
538             sub _rest {
539 3     3   5 my $self = shift;
540 3         5 my $class = "LWP::Simple";
541 3 50       8 &_require($class) || return 0;
542              
543 3         8 $self->{'__ima'} = $class;
544 3         27 return "REST";
545             }
546              
547             sub _require {
548 3     3   5 my $class = shift;
549            
550 0         0 eval "require $class" ||
551 3 50       233 &{ carp $@; return 0; };
  0         0  
552            
553 3         13 return 1;
554             }
555              
556             sub DESTROY {
557 1     1   2199 return 1;
558             }
559              
560             package REST;
561 1     1   7 use constant PINGSITEFORM => "http://newhome.weblogs.com/pingSiteForm";
  1         1  
  1         57  
562 1     1   6 use constant PINGSITEFORMTWOURLS => "http://newhome.weblogs.com/pingSiteFormTwoUrls";
  1         2  
  1         588  
563              
564             my $html_parser = undef;
565              
566             sub call {
567 2     2   4 my $pkg = shift;
568 2         2 my $meth = shift;
569 2         4 my $args = shift;
570              
571 2         3 my $ping = undef;
572              
573 2 100       8 if ($args->{changesurl}) {
574 1         8 $ping = PINGSITEFORMTWOURLS."?name=$args->{name}&url=$args->{url}&changesUrl=$args->{changesurl}";
575             }
576              
577             else {
578 1         4 $ping = PINGSITEFORM."?name=$args->{name}&url=$args->{url}";
579             }
580              
581             #
582              
583 2         11 my $html = LWP::Simple::get($ping);
584              
585 2 50       123671 if (! $html) {
586 2         13 return {flerror=>1,message=>"Failed to ping: ".LWP::Simple::getprint($ping)};
587             }
588              
589             #
590              
591 0           eval "require HTML::Parser";
592              
593 0 0         if ($@) {
594 0           return {flerror=>0,message=>"Failed to parse HTML, $@"};
595             }
596              
597             #
598              
599 0 0         if (! $html_parser) {
600 0           $html_parser = HTML::Parser->new(
601             start_h => [\&start_element, "self,tagname, attr"],
602             text_h => [\&characters, "self,text"],
603             );
604 0           $html_parser->unbroken_text(1);
605             }
606              
607 0           $html_parser->parse($html);
608              
609 0           return {flerror=>0,message=>$html_parser->{__message}};
610             }
611              
612             #
613              
614             sub start_element {
615 0     0     my $parser = shift;
616 0           my $tag = shift;
617              
618 0 0         if ($tag eq "html") {
619 0           $parser->{'__ok'} = 0;
620 0           $parser->{'__message'} = undef;
621             }
622             }
623              
624             sub characters {
625 0     0     my $parser = shift;
626 0           my $chars = shift;
627              
628 0 0         return if (! $chars);
629              
630 0           $chars =~ s/^\s+//;
631 0           $chars =~ s/\s+$//;
632 0 0         return if (! $chars);
633              
634             # Ugh.
635              
636 0 0         if ($chars eq "Enter the name and URL of a weblog that has been updated.") {
637 0           $parser->{'__ok'} = 1;
638 0           return;
639             }
640              
641             # Double ugh.
642              
643 0 0         if ($chars =~ /^Name:/) {
644 0           $parser->{'__ok'} = 0;
645             }
646              
647 0 0         if ($parser->{'__ok'}) {
648 0           $chars =~ s/ / /gm;
649 0           $parser->{__message} .= " $chars";
650             }
651              
652 0           return 1;
653             }
654              
655             =head1 VERSION
656              
657             0.35
658              
659             =head1 DATE
660              
661             October 31, 2002
662              
663             =head1 SEE ALSO
664              
665             http://www.weblogs.com
666              
667             http://www.xmlrpc.com/weblogsComForRss
668              
669             http://www.xmlrpc.com/discuss/msgReader$2014?mode=day
670              
671             =head1 FOOTNOTES
672              
673             [1] http://www.xmlrpc.com/weblogsComForRss#changes103002ByDw
674              
675             =head1 REQUIREMENTS
676              
677             These packages are required in order to support the following transports :
678              
679             =head2 XMLRPC
680              
681             One of the following :
682              
683             =over 4
684              
685             =item *
686              
687             B
688              
689             Default
690              
691             =item *
692              
693             B
694              
695             (part of SOAP::Lite)
696              
697             =back
698              
699             =head2 SOAP
700              
701             =over 4
702              
703             =item *
704              
705             B
706              
707             =back
708              
709             =head2 REST
710              
711             =over 4
712              
713             =item *
714              
715             B
716              
717             =item *
718              
719             B
720              
721             This is optional, but required if you want this package to try and return a short and sweet message instead of raw HTML.
722              
723             =back
724              
725             =head1 LICENSE
726              
727             Copyright (c) 2001-2002, Aaron Straup Cope. All Rights Reserved.
728              
729             This is free software, you may use it and distribute it under the same terms as Perl itself.
730              
731             =cut
732              
733             return 1;
734              
735             }