8519a918ddd319787d0b05c31a619df118460644
[citadel.git] / citadel / routines2.c
1 /* More Citadel/UX routines...
2  * unlike routines.c, some of these DO use global variables.
3  * $Id$
4  */
5
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <ctype.h>
13 #include <string.h>
14 #include <time.h>
15 #include <signal.h>
16 #include <pwd.h>
17 #include <setjmp.h>
18 #include <errno.h>
19 #include "citadel.h"
20 #include "routines2.h"
21 #include "routines.h"
22 #include "commands.h"
23 #include "tools.h"
24 #include "messages.h"
25
26 void interr(int errnum);
27 void strprompt(char *prompt, char *str, int len);
28 void newprompt(char *prompt, char *str, int len);
29 void sttybbs(int cmd);
30 int inkey(void);
31 void serv_write(char *buf, int nbytes);
32 void extract(char *dest, char *source, int parmnum);
33 int haschar(char *st, int ch);
34 void progress(long int curr, long int cmax);
35 void citedit(FILE *fp, long int base_pos);
36 int yesno(void);
37
38 extern char temp[];
39 extern char tempdir[];
40 extern char *axdefs[7];
41 extern long highest_msg_read;
42 extern long maxmsgnum;
43 extern unsigned room_flags;
44 extern int screenwidth;
45
46
47 int eopen(char *name, int mode)
48 {
49         int ret;
50         ret = open(name,mode);
51         if (ret<0) {
52                 fprintf(stderr,"Cannot open file '%s', mode=%d, errno=%d\n",
53                         name,mode,errno);
54                 interr(errno);
55                 }
56         return(ret);
57         }
58
59
60 int room_prompt(int qrflags)    /* return proper room prompt character */
61              {
62         int a;
63         a='>';
64         if (qrflags&QR_DIRECTORY) a=']';
65         if ((a==']')&&(qrflags&QR_NETWORK)) a='}';
66         if ((a=='>')&&(qrflags&QR_NETWORK)) a=')';
67         return(a);
68         }
69
70 void entregis(void)     /* register with name and address */
71         {
72
73         char buf[256];
74         char tmpname[256];
75         char tmpaddr[256];
76         char tmpcity[256];
77         char tmpstate[256];
78         char tmpzip[256];
79         char tmpphone[256];
80         char tmpemail[256];
81         int a;
82
83         strcpy(tmpname,"");
84         strcpy(tmpaddr,"");
85         strcpy(tmpcity,"");
86         strcpy(tmpstate,"");
87         strcpy(tmpzip,"");
88         strcpy(tmpphone,"");
89         strcpy(tmpemail,"");
90
91         serv_puts("GREG _SELF_");
92         serv_gets(buf);
93         if (buf[0]=='1') {
94                 a = 0;
95                 while (serv_gets(buf), strcmp(buf,"000")) {
96                         if (a==2) strcpy(tmpname,buf);
97                         if (a==3) strcpy(tmpaddr,buf);
98                         if (a==4) strcpy(tmpcity,buf);
99                         if (a==5) strcpy(tmpstate,buf);
100                         if (a==6) strcpy(tmpzip,buf);
101                         if (a==7) strcpy(tmpphone,buf);
102                         if (a==9) strcpy(tmpemail,buf);
103                         ++a;
104                         }
105                 }
106
107         strprompt("REAL name",tmpname,29);
108         strprompt("Address",tmpaddr,24);
109         strprompt("City/town",tmpcity,14);
110         strprompt("State",tmpstate,2);
111         strprompt("ZIP Code",tmpzip,10);
112         strprompt("Telephone number",tmpphone,14);
113         strprompt("Email address",tmpemail,31);
114
115         /* now send the registration info back to the server */
116         serv_puts("REGI");
117         serv_gets(buf);
118         if (buf[0]!='4') {
119                 printf("%s\n",&buf[4]);
120                 return;
121                 }
122         serv_puts(tmpname);
123         serv_puts(tmpaddr);
124         serv_puts(tmpcity);
125         serv_puts(tmpstate);
126         serv_puts(tmpzip);
127         serv_puts(tmpphone);
128         serv_puts(tmpemail);
129         serv_puts("000");
130         printf("\n");
131         }
132
133 void updatels(void) {   /* make all messages old in current room */
134         char buf[256];
135         serv_puts("SLRP HIGHEST");
136         serv_gets(buf);
137         if (buf[0]!='2') printf("%s\n",&buf[4]);
138         }
139
140 void updatelsa(void) {   /* only make messages old in this room that have been read */
141         char buf[256];
142         sprintf(buf,"SLRP %ld",highest_msg_read);
143         serv_puts(buf);
144         serv_gets(buf);
145         if (buf[0]!='2') printf("%s\n",&buf[4]);
146         }
147
148
149 /*
150  * This routine completes a client upload
151  */
152 void do_upload(int fd) {
153         char buf[256];
154         char tbuf[4096];
155         long transmitted_bytes, total_bytes;
156         int bytes_to_send;
157         int bytes_expected;
158
159         /* learn the size of the file */
160         total_bytes = lseek(fd,0L,2);
161         lseek(fd,0L,0);
162
163         transmitted_bytes = 0L;
164         progress(transmitted_bytes,total_bytes);
165         do {
166                 bytes_to_send = read(fd,tbuf,4096);
167                 if (bytes_to_send>0) {
168                         sprintf(buf,"WRIT %d",bytes_to_send);
169                         serv_puts(buf);
170                         serv_gets(buf);
171                         if (buf[0]=='7') {
172                                 bytes_expected = atoi(&buf[4]);
173                                 serv_write(tbuf,bytes_expected);
174                                 }
175                         else {
176                                 printf("%s\n",&buf[4]);
177                                 }
178                         }
179                 transmitted_bytes = transmitted_bytes + (long)bytes_to_send;
180                 progress(transmitted_bytes, total_bytes);
181                 } while (bytes_to_send > 0);
182
183         /* close the upload file, locally and at the server */
184         close(fd);
185         serv_puts("UCLS 1");
186         serv_gets(buf);
187         printf("%s\n",&buf[4]);
188         }
189
190
191 /*
192  * client-based uploads (for users with their own clientware)
193  */
194 void cli_upload(void) {
195         char flnm[256];
196         char desc[151];
197         char buf[256];
198         char tbuf[256];
199         int a;
200         int fd;
201
202         if ((room_flags & QR_UPLOAD) == 0) {
203                 printf("*** You cannot upload to this room.\n");
204                 return;
205                 }
206
207         newprompt("File to be uploaded: ",flnm,55);
208         fd = open(flnm,O_RDONLY);
209         if (fd<0) {
210                 printf("Cannot open '%s': %s\n",flnm,strerror(errno));
211                 return;
212                 }
213         printf("Enter a description of this file:\n");
214         newprompt(": ",desc,75);
215
216         /* keep generating filenames in hope of finding a unique one */
217         a = 0;
218         do {
219                 if (a==10) return; /* fail if tried 10 times */
220                 strcpy(buf,flnm);
221                 while ((strlen(buf)>0)&&(haschar(buf,'/')))
222                         strcpy(buf,&buf[1]);
223                 if (a>0) sprintf(&buf[strlen(buf)],"%d",a);
224                 sprintf(tbuf,"UOPN %s|%s",buf,desc);
225                 serv_puts(tbuf);
226                 serv_gets(buf);
227                 if (buf[0]!='2') printf("%s\n",&buf[4]);
228                 ++a;
229                 } while (buf[0]!='2');
230
231         /* at this point we have an open upload file at the server */
232         do_upload(fd);
233         }
234
235
236 /*
237  * Function used for various image upload commands
238  */
239 void cli_image_upload(char *keyname) {
240         char flnm[256];
241         char buf[256];
242         int fd;
243
244         sprintf(buf, "UIMG 0|%s", keyname);
245         serv_puts(buf);
246         serv_gets(buf);
247         if (buf[0] != '2') {
248                 printf("%s\n", &buf[4]);
249                 return;
250                 }
251
252         newprompt("Image file to be uploaded: ",flnm,55);
253         fd = open(flnm,O_RDONLY);
254         if (fd<0) {
255                 printf("Cannot open '%s': %s\n",flnm,strerror(errno));
256                 return;
257                 }
258
259         sprintf(buf, "UIMG 1|%s", keyname);
260         serv_puts(buf);
261         serv_gets(buf);
262         if (buf[0] != '2') {
263                 printf("%s\n", &buf[4]);
264                 return;
265                 }
266
267         do_upload(fd);
268         }
269
270
271 /*
272  * protocol-based uploads (Xmodem, Ymodem, Zmodem)
273  */
274 void upload(int c)      /* c = upload mode */
275        {
276         char flnm[256];
277         char desc[151];
278         char buf[256];
279         char tbuf[4096];
280         int xfer_pid;
281         int a,b;
282         FILE *fp,*lsfp;
283         int fd;
284
285         if ((room_flags & QR_UPLOAD) == 0) {
286                 printf("*** You cannot upload to this room.\n");
287                 return;
288                 }
289
290         /* we don't need a filename when receiving batch y/z modem */
291         if ((c==2)||(c==3)) strcpy(flnm,"x");
292         else newprompt("Enter filename: ",flnm,15);
293
294         for (a=0; a<strlen(flnm); ++a)
295                 if ( (flnm[a]=='/') || (flnm[a]=='\\') || (flnm[a]=='>')
296                      || (flnm[a]=='?') || (flnm[a]=='*')
297                      || (flnm[a]==';') || (flnm[a]=='&') ) flnm[a]='_';
298
299         newprompt("Enter a short description of the file:\n: ",desc,150);
300
301         /* create a temporary directory... */
302         if (mkdir(tempdir,0700) != 0) {
303                 printf("*** Could not create temporary directory %s: %s\n",
304                         tempdir,strerror(errno));
305                 return;
306                 }
307
308         /* now do the transfer ... in a separate process */
309         xfer_pid = fork();
310         if (xfer_pid == 0) {
311             chdir(tempdir);
312             switch(c) {
313                 case 0:
314                         sttybbs(0);
315                         printf("Receiving %s - press Ctrl-D to end.\n",flnm);
316                         fp = fopen(flnm,"w");
317                         do {
318                                 b=inkey(); 
319                                 if (b==13) {
320                                         b=10; printf("\r");
321                                         }
322                                 if (b!=4) {
323                                         printf("%c",b);
324                                         putc(b,fp);
325                                         }
326                                 } while(b!=4);
327                         fclose(fp);
328                         exit(0);
329                 case 1:
330                         sttybbs(3);
331                         execlp("rx","rx",flnm,NULL);
332                         exit(1);
333                 case 2:
334                         sttybbs(3);
335                         execlp("rb","rb",NULL);
336                         exit(1);
337                 case 3:
338                         sttybbs(3);
339                         execlp("rz","rz",NULL);
340                         exit(1);
341                         }
342                 }
343         else do {
344                 b=ka_wait(&a);
345                 } while ((b!=xfer_pid)&&(b!=(-1)));
346         sttybbs(0);
347
348         if (a != 0) {
349                 printf("\r*** Transfer unsuccessful.\n");
350                 nukedir(tempdir);
351                 return;
352                 }
353
354         printf("\r*** Transfer successful.  Sending file(s) to server...\n");
355         sprintf(buf,"cd %s; ls",tempdir);
356         lsfp = popen(buf,"r");
357         if (lsfp!=NULL) {
358                 while (fgets(flnm,256,lsfp)!=NULL) {
359                         flnm[strlen(flnm)-1] = 0;
360                         sprintf(buf,"%s/%s",tempdir,flnm);
361                         fd = open(buf,O_RDONLY);
362                         if (fd>=0) {
363                                 a = 0;
364                                 do {
365                                         sprintf(buf,"UOPN %s|%s",flnm,desc);
366                                         if (a>0) sprintf(&buf[strlen(buf)],
367                                                 ".%d",a);
368                                         ++a;
369                                         serv_puts(buf);
370                                         serv_gets(buf);
371                                         } while((buf[0]!='2')&&(a<100));
372                                 if (buf[0]=='2') do {
373                                         a=read(fd,tbuf,4096);
374                                         if (a>0) {
375                                                 sprintf(buf,"WRIT %d",a);
376                                                 serv_puts(buf);
377                                                 serv_gets(buf);
378                                                 if (buf[0]=='7')
379                                                         serv_write(tbuf,a);
380                                                 }
381                                         } while (a>0);
382                                 close(fd);
383                                 serv_puts("UCLS 1");
384                                 serv_gets(buf);
385                                 printf("%s\n",&buf[4]);
386                                 }
387                         }
388                 pclose(lsfp);
389                 }
390
391         nukedir(tempdir);
392         }
393
394 /* 
395  * validate a user
396  */
397 void val_user(char *user, int do_validate)
398 {
399         int a;
400         char cmd[256];
401         char buf[256];
402         int ax = 0;
403
404         sprintf(cmd, "GREG %s", user);
405         serv_puts(cmd);
406         serv_gets(cmd);
407         if (cmd[0]=='1') {
408                 a = 0;
409                 do {
410                         serv_gets(buf);
411                         ++a;
412                         if (a==1) printf("User #%s - %s  ", buf, &cmd[4]);
413                         if (a==2) printf("PW: %s\n",buf);
414                         if (a==3) printf("%s\n",buf);
415                         if (a==4) printf("%s\n",buf);
416                         if (a==5) printf("%s, ",buf);
417                         if (a==6) printf("%s ",buf);
418                         if (a==7) printf("%s\n",buf);
419                         if (a==8) printf("%s\n",buf);
420                         if (a==9) ax=atoi(buf);
421                         if (a==10) printf("%s\n",buf);
422                         } while(strcmp(buf,"000"));
423                 printf("Current access level: %d (%s)\n",ax,axdefs[ax]);
424                 }
425         else {
426                 printf("%-30s\n%s\n",user,&cmd[4]);
427                 }
428
429         if (do_validate) {
430                 /* now set the access level */
431                 ax = intprompt("Access level", ax, 0, 6);
432                 sprintf(cmd,"VALI %s|%d",user,ax);
433                 serv_puts(cmd);
434                 serv_gets(cmd);
435                 if (cmd[0]!='2') printf("%s\n",&cmd[4]);
436                 }
437         printf("\n");
438         }
439
440
441 void validate(void) {   /* validate new users */
442         char cmd[256];
443         char buf[256];
444         int finished = 0;
445
446         do {
447                 serv_puts("GNUR");
448                 serv_gets(cmd);
449                 if (cmd[0]!='3') finished = 1;
450                 if (cmd[0]=='2') printf("%s\n",&cmd[4]);
451                 if (cmd[0]=='3') {
452                         extract(buf, cmd, 0);
453                         val_user(&buf[4], 1);
454                         }
455                 } while(finished==0);
456         }
457
458 void subshell(void) {
459         int a,b;
460         a=fork();
461         if (a==0) {
462                 sttybbs(SB_RESTORE);
463                 signal(SIGINT,SIG_DFL);
464                 signal(SIGQUIT,SIG_DFL);
465                 execlp(getenv("SHELL"),getenv("SHELL"),NULL);
466                 printf("Could not open a shell: %s\n", strerror(errno));
467                 exit(errno);
468                 }
469         do {
470                 b=ka_wait(NULL);
471                 } while ((a!=b)&&(a!=(-1)));
472         sttybbs(0);
473         }
474
475 /*
476  * <.A>ide <F>ile <D>elete command
477  */
478 void deletefile(void) {
479         char filename[32];
480         char cmd[256];
481
482         newprompt("Filename: ",filename,31);
483         if (strlen(filename)==0) return;
484         sprintf(cmd,"DELF %s",filename);
485         serv_puts(cmd);
486         serv_gets(cmd);
487         printf("%s\n",&cmd[4]);
488         }
489
490 /*
491  * <.A>ide <F>ile <S>end command
492  */
493 void netsendfile(void) {
494         char filename[32],destsys[20],cmd[256];
495
496         newprompt("Filename: ",filename,31);
497         if (strlen(filename)==0) return;
498         newprompt("System to send to: ",destsys,19);
499         sprintf(cmd,"NETF %s|%s",filename,destsys);
500         serv_puts(cmd);
501         serv_gets(cmd);
502         printf("%s\n",&cmd[4]);
503         return;
504         }
505
506 /*
507  * <.A>ide <F>ile <M>ove command
508  */
509 void movefile(void) {
510         char filename[64];
511         char newroom[ROOMNAMELEN];
512         char cmd[256];
513
514         newprompt("Filename: ",filename,63);
515         if (strlen(filename)==0) return;
516         newprompt("Enter target room: ",newroom,ROOMNAMELEN-1);
517
518         sprintf(cmd,"MOVF %s|%s",filename,newroom);
519         serv_puts(cmd);
520         serv_gets(cmd);
521         printf("%s\n",&cmd[4]);
522         }
523
524
525 /* 
526  * list of users who have filled out a bio
527  */
528 void list_bio(void) {
529         char buf[256];
530         int pos = 1;
531
532         serv_puts("LBIO");
533         serv_gets(buf);
534         if (buf[0]!='1') {
535                 printf("%s\n",&buf[4]);
536                 return;
537                 }
538         while (serv_gets(buf), strcmp(buf,"000")) {
539                 if ((pos+strlen(buf)+5)>screenwidth) {
540                         printf("\n");
541                         pos = 1;
542                         }
543                 printf("%s, ",buf);
544                 pos = pos + strlen(buf) + 2;
545                 }
546         printf("%c%c  \n\n",8,8);
547         }
548
549
550 /*
551  * read bio
552  */
553 void read_bio(void) {
554         char who[256];
555         char buf[256];
556
557         do {
558                 newprompt("Read bio for who ('?' for list) : ",who,25);
559                 printf("\n");
560                 if (!strcmp(who,"?")) list_bio();
561                 } while(!strcmp(who,"?"));
562         sprintf(buf,"RBIO %s",who);
563         serv_puts(buf);
564         serv_gets(buf);
565         if (buf[0]!='1') {
566                 printf("%s\n",&buf[4]);
567                 return;
568                 }
569         while (serv_gets(buf), strcmp(buf,"000")) {
570                 printf("%s\n",buf);
571                 }
572         }
573
574
575 /* 
576  * General system configuration command
577  */
578 void do_system_configuration(void) {
579         char buf[256];
580         char sc[19][256];
581         int expire_mode = 0;
582         int expire_value = 0;
583         int a;
584
585         /* Clear out the config buffers */
586         memset(&sc[0][0], 0, sizeof(sc));
587
588         /* Fetch the current config */
589         serv_puts("CONF get");
590         serv_gets(buf);
591         if (buf[0] == '1') {
592                 a = 0;
593                 while (serv_gets(buf), strcmp(buf, "000")) {
594                         if (a<19) strcpy(&sc[a][0], buf);
595                         ++a;
596                         }
597                 }
598
599         /* Fetch the expire policy (this will silently fail on old servers,
600          * resulting in "default" policy)
601          */
602         serv_puts("GPEX site");
603         serv_gets(buf);
604         if (buf[0]=='2') {
605                 expire_mode = extract_int(&buf[4], 0);
606                 expire_value = extract_int(&buf[4], 1);
607                 }
608
609         strprompt("Node name", &sc[0][0], 15);
610         strprompt("Fully qualified domain name", &sc[1][0], 63);
611         strprompt("Human readable node name", &sc[2][0], 20);
612         strprompt("Modem dialup number", &sc[3][0], 15);
613
614         sprintf(&sc[4][0], "%d", (boolprompt(
615                 "Automatically give room aide privs to a user who creates a private room",
616                 atoi(&sc[4][0]))));
617
618         strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
619         strprompt("Initial access level for new users", &sc[6][0], 1);
620
621         sprintf(&sc[7][0], "%d", (boolprompt(
622                 "Require registration for new users",
623                 atoi(&sc[7][0]))));
624
625         sprintf(&sc[8][0], "%d", (boolprompt(
626                 "Automatically move problem user messages to twit room",
627                 atoi(&sc[8][0]))));
628
629         strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
630         strprompt("Paginator prompt", &sc[10][0], 79);
631
632         sprintf(&sc[11][0], "%d", (boolprompt(
633                 "Restrict Internet mail to only those with that privilege",
634                 atoi(&sc[11][0]))));
635
636         strprompt("Geographic location of this system", &sc[12][0], 31);
637         strprompt("Name of system administrator", &sc[13][0], 25);
638         strprompt("Maximum concurrent sessions", &sc[14][0], 4);
639         strprompt("Server-to-server networking password", &sc[15][0], 19);
640         strprompt("Default user purge time (days)", &sc[16][0], 5);
641         strprompt("Default room purge time (days)", &sc[17][0], 5);
642         strprompt("Name of room to log pages", &sc[18][0], ROOMNAMELEN);
643
644         /* Angels and demons dancing in my head... */
645         do {
646                 sprintf(buf, "%d", expire_mode);
647                 strprompt("System default message expire policy (? for list)",
648                         buf, 1);
649                 if (buf[0] == '?') {
650                         printf("\n");
651                         printf("1. Never automatically expire messages\n");
652                         printf("2. Expire by message count\n");
653                         printf("3. Expire by message age\n");
654                         }
655                 } while((buf[0]<49)||(buf[0]>51));
656         expire_mode = buf[0] - 48;
657
658         /* ...lunatics and monsters underneath my bed */
659         if (expire_mode == 2) {
660                 sprintf(buf, "%d", expire_value);
661                 strprompt("Keep how many messages online?", buf, 10);
662                 expire_value = atol(buf);
663                 }
664
665         if (expire_mode == 3) {
666                 sprintf(buf, "%d", expire_value);
667                 strprompt("Keep messages for how many days?", buf, 10);
668                 expire_value = atol(buf);
669                 }
670
671         /* Save it */
672         printf("Save this configuration? ");
673         if (yesno()) {
674                 serv_puts("CONF set");
675                 serv_gets(buf);
676                 if (buf[0] == '4') {
677                         for (a=0; a<19; ++a) serv_puts(&sc[a][0]);
678                         serv_puts("000");
679                         }
680
681                 snprintf(buf, sizeof buf, "SPEX site|%d|%d",
682                         expire_mode, expire_value);
683                 serv_puts(buf);
684                 serv_gets(buf);
685                 }
686         }