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