From: Michael Hampton Date: Thu, 18 Aug 2005 22:59:38 +0000 (+0000) Subject: First-draft of RSS support. X-Git-Tag: v7.86~4713 X-Git-Url: https://code.citadel.org/?a=commitdiff_plain;h=c79881abf6a5af68276a50703d53adf43a210270;p=citadel.git First-draft of RSS support. --- diff --git a/webcit/Makefile.in b/webcit/Makefile.in index 315824fee..b53acba4e 100644 --- a/webcit/Makefile.in +++ b/webcit/Makefile.in @@ -34,7 +34,7 @@ webserver: webserver.o context_loop.o tools.o ical_dezonify.o \ webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o \ roomops.o messages.o userlist.o paging.o sysmsgs.o useredit.o \ vcard.o vcard_edit.o preferences.o html2html.o listsub.o \ - mime_parser.o graphics.o netconf.o siteconfig.o subst.o \ + mime_parser.o graphics.o netconf.o siteconfig.o subst.o rss.o \ calendar.o calendar_tools.o calendar_view.o event.o \ availability.o iconbar.o crypto.o inetconf.o notes.o \ groupdav_main.o groupdav_get.o groupdav_propfind.o fmt_date.o \ @@ -45,7 +45,7 @@ webserver: webserver.o context_loop.o tools.o ical_dezonify.o \ webcit.o auth.o tcp_sockets.o mainmenu.o serv_func.o who.o listsub.o \ roomops.o messages.o userlist.o paging.o sysmsgs.o useredit.o \ locate_host.o siteconfig.o subst.o vcard.o vcard_edit.o floors.o \ - mime_parser.o graphics.o netconf.o preferences.o html2html.o \ + mime_parser.o graphics.o netconf.o preferences.o html2html.o rss.o \ summary.o calendar.o calendar_tools.o calendar_view.o event.o \ availability.o ical_dezonify.o iconbar.o crypto.o inetconf.o notes.o \ groupdav_main.o groupdav_get.o groupdav_propfind.o groupdav_delete.o \ diff --git a/webcit/context_loop.c b/webcit/context_loop.c index 53129a780..f64433afd 100644 --- a/webcit/context_loop.c +++ b/webcit/context_loop.c @@ -337,6 +337,7 @@ void context_loop(int sock) && (strncasecmp(buf, "/freebusy", 9)) && (strncasecmp(buf, "/do_logout", 10)) && (strncasecmp(buf, "/groupdav", 9)) + && (strncasecmp(buf, "/rss", 4)) && (got_cookie == 0)) { strcpy(req->line, "GET /static/nocookies.html" "?force_close_session=yes HTTP/1.0"); diff --git a/webcit/rss.c b/webcit/rss.c new file mode 100644 index 000000000..1c250a913 --- /dev/null +++ b/webcit/rss.c @@ -0,0 +1,286 @@ +/* + * $Id$ + * + * Generate some RSS for our rooms. + */ + +#include "webcit.h" +#include "webserver.h" + +void display_rss(const char *roomname) +{ + int nummsgs; + int a, b; + int bq = 0; + time_t now = 0L; + struct tm now_tm; + iconv_t ic = (iconv_t)(-1) ; + char *ibuf; /* Buffer of characters to be converted */ + char *obuf; /* Buffer for converted characters */ + size_t ibuflen; /* Length of input buffer */ + size_t obuflen; /* Length of output buffer */ + char *osav; /* Saved pointer to output buffer */ + char buf[SIZ]; + char date[30]; + char from[256]; + char subj[256]; + char node[256]; + char hnod[256]; + char room[256]; + char rfca[256]; + char rcpt[256]; + char msgn[256]; + char content_type[256]; + char charset[256]; + + lprintf(3, "Running RSS reader\n"); + if (!WC->logged_in) { + authorization_required(); + return; + } + + lprintf(3, "Going to a room %s\n", roomname); + if (gotoroom(roomname)) { + wprintf("HTTP/1.0 404 Not Found\r\n"); + wprintf("Content-Type: text/html\r\n"); + wprintf("\r\n"); + wprintf("Error retrieving RSS feed: couldn't find room or messages\n"); + return; + } + + lprintf(3, "Loading up all the messages\n"); + nummsgs = load_msg_ptrs("MSGS LAST|50", 0); + if (nummsgs == 0) { + wprintf("HTTP/1.0 404 Not Found\r\n"); + wprintf("Content-Type: text/html\r\n"); + wprintf("\r\n"); + wprintf("Error retrieving RSS feed: couldn't find room or messages\n"); + return; + } + + lprintf(3, "Getting date of the last one\n"); + /* Read time of last message immediately */ + serv_printf("MSG4 %ld", WC->msgarr[nummsgs - 1]); + serv_getln(buf, sizeof buf); + if (buf[0] == '1') { + while (serv_getln(buf, sizeof buf), strcasecmp(buf, "000")) { + if (!strncasecmp(buf, "time=", 5)) { + now = atol(&buf[5]); + gmtime_r(&now, &now_tm); + strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", &now_tm); + } + } + } + + /* Do RSS header */ + output_headers(0, 0, 0, 0, 0, 0, 0); + wprintf("Content-Type: application/rss+xml\r\n"); + wprintf("\r\n"); + wprintf("\n"); + wprintf("\n"); + wprintf(" \n"); + wprintf(" %s - %s\n", WC->wc_roomname, serv_info.serv_humannode); + wprintf(" "); + /* Get room info for description */ + serv_puts("RINF"); + serv_getln(buf, sizeof buf); + if (buf[0] == '1') { + while (1) { + serv_getln(buf, sizeof buf); + if (!strcmp(buf, "000")) + break; + wprintf("%s", buf); + } + } + wprintf("\n"); + if (now) { + wprintf(" %s\n", buf); + } + wprintf(" %s\n", SERVER); + wprintf(" http://blogs.law.harvard.edu/tech/rss\n"); + wprintf(" 30\n"); + + /* Read all messages and output as RSS items */ + for (a = 0; a < nummsgs; ++a) { + lprintf(3, "Sending message %d of %d\n", a+1, nummsgs); + /* Read message and output each as RSS item */ + serv_printf("MSG4 %ld", WC->msgarr[a]); + serv_getln(buf, sizeof buf); + if (buf[0] != '1') continue; + + now = 0L; + strcpy(subj, ""); + strcpy(hnod, ""); + strcpy(node, ""); + strcpy(room, ""); + strcpy(rfca, ""); + strcpy(rcpt, ""); + strcpy(msgn, ""); + + while (serv_getln(buf, sizeof buf), strcasecmp(buf, "text")) { + if (!strcmp(buf, "000")) { + lprintf(3, "ENDITEM 1\n"); + goto ENDITEM; /* screw it */ + } else if (!strncasecmp(buf, "from=", 5)) { + strcpy(from, &buf[5]); +#ifdef HAVE_ICONV + utf8ify_rfc822_string(from); +#endif + } else if (!strncasecmp(buf, "subj=", 5)) { + strcpy(subj, &buf[5]); +#ifdef HAVE_ICONV + utf8ify_rfc822_string(subj); +#endif + } else if (!strncasecmp(buf, "hnod=", 5)) { + strcpy(node, &buf[5]); + } else if (!strncasecmp(buf, "room=", 5)) { + strcpy(room, &buf[5]); + } else if (!strncasecmp(buf, "rfca=", 5)) { + strcpy(rfca, &buf[5]); + } else if (!strncasecmp(buf, "rcpt=", 5)) { + strcpy(rcpt, &buf[5]); + } else if (!strncasecmp(buf, "msgn=", 5)) { + strcpy(msgn, &buf[5]); + } else if (!strncasecmp(buf, "time=", 5)) { + now = atol(&buf[5]); + gmtime_r(&now, &now_tm); + strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", &now_tm); + } + } + wprintf(" \n"); + if (subj[0]) { + wprintf(" %s from", subj); + } else { + wprintf(" <title>From"); + } + wprintf(" %s", from); + wprintf(" in %s", room); + if (strcmp(hnod, serv_info.serv_humannode) && strlen(hnod) > 0) { + wprintf(" on %s", hnod); + } + wprintf("\n"); + if (now) { + wprintf(" %s\n", date); + } + wprintf(" %s\n", msgn); + /* Now the hard part, the message itself */ + strcpy(content_type, "text/plain"); + while (serv_getln(buf, sizeof buf), strlen(buf) > 0) { + if (!strcmp(buf, "000")) { + lprintf(3, "ENDBODY 1\n"); + goto ENDBODY; + } + if (!strncasecmp(buf, "Content-type: ", 14)) { + safestrncpy(content_type, &buf[14], sizeof content_type); + for (b = 0; b < strlen(content_type); ++b) { + if (!strncasecmp(&content_type[b], "charset=", 8)) { + safestrncpy(charset, &content_type[b + 8], sizeof charset); + } + } + for (b = 0; b < strlen(content_type); ++b) { + if (content_type[b] == ';') { + content_type[b] = 0; + } + } + } + } + + /* Set up a character set conversion if we need to */ +#ifdef HAVE_ICONV + if (strcasecmp(charset, "us-ascii") && strcasecmp(charset, "utf-8")) { + ic = iconv_open("UTF-8", charset); + if (ic == (iconv_t)(-1)) { + lprintf(5, "iconv_open() failed: %s\n", strerror(errno)); + goto ENDBODY; + } + } +#endif + + /* Messages in legacy Citadel variformat get handled thusly... */ + if (!strcasecmp(content_type, "text/x-citadel-variformat")) { + int intext = 0; + + wprintf(" "); + wprintf("\n"); + break; + } + if (intext == 1 && isspace(buf[0])) { + wprintf("
"); + } + intext = 1; + if (bq == 0 && !strncmp(buf, " >", 2)) { + wprintf("
"); + bq = 1; + } else if (bq == 1 && strncmp(buf, " >", 2)) { + wprintf("
"); + bq = 0; + } + url(buf); + escputs(buf); + wprintf("\n"); + } + wprintf("]]>
\n"); + } + /* Boring old 80-column fixed format text gets handled this way... */ + else if (!strcasecmp(content_type, "text/plain")) { + wprintf(" 0) && (isspace(buf[strlen(buf) - 1]))) + buf[strlen(buf) - 1] = 0; + if ((bq == 0) && + ((!strncmp(buf, ">", 1)) || (!strncmp(buf, " >", 2)) || (!strncmp(buf, " :-)", 4)))) { + wprintf("
"); + bq = 1; + } else if ((bq == 1) && + (strncmp(buf, ">", 1)) && (strncmp(buf, " >", 2)) && (strncmp(buf, " :-)", 4))) { + wprintf("
"); + bq = 0; + } + wprintf(""); + url(buf); + escputs(buf); + wprintf("
\n"); + } + wprintf("]]>
\n"); + } + /* HTML is fun, but we've got to strip it first */ + else if (!strcasecmp(content_type, "text/html")) { + wprintf(" \n"); + } + +ENDBODY: + wprintf("
\n"); +ENDITEM: + lprintf(3, "Finished message %d of %d\n", a+1, nummsgs); + now = 0L; + } + + /* Do RSS footer */ + wprintf("
\n"); + wprintf("
\n"); + wDumpContent(0); +} diff --git a/webcit/webcit.c b/webcit/webcit.c index fd74ae10e..aa9af913a 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -757,6 +757,19 @@ void display_success(char *successmessage) } +/* Authorization required page */ +/* This is probably temporary and should be revisited */ +void authorization_required(const char *message) +{ + wprintf("HTTP/1.0 401 Authorization Required\r\n"); + wprintf("WWW-Authenticate: Basic realm=\"\"\r\n", serv_info.serv_humannode); + wprintf("Content-Type: text/html\r\n\r\n"); + wprintf("

Authorization Required

\r\n"); + wprintf("The resource you requested requires a valid username and password."); + wprintf("I could not log you in: %s\n", message); + wDumpContent(0); +} + void upload_handler(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, @@ -1031,10 +1044,20 @@ void session_loop(struct httprequest *req) c_httpauth_pass, buf); safestrncpy(WC->httpauth_user, c_httpauth_user, sizeof WC->httpauth_user); safestrncpy(WC->httpauth_pass, c_httpauth_pass, sizeof WC->httpauth_pass); + } else { + /* Should only display when password is wrong */ + authorization_required(&buf[4]); + goto SKIP_ALL_THIS_CRAP; } } } + /* This needs to run early */ + if (!strcasecmp(action, "rss")) { + display_rss(bstr("room")); + goto SKIP_ALL_THIS_CRAP; + } + /* * The GroupDAV stuff relies on HTTP authentication instead of * our session's authentication.