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