4 * Copyright (c) 1996-2010 by the citadel.org team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "webserver.h"
23 extern char* static_dirs[];
25 typedef struct _FileListStruct {
34 void FreeFiles(void *vFile)
36 FileListStruct *F = (FileListStruct*) vFile;
37 FreeStrBuf(&F->Filename);
38 FreeStrBuf(&F->MimeType);
39 FreeStrBuf(&F->Comment);
43 /* -------------------------------------------------------------------------------- */
44 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
46 FileListStruct *F = (FileListStruct*) CTX;
47 StrBufAppendTemplate(Target, TP, F->Filename, 0);
49 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
51 FileListStruct *F = (FileListStruct*) CTX;
52 StrBufAppendPrintf(Target, "%ld", F->FileSize);
54 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
56 FileListStruct *F = (FileListStruct*) CTX;
57 StrBufAppendTemplate(Target, TP, F->MimeType, 0);
59 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
61 FileListStruct *F = (FileListStruct*) CTX;
62 StrBufAppendTemplate(Target, TP, F->Comment, 0);
65 /* -------------------------------------------------------------------------------- */
67 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
69 FileListStruct *F = (FileListStruct*) CTX;
73 /* -------------------------------------------------------------------------------- */
74 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
76 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
77 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
79 if (File1->IsPic != File2->IsPic)
80 return File1->IsPic > File2->IsPic;
81 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
83 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
85 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
86 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
87 if (File1->IsPic != File2->IsPic)
88 return File1->IsPic < File2->IsPic;
89 return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
91 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
93 FileListStruct *File1 = (FileListStruct*) vFile1;
94 FileListStruct *File2 = (FileListStruct*) vFile2;
96 if (File1->IsPic != File2->IsPic)
97 return File1->IsPic > File2->IsPic;
98 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
102 int CompareFilelistByName(const void *vFile1, const void *vFile2)
104 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
105 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
107 if (File1->IsPic != File2->IsPic)
108 return File1->IsPic > File2->IsPic;
109 return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
111 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
113 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
114 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
115 if (File1->IsPic != File2->IsPic)
116 return File1->IsPic < File2->IsPic;
117 return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
119 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
121 FileListStruct *File1 = (FileListStruct*) vFile1;
122 FileListStruct *File2 = (FileListStruct*) vFile2;
124 return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
128 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
130 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
131 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
132 if (File1->FileSize == File2->FileSize)
134 return (File1->FileSize > File2->FileSize);
136 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
138 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
139 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
140 if (File1->FileSize == File2->FileSize)
142 return (File1->FileSize < File2->FileSize);
144 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
150 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
152 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
153 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
154 return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
156 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
158 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
159 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
160 return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
162 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
164 FileListStruct *File1 = (FileListStruct*) vFile1;
165 FileListStruct *File2 = (FileListStruct*) vFile2;
166 return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
170 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
172 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
173 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
174 return (File2->Sequence > File1->Sequence);
176 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
181 /* -------------------------------------------------------------------------------- */
182 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
184 FileListStruct *Entry;
192 WCTemplputParams SubTP;
194 memset(&SubTP, 0, sizeof(WCTemplputParams));
196 serv_getln(buf, sizeof buf);
197 if (buf[0] != '1') return NULL;
200 Files = NewHash(1, NULL);
201 while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
202 if ( (StrLength(Buf)==3) &&
203 !strcmp(ChrPtr(Buf), "000"))
209 Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
210 Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
211 Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
212 Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
214 Entry->Sequence = sequence++;
216 StrBufExtract_token(Entry->Filename, Buf, 0, '|');
217 Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
218 StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
219 StrBufExtract_token(Entry->Comment, Buf, 3, '|');
223 Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
227 Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
229 SubTP.Filter.ContextType = CTX_FILELIST;
230 SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
232 SortByPayload(Files, SortIt);
234 SortByPayload(Files, CompareFilelistBySequence);
236 svputlong("FILE:HAVEPICS", HavePic);
240 void display_mime_icon(void)
243 const char *FileName;
247 MimeType = xbstr("type", &tlen);
248 FileName = GetIconFilename(MimeType, tlen);
250 if (FileName == NULL)
251 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/diskette_24x.gif");
253 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
254 output_static(FileBuf);
257 void download_file(void)
262 StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
264 /* Setting to nonzero forces a MIME type of application/octet-stream */
265 int force_download = 1;
268 StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
269 StrBufUnescape(Buf, 1);
270 serv_printf("OPEN %s", ChrPtr(Buf));
271 StrBuf_ServGetln(Buf);
272 if (GetServerStatus(Buf, NULL) == 2) {
273 StrBufCutLeft(Buf, 4);
274 bytes = StrBufExtract_long(Buf, 0, '|');
275 if (!force_download) {
276 StrBufExtract_token(ContentType, Buf, 3, '|');
278 serv_read_binary(WCC->WBuf, bytes, Buf);
280 StrBuf_ServGetln(Buf);
281 http_transmit_thing(ChrPtr(ContentType), 0);
283 StrBufCutLeft(Buf, 4);
284 hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
285 output_headers(0, 0, 0, 0, 0, 0);
286 hprintf("Content-Type: text/plain\r\n");
287 wc_printf(_("An error occurred while retrieving this file: %s\n"),
291 FreeStrBuf(&ContentType);
297 void delete_file(void)
299 const StrBuf *MimeType;
303 safestrncpy(buf, bstr("file"), sizeof buf);
305 serv_printf("DELF %s", buf);
307 StrBuf_ServGetln(Buf);
308 GetServerStatus(Buf, NULL);
309 StrBufCutLeft(Buf, 4);
310 strcpy(WC->ImportantMessage, ChrPtr(Buf));
311 MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
312 http_transmit_thing(ChrPtr(MimeType), 0);
318 void upload_file(void)
320 const StrBuf *RetMimeType;
321 const char *MimeType;
323 long bytes_transmitted = 0;
326 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
328 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
330 Desc = sbstr("description");
332 serv_printf("UOPN %s|%s|%s",
333 ChrPtr(WCC->upload_filename),
337 serv_getln(buf, sizeof buf);
340 strcpy(WCC->ImportantMessage, &buf[4]);
341 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
342 http_transmit_thing(ChrPtr(RetMimeType), 0);
346 while (bytes_transmitted < WCC->upload_length)
349 if (blocksize > (WCC->upload_length - bytes_transmitted))
351 blocksize = (WCC->upload_length - bytes_transmitted);
353 serv_printf("WRIT %ld", blocksize);
354 serv_getln(buf, sizeof buf);
357 blocksize = atoi(&buf[4]);
358 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
359 bytes_transmitted += blocksize;
364 serv_getln(buf, sizeof buf);
365 strcpy(WCC->ImportantMessage, &buf[4]);
366 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
367 http_transmit_thing(ChrPtr(RetMimeType), 0);
373 * When the browser requests an image file from the Citadel server,
374 * this function is called to transmit it.
376 void output_image(void)
381 const char *MimeType;
384 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
385 StrBuf_ServGetln(Buf);
386 if (GetServerStatus(Buf, NULL) == 2) {
388 StrBufCutLeft(Buf, 4);
389 bytes = StrBufExtract_long(Buf, 0, '|');
391 /** Read it from the server */
393 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
395 StrBuf_ServGetln(Buf);
398 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
399 /** Write it to the browser */
400 if (!IsEmptyStr(MimeType))
402 http_transmit_thing(MimeType, 0);
407 /* hm... unknown mimetype? fallback to blank gif */
412 * Instead of an ugly 404, send a 1x1 transparent GIF
413 * when there's no such image on the server.
415 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/blank.gif");
416 output_static(ChrPtr(Buf));
425 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
426 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
427 IT_FLAG_DETECT_GROUPCHANGE);
429 RegisterSortFunc(HKEY("filemime"),
431 CompareFilelistByMime,
432 CompareFilelistByMimeRev,
433 GroupchangeFilelistByMime,
435 RegisterSortFunc(HKEY("filename"),
437 CompareFilelistByName,
438 CompareFilelistByNameRev,
439 GroupchangeFilelistByName,
441 RegisterSortFunc(HKEY("filesize"),
443 CompareFilelistBySize,
444 CompareFilelistBySizeRev,
445 GroupchangeFilelistBySize,
447 RegisterSortFunc(HKEY("filesubject"),
449 CompareFilelistByComment,
450 CompareFilelistByCommentRev,
451 GroupchangeFilelistByComment,
453 RegisterSortFunc(HKEY("fileunsorted"),
455 CompareFilelistBySequence,
456 CompareFilelistBySequence,
457 GroupchangeFilelistBySequence,
460 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
461 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
462 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
463 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
465 RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST);
467 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
468 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
469 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
470 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
471 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);