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