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);
239 void display_mime_icon(void)
242 const char *FileName;
246 MimeType = xbstr("type", &tlen);
247 FileName = GetIconFilename(MimeType, tlen);
249 if (FileName == NULL)
250 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/diskette_24x.gif");
252 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
253 output_static(FileBuf);
256 void download_file(void)
261 StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
263 /* Setting to nonzero forces a MIME type of application/octet-stream */
264 int force_download = 1;
267 StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
268 StrBufUnescape(Buf, 1);
269 serv_printf("OPEN %s", ChrPtr(Buf));
270 StrBuf_ServGetln(Buf);
271 if (GetServerStatus(Buf, NULL) == 2) {
272 StrBufCutLeft(Buf, 4);
273 bytes = StrBufExtract_long(Buf, 0, '|');
274 if (!force_download) {
275 StrBufExtract_token(ContentType, Buf, 3, '|');
277 serv_read_binary(WCC->WBuf, bytes, Buf);
279 StrBuf_ServGetln(Buf);
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(Buf);
307 GetServerStatus(Buf, NULL);
308 StrBufCutLeft(Buf, 4);
309 strcpy(WC->ImportantMessage, ChrPtr(Buf));
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 serv_getln(buf, sizeof buf);
339 strcpy(WCC->ImportantMessage, &buf[4]);
340 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
341 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 serv_getln(buf, sizeof buf);
356 blocksize = atoi(&buf[4]);
357 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
358 bytes_transmitted += blocksize;
363 serv_getln(buf, sizeof buf);
364 strcpy(WCC->ImportantMessage, &buf[4]);
365 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
366 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 http_transmit_thing(MimeType, 0);
406 /* hm... unknown mimetype? fallback to blank gif */
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], "/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);