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