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