Integrated the DKIM signer into serv_smtpclient, but disabled it
[citadel.git] / webcit / downloads.c
index f2653746ab1ed4335c32906df94d5b0b8fa49a07..9b7dde993c47f254174d3040a2540292ece34b3a 100644 (file)
@@ -1,22 +1,73 @@
 /*
- * $Id$
+ * Copyright (c) 1996-2012 by the citadel.org team
+ *
+ * This program is open source software.  You can redistribute it and/or
+ * modify it under the terms of the GNU General Public License, version 3.
+ *
+ * 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.
  */
+
 #include "webcit.h"
-#include "webserver.h"
+
+
+CtxType CTX_FILELIST = CTX_NONE;
+
+extern void output_static(const char* What);
+
+extern char* static_dirs[];
 
 typedef struct _FileListStruct {
-       char Filename[256];
-       int FilenameLen;
+       StrBuf *Filename;
        long FileSize;
-       char MimeType[64];
-       int MimeTypeLen;
-       char Comment[512];
-       int CommentLen;
+       StrBuf *MimeType;
+       StrBuf *Comment;
        int IsPic;
        int Sequence;
-}FileListStruct;
+} FileListStruct;
+
+void FreeFiles(void *vFile)
+{
+       FileListStruct *F = (FileListStruct*) vFile;
+       FreeStrBuf(&F->Filename);
+       FreeStrBuf(&F->MimeType);
+       FreeStrBuf(&F->Comment);
+       free(F);
+}
+
+/* -------------------------------------------------------------------------------- */
+void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
+{
+       FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
+       StrBufAppendTemplate(Target, TP, F->Filename, 0);
+}
+void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
+{
+       FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
+       StrBufAppendPrintf(Target, "%ld", F->FileSize);
+}
+void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
+{
+       FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
+       StrBufAppendTemplate(Target, TP, F->MimeType, 0);
+}
+void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
+{
+       FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
+       StrBufAppendTemplate(Target, TP, F->Comment, 0);
+}
+
+/* -------------------------------------------------------------------------------- */
 
+int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
+{
+       FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
+       return F->IsPic;
+}
 
+/* -------------------------------------------------------------------------------- */
 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
 {
        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
@@ -24,7 +75,7 @@ int CompareFilelistByMime(const void *vFile1, const void *vFile2)
 
        if (File1->IsPic != File2->IsPic)
                return File1->IsPic > File2->IsPic;
-       return strcasecmp(File1->MimeType, File2->MimeType);
+       return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
 }
 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
 {
@@ -32,9 +83,45 @@ int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
        if (File1->IsPic != File2->IsPic)
                return File1->IsPic < File2->IsPic;
-       return strcasecmp(File2->MimeType, File1->MimeType);
+       return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
+}
+int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
+{
+       FileListStruct *File1 = (FileListStruct*) vFile1;
+       FileListStruct *File2 = (FileListStruct*) vFile2;
+
+       if (File1->IsPic != File2->IsPic)
+               return File1->IsPic > File2->IsPic;
+       return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
 }
 
+
+int CompareFilelistByName(const void *vFile1, const void *vFile2)
+{
+       FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
+       FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
+
+       if (File1->IsPic != File2->IsPic)
+               return File1->IsPic > File2->IsPic;
+       return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
+}
+int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
+{
+       FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
+       FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
+       if (File1->IsPic != File2->IsPic)
+               return File1->IsPic < File2->IsPic;
+       return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
+}
+int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
+{
+       FileListStruct *File1 = (FileListStruct*) vFile1;
+       FileListStruct *File2 = (FileListStruct*) vFile2;
+
+       return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
+}
+
+
 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
 {
        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
@@ -43,7 +130,6 @@ int CompareFilelistBySize(const void *vFile1, const void *vFile2)
                return 0;
        return (File1->FileSize > File2->FileSize);
 }
-
 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
 {
        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
@@ -52,317 +138,103 @@ int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
                return 0;
        return (File1->FileSize < File2->FileSize);
 }
+int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
+{
+       return 0;
+}
+
 
 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
 {
        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
-       return strcasecmp(File1->Comment, File2->Comment);
+       return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
 }
 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
 {
        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
-       return strcasecmp(File2->Comment, File1->Comment);
+       return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
+}
+int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
+{
+       FileListStruct *File1 = (FileListStruct*) vFile1;
+       FileListStruct *File2 = (FileListStruct*) vFile2;
+       return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
 }
 
