No more robots.txt, we now welcome spiders
[citadel.git] / webcit / webcit.c
index 59347777d3cde9ab85f1a848649ecc0b83f552f7..16c533b973d238b2872f5903d84f10225e595cb4 100644 (file)
@@ -1,10 +1,25 @@
 /*
- * $Id$
- *
  * 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.
+ *
+ * Copyright (c) 1996-2010 by the citadel.org team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+
 #define SHOW_ME_VAPPEND_PRINTF
 #include <stdio.h>
 #include <stdarg.h>
@@ -41,21 +56,38 @@ void WebcitAddUrlHandler(const char * UrlString, long UrlSLen,
        Put(HandlerHash, UrlString, UrlSLen, NewHandler, DeleteWebcitHandler);
 }
 
+void tmplput_HANDLER_DISPLAYNAME(StrBuf *Target, WCTemplputParams *TP) 
+{
+       wcsession *WCC = WC;
+       if (WCC->Hdr->HR.Handler != NULL)
+               StrBufAppendTemplate(Target, TP, WCC->Hdr->HR.Handler->DisplayName, 0);
+}
+
 
 /*
  * web-printing funcion. uses our vsnprintf wrapper
  */
+#ifdef UBER_VERBOSE_DEBUGGING
+void wcc_printf(const char *FILE, const char *FUNCTION, long LINE, const char *format,...)
+#else
 void wc_printf(const char *format,...)
+#endif
 {
        wcsession *WCC = WC;
        va_list arg_ptr;
 
        if (WCC->WBuf == NULL)
                WCC->WBuf = NewStrBuf();
+#ifdef UBER_VERBOSE_DEBUGGING
+       StrBufAppendPrintf(WCC->WBuf, "\n%s:%s:%d[", FILE, FUNCTION, LINE);
+#endif
 
        va_start(arg_ptr, format);
        StrBufVAppendPrintf(WCC->WBuf, format, arg_ptr);
        va_end(arg_ptr);
+#ifdef UBER_VERBOSE_DEBUGGING
+       StrBufAppendPrintf(WCC->WBuf, "]\n");
+#endif
 }
 
 /*
@@ -99,17 +131,17 @@ void wDumpContent(int print_standard_html_footer)
 /*
  * Output HTTP headers and leading HTML for a page
  */
