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