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