99009a1b7494b32dc1c5da90fea1fd34c4d90ac8
[citadel.git] / citadel / file_ops.c
1 /* 
2  * $Id$
3  *
4  * Server functions which handle file transfers and room directories.
5  *
6  */
7
8 #include "sysdep.h"
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <fcntl.h>
13 #include <sys/stat.h>
14 #include <errno.h>
15 #include <ctype.h>
16 #include <string.h>
17 #include <sys/stat.h>
18
19 #if TIME_WITH_SYS_TIME
20 # include <sys/time.h>
21 # include <time.h>
22 #else
23 # if HAVE_SYS_TIME_H
24 #  include <sys/time.h>
25 # else
26 #  include <time.h>
27 # endif
28 #endif
29
30 #include <limits.h>
31 #include <libcitadel.h>
32 #include "citadel.h"
33 #include "server.h"
34 #include "config.h"
35 #include "file_ops.h"
36 #include "sysdep_decls.h"
37 #include "user_ops.h"
38 #include "support.h"
39 #include "room_ops.h"
40 #include "msgbase.h"
41 #include "citserver.h"
42 #include "threads.h"
43
44 #ifndef HAVE_SNPRINTF
45 #include "snprintf.h"
46 #endif
47
48 #include "ctdl_module.h"
49
50 /*
51  * network_talking_to()  --  concurrency checker
52  */
53 int network_talking_to(char *nodename, int operation) {
54
55         static char *nttlist = NULL;
56         char *ptr = NULL;
57         int i;
58         char buf[SIZ];
59         int retval = 0;
60
61         begin_critical_section(S_NTTLIST);
62
63         switch(operation) {
64
65                 case NTT_ADD:
66                         if (nttlist == NULL) nttlist = strdup("");
67                         if (nttlist == NULL) break;
68                         nttlist = (char *)realloc(nttlist,
69                                 (strlen(nttlist) + strlen(nodename) + 3) );
70                         strcat(nttlist, "|");
71                         strcat(nttlist, nodename);
72                         break;
73
74                 case NTT_REMOVE:
75                         if (nttlist == NULL) break;
76                         if (IsEmptyStr(nttlist)) break;
77                         ptr = malloc(strlen(nttlist));
78                         if (ptr == NULL) break;
79                         strcpy(ptr, "");
80                         for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
81                                 extract_token(buf, nttlist, i, '|', sizeof buf);
82                                 if ( (!IsEmptyStr(buf))
83                                      && (strcasecmp(buf, nodename)) ) {
84                                                 strcat(ptr, buf);
85                                                 strcat(ptr, "|");
86                                 }
87                         }
88                         free(nttlist);
89                         nttlist = ptr;
90                         break;
91
92                 case NTT_CHECK:
93                         if (nttlist == NULL) break;
94                         if (IsEmptyStr(nttlist)) break;
95                         for (i = 0; i < num_tokens(nttlist, '|'); ++i) {
96                                 extract_token(buf, nttlist, i, '|', sizeof buf);
97                                 if (!strcasecmp(buf, nodename)) ++retval;
98                         }
99                         break;
100         }
101
102         if (nttlist != NULL) CtdlLogPrintf(CTDL_DEBUG, "nttlist=<%s>\n", nttlist);
103         end_critical_section(S_NTTLIST);
104         return(retval);
105 }
106
107
108
109
110 /*
111  * Server command to delete a file from a room's directory
112  */
113 void cmd_delf(char *filename)
114 {
115         char pathname[64];
116         int a;
117
118         if (CtdlAccessCheck(ac_room_aide))
119                 return;
120
121         if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
122                 cprintf("%d No directory in this room.\n",
123                         ERROR + NOT_HERE);
124                 return;
125         }
126
127         if (IsEmptyStr(filename)) {
128                 cprintf("%d You must specify a file name.\n",
129                         ERROR + FILE_NOT_FOUND);
130                 return;
131         }
132         for (a = 0; !IsEmptyStr(&filename[a]); ++a) {
133                 if ( (filename[a] == '/') || (filename[a] == '\\') ) {
134                         filename[a] = '_';
135                 }
136         }
137         snprintf(pathname, sizeof pathname,
138                          "%s/%s/%s",
139                          ctdl_file_dir,
140                          CC->room.QRdirname, filename);
141         a = unlink(pathname);
142         if (a == 0) {
143                 cprintf("%d File '%s' deleted.\n", CIT_OK, pathname);
144         }
145         else {
146                 cprintf("%d File '%s' not found.\n",
147                         ERROR + FILE_NOT_FOUND, pathname);
148         }
149 }
150
151
152
153
154 /*
155  * move a file from one room directory to another
156  */
157 void cmd_movf(char *cmdbuf)
158 {
159         char filename[PATH_MAX];
160         char pathname[PATH_MAX];
161         char newpath[PATH_MAX];
162         char newroom[ROOMNAMELEN];
163         char buf[PATH_MAX];
164         int a;
165         struct ctdlroom qrbuf;
166         int rv = 0;
167
168         extract_token(filename, cmdbuf, 0, '|', sizeof filename);
169         extract_token(newroom, cmdbuf, 1, '|', sizeof newroom);
170
171         if (CtdlAccessCheck(ac_room_aide)) return;
172
173         if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
174                 cprintf("%d No directory in this room.\n",
175                         ERROR + NOT_HERE);
176                 return;
177         }
178
179         if (IsEmptyStr(filename)) {
180                 cprintf("%d You must specify a file name.\n",
181                         ERROR + FILE_NOT_FOUND);
182                 return;
183         }
184
185         for (a = 0; !IsEmptyStr(&filename[a]); ++a) {
186                 if ( (filename[a] == '/') || (filename[a] == '\\') ) {
187                         filename[a] = '_';
188                 }
189         }
190         snprintf(pathname, sizeof pathname, "./files/%s/%s",
191                  CC->room.QRdirname, filename);
192         if (access(pathname, 0) != 0) {
193                 cprintf("%d File '%s' not found.\n",
194                         ERROR + FILE_NOT_FOUND, pathname);
195                 return;
196         }
197
198         if (CtdlGetRoom(&qrbuf, newroom) != 0) {
199                 cprintf("%d '%s' does not exist.\n", ERROR + ROOM_NOT_FOUND, newroom);
200                 return;
201         }
202         if ((qrbuf.QRflags & QR_DIRECTORY) == 0) {
203                 cprintf("%d '%s' is not a directory room.\n",
204                         ERROR + NOT_HERE, qrbuf.QRname);
205                 return;
206         }
207         snprintf(newpath, sizeof newpath, "./files/%s/%s", qrbuf.QRdirname,
208                  filename);
209         if (link(pathname, newpath) != 0) {
210                 cprintf("%d Couldn't move file: %s\n", ERROR + INTERNAL_ERROR,
211                         strerror(errno));
212                 return;
213         }
214         unlink(pathname);
215
216         /* this is a crude method of copying the file description */
217         snprintf(buf, sizeof buf,
218                  "cat ./files/%s/filedir |grep \"%s\" >>./files/%s/filedir",
219                  CC->room.QRdirname, filename, qrbuf.QRdirname);
220         rv = system(buf);
221         cprintf("%d File '%s' has been moved.\n", CIT_OK, filename);
222 }
223
224
225 /*
226  * This code is common to all commands which open a file for downloading,
227  * regardless of whether it's a file from the directory, an image, a network
228  * spool file, a MIME attachment, etc.
229  * It examines the file and displays the OK result code and some information
230  * about the file.  NOTE: this stuff is Unix dependent.
231  */
232 void OpenCmdResult(char *filename, const char *mime_type)
233 {
234         struct stat statbuf;
235         time_t modtime;
236         long filesize;
237
238         fstat(fileno(CC->download_fp), &statbuf);
239         filesize = (long) statbuf.st_size;
240         modtime = (time_t) statbuf.st_mtime;
241
242         cprintf("%d %ld|%ld|%s|%s\n",
243                 CIT_OK, filesize, (long)modtime, filename, mime_type);
244 }
245
246
247 /*
248  * open a file for downloading
249  */
250 void cmd_open(char *cmdbuf)
251 {
252         char filename[256];
253         char pathname[PATH_MAX];
254         int a;
255
256         extract_token(filename, cmdbuf, 0, '|', sizeof filename);
257
258         if (CtdlAccessCheck(ac_logged_in)) return;
259
260         if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
261                 cprintf("%d No directory in this room.\n",
262                         ERROR + NOT_HERE);
263                 return;
264         }
265
266         if (IsEmptyStr(filename)) {
267                 cprintf("%d You must specify a file name.\n",
268                         ERROR + FILE_NOT_FOUND);
269                 return;
270         }
271
272         if (CC->download_fp != NULL) {
273                 cprintf("%d You already have a download file open.\n",
274                         ERROR + RESOURCE_BUSY);
275                 return;
276         }
277
278         for (a = 0; !IsEmptyStr(&filename[a]); ++a) {
279                 if ( (filename[a] == '/') || (filename[a] == '\\') ) {
280                         filename[a] = '_';
281                 }
282         }
283
284         snprintf(pathname, sizeof pathname,
285                          "%s/%s/%s",
286                          ctdl_file_dir,
287                          CC->room.QRdirname, filename);
288         CC->download_fp = fopen(pathname, "r");
289
290         if (CC->download_fp == NULL) {
291                 cprintf("%d cannot open %s: %s\n",
292                         ERROR + INTERNAL_ERROR, pathname, strerror(errno));
293                 return;
294         }
295
296         OpenCmdResult(filename, "application/octet-stream");
297 }
298
299 /*
300  * open an image file
301  */
302 void cmd_oimg(char *cmdbuf)
303 {
304         char filename[256];
305         char pathname[PATH_MAX];
306         char MimeTestBuf[32];
307         struct ctdluser usbuf;
308         char which_user[USERNAME_SIZE];
309         int which_floor;
310         int a;
311         int rv;
312
313         extract_token(filename, cmdbuf, 0, '|', sizeof filename);
314
315         if (IsEmptyStr(filename)) {
316                 cprintf("%d You must specify a file name.\n",
317                         ERROR + FILE_NOT_FOUND);
318                 return;
319         }
320
321         if (CC->download_fp != NULL) {
322                 cprintf("%d You already have a download file open.\n",
323                         ERROR + RESOURCE_BUSY);
324                 return;
325         }
326
327         if (!strcasecmp(filename, "_userpic_")) {
328                 extract_token(which_user, cmdbuf, 1, '|', sizeof which_user);
329                 if (CtdlGetUser(&usbuf, which_user) != 0) {
330                         cprintf("%d No such user.\n",
331                                 ERROR + NO_SUCH_USER);
332                         return;
333                 }
334                 snprintf(pathname, sizeof pathname, 
335                                  "%s/%ld",
336                                  ctdl_usrpic_dir,
337                                  usbuf.usernum);
338         } else if (!strcasecmp(filename, "_floorpic_")) {
339                 which_floor = extract_int(cmdbuf, 1);
340                 snprintf(pathname, sizeof pathname,
341                                  "%s/floor.%d",
342                                  ctdl_image_dir, which_floor);
343         } else if (!strcasecmp(filename, "_roompic_")) {
344                 assoc_file_name(pathname, sizeof pathname, &CC->room, ctdl_image_dir);
345         } else {
346                 for (a = 0; !IsEmptyStr(&filename[a]); ++a) {
347                         filename[a] = tolower(filename[a]);
348                         if ( (filename[a] == '/') || (filename[a] == '\\') ) {
349                                 filename[a] = '_';
350                         }
351                 }
352                 snprintf(pathname, sizeof pathname,
353                                  "%s/%s",
354                                  ctdl_image_dir,
355                                  filename);
356         }
357
358         CC->download_fp = fopen(pathname, "rb");
359         if (CC->download_fp == NULL) {
360                 strcat(pathname, ".gif");
361                 CC->download_fp = fopen(pathname, "rb");
362         }
363         if (CC->download_fp == NULL) {
364                 cprintf("%d Cannot open %s: %s\n",
365                         ERROR + FILE_NOT_FOUND, pathname, strerror(errno));
366                 return;
367         }
368         rv = fread(&MimeTestBuf[0], 1, 32, CC->download_fp);
369         rewind (CC->download_fp);
370         OpenCmdResult(pathname, GuessMimeType(&MimeTestBuf[0], 32));
371 }
372
373 /*
374  * open a file for uploading
375  */
376 void cmd_uopn(char *cmdbuf)
377 {
378         int a;
379
380         extract_token(CC->upl_file, cmdbuf, 0, '|', sizeof CC->upl_file);
381         extract_token(CC->upl_mimetype, cmdbuf, 1, '|', sizeof CC->upl_mimetype);
382         extract_token(CC->upl_comment, cmdbuf, 2, '|', sizeof CC->upl_comment);
383
384         if (CtdlAccessCheck(ac_logged_in)) return;
385
386         if ((CC->room.QRflags & QR_DIRECTORY) == 0) {
387                 cprintf("%d No directory in this room.\n",
388                         ERROR + NOT_HERE);
389                 return;
390         }
391
392         if (IsEmptyStr(CC->upl_file)) {
393                 cprintf("%d You must specify a file name.\n",
394                         ERROR + FILE_NOT_FOUND);
395                 return;
396         }
397
398         if (CC->upload_fp != NULL) {
399                 cprintf("%d You already have a upload file open.\n",
400                         ERROR + RESOURCE_BUSY);
401                 return;
402         }
403
404         for (a = 0; !IsEmptyStr(&CC->upl_file[a]); ++a) {
405                 if ( (CC->upl_file[a] == '/') || (CC->upl_file[a] == '\\') ) {
406                         CC->upl_file[a] = '_';
407                 }
408         }
409         snprintf(CC->upl_path, sizeof CC->upl_path, 
410                          "%s/%s/%s",
411                          ctdl_file_dir,
412                          CC->room.QRdirname, CC->upl_file);
413         snprintf(CC->upl_filedir, sizeof CC->upl_filedir,
414                          "%s/%s/filedir", 
415                          ctdl_file_dir,
416                          CC->room.QRdirname);
417
418         CC->upload_fp = fopen(CC->upl_path, "r");
419         if (CC->upload_fp != NULL) {
420                 fclose(CC->upload_fp);
421                 CC->upload_fp = NULL;
422                 cprintf("%d '%s' already exists\n",
423                         ERROR + ALREADY_EXISTS, CC->upl_path);
424                 return;
425         }
426
427         CC->upload_fp = fopen(CC->upl_path, "wb");
428         if (CC->upload_fp == NULL) {
429                 cprintf("%d Cannot open %s: %s\n",
430                         ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
431                 return;
432         }
433         cprintf("%d Ok\n", CIT_OK);
434 }
435
436
437
438 /*
439  * open an image file for uploading
440  */
441 void cmd_uimg(char *cmdbuf)
442 {
443         int is_this_for_real;
444         char basenm[256];
445         int which_floor;
446         int a;
447
448         if (num_parms(cmdbuf) < 2) {
449                 cprintf("%d Usage error.\n", ERROR + ILLEGAL_VALUE);
450                 return;
451         }
452
453         is_this_for_real = extract_int(cmdbuf, 0);
454         extract_token(CC->upl_mimetype, cmdbuf, 1, '|', sizeof CC->upl_mimetype);
455         extract_token(basenm, cmdbuf, 2, '|', sizeof basenm);
456         if (CC->upload_fp != NULL) {
457                 cprintf("%d You already have an upload file open.\n",
458                         ERROR + RESOURCE_BUSY);
459                 return;
460         }
461
462         strcpy(CC->upl_path, "");
463
464         for (a = 0; !IsEmptyStr(&basenm[a]); ++a) {
465                 basenm[a] = tolower(basenm[a]);
466                 if ( (basenm[a] == '/') || (basenm[a] == '\\') ) {
467                         basenm[a] = '_';
468                 }
469         }
470
471         if (CC->user.axlevel >= 6) {
472                 snprintf(CC->upl_path, sizeof CC->upl_path, 
473                                  "%s/%s",
474                                  ctdl_image_dir,
475                                  basenm);
476         }
477
478         if (!strcasecmp(basenm, "_userpic_")) {
479                 snprintf(CC->upl_path, sizeof CC->upl_path,
480                                  "%s/%ld.gif",
481                                  ctdl_usrpic_dir,
482                                  CC->user.usernum);
483         }
484
485         if ((!strcasecmp(basenm, "_floorpic_"))
486             && (CC->user.axlevel >= 6)) {
487                 which_floor = extract_int(cmdbuf, 2);
488                 snprintf(CC->upl_path, sizeof CC->upl_path,
489                                  "%s/floor.%d.gif",
490                                  ctdl_image_dir,
491                                  which_floor);
492         }
493
494         if ((!strcasecmp(basenm, "_roompic_")) && (is_room_aide())) {
495                 assoc_file_name(CC->upl_path, sizeof CC->upl_path, &CC->room, ctdl_image_dir);
496         }
497
498         if (IsEmptyStr(CC->upl_path)) {
499                 cprintf("%d Higher access required.\n",
500                         ERROR + HIGHER_ACCESS_REQUIRED);
501                 return;
502         }
503
504         if (is_this_for_real == 0) {
505                 cprintf("%d Ok to send image\n", CIT_OK);
506                 return;
507         }
508
509         CC->upload_fp = fopen(CC->upl_path, "wb");
510         if (CC->upload_fp == NULL) {
511                 cprintf("%d Cannot open %s: %s\n",
512                         ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
513                 return;
514         }
515         cprintf("%d Ok\n", CIT_OK);
516         CC->upload_type = UPL_IMAGE;
517 }
518
519
520 /*
521  * close the download file
522  */
523 void cmd_clos(char *cmdbuf)
524 {
525         char buf[256];
526
527         if (CC->download_fp == NULL) {
528                 cprintf("%d You don't have a download file open.\n",
529                         ERROR + RESOURCE_NOT_OPEN);
530                 return;
531         }
532
533         fclose(CC->download_fp);
534         CC->download_fp = NULL;
535
536         if (CC->dl_is_net == 1) {
537                 CC->dl_is_net = 0;
538                 snprintf(buf, sizeof buf, 
539                                  "%s/%s",
540                                  ctdl_netout_dir,
541                                  CC->net_node);
542                 unlink(buf);
543         }
544
545         cprintf("%d Ok\n", CIT_OK);
546 }
547
548
549 /*
550  * abort an upload
551  */
552 void abort_upl(struct CitContext *who)
553 {
554         if (who->upload_fp != NULL) {
555                 fclose(who->upload_fp);
556                 who->upload_fp = NULL;
557                 unlink(CC->upl_path);
558         }
559 }
560
561
562
563 /*
564  * close the upload file
565  */
566 void cmd_ucls(char *cmd)
567 {
568         FILE *fp;
569         char upload_notice[512];
570
571         if (CC->upload_fp == NULL) {
572                 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
573                 return;
574         }
575
576         fclose(CC->upload_fp);
577         CC->upload_fp = NULL;
578
579         if ((!strcasecmp(cmd, "1")) && (CC->upload_type != UPL_FILE)) {
580                 CC->upload_type = UPL_FILE;
581                 cprintf("%d Upload completed.\n", CIT_OK);
582
583                 /* FIXME ... here we need to trigger a network run */
584
585                 return;
586         }
587
588         if (!strcasecmp(cmd, "1")) {
589                 cprintf("%d File '%s' saved.\n", CIT_OK, CC->upl_path);
590                 fp = fopen(CC->upl_filedir, "a");
591                 if (fp == NULL) {
592                         fp = fopen(CC->upl_filedir, "w");
593                 }
594                 if (fp != NULL) {
595                         fprintf(fp, "%s %s %s\n", CC->upl_file,
596                                 CC->upl_mimetype,
597                                 CC->upl_comment);
598                         fclose(fp);
599                 }
600
601                 /* put together an upload notice */
602                 snprintf(upload_notice, sizeof upload_notice,
603                         "NEW UPLOAD: '%s'\n %s\n%s\n",
604                          CC->upl_file, 
605                          CC->upl_comment, 
606                          CC->upl_mimetype);
607                 quickie_message(CC->curr_user, NULL, NULL, CC->room.QRname,
608                                 upload_notice, 0, NULL);
609         } else {
610                 abort_upl(CC);
611                 cprintf("%d File '%s' aborted.\n", CIT_OK, CC->upl_path);
612         }
613 }
614
615
616
617 /*
618  * read from the download file
619  */
620 void cmd_read(char *cmdbuf)
621 {
622         long start_pos;
623         size_t bytes;
624         size_t actual_bytes;
625         char *buf = NULL;
626
627         start_pos = extract_long(cmdbuf, 0);
628         bytes = extract_int(cmdbuf, 1);
629
630         if (CC->download_fp == NULL) {
631                 cprintf("%d You don't have a download file open.\n",
632                         ERROR + RESOURCE_NOT_OPEN);
633                 return;
634         }
635
636         if (bytes > 100000) bytes = 100000;
637         buf = malloc(bytes + 1);
638
639         fseek(CC->download_fp, start_pos, 0);
640         actual_bytes = fread(buf, 1, bytes, CC->download_fp);
641         cprintf("%d %d\n", BINARY_FOLLOWS, (int)actual_bytes);
642         client_write(buf, actual_bytes);
643         free(buf);
644 }
645
646
647
648 /*
649  * write to the upload file
650  */
651 void cmd_writ(char *cmdbuf)
652 {
653         int bytes;
654         char *buf;
655         int rv;
656
657         unbuffer_output();
658
659         bytes = extract_int(cmdbuf, 0);
660
661         if (CC->upload_fp == NULL) {
662                 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
663                 return;
664         }
665
666         if (bytes > 100000) {
667                 cprintf("%d You may not write more than 100000 bytes.\n",
668                         ERROR + TOO_BIG);
669                 return;
670         }
671
672         cprintf("%d %d\n", SEND_BINARY, bytes);
673         buf = malloc(bytes + 1);
674         client_read(buf, bytes);
675         rv = fwrite(buf, bytes, 1, CC->upload_fp);
676         free(buf);
677 }
678
679
680
681
682 /*
683  * cmd_ndop() - open a network spool file for downloading
684  */
685 void cmd_ndop(char *cmdbuf)
686 {
687         char pathname[256];
688         struct stat statbuf;
689
690         if (IsEmptyStr(CC->net_node)) {
691                 cprintf("%d Not authenticated as a network node.\n",
692                         ERROR + NOT_LOGGED_IN);
693                 return;
694         }
695
696         if (CC->download_fp != NULL) {
697                 cprintf("%d You already have a download file open.\n",
698                         ERROR + RESOURCE_BUSY);
699                 return;
700         }
701
702         snprintf(pathname, sizeof pathname, 
703                          "%s/%s",
704                          ctdl_netout_dir,
705                          CC->net_node);
706
707         /* first open the file in append mode in order to create a
708          * zero-length file if it doesn't already exist 
709          */
710         CC->download_fp = fopen(pathname, "a");
711         if (CC->download_fp != NULL)
712                 fclose(CC->download_fp);
713
714         /* now open it */
715         CC->download_fp = fopen(pathname, "r");
716         if (CC->download_fp == NULL) {
717                 cprintf("%d cannot open %s: %s\n",
718                         ERROR + INTERNAL_ERROR, pathname, strerror(errno));
719                 return;
720         }
721
722
723         /* set this flag so other routines know that the download file
724          * currently open is a network spool file 
725          */
726         CC->dl_is_net = 1;
727
728         stat(pathname, &statbuf);
729         cprintf("%d %ld\n", CIT_OK, (long)statbuf.st_size);
730 }
731
732 /*
733  * cmd_nuop() - open a network spool file for uploading
734  */
735 void cmd_nuop(char *cmdbuf)
736 {
737         static int seq = 1;
738
739         if (IsEmptyStr(CC->net_node)) {
740                 cprintf("%d Not authenticated as a network node.\n",
741                         ERROR + NOT_LOGGED_IN);
742                 return;
743         }
744
745         if (CC->upload_fp != NULL) {
746                 cprintf("%d You already have an upload file open.\n",
747                         ERROR + RESOURCE_BUSY);
748                 return;
749         }
750
751         snprintf(CC->upl_path, sizeof CC->upl_path,
752                          "%s/%s.%04lx.%04x",
753                          ctdl_netin_dir,
754                          CC->net_node, 
755                          (long)getpid(), 
756                          ++seq);
757
758         CC->upload_fp = fopen(CC->upl_path, "r");
759         if (CC->upload_fp != NULL) {
760                 fclose(CC->upload_fp);
761                 CC->upload_fp = NULL;
762                 cprintf("%d '%s' already exists\n",
763                         ERROR + ALREADY_EXISTS, CC->upl_path);
764                 return;
765         }
766
767         CC->upload_fp = fopen(CC->upl_path, "w");
768         if (CC->upload_fp == NULL) {
769                 cprintf("%d Cannot open %s: %s\n",
770                         ERROR + INTERNAL_ERROR, CC->upl_path, strerror(errno));
771                 return;
772         }
773
774         CC->upload_type = UPL_NET;
775         cprintf("%d Ok\n", CIT_OK);
776 }
777
778
779 /*****************************************************************************/
780 /*                      MODULE INITIALIZATION STUFF                          */
781 /*****************************************************************************/
782
783 CTDL_MODULE_INIT(file_ops)
784 {
785         CtdlRegisterProtoHook(cmd_delf, "DELF", "Autoconverted. TODO: document me.");
786         CtdlRegisterProtoHook(cmd_movf, "MOVF", "Autoconverted. TODO: document me.");
787         CtdlRegisterProtoHook(cmd_open, "OPEN", "Autoconverted. TODO: document me.");
788         CtdlRegisterProtoHook(cmd_clos, "CLOS", "Autoconverted. TODO: document me.");
789         CtdlRegisterProtoHook(cmd_uopn, "UOPN", "Autoconverted. TODO: document me.");
790         CtdlRegisterProtoHook(cmd_ucls, "UCLS", "Autoconverted. TODO: document me.");
791         CtdlRegisterProtoHook(cmd_read, "READ", "Autoconverted. TODO: document me.");
792         CtdlRegisterProtoHook(cmd_writ, "WRIT", "Autoconverted. TODO: document me.");
793         CtdlRegisterProtoHook(cmd_oimg, "OIMG", "Autoconverted. TODO: document me.");
794         CtdlRegisterProtoHook(cmd_ndop, "NDOP", "Autoconverted. TODO: document me.");
795         CtdlRegisterProtoHook(cmd_nuop, "NUOP", "Autoconverted. TODO: document me.");
796         CtdlRegisterProtoHook(cmd_uimg, "UIMG", "Autoconverted. TODO: document me.");
797         /* return our Subversion id for the Log */
798         return "$Id$";
799 }