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 extern void output_static(const char* What);
18 extern char* static_dirs[];
20 typedef struct _FileListStruct {
29 void FreeFiles(void *vFile)
31 FileListStruct *F = (FileListStruct*) vFile;
32 FreeStrBuf(&F->Filename);
33 FreeStrBuf(&F->MimeType);
34 FreeStrBuf(&F->Comment);
38 /* -------------------------------------------------------------------------------- */
39 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
41 FileListStruct *F = (FileListStruct*) CTX;
42 StrBufAppendTemplate(Target, TP, F->Filename, 0);
44 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
46 FileListStruct *F = (FileListStruct*) CTX;
47 StrBufAppendPrintf(Target, "%ld", F->FileSize);
49 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
51 FileListStruct *F = (FileListStruct*) CTX;
52 StrBufAppendTemplate(Target, TP, F->MimeType, 0);
54 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
56 FileListStruct *F = (FileListStruct*) CTX;
57 StrBufAppendTemplate(Target, TP, F->Comment, 0);
60 /* -------------------------------------------------------------------------------- */
62 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
64 FileListStruct *F = (FileListStruct*) CTX;
68 /* -------------------------------------------------------------------------------- */
69 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
71 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
72 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
74 if (File1->IsPic != File2->IsPic)
75 return File1->IsPic > File2->IsPic;
76 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
78 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
80 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
81 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
82 if (File1->IsPic != File2->IsPic)
83 return File1->IsPic < File2->IsPic;
84 return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
86 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
88 FileListStruct *File1 = (FileListStruct*) vFile1;
89 FileListStruct *File2 = (FileListStruct*) vFile2;
91 if (File1->IsPic != File2->IsPic)
92 return File1->IsPic > File2->IsPic;
93 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
97 int CompareFilelistByName(const void *vFile1, const void *vFile2)
99 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
100 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
102 if (File1->IsPic != File2->IsPic)
103 return File1->IsPic > File2->IsPic;
104 return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
106 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
108 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
109 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
110 if (File1->IsPic != File2->IsPic)
111 return File1->IsPic < File2->IsPic;
112 return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
114 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
116 FileListStruct *File1 = (FileListStruct*) vFile1;
117 FileListStruct *File2 = (FileListStruct*) vFile2;
119 return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
123 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
125 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
126 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
127 if (File1->FileSize == File2->FileSize)
129 return (File1->FileSize > File2->FileSize);
131 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
133 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
134 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
135 if (File1->FileSize == File2->FileSize)
137 return (File1->FileSize < File2->FileSize);
139 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
145 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
147 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
148 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
149 return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
151 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
153 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
154 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
155 return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
157 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
159 FileListStruct *File1 = (FileListStruct*) vFile1;
160 FileListStruct *File2 = (FileListStruct*) vFile2;
161 return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
165 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
167 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
168 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
169 return (File2->Sequence > File1->Sequence);
171 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
176 /* -------------------------------------------------------------------------------- */
177 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
179 FileListStruct *Entry;
187 WCTemplputParams SubTP;
189 memset(&SubTP, 0, sizeof(WCTemplputParams));
191 serv_getln(buf, sizeof buf);
192 if (buf[0] != '1') return NULL;
195 Files = NewHash(1, NULL);
196 while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
197 if ( (StrLength(Buf)==3) &&
198 !strcmp(ChrPtr(Buf), "000"))
204 Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
205 Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
206 Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
207 Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
209 Entry->Sequence = sequence++;
211 StrBufExtract_token(Entry->Filename, Buf, 0, '|');
212 Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
213 StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
214 StrBufExtract_token(Entry->Comment, Buf, 3, '|');
218 Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
222 Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
225 putbstr("__HAVE_PIC", NewStrBufPlain(HKEY("1")));
226 SubTP.Filter.ContextType = CTX_FILELIST;
227 SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
229 SortByPayload(Files, SortIt);
231 SortByPayload(Files, CompareFilelistBySequence);
236 void display_mime_icon(void)
239 const char *FileName;
243 MimeType = xbstr("type", &tlen);
244 FileName = GetIconFilename(MimeType, tlen);
246 if (FileName == NULL)
247 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/webcit_icons/essen/16x16/file.png");
249 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
250 output_static(FileBuf);
253 void download_file(void)
258 StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
260 /* Setting to nonzero forces a MIME type of application/octet-stream */
261 int force_download = 1;
264 StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
265 StrBufUnescape(Buf, 1);
266 serv_printf("OPEN %s", ChrPtr(Buf));
267 StrBuf_ServGetln(Buf);
268 if (GetServerStatus(Buf, NULL) == 2) {
269 StrBufCutLeft(Buf, 4);
270 bytes = StrBufExtract_long(Buf, 0, '|');
271 if (!force_download) {
272 StrBufExtract_token(ContentType, Buf, 3, '|');
274 serv_read_binary(WCC->WBuf, bytes, Buf);
276 StrBuf_ServGetln(Buf);
277 http_transmit_thing(ChrPtr(ContentType), 0);
279 StrBufCutLeft(Buf, 4);
280 hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
281 output_headers(0, 0, 0, 0, 0, 0);
282 hprintf("Content-Type: text/plain\r\n");
283 wc_printf(_("An error occurred while retrieving this file: %s\n"),
287 FreeStrBuf(&ContentType);
293 void delete_file(void)
295 const StrBuf *MimeType;
299 safestrncpy(buf, bstr("file"), sizeof buf);
301 serv_printf("DELF %s", buf);
303 StrBuf_ServGetln(Line);
304 GetServerStatusMsg(Line, NULL, 1, 0);
306 MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
307 http_transmit_thing(ChrPtr(MimeType), 0);
313 void upload_file(void)
315 const StrBuf *RetMimeType;
316 const char *MimeType;
318 long bytes_transmitted = 0;
321 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
323 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
325 Desc = sbstr("description");
327 serv_printf("UOPN %s|%s|%s",
328 ChrPtr(WCC->upload_filename),
332 StrBuf_ServGetln(Line);
333 if (GetServerStatusMsg(Line, NULL, 1, 2) != 2) {
334 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
335 http_transmit_thing(ChrPtr(RetMimeType), 0);
340 while (bytes_transmitted < WCC->upload_length)
343 if (blocksize > (WCC->upload_length - bytes_transmitted))
345 blocksize = (WCC->upload_length - bytes_transmitted);
347 serv_printf("WRIT %ld", blocksize);
348 StrBuf_ServGetln(Line);
349 if (GetServerStatusMsg(Line, NULL, 0, 0) == 7) {
350 blocksize = atoi(ChrPtr(Line) + 4);
351 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
352 bytes_transmitted += blocksize;
359 StrBuf_ServGetln(Line);
360 GetServerStatusMsg(Line, NULL, 1, 0);
361 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
362 http_transmit_thing(ChrPtr(RetMimeType), 0);
369 * When the browser requests an image file from the Citadel server,
370 * this function is called to transmit it.
372 void output_image(void)
377 const char *MimeType;
380 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
381 StrBuf_ServGetln(Buf);
382 if (GetServerStatus(Buf, NULL) == 2) {
384 StrBufCutLeft(Buf, 4);
385 bytes = StrBufExtract_long(Buf, 0, '|');
387 /** Read it from the server */
389 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
391 StrBuf_ServGetln(Buf);
394 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
395 /** Write it to the browser */
396 if (!IsEmptyStr(MimeType))
398 http_transmit_thing(MimeType, 0);
403 /* hm... unknown mimetype? fallback to blank gif */
406 syslog(LOG_DEBUG, "OIMG failed: %s", ChrPtr(Buf));
411 * Instead of an ugly 404, send a 1x1 transparent GIF
412 * when there's no such image on the server.
414 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/webcit_icons/blank.gif");
415 output_static(ChrPtr(Buf));
424 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
425 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
426 IT_FLAG_DETECT_GROUPCHANGE);
428 RegisterSortFunc(HKEY("filemime"),
430 CompareFilelistByMime,
431 CompareFilelistByMimeRev,
432 GroupchangeFilelistByMime,
434 RegisterSortFunc(HKEY("filename"),
436 CompareFilelistByName,
437 CompareFilelistByNameRev,
438 GroupchangeFilelistByName,
440 RegisterSortFunc(HKEY("filesize"),
442 CompareFilelistBySize,
443 CompareFilelistBySizeRev,
444 GroupchangeFilelistBySize,
446 RegisterSortFunc(HKEY("filesubject"),
448 CompareFilelistByComment,
449 CompareFilelistByCommentRev,
450 GroupchangeFilelistByComment,
452 RegisterSortFunc(HKEY("fileunsorted"),
454 CompareFilelistBySequence,
455 CompareFilelistBySequence,
456 GroupchangeFilelistBySequence,
459 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
460 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
461 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
462 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
464 RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST);
466 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
467 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
468 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
469 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
470 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);