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