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