2 * Copyright (c) 1996-2010 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 as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include "webserver.h"
22 extern char* static_dirs[];
24 typedef struct _FileListStruct {
33 void FreeFiles(void *vFile)
35 FileListStruct *F = (FileListStruct*) vFile;
36 FreeStrBuf(&F->Filename);
37 FreeStrBuf(&F->MimeType);
38 FreeStrBuf(&F->Comment);
42 /* -------------------------------------------------------------------------------- */
43 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
45 FileListStruct *F = (FileListStruct*) CTX;
46 StrBufAppendTemplate(Target, TP, F->Filename, 0);
48 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
50 FileListStruct *F = (FileListStruct*) CTX;
51 StrBufAppendPrintf(Target, "%ld", F->FileSize);
53 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
55 FileListStruct *F = (FileListStruct*) CTX;
56 StrBufAppendTemplate(Target, TP, F->MimeType, 0);
58 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
60 FileListStruct *F = (FileListStruct*) CTX;
61 StrBufAppendTemplate(Target, TP, F->Comment, 0);
64 /* -------------------------------------------------------------------------------- */
66 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
68 FileListStruct *F = (FileListStruct*) CTX;
72 /* -------------------------------------------------------------------------------- */
73 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
75 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
76 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
78 if (File1->IsPic != File2->IsPic)
79 return File1->IsPic > File2->IsPic;
80 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
82 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
84 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
85 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
86 if (File1->IsPic != File2->IsPic)
87 return File1->IsPic < File2->IsPic;
88 return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
90 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
92 FileListStruct *File1 = (FileListStruct*) vFile1;
93 FileListStruct *File2 = (FileListStruct*) vFile2;
95 if (File1->IsPic != File2->IsPic)
96 return File1->IsPic > File2->IsPic;
97 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
101 int CompareFilelistByName(const void *vFile1, const void *vFile2)
103 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
104 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
106 if (File1->IsPic != File2->IsPic)
107 return File1->IsPic > File2->IsPic;
108 return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
110 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
112 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
113 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
114 if (File1->IsPic != File2->IsPic)
115 return File1->IsPic < File2->IsPic;
116 return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
118 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
120 FileListStruct *File1 = (FileListStruct*) vFile1;
121 FileListStruct *File2 = (FileListStruct*) vFile2;
123 return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
127 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
129 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
130 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
131 if (File1->FileSize == File2->FileSize)
133 return (File1->FileSize > File2->FileSize);
135 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
137 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
138 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
139 if (File1->FileSize == File2->FileSize)
141 return (File1->FileSize < File2->FileSize);
143 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
149 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
151 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
152 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
153 return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
155 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
157 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
158 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
159 return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
161 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
163 FileListStruct *File1 = (FileListStruct*) vFile1;
164 FileListStruct *File2 = (FileListStruct*) vFile2;
165 return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
169 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
171 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
172 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
173 return (File2->Sequence > File1->Sequence);
175 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
180 /* -------------------------------------------------------------------------------- */
181 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
183 FileListStruct *Entry;
191 WCTemplputParams SubTP;
193 memset(&SubTP, 0, sizeof(WCTemplputParams));
195 serv_getln(buf, sizeof buf);
196 if (buf[0] != '1') return NULL;
199 Files = NewHash(1, NULL);
200 while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
201 if ( (StrLength(Buf)==3) &&
202 !strcmp(ChrPtr(Buf), "000"))
208 Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
209 Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
210 Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
211 Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
213 Entry->Sequence = sequence++;
215 StrBufExtract_token(Entry->Filename, Buf, 0, '|');
216 Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
217 StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
218 StrBufExtract_token(Entry->Comment, Buf, 3, '|');
222 Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
226 Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
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], "/diskette_24x.gif");
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 if (!force_download) {
274 StrBufExtract_token(ContentType, Buf, 3, '|');
276 serv_read_binary(WCC->WBuf, bytes, Buf);
278 StrBuf_ServGetln(Buf);
279 http_transmit_thing(ChrPtr(ContentType), 0);
281 StrBufCutLeft(Buf, 4);
282 hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
283 output_headers(0, 0, 0, 0, 0, 0);
284 hprintf("Content-Type: text/plain\r\n");
285 wc_printf(_("An error occurred while retrieving this file: %s\n"),
289 FreeStrBuf(&ContentType);
295 void delete_file(void)
297 const StrBuf *MimeType;
301 safestrncpy(buf, bstr("file"), sizeof buf);
303 serv_printf("DELF %s", buf);
305 StrBuf_ServGetln(Buf);
306 GetServerStatus(Buf, NULL);
307 StrBufCutLeft(Buf, 4);
308 strcpy(WC->ImportantMessage, ChrPtr(Buf));
309 MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
310 http_transmit_thing(ChrPtr(MimeType), 0);
316 void upload_file(void)
318 const StrBuf *RetMimeType;
319 const char *MimeType;
321 long bytes_transmitted = 0;
324 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
326 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
328 Desc = sbstr("description");
330 serv_printf("UOPN %s|%s|%s",
331 ChrPtr(WCC->upload_filename),
335 serv_getln(buf, sizeof buf);
338 strcpy(WCC->ImportantMessage, &buf[4]);
339 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
340 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 serv_getln(buf, sizeof buf);
355 blocksize = atoi(&buf[4]);
356 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
357 bytes_transmitted += blocksize;
362 serv_getln(buf, sizeof buf);
363 strcpy(WCC->ImportantMessage, &buf[4]);
364 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
365 http_transmit_thing(ChrPtr(RetMimeType), 0);
371 * When the browser requests an image file from the Citadel server,
372 * this function is called to transmit it.
374 void output_image(void)
379 const char *MimeType;
382 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
383 StrBuf_ServGetln(Buf);
384 if (GetServerStatus(Buf, NULL) == 2) {
386 StrBufCutLeft(Buf, 4);
387 bytes = StrBufExtract_long(Buf, 0, '|');
389 /** Read it from the server */
391 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
393 StrBuf_ServGetln(Buf);
396 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
397 /** Write it to the browser */
398 if (!IsEmptyStr(MimeType))
400 http_transmit_thing(MimeType, 0);
405 /* hm... unknown mimetype? fallback to blank gif */
410 * Instead of an ugly 404, send a 1x1 transparent GIF
411 * when there's no such image on the server.
413 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/blank.gif");
414 output_static(ChrPtr(Buf));
423 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
424 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
425 IT_FLAG_DETECT_GROUPCHANGE);
427 RegisterSortFunc(HKEY("filemime"),
429 CompareFilelistByMime,
430 CompareFilelistByMimeRev,
431 GroupchangeFilelistByMime,
433 RegisterSortFunc(HKEY("filename"),
435 CompareFilelistByName,
436 CompareFilelistByNameRev,
437 GroupchangeFilelistByName,
439 RegisterSortFunc(HKEY("filesize"),
441 CompareFilelistBySize,
442 CompareFilelistBySizeRev,
443 GroupchangeFilelistBySize,
445 RegisterSortFunc(HKEY("filesubject"),
447 CompareFilelistByComment,
448 CompareFilelistByCommentRev,
449 GroupchangeFilelistByComment,
451 RegisterSortFunc(HKEY("fileunsorted"),
453 CompareFilelistBySequence,
454 CompareFilelistBySequence,
455 GroupchangeFilelistBySequence,
458 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
459 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
460 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
461 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
463 RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST);
465 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
466 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
467 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
468 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
469 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);