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 */
+ 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.0 200 OK\n");
- httpdate(httpnow, time(NULL));
+ wprintf("HTTP/1.1 200 OK\n");
+ http_datestring(httpnow, sizeof httpnow, time(NULL));
if (do_httpheaders) {
wprintf("Content-type: text/html; charset=utf-8\r\n"
@@ -376,44 +427,39 @@ void output_headers( int do_httpheaders, /* 1 = output HTTP headers
}
if (do_htmlhead) {
- /* wprintf("\n"); */
begin_burst();
-
- if (refresh30) {
- svprintf("REFRESHTAG", WCS_STRING, "%s",
- "\n");
- }
- else {
- svprintf("REFRESHTAG", WCS_STRING, "%s",
- "\n");
+ if (!access("static.local/webcit.css", R_OK)) {
+ svprintf("CSSLOCAL", WCS_STRING,
+ ""
+ );
}
-
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_iconbar();
- wprintf("
\n");
+ do_selected_iconbar();
+ /** check for instant messages (these display in a new window) */
+ page_popup();
+ wprintf("\n");
embed_room_banner(NULL, navbar_default);
@@ -427,41 +473,29 @@ 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.0 302 Moved Temporarily\n");
+ wprintf("HTTP/1.1 302 Moved Temporarily\n");
wprintf("Location: %s\r\n", whichpage);
wprintf("URI: %s\r\n", whichpage);
wprintf("Content-type: text/html; charset=utf-8\r\n\r\n");
- wprintf("\n");
- wprintf("you really want to be here now\n",
- whichpage);
+ wprintf("");
+ wprintf("Go here.", whichpage);
wprintf("\n");
}
-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) {
- output_headers(0, 0, 0, 0, 0, 0, is_static);
+ output_headers(0, 0, 0, 0, 0, is_static);
wprintf("Content-type: %s\r\n"
"Server: %s\r\n"
@@ -470,7 +504,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;
@@ -494,7 +528,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
@@ -504,20 +538,22 @@ 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)
{
- char buf[256];
FILE *fp;
struct stat statbuf;
off_t bytes;
char *bigbuffer;
char content_type[128];
- sprintf(buf, "static/%s", what);
- fp = fopen(buf, "rb");
+ fp = fopen(what, "rb");
if (fp == NULL) {
- wprintf("HTTP/1.0 404 %s\n", strerror(errno));
+ lprintf(9, "output_static('%s') -- NOT FOUND --\n", what);
+ wprintf("HTTP/1.1 404 %s\n", strerror(errno));
wprintf("Content-Type: text/plain\r\n");
wprintf("\r\n");
wprintf("Cannot open %s: %s\n", what, strerror(errno));
@@ -559,6 +595,7 @@ void output_static(char *what)
fread(bigbuffer, bytes, 1, fp);
fclose(fp);
+ lprintf(9, "output_static('%s') %s\n", what, content_type);
http_transmit_thing(bigbuffer, (size_t)bytes, content_type, 1);
free(bigbuffer);
}
@@ -568,8 +605,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()
@@ -584,71 +621,75 @@ 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("blank.gif");
-
- /*
- wprintf("HTTP/1.0 404 %s\n", &buf[4]);
- 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]
- );
- */
-
+ output_static("static/blank.gif");
}
}
-/*
+/**
+ * \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 output_mimepart()
+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", bstr("msgnum"), bstr("partnum"));
+ serv_printf("OPNA %s|%s", msgnum, partnum);
serv_getln(buf, sizeof buf);
if (buf[0] == '2') {
bytes = extract_long(&buf[4], 0);
content = malloc(bytes + 2);
- extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
- output_headers(0, 0, 0, 0, 0, 0, 0);
+ if (force_download) {
+ strcpy(content_type, "application/octet-stream");
+ }
+ else {
+ extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
+ }
+ output_headers(0, 0, 0, 0, 0, 0);
read_server_binary(content, bytes);
serv_puts("CLOS");
serv_getln(buf, sizeof buf);
http_transmit_thing(content, bytes, content_type, 0);
free(content);
} else {
- wprintf("HTTP/1.0 404 %s\n", &buf[4]);
- output_headers(0, 0, 0, 0, 0, 0, 0);
+ wprintf("HTTP/1.1 404 %s\n", &buf[4]);
+ output_headers(0, 0, 0, 0, 0, 0);
wprintf("Content-Type: text/plain\r\n");
wprintf("\r\n");
- wprintf("Error retrieving part: %s\n", &buf[4]);
+ wprintf(_("An error occurred while retrieving this part: %s\n"), &buf[4]);
}
}
-/*
+/**
+ * \brief Read any MIME part of a message, from the server, into memory.
+ * \param msgnum number of the message on the citadel server
+ * \param partnum the MIME part to be loaded
*/
char *load_mimepart(long msgnum, char *partnum)
{
@@ -657,17 +698,15 @@ char *load_mimepart(long msgnum, char *partnum)
char content_type[SIZ];
char *content;
- serv_printf("OPNA %ld|%s", msgnum, partnum);
+ serv_printf("DLAT %ld|%s", msgnum, partnum);
serv_getln(buf, sizeof buf);
- if (buf[0] == '2') {
+ if (buf[0] == '6') {
bytes = extract_long(&buf[4], 0);
extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
content = malloc(bytes + 2);
- read_server_binary(content, bytes);
+ serv_read(content, bytes);
- serv_puts("CLOS");
- serv_getln(buf, sizeof buf);
content[bytes] = 0; /* null terminate for good measure */
return(content);
}
@@ -678,17 +717,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.0 200 OK\n");
- output_headers(1, 1, 2, 0, 0, 0, 0);
+ 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);
@@ -697,17 +739,17 @@ 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, 1, 0, 0);
+ output_headers(1, 1, 0, 0, 0, 0);
wDumpContent(2);
}
-/*
- * A template has been requested
+/**
+ * \brief A template has been requested
*/
void url_do_template(void) {
do_template(bstr("template"));
@@ -715,27 +757,33 @@ 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("\">"
- "Make this my start page"
- ""
- );
+ wprintf("\">");
+ wprintf(_("Make this my start page"));
+ wprintf("");
+/*
+ wprintf("
wc_roomname); + wprintf("\" title=\"RSS 2.0 feed for "); + escputs(WC->wc_roomname); + wprintf("\">\n"); +*/ } -/* - * Change the user's start page +/** + * \brief Change the user's start page */ void change_start_page(void) { if (bstr("startpage") == NULL) { safestrncpy(WC->ImportantMessage, - "startpage set to null", + _("You no longer have a start page selected."), sizeof WC->ImportantMessage); display_main_menu(); return; @@ -743,29 +791,64 @@ void change_start_page(void) { set_preference("startpage", bstr("startpage"), 1); - output_headers(1, 1, 0, 0, 0, 0, 0); + output_headers(1, 1, 0, 0, 0, 0); do_template("newstartpage"); wDumpContent(1); } - +/** + * \brief convenience function to indicate success + * \param successmessage the mesage itself + */ void display_success(char *successmessage) { convenience_page("007700", "OK", successmessage); } +/** + * \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"); + wprintf("WWW-Authenticate: Basic realm=\"\"\r\n", serv_info.serv_humannode); + wprintf("Content-Type: text/html\r\n\r\n"); + wprintf("connected = 1;
- serv_getln(buf, sizeof buf); /* get the server welcome message */
- locate_host(browser_host, WC->http_sock);
+ serv_getln(buf, sizeof buf); /** get the server welcome message */
+
+ /**
+ * From what host is our user connecting? Go with
+ * the host at the other end of the HTTP socket,
+ * unless we are following X-Forwarded-For: headers
+ * and such a header has already turned up something.
+ */
+ if ( (!follow_xff) || (strlen(browser_host) == 0) ) {
+ locate_host(browser_host, WC->http_sock);
+ }
+
get_serv_info(browser_host, user_agent);
if (serv_info.serv_rev_level < MINIMUM_CIT_VERSION) {
- wprintf("You are connected to a Citadel "
- "server running Citadel %d.%02d;\nin "
- "order to run this version of WebCit "
+ wprintf(_("You are connected to a Citadel "
+ "server running Citadel %d.%02d. \n"
+ "In order to run this version of WebCit "
"you must also have Citadel %d.%02d or"
- " newer.\n\n\n",
+ " newer.\n\n\n"),
serv_info.serv_rev_level / 100,
serv_info.serv_rev_level % 100,
MINIMUM_CIT_VERSION / 100,
@@ -1000,7 +1251,7 @@ void session_loop(struct httprequest *req)
}
}
- /*
+ /**
* Functions which can be performed without logging in
*/
if (!strcasecmp(action, "listsub")) {
@@ -1014,7 +1265,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.
*/
@@ -1031,11 +1282,21 @@ void session_loop(struct httprequest *req)
c_httpauth_pass, buf);
safestrncpy(WC->httpauth_user, c_httpauth_user, sizeof WC->httpauth_user);
safestrncpy(WC->httpauth_pass, c_httpauth_pass, sizeof WC->httpauth_pass);
+ } else {
+ /** Should only display when password is wrong */
+ authorization_required(&buf[4]);
+ goto SKIP_ALL_THIS_CRAP;
}
}
}
- /*
+ /** 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.
*/
@@ -1049,20 +1310,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(method, "GET")) && (strcasecmp(method, "POST"))) {
- groupdav_main(req, ContentType, /* do GroupDAV methods */
+ if ((strcasecmp(request_method, "GET")) && (strcasecmp(request_method, "POST"))) {
+ groupdav_main(req, ContentType, /** do GroupDAV methods */
ContentLength, content+body_start);
if (!WC->logged_in) {
- WC->killthis = 1; /* If not logged in, don't */
- } /* 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.
*/
@@ -1079,7 +1340,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.
*/
@@ -1091,25 +1352,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...
*/
@@ -1125,8 +1381,20 @@ 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")) {
- who_inner_html();
+ begin_ajax_response();
+ who_inner_div();
+ end_ajax_response();
+ } else if (!strcasecmp(action, "iconbar_ajax_menu")) {
+ begin_ajax_response();
+ do_iconbar();
+ end_ajax_response();
+ } else if (!strcasecmp(action, "iconbar_ajax_rooms")) {
+ begin_ajax_response();
+ do_iconbar_roomlist();
+ end_ajax_response();
} else if (!strcasecmp(action, "knrooms")) {
knrooms();
} else if (!strcasecmp(action, "gotonext")) {
@@ -1153,8 +1421,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();
+ embed_message(index[1]);
+ } else if (!strcasecmp(action, "printmsg")) {
+ print_message(index[1]);
+ } else if (!strcasecmp(action, "msgheaders")) {
+ display_headers(index[1]);
+ } else if (!strcasecmp(action, "wiki")) {
+ display_wiki_page();
} else if (!strcasecmp(action, "display_enter")) {
display_enter();
} else if (!strcasecmp(action, "post")) {
@@ -1198,14 +1474,14 @@ 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);
+ 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", 3);
+ 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);
+ save_edit(_("Your bio"), "EBIO", 0);
} else if (!strcasecmp(action, "confirm_move_msg")) {
confirm_move_msg();
} else if (!strcasecmp(action, "delete_room")) {
@@ -1213,15 +1489,15 @@ void session_loop(struct httprequest *req)
} else if (!strcasecmp(action, "validate")) {
validate();
} else if (!strcasecmp(action, "display_editpic")) {
- display_graphics_upload("your photo",
+ display_graphics_upload(_("your photo"),
"UIMG 0|_userpic_",
- "/editpic");
+ "editpic");
} else if (!strcasecmp(action, "editpic")) {
do_graphics_upload("UIMG 1|_userpic_");
} else if (!strcasecmp(action, "display_editroompic")) {
- display_graphics_upload("the icon for this room",
+ display_graphics_upload(_("the icon for this room"),
"UIMG 0|_roompic_",
- "/editroompic");
+ "editroompic");
} else if (!strcasecmp(action, "editroompic")) {
do_graphics_upload("UIMG 1|_roompic_");
} else if (!strcasecmp(action, "delete_floor")) {
@@ -1233,9 +1509,9 @@ void session_loop(struct httprequest *req)
} else if (!strcasecmp(action, "display_editfloorpic")) {
sprintf(buf, "UIMG 0|_floorpic_|%s",
bstr("which_floor"));
- display_graphics_upload("the icon for this floor",
+ display_graphics_upload(_("the icon for this floor"),
buf,
- "/editfloorpic");
+ "editfloorpic");
} else if (!strcasecmp(action, "editfloorpic")) {
sprintf(buf, "UIMG 1|_floorpic_|%s",
bstr("which_floor"));
@@ -1277,10 +1553,14 @@ void session_loop(struct httprequest *req)
display_generic();
} else if (!strcasecmp(action, "do_generic")) {
do_generic();
+ } else if (!strcasecmp(action, "ajax_servcmd")) {
+ ajax_servcmd();
} else if (!strcasecmp(action, "display_menubar")) {
display_menubar(1);
- } else if (!strcasecmp(action, "output_mimepart")) {
- output_mimepart();
+ } else if (!strcasecmp(action, "mimepart")) {
+ mimepart(index[1], index[2], 0);
+ } else if (!strcasecmp(action, "mimepart_download")) {
+ mimepart(index[1], index[2], 1);
} else if (!strcasecmp(action, "edit_vcard")) {
edit_vcard();
} else if (!strcasecmp(action, "submit_vcard")) {
@@ -1295,8 +1575,6 @@ void session_loop(struct httprequest *req)
create_user();
} else if (!strcasecmp(action, "changeview")) {
change_view();
- } else if (!strcasecmp(action, "do_stuff_to_msgs")) {
- do_stuff_to_msgs();
} else if (!strcasecmp(action, "change_start_page")) {
change_start_page();
} else if (!strcasecmp(action, "display_floorconfig")) {
@@ -1319,8 +1597,10 @@ void session_loop(struct httprequest *req)
#endif
} else if (!strcasecmp(action, "summary")) {
summary();
- } else if (!strcasecmp(action, "iconbar")) {
- do_iconbar();
+ } else if (!strcasecmp(action, "summary_inner_div")) {
+ begin_ajax_response();
+ summary_inner_div();
+ end_ajax_response();
} else if (!strcasecmp(action, "display_customize_iconbar")) {
display_customize_iconbar();
} else if (!strcasecmp(action, "commit_iconbar")) {
@@ -1331,16 +1611,39 @@ 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, "display_smtpqueue_inner_div")) {
+ display_smtpqueue_inner_div();
+ } else if (!strcasecmp(action, "display_sieve")) {
+ display_sieve();
+ } else if (!strcasecmp(action, "save_sieve")) {
+ save_sieve();
+ } else if (!strcasecmp(action, "display_add_remove_scripts")) {
+ display_add_remove_scripts(NULL);
+ } else if (!strcasecmp(action, "create_script")) {
+ create_script();
+ } else if (!strcasecmp(action, "delete_script")) {
+ delete_script();
} else if (!strcasecmp(action, "setup_wizard")) {
do_setup_wizard();
} else if (!strcasecmp(action, "display_preferences")) {
display_preferences();
} else if (!strcasecmp(action, "set_preferences")) {
set_preferences();
+ } else if (!strcasecmp(action, "recp_autocomplete")) {
+ recp_autocomplete(bstr("recp"));
+ } else if (!strcasecmp(action, "cc_autocomplete")) {
+ recp_autocomplete(bstr("cc"));
+ } else if (!strcasecmp(action, "bcc_autocomplete")) {
+ recp_autocomplete(bstr("bcc"));
+ } else if (!strcasecmp(action, "display_address_book_inner_div")) {
+ display_address_book_inner_div();
+ } else if (!strcasecmp(action, "set_floordiv_expanded")) {
+ set_floordiv_expanded(index[1]);
} else if (!strcasecmp(action, "diagnostics")) {
- output_headers(1, 1, 1, 0, 0, 0, 0);
-
- wprintf("You're in session %d
\n", WC->wc_session); + output_headers(1, 1, 1, 0, 0, 0); + wprintf("Session: %d
\n", WC->wc_session); wprintf("Command:
\n"); @@ -1348,8 +1651,17 @@ void session_loop(struct httprequest *req) dump_vars(); wprintf("
\n"); wDumpContent(1); + } else if (!strcasecmp(action, "updatenote")) { + updatenote(); + } else if (!strcasecmp(action, "display_room_directory")) { + display_room_directory(); + } else if (!strcasecmp(action, "download_file")) { + download_file(index[1]); + } else if (!strcasecmp(action, "upload_file")) { + upload_file(); } - /* When all else fais, display the main menu. */ + + /** When all else fais, display the main menu. */ else { display_main_menu(); } @@ -1365,5 +1677,7 @@ SKIP_ALL_THIS_CRAP: free(WC->upload); WC->upload_length = 0; } - } + + +/*@}*/
wc_roomname); + wprintf("\" title=\"RSS 2.0 feed for "); + escputs(WC->wc_roomname); + wprintf("\">\n"); +*/ } -/* - * Change the user's start page +/** + * \brief Change the user's start page */ void change_start_page(void) { if (bstr("startpage") == NULL) { safestrncpy(WC->ImportantMessage, - "startpage set to null", + _("You no longer have a start page selected."), sizeof WC->ImportantMessage); display_main_menu(); return; @@ -743,29 +791,64 @@ void change_start_page(void) { set_preference("startpage", bstr("startpage"), 1); - output_headers(1, 1, 0, 0, 0, 0, 0); + output_headers(1, 1, 0, 0, 0, 0); do_template("newstartpage"); wDumpContent(1); } - +/** + * \brief convenience function to indicate success + * \param successmessage the mesage itself + */ void display_success(char *successmessage) { convenience_page("007700", "OK", successmessage); } +/** + * \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"); + wprintf("WWW-Authenticate: Basic realm=\"\"\r\n", serv_info.serv_humannode); + wprintf("Content-Type: text/html\r\n\r\n"); + wprintf("
"); + wprintf(_("Authorization Required")); + wprintf("
\r\n"); + wprintf(_("The resource you requested requires a valid username and password. " + "You could not be logged in: %s\n"), message); + wDumpContent(0); +} +/** + * \brief This function is called by the MIME parser to handle data uploaded by + * the browser. Form data, uploaded files, and the data from HTTP PUT + * operations (such as those found in GroupDAV) all arrive this way. + * + * \param name Name of the item being uploaded + * \param filename Filename of the item being uploaded + * \param partnum MIME part identifier (not needed) + * \param disp MIME content disposition (not needed) + * \param content The actual data + * \param cbtype MIME content-type + * \param cbcharset Character set + * \param length Content length + * \param encoding MIME encoding type (not needed) + * \param userdata Not used here + */ void upload_handler(char *name, char *filename, char *partnum, char *disp, void *content, char *cbtype, char *cbcharset, size_t length, char *encoding, void *userdata) { struct 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); /* Form fields */ if ( (length > 0) && (strlen(cbtype) == 0) ) { @@ -778,7 +861,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) { @@ -796,33 +879,141 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp, } +/** + * \brief Convenience functions to wrap around asynchronous ajax responses + */ +void begin_ajax_response(void) { + output_headers(0, 0, 0, 0, 0, 0); + + wprintf("Content-type: text/html; charset=UTF-8\r\n" + "Server: %s\r\n" + "Connection: close\r\n" + "Pragma: no-cache\r\n" + "Cache-Control: no-cache\r\n", + SERVER); + 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]; + char gcontent[1024]; + char *junk; + size_t len; -/* - * Entry point for WebCit transaction + begin_ajax_response(); + + serv_printf("%s", bstr("g_cmd")); + serv_getln(buf, sizeof buf); + wprintf("%s\n", buf); + + if (buf[0] == '8') { + serv_printf("\n\n000"); + } + if ((buf[0] == '1') || (buf[0] == '8')) { + while (serv_getln(gcontent, sizeof gcontent), strcmp(gcontent, "000")) { + wprintf("%s\n", gcontent); + } + wprintf("000"); + } + if (buf[0] == '4') { + text_to_server(bstr("g_input")); + serv_puts("000"); + } + if (buf[0] == '6') { + len = atol(&buf[4]); + junk = malloc(len); + serv_read(junk, len); + free(junk); + } + if (buf[0] == '7') { + len = atol(&buf[4]); + junk = malloc(len); + memset(junk, 0, len); + serv_write(junk, len); + free(junk); + } + + 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(); +} + + + + +/** + * \brief Entry point for WebCit transaction */ void session_loop(struct httprequest *req) { char cmd[1024]; - char method[128]; - char action[128]; - char arg1[128]; - char arg2[128]; - char arg3[128]; + char action[1024]; + char arg[8][128]; + size_t sizes[10]; + char *index[10]; char buf[SIZ]; - int a, b; + char request_method[128]; + char pathname[1024]; + int a, b, nBackDots, nEmpty; int ContentLength = 0; int BytesRead = 0; char ContentType[512]; char *content = NULL; char *content_end = NULL; struct httprequest *hptr; - char browser_host[SIZ]; - char user_agent[SIZ]; + char browser_host[256]; + char user_agent[256]; int body_start = 0; - - /* We stuff these with the values coming from the client cookies, + int is_static = 0; + int n_static = 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_username[SIZ]; @@ -839,11 +1030,11 @@ void session_loop(struct httprequest *req) safestrncpy(c_httpauth_string, "", sizeof c_httpauth_string); safestrncpy(c_httpauth_user, DEFAULT_HTTPAUTH_USER, sizeof c_httpauth_user); safestrncpy(c_httpauth_pass, DEFAULT_HTTPAUTH_PASS, sizeof c_httpauth_pass); + strcpy(browser_host, ""); WC->upload_length = 0; WC->upload = NULL; WC->vars = NULL; - WC->is_wap = 0; hptr = req; @@ -851,31 +1042,35 @@ void session_loop(struct httprequest *req) safestrncpy(cmd, hptr->line, sizeof cmd); hptr = hptr->next; - extract_token(method, cmd, 0, ' ', sizeof method); - - /* Figure out the action */ - extract_token(action, cmd, 1, '/', sizeof action); - if (strstr(action, "?")) *strstr(action, "?") = 0; - if (strstr(action, "&")) *strstr(action, "&") = 0; - if (strstr(action, " ")) *strstr(action, " ") = 0; - - extract_token(arg1, cmd, 2, '/', sizeof arg1); - if (strstr(arg1, "?")) *strstr(arg1, "?") = 0; - if (strstr(arg1, "&")) *strstr(arg1, "&") = 0; - if (strstr(arg1, " ")) *strstr(arg1, " ") = 0; - - extract_token(arg2, cmd, 3, '/', sizeof arg2); - if (strstr(arg2, "?")) *strstr(arg2, "?") = 0; - if (strstr(arg2, "&")) *strstr(arg2, "&") = 0; - if (strstr(arg2, " ")) *strstr(arg2, " ") = 0; - - extract_token(arg3, cmd, 4, '/', sizeof arg3); - if (strstr(arg3, "?")) *strstr(arg3, "?") = 0; - if (strstr(arg3, "&")) *strstr(arg3, "&") = 0; - if (strstr(arg3, " ")) *strstr(arg3, " ") = 0; + extract_token(request_method, cmd, 0, ' ', sizeof request_method); + extract_token(pathname, cmd, 1, ' ', sizeof pathname); + + /** Figure out the action */ + index[0] = action; + sizes[0] = sizeof action; + for (a=1; a<9; a++) + { + index[a] = arg[a-1]; + sizes[a] = sizeof arg[a-1]; + } +//// index[9] = &foo; todo + nBackDots = 0; + nEmpty = 0; + for ( a = 0; a < 9; ++a) + { + extract_token(index[a], pathname, a + 1, '/', sizes[a]); + if (strstr(index[a], "?")) *strstr(index[a], "?") = 0; + if (strstr(index[a], "&")) *strstr(index[a], "&") = 0; + if (strstr(index[a], " ")) *strstr(index[a], " ") = 0; + if ((index[a][0] == '.') && (index[a][1] == '.')) + nBackDots++; + if (index[a][0] == '\0') + nEmpty++; + } while (hptr != NULL) { safestrncpy(buf, hptr->line, sizeof buf); + /* lprintf(9, "HTTP HEADER: %s\n", buf); */ hptr = hptr->next; if (!strncasecmp(buf, "Cookie: webcit=", 15)) { @@ -899,10 +1094,24 @@ 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); + while (num_tokens(browser_host, ',') > 1) { + remove_token(browser_host, 0, ','); + } + 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; } @@ -916,28 +1125,25 @@ void session_loop(struct httprequest *req) ContentType, ContentLength); body_start = strlen(content); - /* Read the entire input data at once. */ - client_read(WC->http_sock, &content[BytesRead+body_start], - ContentLength); + /** Read the entire input data at once. */ + client_read(WC->http_sock, &content[BytesRead+body_start], ContentLength); - if (!strncasecmp(ContentType, - "application/x-www-form-urlencoded", 33)) { + 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; } - /* 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) @@ -948,18 +1154,53 @@ 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. */ - if (!strcasecmp(action, "static")) { - safestrncpy(buf, arg1, sizeof buf); - for (a = 0; a < strlen(buf); ++a) - if (isspace(buf[a])) - buf[a] = 0; - output_static(buf); + /** Static content can be sent without connecting to Citadel. */ + is_static = 0; + for (a=0; a\n", WC->wc_session); + output_headers(1, 1, 1, 0, 0, 0); + wprintf("Session: %d
\n", WC->wc_session); wprintf("Command:
\n"); escputs(cmd); wprintf("
\n"); @@ -1348,8 +1651,17 @@ void session_loop(struct httprequest *req) dump_vars(); wprintf("
\n"); wDumpContent(1); + } else if (!strcasecmp(action, "updatenote")) { + updatenote(); + } else if (!strcasecmp(action, "display_room_directory")) { + display_room_directory(); + } else if (!strcasecmp(action, "download_file")) { + download_file(index[1]); + } else if (!strcasecmp(action, "upload_file")) { + upload_file(); } - /* When all else fais, display the main menu. */ + + /** When all else fais, display the main menu. */ else { display_main_menu(); } @@ -1365,5 +1677,7 @@ SKIP_ALL_THIS_CRAP: free(WC->upload); WC->upload_length = 0; } - } + + +/*@}*/