-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlinkpimpclient.pl
354 lines (270 loc) · 10.2 KB
/
linkpimpclient.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
#!/usr/bin/perl
use diagnostics;
use warnings;
use XML::RSS;
use XML::Simple;
use LWP::Simple;
use Frontier::Client;
use Frontier::RPC2;
use File::Copy;
use SOAP::Lite;
use LWP::UserAgent;
# User changable variables
my $logging = "1";
my $logfile = "logfile.txt";
my $pubsublog = "pubsub.txt";
my $includefile = "feeds.shtml";
my $tempincludefile = "feeds.shtml.tmp";
my $syndic8_userid = "XXXXXXXXXXXXXX";
my $syndic8_password = "XXXXX";
my $syndic8_list_id = "0";
my $syndic8_XMLRPC_path = "http://www.syndic8.com:80/xmlrpc.php";
my $pubsub_listening_procedure = "updatedFeed";
my $pubsub_port = "8889";
my $pubsub_path = "/RPC2";
my $pubsub_protocol = "xml-rpc";
my $content;
my $file;
my $line;
our $url;
our $retrieved_feed;
our $feed_spec;
#####################################################
logger("\n Program started. Let's go!\n");
# First we need to strim the pubsub records and remove all the old entries.
# Work out the time 25 hours ago (1 hour = 3600 seconds, so 25 hours = 90000 seconds)
my $oldestpossibletime = time() - 90000;
logger(
"The oldest allowable subscription cannot have been made earlier than $oldestpossibletime"
);
# Open the subscriber list created by pubSubListener and stick it in an array.
open( PUBSUBLIST, "<$pubsublog" );
my @lines = <PUBSUBLIST>;
close(PUBSUBLIST);
# Clear the subscriber list
unlink($pubsublog) or die "Can't delete the data file\n";
logger("Old Subscription list deleted");
# We need to prevent the file being empty, even if there are no subscriptions, so:
open( NEWPUBSUBLIST, ">$pubsublog" );
print NEWPUBSUBLIST
"This holds the details of all your subscriptions , 0000001\n";
# Go through each line, splitting it back into the right variables.
foreach $line (@lines) {
my ( $rssUrl, $time ) = split ( /,/, "$line" );
# If the time the notification request was made ($time) is later than 25 hours ago
# ($oldestpossibletime) then stick that line back into the data file.
if ( $time > $oldestpossibletime ) {
print NEWPUBSUBLIST "$line\n";
}
}
logger("New PubSublist written");
close(NEWPUBSUBLIST);
# Now, we reopen the pubsublog, and load it as a string for use later
open( PUBSUB, "$pubsublog" );
$/ = '';
my $content_of_pubsublog = <PUBSUB>;
# and we finally close the filehandle.
close(PUBSUB);
##########
# Use xmlrpc to ask for list of feeds from syndic8, and create object from result.
my $syndic8_xmlrpc_call = Frontier::Client->new(
url => $syndic8_XMLRPC_path,
debug => 0,
use_objects => 1
);
my $syndic8_xmlrpc_returned_subscriber_list = $syndic8_xmlrpc_call-> call(
'syndic8.GetSubscribed', $syndic8_userid,
$syndic8_password, $syndic8_list_id
)
or die "Cannot retrieve Syndic8 list";
logger("Retrieved Syndic8 subscription list");
# Place the dataurls from the subscriber list into an array
my @edited_subscribed_feeds_list =
map { $_->{dataurl} } @$syndic8_xmlrpc_returned_subscriber_list;
# Take the next line from the array of DataURLs
foreach $url (@edited_subscribed_feeds_list) {
logger("Now working with $url");
# Check the feed is not on the list of subscribed-to feeds
if ( $content_of_pubsublog =~ m/$url/i ) {
logger(
"Subscription already present, it seems. Excellent. I shall get on with the next one."
);
#We leave the main loop and move onto the next URL
}
else {
# Retrieve the RSS feed
$retrieved_feed = get($url);
logger("Retrieved Feed from $url");
# Examine for <cloud>
if ( $retrieved_feed =~ m/<cloud/ ) {
&subscribetorss092feed;
}
elsif ( $retrieved_feed =~ m/<cp:server/ ) {
&subscribetorss10feed;
}
else {
logger("There is no cloud element");
# Stick it through print_html, with an error trap here
eval { &print_html };
logger("The parsing choked on $url with this error\n $@ \n") if $@;
}
}
# Go to the next url in the list
}
### Replace the include file with the temporary one, and do it fast!
move( "$tempincludefile", "$includefile" );
### Clean up and exit the program
logger("We're all done here for now. Exiting Program.\n\n");
END;
######
## THE SUBROUTINES
######
sub subscribetorss092feed {
logger("We're not subscribed, so I shall attempt to subscribe to the $url");
# First we must parse the <cloud> element with $retrieved_feed This is in a set format:
# e.g <cloud domain="www.newsisfree.com" port="80" path="/RPC" registerProcedure="hpe.rssPleaseNotify" protocol="xml-rpc" />
# We'll do this with XML::Simple
my $parsed_xml = XMLin($retrieved_feed);
my $cloud_domain = $parsed_xml->{channel}->{cloud}->{domain};
my $cloud_port = $parsed_xml->{channel}->{cloud}->{port};
my $cloud_path = $parsed_xml->{channel}->{cloud}->{path};
my $cloud_registerProcedure =
$parsed_xml->{channel}->{cloud}->{registerProcedure};
my $cloud_protocol = $parsed_xml->{channel}->{cloud}->{protocol};
logger("We have retrieved the PubSub data from the RSS 0.92 feed.");
logger("The cloud domain is $cloud_domain");
logger("The port is $cloud_port");
logger("The path is $cloud_path");
logger("The port is $cloud_registerProcedure");
logger("The protocol is $cloud_protocol");
# The protocol is all important. We need to differentiate between SOAP users and those who like XML-RPC
if ( $cloud_protocol eq "xml-rpc" ) {
# Marvellous. That done, we spawn a new xml:rpc client
my $pubsub_call = Frontier::Client->new(
url => "http://$cloud_domain:$cloud_port$cloud_path",
debug => 0,
use_objects => 1
);
# Then call the remote procedure with the rss url, as per the spec
$pubsub_call->call( $cloud_registerProcedure,
$pubsub_listening_procedure, $pubsub_port, $pubsub_path,
$cloud_protocol, $url );
logger("I've asked for the subscription");
}
elsif ( $cloud_protocol eq "soap" ) {
# Initialise the SOAP interface
my $service =
SOAP::Lite->uri("http://$cloud_domain:$cloud_port$cloud_path");
# Run the search
my $result = $service->call(
$cloud_registerProcedure => (
$pubsub_listening_procedure, $pubsub_port,
$pubsub_path, $cloud_protocol,
$url
)
);
}
else {
logger("I can't work out what protocol this guy wants. ho hum");
return 1;
}
# Now add the url, and the time it was made to the pubsublog
open( PUBSUBLOG, ">>$pubsublog" );
my $time = time();
print PUBSUBLOG "$url , $time\n";
close PUBSUBLOG;
# That's it: return to the next one in the list.
}
#######
#######
sub subscribetorss10feed {
logger("We're not subscribed, so I shall attempt to subscribe to the $url");
#We need to work out which URL to send the request to.
my $request_url = $rss->{'channel'}->{'link'}->{'cp:server'};
logger("The Request URL is $request_url");
#We're going to use LWP::UserAgent for this
#So, we need to fire up a new UserAgent implementation
logger("Creating the UserAgent");
my $ua = LWP::UserAgent->new;
#and give it a nice name
$ua->agent( Personal Pubsub 1.0 );
#And then do the requesting,
#Remembering that we only need to pass the URL of the listener,
#and the URL of the feed we want to have running
$ua->request( POST $request_url,
[ responder => $responder, target => $url ] );
logger("Subscription request made");
}
######
######
sub logger {
if ( $logging eq "1" ) {
open( LOG, ">>$logfile" );
print LOG @_, "\n";
close LOG;
return 1;
}
else {
return 1;
}
}
######
######
sub includefile {
## In order to prevent a race condition, or duplicate feeds, we can't just append directly to the include file itself
## so we create a temporary include file, and then replace the real one with the temporary one right at the end of the program
open( INCLUDEFILE, ">>$tempincludefile" );
print INCLUDEFILE '<!--#include file="'
. $outputfile . '" -->' . "\n" . "<br/>" . "\n";
close INCLUDEFILE;
return 1;
}
#######
#######
sub print_html {
# Create new instance of XML::RSS
my $rss = new XML::RSS;
# Parse the $url and stick it in $rss
logger("Now trying to parse $url");
my $feed_to_parse = get($url);
$rss->parse($feed_to_parse);
# Decide on name for outputfile
our $outputfile = "$rss->{'channel'}->{'title'}.html";
$outputfile =~ s/ /_/g;
# Open the output file
logger("I'm going to call the output file $outputfile");
open( OUTPUTFILE, ">$outputfile" );
# Print the Channel Title
print OUTPUTFILE '<div class="channel_link">' . "\n" . '<a href="';
print OUTPUTFILE "$rss->{'channel'}->{'link'}";
print OUTPUTFILE '">';
print OUTPUTFILE "$rss->{'channel'}->{'title'}</a>\n</div>\n";
# Print channel image, checking first if it exists
if ( $rss->{'image'}->{'link'} ) {
print OUTPUTFILE '<div class="channel_image">' . "\n" . '<a href="';
print OUTPUTFILE "$rss->{'image'}->{'link'}";
print OUTPUTFILE '">' . "\n";
print OUTPUTFILE '<img src="';
print OUTPUTFILE "$rss->{'image'}->{'url'}";
print OUTPUTFILE '" alt="';
print OUTPUTFILE "$rss->{'image'}->{'title'}";
print OUTPUTFILE '"/>' . "\n</a>\n</div>";
print OUTPUTFILE "\n";
}
# Print the channel items
print OUTPUTFILE '<div class="linkentries">' . "\n" . "<ul>";
print OUTPUTFILE "\n";
foreach my $item ( @{ $rss->{'items'} } ) {
next unless defined( $item->{'title'} ) && defined( $item->{'link'} );
print OUTPUTFILE '<li><a href="';
print OUTPUTFILE "$item->{'link'}";
print OUTPUTFILE '">';
print OUTPUTFILE "$item->{'title'}</a></li>\n";
}
print OUTPUTFILE "</ul>\n</div>\n";
# Close the OUTPUTFILE
close(OUTPUTFILE);
logger("and lo $outputfile has been written.");
# Add to the include-file
includefile($outputfile);
}