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