]> code.citadel.org Git - citadel.git/blob - citadel/routines.c
* Yanked the citadelapi.c module. This wasn't working out well.
[citadel.git] / citadel / routines.c
1 /* Citadel/UX support routines */
2
3 #include "sysdep.h"
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <ctype.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <sys/ioctl.h>
12 #include <pwd.h>
13 #include <signal.h>
14 #include <dirent.h>
15 #include <errno.h>
16
17
18 #define ROUTINES_C
19
20 #include "citadel.h"
21 #include "routines.h"
22
23 char inkey(void);
24 void sttybbs(int cmd);
25 void newprompt(char *prompt, char *str, int len);
26 void val_user(char *user);
27 int intprompt(char *prompt, int ival, int imin, int imax);
28 void formout(char *name);
29 void logoff(int code);
30 void set_keepalives(int s);
31 void strprompt(char *prompt, char *str, int len);
32 void newprompt(char *prompt, char *str, int len);
33 void color(int colornum);
34
35 #define IFAIDE if(axlevel>=6)
36 #define IFNAIDE if (axlevel<6)
37
38 extern unsigned userflags;
39 extern char *axdefs[7];
40 extern char sigcaught;
41 extern struct CtdlServInfo serv_info;
42 extern char rc_floor_mode;
43
44 int struncmp(char *lstr, char *rstr, int len)
45 {
46         int pos = 0;
47         char lc,rc;
48         while (pos<len) {
49                 lc=tolower(lstr[pos]);
50                 rc=tolower(rstr[pos]);
51                 if ((lc==0)&&(rc==0)) return(0);
52                 if (lc<rc) return(-1);
53                 if (lc>rc) return(1);
54                 pos=pos+1;
55                 }
56         return(0);
57         }
58
59
60 /* 
61  * check for the presence of a character within a string (returns count)
62  */
63 int haschar(char *st, int ch)
64 {
65         int a,b;
66         b=0;
67         for (a=0; a<strlen(st); ++a) if (st[a]==ch) ++b;
68         return(b);
69         }
70
71
72 /*
73  * num_parms()  -  discover number of parameters...
74  */
75 int num_parms(char *source)
76 {
77         int a;
78         int count = 1;
79
80         for (a=0; a<strlen(source); ++a) 
81                 if (source[a]=='|') ++count;
82         return(count);
83         }
84
85 /*
86  * extract()  -  extract a parameter from a series of "|" separated...
87  */
88 void extract(char *dest, char *source, int parmnum)
89 {
90         char buf[256];
91         int count = 0;
92         int n;
93
94         n = num_parms(source);
95
96         if (parmnum >= n) {
97                 strcpy(dest,"");
98                 return;
99                 }
100         strcpy(buf,source);
101         if ( (parmnum == 0) && (n == 1) ) {
102                 strcpy(dest,buf);
103                 return;
104                 }
105
106         while (count++ < parmnum) do {
107                 strcpy(buf,&buf[1]);
108                 } while( (strlen(buf)>0) && (buf[0]!='|') );
109         if (buf[0]=='|') strcpy(buf,&buf[1]);
110         for (count = 0; count<strlen(buf); ++count)
111                 if (buf[count] == '|') buf[count] = 0;
112         strcpy(dest,buf);
113         }
114
115 /*
116  * extract_int()  -  extract an int parm w/o supplying a buffer
117  */
118 int extract_int(char *source, int parmnum)
119 {
120         char buf[256];
121         
122         extract(buf,source,parmnum);
123         return(atoi(buf));
124         }
125
126 /*
127  * extract_long()  -  extract a long parm w/o supplying a buffer
128  */
129 long extract_long(char *source, int parmnum)
130 {
131         char buf[256];
132         
133         extract(buf,source,parmnum);
134         return(atol(buf));
135         }
136
137 void back(int spaces) /* Destructive backspace */
138             {
139 int a;
140         for (a=1; a<=spaces; ++a) {
141                 putc(8,stdout); putc(32,stdout); putc(8,stdout);
142                 }
143         }
144
145 int yesno(void) { /* Returns 1 for yes, 0 for no */
146 int a;
147         while (1) {
148                 a=inkey(); a=tolower(a);
149                 if (a=='y') { printf("Yes\n"); return(1); }
150                 if (a=='n') { printf("No\n");  return(0); }
151                 }
152         }
153
154 int yesno_d(int d) /* Returns 1 for yes, 0 for no, arg is default value */
155        {
156 int a;
157         while (1) {
158                 a=inkey(); a=tolower(a);
159                 if (a==13) a=(d ? 'y' : 'n');
160                 if (a=='y') { printf("Yes\n"); return(1); }
161                 if (a=='n') { printf("No\n");  return(0); }
162                 }
163         }
164
165
166 void hit_any_key(void) {                /* hit any key to continue */
167         int a,b;
168
169         printf("%s\r",serv_info.serv_moreprompt);
170         sttybbs(0);
171         b=inkey();
172         for (a=0; a<strlen(serv_info.serv_moreprompt); ++a)
173                 putc(' ',stdout);
174         putc(13,stdout);
175         sttybbs(1);
176         if (b==NEXT_KEY) sigcaught = SIGINT;
177         if (b==STOP_KEY) sigcaught = SIGQUIT;
178         }
179
180 /*
181  * change a user's access level
182  */
183 void edituser(void)
184 {
185         char who[256];
186         char buf[256];
187
188         newprompt("User name: ",who,25);
189         sprintf(buf,"QUSR %s",who);
190         serv_puts(buf);
191         serv_gets(buf);
192         if (buf[0]!='2') {
193                 printf("%s\n",&buf[4]);
194                 return;
195                 }
196         
197         val_user(who);
198         }
199
200
201 int set_attr(int sval, char *prompt, unsigned int sbit)
202 {
203         int a;
204         int temp;
205
206         temp = sval;
207         color(3);
208         printf("%45s [", prompt);
209         color(1);
210         printf("%3s", ((temp&sbit) ? "Yes":"No"));
211         color(3);
212         printf("]? ");
213         color(2);
214         a=yesno_d(temp&sbit);
215         color(7);
216         temp=(temp|sbit);
217         if (!a) temp=(temp^sbit);
218         return(temp);
219         }
220
221 /*
222  * modes are:  0 - .EC command, 1 - .EC for new user,
223  *             2 - toggle Xpert mode  3 - toggle floor mode
224  */
225 void enter_config(int mode)
226 {
227         int width,height,flags;
228         char buf[128];
229
230         sprintf(buf,"GETU");
231         serv_puts(buf);
232         serv_gets(buf);
233         if (buf[0]!='2') {
234                 printf("%s\n",&buf[4]);
235                 return;
236                 }
237
238         width = extract_int(&buf[4],0);
239         height = extract_int(&buf[4],1);
240         flags = extract_int(&buf[4],2);
241
242         if ((mode==0)||(mode==1)) {
243
244          width = intprompt("Enter your screen width",width,20,255);
245          height = intprompt("Enter your screen height",height,3,255);
246  
247          flags = set_attr(flags,
248                 "Are you an experienced Citadel user",US_EXPERT);
249          if ( ((flags&US_EXPERT)==0) && (mode==1))
250                 return;
251          flags = set_attr(flags,
252                 "Print last old message on New message request",US_LASTOLD);
253          if ((flags&US_EXPERT)==0) formout("unlisted");
254          flags = set_attr(flags,"Be unlisted in userlog",US_UNLISTED);
255          flags = set_attr(flags,"Suppress message prompts",US_NOPROMPT);
256          if ((flags & US_NOPROMPT)==0)
257             flags = set_attr(flags,"Use 'disappearing' prompts",US_DISAPPEAR);
258          flags = set_attr(flags,
259                 "Pause after each screenful of text",US_PAGINATOR);
260          if (rc_floor_mode == RC_DEFAULT) {
261           flags = set_attr(flags,
262                 "View rooms by floor",US_FLOORS);
263           }
264          }
265
266         if (mode==2) {
267          if (flags & US_EXPERT) {
268                 flags = (flags ^ US_EXPERT);
269                 printf("Expert mode now OFF\n");
270                 }
271          else {
272                 flags = (flags | US_EXPERT);
273                 printf("Expert mode now ON\n");
274                 }
275          }
276
277         if (mode==3) {
278          if (flags & US_FLOORS) {
279                 flags = (flags ^ US_FLOORS);
280                 printf("Floor mode now OFF\n");
281                 }
282          else {
283                 flags = (flags | US_FLOORS);
284                 printf("Floor mode now ON\n");
285                 }
286          }
287
288         sprintf(buf,"SETU %d|%d|%d",width,height,flags);
289         serv_puts(buf);
290         serv_gets(buf);
291         if (buf[0]!='2') printf("%s\n",&buf[4]);
292         userflags = flags;
293 }
294
295 /*
296  * getstring()  -  get a line of text from a file
297  *                 ignores lines beginning with "#"
298  */
299 int getstring(FILE *fp, char *string)
300 {
301         int a,c;
302         do {
303                 strcpy(string,"");
304                 a=0;
305                 do {
306                         c=getc(fp);
307                         if (c<0) {
308                                 string[a]=0;
309                                 return(-1);
310                                 }
311                         string[a++]=c;
312                         } while(c!=10);
313                         string[a-1]=0;
314                 } while(string[0]=='#');
315         return(strlen(string));
316         }
317
318 int pattern(char *search, char *patn)   /* Searches for patn in search string */
319               
320             
321 {
322         int a,b;
323         for (a=0; a<strlen(search); ++a)
324         {       b=struncmp(&search[a],patn,strlen(patn));
325                 if (b==0) return(b);
326                 }
327         return(-1);
328 }
329
330 void interr(int errnum) /* display internal error as defined in errmsgs */
331             {
332         printf("*** INTERNAL ERROR %d\n",errnum);
333         printf("(Press any key to continue)\n");
334         inkey();
335         logoff(errnum);
336 }
337
338
339
340 /*
341  * Check to see if we need to pause at the end of a screen.
342  * If we do, we have to disable server keepalives during the pause because
343  * we are probably in the middle of a server operation and the NOOP command
344  * would confuse everything.
345  */
346 int checkpagin(int lp, int pagin, int height)
347 {
348         if (pagin!=1) return(0);
349         if (lp>=(height-1)) {
350                 set_keepalives(KA_NO);
351                 hit_any_key();
352                 set_keepalives(KA_YES);
353                 return(0);
354                 }
355         return(lp);
356         }
357
358
359 void strproc(char *string)
360 {
361         int a;
362
363         if (strlen(string)==0) return;
364
365         /* Convert non-printable characters to blanks */
366         for (a=0; a<strlen(string); ++a) {
367                 if (string[a]<32) string[a]=32;
368                 if (string[a]>126) string[a]=32;
369                 }
370
371         /* Remove leading and trailing blanks */
372         while(string[0]<33) strcpy(string,&string[1]);
373         while(string[strlen(string)-1]<33) string[strlen(string)-1]=0;
374
375         /* Remove double blanks */
376         for (a=0; a<strlen(string); ++a) {
377                 if ((string[a]==32)&&(string[a+1]==32)) {
378                         strcpy(&string[a],&string[a+1]);
379                         a=0;
380                         }
381                 }
382
383         /* remove characters which would interfere with the network */
384         for (a=0; a<strlen(string); ++a) {
385                 if (string[a]=='!') strcpy(&string[a],&string[a+1]);
386                 if (string[a]=='@') strcpy(&string[a],&string[a+1]);
387                 if (string[a]=='_') strcpy(&string[a],&string[a+1]);
388                 if (string[a]==',') strcpy(&string[a],&string[a+1]);
389                 if (string[a]=='%') strcpy(&string[a],&string[a+1]);
390                 if (string[a]=='|') strcpy(&string[a],&string[a+1]);
391                 }
392
393         }
394
395
396 int alias(char *name)           /* process alias and routing info for mail */
397              {
398         FILE *fp;
399         int a,b;
400         char aaa[300],bbb[300];
401         
402         fp=fopen("network/mail.aliases","r");
403         if (fp==NULL) return(2);
404 GNA:    strcpy(aaa,""); strcpy(bbb,"");
405         do {
406                 a=getc(fp);
407                 if (a==',') a=0;
408                 if (a>0) { b=strlen(aaa); aaa[b]=a; aaa[b+1]=0; }
409                 } while(a>0);
410         do {
411                 a=getc(fp);
412                 if (a==10) a=0;
413                 if (a>0) { b=strlen(bbb); bbb[b]=a; bbb[b+1]=0; }
414                 } while(a>0);
415         if (a<0) {
416                 fclose(fp);
417                 goto DETYPE;
418                 }
419         if (strucmp(name,aaa)) goto GNA;
420         fclose(fp);
421         strcpy(name,bbb);
422         printf("*** Mail is being forwarded to %s\n",name);
423
424 DETYPE: /* determine local or remote type, see citadel.h */
425         for (a=0; a<strlen(name); ++a) if (name[a]=='!') return(M_INTERNET);
426         for (a=0; a<strlen(name); ++a)
427                 if (name[a]=='@')
428                         for (b=a; b<strlen(name); ++b)
429                                 if (name[b]=='.') return(M_INTERNET);
430         b=0; for (a=0; a<strlen(name); ++a) if (name[a]=='@') ++b;
431         if (b>1) {
432                 printf("Too many @'s in address\n");
433                 return(M_ERROR);
434                 }
435         if (b==1) {
436                 for (a=0; a<strlen(name); ++a)
437                         if (name[a]=='@') strcpy(bbb,&name[a+1]);
438                 while (bbb[0]==32) strcpy(bbb,&bbb[1]);
439                 fp = fopen("network/mail.sysinfo","r");
440                 if (fp==NULL) return(M_ERROR);
441 GETSN:          do {
442                         a=getstring(fp,aaa);
443                         } while ((a>=0)&&(strucmp(aaa,bbb)));
444                 a=getstring(fp,aaa);
445                 if (!strncmp(aaa,"use ",4)) {
446                         strcpy(bbb,&aaa[4]);
447                         fseek(fp,0L,0);
448                         goto GETSN;
449                         }
450                 fclose(fp);
451                 if (!strncmp(aaa,"uum",3)) {
452                         strcpy(bbb,name);
453                         for (a=0; a<strlen(bbb); ++a) {
454                                 if (bbb[a]=='@') bbb[a]=0;
455                                 if (bbb[a]==' ') bbb[a]='_';
456                                 }
457                         while(bbb[strlen(bbb)-1]=='_') bbb[strlen(bbb)-1]=0;
458                         sprintf(name,&aaa[4],bbb);
459                         return(M_INTERNET);
460                         }
461                 if (!strncmp(aaa,"bin",3)) {
462                         strcpy(aaa,name); strcpy(bbb,name);
463                         while (aaa[strlen(aaa)-1]!='@') aaa[strlen(aaa)-1]=0;
464                         aaa[strlen(aaa)-1]=0;
465                         while (aaa[strlen(aaa)-1]==' ') aaa[strlen(aaa)-1]=0;
466                         while (bbb[0]!='@') strcpy(bbb,&bbb[1]);
467                         strcpy(bbb,&bbb[1]);
468                         while (bbb[0]==' ') strcpy(bbb,&bbb[1]);
469                         sprintf(name,"%s @%s",aaa,bbb);
470                         return(M_BINARY);
471                         }
472                 return(M_ERROR);
473                 }
474         return(M_LOCAL);
475         }
476
477
478 #ifdef NO_STRERROR
479 /*
480  * replacement strerror() for systems that don't have it
481  */
482 char *strerror(int e)
483 {
484         static char buf[32];
485
486         sprintf(buf,"errno = %d",e);
487         return(buf);
488         }
489 #endif
490
491
492 void progress(long int curr, long int cmax)
493 {
494         static long dots_printed;
495         long a;
496
497         if (curr==0) {
498                 printf(".......................................");
499                 printf(".......................................\r");
500                 fflush(stdout);
501                 dots_printed = 0;
502                 }
503         else if (curr==cmax) {
504                 printf("\r%79s\n","");
505                 }
506         else {
507                 a=(curr * 100) / cmax;
508                 a=a*78; a=a/100;
509                 while (dots_printed < a) {
510                         printf("*");
511                         ++dots_printed;
512                         fflush(stdout);
513                         }
514                 }
515         }
516
517
518 /*
519  * NOT the same locate_host() in locate_host.c.  This one just does a
520  * 'who am i' to try to discover where the user is...
521  */
522 void locate_host(char *hbuf)
523 {
524         char buf[256];
525         FILE *who;
526         int a,b;
527
528         who = (FILE *)popen("who am i","r");
529         if (who==NULL) {
530                 strcpy(hbuf,serv_info.serv_fqdn);
531                 return; 
532                 }
533         fgets(buf,256,who);
534         pclose(who);
535
536         b = 0;
537         for (a=0; a<strlen(buf); ++a) {
538                 if ((buf[a]=='(')||(buf[a]==')')) ++b;
539                 }
540         if (b<2) {
541                 strcpy(hbuf,serv_info.serv_fqdn);
542                 return;
543                 }
544
545         for (a=0; a<strlen(buf); ++a) {
546                 if (buf[a]=='(') {
547                         strcpy(buf,&buf[a+1]);
548                         }
549                 }
550         for (a=0; a<strlen(buf); ++a) {
551                 if (buf[a]==')') buf[a] = 0;
552                 }
553
554         if (strlen(buf)==0) strcpy(hbuf,serv_info.serv_fqdn);
555         else strncpy(hbuf,buf,24);
556         }
557
558 /*
559  * miscellaneous server commands (testing, etc.)
560  */
561 void misc_server_cmd(char *cmd) {
562         char buf[256];
563
564         serv_puts(cmd);
565         serv_gets(buf);
566         printf("%s\n",buf);
567         if (buf[0]=='1') {
568                 while (serv_gets(buf), strcmp(buf,"000")) {
569                         printf("%s\n",buf);
570                         }
571                 return;
572                 }
573         if (buf[0]=='4') {
574                 do {
575                         newprompt("> ",buf,255);
576                         serv_puts(buf);
577                         } while(strcmp(buf,"000"));
578                 return;
579                 }
580         }
581
582
583 /*
584  * compute the checksum of a file
585  */
586 int file_checksum(char *filename)
587 {
588         int cksum = 0;
589         int ch;
590         FILE *fp;
591
592         fp = fopen(filename,"r");
593         if (fp == NULL) return(0);
594
595         /* yes, this algorithm may allow cksum to overflow, but that's ok
596          * as long as it overflows consistently, which it will.
597          */
598         while (ch=getc(fp), ch>=0) {
599                 cksum = (cksum + ch);
600                 }
601
602         fclose(fp);
603         return(cksum);
604         }
605
606 /*
607  * nuke a directory and its contents
608  */
609 int nukedir(char *dirname)
610 {
611         DIR *dp;
612         struct dirent *d;
613         char filename[256];
614
615         dp = opendir(dirname);
616         if (dp == NULL) {
617                 return(errno);
618                 }
619
620         while (d = readdir(dp), d != NULL) {
621                 sprintf(filename, "%s/%s", dirname, d->d_name);
622                 unlink(filename);
623                 }
624
625         closedir(dp);
626         return(rmdir(dirname));
627         }