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