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 StrBufExtract_token(ContentType, Buf, 3, '|');
274 serv_read_binary(WCC->WBuf, bytes, Buf);
276 StrBuf_ServGetln(Buf);
277 CheckGZipCompressionAllowed (SKEY(ContentType));
279 FlushStrBuf(ContentType);
280 http_transmit_thing(ChrPtr(ContentType), 0);
282 StrBufCutLeft(Buf, 4);
283 hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
284 output_headers(0, 0, 0, 0, 0, 0);
285 hprintf("Content-Type: text/plain\r\n");
286 wc_printf(_("An error occurred while retrieving this file: %s\n"),
290 FreeStrBuf(&ContentType);
296 void delete_file(void)
298 const StrBuf *MimeType;
302 safestrncpy(buf, bstr("file"), sizeof buf);
304 serv_printf("DELF %s", buf);
306 StrBuf_ServGetln(Line);
307 GetServerStatusMsg(Line, NULL, 1, 0);
309 MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
310 http_transmit_thing(ChrPtr(MimeType), 0);
316 void upload_file(void)
318 const StrBuf *RetMimeType;
319 const char *MimeType;
321 long bytes_transmitted = 0;
324 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
326 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
328 Desc = sbstr("description");
330 serv_printf("UOPN %s|%s|%s",
331 ChrPtr(WCC->upload_filename),
335 StrBuf_ServGetln(Line);
336 if (GetServerStatusMsg(Line, NULL, 1, 2) != 2) {
337 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
338 http_transmit_thing(ChrPtr(RetMimeType), 0);
343 while (bytes_transmitted < WCC->upload_length)
346 if (blocksize > (WCC->upload_length - bytes_transmitted))
348 blocksize = (WCC->upload_length - bytes_transmitted);
350 serv_printf("WRIT %ld", blocksize);
351 StrBuf_ServGetln(Line);
352 if (GetServerStatusMsg(Line, NULL, 0, 0) == 7) {
353 blocksize = atoi(ChrPtr(Line) + 4);
354 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
355 bytes_transmitted += blocksize;
362 StrBuf_ServGetln(Line);
363 GetServerStatusMsg(Line, NULL, 1, 0);
364 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
365 http_transmit_thing(ChrPtr(RetMimeType), 0);
372 * When the browser requests an image file from the Citadel server,
373 * this function is called to transmit it.
375 void output_image(void)
380 const char *MimeType;
383 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
384 StrBuf_ServGetln(Buf);
385 if (GetServerStatus(Buf, NULL) == 2) {
387 StrBufCutLeft(Buf, 4);
388 bytes = StrBufExtract_long(Buf, 0, '|');
390 /** Read it from the server */
392 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
394 StrBuf_ServGetln(Buf);
397 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
398 /** Write it to the browser */
399 if (!IsEmptyStr(MimeType))
401 CheckGZipCompressionAllowed (MimeType, strlen(MimeType));
402 http_transmit_thing(MimeType, 0);
407 /* hm... unknown mimetype? fallback to blank gif */
410 syslog(LOG_DEBUG, "OIMG failed: %s", ChrPtr(Buf));
415 * Instead of an ugly 404, send a 1x1 transparent GIF
416 * when there's no such image on the server.
418 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/webcit_icons/blank.gif");
419 output_static(ChrPtr(Buf));
427 RegisterCTX(CTX_FILELIST);
429 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
430 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
431 IT_FLAG_DETECT_GROUPCHANGE);
433 RegisterSortFunc(HKEY("filemime"),
435 CompareFilelistByMime,
436 CompareFilelistByMimeRev,
437 GroupchangeFilelistByMime,
439 RegisterSortFunc(HKEY("filename"),
441 CompareFilelistByName,
442 CompareFilelistByNameRev,
443 GroupchangeFilelistByName,
445 RegisterSortFunc(HKEY("filesize"),
447 CompareFilelistBySize,
448 CompareFilelistBySizeRev,
449 GroupchangeFilelistBySize,
451 RegisterSortFunc(HKEY("filesubject"),
453 CompareFilelistByComment,
454 CompareFilelistByCommentRev,
455 GroupchangeFilelistByComment,
457 RegisterSortFunc(HKEY("fileunsorted"),
459 CompareFilelistBySequence,
460 CompareFilelistBySequence,
461 GroupchangeFilelistBySequence,
464 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
465 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
466 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
467 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
469 RegisterConditional("COND:FILE:ISPIC", 0, Conditional_FILE_ISPIC, CTX_FILELIST);
471 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
472 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
473 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
474 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
475 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);