+
 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
 {
        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
        return (File2->Sequence >  File1->Sequence);
 }
+int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
+{
+       return 0;
+}
 
-HashList* LoadFileList(int *HavePic)
+/* -------------------------------------------------------------------------------- */
+HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
 {
        FileListStruct *Entry;
+       StrBuf *Buf;
        HashList *Files;
-       int HavePics = 0;
-       int Order;
+       int Done = 0;
        int sequence = 0;
        char buf[1024];
+       CompareFunc SortIt;
+       int HavePic = 0;
+       WCTemplputParams SubTP;
 
+       memset(&SubTP, 0, sizeof(WCTemplputParams));
        serv_puts("RDIR");
        serv_getln(buf, sizeof buf);
-       if (buf[0] == '1') {
-               Files = NewHash(1, NULL);
-               while (serv_getln(buf, sizeof buf), strcmp(buf, "000"))
-               {
-                       Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
-
-                       Entry->FilenameLen = extract_token(
-                               Entry->Filename, buf, 0, '|', 
-                               sizeof(Entry->Filename));
-                       Entry->FileSize = extract_long(buf, 1);
-                       Entry->MimeTypeLen = extract_token(
-                               Entry->MimeType, buf, 2, '|', 
-                               sizeof(Entry->MimeType));
-                       Entry->CommentLen = extract_token(
-                               Entry->Comment,  buf, 3, '|', 
-                               sizeof(Entry->Comment));
-                       
-                       Entry->Sequence = sequence++;
-                       Entry->IsPic = (strstr(Entry->MimeType, "image") != NULL);
-                       if (!HavePics && Entry->IsPic) {
-                               HavePics = 1;
-                               *HavePic = 1;
-                       }
-                       Put(Files, Entry->Filename, 
-                           Entry->FilenameLen, 
-                           Entry, NULL);
-               }
-               Order = ibstr("SortOrder");
-               switch (ibstr("SortBy")){
-               case 1: /*NAME*/
-                       SortByHashKey(Files,Order);
-                       break;
-               case 2: /* SIZE*/
-                       SortByPayload(Files, (Order)? 
-                                     CompareFilelistBySize:
-                                     CompareFilelistBySizeRev);
-                       break;
-               case 3: /*MIME*/
-                       SortByPayload(Files, (Order)? 
-                                     CompareFilelistByMime:
-                                     CompareFilelistByMimeRev);
-                       break;
-               case 4: /*COMM*/
-                       SortByPayload(Files, (Order)? 
-                                     CompareFilelistByComment:
-                                     CompareFilelistByCommentRev);
-                       break;
-               default:
-                       SortByPayload(Files, CompareFilelistBySequence);
-               }
-               return Files;
-       }
-       else
-               return NULL;
-}
+       if (buf[0] != '1') return NULL;
 
