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);
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(Line);
308 GetServerStatusMsg(Line, NULL, 1, 0);
310 MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
311 http_transmit_thing(ChrPtr(MimeType), 0);
317 void upload_file(void)
319 const StrBuf *RetMimeType;
320 const char *MimeType;
322 long bytes_transmitted = 0;
325 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
327 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
329 Desc = sbstr("description");
331 serv_printf("UOPN %s|%s|%s",
332 ChrPtr(WCC->upload_filename),
336 StrBuf_ServGetln(Line);
337 if (GetServerStatusMsg(Line, NULL, 1, 2) != 2) {
338 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
339 http_transmit_thing(ChrPtr(RetMimeType), 0);
344 while (bytes_transmitted < WCC->upload_length)
347 if (blocksize > (WCC->upload_length - bytes_transmitted))
349 blocksize = (WCC->upload_length - bytes_transmitted);
351 serv_printf("WRIT %ld", blocksize);
352 StrBuf_ServGetln(Line);
353 if (GetServerStatusMsg(Line, NULL, 0, 0) == 7) {
354 blocksize = atoi(ChrPtr(Line) + 4);
355 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
356 bytes_transmitted += blocksize;
363 StrBuf_ServGetln(Line);
364 GetServerStatusMsg(Line, NULL, 1, 0);
365 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
366 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 CheckGZipCompressionAllowed (MimeType, strlen(MimeType));
403 http_transmit_thing(MimeType, 0);
408 /* hm... unknown mimetype? fallback to blank gif */
411 syslog(LOG_DEBUG, "OIMG failed: %s", ChrPtr(Buf));
416 * Instead of an ugly 404, send a 1x1 transparent GIF
417 * when there's no such image on the server.
419 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/webcit_icons/blank.gif");
420 output_static(ChrPtr(Buf));
428 RegisterCTX(CTX_FILELIST);
430 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
431 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
432 IT_FLAG_DETECT_GROUPCHANGE);
434 RegisterSortFunc(HKEY("filemime"),
436 CompareFilelistByMime,
437 CompareFilelistByMimeRev,
438 GroupchangeFilelistByMime,
440 RegisterSortFunc(HKEY("filename"),
442 CompareFilelistByName,
443 CompareFilelistByNameRev,
444 GroupchangeFilelistByName,
446 RegisterSortFunc(HKEY("filesize"),
448 CompareFilelistBySize,
449 CompareFilelistBySizeRev,
450 GroupchangeFilelistBySize,
452 RegisterSortFunc(HKEY("filesubject"),
454 CompareFilelistByComment,
455 CompareFilelistByCommentRev,
456 GroupchangeFilelistByComment,
458 RegisterSortFunc(HKEY("fileunsorted"),
460 CompareFilelistBySequence,
461 CompareFilelistBySequence,
462 GroupchangeFilelistBySequence,
465 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
466 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
467 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
468 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
470 RegisterConditional("COND:FILE:ISPIC", 0, Conditional_FILE_ISPIC, CTX_FILELIST);
472 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
473 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
474 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
475 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
476 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);