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