X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fwebcit.c;h=b615dbc5a81bf43d1575fde006f3c8583fbbb854;hb=abeb8adc38f9d55fcb6cb3d076f57239b0a9a4d5;hp=1233b04a4ab7530d8f1e0328355398fbe2291fcc;hpb=7c5d265ebf85f3d84c8d33c72e59846a43a2e17c;p=citadel.git diff --git a/webcit/webcit.c b/webcit/webcit.c index 1233b04a4..b615dbc5a 100644 --- a/webcit/webcit.c +++ b/webcit/webcit.c @@ -1,11 +1,10 @@ /* - * webcit.c + * $Id$ * - * This is the actual program called by the webserver. 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. * - * $Id$ */ #include @@ -29,6 +28,7 @@ #include #include #include "webcit.h" +#include "groupdav.h" #include "webserver.h" #include "mime_parser.h" @@ -54,6 +54,7 @@ void unescape_input(char *buf) hex[0] = buf[a + 1]; hex[1] = buf[a + 2]; hex[2] = 0; + b = 0; sscanf(hex, "%02x", &b); buf[a] = (char) b; strcpy(&buf[a + 1], &buf[a + 3]); @@ -92,11 +93,11 @@ void addurls(char *url) for (a = 0; a <= b; ++a) ++up; - /* locate the & sign */ + /* locate "&" and "?" delimiters */ ptr = up; b = strlen(up); for (a = 0; a < strlen(up); ++a) { - if (!strncmp(ptr, "&", 1)) { + if ( (ptr[0] == '&') || (ptr[0] == '?') ) { b = a; break; } @@ -107,7 +108,7 @@ void addurls(char *url) ++ptr; strcpy(ptr, ""); - u->url_data = malloc(strlen(up) + 1); + u->url_data = malloc(strlen(up) + 2); strcpy(u->url_data, up); u->url_data[b] = 0; unescape_input(u->url_data); @@ -158,10 +159,10 @@ void wprintf(const char *format,...) char wbuf[4096]; va_start(arg_ptr, format); - vsprintf(wbuf, format, arg_ptr); + vsnprintf(wbuf, sizeof wbuf, format, arg_ptr); va_end(arg_ptr); - write(WC->http_sock, wbuf, strlen(wbuf)); + client_write(wbuf, strlen(wbuf)); } @@ -175,10 +176,14 @@ void wprintf(const char *format,...) void wDumpContent(int print_standard_html_footer) { if (print_standard_html_footer) { + wprintf("\n"); /* end of "text" div */ do_template("trailing"); } - + /* If we've been saving it all up for one big output burst, + * go ahead and do that now. + */ + end_burst(); } @@ -186,7 +191,7 @@ void wDumpContent(int print_standard_html_footer) * Copy a string, escaping characters which have meaning in HTML. If * nbsp is nonzero, spaces are converted to non-breaking spaces. */ -void stresc(char *target, char *strbuf, int nbsp) +void stresc(char *target, char *strbuf, int nbsp, int nolinebreaks) { int a; strcpy(target, ""); @@ -208,24 +213,31 @@ void stresc(char *target, char *strbuf, int nbsp) strcat(target, ">"); else if (strbuf[a] == QU) strcat(target, "\""); - else if ((strbuf[a] == 32) && (nbsp == 1)) { + else if ((strbuf[a] == 32) && (nbsp == 1)) strcat(target, " "); - } else { + else if ((strbuf[a] == '\n') && (nolinebreaks)) + strcat(target, ""); /* nothing */ + else if ((strbuf[a] == '\r') && (nolinebreaks)) + strcat(target, ""); /* nothing */ + else strncat(target, &strbuf[a], 1); - } } } -void escputs1(char *strbuf, int nbsp) +void escputs1(char *strbuf, int nbsp, int nolinebreaks) { - char buf[1024]; - stresc(buf, strbuf, nbsp); + char *buf; + + if (strbuf == NULL) return; + buf = malloc( (3 * strlen(strbuf)) + SIZ ); + stresc(buf, strbuf, nbsp, nolinebreaks); wprintf("%s", buf); + free(buf); } void escputs(char *strbuf) { - escputs1(strbuf, 0); + escputs1(strbuf, 0, 0); } /* @@ -262,109 +274,188 @@ void urlescputs(char *strbuf) } +/* + * Copy a string, escaping characters for JavaScript strings. + */ +void jsesc(char *target, 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); + } + } +} +void jsescputs(char *strbuf) +{ + char outbuf[SIZ]; + + jsesc(outbuf, strbuf); + wprintf("%s", outbuf); +} /* - * Output all that important stuff that the browser will want to see - * - * control codes: - * - * Bits 0 and 1: - * 0 = Nothing. Do not display any leading HTTP or HTML. - * 1 = HTTP headers plus the room banner - * 2 = HTTP headers required to terminate the session (unset cookies) - * 3 = HTTP and HTML headers, but no room banner - * - * Bit 2: Set to 1 to auto-refresh page every 30 seconds - * - * Bit 3: suppress check for express messages + * Copy a string, escaping characters for message text hold */ -void output_headers(int controlcode) +void msgesc(char *target, char *strbuf) { + int a; + strcpy(target, ""); + + for (a = 0; a < strlen(strbuf); ++a) { + if (strbuf[a] == '\'') + strcat(target, "\\'"); + else if (strbuf[a] == '\n') + strcat(target, " "); + else if (strbuf[a] == '\r') + strcat(target, " "); + else { + strncat(target, &strbuf[a], 1); + } + } +} + +void msgescputs(char *strbuf) { + char *outbuf; + + if (strbuf == NULL) return; + outbuf = malloc( (3 * strlen(strbuf)) + SIZ); + msgesc(outbuf, strbuf); + wprintf("%s", outbuf); + free(outbuf); +} + + + + +/* + * Output all that important stuff that the browser will want to see + */ +void output_headers( int do_httpheaders, /* 1 = output HTTP headers */ + int do_htmlhead, /* 1 = output HTML section and opener */ + + int do_room_banner, /* 0=no, 1=yes, */ + /* 2 = I'm going to embed my own, so don't open the */ + /*
either. */ + + int unset_cookies, /* 1 = session is terminating, so unset the cookies */ + int refresh30, /* 1 = automatically refresh page every 30 seconds */ + int suppress_check, /* 1 = suppress check for instant messages */ + int cache /* 1 = allow browser to cache this page */ +) { char cookie[SIZ]; - int print_standard_html_head = 0; - int refresh30 = 0; - int suppress_check = 0; char httpnow[SIZ]; - static int pageseq = 0; - print_standard_html_head = controlcode & 0x03; - refresh30 = ((controlcode & 0x04) >> 2); - suppress_check = ((controlcode & 0x08) >> 3); wprintf("HTTP/1.0 200 OK\n"); - httpdate(httpnow, time(NULL)); - if (print_standard_html_head > 0) { - wprintf("Content-type: text/html\n" - "Server: %s\n", SERVER + if (do_httpheaders) { + wprintf("Content-type: text/html\r\n" + "Server: %s / %s\n" + "Connection: close\r\n", + SERVER, serv_info.serv_software ); - wprintf("Connection: close\n" - "Pragma: no-cache\n" - "Cache-Control: no-store\n" + } + + if (cache) { + wprintf("Pragma: public\r\n" + "Cache-Control: max-age=3600, must-revalidate\r\n" + "Last-modified: %s\r\n", + httpnow + ); + } + else { + wprintf("Pragma: no-cache\r\n" + "Cache-Control: no-store\r\n" ); } + stuff_to_cookie(cookie, WC->wc_session, WC->wc_username, WC->wc_password, WC->wc_roomname); - if (print_standard_html_head == 2) { - wprintf("Set-cookie: webcit=%s\n", unset); + + if (unset_cookies) { + wprintf("Set-cookie: webcit=%s; path=/\r\n", unset); } else { - wprintf("Set-cookie: webcit=%s\n", cookie); + wprintf("Set-cookie: webcit=%s; path=/\r\n", cookie); if (server_cookie != NULL) { wprintf("%s\n", server_cookie); } } - if (print_standard_html_head > 0) { - wprintf("\n"); - - if (refresh30) svprintf("REFRESHTAG", WCS_STRING, - "\n"); - else svprintf("REFRESHTAG", WCS_STRING, - "\n"); - /* script for checking for pages (not always launched) */ - svprintf("PAGERSCRIPT", WCS_STRING, - "\n", - ++pageseq - ); - /* end script */ - - do_template("head"); - clear_local_substs(); + if (do_htmlhead) { + /* wprintf("\n"); */ + begin_burst(); - if (!suppress_check) if (WC->HaveExpressMessages) { - svprintf("extrabodyparms", WCS_STRING, "%s", - "onload=\"launch_page_popup()\" "); - WC->HaveExpressMessages = 0; + if (refresh30) { + svprintf("REFRESHTAG", WCS_STRING, "%s", + "\n"); + } + else { + svprintf("REFRESHTAG", WCS_STRING, "%s", + "\n"); } - do_template("background"); - clear_local_substs(); + do_template("head"); + } - if (print_standard_html_head == 1) { - wprintf(""); + /* ICONBAR */ + if (do_htmlhead) { - embed_room_banner(NULL); + if (WC->HaveInstantMessages) { + wprintf("
\n"); + page_popup(); + wprintf("
\n"); + } + if ( (WC->logged_in) && (!unset_cookies) ) { + wprintf("
"); + do_iconbar(); + wprintf("
\n"); + } + if (do_room_banner == 1) { + wprintf("
\n"); + embed_room_banner(NULL, navbar_default); + wprintf("
\n"); + } + } + if (do_room_banner == 1) { + wprintf("
\n"); + + if (strlen(WC->ImportantMessage) > 0) { + wprintf("
\n"); + do_template("beginbox_nt"); + wprintf("" + "%s
\n", WC->ImportantMessage); + do_template("endbox"); + wprintf("
\n"); + strcpy(WC->ImportantMessage, ""); } + } } /* - * + * Generic function to do an HTTP redirect. Easy and fun. */ void http_redirect(char *whichpage) { wprintf("HTTP/1.0 302 Moved Temporarily\n"); - wprintf("Location: %s\n", whichpage); - wprintf("URI: %s\n", whichpage); - wprintf("Content-type: text/html\n\n"); + wprintf("Location: %s\r\n", whichpage); + wprintf("URI: %s\r\n", whichpage); + wprintf("Content-type: text/html\r\n\r\n"); wprintf("\n"); wprintf("you really want to be here now\n", whichpage); @@ -373,13 +464,13 @@ void http_redirect(char *whichpage) { -void check_for_express_messages() +void check_for_instant_messages() { char buf[SIZ]; serv_puts("NOOP"); serv_gets(buf); - if (buf[3] == '*') WC->HaveExpressMessages = 1; + if (buf[3] == '*') WC->HaveInstantMessages = 1; } @@ -388,18 +479,48 @@ void check_for_express_messages() /* * Output a piece of content to the web browser */ -void http_transmit_thing(char *thing, size_t length, char *content_type) { - output_headers(0); - wprintf("Content-type: %s\n" - "Content-length: %ld\n" - "Server: %s\n" - "Connection: close\n" - "\n", +void http_transmit_thing(char *thing, size_t length, char *content_type, + int is_static) { + + output_headers(0, 0, 0, 0, 0, 0, is_static); + + wprintf("Content-type: %s\r\n" + "Server: %s\r\n" + "Connection: close\r\n", content_type, - (long) length, - SERVER + SERVER); + +#ifdef HAVE_ZLIB + /* If we can send the data out compressed, please do so. */ + if (WC->gzip_ok) { + char *compressed_data = NULL; + uLongf compressed_len; + + compressed_len = (uLongf) ((length * 101) / 100) + 100; + compressed_data = malloc(compressed_len); + + if (compress_gzip((Bytef *) compressed_data, + &compressed_len, + (Bytef *) thing, + (uLongf) length, Z_BEST_SPEED) == Z_OK) { + wprintf("Content-encoding: gzip\r\n" + "Content-length: %ld\r\n" + "\r\n", + (long) compressed_len + ); + client_write(compressed_data, (size_t)compressed_len); + free(compressed_data); + return; + } + } +#endif + + /* No compression ... just send it out as-is */ + wprintf("Content-length: %ld\r\n" + "\r\n", + (long) length ); - write(WC->http_sock, thing, (size_t)length); + client_write(thing, (size_t)length); } @@ -414,13 +535,12 @@ void output_static(char *what) char *bigbuffer; char content_type[SIZ]; - lprintf(9, "output_static(%s)\n", what); sprintf(buf, "static/%s", what); fp = fopen(buf, "rb"); if (fp == NULL) { wprintf("HTTP/1.0 404 %s\n", strerror(errno)); - wprintf("Content-Type: text/plain\n"); - wprintf("\n"); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); wprintf("Cannot open %s: %s\n", what, strerror(errno)); } else { if (!strncasecmp(&what[strlen(what) - 4], ".gif", 4)) @@ -433,8 +553,12 @@ void output_static(char *what) strcpy(content_type, "image/jpeg"); else if (!strncasecmp(&what[strlen(what) - 4], ".png", 4)) strcpy(content_type, "image/png"); + else if (!strncasecmp(&what[strlen(what) - 4], ".ico", 4)) + strcpy(content_type, "image/x-icon"); else if (!strncasecmp(&what[strlen(what) - 5], ".html", 5)) strcpy(content_type, "text/html"); + else if (!strncasecmp(&what[strlen(what) - 4], ".htm", 4)) + strcpy(content_type, "text/html"); else if (!strncasecmp(&what[strlen(what) - 4], ".wml", 4)) strcpy(content_type, "text/vnd.wap.wml"); else if (!strncasecmp(&what[strlen(what) - 5], ".wmls", 5)) @@ -444,18 +568,21 @@ void output_static(char *what) else if (!strncasecmp(&what[strlen(what) - 6], ".wmlsc", 6)) strcpy(content_type, "application/vnd.wap.wmlscriptc"); else if (!strncasecmp(&what[strlen(what) - 5], ".wbmp", 5)) - wprintf("Content-type: image/vnd.wap.wbmp"); + strcpy(content_type, "image/vnd.wap.wbmp"); + else if (!strncasecmp(&what[strlen(what) - 3], ".js", 3)) + strcpy(content_type, "text/javascript"); else - wprintf("Content-type: application/octet-stream"); + strcpy(content_type, "application/octet-stream"); fstat(fileno(fp), &statbuf); bytes = statbuf.st_size; - lprintf(3, "Static: %s, %ld bytes\n", what, bytes); - bigbuffer = malloc(bytes); + /* lprintf(3, "Static: %s, (%s; %ld bytes)\r\n", + what, content_type, bytes); */ + bigbuffer = malloc(bytes + 2); fread(bigbuffer, bytes, 1, fp); fclose(fp); - http_transmit_thing(bigbuffer, (size_t)bytes, content_type); + http_transmit_thing(bigbuffer, (size_t)bytes, content_type, 1); free(bigbuffer); } if (!strcasecmp(bstr("force_close_session"), "yes")) { @@ -478,7 +605,7 @@ void output_image() serv_gets(buf); if (buf[0] == '2') { bytes = extract_long(&buf[4], 0); - xferbuf = malloc(bytes); + xferbuf = malloc(bytes + 2); /* Read it from the server */ read_server_binary(xferbuf, bytes); @@ -486,17 +613,26 @@ void output_image() serv_gets(buf); /* Write it to the browser */ - http_transmit_thing(xferbuf, (size_t)bytes, "image/gif"); + http_transmit_thing(xferbuf, (size_t)bytes, "image/gif", 0); free(xferbuf); } else { + + /* Instead of an ugly 404, send a 1x1 transparent GIF + * when there's no such image on the server. + */ + output_static("blank.gif"); + + /* wprintf("HTTP/1.0 404 %s\n", &buf[4]); - output_headers(0); - wprintf("Content-Type: text/plain\n" - "\n" + output_headers(0, 0, 0, 0, 0, 0, 0); + wprintf("Content-Type: text/plain\r\n" + "\r\n" "Error retrieving image: %s\n", &buf[4] ); + */ + } @@ -516,19 +652,19 @@ void output_mimepart() serv_gets(buf); if (buf[0] == '2') { bytes = extract_long(&buf[4], 0); - content = malloc(bytes); - extract(content_type, &buf[4], 3); - output_headers(0); + content = malloc(bytes + 2); + extract_token(content_type, &buf[4], 3, '|', sizeof content_type); + output_headers(0, 0, 0, 0, 0, 0, 0); read_server_binary(content, bytes); serv_puts("CLOS"); serv_gets(buf); - http_transmit_thing(content, bytes, content_type); + http_transmit_thing(content, bytes, content_type, 0); free(content); } else { wprintf("HTTP/1.0 404 %s\n", &buf[4]); - output_headers(0); - wprintf("Content-Type: text/plain\n"); - wprintf("\n"); + output_headers(0, 0, 0, 0, 0, 0, 0); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); wprintf("Error retrieving part: %s\n", &buf[4]); } @@ -548,9 +684,9 @@ char *load_mimepart(long msgnum, char *partnum) serv_gets(buf); if (buf[0] == '2') { bytes = extract_long(&buf[4], 0); - extract(content_type, &buf[4], 3); + extract_token(content_type, &buf[4], 3, '|', sizeof content_type); - content = malloc(bytes + 1); + content = malloc(bytes + 2); read_server_binary(content, bytes); serv_puts("CLOS"); @@ -571,14 +707,15 @@ char *load_mimepart(long msgnum, char *partnum) void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext) { wprintf("HTTP/1.0 200 OK\n"); - output_headers(1); - wprintf("
", titlebarcolor); - wprintf("%s\n", titlebarmsg); - wprintf("

\n"); + output_headers(1, 1, 2, 0, 0, 0, 0); + wprintf("
\n"); + wprintf("
", titlebarcolor); + wprintf("%s\n", titlebarmsg); + wprintf("
\n"); + wprintf("
\n
\n"); escputs(messagetext); - wprintf("
\n"); + wprintf("
\n"); wDumpContent(1); } @@ -587,11 +724,18 @@ void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext) * Display a blank page. */ void blank_page(void) { - output_headers(7); + output_headers(1, 1, 0, 0, 1, 0, 0); wDumpContent(2); } +/* + * A template has been requested + */ +void url_do_template(void) { + do_template(bstr("template")); +} + /* @@ -601,7 +745,7 @@ void offer_start_page(void) { wprintf("this_page); wprintf("\">" - "Make this my start page" + "Make this my start page" "" ); } @@ -613,13 +757,15 @@ void offer_start_page(void) { void change_start_page(void) { if (bstr("startpage") == NULL) { - display_error("startpage set to null"); + strcpy(WC->ImportantMessage, + "startpage set to null"); + display_main_menu(); return; } set_preference("startpage", bstr("startpage")); - output_headers(3); + output_headers(1, 1, 0, 0, 0, 0, 0); do_template("newstartpage"); wDumpContent(1); } @@ -627,11 +773,6 @@ void change_start_page(void) { -void display_error(char *errormessage) -{ - convenience_page("770000", "Error", errormessage); -} - void display_success(char *successmessage) { convenience_page("007700", "OK", successmessage); @@ -644,13 +785,17 @@ void extract_action(char *actbuf, char *cmdbuf) int i; strcpy(actbuf, cmdbuf); - if (!strncasecmp(actbuf, "GET /", 5)) - strcpy(actbuf, &actbuf[5]); - if (!strncasecmp(actbuf, "PUT /", 5)) - strcpy(actbuf, &actbuf[5]); - if (!strncasecmp(actbuf, "POST /", 6)) - strcpy(actbuf, &actbuf[6]); + /* + * First strip out the http method + */ + remove_token(actbuf, 0, ' '); + if (actbuf[0] == ' ') strcpy(actbuf, &actbuf[1]); + if (actbuf[0] == '/') strcpy(actbuf, &actbuf[1]); + + /* + * Now kill invalid (for webcit) characters + */ for (i = 0; i < strlen(actbuf); ++i) { if (actbuf[i] == ' ') { actbuf[i] = 0; @@ -676,25 +821,35 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, size_t length, char *encoding, void *userdata) { + struct urlcontent *u; - lprintf(5, "UPLOAD HANDLER CALLED\n"); - lprintf(5, " name = %s\n", name); - lprintf(5, "filename = %s\n", filename); - lprintf(5, "encoding = %s\n", encoding); - lprintf(5, " type = %s\n", cbtype); - lprintf(5, " length = %ld\n", (long)length); + /* Form fields */ + if ( (length > 0) && (strlen(cbtype) == 0) ) { + u = (struct urlcontent *) malloc(sizeof(struct urlcontent)); + u->next = WC->urlstrings; + WC->urlstrings = u; + safestrncpy(u->url_key, name, sizeof(u->url_key)); + u->url_data = malloc(length + 1); + memcpy(u->url_data, content, length); + u->url_data[length] = 0; + } - if (length > 0) { + /* Uploaded files */ + if ( (length > 0) && (strlen(cbtype) > 0) ) { 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(9, "malloc() failed: %s\n", - strerror(errno)); + lprintf(3, "malloc() failed: %s\n", strerror(errno)); } } + } @@ -706,36 +861,41 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, void session_loop(struct httprequest *req) { char cmd[SIZ]; + char method[SIZ]; char action[SIZ]; char buf[SIZ]; int a, b; int ContentLength = 0; - int BytesRead; + int BytesRead = 0; char ContentType[512]; - char *content; - char *content_end; + char *content = NULL; + char *content_end = NULL; struct httprequest *hptr; char browser_host[SIZ]; char user_agent[SIZ]; + int body_start = 0; /* We stuff these with the values coming from the client cookies, * so we can use them to reconnect a timed out session if we have to. */ - char c_host[SIZ]; - char c_port[SIZ]; char c_username[SIZ]; char c_password[SIZ]; char c_roomname[SIZ]; + char c_httpauth_string[SIZ]; + char c_httpauth_user[SIZ]; + char c_httpauth_pass[SIZ]; char cookie[SIZ]; - strcpy(c_host, defaulthost); - strcpy(c_port, defaultport); strcpy(c_username, ""); strcpy(c_password, ""); strcpy(c_roomname, ""); + strcpy(c_httpauth_string, ""); + strcpy(c_httpauth_user, DEFAULT_HTTPAUTH_USER); + strcpy(c_httpauth_pass, DEFAULT_HTTPAUTH_PASS); WC->upload_length = 0; WC->upload = NULL; + WC->vars = NULL; WC->is_wap = 0; @@ -744,6 +904,7 @@ void session_loop(struct httprequest *req) strcpy(cmd, hptr->line); hptr = hptr->next; + extract_token(method, cmd, 0, ' ', sizeof method); extract_action(action, cmd); while (hptr != NULL) { @@ -751,9 +912,16 @@ void session_loop(struct httprequest *req) hptr = hptr->next; if (!strncasecmp(buf, "Cookie: webcit=", 15)) { - strcpy(cookie, &buf[15]); + safestrncpy(cookie, &buf[15], sizeof cookie); cookie_to_stuff(cookie, NULL, - c_username, c_password, c_roomname); + c_username, sizeof c_username, + c_password, sizeof c_password, + c_roomname, sizeof c_roomname); + } + else if (!strncasecmp(buf, "Authorization: Basic ", 21)) { + CtdlDecodeBase64(c_httpauth_string, &buf[21], strlen(&buf[21])); + extract_token(c_httpauth_user, c_httpauth_string, 0, ':', 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]); @@ -774,23 +942,22 @@ void session_loop(struct httprequest *req) } if (ContentLength > 0) { - lprintf(5, "Content length: %d\n", ContentLength); - content = malloc(ContentLength + 1); - memset(content, 0, ContentLength+1); - BytesRead = 0; - - while (BytesRead < ContentLength) { - a=read(WC->http_sock, &content[BytesRead], - ContentLength - BytesRead); - if (a <= 0) BytesRead = ContentLength; - else BytesRead += a; - } + content = malloc(ContentLength + SIZ); + memset(content, 0, ContentLength + SIZ); + sprintf(content, "Content-type: %s\n" + "Content-length: %d\n\n", + ContentType, ContentLength); + body_start = strlen(content); + + /* Be daring and read it all at once. */ + client_read(WC->http_sock, &content[BytesRead+body_start], + ContentLength); if (!strncasecmp(ContentType, "application/x-www-form-urlencoded", 33)) { - addurls(content); + addurls(&content[body_start]); } else if (!strncasecmp(ContentType, "multipart", 9)) { - content_end = content + ContentLength; + content_end = content + ContentLength + body_start; mime_parser(content, content_end, *upload_handler, NULL, NULL, NULL, 0); } @@ -814,25 +981,29 @@ void session_loop(struct httprequest *req) } } + /* Static content can be sent without connecting to Citadel. */ + if (!strcasecmp(action, "static")) { + strcpy(buf, &cmd[12]); + for (a = 0; a < strlen(buf); ++a) + if (isspace(buf[a])) + buf[a] = 0; + output_static(buf); + goto SKIP_ALL_THIS_CRAP; /* Don't try to connect */ + } + /* * If we're not connected to a Citadel server, try to hook up the - * connection now. Preference is given to the host and port specified - * by browser cookies, if cookies have been supplied. + * connection now. */ if (!WC->connected) { - if (strlen(bstr("host")) > 0) - strcpy(c_host, bstr("host")); - if (strlen(bstr("port")) > 0) - strcpy(c_port, bstr("port")); - - if (!strcasecmp(c_host, "uds")) { + if (!strcasecmp(ctdlhost, "uds")) { /* unix domain socket */ - sprintf(buf, "%s/citadel.socket", c_port); + sprintf(buf, "%s/citadel.socket", ctdlport); WC->serv_sock = uds_connectsock(buf); } else { /* tcp socket */ - WC->serv_sock = tcp_connectsock(c_host, c_port); + WC->serv_sock = tcp_connectsock(ctdlhost, ctdlport); } if (WC->serv_sock < 0) { @@ -868,14 +1039,67 @@ 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, + * 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_gets(buf); + if (buf[0] == '3') { + serv_printf("PASS %s", c_httpauth_pass); + serv_gets(buf); + if (buf[0] == '2') { + become_logged_in(c_httpauth_user, + c_httpauth_pass, buf); + strcpy(WC->httpauth_user, c_httpauth_user); + strcpy(WC->httpauth_pass, c_httpauth_pass); + } + } + } + + /* + * 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 */ + } /* keep the session active */ + goto SKIP_ALL_THIS_CRAP; + } + - check_for_express_messages(); + /* + * If this isn't a GroupDAV session, it's an ordinary browser + * connecting to the user interface. Only allow GET and POST + * methods. + */ + if ((strcasecmp(method, "GET")) && (strcasecmp(method, "POST"))) { + wprintf("HTTP/1.1 405 Method Not Allowed\r\n"); + groupdav_common_headers(); + wprintf("Content-Length: 0\r\n\r\n"); + goto SKIP_ALL_THIS_CRAP; + } /* * If we're not logged in, but we have username and password cookies * supplied by the browser, try using them to log in. */ - if ((!WC->logged_in) && (strlen(c_username) > 0) && (strlen(c_password) > 0)) { + if ((!WC->logged_in) + && (strlen(c_username) > 0) + && (strlen(c_password) > 0)) { serv_printf("USER %s", c_username); serv_gets(buf); if (buf[0] == '3') { @@ -897,13 +1121,13 @@ void session_loop(struct httprequest *req) strcpy(WC->wc_roomname, c_roomname); } } - if (!strcasecmp(action, "static")) { - strcpy(buf, &cmd[12]); - for (a = 0; a < strlen(buf); ++a) - if (isspace(buf[a])) - buf[a] = 0; - output_static(buf); - } else if (!strcasecmp(action, "image")) { + + /* + * If there are instant messages waiting, retrieve them for display. + */ + check_for_instant_messages(); + + if (!strcasecmp(action, "image")) { output_image(); /* @@ -924,6 +1148,10 @@ void session_loop(struct httprequest *req) 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, "display_main_menu")) { display_main_menu(); } else if (!strcasecmp(action, "whobbs")) { @@ -956,12 +1184,10 @@ void session_loop(struct httprequest *req) display_enter(); } else if (!strcasecmp(action, "post")) { post_message(); - } else if (!strcasecmp(action, "delete_msg")) { - delete_msg(); - } else if (!strcasecmp(action, "confirm_move_msg")) { - confirm_move_msg(); } else if (!strcasecmp(action, "move_msg")) { move_msg(); + } else if (!strcasecmp(action, "delete_msg")) { + delete_msg(); } else if (!strcasecmp(action, "userlist")) { userlist(); } else if (!strcasecmp(action, "showuser")) { @@ -986,25 +1212,27 @@ void session_loop(struct httprequest *req) display_entroom(); } else if (!strcasecmp(action, "entroom")) { entroom(); + } else if (!strcasecmp(action, "display_whok")) { + display_whok(); + } else if (!strcasecmp(action, "do_invt_kick")) { + do_invt_kick(); } else if (!strcasecmp(action, "display_editroom")) { display_editroom(); } else if (!strcasecmp(action, "netedit")) { netedit(); } else if (!strcasecmp(action, "editroom")) { editroom(); - } else if (!strcasecmp(action, "display_whok")) { - display_whok(); } else if (!strcasecmp(action, "display_editinfo")) { - display_edit("Room info", "EINF 0", "RINF", "/editinfo"); + display_edit("Room info", "EINF 0", "RINF", "/editinfo", 1); } else if (!strcasecmp(action, "editinfo")) { save_edit("Room info", "EINF 1", 1); } else if (!strcasecmp(action, "display_editbio")) { sprintf(buf, "RBIO %s", WC->wc_username); - display_edit("Your bio", "NOOP", buf, "editbio"); + display_edit("Your bio", "NOOP", buf, "editbio", 3); } else if (!strcasecmp(action, "editbio")) { save_edit("Your bio", "EBIO", 0); - } else if (!strcasecmp(action, "confirm_delete_room")) { - confirm_delete_room(); + } else if (!strcasecmp(action, "confirm_move_msg")) { + confirm_move_msg(); } else if (!strcasecmp(action, "delete_room")) { delete_room(); } else if (!strcasecmp(action, "validate")) { @@ -1039,8 +1267,6 @@ void session_loop(struct httprequest *req) do_graphics_upload(buf); } else if (!strcasecmp(action, "display_reg")) { display_reg(0); - } else if (!strcasecmp(action, "register")) { - register_user(); } else if (!strcasecmp(action, "display_changepw")) { display_changepw(); } else if (!strcasecmp(action, "changepw")) { @@ -1066,8 +1292,10 @@ void session_loop(struct httprequest *req) edit_me(); } else if (!strcasecmp(action, "display_siteconfig")) { display_siteconfig(); - } else if (!strcasecmp(action, "page_popup")) { - page_popup(); + } 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")) { @@ -1085,15 +1313,13 @@ void session_loop(struct httprequest *req) } else if (!strcasecmp(action, "select_user_to_edit")) { select_user_to_edit(NULL, NULL); } else if (!strcasecmp(action, "display_edituser")) { - display_edituser(NULL); + 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, "folders")) { - folders(); } else if (!strcasecmp(action, "do_stuff_to_msgs")) { do_stuff_to_msgs(); } else if (!strcasecmp(action, "change_start_page")) { @@ -1118,16 +1344,30 @@ void session_loop(struct httprequest *req) #endif } else if (!strcasecmp(action, "summary")) { summary(); + } else if (!strcasecmp(action, "iconbar")) { + do_iconbar(); + } 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, "setup_wizard")) { + do_setup_wizard(); } else if (!strcasecmp(action, "diagnostics")) { - output_headers(1); + output_headers(1, 1, 1, 0, 0, 0, 0); - wprintf("You're in session %d
\n", WC->wc_session); - wprintf("Command:
\n");
+		wprintf("You're in session %d
\n", WC->wc_session); + wprintf("Command:
\n");
 		escputs(cmd);
-		wprintf("

\n"); - wprintf("Variables:
\n");
+		wprintf("

\n"); + wprintf("Variables:
\n");
 		dump_vars();
-		wprintf("

\n"); + wprintf("

\n"); wDumpContent(1); } /* When all else fais, display the main menu. */