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