* add contexttype, so the subst can precheck the context pointer for us, and bad...
[citadel.git] / webcit / webcit.c
index f510e27bbd37301bc18243c7ccbf75bf0fe2be43..ed2eefc54bb4670794e31eb0a197948d4b8f32d8 100644 (file)
@@ -149,7 +149,10 @@ void addurls(StrBuf *url)
                up = bptr;
                ++up;
 #ifdef DEBUG_URLSTRINGS
-               lprintf(9, "%s = [%ld]  %s\n", u->url_key, u->url_data_size, ChrPtr(u->url_data)); 
+               lprintf(9, "%s = [%ld]  %s\n", 
+                       u->url_key, 
+                       StrLength(u->url_data), 
+                       ChrPtr(u->url_data)); 
 #endif
        }
        //free(buf);
@@ -173,7 +176,7 @@ void dump_vars(void)
        urlcontent *u;
        void *U;
        long HKLen;
-       char *HKey;
+       const char *HKey;
        HashPos *Cursor;
        
        Cursor = GetNewHashPos ();
@@ -187,7 +190,7 @@ void dump_vars(void)
  * Return the value of a variable supplied to the current web page (from the url or a form)
  */
 
-const char *XBstr(char *key, size_t keylen, size_t *len)
+const char *XBstr(const char *key, size_t keylen, size_t *len)
 {
        void *U;
 
@@ -202,7 +205,7 @@ const char *XBstr(char *key, size_t keylen, size_t *len)
        }
 }
 
-const char *XBSTR(char *key, size_t *len)
+const char *XBSTR(const char *key, size_t *len)
 {
        void *U;
 
@@ -218,7 +221,7 @@ const char *XBSTR(char *key, size_t *len)
 }
 
 
-const char *BSTR(char *key)
+const char *BSTR(const char *key)
 {
        void *U;
 
@@ -229,7 +232,7 @@ const char *BSTR(char *key)
                return ("");
 }
 
-const char *Bstr(char *key, size_t keylen)
+const char *Bstr(const char *key, size_t keylen)
 {
        void *U;
 
@@ -262,7 +265,7 @@ const StrBuf *SBstr(const char *key, size_t keylen)
                return NULL;
 }
 
-long LBstr(char *key, size_t keylen)
+long LBstr(const char *key, size_t keylen)
 {
        void *U;
 
@@ -273,7 +276,7 @@ long LBstr(char *key, size_t keylen)
                return (0);
 }
 
-long LBSTR(char *key)
+long LBSTR(const char *key)
 {
        void *U;
 
@@ -284,7 +287,7 @@ long LBSTR(char *key)
                return (0);
 }
 
-int IBstr(char *key, size_t keylen)
+int IBstr(const char *key, size_t keylen)
 {
        void *U;
 
@@ -295,7 +298,7 @@ int IBstr(char *key, size_t keylen)
                return (0);
 }
 
-int IBSTR(char *key)
+int IBSTR(const char *key)
 {
        void *U;
 
@@ -306,7 +309,7 @@ int IBSTR(char *key)
                return (0);
 }
 
-int HaveBstr(char *key, size_t keylen)
+int HaveBstr(const char *key, size_t keylen)
 {
        void *U;
 
@@ -317,7 +320,7 @@ int HaveBstr(char *key, size_t keylen)
                return (0);
 }
 
-int HAVEBSTR(char *key)
+int HAVEBSTR(const char *key)
 {
        void *U;
 
@@ -329,7 +332,7 @@ int HAVEBSTR(char *key)
 }
 
 
-int YesBstr(char *key, size_t keylen)
+int YesBstr(const char *key, size_t keylen)
 {
        void *U;
 
@@ -340,7 +343,7 @@ int YesBstr(char *key, size_t keylen)
                return (0);
 }
 
