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