Back to index

webcit  8.12-dfsg
downloads.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1996-2012 by the citadel.org team
00003  *
00004  * This program is open source software.  You can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License, version 3.
00006  *
00007  * This program is distributed in the hope that it will be useful,
00008  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00009  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010  * GNU General Public License for more details.
00011  */
00012 
00013 #include "webcit.h"
00014 #include "webserver.h"
00015 
00016 extern void output_static(const char* What);
00017 
00018 extern char* static_dirs[];
00019 
00020 typedef struct _FileListStruct {
00021        StrBuf *Filename;
00022        long FileSize;
00023        StrBuf *MimeType;
00024        StrBuf *Comment;
00025        int IsPic;
00026        int Sequence;
00027 } FileListStruct;
00028 
00029 void FreeFiles(void *vFile)
00030 {
00031        FileListStruct *F = (FileListStruct*) vFile;
00032        FreeStrBuf(&F->Filename);
00033        FreeStrBuf(&F->MimeType);
00034        FreeStrBuf(&F->Comment);
00035        free(F);
00036 }
00037 
00038 /* -------------------------------------------------------------------------------- */
00039 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
00040 {
00041        FileListStruct *F = (FileListStruct*) CTX;
00042        StrBufAppendTemplate(Target, TP, F->Filename, 0);
00043 }
00044 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
00045 {
00046        FileListStruct *F = (FileListStruct*) CTX;
00047        StrBufAppendPrintf(Target, "%ld", F->FileSize);
00048 }
00049 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
00050 {
00051        FileListStruct *F = (FileListStruct*) CTX;
00052        StrBufAppendTemplate(Target, TP, F->MimeType, 0);
00053 }
00054 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
00055 {
00056        FileListStruct *F = (FileListStruct*) CTX;
00057        StrBufAppendTemplate(Target, TP, F->Comment, 0);
00058 }
00059 
00060 /* -------------------------------------------------------------------------------- */
00061 
00062 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
00063 {
00064        FileListStruct *F = (FileListStruct*) CTX;
00065        return F->IsPic;
00066 }
00067 
00068 /* -------------------------------------------------------------------------------- */
00069 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
00070 {
00071        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00072        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00073 
00074        if (File1->IsPic != File2->IsPic)
00075               return File1->IsPic > File2->IsPic;
00076        return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
00077 }
00078 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
00079 {
00080        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00081        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00082        if (File1->IsPic != File2->IsPic)
00083               return File1->IsPic < File2->IsPic;
00084        return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
00085 }
00086 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
00087 {
00088        FileListStruct *File1 = (FileListStruct*) vFile1;
00089        FileListStruct *File2 = (FileListStruct*) vFile2;
00090 
00091        if (File1->IsPic != File2->IsPic)
00092               return File1->IsPic > File2->IsPic;
00093        return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
00094 }
00095 
00096 
00097 int CompareFilelistByName(const void *vFile1, const void *vFile2)
00098 {
00099        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00100        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00101 
00102        if (File1->IsPic != File2->IsPic)
00103               return File1->IsPic > File2->IsPic;
00104        return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
00105 }
00106 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
00107 {
00108        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00109        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00110        if (File1->IsPic != File2->IsPic)
00111               return File1->IsPic < File2->IsPic;
00112        return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
00113 }
00114 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
00115 {
00116        FileListStruct *File1 = (FileListStruct*) vFile1;
00117        FileListStruct *File2 = (FileListStruct*) vFile2;
00118 
00119        return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
00120 }
00121 
00122 
00123 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
00124 {
00125        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00126        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00127        if (File1->FileSize == File2->FileSize)
00128               return 0;
00129        return (File1->FileSize > File2->FileSize);
00130 }
00131 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
00132 {
00133        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00134        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00135        if (File1->FileSize == File2->FileSize)
00136               return 0;
00137        return (File1->FileSize < File2->FileSize);
00138 }
00139 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
00140 {
00141        return 0;
00142 }
00143 
00144 
00145 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
00146 {
00147        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00148        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00149        return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
00150 }
00151 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
00152 {
00153        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00154        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00155        return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
00156 }
00157 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
00158 {
00159        FileListStruct *File1 = (FileListStruct*) vFile1;
00160        FileListStruct *File2 = (FileListStruct*) vFile2;
00161        return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
00162 }
00163 
00164 
00165 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
00166 {
00167        FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
00168        FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
00169        return (File2->Sequence >  File1->Sequence);
00170 }
00171 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
00172 {
00173        return 0;
00174 }
00175 
00176 /* -------------------------------------------------------------------------------- */
00177 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
00178 {
00179        FileListStruct *Entry;
00180        StrBuf *Buf;
00181        HashList *Files;
00182        int Done = 0;
00183        int sequence = 0;
00184        char buf[1024];
00185        CompareFunc SortIt;
00186        int HavePic = 0;
00187        WCTemplputParams SubTP;
00188 
00189        memset(&SubTP, 0, sizeof(WCTemplputParams));
00190        serv_puts("RDIR");
00191        serv_getln(buf, sizeof buf);
00192        if (buf[0] != '1') return NULL;
00193 
00194        Buf = NewStrBuf();          
00195        Files = NewHash(1, NULL);
00196        while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
00197               if ( (StrLength(Buf)==3) && 
00198                   !strcmp(ChrPtr(Buf), "000")) 
00199               {
00200                      Done = 1;
00201                      continue;
00202               }
00203 
00204               Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
00205               Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
00206               Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
00207               Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
00208 
00209               Entry->Sequence = sequence++;
00210 
00211               StrBufExtract_token(Entry->Filename, Buf, 0, '|');
00212               Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
00213               StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
00214               StrBufExtract_token(Entry->Comment, Buf, 3, '|');
00215 
00216 
00217 
00218               Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
00219               if (Entry->IsPic) {
00220                      HavePic = 1;
00221               }
00222               Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
00223        }
00224        if (HavePic)
00225               putbstr("__HAVE_PIC", NewStrBufPlain(HKEY("1")));
00226        SubTP.Filter.ContextType = CTX_FILELIST;
00227        SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
00228        if (SortIt != NULL)
00229               SortByPayload(Files, SortIt);
00230        else 
00231               SortByPayload(Files, CompareFilelistBySequence);
00232        FreeStrBuf(&Buf);
00233        return Files;
00234 }
00235 
00236 void display_mime_icon(void)
00237 {
00238        char FileBuf[SIZ];
00239        const char *FileName;
00240        char *MimeType;
00241        size_t tlen;
00242 
00243        MimeType = xbstr("type", &tlen);
00244        FileName = GetIconFilename(MimeType, tlen);
00245 
00246        if (FileName == NULL)
00247               snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/webcit_icons/essen/16x16/file.png");
00248        else
00249               snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
00250        output_static(FileBuf);
00251 }
00252 
00253 void download_file(void)
00254 {
00255        wcsession *WCC = WC;
00256        StrBuf *Buf;
00257        off_t bytes;
00258        StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
00259 
00260        /* Setting to nonzero forces a MIME type of application/octet-stream */
00261        int force_download = 1;
00262        
00263        Buf = NewStrBuf();
00264        StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
00265        StrBufUnescape(Buf, 1);
00266        serv_printf("OPEN %s", ChrPtr(Buf));
00267        StrBuf_ServGetln(Buf);
00268        if (GetServerStatus(Buf, NULL) == 2) {
00269               StrBufCutLeft(Buf, 4);
00270               bytes = StrBufExtract_long(Buf, 0, '|');
00271               if (!force_download) {
00272                      StrBufExtract_token(ContentType, Buf, 3, '|');
00273               }
00274               serv_read_binary(WCC->WBuf, bytes, Buf);
00275               serv_puts("CLOS");
00276               StrBuf_ServGetln(Buf);
00277               http_transmit_thing(ChrPtr(ContentType), 0);
00278        } else {
00279               StrBufCutLeft(Buf, 4);
00280               hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
00281               output_headers(0, 0, 0, 0, 0, 0);
00282               hprintf("Content-Type: text/plain\r\n");
00283               wc_printf(_("An error occurred while retrieving this file: %s\n"), 
00284                      ChrPtr(Buf));
00285               end_burst();
00286        }
00287        FreeStrBuf(&ContentType);
00288        FreeStrBuf(&Buf);
00289 }
00290 
00291 
00292 
00293 void delete_file(void)
00294 {
00295        const StrBuf *MimeType;
00296        StrBuf *Line;
00297        char buf[256];
00298        
00299        safestrncpy(buf, bstr("file"), sizeof buf);
00300        unescape_input(buf);
00301        serv_printf("DELF %s", buf);
00302 
00303        StrBuf_ServGetln(Line);
00304        GetServerStatusMsg(Line, NULL, 1, 0);
00305 
00306        MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
00307        http_transmit_thing(ChrPtr(MimeType), 0);
00308        FreeStrBuf(&Line);
00309 }
00310 
00311 
00312 
00313 void upload_file(void)
00314 {
00315        const StrBuf *RetMimeType;
00316        const char *MimeType;
00317        StrBuf *Line;
00318        long bytes_transmitted = 0;
00319        long blocksize;
00320        const StrBuf *Desc;
00321        wcsession *WCC = WC;     /* stack this for faster access (WC is a function) */
00322 
00323        MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length); 
00324 
00325               Desc = sbstr("description");
00326 
00327        serv_printf("UOPN %s|%s|%s", 
00328                   ChrPtr(WCC->upload_filename), 
00329                   MimeType, 
00330                   ChrPtr(Desc));
00331        Line = NewStrBuf();
00332        StrBuf_ServGetln(Line);
00333        if (GetServerStatusMsg(Line, NULL, 1, 2) != 2) {
00334               RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
00335               http_transmit_thing(ChrPtr(RetMimeType), 0);
00336               FreeStrBuf(&Line);
00337               return;
00338        }
00339 
00340        while (bytes_transmitted < WCC->upload_length)
00341        {
00342               blocksize = 4096;
00343               if (blocksize > (WCC->upload_length - bytes_transmitted))
00344               {
00345                      blocksize = (WCC->upload_length - bytes_transmitted);
00346               }
00347               serv_printf("WRIT %ld", blocksize);
00348               StrBuf_ServGetln(Line);
00349               if (GetServerStatusMsg(Line, NULL, 0, 0) == 7) {
00350                      blocksize = atoi(ChrPtr(Line) + 4);
00351                      serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
00352                      bytes_transmitted += blocksize;
00353               }
00354               else
00355                      break;
00356        }
00357 
00358        serv_puts("UCLS 1");
00359        StrBuf_ServGetln(Line);
00360        GetServerStatusMsg(Line, NULL, 1, 0);
00361        RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
00362        http_transmit_thing(ChrPtr(RetMimeType), 0);
00363        FreeStrBuf(&Line);
00364 }
00365 
00366 
00367 
00368 /*
00369  * When the browser requests an image file from the Citadel server,
00370  * this function is called to transmit it.
00371  */
00372 void output_image(void)
00373 {
00374        StrBuf *Buf;
00375        wcsession *WCC = WC;
00376        off_t bytes;
00377        const char *MimeType;
00378        
00379        Buf = NewStrBuf();
00380        serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
00381        StrBuf_ServGetln(Buf);
00382        if (GetServerStatus(Buf, NULL) == 2) {
00383               int rc;
00384               StrBufCutLeft(Buf, 4);
00385               bytes = StrBufExtract_long(Buf, 0, '|');
00386 
00389               rc = serv_read_binary(WCC->WBuf, bytes, Buf);
00390               serv_puts("CLOS");
00391               StrBuf_ServGetln(Buf);
00392               
00393               if (rc > 0) {
00394                      MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
00396                      if (!IsEmptyStr(MimeType))
00397                      {
00398                             http_transmit_thing(MimeType, 0);
00399                             FreeStrBuf(&Buf);
00400                             return;
00401                      }
00402               }
00403               /* hm... unknown mimetype? fallback to blank gif */
00404        }
00405        else { 
00406               syslog(LOG_DEBUG, "OIMG failed: %s", ChrPtr(Buf));
00407        }
00408 
00409        
00410        /*
00411         * Instead of an ugly 404, send a 1x1 transparent GIF
00412         * when there's no such image on the server.
00413         */
00414        StrBufPrintf (Buf, "%s%s", static_dirs[0], "/webcit_icons/blank.gif");
00415        output_static(ChrPtr(Buf));
00416        FreeStrBuf(&Buf);
00417 }
00418 
00419 void 
00420 InitModule_DOWNLOAD
00421 (void)
00422 {
00423 
00424        RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
00425                       NULL, DeleteHash, CTX_FILELIST, CTX_NONE, 
00426                       IT_FLAG_DETECT_GROUPCHANGE);
00427 
00428        RegisterSortFunc(HKEY("filemime"),
00429                       NULL, 0,
00430                       CompareFilelistByMime,
00431                       CompareFilelistByMimeRev,
00432                       GroupchangeFilelistByMime,
00433                       CTX_FILELIST);
00434        RegisterSortFunc(HKEY("filename"),
00435                       NULL, 0,
00436                       CompareFilelistByName,
00437                       CompareFilelistByNameRev,
00438                       GroupchangeFilelistByName,
00439                       CTX_FILELIST);
00440        RegisterSortFunc(HKEY("filesize"),
00441                       NULL, 0,
00442                       CompareFilelistBySize,
00443                       CompareFilelistBySizeRev,
00444                       GroupchangeFilelistBySize,
00445                       CTX_FILELIST);
00446        RegisterSortFunc(HKEY("filesubject"),
00447                       NULL, 0,
00448                       CompareFilelistByComment,
00449                       CompareFilelistByCommentRev,
00450                       GroupchangeFilelistByComment,
00451                       CTX_FILELIST);
00452        RegisterSortFunc(HKEY("fileunsorted"),
00453                       NULL, 0,
00454                       CompareFilelistBySequence,
00455                       CompareFilelistBySequence,
00456                       GroupchangeFilelistBySequence,
00457                       CTX_FILELIST);
00458 
00459        RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
00460        RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
00461        RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
00462        RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
00463 
00464        RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST);
00465 
00466        WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
00467        WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
00468        WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
00469        WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
00470        WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);
00471 }