3
RSS 0.91, 0.92, and 2.0
9
cc rss.c stdsoap2.c soapC.c
11
Usage: rss [maxitems] URL
12
Prints RSS content in text format.
15
Installed as CGI application prints Javascript code to view RSS feeds in Web
16
pages. The Javascript code produced by this application is executed with the
17
following example script embedded in the Web page, e.g. to display BBC news:
19
<script src="http://www.cs.fsu.edu/~engelen/rss.cgi/?rss=http%3A%2F%2Fwww.bbc.co.uk%2Fsyndication%2Ffeeds%2Fnews%2Fukfs_news%2Ffront_page%2Frss091.xml&max=10"></script>
20
<noscript><a href="http://www.cs.fsu.edu/~engelen/rss.cgi/?rss=http%3A%2F%2Fwww.bbc.co.uk%2Fsyndication%2Ffeeds%2Fnews%2Fukfs_news%2Ffront_page%2Frss091.xml&max=10">View BBC News | Front Page | UK Edition</a></noscript>
22
To control the appearance with cascading style sheets:
23
rss_box the bounding div for the entire display
24
rss_table the table with title, image, and items
25
rss_title the title of the feed and link style if displayed
27
rss_bar the dividing bar
28
rss_item the title of the item
29
rss_desc the description of the item
31
--------------------------------------------------------------------------------
32
gSOAP XML Web services tools
33
Copyright (C) 2001-2004, Robert van Engelen, Genivia, Inc. All Rights Reserved.
34
This software is released under one of the following two licenses:
35
GPL or Genivia's license for commercial use.
36
--------------------------------------------------------------------------------
39
This program is free software; you can redistribute it and/or modify it under
40
the terms of the GNU General Public License as published by the Free Software
41
Foundation; either version 2 of the License, or (at your option) any later
44
This program is distributed in the hope that it will be useful, but WITHOUT ANY
45
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
46
PARTICULAR PURPOSE. See the GNU General Public License for more details.
48
You should have received a copy of the GNU General Public License along with
49
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
50
Place, Suite 330, Boston, MA 02111-1307 USA
52
Author contact information:
53
engelen@genivia.com / engelen@acm.org
54
--------------------------------------------------------------------------------
55
A commercial use license is available from Genivia, Inc., contact@genivia.com
56
--------------------------------------------------------------------------------
61
#define STR(s) ((s)?(s):"")
63
/* Maximum number of HTTP redirects */
64
#define MAX_REDIRECTS 10
66
static void docwrite0(struct soap *soap, const char *s);
67
static void docwrite1(struct soap *soap, const char *s1, const char *s2, const char *s3);
68
static void docwrite2(struct soap *soap, const char *s1, const char *s2, const char *s3, const char *s4, const char *s5);
69
static void docerror(struct soap *soap, const char *s);
70
static void strwrite(struct soap *soop, const char *s);
71
static char *query_key(char *buf, size_t len, char **s);
72
static char *query_val(char *buf, size_t len, char **s);
74
int main(int argc, char **argv)
75
{ struct soap *soap = soap_new1(SOAP_C_UTFSTRING); /* preserve UTF8 string content */
76
const char *endpoint = NULL;
78
int maxitems = 10; /* max items to show */
79
int show_date = 1; /* show date yes/no */
81
/* RSS has no encoding style */
82
soap->encodingStyle = NULL;
83
/* get URL of RSS feed or run as CGI app */
85
{ maxitems = atoi(argv[1]);
91
{ char *query = getenv("QUERY_STRING"); /* CGI app: get query string */
96
{ len = strlen(query);
97
keybuf = (char*)soap_malloc(soap, len + 1);
98
valbuf = (char*)soap_malloc(soap, len + 1);
100
{ char *key = query_key(keybuf, len, &query); /* decode next query string key */
101
char *val = query_val(valbuf, len, &query); /* decode next query string value (if any) */
102
/* get endpoint and max number of items to display */
104
{ if (!strcmp(key, "rss"))
105
endpoint = soap_strdup(soap, val);
106
else if (!strcmp(key, "max"))
107
maxitems = atoi(val);
108
else if (!strcmp(key, "date"))
109
show_date = (*val == 'y');
114
{ docerror(soap, "No RSS URL");
118
/* connect and parse HTTP header (max HTTP redirects) */
119
for (i = 0; i < MAX_REDIRECTS; i++)
120
{ /* HTTP GET and parse HTTP header */
121
if (soap_connect_command(soap, SOAP_GET, endpoint, NULL)
122
|| soap_begin_recv(soap))
123
{ if ((soap->error >= 301 && soap->error <= 303) || soap->error == 307)
124
endpoint = soap_strdup(soap, soap->endpoint); /* HTTP redirects */
126
{ soap_print_fault(soap, stderr);
134
rss = soap_get_rss(soap, NULL, "rss", NULL);
135
/* close connection */
137
soap_closesock(soap);
139
{ /* CGI application: produce Javascript */
140
if (rss && (!strcmp(rss->version, "0.91") || !strcmp(rss->version, "0.92") || !strcmp(rss->version, "2.0")))
141
{ soap_begin_send(soap);
142
soap->http_content = "application/javascript";
143
soap_response(soap, SOAP_FILE); /* SOAP_FILE specifies http_content should be used */
144
docwrite0(soap, "<div class='rss_box' align='center'>");
145
docwrite0(soap, "<table cellpadding='2' width='100%' class='rss_table'>");
146
if (rss->channel.title)
147
{ if (rss->channel.link)
148
docwrite2(soap, "<tr><th class='rss_title'><a href='", rss->channel.link, "' target='_blank'>", rss->channel.title, "</a></th></tr>");
150
docwrite1(soap, "<tr><th class='rss_title'>", rss->channel.title, "</th></tr>");
152
if (rss->channel.image && rss->channel.image->url)
153
{ struct image *image = rss->channel.image;
155
docwrite2(soap, "<tr><th class='rss_image'><a href='", image->link, "' target='_blank'><img src='", image->url, "' alt='Channel Image' border='0'/></a></th></tr>");
156
else if (rss->channel.link)
157
docwrite2(soap, "<tr><th class='rss_image'><a href='", rss->channel.link, "' target='_blank'><img src='", image->url, "' alt='Channel Image' border='0'/></a></th></tr>");
159
docwrite1(soap, "<tr><th class='rss_image'><img src='", image->url, "' alt='Channel Image' border='0'</th></tr>");
160
if (!rss->channel.title && image->title)
161
docwrite1(soap, "<tr><td class='rss_title'>", image->title, "</td></tr>");
162
if (!rss->channel.description && image->description)
163
docwrite1(soap, "<tr><td class='rss_desc'>", image->description, "</td></tr>");
165
if (rss->channel.description)
166
docwrite1(soap, "<tr><th class='rss_desc'>", rss->channel.description, "</th></tr>");
167
if (rss->channel.copyright)
168
docwrite1(soap, "<tr><td class='rss_desc'>", rss->channel.copyright, "</td></tr>");
169
if (rss->channel.__size < maxitems)
170
maxitems = rss->channel.__size;
171
for (i = 0; i < maxitems; i++)
172
{ struct item *item = &rss->channel.item[i];
173
docwrite0(soap, "<tr><td class='rss_bar' bgcolor='#bbbbbb'></td></tr>");
176
docwrite2(soap, "<tr><td class='rss_item' bgcolor='#dddddd'><a href='", item->link, "' target='_blank'>", item->title, "</a></td></tr>");
178
docwrite1(soap, "<tr><td class='rss_item' bgcolor='#dddddd'>", item->title, "</td></tr>");
179
if (show_date && item->pubDate)
180
docwrite1(soap, "<tr><td class='rss_date' bgcolor='#dddddd'>Posted on ", item->pubDate, "</td></tr>");
181
else if (show_date && item->dc__date)
182
docwrite1(soap, "<tr><td class='rss_date' bgcolor='#dddddd'>Posted on ", ctime(item->dc__date), "</td></tr>");
183
if (item->description)
184
docwrite1(soap, "<tr><td class='rss_desc' bgcolor='#eeeeee'>", item->description, "</td></tr>");
187
docwrite0(soap, "</table>");
188
docwrite0(soap, "</div>");
192
{ docerror(soap, "No RSS 0.91, 0.92, or 2.0 data");
197
{ /* Interactive: produce text output */
198
if (!strcmp(rss->version, "0.91") || !strcmp(rss->version, "0.92") || !strcmp(rss->version, "2.0"))
199
{ printf("Title: %s\n", STR(rss->channel.title));
200
printf("Link: %s\n", STR(rss->channel.link));
201
printf("Language: %s\n", STR(rss->channel.language));
202
printf("Description: %s\n", STR(rss->channel.description));
203
if (rss->channel.image)
204
{ printf("Image title: %s\n", STR(rss->channel.image->title));
205
printf("Image url: %s\n", STR(rss->channel.image->url));
206
printf("Image link: %s\n", STR(rss->channel.image->link));
207
printf("Image dimensions: %d x %d\n", rss->channel.image->width, rss->channel.image->height);
208
printf("Image description: %s\n", STR(rss->channel.image->description));
210
if (rss->channel.__size < maxitems)
211
maxitems = rss->channel.__size;
212
for (i = 0; i < maxitems; i++)
213
{ printf("\n%3d Title: %s\n", i+1, STR(rss->channel.item[i].title));
214
printf(" Link: %s\n", STR(rss->channel.item[i].link));
215
printf(" Description: %s\n", STR(rss->channel.item[i].description));
216
if (rss->channel.item[i].pubDate)
217
printf(" Posted: %s\n", rss->channel.item[i].pubDate);
218
else if (rss->channel.item[i].dc__date)
219
printf(" Posted: %s\n", ctime(rss->channel.item[i].dc__date));
221
printf("\nCopyright: %s\n", STR(rss->channel.copyright));
224
fprintf(stderr, "RSS 0.91, 0.92, or 2.0 content expected\n");
227
soap_print_fault(soap, stderr);
234
static void docwrite0(struct soap *soap, const char *s)
235
{ soap_send3(soap, "document.write(\"", s, "\");\n");
238
static void docwrite1(struct soap *soap, const char *s1, const char *s2, const char *s3)
239
{ soap_send2(soap, "document.write(\"", s1);
241
soap_send2(soap, s3, "\");\n");
244
static void docwrite2(struct soap *soap, const char *s1, const char *s2, const char *s3, const char *s4, const char *s5)
245
{ soap_send2(soap, "document.write(\"", s1);
249
soap_send2(soap, s5, "\");\n");
252
static void docerror(struct soap *soap, const char *s)
253
{ soap_begin_send(soap);
254
soap->http_content = "application/javascript";
255
soap_response(soap, SOAP_FILE);
260
static void strwrite(struct soap *soap, const char *s)
264
if (*t == '\\' || *t == '"' || *t == '\n')
266
soap_send_raw(soap, s, t - s);
268
{ soap_send(soap, "\\\\");
272
{ soap_send(soap, "\\\"");
278
{ soap_send(soap, "<p/>"); /* two line breaks? Probably a new paragraph was intended */
282
soap_send(soap, " ");
288
static const char *decode_url(char *buf, size_t len, const char *val)
293
for (s = val; *s; s++)
294
if (*s != ' ' && *s != '=')
299
while (*s && *s != '"' && --len)
303
while (*s && *s != '&' && *s != '=');
307
while (*s && *s != '&' && *s != '=' && --len)
315
*t++ = ((s[1] >= 'A' ? (s[1]&0x7) + 9 : s[1] - '0') << 4) + (s[2] >= 'A' ? (s[2]&0x7) + 9 : s[2] - '0');
329
static char *query_key(char *buf, size_t len, char **s)
332
{ *s = (char*)decode_url(buf, len, t);
338
static char *query_val(char *buf, size_t len, char **s)
341
{ *s = (char*)decode_url(buf, len, t);
347
/* RSS 0.91 doesn't use namespaces, but RSS 2.0 does, which means that soap->namespace=NULL when serializing RSS 0.91 feeds */
348
struct Namespace namespaces[] = {
349
{ "dc", "http://purl.org/dc/elements/1.1/" },