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