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 void output_static(const char* What);
24 extern char* static_dirs[];
26 typedef struct _FileListStruct {
35 void FreeFiles(void *vFile)
37 FileListStruct *F = (FileListStruct*) vFile;
38 FreeStrBuf(&F->Filename);
39 FreeStrBuf(&F->MimeType);
40 FreeStrBuf(&F->Comment);
44 /* -------------------------------------------------------------------------------- */
45 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
47 FileListStruct *F = (FileListStruct*) CTX;
48 StrBufAppendTemplate(Target, TP, F->Filename, 0);
50 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
52 FileListStruct *F = (FileListStruct*) CTX;
53 StrBufAppendPrintf(Target, "%ld", F->FileSize);
55 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
57 FileListStruct *F = (FileListStruct*) CTX;
58 StrBufAppendTemplate(Target, TP, F->MimeType, 0);
60 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
62 FileListStruct *F = (FileListStruct*) CTX;
63 StrBufAppendTemplate(Target, TP, F->Comment, 0);
66 /* -------------------------------------------------------------------------------- */
68 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
70 FileListStruct *F = (FileListStruct*) CTX;
74 /* -------------------------------------------------------------------------------- */
75 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
77 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
78 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
80 if (File1->IsPic != File2->IsPic)
81 return File1->IsPic > File2->IsPic;
82 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
84 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
86 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
87 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
88 if (File1->IsPic != File2->IsPic)
89 return File1->IsPic < File2->IsPic;
90 return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
92 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
94 FileListStruct *File1 = (FileListStruct*) vFile1;
95 FileListStruct *File2 = (FileListStruct*) vFile2;
97 if (File1->IsPic != File2->IsPic)
98 return File1->IsPic > File2->IsPic;
99 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
103 int CompareFilelistByName(const void *vFile1, const void *vFile2)
105 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
106 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
108 if (File1->IsPic != File2->IsPic)
109 return File1->IsPic > File2->IsPic;
110 return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
112 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
114 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
115 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
116 if (File1->IsPic != File2->IsPic)
117 return File1->IsPic < File2->IsPic;
118 return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
120 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
122 FileListStruct *File1 = (FileListStruct*) vFile1;
123 FileListStruct *File2 = (FileListStruct*) vFile2;
125 return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
129 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
131 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
132 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
133 if (File1->FileSize == File2->FileSize)
135 return (File1->FileSize > File2->FileSize);
137 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
139 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
140 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
141 if (File1->FileSize == File2->FileSize)
143 return (File1->FileSize < File2->FileSize);
145 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
151 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
153 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
154 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
155 return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
157 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
159 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
160 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
161 return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
163 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
165 FileListStruct *File1 = (FileListStruct*) vFile1;
166 FileListStruct *File2 = (FileListStruct*) vFile2;
167 return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
171 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
173 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
174 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
175 return (File2->Sequence > File1->Sequence);
177 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
182 /* -------------------------------------------------------------------------------- */
183 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
185 FileListStruct *Entry;
193 WCTemplputParams SubTP;
195 memset(&SubTP, 0, sizeof(WCTemplputParams));
197 serv_getln(buf, sizeof buf);
198 if (buf[0] != '1') return NULL;
201 Files = NewHash(1, NULL);
202 while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
203 if ( (StrLength(Buf)==3) &&
204 !strcmp(ChrPtr(Buf), "000"))
210 Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
211 Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
212 Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
213 Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
215 Entry->Sequence = sequence++;
217 StrBufExtract_token(Entry->Filename, Buf, 0, '|');
218 Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
219 StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
220 StrBufExtract_token(Entry->Comment, Buf, 3, '|');
224 Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
228 Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
231 putbstr("__HAVE_PIC", NewStrBufPlain(HKEY("1")));
232 SubTP.Filter.ContextType = CTX_FILELIST;
233 SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
235 SortByPayload(Files, SortIt);
237 SortByPayload(Files, CompareFilelistBySequence);
242 void display_mime_icon(void)
245 const char *FileName;
249 MimeType = xbstr("type", &tlen);
250 FileName = GetIconFilename(MimeType, tlen);
252 if (FileName == NULL)
253 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/webcit_icons/essen/16x16/file.png");
255 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
256 output_static(FileBuf);
259 void download_file(void)
264 StrBuf *ContentType = NewStrBufPlain(HKEY("application/octet-stream"));
266 /* Setting to nonzero forces a MIME type of application/octet-stream */
267 int force_download = 1;
270 StrBufExtract_token(Buf, WCC->Hdr->HR.ReqLine, 0, '/');
271 StrBufUnescape(Buf, 1);
272 serv_printf("OPEN %s", ChrPtr(Buf));
273 StrBuf_ServGetln(Buf);
274 if (GetServerStatus(Buf, NULL) == 2) {
275 StrBufCutLeft(Buf, 4);
276 bytes = StrBufExtract_long(Buf, 0, '|');
277 if (!force_download) {
278 StrBufExtract_token(ContentType, Buf, 3, '|');
280 serv_read_binary(WCC->WBuf, bytes, Buf);
282 StrBuf_ServGetln(Buf);
283 http_transmit_thing(ChrPtr(ContentType), 0);
285 StrBufCutLeft(Buf, 4);
286 hprintf("HTTP/1.1 404 %s\n", ChrPtr(Buf));
287 output_headers(0, 0, 0, 0, 0, 0);
288 hprintf("Content-Type: text/plain\r\n");
289 wc_printf(_("An error occurred while retrieving this file: %s\n"),
293 FreeStrBuf(&ContentType);
299 void delete_file(void)
301 const StrBuf *MimeType;
305 safestrncpy(buf, bstr("file"), sizeof buf);
307 serv_printf("DELF %s", buf);
309 StrBuf_ServGetln(Line);
310 GetServerStatusMsg(Line, NULL, 1, 0);
312 MimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
313 http_transmit_thing(ChrPtr(MimeType), 0);
319 void upload_file(void)
321 const StrBuf *RetMimeType;
322 const char *MimeType;
324 long bytes_transmitted = 0;
327 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
329 MimeType = GuessMimeType(ChrPtr(WCC->upload), WCC->upload_length);
331 Desc = sbstr("description");
333 serv_printf("UOPN %s|%s|%s",
334 ChrPtr(WCC->upload_filename),
338 StrBuf_ServGetln(Line);
339 if (GetServerStatusMsg(Line, NULL, 1, 2) != 2) {
340 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
341 http_transmit_thing(ChrPtr(RetMimeType), 0);
346 while (bytes_transmitted < WCC->upload_length)
349 if (blocksize > (WCC->upload_length - bytes_transmitted))
351 blocksize = (WCC->upload_length - bytes_transmitted);
353 serv_printf("WRIT %ld", blocksize);
354 StrBuf_ServGetln(Line);
355 if (GetServerStatusMsg(Line, NULL, 0, 0) == 7) {
356 blocksize = atoi(ChrPtr(Line) + 4);
357 serv_write(&ChrPtr(WCC->upload)[bytes_transmitted], blocksize);
358 bytes_transmitted += blocksize;
365 StrBuf_ServGetln(Line);
366 GetServerStatusMsg(Line, NULL, 1, 0);
367 RetMimeType = DoTemplate(HKEY("files"), NULL, &NoCtx);
368 http_transmit_thing(ChrPtr(RetMimeType), 0);
375 * When the browser requests an image file from the Citadel server,
376 * this function is called to transmit it.
378 void output_image(void)
383 const char *MimeType;
386 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
387 StrBuf_ServGetln(Buf);
388 if (GetServerStatus(Buf, NULL) == 2) {
390 StrBufCutLeft(Buf, 4);
391 bytes = StrBufExtract_long(Buf, 0, '|');
393 /** Read it from the server */
395 rc = serv_read_binary(WCC->WBuf, bytes, Buf);
397 StrBuf_ServGetln(Buf);
400 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
401 /** Write it to the browser */
402 if (!IsEmptyStr(MimeType))
404 http_transmit_thing(MimeType, 0);
409 /* hm... unknown mimetype? fallback to blank gif */
414 * Instead of an ugly 404, send a 1x1 transparent GIF
415 * when there's no such image on the server.
417 StrBufPrintf (Buf, "%s%s", static_dirs[0], "/webcit_icons/blank.gif");
418 output_static(ChrPtr(Buf));
427 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
428 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
429 IT_FLAG_DETECT_GROUPCHANGE);
431 RegisterSortFunc(HKEY("filemime"),
433 CompareFilelistByMime,
434 CompareFilelistByMimeRev,
435 GroupchangeFilelistByMime,
437 RegisterSortFunc(HKEY("filename"),
439 CompareFilelistByName,
440 CompareFilelistByNameRev,
441 GroupchangeFilelistByName,
443 RegisterSortFunc(HKEY("filesize"),
445 CompareFilelistBySize,
446 CompareFilelistBySizeRev,
447 GroupchangeFilelistBySize,
449 RegisterSortFunc(HKEY("filesubject"),
451 CompareFilelistByComment,
452 CompareFilelistByCommentRev,
453 GroupchangeFilelistByComment,
455 RegisterSortFunc(HKEY("fileunsorted"),
457 CompareFilelistBySequence,
458 CompareFilelistBySequence,
459 GroupchangeFilelistBySequence,
462 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, NULL, CTX_FILELIST);
463 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, NULL, CTX_FILELIST);
464 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, NULL, CTX_FILELIST);
465 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, NULL, CTX_FILELIST);
467 RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST);
469 WebcitAddUrlHandler(HKEY("image"), "", 0, output_image, ANONYMOUS);
470 WebcitAddUrlHandler(HKEY("display_mime_icon"), "", 0, display_mime_icon , ANONYMOUS);
471 WebcitAddUrlHandler(HKEY("download_file"), "", 0, download_file, NEED_URL);
472 WebcitAddUrlHandler(HKEY("delete_file"), "", 0, delete_file, NEED_URL);
473 WebcitAddUrlHandler(HKEY("upload_file"), "", 0, upload_file, 0);