Renderers cleanup part 1
[citadel.git] / webcit / static.c
index e12a10b298992fc83e60d14619b8627b5f4616c5..34a656ee2b6058ed3203c4fc5d70cf9ad816dd98 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * $Id: webcit.c 7459 2009-05-17 08:34:33Z dothebart $
- *
  * 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.
 #include <unistd.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <stddef.h>
+
 
 #include "webcit.h"
 #include "webserver.h"
 
-
-HashList *StaticFilemappings[4] = {NULL, NULL, NULL, NULL};
-
-
+unsigned char OnePixelGif[37] = {
+               0x47,
+               0x49,
+               0x46,
+               0x38,
+               0x37,
+               0x61,
+               0x01,
+               0x00,
+               0x01,
+               0x00,
+               0x80,
+               0x00,
+               0x00,
+               0xff,
+               0xff,
+               0xff,
+               0xff,
+               0xff,
+               0xff,
+               0x2c,
+               0x00,
+               0x00,
+               0x00,
+               0x00,
+               0x01,
+               0x00,
+               0x01,
+               0x00,
+               0x00,
+               0x02,
+               0x02,
+               0x44,
+               0x01,
+               0x00,
+               0x3b 
+};
+
+
+HashList *StaticFilemappings[5] = {NULL, NULL, NULL, NULL, NULL};
 /*
-  for ( a = 0; a < 9; ++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;
-  if ((index[a][0] == '.') && (index[a][1] == '.'))
-  nBackDots++;
-  if (index[a][0] == '\0')
-  nEmpty++;
+  syslog(LOG_DEBUG, "Suspicious request. Ignoring.");
+  hprintf("HTTP/1.1 404 Security check failed\r\n");
+  hprintf("Content-Type: text/plain\r\n\r\n");
+  wc_printf("You have sent a malformed or invalid request.\r\n");
+  end_burst();
   }
 */
 
-/* TODO: staticdata
-{
-
-
-       /** 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];
-       }
-       nBackDots = 0;
-       nEmpty = 0;
-
-
-       /* Static content can be sent without connecting to Citadel. * /
-       is_static = 0;
-       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;
-               }
-       }
-       if (is_static) {
-               if (nBackDots < 2)
-               {
-                       snprintf(buf, sizeof buf, "%s/%s/%s/%s/%s/%s/%s/%s",
-                                static_dirs[n_static], 
-                                index[1], index[2], index[3], index[4], index[5], index[6], index[7]);
-                       for (a=0; a<8; ++a) {
-                               if (buf[strlen(buf)-1] == '/') {
-                                       buf[strlen(buf)-1] = 0;
-                               }
-                       }
-                       for (a = 0; a < strlen(buf); ++a) {
-                               if (isspace(buf[a])) {
-                                       buf[a] = 0;
-                               }
-                       }
-                       output_static(buf);
-               }
-               else 
-               {
-                       lprintf(9, "Suspicious request. Ignoring.");
-                       hprintf("HTTP/1.1 404 Security check failed\r\n");
-                       hprintf("Content-Type: text/plain\r\n\r\n");
-                       wprintf("You have sent a malformed or invalid request.\r\n");
-                       end_burst();
-               }
-               goto SKIP_ALL_THIS_CRAP;        /* Don't try to connect * /
-       }
-       }*/
 
