2 * Copyright (c) 1996-2010 by the citadel.org team
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (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
19 #include "webserver.h"
21 extern char* static_dirs[];
23 typedef struct _FileListStruct {
32 void FreeFiles(void *vFile)
34 FileListStruct *F = (FileListStruct*) vFile;
35 FreeStrBuf(&F->Filename);
36 FreeStrBuf(&F->MimeType);
37 FreeStrBuf(&F->Comment);
41 /* -------------------------------------------------------------------------------- */
42 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
44 FileListStruct *F = (FileListStruct*) CTX;
45 StrBufAppendTemplate(Target, TP, F->Filename, 0);
47 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
49 FileListStruct *F = (FileListStruct*) CTX;
50 StrBufAppendPrintf(Target, "%ld", F->FileSize);
52 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
54 FileListStruct *F = (FileListStruct*) CTX;
55 StrBufAppendTemplate(Target, TP, F->MimeType, 0);
57 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
59 FileListStruct *F = (FileListStruct*) CTX;
60 StrBufAppendTemplate(Target, TP, F->Comment, 0);
63 /* -------------------------------------------------------------------------------- */
65 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
67 FileListStruct *F = (FileListStruct*) CTX;
71 /* -------------------------------------------------------------------------------- */
72 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
74 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
75 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
77 if (File1->IsPic != File2->IsPic)
78 return File1->IsPic > File2->IsPic;
79 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
81 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
83 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
84 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
85 if (File1->IsPic != File2->IsPic)
86 return File1->IsPic < File2->IsPic;
87 return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
89 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
91 FileListStruct *File1 = (FileListStruct*) vFile1;
92 FileListStruct *File2 = (FileListStruct*) vFile2;
94 if (File1->IsPic != File2->IsPic)
95 return File1->IsPic > File2->IsPic;
96 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
100 int CompareFilelistByName(const void *vFile1, const void *vFile2)
102 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
103 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
105 if (File1->IsPic != File2->IsPic)
106 return File1->IsPic > File2->IsPic;
107 return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
109 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
111 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
112 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
113 if (File1->IsPic != File2->IsPic)
114 return File1->IsPic < File2->IsPic;
115 return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
117 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
119 FileListStruct *File1 = (FileListStruct*) vFile1;
120 FileListStruct *File2 = (FileListStruct*) vFile2;
122 return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
126 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
128 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
129 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
130 if (File1->FileSize == File2->FileSize)
132 return (File1->FileSize > File2->FileSize);
134 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
136 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
137 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
138 if (File1->FileSize == File2->FileSize)
140 return (File1->FileSize < File2->FileSize);
142 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
148 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
150 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
151 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
152 return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
154 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
156 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
157 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
158 return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
160 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
162 FileListStruct *File1 = (FileListStruct*) vFile1;
163 FileListStruct *File2 = (FileListStruct*) vFile2;
164 return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
168 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
170 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
171 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
172 return (File2->Sequence > File1->Sequence);
174 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
179 /* -------------------------------------------------------------------------------- */
180 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
182 FileListStruct *Entry;
190 WCTemplputParams SubTP;
192 memset(&SubTP, 0, sizeof(WCTemplputParams));
194 serv_getln(buf, sizeof buf);
195 if (buf[0] != '1') return NULL;
198 Files = NewHash(1, NULL);
199 while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
200 if ( (StrLength(Buf)==3) &&
201 !strcmp(ChrPtr(Buf), "000"))
207 Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
208 Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
209 Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
210 Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
212 Entry->Sequence = sequence++;
214 StrBufExtract_token(Entry->Filename, Buf, 0, '|');
215 Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
216 StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
217 StrBufExtract_token(Entry->Comment, Buf, 3, '|');
221 Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
225 Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
227 SubTP.Filter.ContextType = CTX_FILELIST;
228 SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
230 SortByPayload(Files, SortIt);
232 SortByPayload(Files, CompareFilelistBySequence);
237 void display_mime_icon(void)
240 const char *FileName;
244 MimeType = xbstr("type", &tlen);
245 FileName = GetIconFilename(MimeType, tlen);
247 if (FileName == NULL)
248 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/diskette_24x.gif");
250 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
251 output_static(FileBuf);
254 void download_file(void)
259 StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
261 /* Setting to nonzero forces a MIME type of application/octet-stream */
262 int force_download = 1;
265 StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
266 StrBufUnescape(Buf, 1);
267 serv_printf("OPEN %s", ChrPtr(Buf));
268 StrBuf_ServGetln(Buf);
269 if (GetServerStatus(Buf, NULL) == 2) {
270 StrBufCutLeft(Buf, 4);
271 bytes = StrBufExtract_long(Buf, 0, '|');
272 if (!force_download) {
273 StrBufExtract_token(ContentType, Buf, 3, '|');
275 serv_read_binary(WCC->WBuf, bytes, Buf);
277 StrBuf_ServGetln(Buf);
278 http_transmit_thing(ChrPtr(ContentType), 0);
280 StrBufCutLeft(Buf, 4);
281 hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
282 output_headers(0, 0, 0, 0, 0, 0);
283 hprintf("Content-Type: text/plain\r\n");
284 wc_printf(_("An error occurred while retrieving this file: %s\n"),
288 FreeStrBuf(&ContentType);
294 void delete_file(void)
296 const StrBuf *MimeType;
300 safestrncpy(buf, bstr("file"), sizeof buf);
302 serv_printf("DELF %s", buf);
304 StrBuf_ServGetln(Buf);
305 GetServerStatus(Buf, NULL);
306 StrBufCutLeft(Buf, 4);
307 strcpy(WC->ImportantMessage, ChrPtr(Buf));
308 MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
309 http_transmit_thing(ChrPtr(MimeType), 0);
315 void upload_file(void)
317 const StrBuf *RetMimeType;
318 const char *MimeType;
320 long bytes_transmitted = 0;
323 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
325 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
327 Desc = sbstr("description");
329 serv_printf("UOPN %s|%s|%s",
330 ChrPtr(WCC->upload_filename),
334 serv_getln(buf, sizeof buf);
337 strcpy(WCC->ImportantMessage, &buf[4]);
338 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
339 http_transmit_thing(ChrPtr(RetMimeType), 0);
343 while (bytes_transmitted < WCC->upload_length)
346 if (blocksize > (WCC->upload_length - bytes_transmitted))
348 blocksize = (WCC->upload_length - bytes_transmitted);
350 serv_printf("WRIT %ld", blocksize);
351 serv_getln(buf, sizeof buf);
354 blocksize = atoi(&buf[4]);
355 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
356 bytes_transmitted += blocksize;
361 serv_getln(buf, sizeof buf);
362 strcpy(WCC->ImportantMessage, &buf[4]);
363 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
364 http_transmit_thing(ChrPtr(RetMimeType), 0);
370 * When the browser requests an image file from the Citadel server,
371 * this function is called to transmit it.
373 void output_image(void)
378 const char *MimeType;
381 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
382 StrBuf_ServGetln(Buf);
383 if (GetServerStatus(Buf, NULL) == 2) {
385 StrBufCutLeft(Buf, 4);
386 bytes = StrBufExtract_long(Buf, 0, '|');
388 /** Read it from the server */
390 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
392 StrBuf_ServGetln(Buf);
395 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
396 /** Write it to the browser */
397 if (!IsEmptyStr(MimeType))
399 http_transmit_thing(MimeType, 0);
404 /* hm... unknown mimetype? fallback to blank gif */
409 * Instead of an ugly 404, send a 1x1 transparent GIF
410 * when there's no such image on the server.
412 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/blank.gif");
413 output_static(ChrPtr(Buf));
422 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
423 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
424 IT_FLAG_DETECT_GROUPCHANGE);
426 RegisterSortFunc(HKEY("filemime"),
428 CompareFilelistByMime,
429 CompareFilelistByMimeRev,
430 GroupchangeFilelistByMime,
432 RegisterSortFunc(HKEY("filename"),
434 CompareFilelistByName,
435 CompareFilelistByNameRev,
436 GroupchangeFilelistByName,
438 RegisterSortFunc(HKEY("filesize"),
440 CompareFilelistBySize,
441 CompareFilelistBySizeRev,
442 GroupchangeFilelistBySize,
444 RegisterSortFunc(HKEY("filesubject"),
446 CompareFilelistByComment,
447 CompareFilelistByCommentRev,
448 GroupchangeFilelistByComment,
450 RegisterSortFunc(HKEY("fileunsorted"),
452 CompareFilelistBySequence,
453 CompareFilelistBySequence,
454 GroupchangeFilelistBySequence,
457 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
458 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
459 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
460 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
462 RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST);
464 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
465 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
466 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
467 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
468 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);