* added gcc printf format checking to wprintf
[citadel.git] / webcit / downloads.c
1 /*
2  * $Id$
3  */
4 #include "webcit.h"
5 #include "webserver.h"
6
7 typedef struct _FileListStruct {
8         char Filename[256];
9         int FilenameLen;
10         long FileSize;
11         char MimeType[64];
12         int MimeTypeLen;
13         char Comment[512];
14         int CommentLen;
15         int IsPic;
16         int Sequence;
17 }FileListStruct;
18
19
20 int CompareFilelistByMime(const void *vFile1, const void *vFile2)
21 {
22         FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
23         FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
24
25         if (File1->IsPic != File2->IsPic)
26                 return File1->IsPic > File2->IsPic;
27         return strcasecmp(File1->MimeType, File2->MimeType);
28 }
29 int CompareFilelistByMimeRev(const void *vFile1, const void *vFile2)
30 {
31         FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
32         FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
33         if (File1->IsPic != File2->IsPic)
34                 return File1->IsPic < File2->IsPic;
35         return strcasecmp(File2->MimeType, File1->MimeType);
36 }
37
38 int CompareFilelistBySize(const void *vFile1, const void *vFile2)
39 {
40         FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
41         FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
42         if (File1->FileSize == File2->FileSize)
43                 return 0;
44         return (File1->FileSize > File2->FileSize);
45 }
46
47 int CompareFilelistBySizeRev(const void *vFile1, const void *vFile2)
48 {
49         FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
50         FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
51         if (File1->FileSize == File2->FileSize)
52                 return 0;
53         return (File1->FileSize < File2->FileSize);
54 }
55
56 int CompareFilelistByComment(const void *vFile1, const void *vFile2)
57 {
58         FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
59         FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
60         return strcasecmp(File1->Comment, File2->Comment);
61 }
62 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
63 {
64         FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
65         FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
66         return strcasecmp(File2->Comment, File1->Comment);
67 }
68
69 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
70 {
71         FileListStruct *File1 = (FileListStruct*) GetSearchPayload(vFile1);
72         FileListStruct *File2 = (FileListStruct*) GetSearchPayload(vFile2);
73         return (File2->Sequence >  File1->Sequence);
74 }
75
76 HashList* LoadFileList(int *HavePic)
77 {
78         FileListStruct *Entry;
79         HashList *Files;
80         int HavePics = 0;
81         int Order;
82         int sequence = 0;
83         char buf[1024];
84
85         serv_puts("RDIR");
86         serv_getln(buf, sizeof buf);
87         if (buf[0] == '1') {
88                 Files = NewHash(1, NULL);
89                 while (serv_getln(buf, sizeof buf), strcmp(buf, "000"))
90                 {
91                         Entry = (FileListStruct*) malloc(sizeof (FileListStruct));
92
93                         Entry->FilenameLen = extract_token(
94                                 Entry->Filename, buf, 0, '|', 
95                                 sizeof(Entry->Filename));
96                         Entry->FileSize = extract_long(buf, 1);
97                         Entry->MimeTypeLen = extract_token(
98                                 Entry->MimeType, buf, 2, '|', 
99                                 sizeof(Entry->MimeType));
100                         Entry->CommentLen = extract_token(
101                                 Entry->Comment,  buf, 3, '|', 
102                                 sizeof(Entry->Comment));
103                         
104                         Entry->Sequence = sequence++;
105                         Entry->IsPic = (strstr(Entry->MimeType, "image") != NULL);
106                         if (!HavePics && Entry->IsPic) {
107                                 HavePics = 1;
108                                 *HavePic = 1;
109                         }
110                         Put(Files, Entry->Filename, 
111                             Entry->FilenameLen, 
112                             Entry, NULL);
113                 }
114                 Order = ibstr("SortOrder");
115                 switch (ibstr("SortBy")){
116                 case 1: /*NAME*/
117                         SortByHashKey(Files,Order);
118                         break;
119                 case 2: /* SIZE*/
120                         SortByPayload(Files, (Order)? 
121                                       CompareFilelistBySize:
122                                       CompareFilelistBySizeRev);
123                         break;
124                 case 3: /*MIME*/
125                         SortByPayload(Files, (Order)? 
126                                       CompareFilelistByMime:
127                                       CompareFilelistByMimeRev);
128                         break;
129                 case 4: /*COMM*/
130                         SortByPayload(Files, (Order)? 
131                                       CompareFilelistByComment:
132                                       CompareFilelistByCommentRev);
133                         break;
134                 default:
135                         SortByPayload(Files, CompareFilelistBySequence);
136                 }
137                 return Files;
138         }
139         else
140                 return NULL;
141 }
142
143 void FilePrintEntry(const char *FileName, void *vFile, int odd)
144 {
145         FileListStruct *File = (FileListStruct*) vFile;
146
147         wprintf("<tr bgcolor=\"#%s\">", (odd ? "DDDDDD" : "FFFFFF"));
148         wprintf("<td>"
149                 "<a href=\"download_file/");
150         urlescputs(File->Filename);
151         wprintf("\"><img src=\"display_mime_icon?type=%s\" border=0 align=middle>\n", 
152                 File->MimeType);
153         escputs(File->Filename);        wprintf("</a></td>");
154         wprintf("<td>%ld</td>", File->FileSize);
155         wprintf("<td>");        escputs(File->MimeType);        wprintf("</td>");
156         wprintf("<td>");        escputs(File->Comment); wprintf("</td>");
157         wprintf("</tr>\n");
158 }
159
160 void FilePrintTransition(void *vFile1, void *vFile2, int odd)
161 {
162         FileListStruct *File1 = (FileListStruct*) vFile1;
163         FileListStruct *File2 = (FileListStruct*) vFile2;
164         char StartChar[2] = "\0\0";
165         char *SectionName;
166
167         switch (ibstr("SortBy")){
168         case 1: /*NAME*/
169                 if ((File2 != NULL) && 
170                     ((File1 == NULL) ||
171                      (File1->Filename[0] != File2->Filename[0]))) {
172                         StartChar[0] = File2->Filename[0];
173                         SectionName = StartChar;
174                 }
175                 else return;
176                 break;
177         case 2: /* SIZE*/
178                 return;
179         case 3: /*MIME*/
180                 return; /*TODO*/
181                 break;
182         case 4: /*COMM*/
183                 return;
184         default:
185                 return;
186         }
187
188         wprintf("<tr bgcolor=\"#%s\"><th colspan = 4>%s</th></tr>", 
189                 (odd ? "DDDDDD" : "FFFFFF"),  SectionName);
190 }
191
192
193 void display_room_directory(void)
194 {
195         char title[256];
196         int havepics = 0;
197         HashList *Files;
198         int Order;
199         int SortRow;
200         int i;
201
202         long SortDirections[5] = {2,2,2,2,2};
203         const char* SortIcons[3] = {
204                 "static/up_pointer.gif",
205                 "static/down_pointer.gif",
206                 "static/sort_none.gif"};
207         char *RowNames[5] = {"",
208                             _("Filename"),
209                             _("Size"),
210                             _("Content"),
211                             _("Description")};
212
213         Files = LoadFileList (&havepics);
214         output_headers(1, 1, 2, 0, 0, 0);
215         wprintf("<div id=\"banner\">\n");
216         wprintf("<h1>");
217         snprintf(title, sizeof title, _("Files available for download in %s"), WC->wc_roomname);
218         escputs(title);
219         wprintf("</h1>");
220         wprintf("</div>\n");
221
222         wprintf("<div id=\"content\" class=\"service\">\n");
223
224         wprintf("<div class=\"fix_scrollbar_bug\">"
225                 "<table class=\"downloads_background\"><tr><td>\n");
226
227
228         Order = ibstr("SortOrder");
229         if (!havebstr("SortOrder") || Order > 2)
230                 Order = 2; /* <- Unsorted... */
231         SortRow = ibstr("SortBy");
232
233         SortDirections[SortRow] = Order;
234
235         wprintf("<tr>\n");
236         for (i = 1; i < 5; i++) {
237                 switch (SortDirections[i]) {
238                 default:
239                 case 0:
240                         Order = 2;
241                         break;
242                 case 1:
243                         Order = 0;
244                         break;
245                 case 2:
246                         Order = 1;
247                         break;
248                 }                       
249
250                 wprintf("  <th>%s \n"
251                         "      <a href=\"display_room_directory?SortOrder=%d&SortBy=%d\"> \n"
252                         "       <img src=\"%s\" border=\"0\"></a>\n"
253                         "  </th>\n",
254                         RowNames[i],
255                         Order, i,
256                         SortIcons[SortDirections[i]]
257                         );
258
259         }
260         wprintf("</tr>\n");
261 //<th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n",
262         //);
263
264         if (Files != NULL) {
265                 PrintHash(Files, FilePrintTransition, FilePrintEntry);
266                 DeleteHash(&Files);
267         }
268         wprintf("</table>\n");
269
270         /** Now offer the ability to upload files... */
271         if (WC->room_flags & QR_UPLOAD)
272         {
273                 wprintf("<hr>");
274                 wprintf("<form "
275                         "enctype=\"multipart/form-data\" "
276                         "method=\"POST\" "
277                         "accept-charset=\"UTF-8\" "
278                         "action=\"upload_file\" "
279                         "name=\"upload_file_form\""
280                         ">\n"
281                 );
282                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%d\">\n", WC->nonce);
283
284                 wprintf(_("Upload a file:"));
285                 wprintf("&nbsp;<input NAME=\"filename\" SIZE=16 TYPE=\"file\">&nbsp;\n");
286                 wprintf(_("Description:"));
287                 wprintf("&nbsp;<input type=\"text\" name=\"description\" maxlength=\"64\" size=\"64\">&nbsp;");
288                 wprintf("<input type=\"submit\" name=\"attach_button\" value=\"%s\">\n", _("Upload"));
289
290                 wprintf("</form>\n");
291         }
292
293         wprintf("</div>\n");
294         if (havepics)
295                 wprintf("<div class=\"buttons\"><a href=\"display_pictureview&frame=1\">%s</a></div>", _("Slideshow"));
296         wDumpContent(1);
297 }
298
299
300 void display_pictureview(void)
301 {
302         char buf[1024];
303         char filename[256];
304         char filesize[256];
305         char mimetype[64];
306         char comment[512];
307         char title[256];
308         int n = 0;
309                 
310
311         if (lbstr("frame") == 1) {
312
313                 output_headers(1, 1, 2, 0, 0, 0);
314                 wprintf("<div id=\"banner\">\n");
315                 wprintf("<h1>");
316                 snprintf(title, sizeof title, _("Pictures in %s"), WC->wc_roomname);
317                 escputs(title);
318                 wprintf("</h1>");
319                 wprintf("</div>\n");
320                 
321                 wprintf("<div id=\"content\" class=\"service\">\n");
322
323                 wprintf("<div class=\"fix_scrollbar_bug\">"
324                         "<table class=\"downloads_background\"><tr><td>\n");
325
326
327
328                 wprintf("<script type=\"text/javascript\" language=\"JavaScript\" > \nvar fadeimages=new Array()\n");
329
330                 serv_puts("RDIR");
331                 serv_getln(buf, sizeof buf);
332                 if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000"))  {
333                                 extract_token(filename, buf, 0, '|', sizeof filename);
334                                 extract_token(filesize, buf, 1, '|', sizeof filesize);
335                                 extract_token(mimetype, buf, 2, '|', sizeof mimetype);
336                                 extract_token(comment,  buf, 3, '|', sizeof comment);
337                                 if (strstr(mimetype, "image") != NULL) {
338                                         wprintf("fadeimages[%d]=[\"download_file/", n);
339                                         escputs(filename);
340                                         wprintf("\", \"\", \"\"]\n");
341
342                                         /*
343                                                            //mimetype);
344                                            escputs(filename);   wprintf("</a></td>");
345                                            wprintf("<td>");     escputs(filesize);      wprintf("</td>");
346                                            wprintf("<td>");     escputs(mimetype);      wprintf("</td>");
347                                            wprintf("<td>");     escputs(comment);       wprintf("</td>");
348                                            wprintf("</tr>\n");
349                                         */
350                                         n++;
351                                 }
352                         }
353                 wprintf("</script>\n");
354                 wprintf("<tr><td><script type=\"text/javascript\" src=\"static/fadeshow.js\">\n</script>\n");
355                 wprintf("<script type=\"text/javascript\" >\n");
356                 wprintf("new fadeshow(fadeimages, 500, 400, 0, 3000, 1, \"R\");\n");
357                 wprintf("</script></td><th>\n");
358                 wprintf("</div>\n");
359         }
360         wDumpContent(1);
361
362
363 }
364
365 extern char* static_dirs[];
366 void display_mime_icon(void)
367 {
368         char FileBuf[SIZ];
369         const char *FileName;
370         char *MimeType;
371         size_t tlen;
372
373         MimeType = xbstr("type", &tlen);
374         FileName = GetIconFilename(MimeType, tlen);
375
376         if (FileName == NULL)
377                 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/diskette_24x.gif");
378         else
379                 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
380         output_static(FileBuf);
381
382 }
383
384 void download_file(char *filename)
385 {
386         char buf[256];
387         off_t bytes;
388         char content_type[256];
389         char *content = NULL;
390
391         /* Setting to nonzero forces a MIME type of application/octet-stream */
392         int force_download = 1;
393         
394         safestrncpy(buf, filename, sizeof buf);
395         unescape_input(buf);
396         serv_printf("OPEN %s", buf);
397         serv_getln(buf, sizeof buf);
398         if (buf[0] == '2') {
399                 bytes = extract_long(&buf[4], 0);
400                 content = malloc(bytes + 2);
401                 if (force_download) {
402                         strcpy(content_type, "application/octet-stream");
403                 }
404                 else {
405                         extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
406                 }
407                 output_headers(0, 0, 0, 0, 0, 0);
408                 read_server_binary(content, bytes);
409                 serv_puts("CLOS");
410                 serv_getln(buf, sizeof buf);
411                 http_transmit_thing(content, bytes, content_type, 0);
412                 free(content);
413         } else {
414                 wprintf("HTTP/1.1 404 %s\n", &buf[4]);
415                 output_headers(0, 0, 0, 0, 0, 0);
416                 wprintf("Content-Type: text/plain\r\n");
417                 wprintf("\r\n");
418                 wprintf(_("An error occurred while retrieving this file: %s\n"), &buf[4]);
419         }
420
421 }
422
423
424
425 void upload_file(void)
426 {
427         const char *MimeType;
428         char buf[1024];
429         size_t bytes_transmitted = 0;
430         size_t blocksize;
431         struct wcsession *WCC = WC;     /* stack this for faster access (WC is a function) */
432
433         MimeType = GuessMimeType(WCC->upload, WCC->upload_length); 
434         serv_printf("UOPN %s|%s|%s", WCC->upload_filename, MimeType, bstr("description"));
435         serv_getln(buf, sizeof buf);
436         if (buf[0] != '2')
437         {
438                 strcpy(WCC->ImportantMessage, &buf[4]);
439                 display_room_directory();
440                 return;
441         }
442
443         while (bytes_transmitted < WCC->upload_length)
444         {
445                 blocksize = 4096;
446                 if (blocksize > (WCC->upload_length - bytes_transmitted))
447                 {
448                         blocksize = (WCC->upload_length - bytes_transmitted);
449                 }
450                 serv_printf("WRIT %d", blocksize);
451                 serv_getln(buf, sizeof buf);
452                 if (buf[0] == '7')
453                 {
454                         blocksize = atoi(&buf[4]);
455                         serv_write(&WCC->upload[bytes_transmitted], blocksize);
456                         bytes_transmitted += blocksize;
457                 }
458         }
459
460         serv_puts("UCLS 1");
461         serv_getln(buf, sizeof buf);
462         strcpy(WCC->ImportantMessage, &buf[4]);
463         display_room_directory();
464 }