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