* partialy revert r8246; we're working in units of one here, so the number of units...
[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(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
641         actual_bytes = fread(buf, 1, bytes, CC->download_fp);
642         if (actual_bytes > 0) {
643                 cprintf("%d %d\n", BINARY_FOLLOWS, (int)actual_bytes);
644                 client_write(buf, bytes);
645         }
646         else {
647                 cprintf("%d %s\n", ERROR, strerror(errno));
648         }
649         free(buf);
650 }
651
652
653
654 /*
655  * write to the upload file
656  */
657 void cmd_writ(char *cmdbuf)
658 {
659         int bytes;
660         char *buf;
661         int rv;
662
663         unbuffer_output();
664
665         bytes = extract_int(cmdbuf, 0);
666
667         if (CC->upload_fp == NULL) {
668                 cprintf("%d You don't have an upload file open.\n", ERROR + RESOURCE_NOT_OPEN);
669                 return;
670         }
671
672         if (bytes > 100000) {
673                 cprintf("%d You may not write more than 100000 bytes.\n",
674                         ERROR + TOO_BIG);
675                 return;
676         }
677
678         cprintf("%d %d\n", SEND_BINARY, bytes);
679         buf = malloc(bytes + 1);
680         client_read(buf, bytes);
681         rv = fwrite(buf, bytes, 1, CC->upload_fp);
682         free(buf);
683 }
684
685
686
687
688 /*
689  * cmd_ndop() - open a network spool file for downloading
690  */
691 void cmd_ndop(char *cmdbuf)
692 {
693         char pathname[256];
694         struct stat statbuf;
695
696         if (IsEmptyStr(CC->net_node)) {
697                 cprintf("%d Not authenticated as a network node.\n",
698                         ERROR + NOT_LOGGED_IN);
699                 return;
700         }
701
702         if (CC->download_fp != NULL) {
703                 cprintf("%d You already have a download file open.\n",
704                         ERROR + RESOURCE_BUSY);
705                 return;
706         }
707
708         snprintf(pathname, sizeof pathname, 
709                          "%s/%s",
710                          ctdl_netout_dir,
711                          CC->net_node);
712
713         /* first open the file in append mode in order to create a
714          * zero-length file if it doesn't already exist 
715          */
716         CC->download_fp = fopen(pathname, "a");
717         if (CC->download_fp != NULL)
718                 fclose(CC->download_fp);
719
720         /* now open it */
721         CC->download_fp = fopen(pathname, "r");
722         if (CC->download_fp == NULL) {
723                 cprintf("%d cannot open %s: %s\n",
724                         ERROR + INTERNAL_ERROR, pathname, strerror(errno));
725                 return;
726         }
727
728
729         /* set this flag so other routines know that the download file
730          * currently open is a network spool file 
731          */
732         CC->dl_is_net = 1;
733
734         stat(pathname, &statbuf);
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_netin_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                 CtdlRegisterProtoHook(cmd_delf, "DELF", "Autoconverted. TODO: document me.");
793                 CtdlRegisterProtoHook(cmd_movf, "MOVF", "Autoconverted. TODO: document me.");
794                 CtdlRegisterProtoHook(cmd_open, "OPEN", "Autoconverted. TODO: document me.");
795                 CtdlRegisterProtoHook(cmd_clos, "CLOS", "Autoconverted. TODO: document me.");
796                 CtdlRegisterProtoHook(cmd_uopn, "UOPN", "Autoconverted. TODO: document me.");
797                 CtdlRegisterProtoHook(cmd_ucls, "UCLS", "Autoconverted. TODO: document me.");
798                 CtdlRegisterProtoHook(cmd_read, "READ", "Autoconverted. TODO: document me.");
799                 CtdlRegisterProtoHook(cmd_writ, "WRIT", "Autoconverted. TODO: document me.");
800                 CtdlRegisterProtoHook(cmd_oimg, "OIMG", "Autoconverted. TODO: document me.");
801                 CtdlRegisterProtoHook(cmd_ndop, "NDOP", "Autoconverted. TODO: document me.");
802                 CtdlRegisterProtoHook(cmd_nuop, "NUOP", "Autoconverted. TODO: document me.");
803                 CtdlRegisterProtoHook(cmd_uimg, "UIMG", "Autoconverted. TODO: document me.");
804         }
805         /* return our Subversion id for the Log */
806         return "$Id$";
807 }