]> code.citadel.org Git - citadel.git/blob - citadel/routines.c
added more stuff to <.A>ide <E>dit user
[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 int intprompt(char *prompt, int ival, int imin, int imax);
30 void formout(char *name);
31 void logoff(int code);
32 void set_keepalives(int s);
33 void strprompt(char *prompt, char *str, int len);
34 void newprompt(char *prompt, char *str, int len);
35 void color(int colornum);
36
37 #define IFAIDE if(axlevel>=6)
38 #define IFNAIDE if (axlevel<6)
39
40 extern unsigned userflags;
41 extern char *axdefs[7];
42 extern char sigcaught;
43 extern struct CtdlServInfo serv_info;
44 extern char rc_floor_mode;
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          }
278
279         if (mode==2) {
280          if (flags & US_EXPERT) {
281                 flags = (flags ^ US_EXPERT);
282                 printf("Expert mode now OFF\n");
283                 }
284          else {
285                 flags = (flags | US_EXPERT);
286                 printf("Expert mode now ON\n");
287                 }
288          }
289
290         if (mode==3) {
291          if (flags & US_FLOORS) {
292                 flags = (flags ^ US_FLOORS);
293                 printf("Floor mode now OFF\n");
294                 }
295          else {
296                 flags = (flags | US_FLOORS);
297                 printf("Floor mode now ON\n");
298                 }
299          }
300
301         sprintf(buf,"SETU %d|%d|%d",width,height,flags);
302         serv_puts(buf);
303         serv_gets(buf);
304         if (buf[0]!='2') printf("%s\n",&buf[4]);
305         userflags = flags;
306 }
307
308 /*
309  * getstring()  -  get a line of text from a file
310  *                 ignores lines beginning with "#"
311  */
312 int getstring(FILE *fp, char *string)
313 {
314         int a,c;
315         do {
316                 strcpy(string,"");
317                 a=0;
318                 do {
319                         c=getc(fp);
320                         if (c<0) {
321                                 string[a]=0;
322                                 return(-1);
323                                 }
324                         string[a++]=c;
325                         } while(c!=10);
326                         string[a-1]=0;
327                 } while(string[0]=='#');
328         return(strlen(string));
329         }
330
331 int pattern(char *search, char *patn)   /* Searches for patn in search string */
332               
333             
334 {
335         int a,b;
336         for (a=0; a<strlen(search); ++a)
337         {       b=struncmp(&search[a],patn,strlen(patn));
338                 if (b==0) return(b);
339                 }
340         return(-1);
341 }
342
343 void interr(int errnum) /* display internal error as defined in errmsgs */
344             {
345         printf("*** INTERNAL ERROR %d\n",errnum);
346         printf("(Press any key to continue)\n");
347         inkey();
348         logoff(errnum);
349 }
350
351
352
353 /*
354  * Check to see if we need to pause at the end of a screen.
355  * If we do, we have to disable server keepalives during the pause because
356  * we are probably in the middle of a server operation and the NOOP command
357  * would confuse everything.
358  */
359 int checkpagin(int lp, int pagin, int height)
360 {
361         if (pagin!=1) return(0);
362         if (lp>=(height-1)) {
363                 set_keepalives(KA_NO);
364                 hit_any_key();
365                 set_keepalives(KA_YES);
366                 return(0);
367                 }
368         return(lp);
369         }
370
371
372 void strproc(char *string)
373 {
374         int a;
375
376         if (strlen(string)==0) return;
377
378         /* Convert non-printable characters to blanks */
379         for (a=0; a<strlen(string); ++a) {
380                 if (string[a]<32) string[a]=32;
381                 if (string[a]>126) string[a]=32;
382                 }
383
384         /* Remove leading and trailing blanks */
385         while(string[0]<33) strcpy(string,&string[1]);
386         while(string[strlen(string)-1]<33) string[strlen(string)-1]=0;
387
388         /* Remove double blanks */
389         for (a=0; a<strlen(string); ++a) {
390                 if ((string[a]==32)&&(string[a+1]==32)) {
391                         strcpy(&string[a],&string[a+1]);
392                         a=0;
393                         }
394                 }
395
396         /* remove characters which would interfere with the network */
397         for (a=0; a<strlen(string); ++a) {
398                 if (string[a]=='!') strcpy(&string[a],&string[a+1]);
399                 if (string[a]=='@') strcpy(&string[a],&string[a+1]);
400                 if (string[a]=='_') strcpy(&string[a],&string[a+1]);
401                 if (string[a]==',') strcpy(&string[a],&string[a+1]);
402                 if (string[a]=='%') strcpy(&string[a],&string[a+1]);
403                 if (string[a]=='|') strcpy(&string[a],&string[a+1]);
404                 }
405
406         }
407
408
409 #ifndef HAVE_STRERROR
410 /*
411  * replacement strerror() for systems that don't have it
412  */
413 char *strerror(int e)
414 {
415         static char buf[32];
416
417         sprintf(buf,"errno = %d",e);
418         return(buf);
419         }
420 #endif
421
422
423 void progress(long int curr, long int cmax)
424 {
425         static long dots_printed;
426         long a;
427
428         if (curr==0) {
429                 printf(".......................................");
430                 printf(".......................................\r");
431                 fflush(stdout);
432                 dots_printed = 0;
433                 }
434         else if (curr==cmax) {
435                 printf("\r%79s\n","");
436                 }
437         else {
438                 a=(curr * 100) / cmax;
439                 a=a*78; a=a/100;
440                 while (dots_printed < a) {
441                         printf("*");
442                         ++dots_printed;
443                         fflush(stdout);
444                         }
445                 }
446         }
447
448
449 /*
450  * NOT the same locate_host() in locate_host.c.  This one just does a
451  * 'who am i' to try to discover where the user is...
452  */
453 void locate_host(char *hbuf)
454 {
455         char buf[256];
456         FILE *who;
457         int a,b;
458
459         who = (FILE *)popen("who am i","r");
460         if (who==NULL) {
461                 strcpy(hbuf,serv_info.serv_fqdn);
462                 return; 
463                 }
464         fgets(buf,256,who);
465         pclose(who);
466
467         b = 0;
468         for (a=0; a<strlen(buf); ++a) {
469                 if ((buf[a]=='(')||(buf[a]==')')) ++b;
470                 }
471         if (b<2) {
472                 strcpy(hbuf,serv_info.serv_fqdn);
473                 return;
474                 }
475
476         for (a=0; a<strlen(buf); ++a) {
477                 if (buf[a]=='(') {
478                         strcpy(buf,&buf[a+1]);
479                         }
480                 }
481         for (a=0; a<strlen(buf); ++a) {
482                 if (buf[a]==')') buf[a] = 0;
483                 }
484
485         if (strlen(buf)==0) strcpy(hbuf,serv_info.serv_fqdn);
486         else strncpy(hbuf,buf,24);
487         }
488
489 /*
490  * miscellaneous server commands (testing, etc.)
491  */
492 void misc_server_cmd(char *cmd) {
493         char buf[256];
494
495         serv_puts(cmd);
496         serv_gets(buf);
497         printf("%s\n",buf);
498         if (buf[0]=='1') {
499                 while (serv_gets(buf), strcmp(buf,"000")) {
500                         printf("%s\n",buf);
501                         }
502                 return;
503                 }
504         if (buf[0]=='4') {
505                 do {
506                         newprompt("> ",buf,255);
507                         serv_puts(buf);
508                         } while(strcmp(buf,"000"));
509                 return;
510                 }
511         }
512
513
514 /*
515  * compute the checksum of a file
516  */
517 int file_checksum(char *filename)
518 {
519         int cksum = 0;
520         int ch;
521         FILE *fp;
522
523         fp = fopen(filename,"r");
524         if (fp == NULL) return(0);
525
526         /* yes, this algorithm may allow cksum to overflow, but that's ok
527          * as long as it overflows consistently, which it will.
528          */
529         while (ch=getc(fp), ch>=0) {
530                 cksum = (cksum + ch);
531                 }
532
533         fclose(fp);
534         return(cksum);
535         }
536
537 /*
538  * nuke a directory and its contents
539  */
540 int nukedir(char *dirname)
541 {
542         DIR *dp;
543         struct dirent *d;
544         char filename[256];
545
546         dp = opendir(dirname);
547         if (dp == NULL) {
548                 return(errno);
549                 }
550
551         while (d = readdir(dp), d != NULL) {
552                 sprintf(filename, "%s/%s", dirname, d->d_name);
553                 unlink(filename);
554                 }
555
556         closedir(dp);
557         return(rmdir(dirname));
558         }