X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fwebcit.c;h=edc19a0c6422ec9079ed8edd56833871d90a4b65;hb=1b302cba797e9b8d6f94304f80c52ac63845503a;hp=ced1d04edb5a95a1154383bf2b2a25cd32d68d29;hpb=baa3aca94eeb9d4b5c833ef91cfcba0c6bc47fc9;p=citadel.git diff --git a/webcit/webcit.c b/webcit/webcit.c index ced1d04ed..edc19a0c6 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -5,13 +5,13 @@ * persistent session to the Citadel server, handling HTTP WebCit requests as * they arrive and presenting a user interface. */ - +#define SHOW_ME_VAPPEND_PRINTF +#include +#include #include "webcit.h" #include "groupdav.h" #include "webserver.h" -#include -#include /* * String to unset the cookie. @@ -20,233 +20,68 @@ */ 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 - */ -long unescape_input(char *buf) -{ - int a, b; - char hex[3]; - long buflen; - long len; +HashList *HandlerHash = NULL; - buflen = strlen(buf); - - while ((buflen > 0) && (isspace(buf[buflen - 1]))){ - buf[buflen - 1] = 0; - buflen --; - } - - a = 0; - while (a < buflen) { - if (buf[a] == '+') - buf[a] = ' '; - if (buf[a] == '%') { - /* don't let % chars through, rather truncate the input. */ - if (a + 2 > buflen) { - buf[a] = '\0'; - buflen = a; - } - else { - hex[0] = buf[a + 1]; - hex[1] = buf[a + 2]; - hex[2] = 0; - b = 0; - sscanf(hex, "%02x", &b); - buf[a] = (char) b; - len = buflen - a - 2; - if (len > 0) - memmove(&buf[a + 1], &buf[a + 3], len); - - buflen -=2; - } - } - a++; - } - return a; -} - -void free_url(void *U) -{ - urlcontent *u = (urlcontent*) U; - free(u->url_data); - free(u); -} - -/** - * \brief Extract variables from the URL. - * \param url URL supplied by the HTTP parser - */ -void addurls(char *url) +void WebcitAddUrlHandler(const char * UrlString, + long UrlSLen, + WebcitHandlerFunc F, + long Flags) { - char *aptr, *bptr, *eptr; - char *up; - char buf[SIZ]; - int len, n, keylen; - urlcontent *u; - struct wcsession *WCC = WC; - - if (WCC->urlstrings == NULL) - WCC->urlstrings = NewHash(); - eptr = buf + sizeof (buf); - up = url; - /** locate the = sign */ - n = safestrncpy(buf, up, sizeof buf); - if (n < 0) /** hm, we exceeded the buffer... hmmm what todo now? */ - n = -n; - up = buf; -// while ((up < eptr) && (*up != '?') && (*up != '&')) -// up++; - while (!IsEmptyStr(up)) { - aptr = up; - while ((aptr < eptr) && (*aptr != '\0') && (*aptr != '=')) - aptr++; - if (*aptr != '=') - return; - *aptr = '\0'; - aptr++; - bptr = aptr; - while ((bptr < eptr) && (*bptr != '\0') && - (*bptr != '&') && (*bptr != ' ')) - bptr++; - *bptr = '\0'; - u = (urlcontent *) malloc(sizeof(urlcontent)); - - - keylen = safestrncpy(u->url_key, up, sizeof u->url_key); - if (keylen < 0){ - lprintf(1, "URLkey to long! [%s]", up); - continue; - } - - Put(WCC->urlstrings, u->url_key, keylen, u, free_url); - len = bptr - aptr; - u->url_data = malloc(len + 2); - safestrncpy(u->url_data, aptr, len + 2); - u->url_data_size = unescape_input(u->url_data); - u->url_data[u->url_data_size] = '\0'; - up = bptr; - ++up; + WebcitHandler *NewHandler; - lprintf(9, "%s = [%ld] %s\n", u->url_key, u->url_data_size, u->url_data); - } -} - -/** - * \brief free urlstring memory - */ -void free_urls(void) -{ - DeleteHash(&WC->urlstrings); -} - -/** - * \brief Diagnostic function to display the contents of all variables - */ - -void dump_vars(void) -{ - struct wcsession *WCC = WC; - urlcontent *u; - void *U; - long HKLen; - char *HKey; - HashPos *Cursor; + if (HandlerHash == NULL) + HandlerHash = NewHash(1, NULL); - Cursor = GetNewHashPos (); - while (GetNextHashPos(WCC->urlstrings, Cursor, &HKLen, &HKey, &U)) { - u = (urlcontent*) U; - wprintf("%38s = %s\n", u->url_key, u->url_data); - } -} - -/** - * \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 - */ -const char *BSTR(char *key) -{ - void *U; - - if ((WC->urlstrings != NULL) && - GetHash(WC->urlstrings, key, strlen (key), &U)) - return ((urlcontent *)U)->url_data; - else - return (""); + NewHandler = (WebcitHandler*) malloc(sizeof(WebcitHandler)); + NewHandler->F = F; + NewHandler->Flags = Flags; + Put(HandlerHash, UrlString, UrlSLen, NewHandler, NULL); } -const char *XBSTR(char *key, size_t *len) -{ - void *U; - - if ((WC->urlstrings != NULL) && - GetHash(WC->urlstrings, key, strlen (key), &U)){ - *len = ((urlcontent *)U)->url_data_size; - return ((urlcontent *)U)->url_data; - } - else { - *len = 0; - return (""); - } -} -const char *Bstr(char *key, size_t keylen) +/* + * web-printing funcion. uses our vsnprintf wrapper + */ +void wprintf(const char *format,...) { - void *U; + wcsession *WCC = WC; + va_list arg_ptr; - if ((WC->urlstrings != NULL) && - GetHash(WC->urlstrings, key, keylen, &U)) - return ((urlcontent *)U)->url_data; - else - return (""); -} + if (WCC->WBuf == NULL) + WCC->WBuf = NewStrBuf(); -const char *XBstr(char *key, size_t keylen, size_t *len) -{ - void *U; - - if ((WC->urlstrings != NULL) && - GetHash(WC->urlstrings, key, keylen, &U)) { - *len = ((urlcontent *)U)->url_data_size; - return ((urlcontent *)U)->url_data; - } - else { - *len = 0; - return (""); - } + va_start(arg_ptr, format); + StrBufVAppendPrintf(WCC->WBuf, format, arg_ptr); + va_end(arg_ptr); } -/** - * \brief web-printing funcion. uses our vsnprintf wrapper - * \param format printf format string - * \param ... the varargs to put into formatstring +/* + * http-header-printing funcion. uses our vsnprintf wrapper */ -void wprintf(const char *format,...) +void hprintf(const char *format,...) { + wcsession *WCC = WC; va_list arg_ptr; - char wbuf[4096]; va_start(arg_ptr, format); - vsnprintf(wbuf, sizeof wbuf, format, arg_ptr); + StrBufVAppendPrintf(WCC->HBuf, format, arg_ptr); va_end(arg_ptr); - - client_write(wbuf, strlen(wbuf)); } -/** - * \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. + +/* + * wrap up an HTTP session, closes tags, etc. + * + * print_standard_html_footer should be set to: + * 0 - to transmit only, + * nonzero - to append the closing tags */ void wDumpContent(int print_standard_html_footer) { if (print_standard_html_footer) { - wprintf("\n"); /* end of "text" div */ - do_template("trailing"); + wprintf(" \n"); + do_template("trailing", NULL); } /* If we've been saving it all up for one big output burst, @@ -256,363 +91,94 @@ void wDumpContent(int print_standard_html_footer) } -/** - * \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. - */ -long stresc(char *target, long tSize, char *strbuf, int nbsp, int nolinebreaks) -{ - 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; - 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); -} - + -/** - * \brief urlescape buffer and print it to the client - * \param strbuf buffer to urlescape - */ -void urlescputs(char *strbuf) -{ - char outbuf[SIZ]; - - urlesc(outbuf, SIZ, strbuf); - wprintf("%s", outbuf); -} - - -/** - * \brief Copy a string, escaping characters for JavaScript strings. - * \param target output string - * \param strbuf input string - */ -void jsesc(char *target, size_t tlen, char *strbuf) -{ - 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, SIZ, strbuf); - wprintf("%s", outbuf); -} - -/** - * \brief Copy a string, escaping characters for message text hold - * \param target target buffer - * \param strbuf source buffer - */ -void msgesc(char *target, size_t tlen, char *strbuf) -{ - 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; - len = (3 * strlen(strbuf)) + SIZ; - outbuf = malloc(len); - msgesc(outbuf, len, strbuf); - wprintf("%s", outbuf); - free(outbuf); -} - - - - -/** - * \brief Output all that important stuff that the browser will want to see +/* + * Output HTTP headers and leading HTML for a page */ -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 */ ) { + wcsession *WCC = WC; char cookie[1024]; char httpnow[128]; - wprintf("HTTP/1.1 200 OK\n"); + hprintf("HTTP/1.1 200 OK\n"); http_datestring(httpnow, sizeof httpnow, time(NULL)); if (do_httpheaders) { - wprintf("Content-type: text/html; charset=utf-8\r\n" + hprintf("Content-type: text/html; charset=utf-8\r\n" "Server: %s / %s\n" "Connection: close\r\n", - PACKAGE_STRING, serv_info.serv_software + PACKAGE_STRING, + ChrPtr(WCC->serv_info->serv_software) ); } if (cache) { - wprintf("Pragma: public\r\n" + char httpTomorow[128]; + + http_datestring(httpTomorow, sizeof httpTomorow, + time(NULL) + 60 * 60 * 24 * 2); + + hprintf("Pragma: public\r\n" "Cache-Control: max-age=3600, must-revalidate\r\n" - "Last-modified: %s\r\n", - httpnow + "Last-modified: %s\r\n" + "Expires: %s\r\n", + httpnow, + httpTomorow ); } else { - wprintf("Pragma: no-cache\r\n" + hprintf("Pragma: no-cache\r\n" "Cache-Control: no-store\r\n" "Expires: -1\r\n" ); } - stuff_to_cookie(cookie, 1024, WC->wc_session, WC->wc_username, - WC->wc_password, WC->wc_roomname); + stuff_to_cookie(cookie, 1024, + WCC->wc_session, WCC->wc_username, + WCC->wc_password, WCC->wc_roomname); if (unset_cookies) { - wprintf("Set-cookie: webcit=%s; path=/\r\n", unset); + hprintf("Set-cookie: webcit=%s; path=/\r\n", unset); } else { - wprintf("Set-cookie: webcit=%s; path=/\r\n", cookie); + hprintf("Set-cookie: webcit=%s; path=/\r\n", cookie); if (server_cookie != NULL) { - wprintf("%s\n", server_cookie); + hprintf("%s\n", server_cookie); } } if (do_htmlhead) { begin_burst(); - if (!access("static.local/webcit.css", R_OK)) { - svprintf("CSSLOCAL", WCS_STRING, - "" - ); - } - do_template("head"); - } - - /** ICONBAR */ - if (do_htmlhead) { - + do_template("head", NULL); - /** check for ImportantMessages (these display in a div overlaying the main screen) */ + /* check for ImportantMessages (these display in a div overlaying the main screen) */ if (!IsEmptyStr(WC->ImportantMessage)) { wprintf("
\n" ""); escputs(WC->ImportantMessage); wprintf("
\n" "
\n" - "\n"); - WC->ImportantMessage[0] = 0; + ); + StrBufAppendPrintf(WCC->trailing_javascript, + "setTimeout('hide_imsg_popup()', 5000); \n" + ); + WCC->ImportantMessage[0] = 0; } - if ( (WC->logged_in) && (!unset_cookies) ) { - wprintf("
"); - do_selected_iconbar(); - /** check for instant messages (these display in a new window) */ + if ( (WCC->logged_in) && (!unset_cookies) ) { + //DoTemplate(HKEY("iconbar"), NULL, &NoCtx); page_popup(); - wprintf("
"); } if (do_room_banner == 1) { @@ -627,85 +193,68 @@ void output_headers( int do_httpheaders, /**< 1 = output HTTP headers } } +void output_custom_content_header(const char *ctype) { + hprintf("HTTP/1.1 200 OK\r\n"); + hprintf("Content-type: %s; charset=utf-8\r\n",ctype); + hprintf("Server: %s / %s\r\n", PACKAGE_STRING, ChrPtr(WC->serv_info->serv_software)); + hprintf("Connection: close\r\n"); +} -/** - * \brief Generic function to do an HTTP redirect. Easy and fun. - * \param whichpage target url to 302 to + +/* + * Generic function to do an HTTP redirect. Easy and fun. */ -void http_redirect(char *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"); +void http_redirect(const char *whichpage) { + hprintf("HTTP/1.1 302 Moved Temporarily\n"); + hprintf("Location: %s\r\n", whichpage); + hprintf("URI: %s\r\n", whichpage); + hprintf("Content-type: text/html; charset=utf-8\r\n"); wprintf(""); wprintf("Go here.", whichpage); wprintf("\n"); + end_burst(); } -/** - * \brief Output a piece of content to the web browser +/* + * Output a piece of content to the web browser using conformant HTTP and MIME semantics */ -void http_transmit_thing(char *thing, size_t length, const char *content_type, +void http_transmit_thing(const char *content_type, int is_static) { +#ifndef TECH_PREVIEW + lprintf(9, "http_transmit_thing(%s)%s\n", + content_type, + (is_static ? " (static)" : "") + ); +#endif output_headers(0, 0, 0, 0, 0, is_static); - wprintf("Content-type: %s\r\n" + hprintf("Content-type: %s\r\n" "Server: %s\r\n" "Connection: close\r\n", content_type, PACKAGE_STRING); -#ifdef HAVE_ZLIB - /** If we can send the data out compressed, please do so. */ - if (WC->gzip_ok) { - char *compressed_data = NULL; - size_t compressed_len; - - compressed_len = ((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); + end_burst(); } -/** - * \brief print menu box like used in the floor view or admin interface. +/* + * 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 + * Title Title string of the box + * Class CSS Class for the box + * nLines How many string pairs should we print? (URL, UrlText) + * ... 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"); + svput("BOXTITLE", WCS_STRING, Title); + do_template("beginboxx", NULL); wprintf("
    ", Class); @@ -722,207 +271,79 @@ void print_menu_box(char* Title, char *Class, int nLines, ...) wprintf("
"); - do_template("endbox"); + do_template("endbox", NULL); } -/** - * \brief dump out static pages from disk - * \param what the file urs to print +/* + * dump out static pages from disk */ void output_static(char *what) { - FILE *fp; + int fd; struct stat statbuf; off_t bytes; off_t count = 0; - size_t res; - char *bigbuffer; const char *content_type; int len; + const char *Err; - fp = fopen(what, "rb"); - if (fp == NULL) { + fd = open(what, O_RDONLY); + if (fd <= 0) { lprintf(9, "output_static('%s') -- NOT FOUND --\n", what); - wprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); - wprintf("Content-Type: text/plain\r\n"); - wprintf("\r\n"); + hprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); + hprintf("Content-Type: text/plain\r\n"); wprintf("Cannot open %s: %s\r\n", what, strerror(errno)); + end_burst(); } else { len = strlen (what); content_type = GuessMimeByFilename(what, len); - if (fstat(fileno(fp), &statbuf) == -1) { + if (fstat(fd, &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"); + hprintf("HTTP/1.1 404 %s\r\n", strerror(errno)); + hprintf("Content-Type: text/plain\r\n"); wprintf("Cannot fstat %s: %s\n", what, strerror(errno)); + end_burst(); return; } count = 0; bytes = statbuf.st_size; - 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"); + + if (StrBufReadBLOB(WC->WBuf, &fd, 1, bytes, &Err) < 0) + { + if (fd > 0) close(fd); + lprintf(9, "output_static('%s') -- FREAD FAILED (%s) --\n", what, strerror(errno)); + hprintf("HTTP/1.1 500 internal server error \r\n"); + hprintf("Content-Type: text/plain\r\n"); + end_burst(); return; - } - count += res; } - fclose(fp); + close(fd); +#ifndef TECH_PREVIEW lprintf(9, "output_static('%s') %s\n", what, content_type); - http_transmit_thing(bigbuffer, (size_t)bytes, content_type, 1); - free(bigbuffer); +#endif + http_transmit_thing(content_type, 1); } - if (!strcasecmp(bstr("force_close_session"), "yes")) { + if (yesbstr("force_close_session")) { end_webcit_session(); } } -/** - * \brief When the browser requests an image file from the Citadel server, - * this function is called to transmit it. - */ -void output_image() -{ - char buf[SIZ]; - char *xferbuf = NULL; - off_t bytes; - const char *MimeType; - - serv_printf("OIMG %s|%s", bstr("name"), bstr("parm")); - 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_server_binary(xferbuf, bytes); - serv_puts("CLOS"); - serv_getln(buf, sizeof buf); - - MimeType = GuessMimeType (xferbuf, bytes); - /** Write it to the browser */ - if (!IsEmptyStr(MimeType)) - { - http_transmit_thing(xferbuf, - (size_t)bytes, - MimeType, - 0); - free(xferbuf); - return; - } - /* hm... unknown mimetype? fallback to blank gif */ - free(xferbuf); - } - - - /** - * Instead of an ugly 404, send a 1x1 transparent GIF - * when there's no such image on the server. - */ - char blank_gif[SIZ]; - snprintf (blank_gif, SIZ, "%s%s", static_dirs[0], "/blank.gif"); - output_static(blank_gif); -} - -/** - * \brief Generic function to output an arbitrary MIME part from an arbitrary - * message number on the server. +/* + * Convenience functions to display a page containing only a string * - * \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, int force_download) -{ - char buf[256]; - off_t bytes; - char content_type[256]; - char *content = NULL; - - 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); - 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"); - serv_getln(buf, sizeof buf); - http_transmit_thing(content, bytes, content_type, 0); - free(content); - } else { - 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 MIME part to be loaded - */ -char *load_mimepart(long msgnum, char *partnum) -{ - char buf[SIZ]; - off_t bytes; - char content_type[SIZ]; - char *content; - - serv_printf("DLAT %ld|%s", msgnum, partnum); - serv_getln(buf, sizeof buf); - if (buf[0] == '6') { - bytes = extract_long(&buf[4], 0); - extract_token(content_type, &buf[4], 3, '|', sizeof content_type); - - content = malloc(bytes + 2); - serv_read(content, bytes); - - content[bytes] = 0; /* null terminate for good measure */ - return(content); - } - else { - return(NULL); - } - -} - - -/** - * \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 + * titlebarcolor color of the titlebar of the frame + * titlebarmsg text to display in the title bar + * messagetext body of the box */ void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext) { - wprintf("HTTP/1.1 200 OK\n"); + hprintf("HTTP/1.1 200 OK\n"); output_headers(1, 1, 2, 0, 0, 0); wprintf("
\n"); wprintf("
", titlebarcolor); @@ -936,8 +357,8 @@ void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext) } -/** - * \brief Display a blank page. +/* + * Display a blank page. */ void blank_page(void) { output_headers(1, 1, 0, 0, 0, 0); @@ -945,59 +366,22 @@ void blank_page(void) { } -/** - * \brief A template has been requested +/* + * A template has been requested */ void url_do_template(void) { - do_template(bstr("template")); -} - - - -/** - * \brief Offer to make any page the user's "start page." - */ -void offer_start_page(void) { - wprintf("this_page); - wprintf("\">"); - wprintf(_("Make this my start page")); - wprintf(""); -#ifdef TECH_PREVIEW - wprintf("
wc_roomname); - wprintf("\" title=\"RSS 2.0 feed for "); - escputs(WC->wc_roomname); - wprintf("\">\"RSS\"\n"); -#endif -} - - -/** - * \brief Change the user's start page - */ -void change_start_page(void) { - - if (bstr("startpage") == NULL) { - safestrncpy(WC->ImportantMessage, - _("You no longer have a start page selected."), - sizeof WC->ImportantMessage); - display_main_menu(); - return; - } - - set_preference("startpage", bstr("startpage"), 1); - - output_headers(1, 1, 0, 0, 0, 0); - do_template("newstartpage"); - wDumpContent(1); + const StrBuf *MimeType; + const StrBuf *Tmpl = sbstr("template"); + begin_burst(); + output_headers(0, 0, 0, 0, 1, 0); + MimeType = DoTemplate(SKEY(Tmpl), NULL, &NoCtx); + http_transmit_thing(ChrPtr(MimeType), 0); } -/** - * \brief convenience function to indicate success - * \param successmessage the mesage itself +/* + * convenience function to indicate success */ void display_success(char *successmessage) { @@ -1005,110 +389,50 @@ void display_success(char *successmessage) } -/** - * \brief Authorization required page +/* + * 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"); - wprintf("WWW-Authenticate: Basic realm=\"\"\r\n", serv_info.serv_humannode); - wprintf("Content-Type: text/html\r\n\r\n"); + hprintf("HTTP/1.1 401 Authorization Required\r\n"); + hprintf("WWW-Authenticate: Basic realm=\"%s\"\r\n", ChrPtr(WC->serv_info->serv_humannode)); + hprintf("Content-Type: text/html\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 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) -{ - urlcontent *u; - - lprintf(9, "upload_handler() name=%s, type=%s, len=%d\n", name, cbtype, length); - - if (WC->urlstrings == NULL) - WC->urlstrings = NewHash(); - - /* Form fields */ - if ( (length > 0) && (IsEmptyStr(cbtype)) ) { - u = (urlcontent *) malloc(sizeof(urlcontent)); - - safestrncpy(u->url_key, name, sizeof(u->url_key)); - u->url_data = malloc(length + 1); - u->url_data_size = length; - memcpy(u->url_data, content, length); - u->url_data[length] = 0; - Put(WC->urlstrings, u->url_key, strlen(u->url_key), u, free_url); - - /* lprintf(9, "Key: <%s> Data: <%s>\n", u->url_key, u->url_data); */ - } - - /** Uploaded files */ - if ( (length > 0) && (!IsEmptyStr(cbtype)) ) { - WC->upload = malloc(length); - if (WC->upload != NULL) { - WC->upload_length = length; - safestrncpy(WC->upload_filename, filename, - sizeof(WC->upload_filename)); - safestrncpy(WC->upload_content_type, cbtype, - sizeof(WC->upload_content_type)); - memcpy(WC->upload, content, length); - } - else { - lprintf(3, "malloc() failed: %s\n", strerror(errno)); - } - } - -} - -/** - * \brief Convenience functions to wrap around asynchronous ajax responses +/* + * Convenience functions to wrap around asynchronous ajax responses */ void begin_ajax_response(void) { + wcsession *WCC = WC; + + FlushStrBuf(WCC->HBuf); output_headers(0, 0, 0, 0, 0, 0); - wprintf("Content-type: text/html; charset=UTF-8\r\n" + hprintf("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" - "Expires: -1\r\n" , PACKAGE_STRING); begin_burst(); } -/** - * \brief print ajax response footer +/* + * print ajax response footer */ void end_ajax_response(void) { - wprintf("\r\n"); wDumpContent(0); } -/** - * \brief Wraps a Citadel server command in an AJAX transaction. +/* + * Wraps a Citadel server command in an AJAX transaction. */ void ajax_servcmd(void) { @@ -1152,7 +476,7 @@ 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 @@ -1164,19 +488,19 @@ void ajax_servcmd(void) } -/** - * \brief Helper function for the asynchronous check to see if we need +/* + * 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 { + memset(buf, 0, 5); serv_puts("NOOP"); serv_getln(buf, sizeof buf); if (buf[3] == '*') { @@ -1186,70 +510,90 @@ void seconds_since_last_gexp(void) wprintf("NO"); } } - end_ajax_response(); } +/** + * \brief Detects a 'mobile' user agent + */ +int is_mobile_ua(char *user_agent) { + if (strstr(user_agent,"iPhone OS") != NULL) { + return 1; + } else if (strstr(user_agent,"Windows CE") != NULL) { + return 1; + } else if (strstr(user_agent,"SymbianOS") != NULL) { + return 1; + } else if (strstr(user_agent, "Opera Mobi") != NULL) { + return 1; + } else if (strstr(user_agent, "Firefox/2.0.0 Opera 9.51 Beta") != NULL) { + /* For some reason a new install of Opera 9.51beta decided to spoof. */ + return 1; + } + return 0; +} - -/** - * \brief Entry point for WebCit transaction +/* + * Entry point for WebCit transaction */ -void session_loop(struct httprequest *req) +void session_loop(HashList *HTTPHeaders, StrBuf *ReqLine, StrBuf *request_method, StrBuf *ReadBuf) { - char cmd[1024]; + StrBuf *Buf; + const char *pch, *pchs, *pche; + void *vLine; char action[1024]; char arg[8][128]; size_t sizes[10]; char *index[10]; char buf[SIZ]; - char request_method[128]; - char pathname[1024]; - int a, b, nBackDots, nEmpty; + int a, nBackDots, nEmpty; int ContentLength = 0; - int BytesRead = 0; - char ContentType[512]; - char *content = NULL; - char *content_end = NULL; - struct httprequest *hptr; - char browser_host[256]; + StrBuf *ContentType = NULL; + StrBuf *UrlLine = NULL; + StrBuf *content = NULL; + const char *content_end = NULL; + StrBuf *browser_host = NULL; char user_agent[256]; int body_start = 0; int is_static = 0; int n_static = 0; int len = 0; - /** + void *vHandler; + WebcitHandler *Handler; + + /* * 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]; - char c_password[SIZ]; - char c_roomname[SIZ]; + StrBuf *c_username; + StrBuf *c_password; + StrBuf *c_roomname; char c_httpauth_string[SIZ]; - char c_httpauth_user[SIZ]; - char c_httpauth_pass[SIZ]; - char cookie[SIZ]; - - safestrncpy(c_username, "", sizeof c_username); - safestrncpy(c_password, "", sizeof c_password); - safestrncpy(c_roomname, "", sizeof c_roomname); + StrBuf *c_httpauth_user; + StrBuf *c_httpauth_pass; + wcsession *WCC; + + Buf = NewStrBuf(); + c_username = NewStrBuf(); + c_password = NewStrBuf(); + c_roomname = NewStrBuf(); 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, ""); + c_httpauth_user = NewStrBufPlain(HKEY(DEFAULT_HTTPAUTH_USER)); + c_httpauth_pass = NewStrBufPlain(HKEY(DEFAULT_HTTPAUTH_PASS)); - WC->upload_length = 0; - WC->upload = NULL; - WC->vars = NULL; - WC->is_wap = 0; + WCC= WC; + if (WCC->WBuf == NULL) + WC->WBuf = NewStrBufPlain(NULL, 32768); + FlushStrBuf(WCC->WBuf); - hptr = req; - if (hptr == NULL) return; + if (WCC->HBuf == NULL) + WCC->HBuf = NewStrBuf(); + FlushStrBuf(WCC->HBuf); - safestrncpy(cmd, hptr->line, sizeof cmd); - hptr = hptr->next; - extract_token(request_method, cmd, 0, ' ', sizeof request_method); - extract_token(pathname, cmd, 1, ' ', sizeof pathname); + WCC->upload_length = 0; + WCC->upload = NULL; + WCC->is_mobile = 0; + WCC->trailing_javascript = NewStrBuf(); + WCC->nWildfireHeaders = 0; /** Figure out the action */ index[0] = action; @@ -1259,12 +603,12 @@ void session_loop(struct httprequest *req) index[a] = arg[a-1]; sizes[a] = sizeof arg[a-1]; } -//// index[9] = &foo; todo +/*/// index[9] = &foo; todo */ nBackDots = 0; nEmpty = 0; for ( a = 0; a < 9; ++a) { - extract_token(index[a], pathname, a + 1, '/', sizes[a]); + extract_token(index[a], ChrPtr(ReqLine), 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; @@ -1274,109 +618,122 @@ void session_loop(struct httprequest *req) 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)) { - safestrncpy(cookie, &buf[15], sizeof cookie); - cookie_to_stuff(cookie, NULL, - 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, ':', 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]); - } - else if (!strncasecmp(buf, "Content-type: ", 14)) { - safestrncpy(ContentType, &buf[14], sizeof ContentType); - } - 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)) { - if (IsEmptyStr(WC->http_host)) { - safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host); - } + + if (GetHash(HTTPHeaders, HKEY("COOKIE"), &vLine) && + (vLine != NULL)){ + cookie_to_stuff((StrBuf *)vLine, NULL, + c_username, + c_password, + c_roomname); + } + if (GetHash(HTTPHeaders, HKEY("AUTHORIZATION"), &vLine) && + (vLine!=NULL)) { +/* TODO: wrap base64 in strbuf */ + CtdlDecodeBase64(c_httpauth_string, ChrPtr((StrBuf*)vLine), StrLength((StrBuf*)vLine)); + FlushStrBuf(Buf); + StrBufAppendBufPlain(Buf, c_httpauth_string, -1, 0); + StrBufExtract_token(c_httpauth_user, Buf, 0, ':'); + StrBufExtract_token(c_httpauth_pass, Buf, 1, ':'); + } + if (GetHash(HTTPHeaders, HKEY("CONTENT-LENGTH"), &vLine) && + (vLine!=NULL)) { + ContentLength = StrToi((StrBuf*)vLine); + } + if (GetHash(HTTPHeaders, HKEY("CONTENT-TYPE"), &vLine) && + (vLine!=NULL)) { + ContentType = (StrBuf*)vLine; + } + if (GetHash(HTTPHeaders, HKEY("USER-AGENT"), &vLine) && + (vLine!=NULL)) { + safestrncpy(user_agent, ChrPtr((StrBuf*)vLine), sizeof user_agent); +#ifdef TECH_PREVIEW + if ((WCC->is_mobile < 0) && is_mobile_ua(&buf[12])) { + WCC->is_mobile = 1; } - 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); + else { + WCC->is_mobile = 0; } - /** Only WAP gateways explicitly name this content-type */ - else if (strstr(buf, "text/vnd.wap.wml")) { - WC->is_wap = 1; +#endif + } + if ((follow_xff) && + GetHash(HTTPHeaders, HKEY("X-FORWARDED-HOST"), &vLine) && + (vLine != NULL)) { + WCC->http_host = (StrBuf*)vLine; + } + if ((StrLength(WCC->http_host) == 0) && + GetHash(HTTPHeaders, HKEY("HOST"), &vLine) && + (vLine!=NULL)) { + WCC->http_host = (StrBuf*)vLine; + } + + if (GetHash(HTTPHeaders, HKEY("X-FORWARDED-FOR"), &vLine) && + (vLine!=NULL)) { + browser_host = (StrBuf*) vLine; + + while (StrBufNum_tokens(browser_host, ',') > 1) { + StrBufRemove_token(browser_host, 0, ','); } + StrBufTrim(browser_host); } if (ContentLength > 0) { - content = malloc(ContentLength + SIZ); - memset(content, 0, ContentLength + SIZ); - snprintf(content, ContentLength + SIZ, "Content-type: %s\n" - "Content-length: %d\n\n", - ContentType, ContentLength); - body_start = strlen(content); + content = NewStrBuf(); + StrBufPrintf(content, "Content-type: %s\n" + "Content-length: %d\n\n", + ChrPtr(ContentType), ContentLength); +/* + hprintf("Content-type: %s\n" + "Content-length: %d\n\n", + ContentType, ContentLength); +*/ + body_start = StrLength(content); /** 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)) { - 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); + client_read(&WCC->http_sock, content, ReadBuf, ContentLength + body_start); + + if (!strncasecmp(ChrPtr(ContentType), "application/x-www-form-urlencoded", 33)) { + StrBufCutLeft(content, body_start); + ParseURLParams(content); + } else if (!strncasecmp(ChrPtr(ContentType), "multipart", 9)) { + content_end = ChrPtr(content) + ContentLength + body_start; + mime_parser(ChrPtr(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 */ - 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 */ - len = strlen(cmd); - for (a = 0; a < len; ++a) { - if ((cmd[a] == '?') || (cmd[a] == '&')) { - 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; + /* make a note of where we are in case the user wants to save it */ + WCC->this_page = NewStrBufDup(ReqLine); + StrBufRemove_token(WCC->this_page, 2, ' '); + StrBufRemove_token(WCC->this_page, 0, ' '); + + /* If there are variables in the URL, we must grab them now */ + UrlLine = NewStrBufDup(ReqLine); + len = StrLength(UrlLine); + pch = pchs = ChrPtr(UrlLine); + pche = pchs + len; + while (pch < pche) { + if ((*pch == '?') || (*pch == '&')) { + StrBufCutLeft(UrlLine, pch - pchs + 1); + ParseURLParams(UrlLine); + break; } + pch ++; } + FreeStrBuf(&UrlLine); - /** If it's a "force 404" situation then display the error and bail. */ + /* 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"); + hprintf("HTTP/1.1 404 Not found\r\n"); + hprintf("Content-Type: text/plain\r\n"); wprintf("Not found\r\n"); + end_burst(); 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 0) { lprintf(9, "Comparing supplied nonce %s to session nonce %ld\n", - bstr("nonce"), WC->nonce); - if (atoi(bstr("nonce")) != WC->nonce) { + bstr("nonce"), WCC->nonce); + if (ibstr("nonce") != WCC->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"); + hprintf("HTTP/1.1 404 Security check failed\r\n"); + hprintf("Content-Type: text/plain\r\n\r\n"); wprintf("Security check failed.\r\n"); + end_burst(); 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 (!WCC->connected) { if (!strcasecmp(ctdlhost, "uds")) { /* unix domain socket */ snprintf(buf, SIZ, "%s/citadel.socket", ctdlport); - WC->serv_sock = uds_connectsock(buf); + WCC->serv_sock = uds_connectsock(buf); } else { /* tcp socket */ - WC->serv_sock = tcp_connectsock(ctdlhost, ctdlport); + WCC->serv_sock = tcp_connectsock(ctdlhost, ctdlport); } - if (WC->serv_sock < 0) { + if (WCC->serv_sock < 0) { do_logout(); goto SKIP_ALL_THIS_CRAP; } else { - WC->connected = 1; - serv_getln(buf, sizeof buf); /** get the server welcome message */ + WCC->connected = 1; + serv_getln(buf, sizeof buf); /* get the server greeting */ + + /* Are there too many users already logged in? */ + if (!strncmp(buf, "571", 3)) { + wprintf(_("This server is already serving its maximum number of users and cannot accept any additional logins at this time. Please try again later or contact your system administrator.")); + end_burst(); + end_webcit_session(); + goto SKIP_ALL_THIS_CRAP; + } - /** + /* * 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); + if ( (!follow_xff) || (StrLength(browser_host) == 0) ) { + if (browser_host == NULL) { + browser_host = NewStrBuf(); + Put(HTTPHeaders, HKEY("FreeMeWithTheOtherHeaders"), + browser_host, HFreeStrBuf); + } + locate_host(browser_host, WCC->http_sock); } - get_serv_info(browser_host, user_agent); - if (serv_info.serv_rev_level < MINIMUM_CIT_VERSION) { + WCC->serv_info = get_serv_info(browser_host, user_agent); + if (WCC->serv_info->serv_rev_level < MINIMUM_CIT_VERSION) { + begin_burst(); 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"), - serv_info.serv_rev_level / 100, - serv_info.serv_rev_level % 100, + WCC->serv_info->serv_rev_level / 100, + WCC->serv_info->serv_rev_level % 100, MINIMUM_CIT_VERSION / 100, MINIMUM_CIT_VERSION % 100 ); + end_burst(); end_webcit_session(); goto SKIP_ALL_THIS_CRAP; } } } - - /** +/*///////todo: restore language in this case */ + /* * Functions which can be performed without logging in */ if (!strcasecmp(action, "listsub")) { @@ -1484,474 +856,198 @@ void session_loop(struct httprequest *req) goto SKIP_ALL_THIS_CRAP; } if (!strcasecmp(action, "freebusy")) { - do_freebusy(cmd); + do_freebusy(ChrPtr(ReqLine)); goto SKIP_ALL_THIS_CRAP; } - /** + /* * 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)) { - serv_printf("USER %s", c_httpauth_user); - serv_getln(buf, sizeof buf); - if (buf[0] == '3') { - serv_printf("PASS %s", c_httpauth_pass); - serv_getln(buf, sizeof buf); - if (buf[0] == '2') { + if ((!WCC->logged_in) + && (StrLength(c_httpauth_user) > 0) + && (StrLength(c_httpauth_pass) > 0)) + { + FlushStrBuf(Buf); + serv_printf("USER %s", ChrPtr(c_httpauth_user)); + StrBuf_ServGetln(Buf); + if (GetServerStatus(Buf, NULL) == 3) { + serv_printf("PASS %s", ChrPtr(c_httpauth_pass)); + StrBuf_ServGetln(Buf); + if (GetServerStatus(Buf, NULL) == 2) { 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); + c_httpauth_pass, Buf); + if (WCC->httpauth_user == NULL) + WCC->httpauth_user = NewStrBufDup(c_httpauth_user); + else { + FlushStrBuf(WCC->httpauth_user); + StrBufAppendBuf(WCC->httpauth_user, c_httpauth_user, 0); + } + if (WCC->httpauth_pass == NULL) + WCC->httpauth_pass = NewStrBufDup(c_httpauth_pass); + else { + FlushStrBuf(WCC->httpauth_pass); + StrBufAppendBuf(WCC->httpauth_pass, c_httpauth_pass, 0); + } } else { - /** Should only display when password is wrong */ + /* Should only display when password is wrong */ authorization_required(&buf[4]); + FreeStrBuf(&Buf); 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); + display_rss(sbstr("room"), request_method); goto SKIP_ALL_THIS_CRAP; } #endif - /** + /* * The GroupDAV stuff relies on HTTP authentication instead of * our session's authentication. */ if (!strncasecmp(action, "groupdav", 8)) { - groupdav_main(req, ContentType, /* do GroupDAV methods */ - ContentLength, content+body_start); - if (!WC->logged_in) { - WC->killthis = 1; /* If not logged in, don't */ + groupdav_main(HTTPHeaders, + ReqLine, request_method, + ContentType, /* do GroupDAV methods */ + ContentLength, content, body_start); + if (!WCC->logged_in) { + WCC->killthis = 1; /* If not logged in, don't */ } /* keep the session active */ goto SKIP_ALL_THIS_CRAP; } - /** + /* * 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 */ + if ((strcasecmp(ChrPtr(request_method), "GET")) && (strcasecmp(ChrPtr(request_method), "POST"))) { + groupdav_main(HTTPHeaders, ReqLine, + request_method, ContentType, /** do GroupDAV methods */ + ContentLength, content, body_start); + if (!WCC->logged_in) { + WCC->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) - && (!IsEmptyStr(c_username)) - && (!IsEmptyStr(c_password))) { - serv_printf("USER %s", c_username); - serv_getln(buf, sizeof buf); - if (buf[0] == '3') { - serv_printf("PASS %s", c_password); - serv_getln(buf, sizeof buf); - if (buf[0] == '2') { - become_logged_in(c_username, c_password, buf); + if ((!WCC->logged_in) + && (StrLength(c_username)>0) + && (StrLength(c_password)>0)) { + serv_printf("USER %s", ChrPtr(c_username)); + StrBuf_ServGetln(Buf); + if (GetServerStatus(Buf, NULL) == 3) { + serv_printf("PASS %s", ChrPtr(c_password)); + StrBuf_ServGetln(Buf); + if (GetServerStatus(Buf, NULL) == 2) { + StrBuf *Lang; + become_logged_in(c_username, c_password, Buf); + if (get_preference("language", &Lang)) { + set_selected_language(ChrPtr(Lang)); + go_selected_language(); /* set locale */ + } + get_preference("default_header_charset", &WCC->DefaultCharset); } } } - /** + + /* + * If a 'gotofirst' parameter has been specified, attempt to goto that room + * prior to doing anything else. + */ + if (havebstr("gotofirst")) { + gotoroom(sbstr("gotofirst")); /* do this quietly to avoid session output! */ + } + + /* * If we don't have a current room, but a cookie specifying the * current room is supplied, make an effort to go there. */ - if ((IsEmptyStr(WC->wc_roomname)) && (!IsEmptyStr(c_roomname))) { - serv_printf("GOTO %s", c_roomname); - serv_getln(buf, sizeof buf); - if (buf[0] == '2') { - safestrncpy(WC->wc_roomname, c_roomname, sizeof WC->wc_roomname); + if ((StrLength(WCC->wc_roomname) == 0) && (StrLength(c_roomname) > 0)) { + serv_printf("GOTO %s", ChrPtr(c_roomname)); + StrBuf_ServGetln(Buf); + if (GetServerStatus(Buf, NULL) == 2) { + if (WCC->wc_roomname == NULL) { + WCC->wc_roomname = NewStrBufDup(c_roomname); + } + else { + FlushStrBuf(WCC->wc_roomname); + StrBufAppendBuf(WCC->wc_roomname, c_roomname, 0); + } } } - - if (!strcasecmp(action, "image")) { - output_image(); - } else if (!strcasecmp(action, "display_mime_icon")) { - display_mime_icon(); - - /** - * 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... - */ - - else if (!strcasecmp(action, "do_welcome")) { - do_welcome(); - } else if (!strcasecmp(action, "blank")) { - 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, "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(); - 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")) { - slrp_highest(); - gotonext(); - } else if (!strcasecmp(action, "skip")) { - gotonext(); - } else if (!strcasecmp(action, "ungoto")) { - ungoto(); - } else if (!strcasecmp(action, "dotgoto")) { - if (WC->wc_view != VIEW_MAILBOX) { /* dotgoto acts like dotskip when we're in a mailbox view */ - slrp_highest(); + + GetHash(HandlerHash, action, strlen(action) /* TODO*/, &vHandler), + Handler = (WebcitHandler*) vHandler; + if (Handler != NULL) { + if (!WCC->logged_in && ((Handler->Flags & ANONYMOUS) == 0)) { + display_login(NULL); + } + else { + if((Handler->Flags & NEED_URL)) { + if (WCC->UrlFragment1 == NULL) + WCC->UrlFragment1 = NewStrBuf(); + if (WCC->UrlFragment2 == NULL) + WCC->UrlFragment2 = NewStrBuf(); + if (WCC->UrlFragment3 == NULL) + WCC->UrlFragment3 = NewStrBuf(); + StrBufPrintf(WCC->UrlFragment1, "%s", index[0]); + StrBufPrintf(WCC->UrlFragment2, "%s", index[1]); + StrBufPrintf(WCC->UrlFragment3, "%s", index[2]); + } + if ((Handler->Flags & AJAX) != 0) + begin_ajax_response(); + Handler->F(); + if ((Handler->Flags & AJAX) != 0) + end_ajax_response(); } - smart_goto(bstr("room")); - } else if (!strcasecmp(action, "dotskip")) { - smart_goto(bstr("room")); - } else if (!strcasecmp(action, "termquit")) { - do_logout(); - } else if (!strcasecmp(action, "readnew")) { - readloop("readnew"); - } else if (!strcasecmp(action, "readold")) { - readloop("readold"); - } else if (!strcasecmp(action, "readfwd")) { - 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(index[1]); - } else if (!strcasecmp(action, "printmsg")) { - 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")) { - post_message(); - } 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")) { - showuser(); - } else if (!strcasecmp(action, "display_page")) { - display_page(); - } else if (!strcasecmp(action, "page_user")) { - page_user(); - } else if (!strcasecmp(action, "chat")) { - do_chat(); - } else if (!strcasecmp(action, "display_private")) { - display_private("", 0); - } else if (!strcasecmp(action, "goto_private")) { - goto_private(); - } else if (!strcasecmp(action, "zapped_list")) { - zapped_list(); - } else if (!strcasecmp(action, "display_zap")) { - display_zap(); - } else if (!strcasecmp(action, "zap")) { - zap(); - } else if (!strcasecmp(action, "display_entroom")) { - 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_editinfo")) { - 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")) { - 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); - } else if (!strcasecmp(action, "confirm_move_msg")) { - confirm_move_msg(); - } else if (!strcasecmp(action, "delete_room")) { - 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"), - "_userpic_", - "editpic"); - } else if (!strcasecmp(action, "editpic")) { - do_graphics_upload("_userpic_"); - /* room picture dispay / upload facility */ - } else if (!strcasecmp(action, "display_editroompic")) { - display_graphics_upload(_("the icon for this room"), - "_roompic_", - "editroompic"); - } else if (!strcasecmp(action, "editroompic")) { - do_graphics_upload("_roompic_"); - /* the greetingpage hello pic */ - } else if (!strcasecmp(action, "display_edithello")) { - display_graphics_upload(_("the Greetingpicture for the login prompt"), - "hello", - "edithellopic"); - } else if (!strcasecmp(action, "edithellopic")) { - do_graphics_upload("hello"); - /* the logoff banner */ - } else if (!strcasecmp(action, "display_editgoodbyepic")) { - display_graphics_upload(_("the Logoff banner picture"), - "UIMG 0|%s|goodbuye", - "editgoodbuyepic"); - } else if (!strcasecmp(action, "editgoodbuyepic")) { - do_graphics_upload("UIMG 1|%s|goodbuye"); - - } else if (!strcasecmp(action, "delete_floor")) { - delete_floor(); - } else if (!strcasecmp(action, "rename_floor")) { - rename_floor(); - } else if (!strcasecmp(action, "create_floor")) { - create_floor(); - } else if (!strcasecmp(action, "display_editfloorpic")) { - 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")) { - snprintf(buf, SIZ, "UIMG 1|_floorpic_|%s", - bstr("which_floor")); - do_graphics_upload(buf); - } else if (!strcasecmp(action, "display_reg")) { - display_reg(0); - } else if (!strcasecmp(action, "display_changepw")) { - display_changepw(); - } else if (!strcasecmp(action, "changepw")) { - changepw(); - } else if (!strcasecmp(action, "display_edit_node")) { - display_edit_node(); - } else if (!strcasecmp(action, "edit_node")) { - edit_node(); - } else if (!strcasecmp(action, "display_netconf")) { - display_netconf(); - } else if (!strcasecmp(action, "display_confirm_delete_node")) { - display_confirm_delete_node(); - } else if (!strcasecmp(action, "delete_node")) { - delete_node(); - } else if (!strcasecmp(action, "display_add_node")) { - display_add_node(); - } else if (!strcasecmp(action, "terminate_session")) { - slrp_highest(); - terminate_session(); - } else if (!strcasecmp(action, "edit_me")) { - edit_me(); - } else if (!strcasecmp(action, "display_siteconfig")) { - display_siteconfig(); - } else if (!strcasecmp(action, "chat_recv")) { - chat_recv(); - } else if (!strcasecmp(action, "chat_send")) { - chat_send(); - } else if (!strcasecmp(action, "siteconfig")) { - siteconfig(); - } else if (!strcasecmp(action, "display_generic")) { - 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, "mimepart")) { - 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")) { - submit_vcard(); - } else if (!strcasecmp(action, "select_user_to_edit")) { - select_user_to_edit(NULL, NULL); - } else if (!strcasecmp(action, "display_edituser")) { - display_edituser(NULL, 0); - } else if (!strcasecmp(action, "edituser")) { - edituser(); - } else if (!strcasecmp(action, "create_user")) { - create_user(); - } else if (!strcasecmp(action, "changeview")) { - change_view(); - } else if (!strcasecmp(action, "change_start_page")) { - change_start_page(); - } else if (!strcasecmp(action, "display_floorconfig")) { - display_floorconfig(NULL); - } else if (!strcasecmp(action, "toggle_self_service")) { - toggle_self_service(); - } else if (!strcasecmp(action, "display_edit_task")) { - display_edit_task(); - } else if (!strcasecmp(action, "save_task")) { - save_task(); - } else if (!strcasecmp(action, "display_edit_event")) { - display_edit_event(); - } else if (!strcasecmp(action, "save_event")) { - save_event(); - } else if (!strcasecmp(action, "respond_to_request")) { - respond_to_request(); - } else if (!strcasecmp(action, "handle_rsvp")) { - handle_rsvp(); - } else if (!strcasecmp(action, "summary")) { - summary(); - } 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")) { - commit_iconbar(); - } else if (!strcasecmp(action, "set_room_policy")) { - set_room_policy(); - } else if (!strcasecmp(action, "display_inetconf")) { - 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")) { - 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, "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); - wprintf("Command:
\n");
-		escputs(cmd);
-		wprintf("

\n"); - wprintf("Variables:
\n");
-		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, "display_pictureview")) { - display_pictureview(); - } 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(); + if (!WCC->logged_in) + display_login(NULL); + else + display_main_menu(); } SKIP_ALL_THIS_CRAP: + if (WCC->SavePrefsToServer) { + save_preferences(); + WCC->SavePrefsToServer = 0; + } + FreeStrBuf(&Buf); + FreeStrBuf(&c_username); + FreeStrBuf(&c_password); + FreeStrBuf(&c_roomname); + FreeStrBuf(&c_httpauth_user); + FreeStrBuf(&c_httpauth_pass); + FreeStrBuf(&WCC->this_page); fflush(stdout); if (content != NULL) { - free(content); + FreeStrBuf(&content); content = NULL; } - free_urls(); - if (WC->upload_length > 0) { - free(WC->upload); - WC->upload_length = 0; + DeleteHash(&WCC->urlstrings); + if (WCC->upload_length > 0) { + free(WCC->upload); + WCC->upload_length = 0; } + FreeStrBuf(&WCC->trailing_javascript); + WCC->http_host = NULL; } -/** - * \brief Replacement for sleep() that uses select() in order to avoid SIGALRM - * \param seconds how many seconds should we sleep? + +/* + * Replacement for sleep() that uses select() in order to avoid SIGALRM */ void sleeeeeeeeeep(int seconds) { @@ -1963,4 +1059,58 @@ void sleeeeeeeeeep(int seconds) } -/*@}*/ +int ConditionalImportantMesage(StrBuf *Target, WCTemplputParams *TP) +{ + wcsession *WCC = WC; + if (WCC != NULL) + return (!IsEmptyStr(WCC->ImportantMessage)); + else + return 0; +} + +void tmplput_importantmessage(StrBuf *Target, WCTemplputParams *TP) +{ + wcsession *WCC = WC; + + if (WCC != NULL) { +/* + StrBufAppendTemplate(Target, nArgs, Tokens, Context, ContextType, + WCC->ImportantMessage, 0); +*/ + StrEscAppend(Target, NULL, WCC->ImportantMessage, 0, 0); + WCC->ImportantMessage[0] = '\0'; + } +} + +void tmplput_trailing_javascript(StrBuf *Target, WCTemplputParams *TP) +{ + wcsession *WCC = WC; + + if (WCC != NULL) + StrBufAppendTemplate(Target, TP, WCC->trailing_javascript, 0); +} + +void tmplput_csslocal(StrBuf *Target, WCTemplputParams *TP) +{ + extern StrBuf *csslocal; + StrBufAppendBuf(Target, + csslocal, 0); +} + + + + +void +InitModule_WEBCIT +(void) +{ + WebcitAddUrlHandler(HKEY("blank"), blank_page, ANONYMOUS); + WebcitAddUrlHandler(HKEY("do_template"), url_do_template, ANONYMOUS); + WebcitAddUrlHandler(HKEY("sslg"), seconds_since_last_gexp, AJAX); + WebcitAddUrlHandler(HKEY("ajax_servcmd"), ajax_servcmd, 0); + + RegisterConditional(HKEY("COND:IMPMSG"), 0, ConditionalImportantMesage, CTX_NONE); + RegisterNamespace("CSSLOCAL", 0, 0, tmplput_csslocal, CTX_NONE); + RegisterNamespace("IMPORTANTMESSAGE", 0, 0, tmplput_importantmessage, CTX_NONE); + RegisterNamespace("TRAILING_JAVASCRIPT", 0, 0, tmplput_trailing_javascript, CTX_NONE); +}