X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fwebcit.c;h=641b356157f0acc2e4d1e45d185f9fbdce317724;hb=44c30618e25ce2eb103b87e84e10dcd51dad0879;hp=f4261e8b27b4b23b1e02a472734b8ff4fd870afd;hpb=a719bd431b76b3dd4909d16212964b8d7ed899f3;p=citadel.git diff --git a/webcit/webcit.c b/webcit/webcit.c index f4261e8b2..641b35615 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -1,45 +1,37 @@ /* - * webcit.c - * - * This is the actual program called by the webserver. It maintains a + * $Id$ + */ +/** + * \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. - * - * $Id$ + * \ingroup BackendWebServer */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +/*@{*/ #include "webcit.h" #include "groupdav.h" #include "webserver.h" #include "mime_parser.h" -/* +/** + * Subdirectories from which the client may request static content + */ +char *static_content_dirs[] = { + "static", /** static templates */ + "tiny_mce" /** the JS editor */ +}; + +/** * String to unset the cookie. * Any date "in the past" will work, so I chose my birthday, right down to * the exact minute. :) */ static char *unset = "; expires=28-May-1971 18:10:00 GMT"; +/** + * \brief remove escaped strings from i.e. the url string (like %20 for blanks) + * \param buf the buffer to examine + */ void unescape_input(char *buf) { int a, b; @@ -55,6 +47,7 @@ void unescape_input(char *buf) hex[0] = buf[a + 1]; hex[1] = buf[a + 2]; hex[2] = 0; + b = 0; sscanf(hex, "%02x", &b); buf[a] = (char) b; strcpy(&buf[a + 1], &buf[a + 3]); @@ -63,7 +56,10 @@ void unescape_input(char *buf) } - +/** + * \brief add urls??? + * \param url what??? + */ void addurls(char *url) { char *up, *ptr; @@ -74,7 +70,7 @@ void addurls(char *url) up = url; while (strlen(up) > 0) { - /* locate the = sign */ + /** locate the = sign */ safestrncpy(buf, up, sizeof buf); b = (-1); for (a = 255; a >= 0; --a) @@ -87,13 +83,13 @@ void addurls(char *url) u = (struct urlcontent *) malloc(sizeof(struct urlcontent)); u->next = WC->urlstrings; WC->urlstrings = u; - strcpy(u->url_key, buf); + safestrncpy(u->url_key, buf, sizeof u->url_key); - /* now chop that part off */ + /** now chop that part off */ for (a = 0; a <= b; ++a) ++up; - /* locate "&" and "?" delimiters */ + /** locate "&" and "?" delimiters */ ptr = up; b = strlen(up); for (a = 0; a < strlen(up); ++a) { @@ -109,7 +105,7 @@ void addurls(char *url) strcpy(ptr, ""); u->url_data = malloc(strlen(up) + 2); - strcpy(u->url_data, up); + safestrncpy(u->url_data, up, strlen(up) + 1); u->url_data[b] = 0; unescape_input(u->url_data); up = ptr; @@ -117,6 +113,9 @@ void addurls(char *url) } } +/** + * \brief free urlstring memory + */ void free_urls(void) { struct urlcontent *u; @@ -129,8 +128,8 @@ void free_urls(void) } } -/* - * Diagnostic function to display the contents of all variables +/** + * \brief Diagnostic function to display the contents of all variables */ void dump_vars(void) { @@ -141,6 +140,10 @@ void dump_vars(void) } } +/** + * \brief what??? + * \param key what??? + */ char *bstr(char *key) { struct urlcontent *u; @@ -152,7 +155,11 @@ char *bstr(char *key) return (""); } - +/** + * \brief web-printing funcion. uses our vsnprintf wrapper + * \param format printf format string + * \param ... the varargs to put into formatstring + */ void wprintf(const char *format,...) { va_list arg_ptr; @@ -166,26 +173,33 @@ void wprintf(const char *format,...) } -/* - * wDumpContent() wraps up an HTTP session, closes tags, etc. - * - * print_standard_html_footer should be set to 0 to transmit only, 1 to +/** + * \brief wrap up an HTTP session, closes tags, etc. + * \todo multiline params? + * \param print_standard_html_footer should be set to 0 to transmit only, 1 to * append the main menu and closing tags, or 2 to * append the closing tags only. */ void wDumpContent(int print_standard_html_footer) { if (print_standard_html_footer) { - wprintf("\n"); /* end of "text" div */ + wprintf("\n"); /* end of "text" div */ do_template("trailing"); } + /* If we've been saving it all up for one big output burst, + * go ahead and do that now. + */ + end_burst(); } -/* - * Copy a string, escaping characters which have meaning in HTML. If - * nbsp is nonzero, spaces are converted to non-breaking spaces. +/** + * \brief Copy a string, escaping characters which have meaning in HTML. + * \param target target buffer to copy to + * \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. */ void stresc(char *target, char *strbuf, int nbsp, int nolinebreaks) { @@ -220,6 +234,12 @@ void stresc(char *target, char *strbuf, int nbsp, int nolinebreaks) } } +/** + * \brief WHAT??? + * \param strbuf what??? + * \param nbsp If nonzero, spaces are converted to non-breaking spaces. + * \param nolinebreaks if set, linebreaks are removed from the string. + */ void escputs1(char *strbuf, int nbsp, int nolinebreaks) { char *buf; @@ -231,19 +251,25 @@ void escputs1(char *strbuf, int nbsp, int nolinebreaks) free(buf); } +/** + * \brief static wrapper for ecsputs1 + * \param strbuf buffer to print escaped to client + */ void escputs(char *strbuf) { escputs1(strbuf, 0, 0); } -/* - * Escape a string for feeding out as a URL. +/** + * \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??? */ void urlesc(char *outbuf, char *strbuf) { int a, b, c; - char *ec = " #&;`'|*?-~<>^()[]{}$\\"; + char *ec = " #&;`'|*?-~<>^()[]{}$\"\\"; strcpy(outbuf, ""); @@ -261,6 +287,10 @@ void urlesc(char *outbuf, char *strbuf) } } +/** + * \brief urlescape buffer and print it to the client + * \param strbuf buffer to urlescape + */ void urlescputs(char *strbuf) { char outbuf[SIZ]; @@ -270,8 +300,10 @@ void urlescputs(char *strbuf) } -/* - * Copy a string, escaping characters for JavaScript strings. +/** + * \brief Copy a string, escaping characters for JavaScript strings. + * \param target output string + * \param strbuf input string */ void jsesc(char *target, char *strbuf) { @@ -295,6 +327,10 @@ void jsesc(char *target, char *strbuf) } } +/** + * \brief escape and print java script + * \param strbuf the js code + */ void jsescputs(char *strbuf) { char outbuf[SIZ]; @@ -303,8 +339,10 @@ void jsescputs(char *strbuf) wprintf("%s", outbuf); } -/* - * Copy a string, escaping characters for message text hold +/** + * \brief Copy a string, escaping characters for message text hold + * \param target target buffer + * \param strbuf source buffer */ void msgesc(char *target, char *strbuf) { @@ -312,18 +350,22 @@ void msgesc(char *target, char *strbuf) strcpy(target, ""); for (a = 0; a < strlen(strbuf); ++a) { - if (strbuf[a] == '\'') - strcat(target, "\\'"); - else if (strbuf[a] == '\n') + if (strbuf[a] == '\n') strcat(target, " "); else if (strbuf[a] == '\r') strcat(target, " "); + else if (strbuf[a] == '\'') + strcat(target, "'"); else { strncat(target, &strbuf[a], 1); } } } +/** + * \brief print message to the client ??? + * \param strbuf message to print??? + */ void msgescputs(char *strbuf) { char *outbuf; @@ -337,78 +379,89 @@ void msgescputs(char *strbuf) { -/* - * Output all that important stuff that the browser will want to see +/** + * \brief Output all that important stuff that the browser will want to see */ -void output_headers( int do_httpheaders, /* 1 = output HTTP headers */ - int do_htmlhead, /* 1 = output HTML section and opener */ +void output_headers( int do_httpheaders, /**< 1 = output HTTP headers */ + int do_htmlhead, /**< 1 = output HTML section and opener */ - int do_room_banner, /* 0=no, 1=yes, */ - /* 2 = I'm going to embed my own, so don't open the */ - /*
either. */ + int do_room_banner, /**< 0=no, 1=yes, + * 2 = I'm going to embed my own, so don't open the + *
either. + */ - int unset_cookies, /* 1 = session is terminating, so unset the cookies */ - int refresh30, /* 1 = automatically refresh page every 30 seconds */ - int suppress_check, /* 1 = suppress check for instant messages */ - int cache /* 1 = allow browser to cache this page */ + int unset_cookies, /**< 1 = session is terminating, so unset the cookies */ + int suppress_check, /**< 1 = suppress check for instant messages */ + int cache /**< 1 = allow browser to cache this page */ ) { char cookie[SIZ]; char httpnow[SIZ]; - wprintf("HTTP/1.0 200 OK\n"); + wprintf("HTTP/1.1 200 OK\n"); httpdate(httpnow, time(NULL)); if (do_httpheaders) { - wprintf("Content-type: text/html\n" - "Server: %s\n", SERVER + wprintf("Content-type: text/html; charset=utf-8\r\n" + "Server: %s / %s\n" + "Connection: close\r\n", + SERVER, serv_info.serv_software + ); + } + + if (cache) { + wprintf("Pragma: public\r\n" + "Cache-Control: max-age=3600, must-revalidate\r\n" + "Last-modified: %s\r\n", + httpnow + ); + } + else { + wprintf("Pragma: no-cache\r\n" + "Cache-Control: no-store\r\n" ); - if (!cache) - wprintf("Connection: close\n" - "Pragma: no-cache\n" - "Cache-Control: no-store\n" - ); } stuff_to_cookie(cookie, WC->wc_session, WC->wc_username, WC->wc_password, WC->wc_roomname); if (unset_cookies) { - wprintf("Set-cookie: webcit=%s; path=/\n", unset); + wprintf("Set-cookie: webcit=%s; path=/\r\n", unset); } else { - wprintf("Set-cookie: webcit=%s; path=/\n", cookie); + wprintf("Set-cookie: webcit=%s; path=/\r\n", cookie); if (server_cookie != NULL) { wprintf("%s\n", server_cookie); } } if (do_htmlhead) { - wprintf("\n"); - - if (refresh30) { - svprintf("REFRESHTAG", WCS_STRING, "%s", - "\n"); - } - else { - svprintf("REFRESHTAG", WCS_STRING, "%s", - "\n"); - } - + begin_burst(); do_template("head"); } - /* ICONBAR */ + /** ICONBAR */ if (do_htmlhead) { - if (WC->HaveInstantMessages) { - wprintf("
\n"); - page_popup(); + + /** check for ImportantMessages (these display in a div overlaying the main screen) */ + if (strlen(WC->ImportantMessage) > 0) { + wprintf("
\n"); + wprintf("" + "%s
\n", WC->ImportantMessage); wprintf("
\n"); + wprintf("\n"); + safestrncpy(WC->ImportantMessage, "", sizeof WC->ImportantMessage); } + if ( (WC->logged_in) && (!unset_cookies) ) { wprintf("
"); - do_iconbar(); - wprintf("
\n"); + do_selected_iconbar(); + /** check for instant messages (these display in a new window) + page_popup(); */ + wprintf("
"); } + if (do_room_banner == 1) { wprintf("
\n"); embed_room_banner(NULL, navbar_default); @@ -416,131 +469,135 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers } } - if (do_room_banner != 2) { + if (do_room_banner == 1) { wprintf("
\n"); - - - if (strlen(WC->ImportantMessage) > 0) { - do_template("beginbox_nt"); - wprintf("" - "%s
\n", WC->ImportantMessage); - do_template("endbox"); - strcpy(WC->ImportantMessage, ""); - } - } } -/* - * Generic function to do an HTTP redirect. Easy and fun. +/** + * \brief Generic function to do an HTTP redirect. Easy and fun. + * \param whichpage target url to 302 to */ void http_redirect(char *whichpage) { - wprintf("HTTP/1.0 302 Moved Temporarily\n"); - wprintf("Location: %s\n", whichpage); - wprintf("URI: %s\n", whichpage); - wprintf("Content-type: text/html\n\n"); - wprintf("\n"); - wprintf("you really want to be here now\n", - whichpage); + wprintf("HTTP/1.1 302 Moved Temporarily\n"); + wprintf("Location: %s\r\n", whichpage); + wprintf("URI: %s\r\n", whichpage); + wprintf("Content-type: text/html; charset=utf-8\r\n\r\n"); + wprintf(""); + wprintf("Go here.", whichpage); wprintf("\n"); } -void check_for_instant_messages() -{ - char buf[SIZ]; - - serv_puts("NOOP"); - serv_gets(buf); - if (buf[3] == '*') WC->HaveInstantMessages = 1; -} - - - - -/* - * Output a piece of content to the web browser +/** + * \brief Output a piece of content to the web browser */ void http_transmit_thing(char *thing, size_t length, char *content_type, int is_static) { - if (is_static) { - output_headers(0, 0, 0, 0, 0, 0, 1); - } - else { - output_headers(0, 0, 0, 0, 0, 0, 0); - } - wprintf("Content-type: %s\n" - "Content-length: %ld\n" - "Server: %s\n" - "Connection: close\n" - "\n", + + output_headers(0, 0, 0, 0, 0, is_static); + + wprintf("Content-type: %s\r\n" + "Server: %s\r\n" + "Connection: close\r\n", content_type, - (long) length, - SERVER + SERVER); + +#ifdef HAVE_ZLIB + /** If we can send the data out compressed, please do so. */ + if (WC->gzip_ok) { + char *compressed_data = NULL; + uLongf compressed_len; + + compressed_len = (uLongf) ((length * 101) / 100) + 100; + compressed_data = malloc(compressed_len); + + if (compress_gzip((Bytef *) compressed_data, + &compressed_len, + (Bytef *) thing, + (uLongf) length, Z_BEST_SPEED) == Z_OK) { + wprintf("Content-encoding: gzip\r\n" + "Content-length: %ld\r\n" + "\r\n", + (long) compressed_len + ); + client_write(compressed_data, (size_t)compressed_len); + free(compressed_data); + return; + } + } +#endif + + /** No compression ... just send it out as-is */ + wprintf("Content-length: %ld\r\n" + "\r\n", + (long) length ); client_write(thing, (size_t)length); } - +/** + * \brief dump out static pages from disk + * \param what the file urs to print + */ void output_static(char *what) { - char buf[4096]; FILE *fp; struct stat statbuf; off_t bytes; char *bigbuffer; - char content_type[SIZ]; + char content_type[128]; - sprintf(buf, "static/%s", what); - fp = fopen(buf, "rb"); + fp = fopen(what, "rb"); if (fp == NULL) { - wprintf("HTTP/1.0 404 %s\n", strerror(errno)); - wprintf("Content-Type: text/plain\n"); - wprintf("\n"); + lprintf(9, "output_static('%s') -- NOT FOUND --\n", what); + wprintf("HTTP/1.1 404 %s\n", strerror(errno)); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); wprintf("Cannot open %s: %s\n", what, strerror(errno)); } else { if (!strncasecmp(&what[strlen(what) - 4], ".gif", 4)) - strcpy(content_type, "image/gif"); + safestrncpy(content_type, "image/gif", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 4], ".txt", 4)) - strcpy(content_type, "text/plain"); + safestrncpy(content_type, "text/plain", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 4], ".css", 4)) - strcpy(content_type, "text/css"); + safestrncpy(content_type, "text/css", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 4], ".jpg", 4)) - strcpy(content_type, "image/jpeg"); + safestrncpy(content_type, "image/jpeg", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 4], ".png", 4)) - strcpy(content_type, "image/png"); + safestrncpy(content_type, "image/png", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 4], ".ico", 4)) - strcpy(content_type, "image/x-icon"); + safestrncpy(content_type, "image/x-icon", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 5], ".html", 5)) - strcpy(content_type, "text/html"); + safestrncpy(content_type, "text/html", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 4], ".htm", 4)) - strcpy(content_type, "text/html"); + safestrncpy(content_type, "text/html", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 4], ".wml", 4)) - strcpy(content_type, "text/vnd.wap.wml"); + safestrncpy(content_type, "text/vnd.wap.wml", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 5], ".wmls", 5)) - strcpy(content_type, "text/vnd.wap.wmlscript"); + safestrncpy(content_type, "text/vnd.wap.wmlscript", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 5], ".wmlc", 5)) - strcpy(content_type, "application/vnd.wap.wmlc"); + safestrncpy(content_type, "application/vnd.wap.wmlc", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 6], ".wmlsc", 6)) - strcpy(content_type, "application/vnd.wap.wmlscriptc"); + safestrncpy(content_type, "application/vnd.wap.wmlscriptc", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 5], ".wbmp", 5)) - strcpy(content_type, "image/vnd.wap.wbmp"); + safestrncpy(content_type, "image/vnd.wap.wbmp", sizeof content_type); else if (!strncasecmp(&what[strlen(what) - 3], ".js", 3)) - strcpy(content_type, "text/javascript"); + safestrncpy(content_type, "text/javascript", sizeof content_type); else - strcpy(content_type, "application/octet-stream"); + safestrncpy(content_type, "application/octet-stream", sizeof content_type); fstat(fileno(fp), &statbuf); bytes = statbuf.st_size; - lprintf(3, "Static: %s, (%s; %ld bytes)\n", what, content_type, bytes); bigbuffer = malloc(bytes + 2); fread(bigbuffer, bytes, 1, fp); fclose(fp); + lprintf(9, "output_static('%s') %s\n", what, content_type); http_transmit_thing(bigbuffer, (size_t)bytes, content_type, 1); free(bigbuffer); } @@ -550,8 +607,8 @@ void output_static(char *what) } -/* - * When the browser requests an image file from the Citadel server, +/** + * \brief When the browser requests an image file from the Citadel server, * this function is called to transmit it. */ void output_image() @@ -561,76 +618,72 @@ void output_image() off_t bytes; serv_printf("OIMG %s|%s", bstr("name"), bstr("parm")); - serv_gets(buf); + serv_getln(buf, sizeof buf); if (buf[0] == '2') { bytes = extract_long(&buf[4], 0); xferbuf = malloc(bytes + 2); - /* Read it from the server */ + /** Read it from the server */ read_server_binary(xferbuf, bytes); serv_puts("CLOS"); - serv_gets(buf); + serv_getln(buf, sizeof buf); - /* Write it to the browser */ + /** Write it to the browser */ http_transmit_thing(xferbuf, (size_t)bytes, "image/gif", 0); free(xferbuf); } else { - - /* Instead of an ugly 404, send a 1x1 transparent GIF + /** + * Instead of an ugly 404, send a 1x1 transparent GIF * when there's no such image on the server. */ - output_static("blank.gif"); - - /* - wprintf("HTTP/1.0 404 %s\n", &buf[4]); - output_headers(0, 0, 0, 0, 0, 0, 0); - wprintf("Content-Type: text/plain\n" - "\n" - "Error retrieving image: %s\n", - &buf[4] - ); - */ - + output_static("static/blank.gif"); } } -/* +/** + * \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 partnumber??? */ -void output_mimepart() +void mimepart(char *msgnum, char *partnum) { char buf[SIZ]; off_t bytes; char content_type[SIZ]; char *content = NULL; - serv_printf("OPNA %s|%s", bstr("msgnum"), bstr("partnum")); - serv_gets(buf); + serv_printf("OPNA %s|%s", msgnum, partnum); + serv_getln(buf, sizeof buf); if (buf[0] == '2') { bytes = extract_long(&buf[4], 0); content = malloc(bytes + 2); - extract(content_type, &buf[4], 3); - output_headers(0, 0, 0, 0, 0, 0, 0); + 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"); - serv_gets(buf); + serv_getln(buf, sizeof buf); http_transmit_thing(content, bytes, content_type, 0); free(content); } else { - wprintf("HTTP/1.0 404 %s\n", &buf[4]); - output_headers(0, 0, 0, 0, 0, 0, 0); - wprintf("Content-Type: text/plain\n"); - wprintf("\n"); - wprintf("Error retrieving part: %s\n", &buf[4]); + wprintf("HTTP/1.1 404 %s\n", &buf[4]); + output_headers(0, 0, 0, 0, 0, 0); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); + wprintf(_("An error occurred while retrieving this part: %s\n"), &buf[4]); } } -/* +/** + * \brief Read any MIME part of a message, from the server, into memory. + * \param msgnum number of the message on the citadel server + * \param partnum the part number??? */ char *load_mimepart(long msgnum, char *partnum) { @@ -640,16 +693,16 @@ char *load_mimepart(long msgnum, char *partnum) char *content; serv_printf("OPNA %ld|%s", msgnum, partnum); - serv_gets(buf); + serv_getln(buf, sizeof buf); if (buf[0] == '2') { bytes = extract_long(&buf[4], 0); - extract(content_type, &buf[4], 3); + extract_token(content_type, &buf[4], 3, '|', sizeof content_type); content = malloc(bytes + 2); read_server_binary(content, bytes); serv_puts("CLOS"); - serv_gets(buf); + serv_getln(buf, sizeof buf); content[bytes] = 0; /* null terminate for good measure */ return(content); } @@ -660,13 +713,16 @@ char *load_mimepart(long msgnum, char *partnum) } -/* - * Convenience functions to display a page containing only a string +/** + * \brief Convenience functions to display a page containing only a string + * \param titlebarcolor color of the titlebar of the frame + * \param titlebarmsg text to display in the title bar + * \param messagetext body of the box */ void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext) { - wprintf("HTTP/1.0 200 OK\n"); - output_headers(1, 1, 2, 0, 0, 0, 0); + wprintf("HTTP/1.1 200 OK\n"); + output_headers(1, 1, 2, 0, 0, 0); wprintf("
\n"); wprintf("
", titlebarcolor); wprintf("%s\n", titlebarmsg); @@ -679,17 +735,17 @@ void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext) } -/* - * Display a blank page. +/** + * \brief Display a blank page. */ void blank_page(void) { - output_headers(1, 1, 0, 0, 1, 0, 0); + output_headers(1, 1, 0, 0, 0, 0); wDumpContent(2); } -/* - * A template has been requested +/** + * \brief A template has been requested */ void url_do_template(void) { do_template(bstr("template")); @@ -697,87 +753,97 @@ void url_do_template(void) { -/* - * Offer to make any page the user's "start page." +/** + * \brief Offer to make any page the user's "start page." */ void offer_start_page(void) { - wprintf("this_page); - wprintf("\">" - "Make this my start page" - "" - ); + wprintf("\">"); + wprintf(_("Make this my start page")); + wprintf(""); +/* + wprintf("
wc_roomname); + wprintf("\" title=\"RSS 2.0 feed for "); + escputs(WC->wc_roomname); + wprintf("\">\"RSS\"\n"); +*/ } -/* - * Change the user's start page +/** + * \brief Change the user's start page */ void change_start_page(void) { if (bstr("startpage") == NULL) { - strcpy(WC->ImportantMessage, - "startpage set to null"); + safestrncpy(WC->ImportantMessage, + _("You no longer have a start page selected."), + sizeof WC->ImportantMessage); display_main_menu(); return; } - set_preference("startpage", bstr("startpage")); + set_preference("startpage", bstr("startpage"), 1); - output_headers(1, 1, 0, 0, 0, 0, 0); + output_headers(1, 1, 0, 0, 0, 0); do_template("newstartpage"); wDumpContent(1); } - +/** + * \brief display the successfull edit or s.th. lisket hat ??? + * \param successmessage the mesage itself + */ void display_success(char *successmessage) { convenience_page("007700", "OK", successmessage); } - -void extract_action(char *actbuf, char *cmdbuf) +/** + * \brief Authorization required page + * This is probably temporary and should be revisited + * \param message message to put in header +*/ +void authorization_required(const char *message) { - int i; - - strcpy(actbuf, cmdbuf); - if (!strncasecmp(actbuf, "GET /", 5)) - strcpy(actbuf, &actbuf[5]); - if (!strncasecmp(actbuf, "PUT /", 5)) - strcpy(actbuf, &actbuf[5]); - if (!strncasecmp(actbuf, "POST /", 6)) - strcpy(actbuf, &actbuf[6]); - - for (i = 0; i < strlen(actbuf); ++i) { - if (actbuf[i] == ' ') { - actbuf[i] = 0; - i = 0; - } - if (actbuf[i] == '/') { - actbuf[i] = 0; - i = 0; - } - if (actbuf[i] == '?') { - actbuf[i] = 0; - i = 0; - } - if (actbuf[i] == '&') { - actbuf[i] = 0; - i = 0; - } - } + wprintf("HTTP/1.1 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("

"); + wprintf(_("Authorization Required")); + wprintf("

\r\n"); + wprintf(_("The resource you requested requires a valid username and password. " + "You could not be logged in: %s\n"), message); + wDumpContent(0); } - +/** + * \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??? + */ void upload_handler(char *name, char *filename, char *partnum, char *disp, - void *content, char *cbtype, size_t length, - char *encoding, void *userdata) + void *content, char *cbtype, char *cbcharset, + size_t length, char *encoding, void *userdata) { struct urlcontent *u; + /* lprintf(9, "upload_handler() name=%s, type=%s, len=%d\n", + name, cbtype, length); */ + /* Form fields */ if ( (length > 0) && (strlen(cbtype) == 0) ) { u = (struct urlcontent *) malloc(sizeof(struct urlcontent)); @@ -789,7 +855,7 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, u->url_data[length] = 0; } - /* Uploaded files */ + /** Uploaded files */ if ( (length > 0) && (strlen(cbtype) > 0) ) { WC->upload = malloc(length); if (WC->upload != NULL) { @@ -807,30 +873,145 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, } +/** + * \brief Convenience functions to wrap around asynchronous ajax responses + */ +void begin_ajax_response(void) { + output_headers(0, 0, 0, 0, 0, 0); + + wprintf("Content-type: text/html; charset=UTF-8\r\n" + "Server: %s\r\n" + "Connection: close\r\n" + "Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n", + SERVER); + begin_burst(); +} +/** + * \brief print ajax response footer + */ +void end_ajax_response(void) { + wprintf("\r\n"); + wDumpContent(0); +} +/** + * \brief parse server command to execute on the citadel + */ +void ajax_servcmd(void) +{ + char buf[1024]; + char gcontent[1024]; + char *junk; + size_t len; -/* - * Entry point for WebCit transaction + begin_ajax_response(); + + serv_printf("%s", bstr("g_cmd")); + serv_getln(buf, sizeof buf); + wprintf("%s\n", buf); + + if (buf[0] == '8') { + serv_printf("\n\n000"); + } + if ((buf[0] == '1') || (buf[0] == '8')) { + while (serv_getln(gcontent, sizeof gcontent), strcmp(gcontent, "000")) { + wprintf("%s\n", gcontent); + } + wprintf("000"); + } + if (buf[0] == '4') { + text_to_server(bstr("g_input"), 0); + serv_puts("000"); + } + if (buf[0] == '6') { + len = atol(&buf[4]); + junk = malloc(len); + serv_read(junk, len); + free(junk); + } + if (buf[0] == '7') { + len = atol(&buf[4]); + junk = malloc(len); + memset(junk, 0, len); + serv_write(junk, len); + free(junk); + } + + end_ajax_response(); + + /** + * This is kind of an ugly hack, but this is the only place it can go. + * If the command was GEXP, then the instant messenger window must be + * running, so reset the "last_pager_check" watchdog timer so + * that page_popup() doesn't try to open it a second time. + */ + if (!strncasecmp(bstr("g_cmd"), "GEXP", 4)) { + WC->last_pager_check = time(NULL); + } +} + + +/** + * \brief Helper function for the asynchronous check to see if we need + * to open the instant messenger window. + */ +void seconds_since_last_gexp(void) +{ + char buf[256]; + + begin_ajax_response(); + if ( (time(NULL) - WC->last_pager_check) < 30) { + wprintf("NO\n"); + } + else { + serv_puts("NOOP"); + serv_getln(buf, sizeof buf); + if (buf[3] == '*') { + wprintf("YES"); + } + else { + wprintf("NO"); + } + } + end_ajax_response(); +} + + + + +/** + * \brief Entry point for WebCit transaction */ void session_loop(struct httprequest *req) { - char cmd[SIZ]; - char method[SIZ]; - char action[SIZ]; + char cmd[1024]; + char action[1024]; + char arg1[128]; + char arg2[128]; + char arg3[128]; + char arg4[128]; + char arg5[128]; + char arg6[128]; + char arg7[128]; char buf[SIZ]; + char request_method[128]; + char pathname[1024]; int a, b; int ContentLength = 0; int BytesRead = 0; char ContentType[512]; - char *content; - char *content_end; + char *content = NULL; + char *content_end = NULL; struct httprequest *hptr; - char browser_host[SIZ]; - char user_agent[SIZ]; - int body_start; + char browser_host[256]; + char user_agent[256]; + int body_start = 0; + int is_static = 0; - /* We stuff these with the values coming from the client cookies, + /** + * We stuff these with the values coming from the client cookies, * so we can use them to reconnect a timed out session if we have to. */ char c_username[SIZ]; @@ -841,40 +1022,83 @@ void session_loop(struct httprequest *req) char c_httpauth_pass[SIZ]; char cookie[SIZ]; - strcpy(c_username, ""); - strcpy(c_password, ""); - strcpy(c_roomname, ""); - strcpy(c_httpauth_string, ""); - strcpy(c_httpauth_user, ""); - strcpy(c_httpauth_pass, ""); + safestrncpy(c_username, "", sizeof c_username); + safestrncpy(c_password, "", sizeof c_password); + safestrncpy(c_roomname, "", sizeof c_roomname); + safestrncpy(c_httpauth_string, "", sizeof c_httpauth_string); + safestrncpy(c_httpauth_user, DEFAULT_HTTPAUTH_USER, sizeof c_httpauth_user); + safestrncpy(c_httpauth_pass, DEFAULT_HTTPAUTH_PASS, sizeof c_httpauth_pass); + strcpy(browser_host, ""); WC->upload_length = 0; WC->upload = NULL; WC->vars = NULL; - WC->is_wap = 0; hptr = req; if (hptr == NULL) return; - strcpy(cmd, hptr->line); + safestrncpy(cmd, hptr->line, sizeof cmd); hptr = hptr->next; - extract_token(method, cmd, 0, ' '); - extract_action(action, cmd); + extract_token(request_method, cmd, 0, ' ', sizeof request_method); + extract_token(pathname, cmd, 1, ' ', sizeof pathname); + + /** Figure out the action */ + extract_token(action, pathname, 1, '/', sizeof action); + if (strstr(action, "?")) *strstr(action, "?") = 0; + if (strstr(action, "&")) *strstr(action, "&") = 0; + if (strstr(action, " ")) *strstr(action, " ") = 0; + + extract_token(arg1, pathname, 2, '/', sizeof arg1); + if (strstr(arg1, "?")) *strstr(arg1, "?") = 0; + if (strstr(arg1, "&")) *strstr(arg1, "&") = 0; + if (strstr(arg1, " ")) *strstr(arg1, " ") = 0; + + extract_token(arg2, pathname, 3, '/', sizeof arg2); + if (strstr(arg2, "?")) *strstr(arg2, "?") = 0; + if (strstr(arg2, "&")) *strstr(arg2, "&") = 0; + if (strstr(arg2, " ")) *strstr(arg2, " ") = 0; + + extract_token(arg3, pathname, 4, '/', sizeof arg3); + if (strstr(arg3, "?")) *strstr(arg3, "?") = 0; + if (strstr(arg3, "&")) *strstr(arg3, "&") = 0; + if (strstr(arg3, " ")) *strstr(arg3, " ") = 0; + + extract_token(arg4, pathname, 5, '/', sizeof arg4); + if (strstr(arg4, "?")) *strstr(arg4, "?") = 0; + if (strstr(arg4, "&")) *strstr(arg4, "&") = 0; + if (strstr(arg4, " ")) *strstr(arg4, " ") = 0; + + extract_token(arg5, pathname, 6, '/', sizeof arg5); + if (strstr(arg5, "?")) *strstr(arg5, "?") = 0; + if (strstr(arg5, "&")) *strstr(arg5, "&") = 0; + if (strstr(arg5, " ")) *strstr(arg5, " ") = 0; + + extract_token(arg6, pathname, 7, '/', sizeof arg6); + if (strstr(arg6, "?")) *strstr(arg6, "?") = 0; + if (strstr(arg6, "&")) *strstr(arg6, "&") = 0; + if (strstr(arg6, " ")) *strstr(arg6, " ") = 0; + + extract_token(arg7, pathname, 8, '/', sizeof arg7); + if (strstr(arg7, "?")) *strstr(arg7, "?") = 0; + if (strstr(arg7, "&")) *strstr(arg7, "&") = 0; + if (strstr(arg7, " ")) *strstr(arg7, " ") = 0; while (hptr != NULL) { - strcpy(buf, hptr->line); + safestrncpy(buf, hptr->line, sizeof buf); hptr = hptr->next; if (!strncasecmp(buf, "Cookie: webcit=", 15)) { safestrncpy(cookie, &buf[15], sizeof cookie); cookie_to_stuff(cookie, NULL, - c_username, c_password, c_roomname); + c_username, sizeof c_username, + c_password, sizeof c_password, + c_roomname, sizeof c_roomname); } else if (!strncasecmp(buf, "Authorization: Basic ", 21)) { CtdlDecodeBase64(c_httpauth_string, &buf[21], strlen(&buf[21])); - extract_token(c_httpauth_user, c_httpauth_string, 0, ':'); - extract_token(c_httpauth_pass, c_httpauth_string, 1, ':'); + extract_token(c_httpauth_user, c_httpauth_string, 0, ':', sizeof c_httpauth_user); + extract_token(c_httpauth_pass, c_httpauth_string, 1, ':', sizeof c_httpauth_pass); } else if (!strncasecmp(buf, "Content-length: ", 16)) { ContentLength = atoi(&buf[16]); @@ -888,7 +1112,14 @@ void session_loop(struct httprequest *req) else if (!strncasecmp(buf, "Host: ", 6)) { safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host); } - /* Only WAP gateways explicitly name this content-type */ + else if (!strncasecmp(buf, "X-Forwarded-For: ", 17)) { + safestrncpy(browser_host, &buf[17], sizeof browser_host); + while (num_tokens(browser_host, ',') > 1) { + remove_token(browser_host, 0, ','); + } + striplt(browser_host); + } + /** Only WAP gateways explicitly name this content-type */ else if (strstr(buf, "text/vnd.wap.wml")) { WC->is_wap = 1; } @@ -902,7 +1133,7 @@ void session_loop(struct httprequest *req) ContentType, ContentLength); body_start = strlen(content); - /* Be daring and read it all at once. */ + /** Read the entire input data at once. */ client_read(WC->http_sock, &content[BytesRead+body_start], ContentLength); @@ -918,12 +1149,12 @@ void session_loop(struct httprequest *req) content = NULL; } - /* make a note of where we are in case the user wants to save it */ + /** make a note of where we are in case the user wants to save it */ safestrncpy(WC->this_page, cmd, sizeof(WC->this_page)); remove_token(WC->this_page, 2, ' '); remove_token(WC->this_page, 0, ' '); - /* If there are variables in the URL, we must grab them now */ + /** If there are variables in the URL, we must grab them now */ for (a = 0; a < strlen(cmd); ++a) { if ((cmd[a] == '?') || (cmd[a] == '&')) { for (b = a; b < strlen(cmd); ++b) @@ -934,17 +1165,32 @@ void session_loop(struct httprequest *req) } } - /* Static content can be sent without connecting to Citadel. */ - if (!strcasecmp(action, "static")) { - strcpy(buf, &cmd[12]); - for (a = 0; a < strlen(buf); ++a) - if (isspace(buf[a])) + + /** Static content can be sent without connecting to Citadel. */ + is_static = 0; + for (a=0; a<(sizeof(static_content_dirs) / sizeof(char *)); ++a) { + if (!strcasecmp(action, static_content_dirs[a])) { + is_static = 1; + } + } + if (is_static) { + snprintf(buf, sizeof buf, "%s/%s/%s/%s/%s/%s/%s/%s", + action, arg1, arg2, arg3, arg4, arg5, arg6, arg7); + for (a=0; a<8; ++a) { + if (buf[strlen(buf)-1] == '/') { + buf[strlen(buf)-1] = 0; + } + } + for (a = 0; a < strlen(buf); ++a) { + if (isspace(buf[a])) { buf[a] = 0; + } + } output_static(buf); goto SKIP_ALL_THIS_CRAP; /* Don't try to connect */ } - /* + /** * If we're not connected to a Citadel server, try to hook up the * connection now. */ @@ -965,15 +1211,25 @@ void session_loop(struct httprequest *req) } else { WC->connected = 1; - serv_gets(buf); /* get the server welcome message */ - locate_host(browser_host, WC->http_sock); + serv_getln(buf, sizeof buf); /** get the server welcome message */ + + /** + * From what host is our user connecting? Go with + * the host at the other end of the HTTP socket, + * unless we are following X-Forwarded-For: headers + * and such a header has already turned up something. + */ + if ( (!follow_xff) || (strlen(browser_host) == 0) ) { + locate_host(browser_host, WC->http_sock); + } + get_serv_info(browser_host, user_agent); if (serv_info.serv_rev_level < MINIMUM_CIT_VERSION) { - wprintf("You are connected to a Citadel " - "server running Citadel %d.%02d;\nin " - "order to run this version of WebCit " + wprintf(_("You are connected to a Citadel " + "server running Citadel %d.%02d. \n" + "In order to run this version of WebCit " "you must also have Citadel %d.%02d or" - " newer.\n\n\n", + " newer.\n\n\n"), serv_info.serv_rev_level / 100, serv_info.serv_rev_level % 100, MINIMUM_CIT_VERSION / 100, @@ -985,7 +1241,7 @@ void session_loop(struct httprequest *req) } } - /* + /** * Functions which can be performed without logging in */ if (!strcasecmp(action, "listsub")) { @@ -999,76 +1255,107 @@ void session_loop(struct httprequest *req) } #endif - /* + /** * If we're not logged in, but we have HTTP Authentication data, * try logging in to Citadel using that. */ - if ((!WC->logged_in) && (strlen(c_httpauth_user) > 0) && (strlen(c_httpauth_pass) > 0)) { + if ((!WC->logged_in) + && (strlen(c_httpauth_user) > 0) + && (strlen(c_httpauth_pass) > 0)) { serv_printf("USER %s", c_httpauth_user); - serv_gets(buf); + serv_getln(buf, sizeof buf); if (buf[0] == '3') { serv_printf("PASS %s", c_httpauth_pass); - serv_gets(buf); + serv_getln(buf, sizeof buf); if (buf[0] == '2') { - become_logged_in(c_httpauth_user, c_httpauth_pass, buf); - strcpy(WC->httpauth_user, c_httpauth_user); - strcpy(WC->httpauth_pass, c_httpauth_pass); + become_logged_in(c_httpauth_user, + 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"), request_method); + goto SKIP_ALL_THIS_CRAP; + } + + /** * The GroupDAV stuff relies on HTTP authentication instead of * our session's authentication. */ if (!strncasecmp(action, "groupdav", 8)) { - groupdav_main(req); + groupdav_main(req, ContentType, /* do GroupDAV methods */ + ContentLength, content+body_start); + if (!WC->logged_in) { + WC->killthis = 1; /* If not logged in, don't */ + } /* keep the session active */ goto SKIP_ALL_THIS_CRAP; } - check_for_instant_messages(); - /* + /** + * Automatically send requests with any method other than GET or + * POST to the GroupDAV code as well. + */ + if ((strcasecmp(request_method, "GET")) && (strcasecmp(request_method, "POST"))) { + groupdav_main(req, ContentType, /** do GroupDAV methods */ + ContentLength, content+body_start); + if (!WC->logged_in) { + WC->killthis = 1; /** If not logged in, don't */ + } /** keep the session active */ + goto SKIP_ALL_THIS_CRAP; + } + + /** * If we're not logged in, but we have username and password cookies * supplied by the browser, try using them to log in. */ - if ((!WC->logged_in) && (strlen(c_username) > 0) && (strlen(c_password) > 0)) { + if ((!WC->logged_in) + && (strlen(c_username) > 0) + && (strlen(c_password) > 0)) { serv_printf("USER %s", c_username); - serv_gets(buf); + serv_getln(buf, sizeof buf); if (buf[0] == '3') { serv_printf("PASS %s", c_password); - serv_gets(buf); + serv_getln(buf, sizeof buf); if (buf[0] == '2') { become_logged_in(c_username, c_password, buf); } } } - /* + /** * If we don't have a current room, but a cookie specifying the * current room is supplied, make an effort to go there. */ if ((strlen(WC->wc_roomname) == 0) && (strlen(c_roomname) > 0)) { serv_printf("GOTO %s", c_roomname); - serv_gets(buf); + serv_getln(buf, sizeof buf); if (buf[0] == '2') { - strcpy(WC->wc_roomname, c_roomname); + safestrncpy(WC->wc_roomname, c_roomname, sizeof WC->wc_roomname); } } if (!strcasecmp(action, "image")) { output_image(); - /* - * All functions handled below this point ... make sure we log in - * before doing anything else! - */ + /** + * All functions handled below this point ... make sure we log in + * before doing anything else! + */ } else if ((!WC->logged_in) && (!strcasecmp(action, "login"))) { do_login(); } else if (!WC->logged_in) { display_login(NULL); } - /* + /** * Various commands... */ @@ -1078,10 +1365,26 @@ void session_loop(struct httprequest *req) blank_page(); } else if (!strcasecmp(action, "do_template")) { url_do_template(); + } else if (!strcasecmp(action, "display_aide_menu")) { + display_aide_menu(); } else if (!strcasecmp(action, "display_main_menu")) { display_main_menu(); - } else if (!strcasecmp(action, "whobbs")) { - whobbs(); + } else if (!strcasecmp(action, "who")) { + who(); + } else if (!strcasecmp(action, "sslg")) { + seconds_since_last_gexp(); + } else if (!strcasecmp(action, "who_inner_html")) { + begin_ajax_response(); + who_inner_div(); + end_ajax_response(); + } else if (!strcasecmp(action, "iconbar_ajax_menu")) { + begin_ajax_response(); + do_iconbar(); + end_ajax_response(); + } else if (!strcasecmp(action, "iconbar_ajax_rooms")) { + begin_ajax_response(); + do_iconbar_roomlist(); + end_ajax_response(); } else if (!strcasecmp(action, "knrooms")) { knrooms(); } else if (!strcasecmp(action, "gotonext")) { @@ -1092,7 +1395,9 @@ void session_loop(struct httprequest *req) } else if (!strcasecmp(action, "ungoto")) { ungoto(); } else if (!strcasecmp(action, "dotgoto")) { - slrp_highest(); + if (WC->wc_view != VIEW_MAILBOX) { /* dotgoto acts like dotskip when we're in a mailbox view */ + slrp_highest(); + } smart_goto(bstr("room")); } else if (!strcasecmp(action, "dotskip")) { smart_goto(bstr("room")); @@ -1106,14 +1411,22 @@ void session_loop(struct httprequest *req) readloop("readfwd"); } else if (!strcasecmp(action, "headers")) { readloop("headers"); + } else if (!strcasecmp(action, "msg")) { + embed_message(arg1); + } else if (!strcasecmp(action, "printmsg")) { + print_message(arg1); + } else if (!strcasecmp(action, "msgheaders")) { + display_headers(arg1); + } else if (!strcasecmp(action, "wiki")) { + display_wiki_page(); } else if (!strcasecmp(action, "display_enter")) { display_enter(); } else if (!strcasecmp(action, "post")) { post_message(); - } else if (!strcasecmp(action, "do_stuff_to_one_msg")) { - do_stuff_to_one_msg(); } else if (!strcasecmp(action, "move_msg")) { move_msg(); + } else if (!strcasecmp(action, "delete_msg")) { + delete_msg(); } else if (!strcasecmp(action, "userlist")) { userlist(); } else if (!strcasecmp(action, "showuser")) { @@ -1138,39 +1451,41 @@ void session_loop(struct httprequest *req) display_entroom(); } else if (!strcasecmp(action, "entroom")) { entroom(); + } else if (!strcasecmp(action, "display_whok")) { + display_whok(); + } else if (!strcasecmp(action, "do_invt_kick")) { + do_invt_kick(); } else if (!strcasecmp(action, "display_editroom")) { display_editroom(); } else if (!strcasecmp(action, "netedit")) { netedit(); } else if (!strcasecmp(action, "editroom")) { editroom(); - } else if (!strcasecmp(action, "display_whok")) { - display_whok(); } else if (!strcasecmp(action, "display_editinfo")) { - display_edit("Room info", "EINF 0", "RINF", "/editinfo", 1); + display_edit(_("Room info"), "EINF 0", "RINF", "/editinfo", 1); } else if (!strcasecmp(action, "editinfo")) { - save_edit("Room info", "EINF 1", 1); + save_edit(_("Room info"), "EINF 1", 1); } else if (!strcasecmp(action, "display_editbio")) { - sprintf(buf, "RBIO %s", WC->wc_username); - display_edit("Your bio", "NOOP", buf, "editbio", 3); + sprintf(buf, "RBIO %s", WC->wc_fullname); + display_edit(_("Your bio"), "NOOP", buf, "editbio", 3); } else if (!strcasecmp(action, "editbio")) { - save_edit("Your bio", "EBIO", 0); - } else if (!strcasecmp(action, "confirm_delete_room")) { - confirm_delete_room(); + save_edit(_("Your bio"), "EBIO", 0); + } else if (!strcasecmp(action, "confirm_move_msg")) { + confirm_move_msg(); } else if (!strcasecmp(action, "delete_room")) { delete_room(); } else if (!strcasecmp(action, "validate")) { validate(); } else if (!strcasecmp(action, "display_editpic")) { - display_graphics_upload("your photo", + display_graphics_upload(_("your photo"), "UIMG 0|_userpic_", - "/editpic"); + "editpic"); } else if (!strcasecmp(action, "editpic")) { do_graphics_upload("UIMG 1|_userpic_"); } else if (!strcasecmp(action, "display_editroompic")) { - display_graphics_upload("the graphic for this room", + display_graphics_upload(_("the icon for this room"), "UIMG 0|_roompic_", - "/editroompic"); + "editroompic"); } else if (!strcasecmp(action, "editroompic")) { do_graphics_upload("UIMG 1|_roompic_"); } else if (!strcasecmp(action, "delete_floor")) { @@ -1182,9 +1497,9 @@ void session_loop(struct httprequest *req) } else if (!strcasecmp(action, "display_editfloorpic")) { sprintf(buf, "UIMG 0|_floorpic_|%s", bstr("which_floor")); - display_graphics_upload("the graphic for this floor", + display_graphics_upload(_("the icon for this floor"), buf, - "/editfloorpic"); + "editfloorpic"); } else if (!strcasecmp(action, "editfloorpic")) { sprintf(buf, "UIMG 1|_floorpic_|%s", bstr("which_floor")); @@ -1226,10 +1541,12 @@ void session_loop(struct httprequest *req) display_generic(); } else if (!strcasecmp(action, "do_generic")) { do_generic(); + } else if (!strcasecmp(action, "ajax_servcmd")) { + ajax_servcmd(); } else if (!strcasecmp(action, "display_menubar")) { display_menubar(1); - } else if (!strcasecmp(action, "output_mimepart")) { - output_mimepart(); + } else if (!strcasecmp(action, "mimepart")) { + mimepart(arg1, arg2); } else if (!strcasecmp(action, "edit_vcard")) { edit_vcard(); } else if (!strcasecmp(action, "submit_vcard")) { @@ -1244,8 +1561,6 @@ void session_loop(struct httprequest *req) create_user(); } else if (!strcasecmp(action, "changeview")) { change_view(); - } else if (!strcasecmp(action, "do_stuff_to_msgs")) { - do_stuff_to_msgs(); } else if (!strcasecmp(action, "change_start_page")) { change_start_page(); } else if (!strcasecmp(action, "display_floorconfig")) { @@ -1268,8 +1583,10 @@ void session_loop(struct httprequest *req) #endif } else if (!strcasecmp(action, "summary")) { summary(); - } else if (!strcasecmp(action, "iconbar")) { - do_iconbar(); + } else if (!strcasecmp(action, "summary_inner_div")) { + begin_ajax_response(); + summary_inner_div(); + end_ajax_response(); } else if (!strcasecmp(action, "display_customize_iconbar")) { display_customize_iconbar(); } else if (!strcasecmp(action, "commit_iconbar")) { @@ -1280,10 +1597,23 @@ void session_loop(struct httprequest *req) display_inetconf(); } else if (!strcasecmp(action, "save_inetconf")) { save_inetconf(); + } else if (!strcasecmp(action, "setup_wizard")) { + do_setup_wizard(); + } else if (!strcasecmp(action, "display_preferences")) { + display_preferences(); + } else if (!strcasecmp(action, "set_preferences")) { + set_preferences(); + } else if (!strcasecmp(action, "recp_autocomplete")) { + recp_autocomplete(bstr("recp")); + } else if (!strcasecmp(action, "cc_autocomplete")) { + recp_autocomplete(bstr("cc")); + } else if (!strcasecmp(action, "bcc_autocomplete")) { + recp_autocomplete(bstr("bcc")); + } else if (!strcasecmp(action, "set_floordiv_expanded")) { + set_floordiv_expanded(arg1); } else if (!strcasecmp(action, "diagnostics")) { - output_headers(1, 1, 1, 0, 0, 0, 0); - - wprintf("You're in session %d
\n", WC->wc_session); + output_headers(1, 1, 1, 0, 0, 0); + wprintf("Session: %d
\n", WC->wc_session); wprintf("Command:
\n");
 		escputs(cmd);
 		wprintf("

\n"); @@ -1292,7 +1622,8 @@ void session_loop(struct httprequest *req) wprintf("
\n"); wDumpContent(1); } - /* When all else fais, display the main menu. */ + + /** When all else fais, display the main menu. */ else { display_main_menu(); } @@ -1308,5 +1639,7 @@ SKIP_ALL_THIS_CRAP: free(WC->upload); WC->upload_length = 0; } - } + + +/*@}*/