2 * Copyright (c) 1996-2012 by the citadel.org team
4 * This program is open source software. You can redistribute it and/or
5 * modify it under the terms of the GNU General Public License, version 3.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
14 #include "webserver.h"
16 CtxType CTX_FILELIST = CTX_NONE;
18 extern void output_static(const char* What);
20 extern char* static_dirs[];
22 typedef struct _FileListStruct {
31 void FreeFiles(void *vFile)
33 FileListStruct *F = (FileListStruct*) vFile;
34 FreeStrBuf(&F->Filename);
35 FreeStrBuf(&F->MimeType);
36 FreeStrBuf(&F->Comment);
40 /* -------------------------------------------------------------------------------- */
41 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
43 FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
44 StrBufAppendTemplate(Target, TP, F->Filename, 0);
46 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
48 FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
49 StrBufAppendPrintf(Target, "%ld", F->FileSize);
51 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
53 FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
54 StrBufAppendTemplate(Target, TP, F->MimeType, 0);
56 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
58 FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
59 StrBufAppendTemplate(Target, TP, F->Comment, 0);
62 /* -------------------------------------------------------------------------------- */
64 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
66 FileListStruct *F = (FileListStruct*) CTX(CTX_FILELIST);
70 /* -------------------------------------------------------------------------------- */
71 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
73 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
74 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
76 if (File1->IsPic != File2->IsPic)
77 return File1->IsPic > File2->IsPic;
78 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
80 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
82 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
83 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
84 if (File1->IsPic != File2->IsPic)
85 return File1->IsPic < File2->IsPic;
86 return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
88 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
90 FileListStruct *File1 = (FileListStruct*) vFile1;
91 FileListStruct *File2 = (FileListStruct*) vFile2;
93 if (File1->IsPic != File2->IsPic)
94 return File1->IsPic > File2->IsPic;
95 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
99 int CompareFilelistByName(const void *vFile1, const void *vFile2)
101 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
102 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
104 if (File1->IsPic != File2->IsPic)
105 return File1->IsPic > File2->IsPic;
106 return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
108 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
110 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
111 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
112 if (File1->IsPic != File2->IsPic)
113 return File1->IsPic < File2->IsPic;
114 return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
116 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
118 FileListStruct *File1 = (FileListStruct*) vFile1;
119 FileListStruct *File2 = (FileListStruct*) vFile2;
121 return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
125 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
127 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
128 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
129 if (File1->FileSize == File2->FileSize)
131 return (File1->FileSize > File2->FileSize);
133 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
135 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
136 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
137 if (File1->FileSize == File2->FileSize)
139 return (File1->FileSize < File2->FileSize);
141 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
147 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
149 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
150 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
151 return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
153 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
155 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
156 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
157 return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
159 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
161 FileListStruct *File1 = (FileListStruct*) vFile1;
162 FileListStruct *File2 = (FileListStruct*) vFile2;
163 return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
167 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
169 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
170 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
171 return (File2->Sequence > File1->Sequence);
173 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
178 /* -------------------------------------------------------------------------------- */
179 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
181 FileListStruct *Entry;
189 WCTemplputParams SubTP;
191 memset(&SubTP, 0, sizeof(WCTemplputParams));
193 serv_getln(buf, sizeof buf);
194 if (buf[0] != '1') return NULL;
197 Files = NewHash(1, NULL);
198 while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
199 if ( (StrLength(Buf)==3) &&
200 !strcmp(ChrPtr(Buf), "000"))
206 Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
207 Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
208 Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
209 Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
211 Entry->Sequence = sequence++;
213 StrBufExtract_token(Entry->Filename, Buf, 0, '|');
214 Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
215 StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
216 StrBufExtract_token(Entry->Comment, Buf, 3, '|');
220 Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
224 Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
227 putbstr("__HAVE_PIC", NewStrBufPlain(HKEY("1")));
228 SubTP.Filter.ContextType = CTX_FILELIST;
229 SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
231 SortByPayload(Files, SortIt);
233 SortByPayload(Files, CompareFilelistBySequence);
238 void display_mime_icon(void)
241 const char *FileName;
245 MimeType = xbstr("type", &tlen);
246 FileName = GetIconFilename(MimeType, tlen);
248 if (FileName == NULL)
249 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/webcit_icons/essen/16x16/file.png");
251 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
252 output_static(FileBuf);
255 void download_file(void)
260 StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
262 /* Setting to nonzero forces a MIME type of application/octet-stream */
263 int force_download = 1;
266 StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
267 StrBufUnescape(Buf, 1);
268 serv_printf("OPEN %s", ChrPtr(Buf));
269 StrBuf_ServGetln(Buf);
270 if (GetServerStatus(Buf, NULL) == 2) {
271 StrBufCutLeft(Buf, 4);
272 bytes = StrBufExtract_long(Buf, 0, '|');
273 if (!force_download) {
274 StrBufExtract_token(ContentType, Buf, 3, '|');
276 serv_read_binary(WCC->WBuf, bytes, Buf);
278 StrBuf_ServGetln(Buf);
279 http_transmit_thing(ChrPtr(ContentType), 0);
281 StrBufCutLeft(Buf, 4);
282 hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
283 output_headers(0, 0, 0, 0, 0, 0);
284 hprintf("Content-Type: text/plain\r\n");
285 wc_printf(_("An error occurred while retrieving this file: %s\n"),
289 FreeStrBuf(&ContentType);
295 void delete_file(void)
297 const StrBuf *MimeType;
301 safestrncpy(buf, bstr("file"), sizeof buf);
303 serv_printf("DELF %s", buf);
305 StrBuf_ServGetln(Line);
306 GetServerStatusMsg(Line, NULL, 1, 0);
308 MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
309 http_transmit_thing(ChrPtr(MimeType), 0);
315 void upload_file(void)
317 const StrBuf *RetMimeType;
318 const char *MimeType;
320 long bytes_transmitted = 0;
323 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
325 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
327 Desc = sbstr("description");
329 serv_printf("UOPN %s|%s|%s",
330 ChrPtr(WCC->upload_filename),
334 StrBuf_ServGetln(Line);
335 if (GetServerStatusMsg(Line, NULL, 1, 2) != 2) {
336 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
337 http_transmit_thing(ChrPtr(RetMimeType), 0);
342 while (bytes_transmitted < WCC->upload_length)
345 if (blocksize > (WCC->upload_length - bytes_transmitted))
347 blocksize = (WCC->upload_length - bytes_transmitted);
349 serv_printf("WRIT %ld", blocksize);
350 StrBuf_ServGetln(Line);
351 if (GetServerStatusMsg(Line, NULL, 0, 0) == 7) {
352 blocksize = atoi(ChrPtr(Line) + 4);
353 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
354 bytes_transmitted += blocksize;
361 StrBuf_ServGetln(Line);
362 GetServerStatusMsg(Line, NULL, 1, 0);
363 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
364 http_transmit_thing(ChrPtr(RetMimeType), 0);
371 * When the browser requests an image file from the Citadel server,
372 * this function is called to transmit it.
374 void output_image(void)
379 const char *MimeType;
382 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
383 StrBuf_ServGetln(Buf);
384 if (GetServerStatus(Buf, NULL) == 2) {
386 StrBufCutLeft(Buf, 4);
387 bytes = StrBufExtract_long(Buf, 0, '|');
389 /** Read it from the server */
391 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
393 StrBuf_ServGetln(Buf);
396 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
397 /** Write it to the browser */
398 if (!IsEmptyStr(MimeType))
400 http_transmit_thing(MimeType, 0);
405 /* hm... unknown mimetype? fallback to blank gif */
408 syslog(LOG_DEBUG, "OIMG failed: %s", ChrPtr(Buf));
413 * Instead of an ugly 404, send a 1x1 transparent GIF
414 * when there's no such image on the server.
416 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/webcit_icons/blank.gif");
417 output_static(ChrPtr(Buf));
425 RegisterCTX(CTX_FILELIST);
427 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
428 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
429 IT_FLAG_DETECT_GROUPCHANGE);
431 RegisterSortFunc(HKEY("filemime"),
433 CompareFilelistByMime,
434 CompareFilelistByMimeRev,
435 GroupchangeFilelistByMime,
437 RegisterSortFunc(HKEY("filename"),
439 CompareFilelistByName,
440 CompareFilelistByNameRev,
441 GroupchangeFilelistByName,
443 RegisterSortFunc(HKEY("filesize"),
445 CompareFilelistBySize,
446 CompareFilelistBySizeRev,
447 GroupchangeFilelistBySize,
449 RegisterSortFunc(HKEY("filesubject"),
451 CompareFilelistByComment,
452 CompareFilelistByCommentRev,
453 GroupchangeFilelistByComment,
455 RegisterSortFunc(HKEY("fileunsorted"),
457 CompareFilelistBySequence,
458 CompareFilelistBySequence,
459 GroupchangeFilelistBySequence,
462 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
463 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
464 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
465 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
467 RegisterConditional("COND:FILE:ISPIC", 0, Conditional_FILE_ISPIC, CTX_FILELIST);
469 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
470 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
471 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
472 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
473 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);