Initial revision
[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 "proto.h"
14
15 void cmd_delf(char *filename)
16 {
17         char pathname[64];
18         int a;
19
20         if (!(CC->logged_in)) {
21                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
22                 return;
23                 }
24
25         if (!is_room_aide()) {
26                 cprintf("%d Higher access required.\n",
27                         ERROR+HIGHER_ACCESS_REQUIRED);
28                 return;
29                 }
30
31
32         if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
33                 cprintf("%d No directory in this room.\n",ERROR+NOT_HERE);
34                 return;
35                 }
36
37         if (strlen(filename)==0) {
38                 cprintf("%d You must specify a file name.\n",
39                         ERROR+FILE_NOT_FOUND);
40                 return;
41                 }
42         for (a=0; a<strlen(filename); ++a)
43                 if (filename[a]=='/') filename[a] = '_';
44         sprintf(pathname,"./files/%s/%s",CC->quickroom.QRdirname,filename);
45         a=unlink(pathname);
46         if (a==0) cprintf("%d File '%s' deleted.\n",OK,pathname);
47         else cprintf("%d File '%s' not found.\n",ERROR+FILE_NOT_FOUND,pathname);
48         }
49
50
51
52
53 /*
54  * move a file from one room directory to another
55  */
56 void cmd_movf(char *cmdbuf)
57 {
58         char filename[256];
59         char pathname[256];
60         char newpath[256];
61         char newroom[256];
62         char buf[256];
63         FILE *fp;
64         int a;
65         int target_room = (-1);
66         struct quickroom qrbuf;
67
68         extract(filename,cmdbuf,0);
69         extract(newroom,cmdbuf,1);
70
71         if (!(CC->logged_in)) {
72                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
73                 return;
74                 }
75
76         if (!is_room_aide()) {
77                 cprintf("%d Higher access required.\n",
78                         ERROR+HIGHER_ACCESS_REQUIRED);
79                 return;
80                 }
81
82         if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
83                 cprintf("%d No directory in this room.\n",ERROR+NOT_HERE);
84                 return;
85                 }
86
87         if (strlen(filename)==0) {
88                 cprintf("%d You must specify a file name.\n",
89                         ERROR+FILE_NOT_FOUND);
90                 return;
91                 }
92
93         for (a=0; a<strlen(filename); ++a)
94                 if (filename[a]=='/') filename[a] = '_';
95         sprintf(pathname,"./files/%s/%s",CC->quickroom.QRdirname,filename);
96         if (access(pathname,0)!=0) {
97                 cprintf("%d File '%s' not found.\n",
98                         ERROR+FILE_NOT_FOUND,pathname);
99                 return;
100                 }
101
102         for (a=0; a<MAXROOMS; ++a) {
103                 getroom(&qrbuf,a);
104                 if (!strucmp(qrbuf.QRname,newroom)) target_room = a;
105                 }
106         if (target_room < 0) {
107                 cprintf("%d Room '%s' not found.\n",
108                         ERROR+ROOM_NOT_FOUND,newroom);
109                 return;
110                 }
111         getroom(&qrbuf, target_room);
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         long 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() {
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         sprintf(pathname,"./files/%s/%s",CC->quickroom.QRdirname,filename);
267         CC->download_fp = fopen(pathname,"r");
268
269         if (CC->download_fp==NULL) {
270                 cprintf("%d cannot open %s: %s\n",
271                         ERROR,pathname,strerror(errno));
272                 return;
273                 }
274
275         OpenCmdResult();
276         }
277
278 /*
279  * open an image file
280  */
281 void cmd_oimg(char *cmdbuf)
282 {
283         char filename[256];
284         char pathname[256];
285         struct usersupp usbuf;
286         char which_user[32];
287         int which_floor;
288         int a;
289
290         extract(filename,cmdbuf,0);
291
292         if (strlen(filename)==0) {
293                 cprintf("%d You must specify a file name.\n",
294                         ERROR+FILE_NOT_FOUND);
295                 return;
296                 }
297
298         if (CC->download_fp != NULL) {
299                 cprintf("%d You already have a download file open.\n",ERROR);
300                 return;
301                 }
302
303         if (!strucmp(filename, "_userpic_")) {
304                 extract(which_user, cmdbuf, 1);
305                 if (getuser(&usbuf, which_user) != 0) {
306                         cprintf("%d No such user.\n", ERROR+NO_SUCH_USER);
307                         return;
308                         }
309                 sprintf(pathname, "./userpics/%ld.gif", usbuf.usernum);
310                 }
311         else if (!strucmp(filename, "_floorpic_")) {
312                 which_floor = extract_int(cmdbuf, 1);
313                 sprintf(pathname, "./images/floor.%d.gif", which_floor);
314                 }
315         else if (!strucmp(filename, "_roompic_")) {
316                 sprintf(pathname, "./images/room.%d.gif", CC->curr_rm);
317                 }
318         else {
319                 for (a=0; a<strlen(filename); ++a) {
320                         filename[a] = tolower(filename[a]);
321                         if (filename[a]=='/') filename[a] = '_';
322                         }
323                 sprintf(pathname,"./images/%s.gif",filename);
324                 }
325         
326         CC->download_fp = fopen(pathname,"r");
327         if (CC->download_fp == NULL) {
328                 cprintf("%d Cannot open %s: %s\n",
329                         ERROR+FILE_NOT_FOUND,pathname,strerror(errno));
330                 return;
331                 }
332         
333         OpenCmdResult();
334         }
335
336 /*
337  * open a file for uploading
338  */
339 void cmd_uopn(char *cmdbuf)
340 {
341         int a;
342
343         extract(CC->upl_file,cmdbuf,0);
344         extract(CC->upl_comment,cmdbuf,1);
345
346         if (!(CC->logged_in)) {
347                 cprintf("%d Not logged in.\n",ERROR+NOT_LOGGED_IN);
348                 return;
349                 }
350
351         if ((CC->quickroom.QRflags & QR_DIRECTORY) == 0) {
352                 cprintf("%d No directory in this room.\n",ERROR+NOT_HERE);
353                 return;
354                 }
355
356         if (strlen(CC->upl_file)==0) {
357                 cprintf("%d You must specify a file name.\n",
358                         ERROR+FILE_NOT_FOUND);
359                 return;
360                 }
361
362         if (CC->upload_fp != NULL) {
363                 cprintf("%d You already have a upload file open.\n",ERROR);
364                 return;
365                 }
366
367         for (a=0; a<strlen(CC->upl_file); ++a)
368                 if (CC->upl_file[a]=='/') CC->upl_file[a] = '_';
369         sprintf(CC->upl_path,"./files/%s/%s",CC->quickroom.QRdirname,CC->upl_file);
370         sprintf(CC->upl_filedir,"./files/%s/filedir",CC->quickroom.QRdirname);
371         
372         CC->upload_fp = fopen(CC->upl_path,"r");
373         if (CC->upload_fp != NULL) {
374                 fclose(CC->upload_fp);
375                 CC->upload_fp = NULL;
376                 cprintf("%d '%s' already exists\n",
377                         ERROR+ALREADY_EXISTS,CC->upl_path);
378                 return;
379                 }
380
381         CC->upload_fp = fopen(CC->upl_path,"wb");
382         if (CC->upload_fp == NULL) {
383                 cprintf("%d Cannot open %s: %s\n",
384                         ERROR,CC->upl_path,strerror(errno));
385                 return;
386                 }
387         cprintf("%d Ok\n",OK);
388         }
389
390
391
392 /*
393  * open an image file for uploading
394  */
395 void cmd_uimg(char *cmdbuf)
396 {
397         int is_this_for_real;
398         char basenm[256];
399         int which_floor;
400         int a;
401
402         if (num_parms(cmdbuf) < 2) {
403                 cprintf("%d Usage error.\n", ERROR);
404                 return;
405                 }
406
407         is_this_for_real = extract_int(cmdbuf,0);       
408         extract(basenm, cmdbuf, 1);
409         if (CC->upload_fp != NULL) {
410                 cprintf("%d You already have an upload file open.\n", ERROR);
411                 return;
412                 }
413
414         strcpy(CC->upl_path, "");
415
416         for (a=0; a<strlen(basenm); ++a) {
417                 basenm[a] = tolower(basenm[a]);
418                 if (basenm[a]=='/') basenm[a] = '_';
419                 }
420
421         if (CC->usersupp.axlevel >= 6) {
422                 sprintf(CC->upl_path, "./images/%s", basenm);
423                 }
424
425         if (!strucmp(basenm, "_userpic_")) {
426                 sprintf(CC->upl_path, "./userpics/%ld.gif",
427                         CC->usersupp.usernum);
428                 }
429
430         if ( (!strucmp(basenm, "_floorpic_")) && (CC->usersupp.axlevel >= 6) ) {
431                 which_floor = extract_int(cmdbuf, 2);
432                 sprintf(CC->upl_path, "./images/floor.%d.gif", which_floor);
433                 }
434
435         if ( (!strucmp(basenm, "_roompic_")) && (is_room_aide()) ) {
436                 sprintf(CC->upl_path, "./images/room.%d.gif", CC->curr_rm);
437                 }
438
439         if (strlen(CC->upl_path) == 0) {
440                 cprintf("%d Higher access required.\n",
441                         ERROR+HIGHER_ACCESS_REQUIRED);
442                 return;
443                 }
444
445         if (is_this_for_real == 0) {
446                 cprintf("%d Ok to send image\n", OK);
447                 return;
448                 }
449
450         CC->upload_fp = fopen(CC->upl_path,"wb");
451         if (CC->upload_fp == NULL) {
452                 cprintf("%d Cannot open %s: %s\n",
453                         ERROR,CC->upl_path,strerror(errno));
454                 return;
455                 }
456         cprintf("%d Ok\n",OK);
457         CC->upload_type = UPL_IMAGE;
458         }
459
460
461 /*
462  * close the download file
463  */
464 void cmd_clos(void) {
465         char buf[256];
466         
467         if (CC->download_fp == NULL) {
468                 cprintf("%d You don't have a download file open.\n",ERROR);
469                 return;
470                 }
471
472         fclose(CC->download_fp);
473         CC->download_fp = NULL;
474
475         if (CC->dl_is_net == 1) {
476                 CC->dl_is_net = 0;
477                 sprintf(buf,"%s/network/spoolout/%s",BBSDIR,CC->net_node);
478                 unlink(buf);
479                 }
480
481         cprintf("%d Ok\n",OK);
482         }
483
484
485 /*
486  * abort and upload
487  */
488 void abort_upl(struct CitContext *who)
489 {
490         if (who->upload_fp != NULL) {
491                 fclose(who->upload_fp);
492                 who->upload_fp = NULL;
493                 unlink(CC->upl_path);
494                 }
495         }
496
497
498
499 /*
500  * close the upload file
501  */
502 void cmd_ucls(char *cmd)
503 {
504         FILE *fp;
505         long now;
506         
507         if (CC->upload_fp == NULL) {
508                 cprintf("%d You don't have an upload file open.\n",ERROR);
509                 return;
510                 }
511
512         fclose(CC->upload_fp);
513         CC->upload_fp = NULL;
514
515         if ((!strucmp(cmd,"1")) && (CC->upload_type != UPL_FILE)) {
516                 CC->upload_type = UPL_FILE;
517                 cprintf("%d Upload completed.\n", OK);
518                 return;
519                 }
520
521         if (!strucmp(cmd,"1")) {
522                 cprintf("%d File '%s' saved.\n",OK,CC->upl_path);
523                 fp = fopen(CC->upl_filedir,"a");
524                 if (fp==NULL) fp=fopen(CC->upl_filedir,"w");
525                 if (fp!=NULL) {
526                         fprintf(fp,"%s %s\n",CC->upl_file,CC->upl_comment);
527                         fclose(fp);
528                         }
529
530                 /* put together an upload notice */
531                 time(&now);
532                 fp=fopen(CC->temp,"wb");
533                 putc(255,fp);
534                 putc(MES_NORMAL,fp);
535                 putc(0,fp);
536                 fprintf(fp,"Pcit%ld",CC->usersupp.usernum); putc(0,fp);
537                 fprintf(fp,"T%ld",now); putc(0,fp);
538                 fprintf(fp,"A%s",CC->curr_user); putc(0,fp);
539                 fprintf(fp,"O%s",CC->quickroom.QRname); putc(0,fp);
540                 fprintf(fp,"N%s",NODENAME); putc(0,fp); putc('M',fp);
541                 fprintf(fp,"NEW UPLOAD: '%s'\n %s\n",CC->upl_file,CC->upl_comment);
542                 putc(0,fp);
543                 fclose(fp);
544                 save_message(CC->temp, "", 0, M_LOCAL, 1);
545
546                 }
547         else {
548                 abort_upl(CC);
549                 cprintf("%d File '%s' aborted.\n",OK,CC->upl_path);
550                 }
551         }
552
553 /*
554  * read from the download file
555  */
556 void cmd_read(char *cmdbuf)
557 {
558         long start_pos;
559         int bytes;
560         char buf[4096];
561
562         start_pos = extract_long(cmdbuf,0);
563         bytes = extract_int(cmdbuf,1);
564         
565         if (CC->download_fp == NULL) {
566                 cprintf("%d You don't have a download file open.\n",ERROR);
567                 return;
568                 }
569
570         if (bytes > 4096) {
571                 cprintf("%d You may not read more than 4096 bytes.\n",ERROR);
572                 return;
573                 }
574
575         if (CC->dl_is_net) if (bytes>64) bytes = 64; /**** FIX ****/
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         if (CC->upload_type==UPL_NET) if (bytes > 64) bytes = 64; /*** FIX ***/
606
607         cprintf("%d %d\n",SEND_BINARY,bytes);
608         client_read(buf, bytes);
609         fwrite(buf,bytes,1,CC->upload_fp);
610         }
611
612
613
614 /*
615  * cmd_netp() - identify as network poll session
616  */
617 void cmd_netp(char *cmdbuf)
618 {
619         char buf[256];
620         
621         extract(buf,cmdbuf,1);
622         if (strucmp(buf,config.c_net_password)) {
623                 cprintf("%d authentication failed\n",ERROR);
624                 return;
625                 }
626         extract(CC->net_node,cmdbuf,0);
627         cprintf("%d authenticated as network node '%s'\n",OK,CC->net_node);
628         }
629
630 /*
631  * cmd_ndop() - open a network spool file for downloading
632  */
633 void cmd_ndop(char *cmdbuf)
634 {
635         char pathname[256];
636         struct stat statbuf;
637
638         if (strlen(CC->net_node)==0) {
639                 cprintf("%d Not authenticated as a network node.\n",
640                         ERROR+NOT_LOGGED_IN);
641                 return;
642                 }
643
644         if (CC->download_fp != NULL) {
645                 cprintf("%d You already have a download file open.\n",ERROR);
646                 return;
647                 }
648
649         sprintf(pathname,"%s/network/spoolout/%s",BBSDIR,CC->net_node);
650
651         /* first open the file in append mode in order to create a
652          * zero-length file if it doesn't already exist 
653          */
654         CC->download_fp = fopen(pathname,"a");
655         fclose(CC->download_fp);
656
657         /* now open it */
658         CC->download_fp = fopen(pathname,"r");
659         if (CC->download_fp==NULL) {
660                 cprintf("%d cannot open %s: %s\n",
661                         ERROR,pathname,strerror(errno));
662                 return;
663                 }
664
665
666         /* set this flag so other routines know that the download file
667          * currently open is a network spool file 
668          */
669         CC->dl_is_net = 1;
670
671         stat(pathname,&statbuf);
672         cprintf("%d %ld\n",OK,statbuf.st_size);
673         }
674
675 /*
676  * cmd_nuop() - open a network spool file for uploading
677  */
678 void cmd_nuop(char *cmdbuf)
679 {
680         if (strlen(CC->net_node)==0) {
681                 cprintf("%d Not authenticated as a network node.\n",
682                         ERROR+NOT_LOGGED_IN);
683                 return;
684                 }
685
686         if (CC->upload_fp != NULL) {
687                 cprintf("%d You already have an upload file open.\n",ERROR);
688                 return;
689                 }
690
691         sprintf(CC->upl_path,"%s/network/spoolin/%s.%d",
692                 BBSDIR,CC->net_node,getpid());
693
694         CC->upload_fp = fopen(CC->upl_path,"r");
695         if (CC->upload_fp != NULL) {
696                 fclose(CC->upload_fp);
697                 CC->upload_fp = NULL;
698                 cprintf("%d '%s' already exists\n",
699                         ERROR+ALREADY_EXISTS,CC->upl_path);
700                 return;
701                 }
702
703         CC->upload_fp = fopen(CC->upl_path,"w");
704         if (CC->upload_fp == NULL) {
705                 cprintf("%d Cannot open %s: %s\n",
706                         ERROR,CC->upl_path,strerror(errno));
707                 return;
708                 }
709
710         CC->upload_type = UPL_NET;
711         cprintf("%d Ok\n",OK);
712         }