* Attempting to add a smart host in webcit was instead adding it as an RBL host....
[citadel.git] / webcit / downloads.c
blob65ea69bb4040423f7935464645f23a906a9a29c6
1 /*
2 * $Id$
3 */
4 #include "webcit.h"
5 #include "webserver.h"
7 extern char* static_dirs[];
9 typedef struct _FileListStruct {
10 StrBuf *Filename;
11 long FileSize;
12 StrBuf *MimeType;
13 StrBuf *Comment;
14 int IsPic;
15 int Sequence;
16 } FileListStruct;
18 void FreeFiles(void *vFile)
20 FileListStruct *F = (FileListStruct*) vFile;
21 FreeStrBuf(&F->Filename);
22 FreeStrBuf(&F->MimeType);
23 FreeStrBuf(&F->Comment);
24 free(F);
27 /* -------------------------------------------------------------------------------- */
28 void tmplput_FILE_NAME(StrBuf *Target, WCTemplputParams *TP)
30 FileListStruct *F = (FileListStruct*) CTX;
31 StrBufAppendTemplate(Target, TP, F->Filename, 0);
33 void tmplput_FILE_SIZE(StrBuf *Target, WCTemplputParams *TP)
35 FileListStruct *F = (FileListStruct*) CTX;
36 StrBufAppendPrintf(Target, "%ld", F->FileSize);
38 void tmplput_FILEMIMETYPE(StrBuf *Target, WCTemplputParams *TP)
40 FileListStruct *F = (FileListStruct*) CTX;
41 StrBufAppendTemplate(Target, TP, F->MimeType, 0);
43 void tmplput_FILE_COMMENT(StrBuf *Target, WCTemplputParams *TP)
45 FileListStruct *F = (FileListStruct*) CTX;
46 StrBufAppendTemplate(Target, TP, F->Comment, 0);
49 /* -------------------------------------------------------------------------------- */
51 int Conditional_FILE_ISPIC(StrBuf *Target, WCTemplputParams *TP)
53 FileListStruct *F = (FileListStruct*) CTX;
54 return F->IsPic;
57 /* -------------------------------------------------------------------------------- */
58 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
60 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
61 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
63 if (File1->IsPic != File2->IsPic)
64 return File1->IsPic > File2->IsPic;
65 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType));
67 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
69 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
70 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
71 if (File1->IsPic != File2->IsPic)
72 return File1->IsPic < File2->IsPic;
73 return strcasecmp(ChrPtr(File2->MimeType), ChrPtr(File1->MimeType));
75 int GroupchangeFilelistByMime(const void *vFile1, const void *vFile2)
77 FileListStruct *File1 = (FileListStruct*) vFile1;
78 FileListStruct *File2 = (FileListStruct*) vFile2;
80 if (File1->IsPic != File2->IsPic)
81 return File1->IsPic > File2->IsPic;
82 return strcasecmp(ChrPtr(File1->MimeType), ChrPtr(File2->MimeType)) != 0;
86 int CompareFilelistByName(const void *vFile1, const void *vFile2)
88 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
89 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
91 if (File1->IsPic != File2->IsPic)
92 return File1->IsPic > File2->IsPic;
93 return strcasecmp(ChrPtr(File1->Filename), ChrPtr(File2->Filename));
95 int CompareFilelistByNameRev(const void *vFile1, const void *vFile2)
97 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
98 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
99 if (File1->IsPic != File2->IsPic)
100 return File1->IsPic < File2->IsPic;
101 return strcasecmp(ChrPtr(File2->Filename), ChrPtr(File1->Filename));
103 int GroupchangeFilelistByName(const void *vFile1, const void *vFile2)
105 FileListStruct *File1 = (FileListStruct*) vFile1;
106 FileListStruct *File2 = (FileListStruct*) vFile2;
108 return ChrPtr(File1->Filename)[0] != ChrPtr(File2->Filename)[0];
112 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
114 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
115 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
116 if (File1->FileSize == File2->FileSize)
117 return 0;
118 return (File1->FileSize > File2->FileSize);
120 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
122 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
123 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
124 if (File1->FileSize == File2->FileSize)
125 return 0;
126 return (File1->FileSize < File2->FileSize);
128 int GroupchangeFilelistBySize(const void *vFile1, const void *vFile2)
130 return 0;
134 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
136 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
137 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
138 return strcasecmp(ChrPtr(File1->Comment), ChrPtr(File2->Comment));
140 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
142 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
143 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
144 return strcasecmp(ChrPtr(File2->Comment), ChrPtr(File1->Comment));
146 int GroupchangeFilelistByComment(const void *vFile1, const void *vFile2)
148 FileListStruct *File1 = (FileListStruct*) vFile1;
149 FileListStruct *File2 = (FileListStruct*) vFile2;
150 return ChrPtr(File1->Comment)[9] != ChrPtr(File2->Comment)[0];
154 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
156 FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
157 FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
158 return (File2->Sequence > File1->Sequence);
160 int GroupchangeFilelistBySequence(const void *vFile1, const void *vFile2)
162 return 0;
165 /* -------------------------------------------------------------------------------- */
166 HashList* LoadFileList(StrBuf *Target, WCTemplputParams *TP)
168 FileListStruct *Entry;
169 StrBuf *Buf;
170 HashList *Files;
171 int Done = 0;
172 int sequence = 0;
173 char buf[1024];
174 CompareFunc SortIt;
175 int HavePic;
176 WCTemplputParams SubTP;
178 memset(&TP, 0, sizeof(WCTemplputParams));
179 serv_puts("RDIR");
180 serv_getln(buf, sizeof buf);
181 if (buf[0] != '1') return NULL;
183 Buf = NewStrBuf();
184 Files = NewHash(1, NULL);
185 while (!Done && (StrBuf_ServGetln(Buf)>=0)) {
186 if ( (StrLength(Buf)==3) &&
187 !strcmp(ChrPtr(Buf), "000"))
189 Done = 1;
190 continue;
193 Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
194 Entry->Filename = NewStrBufPlain(NULL, StrLength(Buf));
195 Entry->MimeType = NewStrBufPlain(NULL, StrLength(Buf));
196 Entry->Comment = NewStrBufPlain(NULL, StrLength(Buf));
198 Entry->Sequence = sequence++;
200 StrBufExtract_token(Entry->Filename, Buf, 0, '|');
201 Entry->FileSize = StrBufExtract_long(Buf, 1, '|');
202 StrBufExtract_token(Entry->MimeType, Buf, 2, '|');
203 StrBufExtract_token(Entry->Comment, Buf, 3, '|');
207 Entry->IsPic = (strstr(ChrPtr(Entry->MimeType), "image") != NULL);
208 if (Entry->IsPic) {
209 HavePic = 1;
211 Put(Files, SKEY(Entry->Filename), Entry, FreeFiles);
213 SubTP.Filter.ContextType = CTX_FILELIST;
214 SortIt = RetrieveSort(&SubTP, NULL, 0, HKEY("fileunsorted"), 0);
215 if (SortIt != NULL)
216 SortByPayload(Files, SortIt);
217 else
218 SortByPayload(Files, CompareFilelistBySequence);
219 FreeStrBuf(&Buf);
220 svputlong("FILE:HAVEPICS", HavePic);
221 return Files;
224 void display_mime_icon(void)
226 char FileBuf[SIZ];
227 const char *FileName;
228 char *MimeType;
229 size_t tlen;
231 MimeType = xbstr("type", &tlen);
232 FileName = GetIconFilename(MimeType, tlen);
234 if (FileName == NULL)
235 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/diskette_24x.gif");
236 else
237 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
238 output_static(FileBuf);
241 void download_file(void)
243 char buf[256];
244 off_t bytes;
245 char content_type[256];
246 char *content = NULL;
248 /* Setting to nonzero forces a MIME type of application/octet-stream */
249 int force_download = 1;
251 safestrncpy(buf, ChrPtr(WC->UrlFragment2), sizeof buf);
252 unescape_input(buf);
253 serv_printf("OPEN %s", buf);
254 serv_getln(buf, sizeof buf);
255 if (buf[0] == '2') {
256 bytes = extract_long(&buf[4], 0);
257 content = malloc(bytes + 2);
258 if (force_download) {
259 strcpy(content_type, "application/octet-stream");
261 else {
262 extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
264 output_headers(0, 0, 0, 0, 0, 0);
265 read_server_binary(WC->WBuf, bytes);
266 serv_puts("CLOS");
267 serv_getln(buf, sizeof buf);
268 http_transmit_thing(content_type, 0);
269 free(content);
270 } else {
271 hprintf("HTTP/1.1 404 %s\n", &buf[4]);
272 output_headers(0, 0, 0, 0, 0, 0);
273 hprintf("Content-Type: text/plain\r\n");
274 wprintf(_("An error occurred while retrieving this file: %s\n"), &buf[4]);
275 end_burst();
281 void delete_file(void)
283 StrBuf *Buf;
284 char buf[256];
286 safestrncpy(buf, bstr("file"), sizeof buf);
287 unescape_input(buf);
288 serv_printf("DELF %s", buf);
289 Buf = NewStrBuf();
290 StrBuf_ServGetln(Buf);
291 GetServerStatus(Buf, NULL);
292 StrBufCutLeft(Buf, 4);
293 strcpy(WC->ImportantMessage, ChrPtr(Buf));
294 do_template("files", CTX_NONE);
295 output_headers(0, 0, 0, 0, 0, 0);
296 end_burst();
297 FreeStrBuf(&Buf);
302 void upload_file(void)
304 const char *MimeType;
305 char buf[1024];
306 long bytes_transmitted = 0;
307 long blocksize;
308 wcsession *WCC = WC; /* stack this for faster access (WC is a function) */
310 MimeType = GuessMimeType(WCC->upload, WCC->upload_length);
311 serv_printf("UOPN %s|%s|%s", WCC->upload_filename, MimeType, bstr("description"));
312 serv_getln(buf, sizeof buf);
313 if (buf[0] != '2')
315 strcpy(WCC->ImportantMessage, &buf[4]);
316 do_template("files", NULL);
317 output_headers(0, 0, 0, 0, 0, 0);
318 end_burst();
319 return;
322 while (bytes_transmitted < WCC->upload_length)
324 blocksize = 4096;
325 if (blocksize > (WCC->upload_length - bytes_transmitted))
327 blocksize = (WCC->upload_length - bytes_transmitted);
329 serv_printf("WRIT %ld", blocksize);
330 serv_getln(buf, sizeof buf);
331 if (buf[0] == '7')
333 blocksize = atoi(&buf[4]);
334 serv_write(&WCC->upload[bytes_transmitted], blocksize);
335 bytes_transmitted += blocksize;
339 serv_puts("UCLS 1");
340 serv_getln(buf, sizeof buf);
341 strcpy(WCC->ImportantMessage, &buf[4]);
342 do_template("files", CTX_NONE);
343 output_headers(0, 0, 0, 0, 0, 0);
344 end_burst();
350 * When the browser requests an image file from the Citadel server,
351 * this function is called to transmit it.
353 void output_image(void)
355 char blank_gif[SIZ];
356 wcsession *WCC = WC;
357 char buf[SIZ];
358 off_t bytes;
359 const char *MimeType;
361 serv_printf("OIMG %s|%s", bstr("name"), bstr("parm"));
362 serv_getln(buf, sizeof buf);
363 if (buf[0] == '2') {
364 bytes = extract_long(&buf[4], 0);
366 /** Read it from the server */
368 if (read_server_binary(WCC->WBuf, bytes) > 0) {
369 serv_puts("CLOS");
370 serv_getln(buf, sizeof buf);
372 MimeType = GuessMimeType (ChrPtr(WCC->WBuf), StrLength(WCC->WBuf));
373 /** Write it to the browser */
374 if (!IsEmptyStr(MimeType))
376 http_transmit_thing(MimeType, 0);
377 return;
380 /* hm... unknown mimetype? fallback to blank gif */
385 * Instead of an ugly 404, send a 1x1 transparent GIF
386 * when there's no such image on the server.
388 snprintf (blank_gif, SIZ, "%s%s", static_dirs[0], "/blank.gif");
389 output_static(blank_gif);
392 void
393 InitModule_DOWNLOAD
394 (void)
397 RegisterIterator("ROOM:FILES", 0, NULL, LoadFileList,
398 NULL, DeleteHash, CTX_FILELIST, CTX_NONE,
399 IT_FLAG_DETECT_GROUPCHANGE);
401 RegisterSortFunc(HKEY("filemime"),
402 NULL, 0,
403 CompareFilelistByMime,
404 CompareFilelistByMimeRev,
405 GroupchangeFilelistByMime,
406 CTX_FILELIST);
407 RegisterSortFunc(HKEY("filename"),
408 NULL, 0,
409 CompareFilelistByName,
410 CompareFilelistByNameRev,
411 GroupchangeFilelistByName,
412 CTX_FILELIST);
413 RegisterSortFunc(HKEY("filesize"),
414 NULL, 0,
415 CompareFilelistBySize,
416 CompareFilelistBySizeRev,
417 GroupchangeFilelistBySize,
418 CTX_FILELIST);
419 RegisterSortFunc(HKEY("filesubject"),
420 NULL, 0,
421 CompareFilelistByComment,
422 CompareFilelistByCommentRev,
423 GroupchangeFilelistByComment,
424 CTX_FILELIST);
425 RegisterSortFunc(HKEY("fileunsorted"),
426 NULL, 0,
427 CompareFilelistBySequence,
428 CompareFilelistBySequence,
429 GroupchangeFilelistBySequence,
430 CTX_FILELIST);
432 RegisterNamespace("FILE:NAME", 0, 2, tmplput_FILE_NAME, CTX_FILELIST);
433 RegisterNamespace("FILE:SIZE", 0, 1, tmplput_FILE_SIZE, CTX_FILELIST);
434 RegisterNamespace("FILE:MIMETYPE", 0, 2, tmplput_FILEMIMETYPE, CTX_FILELIST);
435 RegisterNamespace("FILE:COMMENT", 0, 2, tmplput_FILE_COMMENT, CTX_FILELIST);
437 RegisterConditional(HKEY("COND:FILE:ISPIC"), 0, Conditional_FILE_ISPIC, CTX_FILELIST);
439 WebcitAddUrlHandler(HKEY("image"), output_image, 0);
440 WebcitAddUrlHandler(HKEY("display_mime_icon"), display_mime_icon , 0);
441 WebcitAddUrlHandler(HKEY("download_file"), download_file, NEED_URL);
442 WebcitAddUrlHandler(HKEY("delete_file"), delete_file, NEED_URL);
443 WebcitAddUrlHandler(HKEY("upload_file"), upload_file, 0);