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