Began making changes to do better handling of character sets.
[citadel.git] / webcit / webcit.c
index 8c9e47b950086f15fab5a85c60af8c0aba14ae4b..85ee1ca4ba9e28af897fcee0279dcaf1dc18074d 100644 (file)
@@ -5,7 +5,7 @@
  * \defgroup MainServer This is the main transaction loop of the web service.  It maintains a
  * persistent session to the Citadel server, handling HTTP WebCit requests as
  * they arrive and presenting a user interface.
- * \ingroup BackendWebServer
+ * \ingroup WebcitHttpServer
  */
 /*@{*/
 #include "webcit.h"
@@ -57,8 +57,8 @@ void unescape_input(char *buf)
 }
 
 /**
- * \brief add urls???
- * \param url what???
+ * \brief Extract variables from the URL.
+ * \param url URL supplied by the HTTP parser
  */
 void addurls(char *url)
 {
@@ -141,8 +141,8 @@ void dump_vars(void)
 }
 
 /**
- * \brief what???
- * \param key what???
+ * \brief Return the value of a variable supplied to the current web page (from the url or a form)
+ * \param key The name of the variable we want
  */
 char *bstr(char *key)
 {
@@ -196,8 +196,8 @@ void wDumpContent(int print_standard_html_footer)
 
 /**
  * \brief Copy a string, escaping characters which have meaning in HTML.  
- * \param target target buffer to copy to
- * \param strbuf source buffer ???
+ * \param target target buffer
+ * \param strbuf source buffer
  * \param nbsp If nonzero, spaces are converted to non-breaking spaces.
  * \param nolinebreaks if set, linebreaks are removed from the string.
  */
@@ -263,8 +263,8 @@ void escputs(char *strbuf)
 /** 
  * \brief Escape a string for feeding out as a URL.
  * Returns a pointer to a buffer that must be freed by the caller!
- * \param outbuf the outputbuffer
- * \param strbuf the input buffer???
+ * \param outbuf the output buffer
+ * \param strbuf the input buffer
  */
 void urlesc(char *outbuf, char *strbuf)
 {
@@ -394,11 +394,11 @@ void output_headers(      int do_httpheaders,     /**< 1 = output HTTP headers
                        int suppress_check,     /**< 1 = suppress check for instant messages          */
                        int cache               /**< 1 = allow browser to cache this page             */
 ) {
-       char cookie[SIZ];
-       char httpnow[SIZ];
+       char cookie[1024];
+       char httpnow[128];
 
        wprintf("HTTP/1.1 200 OK\n");
-       httpdate(httpnow, time(NULL));
+       http_datestring(httpnow, sizeof httpnow, time(NULL));
 
        if (do_httpheaders) {
                wprintf("Content-type: text/html; charset=utf-8\r\n"
@@ -445,8 +445,8 @@ void output_headers(        int do_httpheaders,     /**< 1 = output HTTP headers
                /** check for ImportantMessages (these display in a div overlaying the main screen) */
                if (strlen(WC->ImportantMessage) > 0) {
                        wprintf("<div id=\"important_message\">\n");
-                       wprintf("<SPAN CLASS=\"imsg\">"
-                               "%s</SPAN><br />\n", WC->ImportantMessage);
+                       wprintf("<span class=\"imsg\">"
+                               "%s</span><br />\n", WC->ImportantMessage);
                        wprintf("</div>\n");
                        wprintf("<script type=\"text/javascript\">\n"
                                "        setTimeout('hide_imsg_popup()', 3000); \n"
@@ -646,15 +646,18 @@ void output_image()
 
 /**
  * \brief Generic function to output an arbitrary MIME part from an arbitrary
- * message number on the server.
- * \param msgnum number of the item on the citadel server
- * \param partnum the MIME part to be output
+ *        message number on the server.
+ *
+ * \param msgnum               Number of the item on the citadel server
+ * \param partnum              The MIME part to be output
+ * \param force_download       Nonzero to force set the Content-Type: header
+ *                              to "application/octet-stream"
  */
-void mimepart(char *msgnum, char *partnum)
+void mimepart(char *msgnum, char *partnum, int force_download)
 {
-       char buf[SIZ];
+       char buf[256];
        off_t bytes;
-       char content_type[SIZ];
+       char content_type[256];
        char *content = NULL;
        
        serv_printf("OPNA %s|%s", msgnum, partnum);
@@ -662,7 +665,12 @@ void mimepart(char *msgnum, char *partnum)
        if (buf[0] == '2') {
                bytes = extract_long(&buf[4], 0);
                content = malloc(bytes + 2);
-               extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
+               if (force_download) {
+                       strcpy(content_type, "application/octet-stream");
+               }
+               else {
+                       extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
+               }
                output_headers(0, 0, 0, 0, 0, 0);
                read_server_binary(content, bytes);
                serv_puts("CLOS");
@@ -724,9 +732,9 @@ void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext)
        wprintf("HTTP/1.1 200 OK\n");
        output_headers(1, 1, 2, 0, 0, 0);
        wprintf("<div id=\"banner\">\n");
-       wprintf("<TABLE WIDTH=100%% BORDER=0 BGCOLOR=\"#%s\"><TR><TD>", titlebarcolor);
-       wprintf("<SPAN CLASS=\"titlebar\">%s</SPAN>\n", titlebarmsg);
-       wprintf("</TD></TR></TABLE>\n");
+       wprintf("<table width=100%% border=0 bgcolor=\"#%s\"><tr><td>", titlebarcolor);
+       wprintf("<span class=\"titlebar\">%s</span>\n", titlebarmsg);
+       wprintf("</td></tr></table>\n");
        wprintf("</div>\n<div id=\"content\">\n");
        escputs(messagetext);
 
@@ -759,9 +767,9 @@ void url_do_template(void) {
 void offer_start_page(void) {
        wprintf("<a href=\"change_start_page?startpage=");
        urlescputs(WC->this_page);
-       wprintf("\"><FONT SIZE=-2 COLOR=\"#AAAAAA\">");
+       wprintf("\"><font size=-2 color=\"#AAAAAA\">");
        wprintf(_("Make this my start page"));
-       wprintf("</FONT></A>");
+       wprintf("</font></a>");
 /*
        wprintf("<br/><a href=\"rss?room=");
        urlescputs(WC->wc_roomname);
@@ -823,17 +831,20 @@ void authorization_required(const char *message)
 }
 
 /**
- * \brief handle file uploads 
- * \param name the url the upload is done to
- * \param filename the name of the file being uploaded
- * \param partnum item number on the citadel server ???
- * \param disp what???
- * \param content the file contents???
- * \param cbtype what???
- * \param cbcharset the character set of cb??
- * \param length the size of the file ???
- * \param encoding charset encoding of the file??
- * \param userdata what???
+ * \brief This function is called by the MIME parser to handle data uploaded by
+ *        the browser.  Form data, uploaded files, and the data from HTTP PUT
+ *        operations (such as those found in GroupDAV) all arrive this way.
+ *
+ * \param name Name of the item being uploaded
+ * \param filename Filename of the item being uploaded
+ * \param partnum MIME part identifier (not needed)
+ * \param disp MIME content disposition (not needed)
+ * \param content The actual data
+ * \param cbtype MIME content-type
+ * \param cbcharset Character set
+ * \param length Content length
+ * \param encoding MIME encoding type (not needed)
+ * \param userdata Not used here
  */
 void upload_handler(char *name, char *filename, char *partnum, char *disp,
                        void *content, char *cbtype, char *cbcharset,
@@ -922,7 +933,7 @@ void ajax_servcmd(void)
                wprintf("000");
        }
        if (buf[0] == '4') {
-               text_to_server(bstr("g_input"), 0);
+               text_to_server(bstr("g_input"));
                serv_puts("000");
        }
        if (buf[0] == '6') {
@@ -1086,6 +1097,7 @@ void session_loop(struct httprequest *req)
 
        while (hptr != NULL) {
                safestrncpy(buf, hptr->line, sizeof buf);
+               /* lprintf(9, "HTTP HEADER: %s\n", buf); */
                hptr = hptr->next;
 
                if (!strncasecmp(buf, "Cookie: webcit=", 15)) {
@@ -1109,8 +1121,15 @@ void session_loop(struct httprequest *req)
                else if (!strncasecmp(buf, "User-agent: ", 12)) {
                        safestrncpy(user_agent, &buf[12], sizeof user_agent);
                }
+               else if (!strncasecmp(buf, "X-Forwarded-Host: ", 18)) {
+                       if (follow_xff) {
+                               safestrncpy(WC->http_host, &buf[18], sizeof WC->http_host);
+                       }
+               }
                else if (!strncasecmp(buf, "Host: ", 6)) {
-                       safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host);
+                       if (strlen(WC->http_host) == 0) {
+                               safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host);
+                       }
                }
                else if (!strncasecmp(buf, "X-Forwarded-For: ", 17)) {
                        safestrncpy(browser_host, &buf[17], sizeof browser_host);
@@ -1165,6 +1184,14 @@ void session_loop(struct httprequest *req)
                }
        }
 
+       /** If it's a "force 404" situation then display the error and bail. */
+       if (!strcmp(action, "404")) {
+               wprintf("HTTP/1.1 404 Not found\r\n");
+               wprintf("Content-Type: text/plain\r\n");
+               wprintf("\r\n");
+               wprintf("Not found\r\n");
+               goto SKIP_ALL_THIS_CRAP;
+       }
 
        /** Static content can be sent without connecting to Citadel. */
        is_static = 0;
@@ -1546,7 +1573,9 @@ void session_loop(struct httprequest *req)
        } else if (!strcasecmp(action, "display_menubar")) {
                display_menubar(1);
        } else if (!strcasecmp(action, "mimepart")) {
-               mimepart(arg1, arg2);
+               mimepart(arg1, arg2, 0);
+       } else if (!strcasecmp(action, "mimepart_download")) {
+               mimepart(arg1, arg2, 1);
        } else if (!strcasecmp(action, "edit_vcard")) {
                edit_vcard();
        } else if (!strcasecmp(action, "submit_vcard")) {