]> code.citadel.org Git - citadel.git/blob - citadel/routines.c
6361012502f33b958c363fe0ce7bb9824e2f00f7
[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         color(COLOR_PUSH);
94         color(DIM_RED);
95         printf("%s\r",serv_info.serv_moreprompt);
96         color(COLOR_POP);
97         sttybbs(0);
98         b=inkey();
99         for (a=0; a<strlen(serv_info.serv_moreprompt); ++a)
100                 putc(' ',stdout);
101         putc(13,stdout);
102         sttybbs(1);
103         if (b==NEXT_KEY) sigcaught = SIGINT;
104         if (b==STOP_KEY) sigcaught = SIGQUIT;
105         }
106
107 /*
108  * change a user's access level
109  */
110 void edituser(void)
111 {
112         char buf[256];
113         char who[256];
114         char pass[256];
115         int flags;
116         int timescalled;
117         int posted;
118         int axlevel;
119         long usernum;
120         time_t lastcall;
121         int userpurge;
122
123         newprompt("User name: ",who,25);
124         sprintf(buf,"AGUP %s",who);
125         serv_puts(buf);
126         serv_gets(buf);
127         if (buf[0]!='2') {
128                 printf("%s\n",&buf[4]);
129                 return;
130                 }
131         extract(who, &buf[4], 0);
132         extract(pass, &buf[4], 1);
133         flags = extract_int(&buf[4], 2);
134         timescalled = extract_int(&buf[4], 3);
135         posted = extract_int(&buf[4], 4);
136         axlevel = extract_int(&buf[4], 5);
137         usernum = extract_long(&buf[4], 6);
138         lastcall = extract_long(&buf[4], 7);
139         userpurge = extract_int(&buf[4], 8);
140
141         val_user(who, 0); /* Display registration */
142         strprompt("Password", pass, 19);
143         axlevel = intprompt("Access level", axlevel, 0, 6);
144         timescalled = intprompt("Times called", timescalled, 0, INT_MAX);
145         posted = intprompt("Messages posted", posted, 0, INT_MAX);
146         lastcall = (boolprompt("Set last call to now", 0)?time(NULL):lastcall);
147         userpurge = intprompt("Purge time (in days, 0 for system default",
148                                 userpurge, 0, INT_MAX);
149
150         sprintf(buf, "ASUP %s|%s|%d|%d|%d|%d|%ld|%ld|%d",
151                 who, pass, flags, timescalled, posted, axlevel, usernum,
152                 (long)lastcall, userpurge);
153         serv_puts(buf);
154         serv_gets(buf);
155         if (buf[0]!='2') {
156                 printf("%s\n",&buf[4]);
157                 }
158         }
159
160
161 int set_attr(int sval, char *prompt, unsigned int sbit)
162 {
163         int a;
164         int temp;
165
166         temp = sval;
167         color(DIM_WHITE);
168         printf("%45s ", prompt);
169         color(DIM_MAGENTA);
170         printf("[");
171         color(BRIGHT_MAGENTA);
172         printf("%3s", ((temp&sbit) ? "Yes":"No"));
173         color(DIM_MAGENTA);
174         printf("]? ");
175         color(BRIGHT_CYAN);
176         a=yesno_d(temp&sbit);
177         color(DIM_WHITE);
178         temp=(temp|sbit);
179         if (!a) temp=(temp^sbit);
180         return(temp);
181         }
182
183 /*
184  * modes are:  0 - .EC command, 1 - .EC for new user,
185  *             2 - toggle Xpert mode  3 - toggle floor mode
186  */
187 void enter_config(int mode)
188 {
189         int width,height,flags;
190         char buf[128];
191
192         sprintf(buf,"GETU");
193         serv_puts(buf);
194         serv_gets(buf);
195         if (buf[0]!='2') {
196                 printf("%s\n",&buf[4]);
197                 return;
198                 }
199
200         width = extract_int(&buf[4],0);
201         height = extract_int(&buf[4],1);
202         flags = extract_int(&buf[4],2);
203
204         if ((mode==0)||(mode==1)) {
205
206          width = intprompt("Enter your screen width",width,20,255);
207          height = intprompt("Enter your screen height",height,3,255);
208  
209          flags = set_attr(flags,
210                 "Are you an experienced Citadel user",US_EXPERT);
211          if ( ((flags&US_EXPERT)==0) && (mode==1))
212                 return;
213          flags = set_attr(flags,
214                 "Print last old message on New message request",US_LASTOLD);
215          if ((flags&US_EXPERT)==0) formout("unlisted");
216          flags = set_attr(flags,"Be unlisted in userlog",US_UNLISTED);
217          flags = set_attr(flags,"Suppress message prompts",US_NOPROMPT);
218          if ((flags & US_NOPROMPT)==0)
219             flags = set_attr(flags,"Use 'disappearing' prompts",US_DISAPPEAR);
220          flags = set_attr(flags,
221                 "Pause after each screenful of text",US_PAGINATOR);
222          if (rc_floor_mode == RC_DEFAULT) {
223           flags = set_attr(flags,
224                 "View rooms by floor",US_FLOORS);
225           }
226          if (rc_ansi_color == 3) {
227           flags = set_attr(flags,
228                 "Enable color support",US_COLOR);
229           }
230          }
231
232         if (mode==2) {
233          if (flags & US_EXPERT) {
234                 flags = (flags ^ US_EXPERT);
235                 printf("Expert mode now OFF\n");
236                 }
237          else {
238                 flags = (flags | US_EXPERT);
239                 printf("Expert mode now ON\n");
240                 }
241          }
242
243         if (mode==3) {
244          if (flags & US_FLOORS) {
245                 flags = (flags ^ US_FLOORS);
246                 printf("Floor mode now OFF\n");
247                 }
248          else {
249                 flags = (flags | US_FLOORS);
250                 printf("Floor mode now ON\n");
251                 }
252          }
253
254         sprintf(buf,"SETU %d|%d|%d",width,height,flags);
255         serv_puts(buf);
256         serv_gets(buf);
257         if (buf[0]!='2') printf("%s\n",&buf[4]);
258         userflags = flags;
259 }
260
261 /*
262  * getstring()  -  get a line of text from a file
263  *                 ignores lines beginning with "#"
264  */
265 int getstring(FILE *fp, char *string)
266 {
267         int a,c;
268         do {
269                 strcpy(string,"");
270                 a=0;
271                 do {
272                         c=getc(fp);
273                         if (c<0) {
274                                 string[a]=0;
275                                 return(-1);
276                                 }
277                         string[a++]=c;
278                         } while(c!=10);
279                         string[a-1]=0;
280                 } while(string[0]=='#');
281         return(strlen(string));
282         }
283
284 int pattern(char *search, char *patn)   /* Searches for patn in search string */
285               
286             
287 {
288         int a,b;
289         for (a=0; a<strlen(search); ++a)
290         {       b=struncmp(&search[a],patn,strlen(patn));
291                 if (b==0) return(b);
292                 }
293         return(-1);
294 }
295
296 void interr(int errnum) /* display internal error as defined in errmsgs */
297             {
298         printf("*** INTERNAL ERROR %d\n",errnum);
299         printf("(Press any key to continue)\n");
300         inkey();
301         logoff(errnum);
302 }
303
304
305
306 /*
307  * Check to see if we need to pause at the end of a screen.
308  * If we do, we have to disable server keepalives during the pause because
309  * we are probably in the middle of a server operation and the NOOP command
310  * would confuse everything.
311  */
312 int checkpagin(int lp, int pagin, int height)
313 {
314         if (pagin!=1) return(0);
315         if (lp>=(height-1)) {
316                 set_keepalives(KA_NO);
317                 hit_any_key();
318                 set_keepalives(KA_YES);
319                 return(0);
320                 }
321         return(lp);
322         }
323
324
325 void strproc(char *string)
326 {
327         int a;
328
329         if (strlen(string)==0) return;
330
331         /* Convert non-printable characters to blanks */
332         for (a=0; a<strlen(string); ++a) {
333                 if (string[a]<32) string[a]=32;
334                 if (string[a]>126) string[a]=32;
335                 }
336
337         /* Remove leading and trailing blanks */
338         while(string[0]<33) strcpy(string,&string[1]);
339         while(string[strlen(string)-1]<33) string[strlen(string)-1]=0;
340
341         /* Remove double blanks */
342         for (a=0; a<strlen(string); ++a) {
343                 if ((string[a]==32)&&(string[a+1]==32)) {
344                         strcpy(&string[a],&string[a+1]);
345                         a=0;
346                         }
347                 }
348
349         /* remove characters which would interfere with the network */
350         for (a=0; a<strlen(string); ++a) {
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                 if (string[a]==',') strcpy(&string[a],&string[a+1]);
355                 if (string[a]=='%') strcpy(&string[a],&string[a+1]);
356                 if (string[a]=='|') strcpy(&string[a],&string[a+1]);
357                 }
358
359         }
360
361
362 #ifndef HAVE_STRERROR
363 /*
364  * replacement strerror() for systems that don't have it
365  */
366 char *strerror(int e)
367 {
368         static char buf[32];
369
370         sprintf(buf,"errno = %d",e);
371         return(buf);
372         }
373 #endif
374
375
376 void progress(long int curr, long int cmax)
377 {
378         static long dots_printed;
379         long a;
380
381         if (curr==0) {
382                 printf(".......................................");
383                 printf(".......................................\r");
384                 fflush(stdout);
385                 dots_printed = 0;
386                 }
387         else if (curr==cmax) {
388                 printf("\r%79s\n","");
389                 }
390         else {
391                 a=(curr * 100) / cmax;
392                 a=a*78; a=a/100;
393                 while (dots_printed < a) {
394                         printf("*");
395                         ++dots_printed;
396                         fflush(stdout);
397                         }
398                 }
399         }
400
401
402 /*
403  * NOT the same locate_host() in locate_host.c.  This one just does a
404  * 'who am i' to try to discover where the user is...
405  */
406 void locate_host(char *hbuf)
407 {
408 #ifndef HAVE_UTMP_H
409         char buf[256];
410         FILE *who;
411         int a,b;
412
413         who = (FILE *)popen("who am i","r");
414         if (who==NULL) {
415                 strcpy(hbuf,serv_info.serv_fqdn);
416                 return; 
417                 }
418         fgets(buf,256,who);
419         pclose(who);
420
421         b = 0;
422         for (a=0; a<strlen(buf); ++a) {
423                 if ((buf[a]=='(')||(buf[a]==')')) ++b;
424                 }
425         if (b<2) {
426                 strcpy(hbuf,serv_info.serv_fqdn);
427                 return;
428                 }
429
430         for (a=0; a<strlen(buf); ++a) {
431                 if (buf[a]=='(') {
432                         strcpy(buf,&buf[a+1]);
433                         }
434                 }
435         for (a=0; a<strlen(buf); ++a) {
436                 if (buf[a]==')') buf[a] = 0;
437                 }
438
439         if (strlen(buf)==0) strcpy(hbuf,serv_info.serv_fqdn);
440         else strncpy(hbuf,buf,24);
441 #else
442         char *tty = ttyname(0);
443         struct utmp ut, *put;
444
445         if (tty == NULL) {
446             fail:
447                 safestrncpy(hbuf, serv_info.serv_fqdn, 24);
448                 return;
449                 }
450
451         if (strncmp(tty, "/dev/", 5))
452                 goto fail;
453
454         safestrncpy(ut.ut_line, &tty[5], sizeof ut.ut_line);
455
456         if ((put = getutline(&ut)) == NULL)
457                 goto fail;
458
459 #ifdef HAVE_UT_TYPE
460         if (put->ut_type == USER_PROCESS) {
461 #endif
462 #ifdef HAVE_UT_HOST
463                 if (*put->ut_host)
464                         safestrncpy(hbuf, put->ut_host, 24);
465                 else
466 #endif
467                         safestrncpy(hbuf, put->ut_line, 24);
468 #ifdef HAVE_UT_TYPE
469                 }
470         else goto fail;
471 #endif
472 #endif /* HAVE_UTMP_H */
473         }
474
475 /*
476  * miscellaneous server commands (testing, etc.)
477  */
478 void misc_server_cmd(char *cmd) {
479         char buf[256];
480
481         serv_puts(cmd);
482         serv_gets(buf);
483         printf("%s\n",buf);
484         if (buf[0]=='1') {
485                 set_keepalives(KA_NO);
486                 while (serv_gets(buf), strcmp(buf,"000")) {
487                         printf("%s\n",buf);
488                         }
489                 set_keepalives(KA_YES);
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         }