X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=webcit%2Fwebcit.c;h=b615dbc5a81bf43d1575fde006f3c8583fbbb854;hb=abeb8adc38f9d55fcb6cb3d076f57239b0a9a4d5;hp=464069c71ec3b082e666f0b4edcbd1b19ba9b8d3;hpb=2779defa829432785fd086052bb7234a02289c1d;p=citadel.git diff --git a/webcit/webcit.c b/webcit/webcit.c index 464069c71..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]); @@ -176,16 +177,13 @@ void wDumpContent(int print_standard_html_footer) { if (print_standard_html_footer) { wprintf("\n"); /* end of "text" div */ - - /* NAVBAR - wprintf("
"); - wprintf("FIXME the navbar should go here, dude...\n"); - wprintf("
\n"); - */ - do_template("trailing"); } + /* If we've been saving it all up for one big output burst, + * go ahead and do that now. + */ + end_burst(); } @@ -351,7 +349,7 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers int do_room_banner, /* 0=no, 1=yes, */ /* 2 = I'm going to embed my own, so don't open the */ - /*
either. */ + /*
either. */ int unset_cookies, /* 1 = session is terminating, so unset the cookies */ int refresh30, /* 1 = automatically refresh page every 30 seconds */ @@ -360,37 +358,46 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers ) { char cookie[SIZ]; char httpnow[SIZ]; - char onload_fcn[SIZ]; - static int pageseq = 0; wprintf("HTTP/1.0 200 OK\n"); httpdate(httpnow, time(NULL)); if (do_httpheaders) { - wprintf("Content-type: text/html\n" - "Server: %s\n", SERVER + wprintf("Content-type: text/html\r\n" + "Server: %s / %s\n" + "Connection: close\r\n", + SERVER, serv_info.serv_software + ); + } + + if (cache) { + wprintf("Pragma: public\r\n" + "Cache-Control: max-age=3600, must-revalidate\r\n" + "Last-modified: %s\r\n", + httpnow + ); + } + else { + wprintf("Pragma: no-cache\r\n" + "Cache-Control: no-store\r\n" ); - if (!cache) - wprintf("Connection: close\n" - "Pragma: no-cache\n" - "Cache-Control: no-store\n" - ); } stuff_to_cookie(cookie, WC->wc_session, WC->wc_username, WC->wc_password, WC->wc_roomname); if (unset_cookies) { - wprintf("Set-cookie: webcit=%s; path=/\n", unset); + wprintf("Set-cookie: webcit=%s; path=/\r\n", unset); } else { - wprintf("Set-cookie: webcit=%s; path=/\n", cookie); + wprintf("Set-cookie: webcit=%s; path=/\r\n", cookie); if (server_cookie != NULL) { wprintf("%s\n", server_cookie); } } if (do_htmlhead) { - wprintf("\n"); + /* wprintf("\n"); */ + begin_burst(); if (refresh30) { svprintf("REFRESHTAG", WCS_STRING, "%s", @@ -401,40 +408,17 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers "\n"); } - /* script for checking for pages (not always launched) */ - - sprintf(onload_fcn, "function onload_fcn() { \n"); - if (!suppress_check) if (WC->HaveExpressMessages) { - strcat(onload_fcn, " launch_page_popup(); \n"); - WC->HaveExpressMessages = 0; - } - strcat(onload_fcn, "} \n"); - - svprintf("PAGERscript", WCS_STRING, - "\n", - ++pageseq, - onload_fcn - ); - /* end script */ - do_template("head"); - - svprintf("extrabodyparms", WCS_STRING, "%s", - "onload='onload_fcn();' "); - - do_template("background"); } /* ICONBAR */ if (do_htmlhead) { + + if (WC->HaveInstantMessages) { + wprintf("
\n"); + page_popup(); + wprintf("
\n"); + } if ( (WC->logged_in) && (!unset_cookies) ) { wprintf("
"); do_iconbar(); @@ -442,33 +426,36 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers } if (do_room_banner == 1) { wprintf("
\n"); - embed_room_banner(NULL); + embed_room_banner(NULL, navbar_default); wprintf("
\n"); } } - if (do_room_banner != 2) { + if (do_room_banner == 1) { wprintf("
\n"); - } - if (strlen(WC->ImportantMessage) > 0) { - do_template("beginbox_nt"); - wprintf("" - "%s
\n", WC->ImportantMessage); - do_template("endbox"); - strcpy(WC->ImportantMessage, ""); + 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); @@ -477,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; } @@ -494,20 +481,44 @@ void check_for_express_messages() */ void http_transmit_thing(char *thing, size_t length, char *content_type, int is_static) { - if (is_static) { - output_headers(0, 0, 0, 0, 0, 0, 1); - } - else { - output_headers(0, 0, 0, 0, 0, 0, 0); - } - wprintf("Content-type: %s\n" - "Content-length: %ld\n" - "Server: %s\n" - "Connection: close\n" - "\n", + + output_headers(0, 0, 0, 0, 0, 0, is_static); + + wprintf("Content-type: %s\r\n" + "Server: %s\r\n" + "Connection: close\r\n", content_type, - (long) length, - SERVER + SERVER); + +#ifdef HAVE_ZLIB + /* If we can send the data out compressed, please do so. */ + if (WC->gzip_ok) { + char *compressed_data = NULL; + uLongf compressed_len; + + compressed_len = (uLongf) ((length * 101) / 100) + 100; + compressed_data = malloc(compressed_len); + + if (compress_gzip((Bytef *) compressed_data, + &compressed_len, + (Bytef *) thing, + (uLongf) length, Z_BEST_SPEED) == Z_OK) { + wprintf("Content-encoding: gzip\r\n" + "Content-length: %ld\r\n" + "\r\n", + (long) compressed_len + ); + client_write(compressed_data, (size_t)compressed_len); + free(compressed_data); + return; + } + } +#endif + + /* No compression ... just send it out as-is */ + wprintf("Content-length: %ld\r\n" + "\r\n", + (long) length ); client_write(thing, (size_t)length); } @@ -528,8 +539,8 @@ void output_static(char *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)) @@ -565,7 +576,8 @@ void output_static(char *what) fstat(fileno(fp), &statbuf); bytes = statbuf.st_size; - lprintf(3, "Static: %s, (%s; %ld bytes)\n", what, content_type, 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); @@ -614,8 +626,8 @@ void output_image() /* wprintf("HTTP/1.0 404 %s\n", &buf[4]); output_headers(0, 0, 0, 0, 0, 0, 0); - wprintf("Content-Type: text/plain\n" - "\n" + wprintf("Content-Type: text/plain\r\n" + "\r\n" "Error retrieving image: %s\n", &buf[4] ); @@ -641,7 +653,7 @@ void output_mimepart() if (buf[0] == '2') { bytes = extract_long(&buf[4], 0); content = malloc(bytes + 2); - extract(content_type, &buf[4], 3); + 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"); @@ -651,8 +663,8 @@ void output_mimepart() } else { wprintf("HTTP/1.0 404 %s\n", &buf[4]); output_headers(0, 0, 0, 0, 0, 0, 0); - wprintf("Content-Type: text/plain\n"); - wprintf("\n"); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); wprintf("Error retrieving part: %s\n", &buf[4]); } @@ -672,7 +684,7 @@ 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 + 2); read_server_binary(content, bytes); @@ -773,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; @@ -845,18 +861,19 @@ 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 = 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; + 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. @@ -864,11 +881,17 @@ void session_loop(struct httprequest *req) 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_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; @@ -881,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) { @@ -890,7 +914,14 @@ void session_loop(struct httprequest *req) if (!strncasecmp(buf, "Cookie: webcit=", 15)) { safestrncpy(cookie, &buf[15], sizeof cookie); cookie_to_stuff(cookie, NULL, - c_username, c_password, c_roomname); + c_username, sizeof c_username, + c_password, sizeof c_password, + c_roomname, sizeof c_roomname); + } + else if (!strncasecmp(buf, "Authorization: Basic ", 21)) { + CtdlDecodeBase64(c_httpauth_string, &buf[21], strlen(&buf[21])); + extract_token(c_httpauth_user, c_httpauth_string, 0, ':', 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]); @@ -918,18 +949,9 @@ void session_loop(struct httprequest *req) ContentType, ContentLength); body_start = strlen(content); -/***** old version - BytesRead = 0; - while (BytesRead < ContentLength) { - a=read(WC->http_sock, &content[BytesRead+body_start], - ContentLength - BytesRead); - if (a <= 0) BytesRead = ContentLength; - else BytesRead += a; - } -*******/ - - /* Now we're daring and read it all at once. */ - client_read(WC->http_sock, &content[BytesRead+body_start], ContentLength); + /* 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)) { @@ -1024,13 +1046,60 @@ void session_loop(struct httprequest *req) } #endif - check_for_express_messages(); + /* + * 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; + } + + + /* + * 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') { @@ -1053,6 +1122,11 @@ void session_loop(struct httprequest *req) } } + /* + * If there are instant messages waiting, retrieve them for display. + */ + check_for_instant_messages(); + if (!strcasecmp(action, "image")) { output_image(); @@ -1076,6 +1150,8 @@ void session_loop(struct httprequest *req) blank_page(); } else if (!strcasecmp(action, "do_template")) { url_do_template(); + } else if (!strcasecmp(action, "display_aide_menu")) { + display_aide_menu(); } else if (!strcasecmp(action, "display_main_menu")) { display_main_menu(); } else if (!strcasecmp(action, "whobbs")) { @@ -1108,10 +1184,10 @@ void session_loop(struct httprequest *req) display_enter(); } else if (!strcasecmp(action, "post")) { post_message(); - } else if (!strcasecmp(action, "do_stuff_to_one_msg")) { - do_stuff_to_one_msg(); } else if (!strcasecmp(action, "move_msg")) { move_msg(); + } else if (!strcasecmp(action, "delete_msg")) { + delete_msg(); } else if (!strcasecmp(action, "userlist")) { userlist(); } else if (!strcasecmp(action, "showuser")) { @@ -1136,14 +1212,16 @@ void session_loop(struct httprequest *req) display_entroom(); } else if (!strcasecmp(action, "entroom")) { entroom(); + } else if (!strcasecmp(action, "display_whok")) { + display_whok(); + } else if (!strcasecmp(action, "do_invt_kick")) { + do_invt_kick(); } else if (!strcasecmp(action, "display_editroom")) { display_editroom(); } else if (!strcasecmp(action, "netedit")) { netedit(); } else if (!strcasecmp(action, "editroom")) { editroom(); - } else if (!strcasecmp(action, "display_whok")) { - display_whok(); } else if (!strcasecmp(action, "display_editinfo")) { display_edit("Room info", "EINF 0", "RINF", "/editinfo", 1); } else if (!strcasecmp(action, "editinfo")) { @@ -1153,8 +1231,8 @@ void session_loop(struct httprequest *req) 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")) { @@ -1218,8 +1296,6 @@ void session_loop(struct httprequest *req) chat_recv(); } else if (!strcasecmp(action, "chat_send")) { chat_send(); - } else if (!strcasecmp(action, "page_popup")) { - page_popup(); } else if (!strcasecmp(action, "siteconfig")) { siteconfig(); } else if (!strcasecmp(action, "display_generic")) { @@ -1280,6 +1356,8 @@ void session_loop(struct httprequest *req) display_inetconf(); } else if (!strcasecmp(action, "save_inetconf")) { save_inetconf(); + } else if (!strcasecmp(action, "setup_wizard")) { + do_setup_wizard(); } else if (!strcasecmp(action, "diagnostics")) { output_headers(1, 1, 1, 0, 0, 0, 0);