/*
* $Id$
- */
-/**
- * \defgroup MainServer This is the main transaction loop of the web service. It maintains a
+ *
+ * This is the main transaction loop of the web service. It maintains a
* persistent session to the Citadel server, handling HTTP WebCit requests as
* they arrive and presenting a user interface.
- * \ingroup WebcitHttpServer
*/
-/*@{*/
+
#include "webcit.h"
#include "groupdav.h"
#include "webserver.h"
#include <stdio.h>
#include <stdarg.h>
-/**
+/*
* String to unset the cookie.
* Any date "in the past" will work, so I chose my birthday, right down to
* the exact minute. :)
* \brief remove escaped strings from i.e. the url string (like %20 for blanks)
* \param buf the buffer to examine
*/
-void unescape_input(char *buf)
+long unescape_input(char *buf)
{
int a, b;
char hex[3];
long buflen;
+ long len;
buflen = strlen(buf);
buflen --;
}
- for (a = 0; a < buflen; ++a) {
+ a = 0;
+ while (a < buflen) {
if (buf[a] == '+')
buf[a] = ' ';
if (buf[a] == '%') {
- hex[0] = buf[a + 1];
- hex[1] = buf[a + 2];
- hex[2] = 0;
- b = 0;
- sscanf(hex, "%02x", &b);
- buf[a] = (char) b;
- memmove(&buf[a + 1], &buf[a + 3], buflen - a - 2);
+ /* don't let % chars through, rather truncate the input. */
+ if (a + 2 > buflen) {
+ buf[a] = '\0';
+ buflen = a;
+ }
+ else {
+ hex[0] = buf[a + 1];
+ hex[1] = buf[a + 2];
+ hex[2] = 0;
+ b = 0;
+ sscanf(hex, "%02x", &b);
+ buf[a] = (char) b;
+ len = buflen - a - 2;
+ if (len > 0)
+ memmove(&buf[a + 1], &buf[a + 3], len);
- buflen -=2;
+ buflen -=2;
+ }
}
+ a++;
}
+ return a;
+}
+void free_url(void *U)
+{
+ urlcontent *u = (urlcontent*) U;
+ free(u->url_data);
+ free(u);
}
/**
*/
void addurls(char *url)
{
- char *up, *ptr;
- char buf[SIZ];
- int a, b, len;
- struct urlcontent *u;
-
+ char *aptr, *bptr, *eptr;
+ char *up;
+ char buf[SIZ] = "";
+ int len, n, keylen;
+ urlcontent *u;
+ struct wcsession *WCC = WC;
+
+ if (WCC->urlstrings == NULL)
+ WCC->urlstrings = NewHash();
+ eptr = buf + sizeof (buf);
up = url;
+ /** locate the = sign */
+ n = safestrncpy(buf, up, sizeof buf);
+ if (n < 0) /** hm, we exceeded the buffer... hmmm what todo now? */
+ n = -n;
+ up = buf;
+// while ((up < eptr) && (*up != '?') && (*up != '&'))
+// up++;
while (!IsEmptyStr(up)) {
-
- /** locate the = sign */
- safestrncpy(buf, up, sizeof buf);
- b = (-1);
- for (a = 255; a >= 0; --a)
- if (buf[a] == '=')
- b = a;
- if (b < 0)
+ aptr = up;
+ while ((aptr < eptr) && (*aptr != '\0') && (*aptr != '='))
+ aptr++;
+ if (*aptr != '=')
return;
- buf[b] = 0;
-
- u = (struct urlcontent *) malloc(sizeof(struct urlcontent));
- u->next = WC->urlstrings;
- WC->urlstrings = u;
- safestrncpy(u->url_key, buf, sizeof u->url_key);
-
- /** now chop that part off */
- for (a = 0; a <= b; ++a)
- ++up;
-
- /** locate "&" and "?" delimiters */
- ptr = up;
- len = b = strlen(up);
- for (a = 0; a < len; ++a) {
- if ( (ptr[0] == '&') || (ptr[0] == '?') ) {
- b = a;
- break;
- }
- ++ptr;
+ *aptr = '\0';
+ aptr++;
+ bptr = aptr;
+ while ((bptr < eptr) && (*bptr != '\0')
+ && (*bptr != '&') && (*bptr != '?') && (*bptr != ' ')) {
+ bptr++;
+ }
+ *bptr = '\0';
+ u = (urlcontent *) malloc(sizeof(urlcontent));
+
+ keylen = safestrncpy(u->url_key, up, sizeof u->url_key);
+ if (keylen < 0){
+ lprintf(1, "URLkey to long! [%s]", up);
+ continue;
}
- ptr = up + b;
- *ptr = '\0';
- len = b;
+ Put(WCC->urlstrings, u->url_key, keylen, u, free_url);
+ len = bptr - aptr;
u->url_data = malloc(len + 2);
- safestrncpy(u->url_data, up, b + 1);
- u->url_data[b] = 0;
- unescape_input(u->url_data);
- up = ptr;
+ safestrncpy(u->url_data, aptr, len + 2);
+ u->url_data_size = unescape_input(u->url_data);
+ u->url_data[u->url_data_size] = '\0';
+ up = bptr;
++up;
- /* lprintf(9, "%s = %s\n", u->url_key, u->url_data); */
+ lprintf(9, "%s = [%ld] %s\n", u->url_key, u->url_data_size, u->url_data);
}
}
*/
void free_urls(void)
{
- struct urlcontent *u;
-
- while (WC->urlstrings != NULL) {
- free(WC->urlstrings->url_data);
- u = WC->urlstrings->next;
- free(WC->urlstrings);
- WC->urlstrings = u;
- }
+ DeleteHash(&WC->urlstrings);
}
/**
* \brief Diagnostic function to display the contents of all variables
*/
+
void dump_vars(void)
{
- struct urlcontent *u;
-
- for (u = WC->urlstrings; u != NULL; u = u->next) {
+ struct wcsession *WCC = WC;
+ urlcontent *u;
+ void *U;
+ long HKLen;
+ char *HKey;
+ HashPos *Cursor;
+
+ Cursor = GetNewHashPos ();
+ while (GetNextHashPos(WCC->urlstrings, Cursor, &HKLen, &HKey, &U)) {
+ u = (urlcontent*) U;
wprintf("%38s = %s\n", u->url_key, u->url_data);
}
}
* \brief Return the value of a variable supplied to the current web page (from the url or a form)
* \param key The name of the variable we want
*/
-char *bstr(char *key)
+
+const char *XBstr(char *key, size_t keylen, size_t *len)
{
- struct urlcontent *u;
+ void *U;
- for (u = WC->urlstrings; u != NULL; u = u->next) {
- if (!strcasecmp(u->url_key, key))
- return (u->url_data);
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, keylen, &U)) {
+ *len = ((urlcontent *)U)->url_data_size;
+ return ((urlcontent *)U)->url_data;
+ }
+ else {
+ *len = 0;
+ return ("");
}
- return ("");
+}
+
+const char *XBSTR(char *key, size_t *len)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, strlen (key), &U)){
+ *len = ((urlcontent *)U)->url_data_size;
+ return ((urlcontent *)U)->url_data;
+ }
+ else {
+ *len = 0;
+ return ("");
+ }
+}
+
+
+const char *BSTR(char *key)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, strlen (key), &U))
+ return ((urlcontent *)U)->url_data;
+ else
+ return ("");
+}
+
+const char *Bstr(char *key, size_t keylen)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, keylen, &U))
+ return ((urlcontent *)U)->url_data;
+ else
+ return ("");
+}
+
+long LBstr(char *key, size_t keylen)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, keylen, &U))
+ return atol(((urlcontent *)U)->url_data);
+ else
+ return (0);
+}
+
+long LBSTR(char *key)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, strlen(key), &U))
+ return atol(((urlcontent *)U)->url_data);
+ else
+ return (0);
+}
+
+int IBstr(char *key, size_t keylen)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, keylen, &U))
+ return atoi(((urlcontent *)U)->url_data);
+ else
+ return (0);
+}
+
+int IBSTR(char *key)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, strlen(key), &U))
+ return atoi(((urlcontent *)U)->url_data);
+ else
+ return (0);
+}
+
+int HaveBstr(char *key, size_t keylen)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, keylen, &U))
+ return ((urlcontent *)U)->url_data_size != 0;
+ else
+ return (0);
+}
+
+int HAVEBSTR(char *key)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, strlen(key), &U))
+ return ((urlcontent *)U)->url_data_size != 0;
+ else
+ return (0);
+}
+
+
+int YesBstr(char *key, size_t keylen)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, keylen, &U))
+ return strcmp( ((urlcontent *)U)->url_data, "yes") == 0;
+ else
+ return (0);
+}
+
+int YESBSTR(char *key)
+{
+ void *U;
+
+ if ((WC->urlstrings != NULL) &&
+ GetHash(WC->urlstrings, key, strlen(key), &U))
+ return strcmp( ((urlcontent *)U)->url_data, "yes") == 0;
+ else
+ return (0);
}
/**
target[0]='\0';
len = strlen (strbuf);
send = strbuf + len;
+ tend = target + tlen;
sptr = strbuf;
tptr = target;
target[0]='\0';
len = strlen (strbuf);
send = strbuf + len;
+ tend = target + tlen;
sptr = strbuf;
tptr = target;
/** check for ImportantMessages (these display in a div overlaying the main screen) */
if (!IsEmptyStr(WC->ImportantMessage)) {
- wprintf("<div id=\"important_message\">\n");
- wprintf("<span class=\"imsg\">"
- "%s</span><br />\n", WC->ImportantMessage);
- wprintf("</div>\n");
- wprintf("<script type=\"text/javascript\">\n"
- " setTimeout('hide_imsg_popup()', 3000); \n"
+ wprintf("<div id=\"important_message\">\n"
+ "<span class=\"imsg\">");
+ escputs(WC->ImportantMessage);
+ wprintf("</span><br />\n"
+ "</div>\n"
+ "<script type=\"text/javascript\">\n"
+ " setTimeout('hide_imsg_popup()', 5000); \n"
"</script>\n");
- safestrncpy(WC->ImportantMessage, "", sizeof WC->ImportantMessage);
+ WC->ImportantMessage[0] = 0;
}
if ( (WC->logged_in) && (!unset_cookies) ) {
/**
* \brief Output a piece of content to the web browser
*/
-void http_transmit_thing(char *thing, size_t length, char *content_type,
+void http_transmit_thing(char *thing, size_t length, const char *content_type,
int is_static) {
output_headers(0, 0, 0, 0, 0, is_static);
FILE *fp;
struct stat statbuf;
off_t bytes;
+ off_t count = 0;
+ size_t res;
char *bigbuffer;
- char content_type[128];
+ const char *content_type;
int len;
fp = fopen(what, "rb");
if (fp == NULL) {
lprintf(9, "output_static('%s') -- NOT FOUND --\n", what);
- wprintf("HTTP/1.1 404 %s\n", strerror(errno));
+ wprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
wprintf("Content-Type: text/plain\r\n");
wprintf("\r\n");
- wprintf("Cannot open %s: %s\n", what, strerror(errno));
+ wprintf("Cannot open %s: %s\r\n", what, strerror(errno));
} else {
len = strlen (what);
- if (!strncasecmp(&what[len - 4], ".gif", 4))
- safestrncpy(content_type, "image/gif", sizeof content_type);
- else if (!strncasecmp(&what[len - 4], ".txt", 4))
- safestrncpy(content_type, "text/plain", sizeof content_type);
- else if (!strncasecmp(&what[len - 4], ".css", 4))
- safestrncpy(content_type, "text/css", sizeof content_type);
- else if (!strncasecmp(&what[len - 4], ".jpg", 4))
- safestrncpy(content_type, "image/jpeg", sizeof content_type);
- else if (!strncasecmp(&what[len - 4], ".png", 4))
- safestrncpy(content_type, "image/png", sizeof content_type);
- else if (!strncasecmp(&what[len - 4], ".ico", 4))
- safestrncpy(content_type, "image/x-icon", sizeof content_type);
- else if (!strncasecmp(&what[len - 5], ".html", 5))
- safestrncpy(content_type, "text/html", sizeof content_type);
- else if (!strncasecmp(&what[len - 4], ".htm", 4))
- safestrncpy(content_type, "text/html", sizeof content_type);
- else if (!strncasecmp(&what[len - 4], ".wml", 4))
- safestrncpy(content_type, "text/vnd.wap.wml", sizeof content_type);
- else if (!strncasecmp(&what[len - 5], ".wmls", 5))
- safestrncpy(content_type, "text/vnd.wap.wmlscript", sizeof content_type);
- else if (!strncasecmp(&what[len - 5], ".wmlc", 5))
- safestrncpy(content_type, "application/vnd.wap.wmlc", sizeof content_type);
- else if (!strncasecmp(&what[len - 6], ".wmlsc", 6))
- safestrncpy(content_type, "application/vnd.wap.wmlscriptc", sizeof content_type);
- else if (!strncasecmp(&what[len - 5], ".wbmp", 5))
- safestrncpy(content_type, "image/vnd.wap.wbmp", sizeof content_type);
- else if (!strncasecmp(&what[len - 3], ".js", 3))
- safestrncpy(content_type, "text/javascript", sizeof content_type);
- else
- safestrncpy(content_type, "application/octet-stream", sizeof content_type);
-
- fstat(fileno(fp), &statbuf);
+ content_type = GuessMimeByFilename(what, len);
+
+ if (fstat(fileno(fp), &statbuf) == -1) {
+ lprintf(9, "output_static('%s') -- FSTAT FAILED --\n", what);
+ wprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
+ wprintf("Content-Type: text/plain\r\n");
+ wprintf("\r\n");
+ wprintf("Cannot fstat %s: %s\n", what, strerror(errno));
+ return;
+ }
+
+ count = 0;
bytes = statbuf.st_size;
- bigbuffer = malloc(bytes + 2);
- fread(bigbuffer, bytes, 1, fp);
+ if ((bigbuffer = malloc(bytes + 2)) == NULL) {
+ lprintf(9, "output_static('%s') -- MALLOC FAILED (%s) --\n", what, strerror(errno));
+ wprintf("HTTP/1.1 500 internal server error\r\n");
+ wprintf("Content-Type: text/plain\r\n");
+ wprintf("\r\n");
+ return;
+ }
+ while (count < bytes) {
+ if ((res = fread(bigbuffer + count, 1, bytes - count, fp)) == 0) {
+ lprintf(9, "output_static('%s') -- FREAD FAILED (%s) %zu bytes of %zu --\n", what, strerror(errno), bytes - count, bytes);
+ wprintf("HTTP/1.1 500 internal server error \r\n");
+ wprintf("Content-Type: text/plain\r\n");
+ wprintf("\r\n");
+ return;
+ }
+ count += res;
+ }
+
fclose(fp);
lprintf(9, "output_static('%s') %s\n", what, content_type);
http_transmit_thing(bigbuffer, (size_t)bytes, content_type, 1);
free(bigbuffer);
}
- if (!strcasecmp(bstr("force_close_session"), "yes")) {
+ if (yesbstr("force_close_session")) {
end_webcit_session();
}
}
-
/**
* \brief When the browser requests an image file from the Citadel server,
* this function is called to transmit it.
char buf[SIZ];
char *xferbuf = NULL;
off_t bytes;
+ const char *MimeType;
serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
serv_getln(buf, sizeof buf);
serv_puts("CLOS");
serv_getln(buf, sizeof buf);
+ MimeType = GuessMimeType (xferbuf, bytes);
/** Write it to the browser */
- http_transmit_thing(xferbuf, (size_t)bytes, "image/gif", 0);
+ if (!IsEmptyStr(MimeType))
+ {
+ http_transmit_thing(xferbuf,
+ (size_t)bytes,
+ MimeType,
+ 0);
+ free(xferbuf);
+ return;
+ }
+ /* hm... unknown mimetype? fallback to blank gif */
free(xferbuf);
+ }
- } else {
- /**
- * Instead of an ugly 404, send a 1x1 transparent GIF
- * when there's no such image on the server.
- */
- char blank_gif[SIZ];
- snprintf (blank_gif, SIZ, "%s%s", static_dirs[0], "/blank.gif");
- output_static(blank_gif);
- }
-
-
-
+
+ /**
+ * Instead of an ugly 404, send a 1x1 transparent GIF
+ * when there's no such image on the server.
+ */
+ char blank_gif[SIZ];
+ snprintf (blank_gif, SIZ, "%s%s", static_dirs[0], "/blank.gif");
+ output_static(blank_gif);
}
/**
wprintf("\">");
wprintf(_("Make this my start page"));
wprintf("</a>");
-/*
+#ifdef TECH_PREVIEW
wprintf("<br/><a href=\"rss?room=");
urlescputs(WC->wc_roomname);
wprintf("\" title=\"RSS 2.0 feed for ");
escputs(WC->wc_roomname);
wprintf("\"><img alt=\"RSS\" border=\"0\" src=\"static/xml_button.gif\"/></a>\n");
-*/
+#endif
}
void *content, char *cbtype, char *cbcharset,
size_t length, char *encoding, void *userdata)
{
- struct urlcontent *u;
+ urlcontent *u;
lprintf(9, "upload_handler() name=%s, type=%s, len=%d\n", name, cbtype, length);
+ if (WC->urlstrings == NULL)
+ WC->urlstrings = NewHash();
+
/* Form fields */
if ( (length > 0) && (IsEmptyStr(cbtype)) ) {
- u = (struct urlcontent *) malloc(sizeof(struct urlcontent));
- u->next = WC->urlstrings;
- WC->urlstrings = u;
+ u = (urlcontent *) malloc(sizeof(urlcontent));
+
safestrncpy(u->url_key, name, sizeof(u->url_key));
u->url_data = malloc(length + 1);
+ u->url_data_size = length;
memcpy(u->url_data, content, length);
u->url_data[length] = 0;
+ Put(WC->urlstrings, u->url_key, strlen(u->url_key), u, free_url);
+
/* lprintf(9, "Key: <%s> Data: <%s>\n", u->url_key, u->url_data); */
}
if (strlen(bstr("nonce")) > 0) {
lprintf(9, "Comparing supplied nonce %s to session nonce %ld\n",
bstr("nonce"), WC->nonce);
- if (atoi(bstr("nonce")) != WC->nonce) {
+ if (ibstr("nonce") != WC->nonce) {
lprintf(9, "Ignoring request with mismatched nonce.\n");
wprintf("HTTP/1.1 404 Security check failed\r\n");
wprintf("Content-Type: text/plain\r\n");
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,
}
/** This needs to run early */
+#ifdef TECH_PREVIEW
if (!strcasecmp(action, "rss")) {
display_rss(bstr("room"), request_method);
goto SKIP_ALL_THIS_CRAP;
}
+#endif
/**
* The GroupDAV stuff relies on HTTP authentication instead of
if (!strcasecmp(action, "image")) {
output_image();
+ } else if (!strcasecmp(action, "display_mime_icon")) {
+ display_mime_icon();
/**
* All functions handled below this point ... make sure we log in
delete_room();
} else if (!strcasecmp(action, "validate")) {
validate();
+ /* The users photo display / upload facility */
} else if (!strcasecmp(action, "display_editpic")) {
display_graphics_upload(_("your photo"),
- "UIMG 0|_userpic_",
+ "_userpic_",
"editpic");
} else if (!strcasecmp(action, "editpic")) {
- do_graphics_upload("UIMG 1|_userpic_");
+ do_graphics_upload("_userpic_");
+ /* room picture dispay / upload facility */
} else if (!strcasecmp(action, "display_editroompic")) {
display_graphics_upload(_("the icon for this room"),
- "UIMG 0|_roompic_",
+ "_roompic_",
"editroompic");
} else if (!strcasecmp(action, "editroompic")) {
- do_graphics_upload("UIMG 1|_roompic_");
+ do_graphics_upload("_roompic_");
+ /* the greetingpage hello pic */
+ } else if (!strcasecmp(action, "display_edithello")) {
+ display_graphics_upload(_("the Greetingpicture for the login prompt"),
+ "hello",
+ "edithellopic");
+ } else if (!strcasecmp(action, "edithellopic")) {
+ do_graphics_upload("hello");
+ /* the logoff banner */
+ } else if (!strcasecmp(action, "display_editgoodbyepic")) {
+ display_graphics_upload(_("the Logoff banner picture"),
+ "UIMG 0|%s|goodbuye",
+ "editgoodbuyepic");
+ } else if (!strcasecmp(action, "editgoodbuyepic")) {
+ do_graphics_upload("UIMG 1|%s|goodbuye");
+
} else if (!strcasecmp(action, "delete_floor")) {
delete_floor();
} else if (!strcasecmp(action, "rename_floor")) {
display_floorconfig(NULL);
} else if (!strcasecmp(action, "toggle_self_service")) {
toggle_self_service();
-#ifdef WEBCIT_WITH_CALENDAR_SERVICE
} else if (!strcasecmp(action, "display_edit_task")) {
display_edit_task();
} else if (!strcasecmp(action, "save_task")) {
respond_to_request();
} else if (!strcasecmp(action, "handle_rsvp")) {
handle_rsvp();
-#endif
} else if (!strcasecmp(action, "summary")) {
summary();
} else if (!strcasecmp(action, "summary_inner_div")) {
updatenote();
} else if (!strcasecmp(action, "display_room_directory")) {
display_room_directory();
+ } else if (!strcasecmp(action, "display_pictureview")) {
+ display_pictureview();
} else if (!strcasecmp(action, "download_file")) {
download_file(index[1]);
} else if (!strcasecmp(action, "upload_file")) {