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