-void FilePrintEntry(const char *FileName, void *vFile, int odd)
-{
-       FileListStruct *File = (FileListStruct*) vFile;
-
-       wprintf("<tr bgcolor=\"#%s\">", (odd ? "DDDDDD" : "FFFFFF"));
-       wprintf("<td>"
-               "<a href=\"download_file/");
-       urlescputs(File->Filename);
-       wprintf("\"><img src=\"display_mime_icon?type=%s\" border=0 align=middle>\n", 
-               File->MimeType);
-       escputs(File->Filename);        wprintf("</a></td>");
-       wprintf("<td>%ld</td>", File->FileSize);
-       wprintf("<td>");        escputs(File->MimeType);        wprintf("</td>");
-       wprintf("<td>");        escputs(File->Comment); wprintf("</td>");
-       wprintf("</tr>\n");
-}
-
-void FilePrintTransition(void *vFile1, void *vFile2, int odd)
-{
-       FileListStruct *File1 = (FileListStruct*) vFile1;
-       FileListStruct *File2 = (FileListStruct*) vFile2;
-       char StartChar[2] = "\0\0";
-       char *SectionName;
-
-       switch (ibstr("SortBy")){
-       case 1: /*NAME*/
-               if ((File2 != NULL) && 
-                   ((File1 == NULL) ||
-                    (File1->Filename[0] != File2->Filename[0]))) {
-                       StartChar[0] = File2->Filename[0];
-                       SectionName = StartChar;
+       Buf = NewStrBuf();             
+       Files = NewHash(1, NULL);
+       while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
+               if ( (StrLength(Buf)==3) && 
+                   !strcmp(ChrPtr(Buf), "000")) 
+               {
+                       Done = 1;
+                       continue;
                }
-               else return;
-               break;
-       case 2: /* SIZE*/
-               return;
-       case 3: /*MIME*/
-               return; /*TODO*/
-               break;
-       case 4: /*COMM*/
-               return;
-       default:
-               return;
-       }
-
-       wprintf("<tr bgcolor=\"#%s\"><th colspan = 4>%s</th></tr>", 
-               (odd ? "DDDDDD" : "FFFFFF"),  SectionName);
-}
-
-
-void display_room_directory(void)
-{
-       char title[256];
-       int havepics = 0;
-       HashList *Files;
-       int Order;
-       int SortRow;
-       int i;
-
-       long SortDirections[5] = {2,2,2,2,2};
-       const char* SortIcons[3] = {
-               "static/up_pointer.gif",
-               "static/down_pointer.gif",
-               "static/sort_none.gif"};
-       char *RowNames[5] = {"",
-                           _("Filename"),
-                           _("Size"),
-                           _("Content"),
-                           _("Description")};
-
-       Files = LoadFileList (&havepics);
-       output_headers(1, 1, 2, 0, 0, 0);
-       wprintf("<div id=\"banner\">\n");
-       wprintf("<h1>");
-       snprintf(title, sizeof title, _("Files available for download in %s"), WC->wc_roomname);
-       escputs(title);
-       wprintf("</h1>");
-       wprintf("</div>\n");
-
-       wprintf("<div id=\"content\" class=\"service\">\n");
-
-       wprintf("<div class=\"fix_scrollbar_bug\">"
-               "<table class=\"downloads_background\"><tr><td>\n");
-
-
-       Order = ibstr("SortOrder");
-       if (!havebstr("SortOrder") || Order > 2)
-               Order = 2; /* <- Unsorted... */
-       SortRow = ibstr("SortBy");
-
-       SortDirections[SortRow] = Order;
-
-       wprintf("<tr>\n");
-       for (i = 1; i < 5; i++) {
-               switch (SortDirections[i]) {
-               default:
-               case 0:
-                       Order = 2;
-                       break;
-               case 1:
-                       Order = 0;
-                       break;
-               case 2:
-                       Order = 1;
-                       break;
-               }                       
-
-               wprintf("  <th>%s \n"
-                       "      <a href=\"display_room_directory?SortOrder=%d&SortBy=%d\"> \n"
-                       "       <img src=\"%s\" border=\"0\"></a>\n"
-                       "  </th>\n",
-                       RowNames[i],
-                       Order, i,
-                       SortIcons[SortDirections[i]]
-                       );
-
-       }
-       wprintf("</tr>\n");
-//<th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n",
-       //);
 
-       if (Files != NULL) {
-               PrintHash(Files, FilePrintTransition, FilePrintEntry);
-               DeleteHash(&Files);
-       }
-       wprintf("</table>\n");
+               Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
+               Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
+               Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
+               Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
 
-       /** Now offer the ability to upload files... */
-       if (WC->room_flags & QR_UPLOAD)
-       {
-               wprintf("<hr>");
-               wprintf("<form "
-                       "enctype=\"multipart/form-data\" "
-                       "method=\"POST\" "
-                       "accept-charset=\"UTF-8\" "
-                       "action=\"upload_file\" "
-                       "name=\"upload_file_form\""
-                       ">\n"
-               );
-               wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
-
-               wprintf(_("Upload a file:"));
-               wprintf("&nbsp;<input NAME=\"filename\" SIZE=16 TYPE=\"file\">&nbsp;\n");
-               wprintf(_("Description:"));
-               wprintf("&nbsp;<input type=\"text\" name=\"description\" maxlength=\"64\" size=\"64\">&nbsp;");
-               wprintf("<input type=\"submit\" name=\"attach_button\" value=\"%s\">\n", _("Upload"));
-
-               wprintf("</form>\n");
-       }
-
-       wprintf("</div>\n");
-       if (havepics)
-               wprintf("<div class=\"buttons\"><a href=\"display_pictureview&frame=1\">%s</a></div>", _("Slideshow"));
-       wDumpContent(1);
-}
+               Entry->Sequence = sequence++;
 
+               StrBufExtract_token(Entry->Filename, Buf, 0, '|');
+               Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
+               StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
+               StrBufExtract_token(Entry->Comment, Buf, 3, '|');
 
-void display_pictureview(void)
-{
-       char buf[1024];
-       char filename[256];
-       char filesize[256];
-       char mimetype[64];
-       char comment[512];
-       char title[256];
-       int n = 0;
-               
 
-       if (lbstr("frame") == 1) {
 
-               output_headers(1, 1, 2, 0, 0, 0);
-               wprintf("<div id=\"banner\">\n");
-               wprintf("<h1>");
-               snprintf(title, sizeof title, _("Pictures in %s"), WC->wc_roomname);
-               escputs(title);
-               wprintf("</h1>");
-               wprintf("</div>\n");
-               
-               wprintf("<div id=\"content\" class=\"service\">\n");
-
-               wprintf("<div class=\"fix_scrollbar_bug\">"
-                       "<table class=\"downloads_background\"><tr><td>\n");
-
-
-
-               wprintf("<script type=\"text/javascript\" language=\"JavaScript\" > \nvar fadeimages=new Array()\n");
-
-               serv_puts("RDIR");
-               serv_getln(buf, sizeof buf);
-               if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000"))  {
-                               extract_token(filename, buf, 0, '|', sizeof filename);
-                               extract_token(filesize, buf, 1, '|', sizeof filesize);
-                               extract_token(mimetype, buf, 2, '|', sizeof mimetype);
-                               extract_token(comment,  buf, 3, '|', sizeof comment);
-                               if (strstr(mimetype, "image") != NULL) {
-                                       wprintf("fadeimages[%d]=[\"download_file/", n);
-                                       escputs(filename);
-                                       wprintf("\", \"\", \"\"]\n");
-
-                                       /*
-                                                          //mimetype);
-                                          escputs(filename);   wprintf("</a></td>");
-                                          wprintf("<td>");     escputs(filesize);      wprintf("</td>");
-                                          wprintf("<td>");     escputs(mimetype);      wprintf("</td>");
-                                          wprintf("<td>");     escputs(comment);       wprintf("</td>");
-                                          wprintf("</tr>\n");
-                                       */
-                                       n++;
-                               }
-                       }
-               wprintf("</script>\n");
-               wprintf("<tr><td><script type=\"text/javascript\" src=\"static/fadeshow.js\">\n</script>\n");
-               wprintf("<script type=\"text/javascript\" >\n");
-               wprintf("new fadeshow(fadeimages, 500, 400, 0, 3000, 1, \"R\");\n");
-               wprintf("</script></td><th>\n");
-               wprintf("</div>\n");
+               Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
+               if (Entry->IsPic) {
+                       HavePic = 1;
+               }
+               Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
        }
-       wDumpContent(1);
-
-
+       if (HavePic)
+               putbstr("__HAVE_PIC", NewStrBufPlain(HKEY("1")));
+       SubTP.Filter.ContextType = CTX_FILELIST;
+       SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
+       if (SortIt != NULL)
+               SortByPayload(Files, SortIt);
+       else 
+               SortByPayload(Files, CompareFilelistBySequence);
+       FreeStrBuf(&Buf);
+       return Files;
 }
 
