either.
+ */
- int unset_cookies, /* 1 = session is terminating, so unset the cookies */
- int suppress_check, /* 1 = suppress check for instant messages */
- int cache /* 1 = allow browser to cache this page */
+ int unset_cookies, /**< 1 = session is terminating, so unset the cookies */
+ int suppress_check, /**< 1 = suppress check for instant messages */
+ int cache /**< 1 = allow browser to cache this page */
) {
- char cookie[SIZ];
- char httpnow[SIZ];
+ char cookie[1024];
+ char httpnow[128];
wprintf("HTTP/1.1 200 OK\n");
- httpdate(httpnow, time(NULL));
+ http_datestring(httpnow, sizeof httpnow, time(NULL));
if (do_httpheaders) {
wprintf("Content-type: text/html; charset=utf-8\r\n"
@@ -387,29 +430,30 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers
do_template("head");
}
- /* ICONBAR */
+ /** ICONBAR */
if (do_htmlhead) {
- if (WC->HaveInstantMessages) {
- wprintf("
");
}
+
if (do_room_banner == 1) {
wprintf("\n");
- page_popup();
- wprintf("
\n");
- }
+
+ /** 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("" + "%s
\n", WC->ImportantMessage); wprintf("
\n");
wprintf("\n");
safestrncpy(WC->ImportantMessage, "", sizeof WC->ImportantMessage);
}
+
if ( (WC->logged_in) && (!unset_cookies) ) {
wprintf("\n", WC->ImportantMessage); + wprintf("" + "%s
\n", WC->ImportantMessage); wprintf("
");
do_selected_iconbar();
- wprintf("
\n");
+ /** check for instant messages (these display in a new window) */
+ page_popup();
+ wprintf("\n");
embed_room_banner(NULL, navbar_default);
@@ -423,8 +467,9 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers
}
-/*
- * Generic function to do an HTTP redirect. Easy and fun.
+/**
+ * \brief Generic function to do an HTTP redirect. Easy and fun.
+ * \param whichpage target url to 302 to
*/
void http_redirect(char *whichpage) {
wprintf("HTTP/1.1 302 Moved Temporarily\n");
@@ -438,20 +483,8 @@ void http_redirect(char *whichpage) {
-void check_for_instant_messages()
-{
- char buf[SIZ];
-
- serv_puts("NOOP");
- serv_getln(buf, sizeof buf);
- if (buf[3] == '*') WC->HaveInstantMessages = 1;
-}
-
-
-
-
-/*
- * Output a piece of content to the web browser
+/**
+ * \brief Output a piece of content to the web browser
*/
void http_transmit_thing(char *thing, size_t length, char *content_type,
int is_static) {
@@ -465,7 +498,7 @@ void http_transmit_thing(char *thing, size_t length, char *content_type,
SERVER);
#ifdef HAVE_ZLIB
- /* If we can send the data out compressed, please do so. */
+ /** If we can send the data out compressed, please do so. */
if (WC->gzip_ok) {
char *compressed_data = NULL;
uLongf compressed_len;
@@ -489,7 +522,7 @@ void http_transmit_thing(char *thing, size_t length, char *content_type,
}
#endif
- /* No compression ... just send it out as-is */
+ /** No compression ... just send it out as-is */
wprintf("Content-length: %ld\r\n"
"\r\n",
(long) length
@@ -499,7 +532,10 @@ void http_transmit_thing(char *thing, size_t length, char *content_type,
-
+/**
+ * \brief dump out static pages from disk
+ * \param what the file urs to print
+ */
void output_static(char *what)
{
FILE *fp;
@@ -563,8 +599,8 @@ void output_static(char *what)
}
-/*
- * When the browser requests an image file from the Citadel server,
+/**
+ * \brief When the browser requests an image file from the Citadel server,
* this function is called to transmit it.
*/
void output_image()
@@ -579,17 +615,18 @@ void output_image()
bytes = extract_long(&buf[4], 0);
xferbuf = malloc(bytes + 2);
- /* Read it from the server */
+ /** Read it from the server */
read_server_binary(xferbuf, bytes);
serv_puts("CLOS");
serv_getln(buf, sizeof buf);
- /* Write it to the browser */
+ /** Write it to the browser */
http_transmit_thing(xferbuf, (size_t)bytes, "image/gif", 0);
free(xferbuf);
} else {
- /* Instead of an ugly 404, send a 1x1 transparent GIF
+ /**
+ * Instead of an ugly 404, send a 1x1 transparent GIF
* when there's no such image on the server.
*/
output_static("static/blank.gif");
@@ -599,15 +636,20 @@ void output_image()
}
-/*
- * Generic function to output an arbitrary MIME part from an arbitrary
- * message number on the server.
+/**
+ * \brief Generic function to output an arbitrary MIME part from an arbitrary
+ * message number on the server.
+ *
+ * \param msgnum Number of the item on the citadel server
+ * \param partnum The MIME part to be output
+ * \param force_download Nonzero to force set the Content-Type: header
+ * to "application/octet-stream"
*/
-void mimepart(char *msgnum, char *partnum)
+void mimepart(char *msgnum, char *partnum, int force_download)
{
- char buf[SIZ];
+ char buf[256];
off_t bytes;
- char content_type[SIZ];
+ char content_type[256];
char *content = NULL;
serv_printf("OPNA %s|%s", msgnum, partnum);
@@ -615,7 +657,12 @@ void mimepart(char *msgnum, char *partnum)
if (buf[0] == '2') {
bytes = extract_long(&buf[4], 0);
content = malloc(bytes + 2);
- extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
+ if (force_download) {
+ strcpy(content_type, "application/octet-stream");
+ }
+ else {
+ extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
+ }
output_headers(0, 0, 0, 0, 0, 0);
read_server_binary(content, bytes);
serv_puts("CLOS");
@@ -633,8 +680,10 @@ void mimepart(char *msgnum, char *partnum)
}
-/*
- * Read any MIME part of a message, from the server, into memory.
+/**
+ * \brief Read any MIME part of a message, from the server, into memory.
+ * \param msgnum number of the message on the citadel server
+ * \param partnum the MIME part to be loaded
*/
char *load_mimepart(long msgnum, char *partnum)
{
@@ -664,17 +713,20 @@ char *load_mimepart(long msgnum, char *partnum)
}
-/*
- * Convenience functions to display a page containing only a string
+/**
+ * \brief Convenience functions to display a page containing only a string
+ * \param titlebarcolor color of the titlebar of the frame
+ * \param titlebarmsg text to display in the title bar
+ * \param messagetext body of the box
*/
void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext)
{
wprintf("HTTP/1.1 200 OK\n");
output_headers(1, 1, 2, 0, 0, 0);
wprintf("
\n");
- wprintf("
\n");
+ wprintf("
\n");
wprintf("
\n", titlebarcolor); - wprintf("%s\n", titlebarmsg); - wprintf(" |
", titlebarcolor); + wprintf("%s\n", titlebarmsg); + wprintf(" |
\n");
escputs(messagetext);
@@ -683,8 +735,8 @@ void convenience_page(char *titlebarcolor, char *titlebarmsg, char *messagetext)
}
-/*
- * Display a blank page.
+/**
+ * \brief Display a blank page.
*/
void blank_page(void) {
output_headers(1, 1, 0, 0, 0, 0);
@@ -692,8 +744,8 @@ void blank_page(void) {
}
-/*
- * A template has been requested
+/**
+ * \brief A template has been requested
*/
void url_do_template(void) {
do_template(bstr("template"));
@@ -701,15 +753,15 @@ void url_do_template(void) {
-/*
- * Offer to make any page the user's "start page."
+/**
+ * \brief Offer to make any page the user's "start page."
*/
void offer_start_page(void) {
wprintf("this_page);
- wprintf("\">");
+ wprintf("\">");
wprintf(_("Make this my start page"));
- wprintf("");
+ wprintf("");
/*
wprintf("
wc_roomname); @@ -720,8 +772,8 @@ void offer_start_page(void) { } -/* - * Change the user's start page +/** + * \brief Change the user's start page */ void change_start_page(void) { @@ -742,15 +794,21 @@ void change_start_page(void) { - +/** + * \brief convenience function to indicate success + * \param successmessage the mesage itself + */ void display_success(char *successmessage) { convenience_page("007700", "OK", successmessage); } -/* Authorization required page */ -/* This is probably temporary and should be revisited */ +/** + * \brief Authorization required page + * This is probably temporary and should be revisited + * \param message message to put in header +*/ void authorization_required(const char *message) { wprintf("HTTP/1.1 401 Authorization Required\r\n"); @@ -764,7 +822,22 @@ void authorization_required(const char *message) wDumpContent(0); } - +/** + * \brief This function is called by the MIME parser to handle data uploaded by + * the browser. Form data, uploaded files, and the data from HTTP PUT + * operations (such as those found in GroupDAV) all arrive this way. + * + * \param name Name of the item being uploaded + * \param filename Filename of the item being uploaded + * \param partnum MIME part identifier (not needed) + * \param disp MIME content disposition (not needed) + * \param content The actual data + * \param cbtype MIME content-type + * \param cbcharset Character set + * \param length Content length + * \param encoding MIME encoding type (not needed) + * \param userdata Not used here + */ void upload_handler(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, void *userdata) @@ -785,7 +858,7 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, u->url_data[length] = 0; } - /* Uploaded files */ + /** Uploaded files */ if ( (length > 0) && (strlen(cbtype) > 0) ) { WC->upload = malloc(length); if (WC->upload != NULL) { @@ -803,8 +876,8 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, } -/* - * Convenience functions to wrap around asynchronous ajax responses +/** + * \brief Convenience functions to wrap around asynchronous ajax responses */ void begin_ajax_response(void) { output_headers(0, 0, 0, 0, 0, 0); @@ -818,11 +891,17 @@ void begin_ajax_response(void) { begin_burst(); } +/** + * \brief print ajax response footer + */ void end_ajax_response(void) { wprintf("\r\n"); wDumpContent(0); } +/** + * \brief Wraps a Citadel server command in an AJAX transaction. + */ void ajax_servcmd(void) { char buf[1024]; @@ -832,11 +911,9 @@ void ajax_servcmd(void) begin_ajax_response(); - /* lprintf(9, "Sending cmd: %s\n", bstr("g_cmd")); */ serv_printf("%s", bstr("g_cmd")); serv_getln(buf, sizeof buf); wprintf("%s\n", buf); - /* lprintf(9, " Response: %s\n", buf); */ if (buf[0] == '8') { serv_printf("\n\n000"); @@ -848,7 +925,7 @@ void ajax_servcmd(void) wprintf("000"); } if (buf[0] == '4') { - text_to_server(bstr("g_input"), 0); + text_to_server(bstr("g_input")); serv_puts("000"); } if (buf[0] == '6') { @@ -866,15 +943,49 @@ void ajax_servcmd(void) } end_ajax_response(); + + /** + * This is kind of an ugly hack, but this is the only place it can go. + * If the command was GEXP, then the instant messenger window must be + * running, so reset the "last_pager_check" watchdog timer so + * that page_popup() doesn't try to open it a second time. + */ + if (!strncasecmp(bstr("g_cmd"), "GEXP", 4)) { + WC->last_pager_check = time(NULL); + } } +/** + * \brief Helper function for the asynchronous check to see if we need + * to open the instant messenger window. + */ +void seconds_since_last_gexp(void) +{ + char buf[256]; + + begin_ajax_response(); + if ( (time(NULL) - WC->last_pager_check) < 30) { + wprintf("NO\n"); + } + else { + serv_puts("NOOP"); + serv_getln(buf, sizeof buf); + if (buf[3] == '*') { + wprintf("YES"); + } + else { + wprintf("NO"); + } + } + end_ajax_response(); +} -/* - * Entry point for WebCit transaction +/** + * \brief Entry point for WebCit transaction */ void session_loop(struct httprequest *req) { @@ -902,7 +1013,8 @@ void session_loop(struct httprequest *req) int body_start = 0; int is_static = 0; - /* We stuff these with the values coming from the client cookies, + /** + * 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]; @@ -934,7 +1046,7 @@ void session_loop(struct httprequest *req) extract_token(request_method, cmd, 0, ' ', sizeof request_method); extract_token(pathname, cmd, 1, ' ', sizeof pathname); - /* Figure out the action */ + /** Figure out the action */ extract_token(action, pathname, 1, '/', sizeof action); if (strstr(action, "?")) *strstr(action, "?") = 0; if (strstr(action, "&")) *strstr(action, "&") = 0; @@ -977,6 +1089,7 @@ void session_loop(struct httprequest *req) while (hptr != NULL) { safestrncpy(buf, hptr->line, sizeof buf); + /* lprintf(9, "HTTP HEADER: %s\n", buf); */ hptr = hptr->next; if (!strncasecmp(buf, "Cookie: webcit=", 15)) { @@ -1000,8 +1113,15 @@ void session_loop(struct httprequest *req) else if (!strncasecmp(buf, "User-agent: ", 12)) { safestrncpy(user_agent, &buf[12], sizeof user_agent); } + else if (!strncasecmp(buf, "X-Forwarded-Host: ", 18)) { + if (follow_xff) { + safestrncpy(WC->http_host, &buf[18], sizeof WC->http_host); + } + } else if (!strncasecmp(buf, "Host: ", 6)) { - safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host); + if (strlen(WC->http_host) == 0) { + safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host); + } } else if (!strncasecmp(buf, "X-Forwarded-For: ", 17)) { safestrncpy(browser_host, &buf[17], sizeof browser_host); @@ -1010,7 +1130,7 @@ void session_loop(struct httprequest *req) } striplt(browser_host); } - /* Only WAP gateways explicitly name this content-type */ + /** Only WAP gateways explicitly name this content-type */ else if (strstr(buf, "text/vnd.wap.wml")) { WC->is_wap = 1; } @@ -1024,7 +1144,7 @@ void session_loop(struct httprequest *req) ContentType, ContentLength); body_start = strlen(content); - /* Read the entire input data at once. */ + /** Read the entire input data at once. */ client_read(WC->http_sock, &content[BytesRead+body_start], ContentLength); @@ -1040,12 +1160,12 @@ void session_loop(struct httprequest *req) content = NULL; } - /* make a note of where we are in case the user wants to save it */ + /** make a note of where we are in case the user wants to save it */ safestrncpy(WC->this_page, cmd, sizeof(WC->this_page)); remove_token(WC->this_page, 2, ' '); remove_token(WC->this_page, 0, ' '); - /* If there are variables in the URL, we must grab them now */ + /** If there are variables in the URL, we must grab them now */ for (a = 0; a < strlen(cmd); ++a) { if ((cmd[a] == '?') || (cmd[a] == '&')) { for (b = a; b < strlen(cmd); ++b) @@ -1056,11 +1176,19 @@ void session_loop(struct httprequest *req) } } + /** If it's a "force 404" situation then display the error and bail. */ + if (!strcmp(action, "404")) { + wprintf("HTTP/1.1 404 Not found\r\n"); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); + wprintf("Not found\r\n"); + goto SKIP_ALL_THIS_CRAP; + } - /* Static content can be sent without connecting to Citadel. */ + /** Static content can be sent without connecting to Citadel. */ is_static = 0; - for (a=0; a<(sizeof(static_content_dirs) / sizeof(char *)); ++a) { - if (!strcasecmp(action, static_content_dirs[a])) { + for (a=0; aconnected = 1;
- serv_getln(buf, sizeof buf); /* get the server welcome message */
+ serv_getln(buf, sizeof buf); /** get the server welcome message */
- /* From what host is our user connecting? Go with
+ /**
+ * From what host is our user connecting? Go with
* the host at the other end of the HTTP socket,
* unless we are following X-Forwarded-For: headers
* and such a header has already turned up something.
@@ -1131,7 +1260,7 @@ void session_loop(struct httprequest *req)
}
}
- /*
+ /**
* Functions which can be performed without logging in
*/
if (!strcasecmp(action, "listsub")) {
@@ -1145,7 +1274,7 @@ void session_loop(struct httprequest *req)
}
#endif
- /*
+ /**
* If we're not logged in, but we have HTTP Authentication data,
* try logging in to Citadel using that.
*/
@@ -1163,20 +1292,20 @@ void session_loop(struct httprequest *req)
safestrncpy(WC->httpauth_user, c_httpauth_user, sizeof WC->httpauth_user);
safestrncpy(WC->httpauth_pass, c_httpauth_pass, sizeof WC->httpauth_pass);
} else {
- /* Should only display when password is wrong */
+ /** Should only display when password is wrong */
authorization_required(&buf[4]);
goto SKIP_ALL_THIS_CRAP;
}
}
}
- /* This needs to run early */
+ /** This needs to run early */
if (!strcasecmp(action, "rss")) {
display_rss(bstr("room"), request_method);
goto SKIP_ALL_THIS_CRAP;
}
- /*
+ /**
* The GroupDAV stuff relies on HTTP authentication instead of
* our session's authentication.
*/
@@ -1190,20 +1319,20 @@ void session_loop(struct httprequest *req)
}
- /*
+ /**
* Automatically send requests with any method other than GET or
* POST to the GroupDAV code as well.
*/
if ((strcasecmp(request_method, "GET")) && (strcasecmp(request_method, "POST"))) {
- groupdav_main(req, ContentType, /* do GroupDAV methods */
+ groupdav_main(req, ContentType, /** do GroupDAV methods */
ContentLength, content+body_start);
if (!WC->logged_in) {
- WC->killthis = 1; /* If not logged in, don't */
- } /* keep the session active */
+ WC->killthis = 1; /** If not logged in, don't */
+ } /** keep the session active */
goto SKIP_ALL_THIS_CRAP;
}
- /*
+ /**
* If we're not logged in, but we have username and password cookies
* supplied by the browser, try using them to log in.
*/
@@ -1220,7 +1349,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.
*/
@@ -1232,25 +1361,20 @@ void session_loop(struct httprequest *req)
}
}
- /*
- * If there are instant messages waiting, retrieve them for display.
- */
- check_for_instant_messages();
-
if (!strcasecmp(action, "image")) {
output_image();
- /*
- * All functions handled below this point ... make sure we log in
- * before doing anything else!
- */
+ /**
+ * All functions handled below this point ... make sure we log in
+ * before doing anything else!
+ */
} else if ((!WC->logged_in) && (!strcasecmp(action, "login"))) {
do_login();
} else if (!WC->logged_in) {
display_login(NULL);
}
- /*
+ /**
* Various commands...
*/
@@ -1266,6 +1390,8 @@ void session_loop(struct httprequest *req)
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();
@@ -1304,10 +1430,16 @@ void session_loop(struct httprequest *req)
readloop("readfwd");
} else if (!strcasecmp(action, "headers")) {
readloop("headers");
+ } else if (!strcasecmp(action, "do_search")) {
+ readloop("do_search");
} else if (!strcasecmp(action, "msg")) {
embed_message(arg1);
} else if (!strcasecmp(action, "printmsg")) {
print_message(arg1);
+ } else if (!strcasecmp(action, "msgheaders")) {
+ display_headers(arg1);
+ } else if (!strcasecmp(action, "wiki")) {
+ display_wiki_page();
} else if (!strcasecmp(action, "display_enter")) {
display_enter();
} else if (!strcasecmp(action, "post")) {
@@ -1355,7 +1487,7 @@ void session_loop(struct httprequest *req)
} 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);
+ sprintf(buf, "RBIO %s", WC->wc_fullname);
display_edit(_("Your bio"), "NOOP", buf, "editbio", 3);
} else if (!strcasecmp(action, "editbio")) {
save_edit(_("Your bio"), "EBIO", 0);
@@ -1435,7 +1567,9 @@ void session_loop(struct httprequest *req)
} else if (!strcasecmp(action, "display_menubar")) {
display_menubar(1);
} else if (!strcasecmp(action, "mimepart")) {
- mimepart(arg1, arg2);
+ mimepart(arg1, arg2, 0);
+ } else if (!strcasecmp(action, "mimepart_download")) {
+ mimepart(arg1, arg2, 1);
} else if (!strcasecmp(action, "edit_vcard")) {
edit_vcard();
} else if (!strcasecmp(action, "submit_vcard")) {
@@ -1486,6 +1620,8 @@ void session_loop(struct httprequest *req)
display_inetconf();
} else if (!strcasecmp(action, "save_inetconf")) {
save_inetconf();
+ } else if (!strcasecmp(action, "display_smtpqueue")) {
+ display_smtpqueue();
} else if (!strcasecmp(action, "setup_wizard")) {
do_setup_wizard();
} else if (!strcasecmp(action, "display_preferences")) {
@@ -1510,9 +1646,11 @@ void session_loop(struct httprequest *req)
dump_vars();
wprintf("
\n"); wDumpContent(1); + } else if (!strcasecmp(action, "updatenote")) { + updatenote(); } - /* When all else fais, display the main menu. */ + /** When all else fais, display the main menu. */ else { display_main_menu(); } @@ -1529,3 +1667,6 @@ SKIP_ALL_THIS_CRAP: WC->upload_length = 0; } } + + +/*@}*/
wc_roomname); @@ -720,8 +772,8 @@ void offer_start_page(void) { } -/* - * Change the user's start page +/** + * \brief Change the user's start page */ void change_start_page(void) { @@ -742,15 +794,21 @@ void change_start_page(void) { - +/** + * \brief convenience function to indicate success + * \param successmessage the mesage itself + */ void display_success(char *successmessage) { convenience_page("007700", "OK", successmessage); } -/* Authorization required page */ -/* This is probably temporary and should be revisited */ +/** + * \brief Authorization required page + * This is probably temporary and should be revisited + * \param message message to put in header +*/ void authorization_required(const char *message) { wprintf("HTTP/1.1 401 Authorization Required\r\n"); @@ -764,7 +822,22 @@ void authorization_required(const char *message) wDumpContent(0); } - +/** + * \brief This function is called by the MIME parser to handle data uploaded by + * the browser. Form data, uploaded files, and the data from HTTP PUT + * operations (such as those found in GroupDAV) all arrive this way. + * + * \param name Name of the item being uploaded + * \param filename Filename of the item being uploaded + * \param partnum MIME part identifier (not needed) + * \param disp MIME content disposition (not needed) + * \param content The actual data + * \param cbtype MIME content-type + * \param cbcharset Character set + * \param length Content length + * \param encoding MIME encoding type (not needed) + * \param userdata Not used here + */ void upload_handler(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, void *userdata) @@ -785,7 +858,7 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, u->url_data[length] = 0; } - /* Uploaded files */ + /** Uploaded files */ if ( (length > 0) && (strlen(cbtype) > 0) ) { WC->upload = malloc(length); if (WC->upload != NULL) { @@ -803,8 +876,8 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, } -/* - * Convenience functions to wrap around asynchronous ajax responses +/** + * \brief Convenience functions to wrap around asynchronous ajax responses */ void begin_ajax_response(void) { output_headers(0, 0, 0, 0, 0, 0); @@ -818,11 +891,17 @@ void begin_ajax_response(void) { begin_burst(); } +/** + * \brief print ajax response footer + */ void end_ajax_response(void) { wprintf("\r\n"); wDumpContent(0); } +/** + * \brief Wraps a Citadel server command in an AJAX transaction. + */ void ajax_servcmd(void) { char buf[1024]; @@ -832,11 +911,9 @@ void ajax_servcmd(void) begin_ajax_response(); - /* lprintf(9, "Sending cmd: %s\n", bstr("g_cmd")); */ serv_printf("%s", bstr("g_cmd")); serv_getln(buf, sizeof buf); wprintf("%s\n", buf); - /* lprintf(9, " Response: %s\n", buf); */ if (buf[0] == '8') { serv_printf("\n\n000"); @@ -848,7 +925,7 @@ void ajax_servcmd(void) wprintf("000"); } if (buf[0] == '4') { - text_to_server(bstr("g_input"), 0); + text_to_server(bstr("g_input")); serv_puts("000"); } if (buf[0] == '6') { @@ -866,15 +943,49 @@ void ajax_servcmd(void) } end_ajax_response(); + + /** + * This is kind of an ugly hack, but this is the only place it can go. + * If the command was GEXP, then the instant messenger window must be + * running, so reset the "last_pager_check" watchdog timer so + * that page_popup() doesn't try to open it a second time. + */ + if (!strncasecmp(bstr("g_cmd"), "GEXP", 4)) { + WC->last_pager_check = time(NULL); + } } +/** + * \brief Helper function for the asynchronous check to see if we need + * to open the instant messenger window. + */ +void seconds_since_last_gexp(void) +{ + char buf[256]; + + begin_ajax_response(); + if ( (time(NULL) - WC->last_pager_check) < 30) { + wprintf("NO\n"); + } + else { + serv_puts("NOOP"); + serv_getln(buf, sizeof buf); + if (buf[3] == '*') { + wprintf("YES"); + } + else { + wprintf("NO"); + } + } + end_ajax_response(); +} -/* - * Entry point for WebCit transaction +/** + * \brief Entry point for WebCit transaction */ void session_loop(struct httprequest *req) { @@ -902,7 +1013,8 @@ void session_loop(struct httprequest *req) int body_start = 0; int is_static = 0; - /* We stuff these with the values coming from the client cookies, + /** + * 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]; @@ -934,7 +1046,7 @@ void session_loop(struct httprequest *req) extract_token(request_method, cmd, 0, ' ', sizeof request_method); extract_token(pathname, cmd, 1, ' ', sizeof pathname); - /* Figure out the action */ + /** Figure out the action */ extract_token(action, pathname, 1, '/', sizeof action); if (strstr(action, "?")) *strstr(action, "?") = 0; if (strstr(action, "&")) *strstr(action, "&") = 0; @@ -977,6 +1089,7 @@ void session_loop(struct httprequest *req) while (hptr != NULL) { safestrncpy(buf, hptr->line, sizeof buf); + /* lprintf(9, "HTTP HEADER: %s\n", buf); */ hptr = hptr->next; if (!strncasecmp(buf, "Cookie: webcit=", 15)) { @@ -1000,8 +1113,15 @@ void session_loop(struct httprequest *req) else if (!strncasecmp(buf, "User-agent: ", 12)) { safestrncpy(user_agent, &buf[12], sizeof user_agent); } + else if (!strncasecmp(buf, "X-Forwarded-Host: ", 18)) { + if (follow_xff) { + safestrncpy(WC->http_host, &buf[18], sizeof WC->http_host); + } + } else if (!strncasecmp(buf, "Host: ", 6)) { - safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host); + if (strlen(WC->http_host) == 0) { + safestrncpy(WC->http_host, &buf[6], sizeof WC->http_host); + } } else if (!strncasecmp(buf, "X-Forwarded-For: ", 17)) { safestrncpy(browser_host, &buf[17], sizeof browser_host); @@ -1010,7 +1130,7 @@ void session_loop(struct httprequest *req) } striplt(browser_host); } - /* Only WAP gateways explicitly name this content-type */ + /** Only WAP gateways explicitly name this content-type */ else if (strstr(buf, "text/vnd.wap.wml")) { WC->is_wap = 1; } @@ -1024,7 +1144,7 @@ void session_loop(struct httprequest *req) ContentType, ContentLength); body_start = strlen(content); - /* Read the entire input data at once. */ + /** Read the entire input data at once. */ client_read(WC->http_sock, &content[BytesRead+body_start], ContentLength); @@ -1040,12 +1160,12 @@ void session_loop(struct httprequest *req) content = NULL; } - /* make a note of where we are in case the user wants to save it */ + /** make a note of where we are in case the user wants to save it */ safestrncpy(WC->this_page, cmd, sizeof(WC->this_page)); remove_token(WC->this_page, 2, ' '); remove_token(WC->this_page, 0, ' '); - /* If there are variables in the URL, we must grab them now */ + /** If there are variables in the URL, we must grab them now */ for (a = 0; a < strlen(cmd); ++a) { if ((cmd[a] == '?') || (cmd[a] == '&')) { for (b = a; b < strlen(cmd); ++b) @@ -1056,11 +1176,19 @@ void session_loop(struct httprequest *req) } } + /** If it's a "force 404" situation then display the error and bail. */ + if (!strcmp(action, "404")) { + wprintf("HTTP/1.1 404 Not found\r\n"); + wprintf("Content-Type: text/plain\r\n"); + wprintf("\r\n"); + wprintf("Not found\r\n"); + goto SKIP_ALL_THIS_CRAP; + } - /* Static content can be sent without connecting to Citadel. */ + /** Static content can be sent without connecting to Citadel. */ is_static = 0; - for (a=0; a<(sizeof(static_content_dirs) / sizeof(char *)); ++a) { - if (!strcasecmp(action, static_content_dirs[a])) { + for (a=0; a
\n"); wDumpContent(1); + } else if (!strcasecmp(action, "updatenote")) { + updatenote(); } - /* When all else fais, display the main menu. */ + /** When all else fais, display the main menu. */ else { display_main_menu(); } @@ -1529,3 +1667,6 @@ SKIP_ALL_THIS_CRAP: WC->upload_length = 0; } } + + +/*@}*/