+void output_error_pic(const char *ErrMsg1, const char *ErrMsg2)
+{
+       hprintf("HTTP/1.1 200 %s\r\n", ErrMsg1);
+       hprintf("Content-Type: image/gif\r\n");
+       hprintf("x-webcit-errormessage: %s\r\n", ErrMsg2);
+       begin_burst();
+       StrBufPlain(WC->WBuf, (const char *)OnePixelGif, sizeof(OnePixelGif));
+       end_burst();
+}
 
 /*
  * dump out static pages from disk
@@ -98,38 +86,52 @@ void output_static(const char *what)
        int fd;
        struct stat statbuf;
        off_t bytes;
-       off_t count = 0;
        const char *content_type;
        int len;
        const char *Err;
 
+       len = strlen (what);
+       content_type = GuessMimeByFilename(what, len);
        fd = open(what, O_RDONLY);
        if (fd <= 0) {
-               lprintf(9, "output_static('%s')  -- NOT FOUND --\n", what);
-               hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
-               hprintf("Content-Type: text/plain\r\n");
-               wprintf("Cannot open %s: %s\r\n", what, strerror(errno));
-               end_burst();
-       } else {
-               len = strlen (what);
-               content_type = GuessMimeByFilename(what, len);
-
-               if (fstat(fd, &statbuf) == -1) {
-                       lprintf(9, "output_static('%s')  -- FSTAT FAILED --\n", what);
+               syslog(LOG_INFO, "output_static('%s') [%s]  -- NOT FOUND --\n", what, ChrPtr(WC->Hdr->this_page));
+               if (strstr(content_type, "image/") != NULL)
+               {
+                       output_error_pic("the file you requsted is gone.", strerror(errno));
+               }
+               else
+               {
                        hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
                        hprintf("Content-Type: text/plain\r\n");
-                       wprintf("Cannot fstat %s: %s\n", what, strerror(errno));
+                       begin_burst();
+                       wc_printf("Cannot open %s: %s\r\n", what, strerror(errno));
                        end_burst();
+               }
+       } else {
+               if (fstat(fd, &statbuf) == -1) {
+                       syslog(LOG_INFO, "output_static('%s')  -- FSTAT FAILED --\n", what);
+                       if (strstr(content_type, "image/") != NULL)
+                       {
+                               output_error_pic("Stat failed!", strerror(errno));
+                       }
+                       else
+                       {
+                               hprintf("HTTP/1.1 404 %s\r\n", strerror(errno));
+                               hprintf("Content-Type: text/plain\r\n");
+                               begin_burst();
+                               wc_printf("Cannot fstat %s: %s\n", what, strerror(errno));
+                               end_burst();
+                       }
+                       if (fd > 0) close(fd);
                        return;
                }
 
-               count = 0;
                bytes = statbuf.st_size;
 
                if (StrBufReadBLOB(WC->WBuf, &fd, 1, bytes, &Err) < 0)
                {
                        if (fd > 0) close(fd);
-                       lprintf(9, "output_static('%s')  -- FREAD FAILED (%s) --\n", what, strerror(errno));
+                       syslog(LOG_INFO, "output_static('%s')  -- FREAD FAILED (%s) --\n", what, strerror(errno));
                                hprintf("HTTP/1.1 500 internal server error \r\n");
                                hprintf("Content-Type: text/plain\r\n");
                                end_burst();
@@ -138,76 +140,77 @@ void output_static(const char *what)
 
 
                close(fd);
-#ifndef TECH_PREVIEW
-               lprintf(9, "output_static('%s')  %s\n", what, content_type);
-#endif
-               http_transmit_thing(content_type, 1);
+               http_transmit_thing(content_type, 2);
        }
        if (yesbstr("force_close_session")) {
                end_webcit_session();
        }
 }
 
-       /* TODO: integrate this into the static startup logic
-
-        * While we're at it, gracefully handle requests for the
-        * robots.txt and favicon.ico files.
-        * /
-       if ((StrLength(ReqLine) >= 11) &&
-           !strncasecmp(ChrPtr(ReqLine), "/robots.txt", 11)) {
-               StrBufPlain(ReqLine, 
-                           HKEY("/static/robots.txt"
-                                "?force_close_session=yes HTTP/1.1"));
-               Hdr.eReqType = eGET;
-       }
-       else if ((StrLength(ReqLine) >= 11) &&
-                !strncasecmp(ChrPtr(ReqLine), "/favicon.ico", 12)) {
-               StrBufPlain(ReqLine, HKEY("/static/favicon.ico"));
-               Hdr.eReqType = eGET;
-       }
-
-*/
-
-
-
 
 int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
 {
        char dirname[PATH_MAX];
        char reldir[PATH_MAX];
-       StrBuf *FileName;
-       StrBuf *Tag;
-       StrBuf *Dir;
-       StrBuf *WebDir;
-       StrBuf *OneWebName;
+       StrBuf *FileName = NULL;
+       StrBuf *Dir = NULL;
+       StrBuf *WebDir = NULL;
+       StrBuf *OneWebName = NULL;
        DIR *filedir = NULL;
-       struct dirent d;
+       struct dirent *d;
        struct dirent *filedir_entry;
-       int d_namelen;
-       int d_without_ext;
+       int d_type = 0;
+        int d_namelen;
+       int istoplevel;
                
-       Dir = NewStrBufPlain(DirName, -1);
-       WebDir = NewStrBufPlain(RelDir, -1);
-       OneWebName = NewStrBuf();
+       if (IsEmptyStr(DirName))
+       {
+               return 0;
+       }
+
        filedir = opendir (DirName);
-       if (filedir == NULL) {
-               FreeStrBuf(&Dir);
+       if (filedir == NULL)
+       {
                return 0;
        }
 
-       FileName = NewStrBuf();
-       Tag = NewStrBuf();
-       while ((readdir_r(filedir, &d, &filedir_entry) == 0) &&
+       d = (struct dirent *)malloc(offsetof(struct dirent, d_name) + PATH_MAX + 1);
+       if (d == NULL)
+       {
+               closedir(filedir);
+               return 0;
+       }
+
+       Dir = NewStrBufPlain(DirName, -1);
+       WebDir = NewStrBufPlain(RelDir, -1);
+       istoplevel = IsEmptyStr(RelDir);
+       OneWebName = NewStrBuf();
+
+       while ((readdir_r(filedir, d, &filedir_entry) == 0) &&
               (filedir_entry != NULL))
        {
-               char *PStart;
-#ifdef _DIRENT_HAVE_D_NAMELEN
-               d_namelen = filedir_entry->d_namelen;
+#ifdef _DIRENT_HAVE_D_NAMLEN
+               d_namelen = filedir_entry->d_namlen;
+
 #else
                d_namelen = strlen(filedir_entry->d_name);
 #endif
-               d_without_ext = d_namelen;
 
+#ifdef _DIRENT_HAVE_D_TYPE
+               d_type = filedir_entry->d_type;
+#else
+
+#ifndef DT_UNKNOWN
+#define DT_UNKNOWN     0
+#define DT_DIR         4
+#define DT_REG         8
+#define DT_LNK         10
+
+#define IFTODT(mode)   (((mode) & 0170000) >> 12)
+#define DTTOIF(dirtype)        ((dirtype) << 12)
+#endif
+               d_type = DT_UNKNOWN;
+#endif
                if ((d_namelen > 1) && filedir_entry->d_name[d_namelen - 1] == '~')
                        continue; /* Ignore backup files... */
 
@@ -220,22 +223,37 @@ int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
                    (filedir_entry->d_name[1] == '.'))
                        continue;
 
-               switch (filedir_entry->d_type)
+               if (d_type == DT_UNKNOWN) {
+                       struct stat s;
+                       char path[PATH_MAX];
+                       snprintf(path, PATH_MAX, "%s/%s", 
+                               DirName, filedir_entry->d_name);
+                       if (lstat(path, &s) == 0) {
+                               d_type = IFTODT(s.st_mode);
+                       }
+               }
+
+               switch (d_type)
                {
                case DT_DIR:
                        /* Skip directories we are not interested in... */
                        if ((strcmp(filedir_entry->d_name, ".svn") == 0) ||
                            (strcmp(filedir_entry->d_name, "t") == 0))
                                break;
-                       snprintf(dirname, PATH_MAX, "%s/%s", 
+                       snprintf(dirname, PATH_MAX, "%s/%s/", 
                                 DirName, filedir_entry->d_name);
-                       snprintf(reldir, PATH_MAX, "%s/%s", 
-                                RelDir, filedir_entry->d_name);
+                       if (istoplevel)
+                               snprintf(reldir, PATH_MAX, "%s/", 
+                                        filedir_entry->d_name);
+                       else
+                               snprintf(reldir, PATH_MAX, "%s/%s/", 
+                                        RelDir, filedir_entry->d_name);
+                       StripSlashes(dirname, 1);
+                       StripSlashes(reldir, 1);
                        LoadStaticDir(dirname, DirList, reldir);                                 
                        break;
                case DT_LNK: /* TODO: check whether its a file or a directory */
                case DT_REG:
-                       PStart = filedir_entry->d_name;
                        FileName = NewStrBufDup(Dir);
                        if (ChrPtr(FileName) [ StrLength(FileName) - 1] != '/')
                                StrBufAppendBufPlain(FileName, "/", 1, 0);
@@ -244,12 +262,12 @@ int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
                        FlushStrBuf(OneWebName);
                        StrBufAppendBuf(OneWebName, WebDir, 0);
                        if ((StrLength(OneWebName) != 0) && 
-                           (ChrPtr(OneWebName) [ StrLength(OneWebName)] != '/'))
+                           (ChrPtr(OneWebName) [ StrLength(OneWebName) - 1] != '/'))
                                StrBufAppendBufPlain(OneWebName, "/", 1, 0);
                        StrBufAppendBufPlain(OneWebName, filedir_entry->d_name, d_namelen, 0);
 
                        Put(DirList, SKEY(OneWebName), FileName, HFreeStrBuf);
-                       printf("[%s | %s]  \n", ChrPtr(OneWebName), ChrPtr(FileName));
+                       /* syslog(LOG_DEBUG, "[%s | %s]\n", ChrPtr(OneWebName), ChrPtr(FileName)); */
                        break;
                default:
                        break;
@@ -257,29 +275,56 @@ int LoadStaticDir(const char *DirName, HashList *DirList, const char *RelDir)
 
 
        }
+       free(d);
        closedir(filedir);
-       FreeStrBuf(&FileName);
-       FreeStrBuf(&Tag);
        FreeStrBuf(&Dir);
+       FreeStrBuf(&WebDir);
        FreeStrBuf(&OneWebName);
        return 1;
 }
 
 
+void output_flat_static(void)
+{
+       wcsession *WCC = WC;
+       void *vFile;
+       StrBuf *File;
+
+       if (WCC->Hdr->HR.Handler == NULL)
+               return;
+       if (GetHash(StaticFilemappings[0], SKEY(WCC->Hdr->HR.Handler->Name), &vFile) &&
+           (vFile != NULL))
+       {
+               File = (StrBuf*) vFile;
+               output_static(ChrPtr(File));
+       }
+}
+
 void output_static_safe(HashList *DirList)
 {
        wcsession *WCC = WC;
        void *vFile;
        StrBuf *File;
+       const char *MimeType;
 
-       if (GetHash(DirList, SKEY(WCC->Hdr->ReqLine), &vFile) &&
+       if (GetHash(DirList, SKEY(WCC->Hdr->HR.ReqLine), &vFile) &&
            (vFile != NULL))
        {
                File = (StrBuf*) vFile;
-               output_static(ChrPtr(vFile));
+               output_static(ChrPtr(File));
        }
        else {
-///TODO: detect image & output blank image
+               syslog(LOG_INFO, "output_static_safe() file %s not found. \n", 
+                       ChrPtr(WCC->Hdr->HR.ReqLine));
+               MimeType =  GuessMimeByFilename(SKEY(WCC->Hdr->HR.ReqLine));
+               if (strstr(MimeType, "image/") != NULL)
+               {
+                       output_error_pic("the file you requested isn't known to our cache", "maybe reload webcit?");
+               }
+               else
+               {                   
+                       do_404();
+               }
        }
 }
 void output_static_0(void)
@@ -296,9 +341,43 @@ void output_static_2(void)
 }
 void output_static_3(void)
 {
-       output_static_safe(StaticFilemappings[3]);
+       output_static_safe(StaticFilemappings[4]);
 }
 
+
+/*
+ * robots.txt
+ */
+void robots_txt(void) {
+       output_headers(0, 0, 0, 0, 0, 0);
+
+       hprintf("Content-type: text/plain\r\n"
+               "Server: %s\r\n"
+               "Connection: close\r\n",
+               PACKAGE_STRING);
+       begin_burst();
+
+       wc_printf("User-agent: *\r\n"
+               "Disallow: /printmsg\r\n"
+               "Disallow: /msgheaders\r\n"
+               "Disallow: /groupdav\r\n"
+               "Disallow: /do_template\r\n"
+               "Disallow: /static\r\n"
+               "Disallow: /display_page\r\n"
+               "Disallow: /readnew\r\n"
+               "Disallow: /display_enter\r\n"
+               "Disallow: /skip\r\n"
+               "Disallow: /ungoto\r\n"
+               "Sitemap: %s/sitemap.xml\r\n"
+               "\r\n"
+               ,
+               ChrPtr(site_prefix)
+       );
+
+       wDumpContent(0);
+}
+
+
 void 
 ServerStartModule_STATIC
 (void)
@@ -307,6 +386,7 @@ ServerStartModule_STATIC
        StaticFilemappings[1] = NewHash(1, NULL);
        StaticFilemappings[2] = NewHash(1, NULL);
        StaticFilemappings[3] = NewHash(1, NULL);
+       StaticFilemappings[4] = NewHash(1, NULL);
 }
 void 
 ServerShutdownModule_STATIC
@@ -316,6 +396,7 @@ ServerShutdownModule_STATIC
        DeleteHash(&StaticFilemappings[1]);
        DeleteHash(&StaticFilemappings[2]);
        DeleteHash(&StaticFilemappings[3]);
+       DeleteHash(&StaticFilemappings[4]);
 }
 
 