-extern char* static_dirs[];
 void display_mime_icon(void)
 {
        char FileBuf[SIZ];
@@ -374,69 +246,98 @@ void display_mime_icon(void)
        FileName = GetIconFilename(MimeType, tlen);
 
        if (FileName == NULL)
-               snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/diskette_24x.gif");
+               snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/webcit_icons/essen/16x16/file.png");
        else
                snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
        output_static(FileBuf);
-
 }
 
 void download_file(void)
 {
-       char buf[256];
+       wcsession *WCC = WC;
+       StrBuf *Buf;
        off_t bytes;
-       char content_type[256];
-       char *content = NULL;
+       StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
 
        /* Setting to nonzero forces a MIME type of application/octet-stream */
        int force_download = 1;
        
-       safestrncpy(buf, ChrPtr(WC->UrlFragment1), sizeof buf);
-       unescape_input(buf);
-       serv_printf("OPEN %s", buf);
-       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");
-               }
-               else {
-                       extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
-               }
-               output_headers(0, 0, 0, 0, 0, 0);
-               read_server_binary(content, bytes);
+       Buf = NewStrBuf();
+       StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
+       StrBufUnescape(Buf, 1);
+       serv_printf("OPEN %s", ChrPtr(Buf));
+       StrBuf_ServGetln(Buf);
+       if (GetServerStatus(Buf, NULL) == 2) {
+               StrBufCutLeft(Buf, 4);
+               bytes = StrBufExtract_long(Buf, 0, '|');
+               StrBufExtract_token(ContentType, Buf, 3, '|');
+
+               CheckGZipCompressionAllowed (SKEY(ContentType));
+               if (force_download)
+                       FlushStrBuf(ContentType);
+
+               serv_read_binary_to_http(ContentType, bytes, 0, 0);
                serv_puts("CLOS");
-               serv_getln(buf, sizeof buf);
-               http_transmit_thing(content, bytes, content_type, 0);
-               free(content);
+               StrBuf_ServGetln(Buf);
        } else {
-               wprintf("HTTP/1.1 404 %s\n", &buf[4]);
+               StrBufCutLeft(Buf, 4);
+               hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
                output_headers(0, 0, 0, 0, 0, 0);
-               wprintf("Content-Type: text/plain\r\n");
-               wprintf("\r\n");
-               wprintf(_("An error occurred while retrieving this file: %s\n"), &buf[4]);
+               hprintf("Content-Type: text/plain\r\n");
+               wc_printf(_("An error occurred while retrieving this file: %s\n"), 
+                       ChrPtr(Buf));
+               end_burst();
        }
