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