X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fwebcit.c;h=dd6955d68ee834eb9a0119a41a19e13918f962a6;hb=9f145319b92b196662aa51cb2e3d7c392629965e;hp=c8a49e6025a6343dacf60fa7ab48bd13e2d07214;hpb=1638755b1a025a11d8e837f02d3e6f2d5df255cb;p=citadel.git diff --git a/webcit/webcit.c b/webcit/webcit.c index c8a49e602..dd6955d68 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -1,51 +1,77 @@ /* * $Id$ - */ -/** - * \defgroup MainServer This is the main transaction loop of the web service. It maintains a + * + * 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" -/** +#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) +long unescape_input(char *buf) { int a, b; char hex[3]; + long buflen; + long len; + + 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] == '%') { - hex[0] = buf[a + 1]; - hex[1] = buf[a + 2]; - hex[2] = 0; - b = 0; - sscanf(hex, "%02x", &b); - buf[a] = (char) b; - strcpy(&buf[a + 1], &buf[a + 3]); + /* 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); } /** @@ -54,56 +80,56 @@ void unescape_input(char *buf) */ void addurls(char *url) { - char *up, *ptr; - char buf[SIZ]; - int a, b; - struct urlcontent *u; - + 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; - while (strlen(up) > 0) { - - /** locate the = sign */ - safestrncpy(buf, up, sizeof buf); - b = (-1); - for (a = 255; a >= 0; --a) - if (buf[a] == '=') - b = a; - if (b < 0) + /** 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; - buf[b] = 0; - - u = (struct urlcontent *) malloc(sizeof(struct urlcontent)); - u->next = WC->urlstrings; - WC->urlstrings = u; - safestrncpy(u->url_key, buf, sizeof u->url_key); - - /** now chop that part off */ - for (a = 0; a <= b; ++a) - ++up; - - /** locate "&" and "?" delimiters */ - ptr = up; - b = strlen(up); - for (a = 0; a < strlen(up); ++a) { - if ( (ptr[0] == '&') || (ptr[0] == '?') ) { - b = a; - break; - } - ++ptr; + *aptr = '\0'; + aptr++; + bptr = aptr; + while ((bptr < eptr) && (*bptr != '\0') + && (*bptr != '&') && (*bptr != '?') && (*bptr != ' ')) { + bptr++; } - ptr = up; - for (a = 0; a < b; ++a) - ++ptr; - strcpy(ptr, ""); - - u->url_data = malloc(strlen(up) + 2); - safestrncpy(u->url_data, up, strlen(up) + 1); - u->url_data[b] = 0; - unescape_input(u->url_data); - up = ptr; + *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; - /* lprintf(9, "%s = %s\n", u->url_key, u->url_data); */ + lprintf(9, "%s = [%ld] %s\n", u->url_key, u->url_data_size, u->url_data); } } @@ -112,24 +138,25 @@ void addurls(char *url) */ void free_urls(void) { - struct urlcontent *u; - - while (WC->urlstrings != NULL) { - free(WC->urlstrings->url_data); - u = WC->urlstrings->next; - free(WC->urlstrings); - WC->urlstrings = u; - } + DeleteHash(&WC->urlstrings); } /** * \brief Diagnostic function to display the contents of all variables */ + void dump_vars(void) { - struct urlcontent *u; - - for (u = WC->urlstrings; u != NULL; u = u->next) { + struct wcsession *WCC = WC; + urlcontent *u; + void *U; + long HKLen; + char *HKey; + HashPos *Cursor; + + Cursor = GetNewHashPos (); + while (GetNextHashPos(WCC->urlstrings, Cursor, &HKLen, &HKey, &U)) { + u = (urlcontent*) U; wprintf("%38s = %s\n", u->url_key, u->url_data); } } @@ -138,15 +165,147 @@ 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) + +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 (""); + } +} + +const char *XBSTR(char *key, size_t *len) { - struct urlcontent *u; + void *U; - for (u = WC->urlstrings; u != NULL; u = u->next) { - if (!strcasecmp(u->url_key, key)) - return (u->url_data); + 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 (""); } - return (""); +} + + +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 (""); +} + +const char *Bstr(char *key, size_t keylen) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, keylen, &U)) + return ((urlcontent *)U)->url_data; + else + return (""); +} + +long LBstr(char *key, size_t keylen) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, keylen, &U)) + return atol(((urlcontent *)U)->url_data); + else + return (0); +} + +long LBSTR(char *key) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, strlen(key), &U)) + return atol(((urlcontent *)U)->url_data); + else + return (0); +} + +int IBstr(char *key, size_t keylen) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, keylen, &U)) + return atoi(((urlcontent *)U)->url_data); + else + return (0); +} + +int IBSTR(char *key) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, strlen(key), &U)) + return atoi(((urlcontent *)U)->url_data); + else + return (0); +} + +int HaveBstr(char *key, size_t keylen) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, keylen, &U)) + return ((urlcontent *)U)->url_data_size != 0; + else + return (0); +} + +int HAVEBSTR(char *key) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, strlen(key), &U)) + return ((urlcontent *)U)->url_data_size != 0; + else + return (0); +} + + +int YesBstr(char *key, size_t keylen) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, keylen, &U)) + return strcmp( ((urlcontent *)U)->url_data, "yes") == 0; + else + return (0); +} + +int YESBSTR(char *key) +{ + void *U; + + if ((WC->urlstrings != NULL) && + GetHash(WC->urlstrings, key, strlen(key), &U)) + return strcmp( ((urlcontent *)U)->url_data, "yes") == 0; + else + return (0); } /** @@ -195,37 +354,68 @@ void wDumpContent(int print_standard_html_footer) * \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); } /** @@ -237,10 +427,12 @@ void stresc(char *target, char *strbuf, int nbsp, int nolinebreaks) 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); } @@ -254,32 +446,6 @@ void escputs(char *strbuf) escputs1(strbuf, 0, 0); } -/** - * \brief Escape a string for feeding out as a URL. - * Returns a pointer to a buffer that must be freed by the caller! - * \param outbuf the output buffer - * \param strbuf the input buffer - */ -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 @@ -289,7 +455,7 @@ void urlescputs(char *strbuf) { char outbuf[SIZ]; - urlesc(outbuf, strbuf); + urlesc(outbuf, SIZ, strbuf); wprintf("%s", outbuf); } @@ -299,26 +465,59 @@ void urlescputs(char *strbuf) * \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'; } /** @@ -329,7 +528,7 @@ void jsescputs(char *strbuf) { char outbuf[SIZ]; - jsesc(outbuf, strbuf); + jsesc(outbuf, SIZ, strbuf); wprintf("%s", outbuf); } @@ -338,22 +537,64 @@ void jsescputs(char *strbuf) * \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); } /** @@ -362,10 +603,12 @@ void msgesc(char *target, char *strbuf) */ 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); } @@ -398,7 +641,7 @@ void output_headers( int do_httpheaders, /**< 1 = output HTTP headers 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 ); } @@ -412,10 +655,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) { @@ -442,15 +686,16 @@ void output_headers( int do_httpheaders, /**< 1 = output HTTP headers /** check for ImportantMessages (these display in a div overlaying the main screen) */ - if (strlen(WC->ImportantMessage) > 0) { - wprintf("
\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) ) { @@ -493,7 +738,7 @@ void http_redirect(char *whichpage) { /** * \brief Output a piece of content to the web browser */ -void http_transmit_thing(char *thing, size_t length, char *content_type, +void http_transmit_thing(char *thing, size_t length, const char *content_type, int is_static) { output_headers(0, 0, 0, 0, 0, is_static); @@ -502,15 +747,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 (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, @@ -537,6 +782,39 @@ 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"); +} /** @@ -548,64 +826,63 @@ 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]; + const char *content_type; + 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)) - safestrncpy(content_type, "image/gif", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".txt", 4)) - safestrncpy(content_type, "text/plain", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".css", 4)) - safestrncpy(content_type, "text/css", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".jpg", 4)) - safestrncpy(content_type, "image/jpeg", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".png", 4)) - safestrncpy(content_type, "image/png", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".ico", 4)) - safestrncpy(content_type, "image/x-icon", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 5], ".html", 5)) - safestrncpy(content_type, "text/html", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".htm", 4)) - safestrncpy(content_type, "text/html", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 4], ".wml", 4)) - safestrncpy(content_type, "text/vnd.wap.wml", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 5], ".wmls", 5)) - safestrncpy(content_type, "text/vnd.wap.wmlscript", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 5], ".wmlc", 5)) - safestrncpy(content_type, "application/vnd.wap.wmlc", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 6], ".wmlsc", 6)) - safestrncpy(content_type, "application/vnd.wap.wmlscriptc", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 5], ".wbmp", 5)) - safestrncpy(content_type, "image/vnd.wap.wbmp", sizeof content_type); - else if (!strncasecmp(&what[strlen(what) - 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); + len = strlen (what); + content_type = GuessMimeByFilename(what, len); + + 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); http_transmit_thing(bigbuffer, (size_t)bytes, content_type, 1); free(bigbuffer); } - 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. @@ -615,6 +892,7 @@ 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); @@ -627,20 +905,29 @@ void output_image() serv_puts("CLOS"); serv_getln(buf, sizeof buf); + MimeType = GuessMimeType (xferbuf, bytes); /** Write it to the browser */ - http_transmit_thing(xferbuf, (size_t)bytes, "image/gif", 0); + if (!IsEmptyStr(MimeType)) + { + http_transmit_thing(xferbuf, + (size_t)bytes, + MimeType, + 0); + free(xferbuf); + return; + } + /* hm... unknown mimetype? fallback to blank gif */ free(xferbuf); + } - } else { - /** - * Instead of an ugly 404, send a 1x1 transparent GIF - * when there's no such image on the server. - */ - output_static("static/blank.gif"); - } - - - + + /** + * 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); } /** @@ -764,16 +1051,16 @@ void url_do_template(void) { 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 } @@ -847,24 +1134,29 @@ 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; + 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); */ + if (WC->urlstrings == NULL) + WC->urlstrings = NewHash(); /* Form fields */ - if ( (length > 0) && (strlen(cbtype) == 0) ) { - u = (struct urlcontent *) malloc(sizeof(struct urlcontent)); - u->next = WC->urlstrings; - WC->urlstrings = u; + 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) && (strlen(cbtype) > 0) ) { + if ( (length > 0) && (!IsEmptyStr(cbtype)) ) { WC->upload = malloc(length); if (WC->upload != NULL) { WC->upload_length = length; @@ -891,8 +1183,10 @@ 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(); } @@ -1014,6 +1308,7 @@ void session_loop(struct httprequest *req) int body_start = 0; int is_static = 0; 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. @@ -1102,7 +1397,7 @@ void session_loop(struct httprequest *req) } } else if (!strncasecmp(buf, "Host: ", 6)) { - if (strlen(WC->http_host) == 0) { + if (IsEmptyStr(WC->http_host)) { safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host); } } @@ -1122,22 +1417,19 @@ 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); + 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; @@ -1149,13 +1441,18 @@ void session_loop(struct httprequest *req) 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) { + 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; } } @@ -1197,14 +1494,28 @@ void session_loop(struct httprequest *req) else { lprintf(9, "Suspicious request. Ignoring."); - wprintf("HTTP/1.1 404 Not found. Don't try to Trick me DUDE!\r\n"); + wprintf("HTTP/1.1 404 Security check failed\r\n"); wprintf("Content-Type: text/plain\r\n"); wprintf("\r\n"); - wprintf("Not found. Don't play games on me!\r\n"); + wprintf("You have sent a malformed or invalid request.\r\n"); } goto SKIP_ALL_THIS_CRAP; /* Don't try to connect */ } + /* If the client sent a nonce that is incorrect, kill the request. */ + if (strlen(bstr("nonce")) > 0) { + lprintf(9, "Comparing supplied nonce %s to session nonce %ld\n", + bstr("nonce"), WC->nonce); + if (ibstr("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. @@ -1212,7 +1523,7 @@ void session_loop(struct httprequest *req) 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 { @@ -1263,12 +1574,10 @@ void session_loop(struct httprequest *req) do_listsub(); goto SKIP_ALL_THIS_CRAP; } -#ifdef WEBCIT_WITH_CALENDAR_SERVICE if (!strcasecmp(action, "freebusy")) { do_freebusy(cmd); goto SKIP_ALL_THIS_CRAP; } -#endif /** * If we're not logged in, but we have HTTP Authentication data, @@ -1296,10 +1605,12 @@ void session_loop(struct httprequest *req) } /** 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 @@ -1333,8 +1644,8 @@ void session_loop(struct httprequest *req) * 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') { @@ -1349,7 +1660,7 @@ 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') { @@ -1359,6 +1670,8 @@ void session_loop(struct httprequest *req) 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 @@ -1382,6 +1695,8 @@ 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")) { @@ -1392,6 +1707,26 @@ void session_loop(struct httprequest *req) 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(); @@ -1479,11 +1814,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_fullname); + 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); @@ -1493,18 +1828,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_", + "_userpic_", "editpic"); } else if (!strcasecmp(action, "editpic")) { - do_graphics_upload("UIMG 1|_userpic_"); + do_graphics_upload("_userpic_"); + /* room picture dispay / upload facility */ } else if (!strcasecmp(action, "display_editroompic")) { display_graphics_upload(_("the icon for this room"), - "UIMG 0|_roompic_", + "_roompic_", "editroompic"); } else if (!strcasecmp(action, "editroompic")) { - do_graphics_upload("UIMG 1|_roompic_"); + 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")) { @@ -1512,13 +1864,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")) { @@ -1539,8 +1891,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(); @@ -1586,7 +1936,6 @@ void session_loop(struct httprequest *req) display_floorconfig(NULL); } else if (!strcasecmp(action, "toggle_self_service")) { toggle_self_service(); -#ifdef WEBCIT_WITH_CALENDAR_SERVICE } else if (!strcasecmp(action, "display_edit_task")) { display_edit_task(); } else if (!strcasecmp(action, "save_task")) { @@ -1599,7 +1948,6 @@ void session_loop(struct httprequest *req) respond_to_request(); } else if (!strcasecmp(action, "handle_rsvp")) { handle_rsvp(); -#endif } else if (!strcasecmp(action, "summary")) { summary(); } else if (!strcasecmp(action, "summary_inner_div")) { @@ -1624,6 +1972,10 @@ void session_loop(struct httprequest *req) 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")) { @@ -1642,6 +1994,10 @@ 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")) { @@ -1658,6 +2014,8 @@ void session_loop(struct httprequest *req) 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")) { @@ -1682,5 +2040,18 @@ SKIP_ALL_THIS_CRAP: } } +/** + * \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); +} + /*@}*/