+       FreeStrBuf(&ContentType);
+       FreeStrBuf(&Buf);
+}
+
+
+
+void delete_file(void)
+{
+       const StrBuf *MimeType;
+       StrBuf *Line;
+       char buf[256];
+       
+       safestrncpy(buf, bstr("file"), sizeof buf);
+       unescape_input(buf);
+       serv_printf("DELF %s", buf);
 
+       StrBuf_ServGetln(Line);
+       GetServerStatusMsg(Line, NULL, 1, 0);
+
+       MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
+       http_transmit_thing(ChrPtr(MimeType), 0);
+       FreeStrBuf(&Line);
 }
 
 
 
 void upload_file(void)
 {
+       const StrBuf *RetMimeType;
        const char *MimeType;
-       char buf[1024];
-       size_t bytes_transmitted = 0;
-       size_t blocksize;
-       struct wcsession *WCC = WC;     /* stack this for faster access (WC is a function) */
-
-       MimeType = GuessMimeType(WCC->upload, WCC->upload_length); 
-       serv_printf("UOPN %s|%s|%s", WCC->upload_filename, MimeType, bstr("description"));
-       serv_getln(buf, sizeof buf);
-       if (buf[0] != '2')
-       {
-               strcpy(WCC->ImportantMessage, &buf[4]);
-               display_room_directory();
+       StrBuf *Line;
+       long bytes_transmitted = 0;
+       long blocksize;
+       const StrBuf *Desc;
+       wcsession *WCC = WC;     /* stack this for faster access (WC is a function) */
+
+       MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length); 
+
+               Desc = sbstr("description");
+
+       serv_printf("UOPN %s|%s|%s", 
+                   ChrPtr(WCC->upload_filename), 
+                   MimeType, 
+                   ChrPtr(Desc));
+       Line = NewStrBuf();
+       StrBuf_ServGetln(Line);
+       if (GetServerStatusMsg(Line, NULL, 1, 2) != 2) {
+               RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
+               http_transmit_thing(ChrPtr(RetMimeType), 0);
+               FreeStrBuf(&Line);
                return;
        }
 
@@ -447,28 +348,129 @@ void upload_file(void)
                {
                        blocksize = (WCC->upload_length - bytes_transmitted);
                }
-               serv_printf("WRIT %d", blocksize);
-               serv_getln(buf, sizeof buf);
-               if (buf[0] == '7')
-               {
-                       blocksize = atoi(&buf[4]);
-                       serv_write(&WCC->upload[bytes_transmitted], blocksize);
+               serv_printf("WRIT %ld", blocksize);
+               StrBuf_ServGetln(Line);
+               if (GetServerStatusMsg(Line, NULL, 0, 0) == 7) {
+                       blocksize = atoi(ChrPtr(Line) + 4);
+                       serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
                        bytes_transmitted += blocksize;
                }
+               else
+                       break;
        }
 
        serv_puts("UCLS 1");
-       serv_getln(buf, sizeof buf);
-       strcpy(WCC->ImportantMessage, &buf[4]);
-       display_room_directory();
+       StrBuf_ServGetln(Line);
+       GetServerStatusMsg(Line, NULL, 1, 0);
+       RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
+       http_transmit_thing(ChrPtr(RetMimeType), 0);
+       FreeStrBuf(&Line);
+}
+
+
+
+/*
+ * When the browser requests an image file from the Citadel server,
+ * this function is called to transmit it.
+ */
+void output_image(void)
+{
+       StrBuf *Buf;
+       wcsession *WCC = WC;
+       off_t bytes;
+       const char *MimeType;
+       
+       Buf = NewStrBuf();
+       serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
+       StrBuf_ServGetln(Buf);
+       if (GetServerStatus(Buf, NULL) == 2) {
+               int rc;
+               StrBufCutLeft(Buf, 4);
+               bytes = StrBufExtract_long(Buf, 0, '|');
+
+               /** Read it from the server */
+               
+               rc = serv_read_binary(WCC->WBuf, bytes, Buf);
+               serv_puts("CLOS");
+               StrBuf_ServGetln(Buf);
+               
+               if (rc > 0) {
+                       MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
+                       /** Write it to the browser */
+                       if (!IsEmptyStr(MimeType))
+                       {
+                               CheckGZipCompressionAllowed (MimeType, strlen(MimeType));
+                               http_transmit_thing(MimeType, 0);
+                               FreeStrBuf(&Buf);
+                               return;
+                       }
+               }
+               /* hm... unknown mimetype? fallback to blank gif */
+       }
+       else { 
+               syslog(LOG_DEBUG, "OIMG failed: %s", ChrPtr(Buf));
+       }
+
+       
+       /*
+        * Instead of an ugly 404, send a 1x1 transparent GIF
+        * when there's no such image on the server display blank
+        */
+       output_static(NULL);
+       FreeStrBuf(&Buf);
 }
 
 void 
 InitModule_DOWNLOAD
 (void)
 {
-       WebcitAddUrlHandler(HKEY("display_room_directory"), display_room_directory, 0);
-       WebcitAddUrlHandler(HKEY("display_pictureview"), display_pictureview, 0);
-       WebcitAddUrlHandler(HKEY("download_file"), download_file, NEED_URL);
-       WebcitAddUrlHandler(HKEY("upload_file"), upload_file, 0);
+       RegisterCTX(CTX_FILELIST);
+
+       RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
+                        NULL, DeleteHash, CTX_FILELIST, CTX_NONE, 
+                        IT_FLAG_DETECT_GROUPCHANGE);
+
+       RegisterSortFunc(HKEY("filemime"),
+                        NULL, 0,
+                        CompareFilelistByMime,
+                        CompareFilelistByMimeRev,
+                        GroupchangeFilelistByMime,
+                        CTX_FILELIST);
+       RegisterSortFunc(HKEY("filename"),
+                        NULL, 0,
+                        CompareFilelistByName,
+                        CompareFilelistByNameRev,
+                        GroupchangeFilelistByName,
+                        CTX_FILELIST);
+       RegisterSortFunc(HKEY("filesize"),
+                        NULL, 0,
+                        CompareFilelistBySize,
+                        CompareFilelistBySizeRev,
+                        GroupchangeFilelistBySize,
+                        CTX_FILELIST);
+       RegisterSortFunc(HKEY("filesubject"),
+                        NULL, 0,
+                        CompareFilelistByComment,
+                        CompareFilelistByCommentRev,
+                        GroupchangeFilelistByComment,
+                        CTX_FILELIST);
+       RegisterSortFunc(HKEY("fileunsorted"),
+                        NULL, 0,
+                        CompareFilelistBySequence,
+                        CompareFilelistBySequence,
+                        GroupchangeFilelistBySequence,
+                        CTX_FILELIST);
+
+       RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
+       RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
+       RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
+       RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
+
+       RegisterConditional("COND:FILE:ISPIC", 0, Conditional_FILE_ISPIC, CTX_FILELIST);
+
+       WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
+       WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
+       WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
+       WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
+       WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);
 }