X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fwebcit.c;h=71b780a76a4c3d6b7d78f9bb5c43c597846c1967;hb=4173c5f13716fb5658deaa4046c5b3d99682e413;hp=c58876f9b473e6e2039101342def2018b5802803;hpb=96d09185cc9b946d17dc7061508208583dcb493b;p=citadel.git diff --git a/webcit/webcit.c b/webcit/webcit.c index c58876f9b..71b780a76 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -1,41 +1,46 @@ /* * $Id$ - * - * This is the main transaction loop of the web service. It maintains a + */ +/** + * \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 WebcitHttpServer */ - +/*@{*/ #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", - "tiny_mce" -}; +#include +#include -/* +/** * 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; char hex[3]; + long buflen; + + buflen = strlen(buf); - while ((isspace(buf[strlen(buf) - 1])) && (strlen(buf) > 0)) - buf[strlen(buf) - 1] = 0; + while ((buflen > 0) && (isspace(buf[buflen - 1]))){ + buf[buflen - 1] = 0; + buflen --; + } - for (a = 0; a < strlen(buf); ++a) { + a = 0; + while (a < buflen) { if (buf[a] == '+') buf[a] = ' '; if (buf[a] == '%') { @@ -45,24 +50,30 @@ void unescape_input(char *buf) b = 0; sscanf(hex, "%02x", &b); buf[a] = (char) b; - strcpy(&buf[a + 1], &buf[a + 3]); + memmove(&buf[a + 1], &buf[a + 3], buflen - a - 2); + + buflen -=2; } + a++; } } - +/** + * \brief Extract variables from the URL. + * \param url URL supplied by the HTTP parser + */ void addurls(char *url) { char *up, *ptr; char buf[SIZ]; - int a, b; + int a, b, len; struct urlcontent *u; up = url; - while (strlen(up) > 0) { + while (!IsEmptyStr(up)) { - /* locate the = sign */ + /** locate the = sign */ safestrncpy(buf, up, sizeof buf); b = (-1); for (a = 255; a >= 0; --a) @@ -77,34 +88,38 @@ void addurls(char *url) WC->urlstrings = u; 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) { + len = b = strlen(up); + for (a = 0; a < len; ++a) { if ( (ptr[0] == '&') || (ptr[0] == '?') ) { b = a; break; } ++ptr; } - ptr = up; - for (a = 0; a < b; ++a) - ++ptr; - strcpy(ptr, ""); + ptr = up + b; + *ptr = '\0'; - u->url_data = malloc(strlen(up) + 2); - safestrncpy(u->url_data, up, strlen(up) + 1); + len = b; + u->url_data = malloc(len + 2); + safestrncpy(u->url_data, up, b + 1); u->url_data[b] = 0; unescape_input(u->url_data); up = ptr; ++up; + + /* lprintf(9, "%s = %s\n", u->url_key, u->url_data); */ } } +/** + * \brief free urlstring memory + */ void free_urls(void) { struct urlcontent *u; @@ -117,8 +132,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) { @@ -129,6 +144,10 @@ void dump_vars(void) } } +/** + * \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) { struct urlcontent *u; @@ -140,7 +159,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; @@ -154,10 +177,10 @@ 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. */ @@ -175,153 +198,268 @@ void wDumpContent(int print_standard_html_footer) } -/* - * 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 + * \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) +long stresc(char *target, long tSize, char *strbuf, int nbsp, int nolinebreaks) { - int a; - strcpy(target, ""); - - for (a = 0; a < strlen(strbuf); ++a) { - if (strbuf[a] == '<') - strcat(target, "<"); - else if (strbuf[a] == '>') - strcat(target, ">"); - else if (strbuf[a] == '&') - strcat(target, "&"); - else if (strbuf[a] == '\"') - strcat(target, """); - else if (strbuf[a] == '\'') - strcat(target, "'"); - else if (strbuf[a] == LB) - strcat(target, "<"); - else if (strbuf[a] == RB) - strcat(target, ">"); - else if (strbuf[a] == QU) - strcat(target, "\""); - else if ((strbuf[a] == 32) && (nbsp == 1)) - strcat(target, " "); - else if ((strbuf[a] == '\n') && (nolinebreaks)) - strcat(target, ""); /* nothing */ - else if ((strbuf[a] == '\r') && (nolinebreaks)) - strcat(target, ""); /* nothing */ - else - strncat(target, &strbuf[a], 1); + char *aptr, *bptr, *eptr; + + *target = '\0'; + aptr = strbuf; + bptr = target; + eptr = target + tSize - 6; // our biggest unit to put in... + + while ((bptr < eptr) && !IsEmptyStr(aptr) ){ + if (*aptr == '<') { + memcpy(bptr, "<", 4); + bptr += 4; + } + else if (*aptr == '>') { + memcpy(bptr, ">", 4); + bptr += 4; + } + else if (*aptr == '&') { + memcpy(bptr, "&", 5); + bptr += 5; + } + else if (*aptr == '\"') { + memcpy(bptr, """, 6); + bptr += 6; + } + else if (*aptr == '\'') { + memcpy(bptr, "'", 5); + bptr += 5; + } + else if (*aptr == LB) { + *bptr = '<'; + bptr ++; + } + else if (*aptr == RB) { + *bptr = '>'; + bptr ++; + } + else if (*aptr == QU) { + *bptr ='"'; + bptr ++; + } + else if ((*aptr == 32) && (nbsp == 1)) { + memcpy(bptr, " ", 6); + bptr += 6; + } + else if ((*aptr == '\n') && (nolinebreaks)) { + *bptr='\0'; /* nothing */ + } + else if ((*aptr == '\r') && (nolinebreaks)) { + *bptr='\0'; /* nothing */ + } + else{ + *bptr = *aptr; + bptr++; + } + aptr ++; } + *bptr = '\0'; + if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) ) + return -1; + return (bptr - target); } +/** + * \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; + long Siz; if (strbuf == NULL) return; - buf = malloc( (3 * strlen(strbuf)) + SIZ ); - stresc(buf, strbuf, nbsp, nolinebreaks); + Siz = (3 * strlen(strbuf)) + SIZ ; + buf = malloc(Siz); + stresc(buf, Siz, strbuf, nbsp, nolinebreaks); wprintf("%s", buf); 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. - * Returns a pointer to a buffer that must be freed by the caller! - */ -void urlesc(char *outbuf, char *strbuf) -{ - int a, b, c; - char *ec = " #&;`'|*?-~<>^()[]{}$\"\\"; - - strcpy(outbuf, ""); - - for (a = 0; a < strlen(strbuf); ++a) { - c = 0; - for (b = 0; b < strlen(ec); ++b) { - if (strbuf[a] == ec[b]) - c = 1; - } - b = strlen(outbuf); - if (c == 1) - sprintf(&outbuf[b], "%%%02x", strbuf[a]); - else - sprintf(&outbuf[b], "%c", strbuf[a]); - } -} +/** + * \brief urlescape buffer and print it to the client + * \param strbuf buffer to urlescape + */ void urlescputs(char *strbuf) { char outbuf[SIZ]; - urlesc(outbuf, strbuf); + urlesc(outbuf, SIZ, strbuf); wprintf("%s", outbuf); } -/* - * 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) +void jsesc(char *target, size_t tlen, char *strbuf) { - int a; - strcpy(target, ""); - - for (a = 0; a < strlen(strbuf); ++a) { - if (strbuf[a] == '<') - strcat(target, "["); - else if (strbuf[a] == '>') - strcat(target, "]"); - else if (strbuf[a] == '\"') - strcat(target, """); - else if (strbuf[a] == '&') - strcat(target, "&;"); - else if (strbuf[a] == '\'') - strcat(target, "\\'"); - else { - strncat(target, &strbuf[a], 1); + int len; + char *tend; + char *send; + char *tptr; + char *sptr; + + target[0]='\0'; + len = strlen (strbuf); + send = strbuf + len; + tend = target + tlen; + sptr = strbuf; + tptr = target; + + while (!IsEmptyStr(sptr) && + (sptr < send) && + (tptr < tend)) { + + if (*sptr == '<') + *tptr = '['; + else if (*sptr == '>') + *tptr = ']'; + else if (*sptr == '\'') { + if (tend - tptr < 3) + return; + *(tptr++) = '\\'; + *tptr = '\''; + } + else if (*sptr == '"') { + if (tend - tptr < 8) + return; + *(tptr++) = '&'; + *(tptr++) = 'q'; + *(tptr++) = 'u'; + *(tptr++) = 'o'; + *(tptr++) = 't'; + *tptr = ';'; + } + else if (*sptr == '&') { + if (tend - tptr < 7) + return; + *(tptr++) = '&'; + *(tptr++) = 'a'; + *(tptr++) = 'm'; + *(tptr++) = 'p'; + *tptr = ';'; + } else { + *tptr = *sptr; } + tptr++; sptr++; } + *tptr = '\0'; } +/** + * \brief escape and print java script + * \param strbuf the js code + */ void jsescputs(char *strbuf) { char outbuf[SIZ]; - jsesc(outbuf, strbuf); + jsesc(outbuf, SIZ, 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) +void msgesc(char *target, size_t tlen, char *strbuf) { - int a; - strcpy(target, ""); - - for (a = 0; a < strlen(strbuf); ++a) { - 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); + int len; + char *tend; + char *send; + char *tptr; + char *sptr; + + target[0]='\0'; + len = strlen (strbuf); + send = strbuf + len; + tend = target + tlen; + sptr = strbuf; + tptr = target; + + while (!IsEmptyStr(sptr) && + (sptr < send) && + (tptr < tend)) { + + if (*sptr == '\n') + *tptr = ' '; + else if (*sptr == '\r') + *tptr = ' '; + else if (*sptr == '\'') { + if (tend - tptr < 8) + return; + *(tptr++) = '&'; + *(tptr++) = '#'; + *(tptr++) = '3'; + *(tptr++) = '9'; + *tptr = ';'; + } else { + *tptr = *sptr; } + tptr++; sptr++; } + *tptr = '\0'; +} + +/** + * \brief print a string to the client after cleaning it with msgesc() and stresc() + * \param strbuf string to be printed + */ +void msgescputs1( char *strbuf) +{ + char *outbuf; + char *outbuf2; + int buflen; + + if (strbuf == NULL) return; + buflen = 3 * strlen(strbuf) + SIZ; + outbuf = malloc( buflen); + outbuf2 = malloc( buflen); + msgesc(outbuf, buflen, strbuf); + stresc(outbuf2, buflen, outbuf, 0, 0); + wprintf("%s", outbuf2); + free(outbuf); + free(outbuf2); } +/** + * \brief print a string to the client after cleaning it with msgesc() + * \param strbuf string to be printed + */ void msgescputs(char *strbuf) { char *outbuf; + size_t len; if (strbuf == NULL) return; - outbuf = malloc( (3 * strlen(strbuf)) + SIZ); - msgesc(outbuf, strbuf); + len = (3 * strlen(strbuf)) + SIZ; + outbuf = malloc(len); + msgesc(outbuf, len, strbuf); wprintf("%s", outbuf); free(outbuf); } @@ -329,31 +467,32 @@ 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 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]; + 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" "Server: %s / %s\n" "Connection: close\r\n", - SERVER, serv_info.serv_software + PACKAGE_STRING, serv_info.serv_software ); } @@ -367,10 +506,11 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers else { wprintf("Pragma: no-cache\r\n" "Cache-Control: no-store\r\n" + "Expires: -1\r\n" ); } - stuff_to_cookie(cookie, WC->wc_session, WC->wc_username, + stuff_to_cookie(cookie, 1024, WC->wc_session, WC->wc_username, WC->wc_password, WC->wc_roomname); if (unset_cookies) { @@ -384,32 +524,39 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers if (do_htmlhead) { begin_burst(); + if (!access("static.local/webcit.css", R_OK)) { + svprintf("CSSLOCAL", WCS_STRING, + "" + ); + } do_template("head"); } - /* ICONBAR */ + /** ICONBAR */ if (do_htmlhead) { - if (WC->HaveInstantMessages) { - wprintf("
\n"); - page_popup(); - wprintf("
\n"); - } - if (strlen(WC->ImportantMessage) > 0) { - wprintf("
\n"); - wprintf("" - "%s
\n", WC->ImportantMessage); - wprintf("
\n"); - wprintf("\n"); - safestrncpy(WC->ImportantMessage, "", sizeof WC->ImportantMessage); + WC->ImportantMessage[0] = 0; } + 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); @@ -423,8 +570,9 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers } -/* - * 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.1 302 Moved Temporarily\n"); @@ -438,20 +586,8 @@ void http_redirect(char *whichpage) { -void check_for_instant_messages() -{ - char buf[SIZ]; - - serv_puts("NOOP"); - serv_getln(buf, sizeof 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) { @@ -462,15 +598,15 @@ void http_transmit_thing(char *thing, size_t length, char *content_type, "Server: %s\r\n" "Connection: close\r\n", content_type, - SERVER); + PACKAGE_STRING); #ifdef HAVE_ZLIB - /* If we can send the data out compressed, please do so. */ + /** If we can send the data out compressed, please do so. */ if (WC->gzip_ok) { char *compressed_data = NULL; - uLongf compressed_len; + size_t compressed_len; - compressed_len = (uLongf) ((length * 101) / 100) + 100; + compressed_len = ((length * 101) / 100) + 100; compressed_data = malloc(compressed_len); if (compress_gzip((Bytef *) compressed_data, @@ -489,7 +625,7 @@ void http_transmit_thing(char *thing, size_t length, char *content_type, } #endif - /* No compression ... just send it out as-is */ + /** No compression ... just send it out as-is */ wprintf("Content-length: %ld\r\n" "\r\n", (long) length @@ -497,60 +633,125 @@ void http_transmit_thing(char *thing, size_t length, char *content_type, client_write(thing, (size_t)length); } +/** + * \brief print menu box like used in the floor view or admin interface. + * This function takes pair of strings as va_args, + * \param Title Title string of the box + * \param Class CSS Class for the box + * \param nLines How many string pairs should we print? (URL, UrlText) + * \param ... Pairs of URL Strings and their Names + */ +void print_menu_box(char* Title, char *Class, int nLines, ...) +{ + va_list arg_list; + long i; + + svprintf("BOXTITLE", WCS_STRING, Title); + do_template("beginbox"); + + wprintf(""); + + do_template("endbox"); +} - +/** + * \brief dump out static pages from disk + * \param what the file urs to print + */ void output_static(char *what) { FILE *fp; struct stat statbuf; off_t bytes; + off_t count = 0; + size_t res; char *bigbuffer; char content_type[128]; + int len; fp = fopen(what, "rb"); if (fp == NULL) { lprintf(9, "output_static('%s') -- NOT FOUND --\n", what); - wprintf("HTTP/1.1 404 %s\n", strerror(errno)); + wprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); wprintf("Content-Type: text/plain\r\n"); wprintf("\r\n"); - wprintf("Cannot open %s: %s\n", what, strerror(errno)); + wprintf("Cannot open %s: %s\r\n", what, strerror(errno)); } else { - if (!strncasecmp(&what[strlen(what) - 4], ".gif", 4)) + len = strlen (what); + if (!strncasecmp(&what[len - 4], ".gif", 4)) safestrncpy(content_type, "image/gif", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".txt", 4)) + else if (!strncasecmp(&what[len - 4], ".txt", 4)) safestrncpy(content_type, "text/plain", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".css", 4)) + else if (!strncasecmp(&what[len - 4], ".css", 4)) safestrncpy(content_type, "text/css", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".jpg", 4)) + else if (!strncasecmp(&what[len - 4], ".jpg", 4)) safestrncpy(content_type, "image/jpeg", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".png", 4)) + else if (!strncasecmp(&what[len - 4], ".png", 4)) safestrncpy(content_type, "image/png", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".ico", 4)) + else if (!strncasecmp(&what[len - 4], ".ico", 4)) safestrncpy(content_type, "image/x-icon", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 5], ".html", 5)) + else if (!strncasecmp(&what[len - 5], ".html", 5)) safestrncpy(content_type, "text/html", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".htm", 4)) + else if (!strncasecmp(&what[len - 4], ".htm", 4)) safestrncpy(content_type, "text/html", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".wml", 4)) + else if (!strncasecmp(&what[len - 4], ".wml", 4)) safestrncpy(content_type, "text/vnd.wap.wml", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 5], ".wmls", 5)) + else if (!strncasecmp(&what[len - 5], ".wmls", 5)) safestrncpy(content_type, "text/vnd.wap.wmlscript", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 5], ".wmlc", 5)) + else if (!strncasecmp(&what[len - 5], ".wmlc", 5)) safestrncpy(content_type, "application/vnd.wap.wmlc", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 6], ".wmlsc", 6)) + else if (!strncasecmp(&what[len - 6], ".wmlsc", 6)) safestrncpy(content_type, "application/vnd.wap.wmlscriptc", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 5], ".wbmp", 5)) + else if (!strncasecmp(&what[len - 5], ".wbmp", 5)) safestrncpy(content_type, "image/vnd.wap.wbmp", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 3], ".js", 3)) + else if (!strncasecmp(&what[len - 3], ".js", 3)) safestrncpy(content_type, "text/javascript", sizeof content_type); else safestrncpy(content_type, "application/octet-stream", sizeof content_type); - fstat(fileno(fp), &statbuf); + if (fstat(fileno(fp), &statbuf) == -1) { + lprintf(9, "output_static('%s') -- FSTAT FAILED --\n", what); + wprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); + wprintf("Cannot fstat %s: %s\n", what, strerror(errno)); + return; + } + + count = 0; bytes = statbuf.st_size; - bigbuffer = malloc(bytes + 2); - fread(bigbuffer, bytes, 1, fp); + if ((bigbuffer = malloc(bytes + 2)) == NULL) { + lprintf(9, "output_static('%s') -- MALLOC FAILED (%s) --\n", what, strerror(errno)); + wprintf("HTTP/1.1 500 internal server error\r\n"); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); + return; + } + while (count < bytes) { + if ((res = fread(bigbuffer + count, 1, bytes - count, fp)) == 0) { + lprintf(9, "output_static('%s') -- FREAD FAILED (%s) %zu bytes of %zu --\n", what, strerror(errno), bytes - count, bytes); + wprintf("HTTP/1.1 500 internal server error \r\n"); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); + return; + } + count += res; + } + fclose(fp); lprintf(9, "output_static('%s') %s\n", what, content_type); @@ -563,8 +764,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() @@ -579,35 +780,43 @@ void output_image() 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_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("static/blank.gif"); + char blank_gif[SIZ]; + snprintf (blank_gif, SIZ, "%s%s", static_dirs[0], "/blank.gif"); + output_static(blank_gif); } } -/* - * Generic function to output an arbitrary MIME part from an arbitrary - * message number on the server. +/** + * \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 + * \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); @@ -615,7 +824,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"); @@ -633,8 +847,10 @@ void mimepart(char *msgnum, char *partnum) } -/* - * Read any MIME part of a message, from the server, into memory. +/** + * \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 MIME part to be loaded */ char *load_mimepart(long msgnum, char *partnum) { @@ -643,17 +859,15 @@ char *load_mimepart(long msgnum, char *partnum) char content_type[SIZ]; char *content; - serv_printf("OPNA %ld|%s", msgnum, partnum); + serv_printf("DLAT %ld|%s", msgnum, partnum); serv_getln(buf, sizeof buf); - if (buf[0] == '2') { + if (buf[0] == '6') { bytes = extract_long(&buf[4], 0); extract_token(content_type, &buf[4], 3, '|', sizeof content_type); content = malloc(bytes + 2); - read_server_binary(content, bytes); + serv_read(content, bytes); - serv_puts("CLOS"); - serv_getln(buf, sizeof buf); content[bytes] = 0; /* null terminate for good measure */ return(content); } @@ -664,17 +878,20 @@ 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.1 200 OK\n"); output_headers(1, 1, 2, 0, 0, 0); wprintf("
\n"); - wprintf("
", titlebarcolor); - wprintf("%s\n", titlebarmsg); - wprintf("
\n"); + wprintf("
", titlebarcolor); + wprintf("%s\n", titlebarmsg); + wprintf("
\n"); wprintf("
\n
\n"); escputs(messagetext); @@ -683,8 +900,8 @@ 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, 0, 0); @@ -692,8 +909,8 @@ void blank_page(void) { } -/* - * A template has been requested +/** + * \brief A template has been requested */ void url_do_template(void) { do_template(bstr("template")); @@ -701,27 +918,27 @@ 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("\">"); + wprintf("\">"); wprintf(_("Make this my start page")); - wprintf(""); -/* + wprintf(""); +#ifdef TECH_PREVIEW wprintf("
wc_roomname); wprintf("\" title=\"RSS 2.0 feed for "); escputs(WC->wc_roomname); wprintf("\">\"RSS\"\n"); -*/ +#endif } -/* - * Change the user's start page +/** + * \brief Change the user's start page */ void change_start_page(void) { @@ -742,15 +959,21 @@ void change_start_page(void) { - +/** + * \brief convenience function to indicate success + * \param successmessage the mesage itself + */ void display_success(char *successmessage) { convenience_page("007700", "OK", successmessage); } -/* Authorization required page */ -/* This is probably temporary and should be revisited */ +/** + * \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) { wprintf("HTTP/1.1 401 Authorization Required\r\n"); @@ -764,18 +987,32 @@ void authorization_required(const char *message) wDumpContent(0); } - +/** + * \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, size_t length, char *encoding, void *userdata) { struct urlcontent *u; - /* lprintf(9, "upload_handler() name=%s, type=%s, len=%d\n", - name, cbtype, length); */ + lprintf(9, "upload_handler() name=%s, type=%s, len=%d\n", name, cbtype, length); /* Form fields */ - if ( (length > 0) && (strlen(cbtype) == 0) ) { + if ( (length > 0) && (IsEmptyStr(cbtype)) ) { u = (struct urlcontent *) malloc(sizeof(struct urlcontent)); u->next = WC->urlstrings; WC->urlstrings = u; @@ -783,10 +1020,11 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, u->url_data = malloc(length + 1); memcpy(u->url_data, content, length); u->url_data[length] = 0; + /* lprintf(9, "Key: <%s> Data: <%s>\n", u->url_key, u->url_data); */ } - /* Uploaded files */ - if ( (length > 0) && (strlen(cbtype) > 0) ) { + /** Uploaded files */ + if ( (length > 0) && (!IsEmptyStr(cbtype)) ) { WC->upload = malloc(length); if (WC->upload != NULL) { WC->upload_length = length; @@ -803,8 +1041,8 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, } -/* - * Convenience functions to wrap around asynchronous ajax responses +/** + * \brief Convenience functions to wrap around asynchronous ajax responses */ void begin_ajax_response(void) { output_headers(0, 0, 0, 0, 0, 0); @@ -813,16 +1051,24 @@ void begin_ajax_response(void) { "Server: %s\r\n" "Connection: close\r\n" "Pragma: no-cache\r\n" - "Cache-Control: no-cache\r\n", - SERVER); + "Cache-Control: no-cache\r\n" + "Expires: -1\r\n" + , + PACKAGE_STRING); begin_burst(); } +/** + * \brief print ajax response footer + */ void end_ajax_response(void) { wprintf("\r\n"); wDumpContent(0); } +/** + * \brief Wraps a Citadel server command in an AJAX transaction. + */ void ajax_servcmd(void) { char buf[1024]; @@ -832,22 +1078,21 @@ void ajax_servcmd(void) begin_ajax_response(); - /* lprintf(9, "Sending cmd: %s\n", bstr("g_cmd")); */ serv_printf("%s", bstr("g_cmd")); serv_getln(buf, sizeof buf); - /* lprintf(9, " Response: %s\n", 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")) { - /* maybe do something with it? */ + wprintf("%s\n", gcontent); } 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') { @@ -865,31 +1110,61 @@ void ajax_servcmd(void) } 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(); +} -/* - * Entry point for WebCit transaction + +/** + * \brief Entry point for WebCit transaction */ void session_loop(struct httprequest *req) { 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 arg[8][128]; + size_t sizes[10]; + char *index[10]; char buf[SIZ]; char request_method[128]; char pathname[1024]; - int a, b; + int a, b, nBackDots, nEmpty; int ContentLength = 0; int BytesRead = 0; char ContentType[512]; @@ -900,8 +1175,10 @@ void session_loop(struct httprequest *req) char user_agent[256]; int body_start = 0; int is_static = 0; - - /* We stuff these with the values coming from the client cookies, + int n_static = 0; + int len = 0; + /** + * 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]; @@ -923,7 +1200,6 @@ void session_loop(struct httprequest *req) WC->upload_length = 0; WC->upload = NULL; WC->vars = NULL; - WC->is_wap = 0; hptr = req; @@ -934,49 +1210,32 @@ void session_loop(struct httprequest *req) 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; + /** Figure out the action */ + index[0] = action; + sizes[0] = sizeof action; + for (a=1; a<9; a++) + { + index[a] = arg[a-1]; + sizes[a] = sizeof arg[a-1]; + } +//// index[9] = &foo; todo + nBackDots = 0; + nEmpty = 0; + for ( a = 0; a < 9; ++a) + { + extract_token(index[a], pathname, a + 1, '/', sizes[a]); + if (strstr(index[a], "?")) *strstr(index[a], "?") = 0; + if (strstr(index[a], "&")) *strstr(index[a], "&") = 0; + if (strstr(index[a], " ")) *strstr(index[a], " ") = 0; + if ((index[a][0] == '.') && (index[a][1] == '.')) + nBackDots++; + if (index[a][0] == '\0') + nEmpty++; + } 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)) { @@ -1000,8 +1259,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 (IsEmptyStr(WC->http_host)) { + 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); @@ -1010,7 +1276,7 @@ void session_loop(struct httprequest *req) } striplt(browser_host); } - /* Only WAP gateways explicitly name this content-type */ + /** Only WAP gateways explicitly name this content-type */ else if (strstr(buf, "text/vnd.wap.wml")) { WC->is_wap = 1; } @@ -1019,76 +1285,113 @@ void session_loop(struct httprequest *req) if (ContentLength > 0) { content = malloc(ContentLength + SIZ); memset(content, 0, ContentLength + SIZ); - sprintf(content, "Content-type: %s\n" + snprintf(content, ContentLength + SIZ, "Content-type: %s\n" "Content-length: %d\n\n", ContentType, ContentLength); body_start = strlen(content); - /* Read the entire input data at once. */ - client_read(WC->http_sock, &content[BytesRead+body_start], - ContentLength); + /** Read the entire input data at once. */ + client_read(WC->http_sock, &content[BytesRead+body_start], ContentLength); - if (!strncasecmp(ContentType, - "application/x-www-form-urlencoded", 33)) { + if (!strncasecmp(ContentType, "application/x-www-form-urlencoded", 33)) { addurls(&content[body_start]); } else if (!strncasecmp(ContentType, "multipart", 9)) { content_end = content + ContentLength + body_start; - mime_parser(content, content_end, *upload_handler, - NULL, NULL, NULL, 0); + mime_parser(content, content_end, *upload_handler, NULL, NULL, NULL, 0); } } else { 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 */ - for (a = 0; a < strlen(cmd); ++a) { + /** If there are variables in the URL, we must grab them now */ + len = strlen(cmd); + for (a = 0; a < len; ++a) { if ((cmd[a] == '?') || (cmd[a] == '&')) { - for (b = a; b < strlen(cmd); ++b) - if (isspace(cmd[b])) + for (b = a; b < len; ++b) { + if (isspace(cmd[b])){ cmd[b] = 0; + len = b - 1; + } + } addurls(&cmd[a + 1]); cmd[a] = 0; + len = a - 1; } } + /** 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. */ + /** 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])) { + for (a=0; a 0) { + lprintf(9, "Comparing supplied nonce %s to session nonce %ld\n", + bstr("nonce"), WC->nonce); + if (atoi(bstr("nonce")) != WC->nonce) { + lprintf(9, "Ignoring request with mismatched nonce.\n"); + wprintf("HTTP/1.1 404 Security check failed\r\n"); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); + wprintf("Security check failed.\r\n"); + goto SKIP_ALL_THIS_CRAP; + } + } + + /** * If we're not connected to a Citadel server, try to hook up the * connection now. */ if (!WC->connected) { if (!strcasecmp(ctdlhost, "uds")) { /* unix domain socket */ - sprintf(buf, "%s/citadel.socket", ctdlport); + snprintf(buf, SIZ, "%s/citadel.socket", ctdlport); WC->serv_sock = uds_connectsock(buf); } else { @@ -1102,9 +1405,10 @@ void session_loop(struct httprequest *req) } else { WC->connected = 1; - serv_getln(buf, sizeof buf); /* get the server welcome message */ + serv_getln(buf, sizeof buf); /** get the server welcome message */ - /* From what host is our user connecting? Go with + /** + * 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. @@ -1131,7 +1435,7 @@ void session_loop(struct httprequest *req) } } - /* + /** * Functions which can be performed without logging in */ if (!strcasecmp(action, "listsub")) { @@ -1145,7 +1449,7 @@ 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. */ @@ -1163,20 +1467,22 @@ void session_loop(struct httprequest *req) 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 */ + /** Should only display when password is wrong */ authorization_required(&buf[4]); goto SKIP_ALL_THIS_CRAP; } } } - /* This needs to run early */ + /** This needs to run early */ +#ifdef TECH_PREVIEW if (!strcasecmp(action, "rss")) { display_rss(bstr("room"), request_method); goto SKIP_ALL_THIS_CRAP; } +#endif - /* + /** * The GroupDAV stuff relies on HTTP authentication instead of * our session's authentication. */ @@ -1190,26 +1496,26 @@ void session_loop(struct httprequest *req) } - /* + /** * 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 */ + 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 */ + 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)) { + && (!IsEmptyStr(c_username)) + && (!IsEmptyStr(c_password))) { serv_printf("USER %s", c_username); serv_getln(buf, sizeof buf); if (buf[0] == '3') { @@ -1220,11 +1526,11 @@ void session_loop(struct httprequest *req) } } } - /* + /** * 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)) { + if ((IsEmptyStr(WC->wc_roomname)) && (!IsEmptyStr(c_roomname))) { serv_printf("GOTO %s", c_roomname); serv_getln(buf, sizeof buf); if (buf[0] == '2') { @@ -1232,25 +1538,20 @@ void session_loop(struct httprequest *req) } } - /* - * If there are instant messages waiting, retrieve them for display. - */ - check_for_instant_messages(); - 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... */ @@ -1262,14 +1563,38 @@ void session_loop(struct httprequest *req) url_do_template(); } else if (!strcasecmp(action, "display_aide_menu")) { display_aide_menu(); + } else if (!strcasecmp(action, "server_shutdown")) { + display_shutdown(); } else if (!strcasecmp(action, "display_main_menu")) { display_main_menu(); } 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, "wholist_section")) { + begin_ajax_response(); + wholist_section(); + end_ajax_response(); + } else if (!strcasecmp(action, "new_messages_html")) { + begin_ajax_response(); + new_messages_section(); + end_ajax_response(); + } else if (!strcasecmp(action, "tasks_inner_html")) { + begin_ajax_response(); + tasks_section(); + end_ajax_response(); + } else if (!strcasecmp(action, "calendar_inner_html")) { + begin_ajax_response(); + calendar_section(); + end_ajax_response(); + } else if (!strcasecmp(action, "mini_calendar")) { + begin_ajax_response(); + ajax_mini_calendar(); + end_ajax_response(); } else if (!strcasecmp(action, "iconbar_ajax_menu")) { begin_ajax_response(); do_iconbar(); @@ -1304,10 +1629,16 @@ void session_loop(struct httprequest *req) readloop("readfwd"); } else if (!strcasecmp(action, "headers")) { readloop("headers"); + } else if (!strcasecmp(action, "do_search")) { + readloop("do_search"); } else if (!strcasecmp(action, "msg")) { - embed_message(arg1); + embed_message(index[1]); } else if (!strcasecmp(action, "printmsg")) { - print_message(arg1); + print_message(index[1]); + } else if (!strcasecmp(action, "msgheaders")) { + display_headers(index[1]); + } else if (!strcasecmp(action, "wiki")) { + display_wiki_page(); } else if (!strcasecmp(action, "display_enter")) { display_enter(); } else if (!strcasecmp(action, "post")) { @@ -1351,11 +1682,11 @@ void session_loop(struct httprequest *req) } else if (!strcasecmp(action, "editroom")) { editroom(); } 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); } else if (!strcasecmp(action, "display_editbio")) { - sprintf(buf, "RBIO %s", WC->wc_username); + snprintf(buf, SIZ, "RBIO %s", WC->wc_fullname); display_edit(_("Your bio"), "NOOP", buf, "editbio", 3); } else if (!strcasecmp(action, "editbio")) { save_edit(_("Your bio"), "EBIO", 0); @@ -1365,18 +1696,35 @@ void session_loop(struct httprequest *req) delete_room(); } else if (!strcasecmp(action, "validate")) { validate(); + /* The users photo display / upload facility */ } else if (!strcasecmp(action, "display_editpic")) { display_graphics_upload(_("your photo"), "UIMG 0|_userpic_", "editpic"); } else if (!strcasecmp(action, "editpic")) { do_graphics_upload("UIMG 1|_userpic_"); + /* room picture dispay / upload facility */ } else if (!strcasecmp(action, "display_editroompic")) { display_graphics_upload(_("the icon for this room"), "UIMG 0|_roompic_", "editroompic"); } else if (!strcasecmp(action, "editroompic")) { do_graphics_upload("UIMG 1|_roompic_"); + /* the greetingpage hello pic */ + } else if (!strcasecmp(action, "display_edithello")) { + display_graphics_upload(_("the Greetingpicture for the login prompt"), + "UIMG 0|hello.gif", + "edithellopic"); + } else if (!strcasecmp(action, "edithellopic")) { + do_graphics_upload("UIMG 1|hello.gif"); + /* the logoff banner */ + } else if (!strcasecmp(action, "display_editgoodbyepic")) { + display_graphics_upload(_("the Logoff banner picture"), + "UIMG 0|goodbuye.gif", + "editgoodbuyepic"); + } else if (!strcasecmp(action, "editgoodbuyepic")) { + do_graphics_upload("UIMG 1|goodbuye.gif"); + } else if (!strcasecmp(action, "delete_floor")) { delete_floor(); } else if (!strcasecmp(action, "rename_floor")) { @@ -1384,13 +1732,13 @@ void session_loop(struct httprequest *req) } else if (!strcasecmp(action, "create_floor")) { create_floor(); } else if (!strcasecmp(action, "display_editfloorpic")) { - sprintf(buf, "UIMG 0|_floorpic_|%s", + snprintf(buf, SIZ, "UIMG 0|_floorpic_|%s", bstr("which_floor")); display_graphics_upload(_("the icon for this floor"), buf, "editfloorpic"); } else if (!strcasecmp(action, "editfloorpic")) { - sprintf(buf, "UIMG 1|_floorpic_|%s", + snprintf(buf, SIZ, "UIMG 1|_floorpic_|%s", bstr("which_floor")); do_graphics_upload(buf); } else if (!strcasecmp(action, "display_reg")) { @@ -1411,8 +1759,6 @@ void session_loop(struct httprequest *req) delete_node(); } else if (!strcasecmp(action, "display_add_node")) { display_add_node(); - } else if (!strcasecmp(action, "add_node")) { - add_node(); } else if (!strcasecmp(action, "terminate_session")) { slrp_highest(); terminate_session(); @@ -1435,7 +1781,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(index[1], index[2], 0); + } else if (!strcasecmp(action, "mimepart_download")) { + mimepart(index[1], index[2], 1); } else if (!strcasecmp(action, "edit_vcard")) { edit_vcard(); } else if (!strcasecmp(action, "submit_vcard")) { @@ -1486,6 +1834,24 @@ void session_loop(struct httprequest *req) display_inetconf(); } else if (!strcasecmp(action, "save_inetconf")) { save_inetconf(); + } else if (!strcasecmp(action, "display_smtpqueue")) { + display_smtpqueue(); + } else if (!strcasecmp(action, "display_smtpqueue_inner_div")) { + display_smtpqueue_inner_div(); + } else if (!strcasecmp(action, "display_sieve")) { + display_sieve(); + } else if (!strcasecmp(action, "save_sieve")) { + save_sieve(); + } else if (!strcasecmp(action, "display_pushemail")) { + display_pushemail(); + } else if (!strcasecmp(action, "save_pushemail")) { + save_pushemail(); + } else if (!strcasecmp(action, "display_add_remove_scripts")) { + display_add_remove_scripts(NULL); + } else if (!strcasecmp(action, "create_script")) { + create_script(); + } else if (!strcasecmp(action, "delete_script")) { + delete_script(); } else if (!strcasecmp(action, "setup_wizard")) { do_setup_wizard(); } else if (!strcasecmp(action, "display_preferences")) { @@ -1498,6 +1864,12 @@ void session_loop(struct httprequest *req) recp_autocomplete(bstr("cc")); } else if (!strcasecmp(action, "bcc_autocomplete")) { recp_autocomplete(bstr("bcc")); + } else if (!strcasecmp(action, "display_address_book_middle_div")) { + display_address_book_middle_div(); + } else if (!strcasecmp(action, "display_address_book_inner_div")) { + display_address_book_inner_div(); + } else if (!strcasecmp(action, "set_floordiv_expanded")) { + set_floordiv_expanded(index[1]); } else if (!strcasecmp(action, "diagnostics")) { output_headers(1, 1, 1, 0, 0, 0); wprintf("Session: %d
\n", WC->wc_session); @@ -1508,9 +1880,17 @@ void session_loop(struct httprequest *req) dump_vars(); wprintf("
\n"); wDumpContent(1); + } else if (!strcasecmp(action, "updatenote")) { + updatenote(); + } else if (!strcasecmp(action, "display_room_directory")) { + display_room_directory(); + } else if (!strcasecmp(action, "download_file")) { + download_file(index[1]); + } else if (!strcasecmp(action, "upload_file")) { + upload_file(); } - /* When all else fais, display the main menu. */ + /** When all else fais, display the main menu. */ else { display_main_menu(); } @@ -1526,5 +1906,20 @@ SKIP_ALL_THIS_CRAP: free(WC->upload); WC->upload_length = 0; } +} + +/** + * \brief Replacement for sleep() that uses select() in order to avoid SIGALRM + * \param seconds how many seconds should we sleep? + */ +void sleeeeeeeeeep(int seconds) +{ + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = 0; + select(0, NULL, NULL, NULL, &tv); } + + +/*@}*/