@@ -327,12 +408,13 @@ InitModule_STATIC
        LoadStaticDir(static_dirs[1], StaticFilemappings[1], "");
        LoadStaticDir(static_dirs[2], StaticFilemappings[2], "");
        LoadStaticDir(static_dirs[3], StaticFilemappings[3], "");
-
-       WebcitAddUrlHandler(HKEY("robots.txt"), output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
-       WebcitAddUrlHandler(HKEY("favicon.ico"), output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
-       WebcitAddUrlHandler(HKEY("static"), output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
-       WebcitAddUrlHandler(HKEY("static.local"), output_static_1, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
-       WebcitAddUrlHandler(HKEY("tinymce"), output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC);
-
-
+       LoadStaticDir(static_dirs[4], StaticFilemappings[4], "");
+
+       WebcitAddUrlHandler(HKEY("robots.txt"), "", 0, robots_txt, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
+       WebcitAddUrlHandler(HKEY("favicon.ico"), "", 0, output_flat_static, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
+       WebcitAddUrlHandler(HKEY("static"), "", 0, output_static_0, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
+       WebcitAddUrlHandler(HKEY("static.local"), "", 0, output_static_1, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
+       WebcitAddUrlHandler(HKEY("tinymce"), "", 0, output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
+       WebcitAddUrlHandler(HKEY("tiny_mce"), "", 0, output_static_2, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
+       WebcitAddUrlHandler(HKEY("epiceditor"), "", 0, output_static_3, ANONYMOUS|COOKIEUNNEEDED|ISSTATIC|LOGCHATTY);
 }