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