1c250a91321f6e0894920d8488b9f721ea6cbe5b
[citadel.git] / webcit / rss.c
1 /*
2  * $Id$
3  *
4  * Generate some RSS for our rooms.
5  */
6
7 #include "webcit.h"
8 #include "webserver.h"
9
10 void display_rss(const char *roomname)
11 {
12         int nummsgs;
13         int a, b;
14         int bq = 0;
15         time_t now = 0L;
16         struct tm now_tm;
17         iconv_t ic = (iconv_t)(-1) ;
18         char *ibuf;                   /* Buffer of characters to be converted */
19         char *obuf;                   /* Buffer for converted characters      */
20         size_t ibuflen;               /* Length of input buffer               */
21         size_t obuflen;               /* Length of output buffer              */
22         char *osav;                   /* Saved pointer to output buffer       */
23         char buf[SIZ];
24         char date[30];
25         char from[256];
26         char subj[256];
27         char node[256];
28         char hnod[256];
29         char room[256];
30         char rfca[256];
31         char rcpt[256];
32         char msgn[256];
33         char content_type[256];
34         char charset[256];
35
36         lprintf(3, "Running RSS reader\n");
37         if (!WC->logged_in) {
38                 authorization_required();
39                 return;
40         }
41
42         lprintf(3, "Going to a room %s\n", roomname);
43         if (gotoroom(roomname)) {
44                 wprintf("HTTP/1.0 404 Not Found\r\n");
45                 wprintf("Content-Type: text/html\r\n");
46                 wprintf("\r\n");
47                 wprintf("Error retrieving RSS feed: couldn't find room or messages\n");
48                 return;
49         }
50
51         lprintf(3, "Loading up all the messages\n");
52         nummsgs = load_msg_ptrs("MSGS LAST|50", 0);
53         if (nummsgs == 0) {
54                 wprintf("HTTP/1.0 404 Not Found\r\n");
55                 wprintf("Content-Type: text/html\r\n");
56                 wprintf("\r\n");
57                 wprintf("Error retrieving RSS feed: couldn't find room or messages\n");
58                 return;
59         }
60
61         lprintf(3, "Getting date of the last one\n");
62         /* Read time of last message immediately */
63         serv_printf("MSG4 %ld", WC->msgarr[nummsgs - 1]);
64         serv_getln(buf, sizeof buf);
65         if (buf[0] == '1') {
66                 while (serv_getln(buf, sizeof buf), strcasecmp(buf, "000")) {
67                         if (!strncasecmp(buf, "time=", 5)) {
68                                 now = atol(&buf[5]);
69                                 gmtime_r(&now, &now_tm);
70                                 strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", &now_tm);
71                         }
72                 }
73         }
74
75         /* Do RSS header */
76         output_headers(0, 0, 0, 0, 0, 0, 0);
77         wprintf("Content-Type: application/rss+xml\r\n");
78         wprintf("\r\n");
79         wprintf("<?xml version=\"1.0\"?>\n");
80         wprintf("<rss version=\"2.0\">\n");
81         wprintf("   <channel>\n");
82         wprintf("   <title>%s - %s</title>\n", WC->wc_roomname, serv_info.serv_humannode);
83         wprintf("   <description>");
84         /* Get room info for description */
85         serv_puts("RINF");
86         serv_getln(buf, sizeof buf);
87         if (buf[0] == '1') {
88                 while (1) {
89                         serv_getln(buf, sizeof buf);
90                         if (!strcmp(buf, "000"))
91                                 break;
92                         wprintf("%s", buf);
93                 }
94         }
95         wprintf("</description>\n");
96         if (now) {
97                 wprintf("   <pubDate>%s</pubDate>\n", buf);
98         }
99         wprintf("   <generator>%s</generator>\n", SERVER);
100         wprintf("   <docs>http://blogs.law.harvard.edu/tech/rss</docs>\n");
101         wprintf("   <ttl>30</ttl>\n");
102
103         /* Read all messages and output as RSS items */
104         for (a = 0; a < nummsgs; ++a) {
105                 lprintf(3, "Sending message %d of %d\n", a+1, nummsgs);
106                 /* Read message and output each as RSS item */
107                 serv_printf("MSG4 %ld", WC->msgarr[a]);
108                 serv_getln(buf, sizeof buf);
109                 if (buf[0] != '1') continue;
110
111                 now = 0L;
112                 strcpy(subj, "");
113                 strcpy(hnod, "");
114                 strcpy(node, "");
115                 strcpy(room, "");
116                 strcpy(rfca, "");
117                 strcpy(rcpt, "");
118                 strcpy(msgn, "");
119
120                 while (serv_getln(buf, sizeof buf), strcasecmp(buf, "text")) {
121                         if (!strcmp(buf, "000")) {
122                                 lprintf(3, "ENDITEM 1\n");
123                                 goto ENDITEM;   /* screw it */
124                         } else if (!strncasecmp(buf, "from=", 5)) {
125                                 strcpy(from, &buf[5]);
126 #ifdef HAVE_ICONV
127                                 utf8ify_rfc822_string(from);
128 #endif
129                         } else if (!strncasecmp(buf, "subj=", 5)) {
130                                 strcpy(subj, &buf[5]);
131 #ifdef HAVE_ICONV
132                                 utf8ify_rfc822_string(subj);
133 #endif
134                         } else if (!strncasecmp(buf, "hnod=", 5)) {
135                                 strcpy(node, &buf[5]);
136                         } else if (!strncasecmp(buf, "room=", 5)) {
137                                 strcpy(room, &buf[5]);
138                         } else if (!strncasecmp(buf, "rfca=", 5)) {
139                                 strcpy(rfca, &buf[5]);
140                         } else if (!strncasecmp(buf, "rcpt=", 5)) {
141                                 strcpy(rcpt, &buf[5]);
142                         } else if (!strncasecmp(buf, "msgn=", 5)) {
143                                 strcpy(msgn, &buf[5]);
144                         } else if (!strncasecmp(buf, "time=", 5)) {
145                                 now = atol(&buf[5]);
146                                 gmtime_r(&now, &now_tm);
147                                 strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", &now_tm);
148                         }
149                 }
150                 wprintf("   <item>\n");
151                 if (subj[0]) {
152                         wprintf("      <title>%s from", subj);
153                 } else {
154                         wprintf("      <title>From");
155                 }
156                 wprintf(" %s", from);
157                 wprintf(" in %s", room);
158                 if (strcmp(hnod, serv_info.serv_humannode) && strlen(hnod) > 0) {
159                         wprintf(" on %s", hnod);
160                 }
161                 wprintf("</title>\n");
162                 if (now) {
163                         wprintf("      <pubDate>%s</pubDate>\n", date);
164                 }
165                 wprintf("      <guid isPermaLink=\"false\">%s</guid>\n", msgn);
166                 /* Now the hard part, the message itself */
167                 strcpy(content_type, "text/plain");
168                 while (serv_getln(buf, sizeof buf), strlen(buf) > 0) {
169                         if (!strcmp(buf, "000")) {
170                                 lprintf(3, "ENDBODY 1\n");
171                                 goto ENDBODY;
172                         }
173                         if (!strncasecmp(buf, "Content-type: ", 14)) {
174                                 safestrncpy(content_type, &buf[14], sizeof content_type);
175                                 for (b = 0; b < strlen(content_type); ++b) {
176                                         if (!strncasecmp(&content_type[b], "charset=", 8)) {
177                                                 safestrncpy(charset, &content_type[b + 8], sizeof charset);
178                                         }
179                                 }
180                                 for (b = 0; b < strlen(content_type); ++b) {
181                                         if (content_type[b] == ';') {
182                                                 content_type[b] = 0;
183                                         }
184                                 }
185                         }
186                 }
187
188                 /* Set up a character set conversion if we need to */
189 #ifdef HAVE_ICONV
190                 if (strcasecmp(charset, "us-ascii") && strcasecmp(charset, "utf-8")) {
191                         ic = iconv_open("UTF-8", charset);
192                         if (ic == (iconv_t)(-1)) {
193                                 lprintf(5, "iconv_open() failed: %s\n", strerror(errno));
194                                 goto ENDBODY;
195                         }
196                 }
197 #endif
198
199                 /* Messages in legacy Citadel variformat get handled thusly... */
200                 if (!strcasecmp(content_type, "text/x-citadel-variformat")) {
201                         int intext = 0;
202
203                         wprintf("      <description><![CDATA[");
204                         while (1) {
205                                 serv_getln(buf, sizeof buf);
206                                 if (!strcmp(buf, "000")) {
207                                         if (bq == 1)
208                                                 wprintf("</blockquote>");
209                                         wprintf("\n");
210                                         break;
211                                 }
212                                 if (intext == 1 && isspace(buf[0])) {
213                                         wprintf("<br/>");
214                                 }
215                                 intext = 1;
216                                 if (bq == 0 && !strncmp(buf, " >", 2)) {
217                                         wprintf("<blockquote>");
218                                         bq = 1;
219                                 } else if (bq == 1 && strncmp(buf, " >", 2)) {
220                                         wprintf("</blockquote>");
221                                         bq = 0;
222                                 }
223                                 url(buf);
224                                 escputs(buf);
225                                 wprintf("\n");
226                         }
227                         wprintf("]]></description>\n");
228                 }
229                 /* Boring old 80-column fixed format text gets handled this way... */
230                 else if (!strcasecmp(content_type, "text/plain")) {
231                         wprintf("      <description><![CDATA[");
232                         while (serv_getln(buf, sizeof buf), strcmp(buf, "000")) {
233                                 if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = 0;
234                                 if (buf[strlen(buf)-1] == '\r') buf[strlen(buf)-1] = 0;
235         
236 #ifdef HAVE_ICONV
237                                 if (ic != (iconv_t)(-1) ) {
238                                         ibuf = buf;
239                                         ibuflen = strlen(ibuf);
240                                         obuflen = SIZ;
241                                         obuf = (char *) malloc(obuflen);
242                                         osav = obuf;
243                                         iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
244                                         osav[SIZ-obuflen] = 0;
245                                         safestrncpy(buf, osav, sizeof buf);
246                                         free(osav);
247                                 }
248 #endif
249
250                                 while ((strlen(buf) > 0) && (isspace(buf[strlen(buf) - 1])))
251                                         buf[strlen(buf) - 1] = 0;
252                                 if ((bq == 0) &&
253                                 ((!strncmp(buf, ">", 1)) || (!strncmp(buf, " >", 2)) || (!strncmp(buf, " :-)", 4)))) {
254                                         wprintf("<blockquote>");
255                                         bq = 1;
256                                 } else if ((bq == 1) &&
257                                         (strncmp(buf, ">", 1)) && (strncmp(buf, " >", 2)) && (strncmp(buf, " :-)", 4))) {
258                                         wprintf("</blockquote>");
259                                         bq = 0;
260                                 }
261                                 wprintf("<tt>");
262                                 url(buf);
263                                 escputs(buf);
264                                 wprintf("</tt><br />\n");
265                         }
266                         wprintf("]]></description>\n");
267                 }
268                 /* HTML is fun, but we've got to strip it first */
269                 else if (!strcasecmp(content_type, "text/html")) {
270                         wprintf("      <description><![CDATA[");
271                         output_html(charset);
272                         wprintf("]]></description>\n");
273                 }
274
275 ENDBODY:
276                 wprintf("   </item>\n");
277 ENDITEM:
278                 lprintf(3, "Finished message %d of %d\n", a+1, nummsgs);
279                 now = 0L;
280         }
281
282         /* Do RSS footer */
283         wprintf("   </channel>\n");
284         wprintf("</rss>\n");
285         wDumpContent(0);
286 }