-int YESBSTR(char *key)
+int YESBSTR(const char *key)
 {
        void *U;
 
@@ -399,7 +402,7 @@ void wDumpContent(int print_standard_html_footer)
 {
        if (print_standard_html_footer) {
                wprintf("</div>\n");    /* end of "text" div */
-               do_template("trailing");
+               do_template("trailing", NULL);
        }
 
        /* If we've been saving it all up for one big output burst,
@@ -409,89 +412,89 @@ void wDumpContent(int print_standard_html_footer)
 }
 
 
 /*
  * Copy a string, escaping characters which have meaning in HTML.  
  *
- * target              target buffer
- * strbuf              source buffer
- * nbsp                        If nonzero, spaces are converted to non-breaking spaces.
- * nolinebreaks                if set, linebreaks are removed from the string.
+ * target              target buffer
+ * strbuf              source buffer
+ * nbsp                        If nonzero, spaces are converted to non-breaking spaces.
+ * nolinebreaks                if set, linebreaks are removed from the string.
  */
 long stresc(char *target, long tSize, char *strbuf, int nbsp, int nolinebreaks)
 {
-       char *aptr, *bptr, *eptr;
-
-       *target = '\0';
-       aptr = strbuf;
-       bptr = target;
-       eptr = target + tSize - 6; // our biggest unit to put in... 
-
-       while ((bptr < eptr) && !IsEmptyStr(aptr) ){
-               if (*aptr == '<') {
-                       memcpy(bptr, "&lt;", 4);
-                       bptr += 4;
-               }
-               else if (*aptr == '>') {
-                       memcpy(bptr, "&gt;", 4);
-                       bptr += 4;
-               }
-               else if (*aptr == '&') {
-                       memcpy(bptr, "&amp;", 5);
-                       bptr += 5;
-               }
-               else if (*aptr == '\"') {
-                       memcpy(bptr, "&quot;", 6);
-                       bptr += 6;
-               }
-               else if (*aptr == '\'') {
-                       memcpy(bptr, "&#39;", 5);
-                       bptr += 5;
-               }
-               else if (*aptr == LB) {
-                       *bptr = '<';
-                       bptr ++;
-               }
-               else if (*aptr == RB) {
-                       *bptr = '>';
-                       bptr ++;
-               }
-               else if (*aptr == QU) {
-                       *bptr ='"';
-                       bptr ++;
-               }
-               else if ((*aptr == 32) && (nbsp == 1)) {
-                       memcpy(bptr, "&nbsp;", 6);
-                       bptr += 6;
-               }
-               else if ((*aptr == '\n') && (nolinebreaks)) {
-                       *bptr='\0';     /* nothing */
-               }
-               else if ((*aptr == '\r') && (nolinebreaks)) {
-                       *bptr='\0';     /* nothing */
-               }
-               else{
-                       *bptr = *aptr;
-                       bptr++;
-               }
-               aptr ++;
-       }
-       *bptr = '\0';
-       if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
-               return -1;
-       return (bptr - target);
+        char *aptr, *bptr, *eptr;
+        *target = '\0';
+        aptr = strbuf;
+        bptr = target;
+        eptr = target + tSize - 6; // our biggest unit to put in... 
+        while ((bptr < eptr) && !IsEmptyStr(aptr) ){
+                if (*aptr == '<') {
+                        memcpy(bptr, "&lt;", 4);
+                        bptr += 4;
+                }
+                else if (*aptr == '>') {
+                        memcpy(bptr, "&gt;", 4);
+                        bptr += 4;
+                }
+                else if (*aptr == '&') {
+                        memcpy(bptr, "&amp;", 5);
+                        bptr += 5;
+                }
+                else if (*aptr == '\"') {
+                        memcpy(bptr, "&quot;", 6);
+                        bptr += 6;
+                }
+                else if (*aptr == '\'') {
+                        memcpy(bptr, "&#39;", 5);
+                        bptr += 5;
+                }
+                else if (*aptr == LB) {
+                        *bptr = '<';
+                        bptr ++;
+                }
+                else if (*aptr == RB) {
+                        *bptr = '>';
+                        bptr ++;
+                }
+                else if (*aptr == QU) {
+                        *bptr ='"';
+                        bptr ++;
+                }
+                else if ((*aptr == 32) && (nbsp == 1)) {
+                        memcpy(bptr, "&nbsp;", 6);
+                        bptr += 6;
+                }
+                else if ((*aptr == '\n') && (nolinebreaks)) {
+                        *bptr='\0';     /* nothing */
+                }
+                else if ((*aptr == '\r') && (nolinebreaks)) {
+                        *bptr='\0';     /* nothing */
+                }
+                else{
+                        *bptr = *aptr;
+                        bptr++;
+                }
+                aptr ++;
+        }
+        *bptr = '\0';
+        if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
+                return -1;
+        return (bptr - target);
 }
 
+
 void escputs1(char *strbuf, int nbsp, int nolinebreaks)
 {
-       char *buf;
-       long Siz;
+       StrEscAppend(WC->WBuf, NULL, strbuf, nbsp, nolinebreaks);
+}
 
-       if (strbuf == NULL) return;
-       Siz = (3 * strlen(strbuf)) + SIZ ;
-       buf = malloc(Siz);
-       stresc(buf, Siz, strbuf, nbsp, nolinebreaks);
-       wprintf("%s", buf);
-       free(buf);
+void StrEscputs1(const StrBuf *strbuf, int nbsp, int nolinebreaks)
+{
+       StrEscAppend(WC->WBuf, strbuf, NULL, nbsp, nolinebreaks);
 }
 
 /* 
@@ -503,24 +506,37 @@ void escputs(char *strbuf)
 }
 
 
+/* 
+ * static wrapper for ecsputs1
+ */
+void StrEscPuts(const StrBuf *strbuf)
+{
+       StrEscputs1(strbuf, 0, 0);
+}
+
+
 /*
  * urlescape buffer and print it to the client
  */
-void urlescputs(char *strbuf)
+void urlescputs(const char *strbuf)
 {
-       char outbuf[SIZ];
-       
-       urlesc(outbuf, SIZ, strbuf);
-       wprintf("%s", outbuf);
+       StrBufUrlescAppend(WC->WBuf, NULL, strbuf);
 }
+
+/*
+ * urlescape buffer and print it to the client
+ */
+void UrlescPutStrBuf(const StrBuf *strbuf)
+{
+       StrBufUrlescAppend(WC->WBuf, strbuf, NULL);
+}
+
 /**
  * urlescape buffer and print it as header 
  */
-void hurlescputs(char *strbuf) {
-       char outbuf[SIZ];
-       
-       urlesc(outbuf, SIZ, strbuf);
-       hprintf("%s", outbuf);
+void hurlescputs(const char *strbuf) 
+{
+       StrBufUrlescAppend(WC->HBuf, NULL, strbuf);
 }
 
 
@@ -593,81 +609,27 @@ void jsescputs(char *strbuf)
        wprintf("%s", outbuf);
 }
 
-/*
- * Copy a string, escaping characters for message text hold
- */
-void msgesc(char *target, size_t tlen, char *strbuf)
-{
-       int len;
-       char *tend;
-       char *send;
-       char *tptr;
-       char *sptr;
-
-       target[0]='\0';
-       len = strlen (strbuf);
-       send = strbuf + len;
-       tend = target + tlen;
-       sptr = strbuf;
-       tptr = target;
-
-       while (!IsEmptyStr(sptr) && 
-              (sptr < send) &&
-              (tptr < tend)) {
-              
-               if (*sptr == '\n')
-                       *tptr = ' ';
-               else if (*sptr == '\r')
-                       *tptr = ' ';
-               else if (*sptr == '\'') {
-                       if (tend - tptr < 8)
-                               return;
-                       *(tptr++) = '&';
-                       *(tptr++) = '#';
-                       *(tptr++) = '3';
-                       *(tptr++) = '9';
-                       *tptr = ';';
-               } else {
-                       *tptr = *sptr;
-               }
-               tptr++; sptr++;
-       }
-       *tptr = '\0';
-}
-
 /*
  * print a string to the client after cleaning it with msgesc() and stresc()
  */
 void msgescputs1( char *strbuf)
 {
-       char *outbuf;
-       char *outbuf2;
-       int buflen;
+       StrBuf *OutBuf;
 
-       if (strbuf == NULL) return;
-       buflen = 3 * strlen(strbuf) + SIZ;
-       outbuf = malloc( buflen);
-       outbuf2 = malloc( buflen);
-       msgesc(outbuf, buflen, strbuf);
-       stresc(outbuf2, buflen, outbuf, 0, 0);
-       wprintf("%s", outbuf2);
-       free(outbuf);
-       free(outbuf2);
+       if ((strbuf == NULL) || IsEmptyStr(strbuf))
+               return;
+       OutBuf = NewStrBuf();
+       StrMsgEscAppend(OutBuf, NULL, strbuf);
+       StrEscAppend(WC->WBuf, OutBuf, NULL, 0, 0);
+       FreeStrBuf(&OutBuf);
 }
 
 /*
  * print a string to the client after cleaning it with msgesc()
  */
 void msgescputs(char *strbuf) {
-       char *outbuf;
-       size_t len;
-
-       if (strbuf == NULL) return;
-       len =  (3 * strlen(strbuf)) + SIZ;
-       outbuf = malloc(len);
-       msgesc(outbuf, len, strbuf);
-       wprintf("%s", outbuf);
-       free(outbuf);
+       if ((strbuf != NULL) && !IsEmptyStr(strbuf))
+               StrMsgEscAppend(WC->WBuf, NULL, strbuf);
 }
 
 
@@ -742,12 +704,12 @@ void output_headers(      int do_httpheaders,     /* 1 = output HTTP headers
                           "<link href=\"static.local/webcit.css\" rel=\"stylesheet\" type=\"text/css\">"
                        );
                }
-               do_template("head");
+               do_template("head", NULL);
        }
 
        /* ICONBAR */
        if (do_htmlhead) {
-
+               begin_burst();
 
                /* check for ImportantMessages (these display in a div overlaying the main screen) */
                if (!IsEmptyStr(WC->ImportantMessage)) {
@@ -805,6 +767,10 @@ void http_redirect(const char *whichpage) {
 void http_transmit_thing(const char *content_type,
                         int is_static) {
 
+       lprintf(9, "http_transmit_thing(%s)%s\n",
+               content_type,
+               (is_static ? " (static)" : "")
+       );
        output_headers(0, 0, 0, 0, 0, is_static);
 
        hprintf("Content-type: %s\r\n"
@@ -830,7 +796,7 @@ void print_menu_box(char* Title, char *Class, int nLines, ...)
        long i;
        
        svput("BOXTITLE", WCS_STRING, Title);
-       do_template("beginbox");
+       do_template("beginbox", NULL);
        
        wprintf("<ul class=\"%s\">", Class);
        
@@ -847,7 +813,7 @@ void print_menu_box(char* Title, char *Class, int nLines, ...)
        
        wprintf("</ul>");
        
-       do_template("endbox");
+       do_template("endbox", NULL);
 }
 
 
@@ -999,13 +965,11 @@ void mimepart(const char *msgnum, const char *partnum, int force_download)
        char buf[256];
        off_t bytes;
        char content_type[256];
-       char *content = NULL;
        
        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);
                if (force_download) {
                        strcpy(content_type, "application/octet-stream");
                }
@@ -1025,7 +989,6 @@ void mimepart(const char *msgnum, const char *partnum, int force_download)
                wprintf(_("An error occurred while retrieving this part: %s\n"), &buf[4]);
                end_burst();
        }
-
 }
 
 
@@ -1054,7 +1017,6 @@ char *load_mimepart(long msgnum, char *partnum)
        else {
                return(NULL);
        }
-
 }
 
 
@@ -1094,7 +1056,11 @@ void blank_page(void) {
  * A template has been requested
  */
 void url_do_template(void) {
-       do_template(bstr("template"));
+       const StrBuf *Tmpl = sbstr("template");
+       begin_burst();
+       output_headers(1, 0, 0, 0, 1, 0);
+       DoTemplate(ChrPtr(Tmpl), StrLength(Tmpl), NULL, NULL, 0);
+       end_burst();
 }
 
 
@@ -1102,7 +1068,7 @@ void url_do_template(void) {
 /*
  * Offer to make any page the user's "start page."
  */
-void offer_start_page(void) {
+void offer_start_page(StrBuf *Target, int nArgs, WCTemplateToken *Token, void *Context, int ContextType) {
        wprintf("<a href=\"change_start_page?startpage=");
        urlescputs(WC->this_page);
        wprintf("\">");
@@ -1134,7 +1100,7 @@ void change_start_page(void) {
        set_preference("startpage", NewStrBufPlain(bstr("startpage"), -1), 1);
 
        output_headers(1, 1, 0, 0, 0, 0);
-       do_template("newstartpage");
+       do_template("newstartpage", NULL);
        wDumpContent(1);
 }
 
@@ -1203,7 +1169,10 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp,
                
                Put(WC->urlstrings, u->url_key, strlen(u->url_key), u, free_url);
 #ifdef DEBUG_URLSTRINGS
-               lprintf(9, "Key: <%s> len: [%ld] Data: <%s>\n", u->url_key, u->url_data_size, u->url_data);
+               lprintf(9, "Key: <%s> len: [%ld] Data: <%s>\n", 
+                       u->url_key, 
+                       StrLength(u->url_data), 
+                       ChrPtr(u->url_data));
 #endif
        }
 
@@ -1229,14 +1198,14 @@ void upload_handler(char *name, char *filename, char *partnum, char *disp,
  * Convenience functions to wrap around asynchronous ajax responses
  */
 void begin_ajax_response(void) {
+       struct wcsession *WCC = WC;
+
+       FlushStrBuf(WCC->HBuf);
         output_headers(0, 0, 0, 0, 0, 0);
 
         hprintf("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"
-               "Expires: -1\r\n"
                ,
                 PACKAGE_STRING);
         begin_burst();
@@ -1246,7 +1215,6 @@ void begin_ajax_response(void) {
  * print ajax response footer 
  */
 void end_ajax_response(void) {
-        ///hprintf("\r\n");///// todo: is this right?
         wDumpContent(0);
 }
 
@@ -1315,11 +1283,11 @@ void seconds_since_last_gexp(void)
 {
        char buf[256];
 
-       begin_ajax_response();
        if ( (time(NULL) - WC->last_pager_check) < 30) {
                wprintf("NO\n");
        }
        else {
+               memset(buf, 5, 0);
                serv_puts("NOOP");
                serv_getln(buf, sizeof buf);
                if (buf[3] == '*') {
@@ -1329,7 +1297,6 @@ void seconds_since_last_gexp(void)
                        wprintf("NO");
                }
        }
-       end_ajax_response();
 }
 
 /**
@@ -1355,22 +1322,21 @@ int is_mobile_ua(char *user_agent) {
 /*
  * Entry point for WebCit transaction
  */
-void session_loop(struct httprequest *req)
+void session_loop(HashList *HTTPHeaders, StrBuf *ReqLine, StrBuf *request_method, StrBuf *ReadBuf)
 {
-       char cmd[1024];
+       const char *pch, *pchs, *pche;
+       void *vLine;
        char action[1024];
        char arg[8][128];
        size_t sizes[10];
        char *index[10];
        char buf[SIZ];
-       char request_method[128];
-       char pathname[1024];
-       int a, b, nBackDots, nEmpty;
+       int a, nBackDots, nEmpty;
        int ContentLength = 0;
-       char ContentType[512];
-       char *content = NULL;
-       char *content_end = NULL;
-       struct httprequest *hptr;
+       StrBuf *ContentType = NULL;
+       StrBuf *UrlLine = NULL;
+       StrBuf *content = NULL;
+       const char *content_end = NULL;
        char browser_host[256];
        char user_agent[256];
        int body_start = 0;
@@ -1387,7 +1353,6 @@ void session_loop(struct httprequest *req)
        char c_httpauth_string[SIZ];
        char c_httpauth_user[SIZ];
        char c_httpauth_pass[SIZ];
-       char cookie[SIZ];
        struct wcsession *WCC;
        
        safestrncpy(c_username, "", sizeof c_username);
@@ -1411,14 +1376,6 @@ void session_loop(struct httprequest *req)
        WCC->upload = NULL;
        WCC->is_mobile = 0;
 
-       hptr = req;
-       if (hptr == NULL) return;
-
-       safestrncpy(cmd, hptr->line, sizeof cmd);
-       hptr = hptr->next;
-       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;
@@ -1432,7 +1389,7 @@ void session_loop(struct httprequest *req)
        nEmpty = 0;
        for ( a = 0; a < 9; ++a)
        {
-               extract_token(index[a], pathname, a + 1, '/', sizes[a]);
+               extract_token(index[a], ChrPtr(ReqLine), 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;
@@ -1442,107 +1399,109 @@ void session_loop(struct httprequest *req)
                        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)) {
-                       safestrncpy(cookie, &buf[15], sizeof cookie);
-                       cookie_to_stuff(cookie, NULL,
-                                       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]);
-               }
-               else if (!strncasecmp(buf, "Content-type: ", 14)) {
-                       safestrncpy(ContentType, &buf[14], sizeof ContentType);
-               }
-               else if (!strncasecmp(buf, "User-agent: ", 12)) {
-                       safestrncpy(user_agent, &buf[12], sizeof user_agent);
-                       #ifdef TECH_PREVIEW
-                       if (is_mobile_ua(&buf[12])) {
-                               WCC->is_mobile = 1;
-                       }
-                       #endif
-               }
-               else if (!strncasecmp(buf, "X-Forwarded-Host: ", 18)) {
-                       if (follow_xff) {
-                               safestrncpy(WCC->http_host, &buf[18], sizeof WCC->http_host);
-                       }
+       if (GetHash(HTTPHeaders, HKEY("COOKIE"), &vLine) && 
+           (vLine != NULL)){
+               cookie_to_stuff((StrBuf *)vLine, NULL,
+                               c_username, sizeof c_username,
+                               c_password, sizeof c_password,
+                               c_roomname, sizeof c_roomname);
+       }
+       if (GetHash(HTTPHeaders, HKEY("AUTHORIZATION"), &vLine) &&
+           (vLine!=NULL)) {
+               CtdlDecodeBase64(c_httpauth_string, ChrPtr((StrBuf*)vLine), StrLength((StrBuf*)vLine));
+               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);
+       }
+       if (GetHash(HTTPHeaders, HKEY("CONTENT-LENGTH"), &vLine) &&
+           (vLine!=NULL)) {
+               ContentLength = StrToi((StrBuf*)vLine);
+       }
+       if (GetHash(HTTPHeaders, HKEY("CONTENT-TYPE"), &vLine) &&
+           (vLine!=NULL)) {
+               ContentType = (StrBuf*)vLine;
+       }
+       if (GetHash(HTTPHeaders, HKEY("USER-AGENT"), &vLine) &&
+           (vLine!=NULL)) {
+               safestrncpy(user_agent, ChrPtr((StrBuf*)vLine), sizeof user_agent);
+#ifdef TECH_PREVIEW
+               if ((WCC->is_mobile < 0) && is_mobile_ua(&buf[12])) {                   
+                       WCC->is_mobile = 1;
                }
-               else if (!strncasecmp(buf, "Host: ", 6)) {
-                       if (IsEmptyStr(WCC->http_host)) {
-                               safestrncpy(WCC->http_host, &buf[6], sizeof WCC->http_host);
-                       }
+               else {
+                       WCC->is_mobile = 0;
                }
-               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);
+#endif
+       }
+       if ((follow_xff) &&
+           GetHash(HTTPHeaders, HKEY("X-FORWARDED-HOST"), &vLine) &&
+           (vLine != NULL)) {
+               safestrncpy(WCC->http_host, &buf[18], sizeof WCC->http_host);
+       }
+       if (IsEmptyStr(WCC->http_host) && 
+           GetHash(HTTPHeaders, HKEY("HOST"), &vLine) &&
+           (vLine!=NULL)) {
+               safestrncpy(WCC->http_host, 
+                           ChrPtr((StrBuf*)vLine), 
+                           sizeof WCC->http_host);
+               
+       }
+       if (GetHash(HTTPHeaders, HKEY("X-FORWARDED-FOR"), &vLine) &&
+           (vLine!=NULL)) {
+               safestrncpy(browser_host, 
+                           ChrPtr((StrBuf*) vLine), 
+                           sizeof browser_host);
+               while (num_tokens(browser_host, ',') > 1) {
+                       remove_token(browser_host, 0, ',');
                }
+               striplt(browser_host);
        }
 
        if (ContentLength > 0) {
-               int BuffSize;
-
-               BuffSize = ContentLength + SIZ;
-               content = malloc(BuffSize);
-               memset(content, 0, BuffSize);
-               snprintf(content,  BuffSize, "Content-type: %s\n"
-                               "Content-length: %d\n\n",
-                               ContentType, ContentLength);
-               body_start = strlen(content);
+               content = NewStrBuf();
+               StrBufPrintf(content, "Content-type: %s\n"
+                        "Content-length: %d\n\n",
+                        ChrPtr(ContentType), ContentLength);
+/*
+               hprintf("Content-type: %s\n"
+                       "Content-length: %d\n\n",
+                       ContentType, ContentLength);
+*/
+               body_start = StrLength(content);
 
                /** Read the entire input data at once. */
-               client_read(WCC->http_sock, &content[body_start], ContentLength);
-
-               if (!strncasecmp(ContentType, "application/x-www-form-urlencoded", 33)) {
-                       StrBuf *Content;
-
-                       Content = _NewConstStrBuf(&content[body_start],ContentLength);
-                       addurls(Content);
-                       FreeStrBuf(&Content);
-               } else if (!strncasecmp(ContentType, "multipart", 9)) {
-                       content_end = content + ContentLength + body_start;
-                       mime_parser(content, content_end, *upload_handler, NULL, NULL, NULL, 0);
+               client_read(&WCC->http_sock, content, ReadBuf, ContentLength);
+
+               if (!strncasecmp(ChrPtr(ContentType), "application/x-www-form-urlencoded", 33)) {
+                       StrBufCutLeft(content, body_start);
+                       addurls(content);
+               } else if (!strncasecmp(ChrPtr(ContentType), "multipart", 9)) {
+                       content_end = ChrPtr(content) + ContentLength + body_start;
+                       mime_parser(ChrPtr(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 */
-       safestrncpy(WCC->this_page, cmd, sizeof(WCC->this_page));
+       safestrncpy(WCC->this_page, ChrPtr(ReqLine), sizeof(WCC->this_page));
        remove_token(WCC->this_page, 2, ' ');
        remove_token(WCC->this_page, 0, ' ');
 
        /* If there are variables in the URL, we must grab them now */
-       len = strlen(cmd);
-       for (a = 0; a < len; ++a) {
-               if ((cmd[a] == '?') || (cmd[a] == '&')) {
-                       StrBuf *Params;
-                       for (b = a; b < len; ++b) {
-                               if (isspace(cmd[b])){
-                                       cmd[b] = 0;
-                                       len = b - 1;
-                               }
-                       }
-                       //cmd[len - a] = '\0';
-                       Params = _NewConstStrBuf(&cmd[a + 1], len - a);
-                       addurls(Params);
-                       cmd[a] = 0;
-                       len = a - 1;
+       UrlLine = NewStrBufDup(ReqLine);
+       len = StrLength(UrlLine);
+       pch = pchs = ChrPtr(UrlLine);
+       pche = pchs + len;
+       while (pch < pche) {
+               if ((*pch == '?') || (*pch == '&')) {
+                       StrBufCutLeft(UrlLine, pch - pchs + 1);
+                       addurls(UrlLine);
+                       break;
                }
+               pch ++;
        }
+       FreeStrBuf(&UrlLine);
 
        /* If it's a "force 404" situation then display the error and bail. */
        if (!strcmp(action, "404")) {
@@ -1555,7 +1514,7 @@ void session_loop(struct httprequest *req)
 
        /* Static content can be sent without connecting to Citadel. */
        is_static = 0;
-       for (a=0; a<ndirs; ++a) {
+       for (a=0; a<ndirs && ! is_static; ++a) {
                if (!strcasecmp(action, (char*)static_content_dirs[a])) { /* map web to disk location */
                        is_static = 1;
                        n_static = a;
@@ -1654,7 +1613,7 @@ void session_loop(struct httprequest *req)
                        }
                }
        }
-////////todo: restorte language in this case
+////////todo: restore language in this case
        /*
         * Functions which can be performed without logging in
         */
@@ -1663,7 +1622,7 @@ void session_loop(struct httprequest *req)
                goto SKIP_ALL_THIS_CRAP;
        }
        if (!strcasecmp(action, "freebusy")) {
-               do_freebusy(cmd);
+               do_freebusy(ChrPtr(ReqLine));
                goto SKIP_ALL_THIS_CRAP;
        }
 
@@ -1705,8 +1664,10 @@ void session_loop(struct httprequest *req)
         * our session's authentication.
         */
        if (!strncasecmp(action, "groupdav", 8)) {
-               groupdav_main(req, ContentType, /* do GroupDAV methods */
-                       ContentLength, content+body_start);
+               groupdav_main(HTTPHeaders, 
+                             ReqLine, request_method,
+                             ContentType, /* do GroupDAV methods */
+                             ContentLength, content, body_start);
                if (!WCC->logged_in) {
                        WCC->killthis = 1;      /* If not logged in, don't */
                }                               /* keep the session active */
@@ -1718,9 +1679,10 @@ 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 */
-                       ContentLength, content+body_start);
+       if ((strcasecmp(ChrPtr(request_method), "GET")) && (strcasecmp(ChrPtr(request_method), "POST"))) {
+               groupdav_main(HTTPHeaders, ReqLine, 
+                             request_method, ContentType, /** do GroupDAV methods */
+                             ContentLength, content, body_start);
                if (!WCC->logged_in) {
                        WCC->killthis = 1;      /** If not logged in, don't */
                }                               /** keep the session active */
@@ -1803,7 +1765,7 @@ void session_loop(struct httprequest *req)
 SKIP_ALL_THIS_CRAP:
        fflush(stdout);
        if (content != NULL) {
-               free(content);
+               FreeStrBuf(&content);
                content = NULL;
        }
        free_urls();
@@ -1831,9 +1793,9 @@ void diagnostics(void)
        output_headers(1, 1, 1, 0, 0, 0);
        wprintf("Session: %d<hr />\n", WC->wc_session);
        wprintf("Command: <br /><PRE>\n");
-       escputs(WC->UrlFragment1);
+       StrEscPuts(WC->UrlFragment1);
        wprintf("<br />\n");
-       escputs(WC->UrlFragment2);
+       StrEscPuts(WC->UrlFragment2);
        wprintf("</PRE><hr />\n");
        wprintf("Variables: <br /><PRE>\n");
        dump_vars();
@@ -1853,6 +1815,44 @@ void download_mimepart(void) {
                 1);
 }
 
+
+int ConditionalImportantMesage(WCTemplateToken *Tokens, void *Context, int ContextType)
+{
+       struct wcsession *WCC = WC;
+       if (WCC != NULL)
+               return (!IsEmptyStr(WCC->ImportantMessage));
+       else
+               return 0;
+}
+
+void tmplput_importantmessage(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
+{
+       struct wcsession *WCC = WC;
+       
+       if (WCC != NULL) {
+               StrEscAppend(Target, NULL, WCC->ImportantMessage, 0, 0);
+                       WCC->ImportantMessage[0] = '\0';
+       }
+}
+
+int ConditionalBstr(WCTemplateToken *Tokens, void *Context, int ContextType)
+{
+       if(Tokens->nParameters == 1)
+               return HaveBstr(Tokens->Params[0]->Start, 
+                               Tokens->Params[0]->len);
+       else
+               return strcmp(Bstr(Tokens->Params[0]->Start, 
+                                  Tokens->Params[0]->len),
+                             Tokens->Params[1]->Start) == 0;
+}
+
+void tmplput_bstr(StrBuf *Target, int nArgs, WCTemplateToken *Tokens, void *Context, int ContextType)
+{
+       StrBufAppendBuf(Target, 
+                       SBstr(Tokens->Params[0]->Start, 
+                             Tokens->Params[0]->len), 0);
+}
+
 void 
 InitModule_WEBCIT
 (void)
@@ -1867,4 +1867,10 @@ InitModule_WEBCIT
        WebcitAddUrlHandler(HKEY("mimepart"), view_mimepart, NEED_URL);
        WebcitAddUrlHandler(HKEY("mimepart_download"), download_mimepart, NEED_URL);
        WebcitAddUrlHandler(HKEY("diagnostics"), diagnostics, NEED_URL);
+
+       RegisterConditional(HKEY("COND:IMPMSG"), 0, ConditionalImportantMesage, CTX_NONE);
+       RegisterConditional(HKEY("COND:BSTR"), 1, ConditionalBstr, CTX_NONE);
+       RegisterNamespace("BSTR", 1, 2, tmplput_bstr, CTX_NONE);
+       RegisterNamespace("IMPORTANTMESSAGE", 0, 0, tmplput_importantmessage, CTX_NONE);
+       RegisterNamespace("OFFERSTARTPAGE", 0, 0, offer_start_page, CTX_NONE);
 }