-void output_headers(   int do_httpheaders,     /* 1 = output HTTP headers                          */
+void output_headers(   int do_httpheaders,     /* 1 = output HTTP headers                        */
                        int do_htmlhead,        /* 1 = output HTML <head> section and <body> opener */
 
-                       int do_room_banner,     /* 0=no, 1=yes,                                     
+                       int do_room_banner,     /* 0=no, 1=yes,                              
                                                 * 2 = I'm going to embed my own, so don't open the 
-                                                *     <div id="content"> either.                   
+                                                *     <div id="content"> 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 suppress_check,     /* 1 = suppress check for instant messages        */
+                       int cache               /* 1 = allow browser to cache this page      */
 ) {
        wcsession *WCC = WC;
        char httpnow[128];
@@ -190,9 +222,7 @@ void output_headers(        int do_httpheaders,     /* 1 = output HTTP headers
                }
 
                if (do_room_banner == 1) {
-                       wc_printf("<div id=\"banner\">\n");
-                       embed_room_banner(NULL, navbar_default);
-                       wc_printf("</div>\n");
+                       tmplput_roombanner(NULL, NULL);
                }
        }
 
@@ -345,21 +375,21 @@ void begin_ajax_response(void) {
        wcsession *WCC = WC;
 
        FlushStrBuf(WCC->HBuf);
-        output_headers(0, 0, 0, 0, 0, 0);
+       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"
+       hprintf("Content-type: text/html; charset=UTF-8\r\n"
+               "Server: %s\r\n"
+               "Connection: close\r\n"
                ,
-                PACKAGE_STRING);
-        begin_burst();
+               PACKAGE_STRING);
+       begin_burst();
 }
 
 /*
  * print ajax response footer 
  */
 void end_ajax_response(void) {
-        wDumpContent(0);
+       wDumpContent(0);
 }
 
 
@@ -458,8 +488,9 @@ void seconds_since_last_gexp(void)
 
 
 
-void ReadPostData(void)
+int ReadPostData(void)
 {
+       int rc;
        int body_start = 0;
        wcsession *WCC = WC;
        StrBuf *content = NULL;
@@ -479,9 +510,12 @@ void ReadPostData(void)
        body_start = StrLength(content);
 
        /** Read the entire input data at once. */
-       client_read_to(WCC->Hdr, content, 
-                      WCC->Hdr->HR.ContentLength,
-                      SLEEPING);
+       rc = client_read_to(WCC->Hdr, content, 
+                           WCC->Hdr->HR.ContentLength,
+                           SLEEPING);
+       if (rc < 0)
+               return rc;
+               
        
        if (!strncasecmp(ChrPtr(WCC->Hdr->HR.ContentType), "application/x-www-form-urlencoded", 33)) {
                StrBufCutLeft(content, body_start);
@@ -502,6 +536,7 @@ void ReadPostData(void)
                content = NULL;
        }
        FreeStrBuf(&content);
+       return 1;
 }
 
 
@@ -515,32 +550,57 @@ void ParseREST_URL(void)
        HashList *Floors;
        void *vFloor;
 
+       lprintf(1, "parsing rest URL: %s\n", ChrPtr(WCC->Hdr->HR.ReqLine));
+
        WCC->Directory = NewHash(1, Flathash);
+       WCC->CurrentFloor = NULL;
 
        Buf = NewStrBuf();
-       while (StrBufExtract_NextToken(WCC->Hdr->HR.ReqLine, 
-                                      Buf, &pCh,  '/') >= 0)
+       while (StrBufExtract_NextToken(Buf, WCC->Hdr->HR.ReqLine, &pCh,  '/') >= 0)
        {
-               Put(WCC->Directory, IKEY(i), Buf, HFreeStrBuf);
-               if (i==0)
-                       pFloor = Buf;
+               if (StrLength(Buf) != 0) {
+                       /* ignore empty path segments */
+                       StrBufUnescape(Buf, 1);
+                       Put(WCC->Directory, IKEY(i), Buf, HFreeStrBuf);
+                       if (i==0)
+                               pFloor = Buf;
+                       Buf = NewStrBuf();
+               }
                i++;
-               Buf = NewStrBuf();
        }
-       if (i == 0)
-               FreeStrBuf(&Buf);
-       else if (pFloor != NULL)
+
+       FreeStrBuf(&Buf);
+       if (pFloor != NULL)
        {
                Floors = GetFloorListHash(NULL, NULL);
                
                if (Floors != NULL)
                {
-                       if (GetHash(Floors, SKEY(pFloor), &vFloor))
-                               WCC->CurrentFloor = (floor*) vFloor;
+                       if (GetHash(WCC->FloorsByName, SKEY(pFloor), &vFloor))
+                               WCC->CurrentFloor = (Floor*) vFloor;
                }
        }
 }
 
+int Conditional_REST_DEPTH(StrBuf *Target, WCTemplputParams *TP)
+{
+       long Depth, IsDepth;
+       long offset = 0;
+       wcsession *WCC = WC;
+
+       if (WCC->Hdr->HR.Handler != NULL)
+               offset ++;
+       Depth = GetTemplateTokenNumber(Target, TP, 2, 0);
+       IsDepth = GetCount(WCC->Directory) + offset;
+
+//     LogTemplateError(Target, "bla", 1, TP, "REST_DEPTH: %ld : %ld\n", Depth, IsDepth);
+       if (Depth < 0) {
+               Depth = -Depth;
+               return IsDepth > Depth;
+       }
+       else 
+               return Depth == IsDepth;
+}
 
 
 
@@ -558,22 +618,30 @@ void session_loop(void)
         * so we can use them to reconnect a timed out session if we have to.
         */
        wcsession *WCC;
-
-       
-       Buf = NewStrBuf();
-
+      
        WCC= WC;
-
        WCC->upload_length = 0;
        WCC->upload = NULL;
        WCC->is_mobile = 0;
-       WCC->trailing_javascript = NewStrBuf();
        WCC->Hdr->nWildfireHeaders = 0;
        if (WCC->Hdr->HR.Handler != NULL)
                Flags = WCC->Hdr->HR.Handler->Flags; /* so we can temporarily add our own... */
 
        if (WCC->Hdr->HR.ContentLength > 0) {
-               ReadPostData();
+               if (ReadPostData() < 0) {
+                       return;
+               }
+       }
+
+       Buf = NewStrBuf();
+       WCC->trailing_javascript = NewStrBuf();
+
+       /* Convert base64-encoded URL's back to plain text */
+       if (!strncmp(ChrPtr(WCC->Hdr->this_page), "/B64", 4)) {
+               StrBufCutLeft(WCC->Hdr->this_page, 4);
+               StrBufDecodeBase64(WCC->Hdr->this_page);
+               http_redirect(ChrPtr(WCC->Hdr->this_page));
+               goto SKIP_ALL_THIS_CRAP;
        }
 
        /* If there are variables in the URL, we must grab them now */
@@ -613,10 +681,12 @@ void session_loop(void)
            && (StrLength(WCC->Hdr->c_username) > 0)
            && (StrLength(WCC->Hdr->c_password) > 0))
        {
+               long Status;
+
                FlushStrBuf(Buf);
                serv_printf("USER %s", ChrPtr(WCC->Hdr->c_username));
                StrBuf_ServGetln(Buf);
-               if (GetServerStatus(Buf, NULL) == 3) {
+               if (GetServerStatus(Buf, &Status) == 3) {
                        serv_printf("PASS %s", ChrPtr(WCC->Hdr->c_password));
                        StrBuf_ServGetln(Buf);
                        if (GetServerStatus(Buf, NULL) == 2) {
@@ -630,6 +700,9 @@ void session_loop(void)
                                goto SKIP_ALL_THIS_CRAP;
                        }
                }
+               else if (Status == 541) {
+                       WCC->logged_in = 1;
+               }
        }
 
        xhttp = (WCC->Hdr->HR.eReqType != eGET) &&
@@ -653,11 +726,11 @@ void session_loop(void)
         * If we aren't in any room yet, but we have cookie data telling us where we're
         * supposed to be, and 'gotofirst' was not specified, then go there.
         */
-       else if ( (StrLength(WCC->wc_roomname) == 0) && ( (StrLength(WCC->Hdr->c_roomname) > 0) )) {
+       else if ( (StrLength(WCC->CurRoom.name) == 0) && ( (StrLength(WCC->Hdr->c_roomname) > 0) )) {
                int ret;
 
                lprintf(9, "We are in '%s' but cookie indicates '%s', going there...\n",
-                       ChrPtr(WCC->wc_roomname),
+                       ChrPtr(WCC->CurRoom.name),
                        ChrPtr(WCC->Hdr->c_roomname)
                );
                ret = gotoroom(WCC->Hdr->c_roomname);   /* do quietly to avoid session output! */
@@ -669,7 +742,7 @@ void session_loop(void)
 
        if (WCC->Hdr->HR.Handler != NULL) {
                if (!WCC->logged_in && ((WCC->Hdr->HR.Handler->Flags & ANONYMOUS) == 0)) {
-                       display_login(NULL);
+                       display_login();
                }
                else {
 /*
@@ -693,7 +766,7 @@ void session_loop(void)
                        if (xhttp)
                                authorization_required();
                        else 
-                               display_login(NULL);
+                               display_login();
                }
                /*
                 * Toplevel dav requests? or just a flat browser request? 
@@ -724,6 +797,21 @@ void sleeeeeeeeeep(int seconds)
        select(0, NULL, NULL, NULL, &tv);
 }
 
+int Conditional_IS_HTTPS(StrBuf *Target, WCTemplputParams *TP)
+{
+       return is_https != 0;
+}
+
+void AppendImportantMessage(const char *pch, long len)
+{
+       wcsession *WCC = WC;
+
+       if (StrLength(WCC->ImportantMsg) > 0) {
+               StrBufAppendBufPlain(WCC->ImportantMsg, HKEY("\n"), 0);
+       }
+               
+       StrBufAppendBufPlain(WCC->ImportantMsg, pch, len, 0);
+}
 
 int ConditionalImportantMesage(StrBuf *Target, WCTemplputParams *TP)
 {
@@ -781,10 +869,15 @@ InitModule_WEBCIT
 
        WebcitAddUrlHandler(HKEY("401"), "", 0, authorization_required, ANONYMOUS|COOKIEUNNEEDED);
        RegisterConditional(HKEY("COND:IMPMSG"), 0, ConditionalImportantMesage, CTX_NONE);
+       RegisterConditional(HKEY("COND:REST:DEPTH"), 0, Conditional_REST_DEPTH, CTX_NONE);
+       RegisterConditional(HKEY("COND:IS_HTTPS"), 0, Conditional_IS_HTTPS, CTX_NONE);
+
        RegisterNamespace("CSSLOCAL", 0, 0, tmplput_csslocal, NULL, CTX_NONE);
        RegisterNamespace("IMPORTANTMESSAGE", 0, 0, tmplput_importantmessage, NULL, CTX_NONE);
        RegisterNamespace("TRAILING_JAVASCRIPT", 0, 0, tmplput_trailing_javascript, NULL, CTX_NONE);
+       RegisterNamespace("URL:DISPLAYNAME", 0, 1, tmplput_HANDLER_DISPLAYNAME, NULL, CTX_NONE);
 
+       
        snprintf(dir, SIZ, "%s/webcit.css", static_local_dir);
        if (!access(dir, R_OK)) {
                lprintf(9, "Using local Stylesheet [%s]\n", dir);