4 * Copyright (c) 1996-2010 by the citadel.org team
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "webserver.h"
23 extern char* static_dirs[];
25 typedef struct _FileListStruct {
34 void FreeFiles(void *vFile)
36 FileListStruct *F = (FileListStruct*) vFile;
37 FreeStrBuf(&F->Filename);
38 FreeStrBuf(&F->MimeType);
39 FreeStrBuf(&F->Comment);
43 /* -------------------------------------------------------------------------------- */
44 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
46 FileListStruct *F = (FileListStruct*) CTX;
47 StrBufAppendTemplate(Target, TP, F->Filename, 0);
49 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
51 FileListStruct *F = (FileListStruct*) CTX;
52 StrBufAppendPrintf(Target, "%ld", F->FileSize);
54 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
56 FileListStruct *F = (FileListStruct*) CTX;
57 StrBufAppendTemplate(Target, TP, F->MimeType, 0);
59 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
61 FileListStruct *F = (FileListStruct*) CTX;
62 StrBufAppendTemplate(Target, TP, F->Comment, 0);
65 /* -------------------------------------------------------------------------------- */
67 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
69 FileListStruct *F = (FileListStruct*) CTX;
73 /* -------------------------------------------------------------------------------- */
74 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
76 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
77 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
79 if (File1->IsPic != File2->IsPic)
80 return File1->IsPic > File2->IsPic;
81 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
83 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
85 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
86 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
87 if (File1->IsPic != File2->IsPic)
88 return File1->IsPic < File2->IsPic;
89 return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
91 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
93 FileListStruct *File1 = (FileListStruct*) vFile1;
94 FileListStruct *File2 = (FileListStruct*) vFile2;
96 if (File1->IsPic != File2->IsPic)
97 return File1->IsPic > File2->IsPic;
98 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
102 int CompareFilelistByName(const void *vFile1, const void *vFile2)
104 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
105 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
107 if (File1->IsPic != File2->IsPic)
108 return File1->IsPic > File2->IsPic;
109 return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
111 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
113 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
114 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
115 if (File1->IsPic != File2->IsPic)
116 return File1->IsPic < File2->IsPic;
117 return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
119 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
121 FileListStruct *File1 = (FileListStruct*) vFile1;
122 FileListStruct *File2 = (FileListStruct*) vFile2;
124 return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
128 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
130 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
131 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
132 if (File1->FileSize == File2->FileSize)
134 return (File1->FileSize > File2->FileSize);
136 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
138 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
139 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
140 if (File1->FileSize == File2->FileSize)
142 return (File1->FileSize < File2->FileSize);
144 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
150 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
152 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
153 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
154 return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
156 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
158 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
159 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
160 return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
162 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
164 FileListStruct *File1 = (FileListStruct*) vFile1;
165 FileListStruct *File2 = (FileListStruct*) vFile2;
166 return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
170 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
172 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
173 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
174 return (File2->Sequence > File1->Sequence);
176 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
181 /* -------------------------------------------------------------------------------- */
182 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
184 FileListStruct *Entry;
192 WCTemplputParams SubTP;
194 memset(&SubTP, 0, sizeof(WCTemplputParams));
196 serv_getln(buf, sizeof buf);
197 if (buf[0] != '1') return NULL;
200 Files = NewHash(1, NULL);
201 while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
202 if ( (StrLength(Buf)==3) &&
203 !strcmp(ChrPtr(Buf), "000"))
209 Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
210 Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
211 Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
212 Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
214 Entry->Sequence = sequence++;
216 StrBufExtract_token(Entry->Filename, Buf, 0, '|');
217 Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
218 StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
219 StrBufExtract_token(Entry->Comment, Buf, 3, '|');
223 Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
227 Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
229 SubTP.Filter.ContextType = CTX_FILELIST;
230 SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
232 SortByPayload(Files, SortIt);
234 SortByPayload(Files, CompareFilelistBySequence);
236 svputlong("FILE:HAVEPICS", HavePic);
240 void display_mime_icon(void)
243 const char *FileName;
247 MimeType = xbstr("type", &tlen);
248 FileName = GetIconFilename(MimeType, tlen);
250 if (FileName == NULL)
251 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/diskette_24x.gif");
253 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
254 output_static(FileBuf);
257 void download_file(void)
262 StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
264 /* Setting to nonzero forces a MIME type of application/octet-stream */
265 int force_download = 1;
268 StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
269 StrBufUnescape(Buf, 1);
270 serv_printf("OPEN %s", ChrPtr(Buf));
271 StrBuf_ServGetln(Buf);
272 if (GetServerStatus(Buf, NULL) == 2) {
273 StrBufCutLeft(Buf, 4);
274 bytes = StrBufExtract_long(Buf, 0, '|');
275 if (!force_download) {
276 StrBufExtract_token(ContentType, Buf, 3, '|');
278 serv_read_binary(WCC->WBuf, bytes, Buf);
280 StrBuf_ServGetln(Buf);
281 http_transmit_thing(ChrPtr(ContentType), 0);
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(Buf);
308 GetServerStatus(Buf, NULL);
309 StrBufCutLeft(Buf, 4);
310 strcpy(WC->ImportantMessage, ChrPtr(Buf));
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;
325 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
327 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
328 serv_printf("UOPN %s|%s|%s", WCC->upload_filename, MimeType, bstr("description"));
329 serv_getln(buf, sizeof buf);
332 strcpy(WCC->ImportantMessage, &buf[4]);
333 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
334 http_transmit_thing(ChrPtr(RetMimeType), 0);
338 while (bytes_transmitted < WCC->upload_length)
341 if (blocksize > (WCC->upload_length - bytes_transmitted))
343 blocksize = (WCC->upload_length - bytes_transmitted);
345 serv_printf("WRIT %ld", blocksize);
346 serv_getln(buf, sizeof buf);
349 blocksize = atoi(&buf[4]);
350 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
351 bytes_transmitted += blocksize;
356 serv_getln(buf, sizeof buf);
357 strcpy(WCC->ImportantMessage, &buf[4]);
358 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
359 http_transmit_thing(ChrPtr(RetMimeType), 0);
365 * When the browser requests an image file from the Citadel server,
366 * this function is called to transmit it.
368 void output_image(void)
373 const char *MimeType;
376 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
377 StrBuf_ServGetln(Buf);
378 if (GetServerStatus(Buf, NULL) == 2) {
380 StrBufCutLeft(Buf, 4);
381 bytes = StrBufExtract_long(Buf, 0, '|');
383 /** Read it from the server */
385 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
387 StrBuf_ServGetln(Buf);
390 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
391 /** Write it to the browser */
392 if (!IsEmptyStr(MimeType))
394 http_transmit_thing(MimeType, 0);
399 /* hm... unknown mimetype? fallback to blank gif */
404 * Instead of an ugly 404, send a 1x1 transparent GIF
405 * when there's no such image on the server.
407 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/blank.gif");
408 output_static(ChrPtr(Buf));
417 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
418 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
419 IT_FLAG_DETECT_GROUPCHANGE);
421 RegisterSortFunc(HKEY("filemime"),
423 CompareFilelistByMime,
424 CompareFilelistByMimeRev,
425 GroupchangeFilelistByMime,
427 RegisterSortFunc(HKEY("filename"),
429 CompareFilelistByName,
430 CompareFilelistByNameRev,
431 GroupchangeFilelistByName,
433 RegisterSortFunc(HKEY("filesize"),
435 CompareFilelistBySize,
436 CompareFilelistBySizeRev,
437 GroupchangeFilelistBySize,
439 RegisterSortFunc(HKEY("filesubject"),
441 CompareFilelistByComment,
442 CompareFilelistByCommentRev,
443 GroupchangeFilelistByComment,
445 RegisterSortFunc(HKEY("fileunsorted"),
447 CompareFilelistBySequence,
448 CompareFilelistBySequence,
449 GroupchangeFilelistBySequence,
452 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
453 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
454 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
455 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
457 RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST);
459 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
460 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
461 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
462 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
463 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);