]> code.citadel.org Git - citadel.git/blob - citadel/textclient/routines.c
Removed obsolete features from client
[citadel.git] / citadel / textclient / routines.c
1 /*
2  * Client-side support functions.
3  */
4
5 #include "sysdep.h"
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <ctype.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/ioctl.h>
14 #include <pwd.h>
15 #include <signal.h>
16 #include <dirent.h>
17 #include <errno.h>
18
19 #if TIME_WITH_SYS_TIME
20 # include <sys/time.h>
21 # include <time.h>
22 #else
23 # if HAVE_SYS_TIME_H
24 #  include <sys/time.h>
25 # else
26 #  include <time.h>
27 # endif
28 #endif
29
30 #ifdef HAVE_LIMITS_H
31 #include <limits.h>
32 #endif
33 #ifdef HAVE_UTMP_H
34 #include <utmp.h>
35 #endif
36 #ifdef HAVE_UTMPX_H
37 #include <utmpx.h>
38 #endif
39
40 #include <libcitadel.h>
41 #include "citadel.h"
42 #include "citadel_ipc.h"
43 #include "screen.h"
44
45 #ifndef HAVE_GETUTLINE
46 struct utmp *getutline(struct utmp *ut);
47 #endif
48
49 #define ROUTINES_C
50
51 #include "citadel.h"
52 #include "routines.h"
53 #include "commands.h"
54 #include "citadel_decls.h"
55 #include "routines2.h"
56 #include "tuiconfig.h"
57
58 #define IFAIDE if(axlevel>=AxAideU)
59 #define IFNAIDE if (axlevel<AxAideU)
60
61 extern unsigned userflags;
62 //extern char *axdefs[8];
63 extern char sigcaught;
64 extern char rc_floor_mode;
65 extern int rc_ansi_color;
66 extern int rc_prompt_control;
67
68 /* Destructive backspace */
69 void back(int spaces) {
70         int a;
71         for (a=0; a<spaces; ++a) {
72                 scr_putc(8);
73                 scr_putc(32);
74                 scr_putc(8);
75         }
76 }
77
78 /*
79  * Edit or delete a user (cmd=25 to edit/create, 96 to delete)
80  */
81 void edituser(CtdlIPC *ipc, int cmd)
82 {
83         char buf[SIZ];
84         char who[USERNAME_SIZE];
85         char newname[USERNAME_SIZE];
86         struct ctdluser *user = NULL;
87         int newnow = 0;
88         int r;                          /* IPC response code */
89         int change_name = 0;
90
91         strcpy(newname, "");
92
93         newprompt("User name: ", who, 29);
94         while ((r = CtdlIPCAideGetUserParameters(ipc, who, &user, buf)) / 100 != 2) {
95                 scr_printf("%s\n", buf);
96                 if (cmd == 25) {
97                         scr_printf("Do you want to create this user? ");
98                         if (yesno()) {
99                                 r = CtdlIPCCreateUser(ipc, who, 0, buf);
100                                 if (r / 100 == 2) {
101                                         newnow = 1;
102                                         continue;
103                                 }
104                                 scr_printf("%s\n", buf);
105                         }
106                 }
107                 free(user);
108                 return;
109         }
110
111         if (cmd == 25) {
112                 val_user(ipc, user->fullname, 0); /* Display registration */
113
114                 if (!newnow) {
115                         change_name = 1;
116                         while (change_name == 1) {
117                                 if (boolprompt("Change name", 0)) {
118                                         strprompt("New name", newname, USERNAME_SIZE-1);
119                                         r = CtdlIPCRenameUser(ipc, user->fullname, newname, buf);
120                                         if (r / 100 != 2) {
121                                                 scr_printf("%s\n", buf);
122                                         }
123                                         else {
124                                                 strcpy(user->fullname, newname);
125                                                 change_name = 0;
126                                         }
127                                 }
128                                 else {
129                                         change_name = 0;
130                                 }
131                         }
132                 }
133
134                 if (newnow || boolprompt("Change password", 0)) {
135                         strprompt("Password", user->password, -19);
136                 }
137         
138                 user->axlevel = intprompt("Access level", user->axlevel, 0, 6);
139                 if (boolprompt("Permission to send Internet mail", (user->flags & US_INTERNET)))
140                         user->flags |= US_INTERNET;
141                 else
142                         user->flags &= ~US_INTERNET;
143                 if (boolprompt("Ask user to register again", !(user->flags & US_REGIS)))
144                         user->flags &= ~US_REGIS;
145                 else
146                         user->flags |= US_REGIS;
147                 user->timescalled = intprompt("Times called",
148                                 user->timescalled, 0, INT_MAX);
149                 user->posted = intprompt("Messages posted",
150                                         user->posted, 0, INT_MAX);
151                 user->lastcall = boolprompt("Set last call to now", 0) ?
152                                         time(NULL) : user->lastcall;
153                 user->USuserpurge = intprompt("Purge time (in days, 0 for system default",
154                                 user->USuserpurge, 0, INT_MAX);
155         }
156
157         if (cmd == 96) {
158                 scr_printf("Do you want to delete this user? ");
159                 if (!yesno()) {
160                         free(user);
161                         return;
162                 }
163                 user->axlevel = AxDeleted;
164         }
165
166         r = CtdlIPCAideSetUserParameters(ipc, user, buf);
167         if (r / 100 != 2) {
168                 scr_printf("%s\n", buf);
169         }
170         free(user);
171 }
172
173
174 /* Display a prompt and flip a bit based on whether the user answers
175  * yes or no.  Yes=1 and No=0, unless 'backwards' is set to a nonzero value
176  * in which case No=1 and Yes=0.
177  */
178 int set_attr(CtdlIPC *ipc, unsigned int sval, char *prompt, unsigned int sbit, int backwards)
179 {
180         int a;
181         int temp;
182
183         temp = sval;
184         color(DIM_WHITE);
185         scr_printf("%50s ", prompt);
186         color(DIM_MAGENTA);
187         scr_printf("[");
188         color(BRIGHT_MAGENTA);
189
190         if (backwards) {
191                 scr_printf("%3s", ((temp&sbit) ? "No":"Yes"));
192         }
193         else {
194                 scr_printf("%3s", ((temp&sbit) ? "Yes":"No"));
195         }
196
197         color(DIM_MAGENTA);
198         scr_printf("]? ");
199         color(BRIGHT_CYAN);
200         a = (temp & sbit);
201         if (a != 0) a = 1;
202         if (backwards) a = 1 - a;
203         a = yesno_d(a);
204         if (backwards) a = 1 - a;
205         color(DIM_WHITE);
206         temp = (temp|sbit);
207         if (!a) temp = (temp^sbit);
208         return(temp);
209 }
210
211 /*
212  * modes are:  0 - .EC command, 1 - .EC for new user,
213  *             2 - toggle Xpert mode  3 - toggle floor mode
214  */
215 void enter_config(CtdlIPC *ipc, int mode)
216 {
217         char buf[SIZ];
218         struct ctdluser *user = NULL;
219         int r;                          /* IPC response code */
220
221         r = CtdlIPCGetConfig(ipc, &user, buf);
222         if (r / 100 != 2) {
223                 scr_printf("%s\n", buf);
224                 free(user);
225                 return;
226         }
227
228         if (mode == 0 || mode == 1) {
229
230                 user->flags = set_attr(ipc, user->flags,
231                                        "Are you an experienced Citadel user",
232                                        US_EXPERT, 0);
233                 if ((user->flags & US_EXPERT) == 0 && mode == 1) {
234                         free(user);
235                         return;
236                 }
237
238                 user->flags = set_attr(
239                         ipc,
240                         user->flags,
241                         "Print last old message on New message request",
242                         US_LASTOLD,
243                         0
244                 );
245
246                 user->flags = set_attr(
247                         ipc,
248                         user->flags,
249                         "Prompt after each message",
250                         US_NOPROMPT,
251                         1
252                 );
253
254                 if ((user->flags & US_NOPROMPT) == 0) {
255                         user->flags = set_attr(
256                                 ipc,
257                                 user->flags,
258                                 "Use 'disappearing' prompts",
259                                 US_DISAPPEAR,
260                                 0
261                         );
262                 }
263
264                 user->flags = set_attr(
265                         ipc,
266                         user->flags,
267                         "Pause after each screenful of text",
268                         US_PAGINATOR,
269                         0
270                 );
271
272                 if (rc_prompt_control == 3 && (user->flags & US_PAGINATOR)) {
273                         user->flags = set_attr(
274                                 ipc,
275                                 user->flags,
276                                 "<N>ext and <S>top work at paginator prompt",
277                                 US_PROMPTCTL,
278                                 0
279                         );
280                 }
281
282                 if (rc_floor_mode == RC_DEFAULT) {
283                         user->flags = set_attr(
284                                 ipc,
285                                 user->flags,
286                                 "View rooms by floor",
287                                 US_FLOORS,
288                                 0
289                         );
290                 }
291
292                 if (rc_ansi_color == 3) {
293                         user->flags = set_attr(
294                                 ipc,
295                                 user->flags,
296                                 "Enable color support",
297                                 US_COLOR,
298                                 0
299                         );
300                 }
301
302                 if ((user->flags & US_EXPERT) == 0) {
303                         formout(ipc, "unlisted");
304                 }
305
306                 user->flags = set_attr(
307                         ipc,
308                         user->flags,
309                         "Be unlisted in userlog",
310                         US_UNLISTED,
311                         0
312                 );
313
314                 if (!IsEmptyStr(editor_path)) {
315                         user->flags = set_attr(
316                                 ipc,
317                                 user->flags,
318                                 "Always enter messages with the full-screen editor",
319                                 US_EXTEDIT,
320                                 0
321                         );
322                 }
323
324         }
325
326         if (mode == 2) {
327                 if (user->flags & US_EXPERT) {
328                         user->flags ^= US_EXPERT;
329                         scr_printf("Expert mode now OFF\n");
330                 } else {
331                         user->flags |= US_EXPERT;
332                         scr_printf("Expert mode now ON\n");
333                 }
334         }
335
336         if (mode == 3) {
337                 if (user->flags & US_FLOORS) {
338                         user->flags ^= US_FLOORS;
339                         scr_printf("Floor mode now OFF\n");
340                 } else {
341                         user->flags |= US_FLOORS;
342                         scr_printf("Floor mode now ON\n");
343                 }
344         }
345
346         r = CtdlIPCSetConfig(ipc, user, buf);
347         if (r / 100 != 2) scr_printf("%s\n", buf);
348         userflags = user->flags;
349         free(user);
350 }
351
352 /*
353  * getstring()  -  get a line of text from a file
354  *                 ignores lines beginning with "#"
355  */
356 int getstring(FILE *fp, char *string)
357 {
358         int a,c;
359         do {
360                 strcpy(string,"");
361                 a=0;
362                 do {
363                         c=getc(fp);
364                         if (c<0) {
365                                 string[a]=0;
366                                 return(-1);
367                         }
368                         string[a++]=c;
369                 } while(c!=10);
370                         string[a-1]=0;
371         } while(string[0]=='#');
372         return(strlen(string));
373 }
374
375
376 /* Searches for patn in search string */
377 int pattern(char *search, char *patn) {
378         int a,b,len;
379         
380         len = strlen(patn);
381         for (a=0; !IsEmptyStr(&search[a]); ++a) {
382                 b=strncasecmp(&search[a],patn,len);
383                 if (b==0) return(b);
384         }
385         return(-1);
386 }
387
388
389 void strproc(char *string)
390 {
391         int a;
392
393         if (IsEmptyStr(string)) return;
394
395         /* Convert non-printable characters to blanks */
396         for (a=0; !IsEmptyStr(&string[a]); ++a) {
397                 if (string[a]<32) string[a]=32;
398                 if (string[a]>126) string[a]=32;
399         }
400
401         /* Remove leading and trailing blanks */
402         while(string[0]<33) strcpy(string,&string[1]);
403         while(string[strlen(string)-1]<33) string[strlen(string)-1]=0;
404
405         /* Remove double blanks */
406         for (a=0; a<strlen(string); ++a) {
407                 if ((string[a]==32)&&(string[a+1]==32)) {
408                         strcpy(&string[a],&string[a+1]);
409                         a=0;
410                 }
411         }
412
413         /* remove characters which would interfere with the network */
414         for (a=0; a<strlen(string); ++a) {
415                 if (string[a]=='!') strcpy(&string[a],&string[a+1]);
416                 if (string[a]=='@') strcpy(&string[a],&string[a+1]);
417                 if (string[a]=='_') strcpy(&string[a],&string[a+1]);
418                 if (string[a]==',') strcpy(&string[a],&string[a+1]);
419                 if (string[a]=='%') strcpy(&string[a],&string[a+1]);
420                 if (string[a]=='|') strcpy(&string[a],&string[a+1]);
421         }
422
423 }
424
425
426 #ifndef HAVE_STRERROR
427 /*
428  * replacement strerror() for systems that don't have it
429  */
430 char *strerror(int e)
431 {
432         static char buf[128];
433
434         snprintf(buf, sizeof buf, "errno = %d",e);
435         return(buf);
436 }
437 #endif
438
439
440 void progress(CtdlIPC* ipc, unsigned long curr, unsigned long cmax)
441 {
442         static char dots[] =
443                 "**************************************************";
444         char dots_printed[51];
445         char fmt[42];
446         unsigned long a;
447
448         if (curr >= cmax) {
449                 scr_printf("\r%79s\r","");
450         } else {
451                 /* a will be range 0-50 rather than 0-100 */
452                 a=(curr * 50) / cmax;
453                 sprintf(fmt, "[%%s%%%lds] %%3ld%%%% %%10ld/%%10ld\r", 50 - a);
454                 strncpy(dots_printed, dots, a);
455                 dots_printed[a] = 0;
456                 scr_printf(fmt, dots_printed, "",
457                                 curr * 100 / cmax, curr, cmax);
458                 scr_flush();
459         }
460 }
461
462
463 /*
464  * NOT the same locate_host() in locate_host.c.  This one just does a
465  * 'who am i' to try to discover where the user is...
466  */
467 void locate_host(CtdlIPC* ipc, char *hbuf)
468 {
469 #ifndef HAVE_UTMP_H
470         char buf[SIZ];
471         FILE *who;
472         int a,b;
473
474         who = (FILE *)popen("who am i","r");
475         if (who==NULL) {
476                 strcpy(hbuf, ipc->ServInfo.fqdn);
477                 return; 
478         }
479         fgets(buf,sizeof buf,who);
480         pclose(who);
481
482         b = 0;
483         for (a=0; !IsEmptyStr(&buf[a]); ++a) {
484                 if ((buf[a]=='(')||(buf[a]==')')) ++b;
485         }
486         if (b<2) {
487                 strcpy(hbuf, ipc->ServInfo.fqdn);
488                 return;
489         }
490
491         for (a=0; a<strlen(buf); ++a) {
492                 if (buf[a]=='(') {
493                         strcpy(buf,&buf[a+1]);
494                 }
495         }
496         for (a=0; a<strlen(buf); ++a) {
497                 if (buf[a]==')') buf[a] = 0;
498         }
499
500         if (IsEmptyStr(buf)) strcpy(hbuf, ipc->ServInfo.fqdn);
501         else strncpy(hbuf,buf,24);
502 #else
503         char *tty = ttyname(0);
504 #ifdef HAVE_GETUTXLINE
505         struct utmpx ut, *put;
506 #else
507         struct utmp ut, *put;
508 #endif
509
510         if (tty == NULL) {
511             fail:
512                 safestrncpy(hbuf, ipc->ServInfo.fqdn, 24);
513                 return;
514         }
515
516         if (strncmp(tty, "/dev/", 5))
517                 goto fail;
518
519         safestrncpy(ut.ut_line, &tty[5], sizeof ut.ut_line);
520
521 #ifdef HAVE_GETUTXLINE /* Solaris uses this */
522         if ((put = getutxline(&ut)) == NULL)
523 #else
524         if ((put = getutline(&ut)) == NULL)
525 #endif
526                 goto fail;
527
528 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
529         if (put->ut_type == USER_PROCESS) {
530 #endif
531 #if defined(HAVE_UT_HOST) || defined(HAVE_GETUTXLINE)
532                 if (*put->ut_host)
533                         safestrncpy(hbuf, put->ut_host, 24);
534                 else
535 #endif
536                         safestrncpy(hbuf, put->ut_line, 24);
537 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
538         }
539         else goto fail;
540 #endif
541 #endif /* HAVE_UTMP_H */
542 }
543
544 /*
545  * miscellaneous server commands (testing, etc.)
546  */
547 void misc_server_cmd(CtdlIPC *ipc, char *cmd) {
548         char buf[SIZ];
549
550         CtdlIPC_chat_send(ipc, cmd);
551         CtdlIPC_chat_recv(ipc, buf);
552         scr_printf("%s\n",buf);
553         if (buf[0]=='1') {
554                 set_keepalives(KA_HALF);
555                 while (CtdlIPC_chat_recv(ipc, buf), strcmp(buf,"000")) {
556                         scr_printf("%s\n",buf);
557                 }
558                 set_keepalives(KA_YES);
559                 return;
560         }
561         if (buf[0]=='4') {
562                 do {
563                         newprompt("> ",buf,255);
564                         CtdlIPC_chat_send(ipc, buf);
565                 } while(strcmp(buf,"000"));
566                 return;
567         }
568 }
569
570
571 /*
572  * compute the checksum of a file
573  */
574 int file_checksum(char *filename)
575 {
576         int cksum = 0;
577         int ch;
578         FILE *fp;
579
580         fp = fopen(filename,"r");
581         if (fp == NULL) return(0);
582
583         /* yes, this algorithm may allow cksum to overflow, but that's ok
584          * as long as it overflows consistently, which it will.
585          */
586         while (ch=getc(fp), ch>=0) {
587                 cksum = (cksum + ch);
588         }
589
590         fclose(fp);
591         return(cksum);
592 }
593
594 /*
595  * nuke a directory and its contents
596  */
597 int nukedir(char *dirname)
598 {
599         DIR *dp;
600         struct dirent *d;
601         char filename[SIZ];
602
603         dp = opendir(dirname);
604         if (dp == NULL) {
605                 return(errno);
606         }
607
608         while (d = readdir(dp), d != NULL) {
609                 snprintf(filename, sizeof filename, "%s/%s",
610                         dirname, d->d_name);
611                 unlink(filename);
612         }
613
614         closedir(dp);
615         return(rmdir(dirname));
616 }