5 * \defgroup RssRooms Generate some RSS for our rooms.
6 * \ingroup WebcitHttpServerRSS
10 #include "webserver.h"
13 time_t if_modified_since; /**< the last modified stamp */
16 * \brief view rss Config menu
17 * \param reply_to the original author
18 * \param subject the subject of the feed
20 void display_rss_control(char *reply_to, char *subject)
22 wprintf("<div style=\"align: right;\"><p>\n");
23 wprintf("<a href=\"display_enter?recp=");
26 if (strncasecmp(subject, "Re: ", 3)) wprintf("Re:%20");
28 wprintf("\">[%s]</a> \n", _("Reply"));
29 wprintf("<a href=\"display_enter?recp=");
31 wprintf("&force_room=_MAIL_&subject=");
32 if (strncasecmp(subject, "Re: ", 3)) wprintf("Re:%20");
34 wprintf("\">[%s]</a>\n", _("Email"));
35 wprintf("</p></div>\n");
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????
44 void display_rss(char *roomname, char *request_method)
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 */
69 char content_type[256];
73 authorization_required(_("Not logged in"));
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");
82 wprintf("Error retrieving RSS feed: couldn't find room\n");
86 nummsgs = load_msg_ptrs("MSGS LAST|15", 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");
92 wprintf(_("Error retrieving RSS feed: couldn't find messages\n"));
96 /** Read time of last message immediately */
97 serv_printf("MSG4 %ld", WC->msgarr[nummsgs - 1]);
98 serv_getln(buf, sizeof buf);
100 while (serv_getln(buf, sizeof buf), strcasecmp(buf, "000")) {
101 if (!strncasecmp(buf, "msgn=", 5)) {
102 strcpy(msgn, &buf[5]);
104 if (!strncasecmp(buf, "time=", 5)) {
106 gmtime_r(&now, &now_tm);
107 strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", &now_tm);
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);
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); */
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", PACKAGE_STRING);
132 wprintf("Connection: close\r\n");
134 if (!strcasecmp(request_method, "HEAD"))
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);
143 wprintf("</link>\n");
144 wprintf(" <description>");
145 /** Get room info for description */
147 serv_getln(buf, sizeof buf);
150 serv_getln(buf, sizeof buf);
151 if (!strcmp(buf, "000"))
153 wprintf("%s\n", buf);
156 wprintf("</description>\n");
158 wprintf(" <pubDate>%s</pubDate>\n", date);
160 wprintf(" <generator>%s</generator>\n", PACKAGE_STRING);
161 wprintf(" <docs>http://blogs.law.harvard.edu/tech/rss</docs>\n");
162 wprintf(" <ttl>30</ttl>\n");
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;
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 utf8ify_rfc822_string(from);
186 } else if (!strncasecmp(buf, "subj=", 5)) {
187 strcpy(subj, &buf[5]);
188 utf8ify_rfc822_string(subj);
189 } else if (!strncasecmp(buf, "hnod=", 5)) {
190 strcpy(node, &buf[5]);
191 } else if (!strncasecmp(buf, "room=", 5)) {
192 strcpy(room, &buf[5]);
193 } else if (!strncasecmp(buf, "rfca=", 5)) {
194 strcpy(rfca, &buf[5]);
195 } else if (!strncasecmp(buf, "rcpt=", 5)) {
196 strcpy(rcpt, &buf[5]);
197 } else if (!strncasecmp(buf, "msgn=", 5)) {
198 strcpy(msgn, &buf[5]);
199 } else if (!strncasecmp(buf, "time=", 5)) {
201 gmtime_r(&now, &now_tm);
202 strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", &now_tm);
205 wprintf(" <item>\n");
207 wprintf(" <title>%s from", subj);
209 wprintf(" <title>From");
211 wprintf(" %s", from);
212 wprintf(" in %s", room);
213 if (strcmp(hnod, serv_info.serv_humannode) && !IsEmptyStr(hnod)) {
214 wprintf(" on %s", hnod);
216 wprintf("</title>\n");
218 wprintf(" <pubDate>%s</pubDate>\n", date);
220 wprintf(" <guid isPermaLink=\"false\">%s</guid>\n", msgn);
221 /** Now the hard part, the message itself */
222 strcpy(content_type, "text/plain");
223 while (serv_getln(buf, sizeof buf), !IsEmptyStr(buf)) {
224 if (!strcmp(buf, "000")) {
227 if (!strncasecmp(buf, "Content-type: ", 14)) {
229 safestrncpy(content_type, &buf[14], sizeof content_type);
230 len = strlen (content_type);
231 for (b = 0; b < len; ++b) {
232 if (!strncasecmp(&content_type[b], "charset=", 8)) {
233 safestrncpy(charset, &content_type[b + 8], sizeof charset);
236 for (b = 0; b < len; ++b) {
237 if (content_type[b] == ';') {
245 /** Set up a character set conversion if we need to */
247 if (strcasecmp(charset, "us-ascii") && strcasecmp(charset, "utf-8") && strcasecmp(charset, "") ) {
248 ic = ctdl_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));
257 /** Messages in legacy Citadel variformat get handled thusly... */
258 if (!strcasecmp(content_type, "text/x-citadel-variformat")) {
261 wprintf(" <description><![CDATA[");
263 serv_getln(buf, sizeof buf);
264 if (!strcmp(buf, "000")) {
266 wprintf("</blockquote>");
270 if (intext == 1 && isspace(buf[0])) {
274 if (bq == 0 && !strncmp(buf, " >", 2)) {
275 wprintf("<blockquote>");
277 } else if (bq == 1 && strncmp(buf, " >", 2)) {
278 wprintf("</blockquote>");
281 url(buf, sizeof(buf));
285 display_rss_control(from, subj);
286 wprintf("]]></description>\n");
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")) {
294 if (buf[len-1] == '\n') buf[--len] = 0;
295 if (buf[len-1] == '\r') buf[--len] = 0;
298 if (ic != (iconv_t)(-1) ) {
302 obuf = (char *) malloc(obuflen);
304 iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
305 osav[SIZ-obuflen] = 0;
306 safestrncpy(buf, osav, sizeof buf);
311 while ((!IsEmptyStr(buf)) && (isspace(buf[len - 1])))
314 ((!strncmp(buf, ">", 1)) || (!strncmp(buf, " >", 2)) || (!strncmp(buf, " :-)", 4)))) {
315 wprintf("<blockquote>");
317 } else if ((bq == 1) &&
318 (strncmp(buf, ">", 1)) && (strncmp(buf, " >", 2)) && (strncmp(buf, " :-)", 4))) {
319 wprintf("</blockquote>");
323 url(buf, sizeof(buf));
325 wprintf("</tt><br />\n");
327 display_rss_control(from, subj);
328 wprintf("]]></description>\n");
330 /** HTML is fun, but we've got to strip it first */
331 else if (!strcasecmp(content_type, "text/html")) {
332 wprintf(" <description><![CDATA[");
333 output_html(charset, 0);
334 wprintf("]]></description>\n");
338 wprintf(" </item>\n");
344 wprintf(" </channel>\n");