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, '|');
275 CheckGZipCompressionAllowed (SKEY(ContentType));
277 FlushStrBuf(ContentType);
279 serv_read_binary_to_http(ContentType, bytes, 0, 0);
281 StrBuf_ServGetln(Buf);
282 // http_transmit_thing(ChrPtr(ContentType), 0);
284 StrBufCutLeft(Buf, 4);
285 hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
286 output_headers(0, 0, 0, 0, 0, 0);
287 hprintf("Content-Type: text/plain\r\n");
288 wc_printf(_("An error occurred while retrieving this file: %s\n"),
292 FreeStrBuf(&ContentType);
298 void delete_file(void)
300 const StrBuf *MimeType;
304 safestrncpy(buf, bstr("file"), sizeof buf);
306 serv_printf("DELF %s", buf);
308 StrBuf_ServGetln(Line);
309 GetServerStatusMsg(Line, NULL, 1, 0);
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 StrBuf_ServGetln(Line);
338 if (GetServerStatusMsg(Line, NULL, 1, 2) != 2) {
339 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
340 http_transmit_thing(ChrPtr(RetMimeType), 0);
345 while (bytes_transmitted < WCC->upload_length)
348 if (blocksize > (WCC->upload_length - bytes_transmitted))
350 blocksize = (WCC->upload_length - bytes_transmitted);
352 serv_printf("WRIT %ld", blocksize);
353 StrBuf_ServGetln(Line);
354 if (GetServerStatusMsg(Line, NULL, 0, 0) == 7) {
355 blocksize = atoi(ChrPtr(Line) + 4);
356 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
357 bytes_transmitted += blocksize;
364 StrBuf_ServGetln(Line);
365 GetServerStatusMsg(Line, NULL, 1, 0);
366 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
367 http_transmit_thing(ChrPtr(RetMimeType), 0);
374 * When the browser requests an image file from the Citadel server,
375 * this function is called to transmit it.
377 void output_image(void)
382 const char *MimeType;
385 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
386 StrBuf_ServGetln(Buf);
387 if (GetServerStatus(Buf, NULL) == 2) {
389 StrBufCutLeft(Buf, 4);
390 bytes = StrBufExtract_long(Buf, 0, '|');
392 /** Read it from the server */
394 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
396 StrBuf_ServGetln(Buf);
399 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
400 /** Write it to the browser */
401 if (!IsEmptyStr(MimeType))
403 CheckGZipCompressionAllowed (MimeType, strlen(MimeType));
404 http_transmit_thing(MimeType, 0);
409 /* hm... unknown mimetype? fallback to blank gif */
412 syslog(LOG_DEBUG, "OIMG failed: %s", ChrPtr(Buf));
417 * Instead of an ugly 404, send a 1x1 transparent GIF
418 * when there's no such image on the server.
420 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/webcit_icons/blank.gif");
421 output_static(ChrPtr(Buf));
429 RegisterCTX(CTX_FILELIST);
431 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
432 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
433 IT_FLAG_DETECT_GROUPCHANGE);
435 RegisterSortFunc(HKEY("filemime"),
437 CompareFilelistByMime,
438 CompareFilelistByMimeRev,
439 GroupchangeFilelistByMime,
441 RegisterSortFunc(HKEY("filename"),
443 CompareFilelistByName,
444 CompareFilelistByNameRev,
445 GroupchangeFilelistByName,
447 RegisterSortFunc(HKEY("filesize"),
449 CompareFilelistBySize,
450 CompareFilelistBySizeRev,
451 GroupchangeFilelistBySize,
453 RegisterSortFunc(HKEY("filesubject"),
455 CompareFilelistByComment,
456 CompareFilelistByCommentRev,
457 GroupchangeFilelistByComment,
459 RegisterSortFunc(HKEY("fileunsorted"),
461 CompareFilelistBySequence,
462 CompareFilelistBySequence,
463 GroupchangeFilelistBySequence,
466 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
467 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
468 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
469 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
471 RegisterConditional("COND:FILE:ISPIC", 0, Conditional_FILE_ISPIC, CTX_FILELIST);
473 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
474 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
475 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
476 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
477 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);