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