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