* updated listsorts to have '0' as sort order in all places that used SortByHashKey
[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*) vFile1;
23         FileListStruct *File2 = (FileListStruct*) 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*) vFile1;
32         FileListStruct *File2 = (FileListStruct*) 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*) vFile1;
41         FileListStruct *File2 = (FileListStruct*) 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*) vFile1;
50         FileListStruct *File2 = (FileListStruct*) 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*) vFile1;
59         FileListStruct *File2 = (FileListStruct*) vFile2;
60         return strcasecmp(File1->Comment, File2->Comment);
61 }
62 int CompareFilelistByCommentRev(const void *vFile1, const void *vFile2)
63 {
64         FileListStruct *File1 = (FileListStruct*) vFile1;
65         FileListStruct *File2 = (FileListStruct*) vFile2;
66         return strcasecmp(File2->Comment, File1->Comment);
67 }
68
69 int CompareFilelistBySequence(const void *vFile1, const void *vFile2)
70 {
71         FileListStruct *File1 = (FileListStruct*) vFile1;
72         FileListStruct *File2 = (FileListStruct*) 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         if (havebstr("SortOrder"))
229                 Order = ibstr("SortOrder");
230         else
231                 Order = 2; /* <- Unsorted... */
232         SortRow = ibstr("SortBy");
233
234         SortDirections[SortRow] = Order;
235
236         wprintf("<tr>\n");
237         for (i = 1; i < 5; i++) {
238                 switch (SortDirections[i]) {
239                 default:
240                 case 0:
241                         Order = 1;
242                         break;
243                 case 1:
244                         Order = 0;
245                         break;
246                 case 2:
247                         Order = 1;
248                         break;
249                 }                       
250
251                 wprintf("  <th>%s \n"
252                         "      <a href=\"display_room_directory?SortOrder=%d&SortBy=%d\"> \n"
253                         "       <img src=\"%s\" border=\"0\"></a>\n"
254                         "  </th>\n",
255                         RowNames[i],
256                         i, Order, 
257                         SortIcons[SortDirections[i]]
258                         );
259
260         }
261         wprintf("</tr>\n");
262 //<th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n",
263         //);
264
265         if (Files != NULL) {
266                 PrintHash(Files, FilePrintTransition, FilePrintEntry);
267                 DeleteHash(&Files);
268         }
269         wprintf("</table>\n");
270
271         /** Now offer the ability to upload files... */
272         if (WC->room_flags & QR_UPLOAD)
273         {
274                 wprintf("<hr>");
275                 wprintf("<form "
276                         "enctype=\"multipart/form-data\" "
277                         "method=\"POST\" "
278                         "accept-charset=\"UTF-8\" "
279                         "action=\"upload_file\" "
280                         "name=\"upload_file_form\""
281                         ">\n"
282                 );
283                 wprintf("<input type=\"hidden\" name=\"nonce\" value=\"%ld\">\n", WC->nonce);
284
285                 wprintf(_("Upload a file:"));
286                 wprintf("&nbsp;<input NAME=\"filename\" SIZE=16 TYPE=\"file\">&nbsp;\n");
287                 wprintf(_("Description:"));
288                 wprintf("&nbsp;<input type=\"text\" name=\"description\" maxlength=\"64\" size=\"64\">&nbsp;");
289                 wprintf("<input type=\"submit\" name=\"attach_button\" value=\"%s\">\n", _("Upload"));
290
291                 wprintf("</form>\n");
292         }
293
294         wprintf("</div>\n");
295         if (havepics)
296                 wprintf("<div class=\"buttons\"><a href=\"display_pictureview&frame=1\">%s</a></div>", _("Slideshow"));
297         wDumpContent(1);
298 }
299
300
301 void display_pictureview(void)
302 {
303         char buf[1024];
304         char filename[256];
305         char filesize[256];
306         char mimetype[64];
307         char comment[512];
308         char title[256];
309         int n = 0;
310                 
311
312         if (lbstr("frame") == 1) {
313
314                 output_headers(1, 1, 2, 0, 0, 0);
315                 wprintf("<div id=\"banner\">\n");
316                 wprintf("<h1>");
317                 snprintf(title, sizeof title, _("Pictures in %s"), WC->wc_roomname);
318                 escputs(title);
319                 wprintf("</h1>");
320                 wprintf("</div>\n");
321                 
322                 wprintf("<div id=\"content\" class=\"service\">\n");
323
324                 wprintf("<div class=\"fix_scrollbar_bug\">"
325                         "<table class=\"downloads_background\"><tr><td>\n");
326
327
328
329                 wprintf("<script type=\"text/javascript\" language=\"JavaScript\" > \nvar fadeimages=new Array()\n");
330
331                 serv_puts("RDIR");
332                 serv_getln(buf, sizeof buf);
333                 if (buf[0] == '1') while (serv_getln(buf, sizeof buf), strcmp(buf, "000"))  {
334                                 extract_token(filename, buf, 0, '|', sizeof filename);
335                                 extract_token(filesize, buf, 1, '|', sizeof filesize);
336                                 extract_token(mimetype, buf, 2, '|', sizeof mimetype);
337                                 extract_token(comment,  buf, 3, '|', sizeof comment);
338                                 if (strstr(mimetype, "image") != NULL) {
339                                         wprintf("fadeimages[%d]=[\"download_file/", n);
340                                         escputs(filename);
341                                         wprintf("\", \"\", \"\"]\n");
342
343                                         /*
344                                                            //mimetype);
345                                            escputs(filename);   wprintf("</a></td>");
346                                            wprintf("<td>");     escputs(filesize);      wprintf("</td>");
347                                            wprintf("<td>");     escputs(mimetype);      wprintf("</td>");
348                                            wprintf("<td>");     escputs(comment);       wprintf("</td>");
349                                            wprintf("</tr>\n");
350                                         */
351                                         n++;
352                                 }
353                         }
354                 wprintf("</script>\n");
355                 wprintf("<tr><td><script type=\"text/javascript\" src=\"static/fadeshow.js\">\n</script>\n");
356                 wprintf("<script type=\"text/javascript\" >\n");
357                 wprintf("new fadeshow(fadeimages, 500, 400, 0, 3000, 1, \"R\");\n");
358                 wprintf("</script></td><th>\n");
359                 wprintf("</div>\n");
360         }
361         wDumpContent(1);
362
363
364 }
365
366 extern char* static_dirs[];
367 void display_mime_icon(void)
368 {
369         char FileBuf[SIZ];
370         const char *FileName;
371         char *MimeType;
372         size_t tlen;
373
374         MimeType = xbstr("type", &tlen);
375         FileName = GetIconFilename(MimeType, tlen);
376
377         if (FileName == NULL)
378                 snprintf (FileBuf, SIZ, "%s%s", static_dirs[0], "/diskette_24x.gif");
379         else
380                 snprintf (FileBuf, SIZ, "%s%s", static_dirs[3], FileName);
381         output_static(FileBuf);
382
383 }
384
385 void download_file(char *filename)
386 {
387         char buf[256];
388         off_t bytes;
389         char content_type[256];
390         char *content = NULL;
391
392         /* Setting to nonzero forces a MIME type of application/octet-stream */
393         int force_download = 1;
394         
395         safestrncpy(buf, filename, sizeof buf);
396         unescape_input(buf);
397         serv_printf("OPEN %s", buf);
398         serv_getln(buf, sizeof buf);
399         if (buf[0] == '2') {
400                 bytes = extract_long(&buf[4], 0);
401                 content = malloc(bytes + 2);
402                 if (force_download) {
403                         strcpy(content_type, "application/octet-stream");
404                 }
405                 else {
406                         extract_token(content_type, &buf[4], 3, '|', sizeof content_type);
407                 }
408                 output_headers(0, 0, 0, 0, 0, 0);
409                 read_server_binary(content, bytes);
410                 serv_puts("CLOS");
411                 serv_getln(buf, sizeof buf);
412                 http_transmit_thing(content, bytes, content_type, 0);
413                 free(content);
414         } else {
415                 wprintf("HTTP/1.1 404 %s\n", &buf[4]);
416                 output_headers(0, 0, 0, 0, 0, 0);
417                 wprintf("Content-Type: text/plain\r\n");
418                 wprintf("\r\n");
419                 wprintf(_("An error occurred while retrieving this file: %s\n"), &buf[4]);
420         }
421
422 }
423
424
425
426 void upload_file(void)
427 {
428         const char *MimeType;
429         char buf[1024];
430         size_t bytes_transmitted = 0;
431         size_t blocksize;
432         struct wcsession *WCC = WC;     /* stack this for faster access (WC is a function) */
433
434         MimeType = GuessMimeType(WCC->upload, WCC->upload_length); 
435         serv_printf("UOPN %s|%s|%s", WCC->upload_filename, MimeType, bstr("description"));
436         serv_getln(buf, sizeof buf);
437         if (buf[0] != '2')
438         {
439                 strcpy(WCC->ImportantMessage, &buf[4]);
440                 display_room_directory();
441                 return;
442         }
443
444         while (bytes_transmitted < WCC->upload_length)
445         {
446                 blocksize = 4096;
447                 if (blocksize > (WCC->upload_length - bytes_transmitted))
448                 {
449                         blocksize = (WCC->upload_length - bytes_transmitted);
450                 }
451                 serv_printf("WRIT %d", blocksize);
452                 serv_getln(buf, sizeof buf);
453                 if (buf[0] == '7')
454                 {
455                         blocksize = atoi(&buf[4]);
456                         serv_write(&WCC->upload[bytes_transmitted], blocksize);
457                         bytes_transmitted += blocksize;
458                 }
459         }
460
461         serv_puts("UCLS 1");
462         serv_getln(buf, sizeof buf);
463         strcpy(WCC->ImportantMessage, &buf[4]);
464         display_room_directory();
465 }