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