2 * Client-side support functions.
4 * Copyright (c) 1987-2012 by the citadel.org team
6 * This program is open source software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
22 #include <sys/types.h>
23 #include <sys/ioctl.h>
29 #if TIME_WITH_SYS_TIME
30 # include <sys/time.h>
34 # include <sys/time.h>
50 #include <libcitadel.h>
51 ///#include "citadel.h"
52 #include "citadel_ipc.h"
55 #ifndef HAVE_GETUTLINE
56 struct utmp *getutline(struct utmp *ut);
61 ///#include "citadel.h"
64 #include "citadel_decls.h"
65 #include "routines2.h"
66 #include "tuiconfig.h"
68 #define IFAIDE if(axlevel>=AxAideU)
69 #define IFNAIDE if (axlevel<AxAideU)
71 extern unsigned userflags;
72 //extern char *axdefs[8];
73 extern char sigcaught;
74 extern char rc_floor_mode;
75 extern int rc_ansi_color;
76 extern int rc_prompt_control;
78 /* Destructive backspace */
79 void back(int spaces) {
81 for (a=0; a<spaces; ++a) {
89 * Edit or delete a user (cmd=25 to edit/create, 96 to delete)
91 void edituser(CtdlIPC *ipc, int cmd)
94 char who[USERNAME_SIZE];
95 char newname[USERNAME_SIZE];
96 struct ctdluser *user = NULL;
98 int r; /* IPC response code */
103 newprompt("User name: ", who, 29);
104 while ((r = CtdlIPCAideGetUserParameters(ipc, who, &user, buf)) / 100 != 2) {
105 scr_printf("%s\n", buf);
107 scr_printf("Do you want to create this user? ");
109 r = CtdlIPCCreateUser(ipc, who, 0, buf);
114 scr_printf("%s\n", buf);
122 val_user(ipc, user->fullname, 0); /* Display registration */
126 while (change_name == 1) {
127 if (boolprompt("Change name", 0)) {
128 strprompt("New name", newname, USERNAME_SIZE-1);
129 r = CtdlIPCRenameUser(ipc, user->fullname, newname, buf);
131 scr_printf("%s\n", buf);
134 strcpy(user->fullname, newname);
144 if (newnow || boolprompt("Change password", 0)) {
145 strprompt("Password", user->password, -19);
148 user->axlevel = intprompt("Access level", user->axlevel, 0, 6);
149 if (boolprompt("Permission to send Internet mail", (user->flags & US_INTERNET)))
150 user->flags |= US_INTERNET;
152 user->flags &= ~US_INTERNET;
153 if (boolprompt("Ask user to register again", !(user->flags & US_REGIS)))
154 user->flags &= ~US_REGIS;
156 user->flags |= US_REGIS;
157 user->timescalled = intprompt("Times called",
158 user->timescalled, 0, INT_MAX);
159 user->posted = intprompt("Messages posted",
160 user->posted, 0, INT_MAX);
161 user->lastcall = boolprompt("Set last call to now", 0) ?
162 time(NULL) : user->lastcall;
163 user->USuserpurge = intprompt("Purge time (in days, 0 for system default",
164 user->USuserpurge, 0, INT_MAX);
168 scr_printf("Do you want to delete this user? ");
173 user->axlevel = AxDeleted;
176 r = CtdlIPCAideSetUserParameters(ipc, user, buf);
178 scr_printf("%s\n", buf);
184 /* Display a prompt and flip a bit based on whether the user answers
185 * yes or no. Yes=1 and No=0, unless 'backwards' is set to a nonzero value
186 * in which case No=1 and Yes=0.
188 int set_attr(CtdlIPC *ipc, unsigned int sval, char *prompt, unsigned int sbit, int backwards)
195 scr_printf("%50s ", prompt);
198 color(BRIGHT_MAGENTA);
201 scr_printf("%3s", ((temp&sbit) ? "No":"Yes"));
204 scr_printf("%3s", ((temp&sbit) ? "Yes":"No"));
212 if (backwards) a = 1 - a;
214 if (backwards) a = 1 - a;
217 if (!a) temp = (temp^sbit);
222 * modes are: 0 - .EC command, 1 - .EC for new user,
223 * 2 - toggle Xpert mode 3 - toggle floor mode
225 void enter_config(CtdlIPC *ipc, int mode)
228 struct ctdluser *user = NULL;
229 int r; /* IPC response code */
231 r = CtdlIPCGetConfig(ipc, &user, buf);
233 scr_printf("%s\n", buf);
238 if (mode == 0 || mode == 1) {
240 user->flags = set_attr(ipc, user->flags,
241 "Are you an experienced Citadel user",
243 if ((user->flags & US_EXPERT) == 0 && mode == 1) {
248 user->flags = set_attr(
251 "Print last old message on New message request",
256 user->flags = set_attr(
259 "Prompt after each message",
264 if ((user->flags & US_NOPROMPT) == 0) {
265 user->flags = set_attr(
268 "Use 'disappearing' prompts",
274 user->flags = set_attr(
277 "Pause after each screenful of text",
282 if (rc_prompt_control == 3 && (user->flags & US_PAGINATOR)) {
283 user->flags = set_attr(
286 "<N>ext and <S>top work at paginator prompt",
292 if (rc_floor_mode == RC_DEFAULT) {
293 user->flags = set_attr(
296 "View rooms by floor",
302 if (rc_ansi_color == 3) {
303 user->flags = set_attr(
306 "Enable color support",
312 if ((user->flags & US_EXPERT) == 0) {
313 formout(ipc, "unlisted");
316 user->flags = set_attr(
319 "Be unlisted in userlog",
324 if (!IsEmptyStr(editor_path)) {
325 user->flags = set_attr(
328 "Always enter messages with the full-screen editor",
337 if (user->flags & US_EXPERT) {
338 user->flags ^= US_EXPERT;
339 scr_printf("Expert mode now OFF\n");
341 user->flags |= US_EXPERT;
342 scr_printf("Expert mode now ON\n");
347 if (user->flags & US_FLOORS) {
348 user->flags ^= US_FLOORS;
349 scr_printf("Floor mode now OFF\n");
351 user->flags |= US_FLOORS;
352 scr_printf("Floor mode now ON\n");
356 r = CtdlIPCSetConfig(ipc, user, buf);
357 if (r / 100 != 2) scr_printf("%s\n", buf);
358 userflags = user->flags;
363 * getstring() - get a line of text from a file
364 * ignores lines beginning with "#"
366 int getstring(FILE *fp, char *string)
381 } while(string[0]=='#');
382 return(strlen(string));
386 /* Searches for patn in search string */
387 int pattern(char *search, char *patn) {
391 for (a=0; !IsEmptyStr(&search[a]); ++a) {
392 b=strncasecmp(&search[a],patn,len);
399 void strproc(char *string)
403 if (IsEmptyStr(string)) return;
405 /* Convert non-printable characters to blanks */
406 for (a=0; !IsEmptyStr(&string[a]); ++a) {
407 if (string[a]<32) string[a]=32;
408 if (string[a]>126) string[a]=32;
411 /* Remove leading and trailing blanks */
412 while(string[0]<33) strcpy(string,&string[1]);
413 while(string[strlen(string)-1]<33) string[strlen(string)-1]=0;
415 /* Remove double blanks */
416 for (a=0; a<strlen(string); ++a) {
417 if ((string[a]==32)&&(string[a+1]==32)) {
418 strcpy(&string[a],&string[a+1]);
423 /* remove characters which would interfere with the network */
424 for (a=0; a<strlen(string); ++a) {
425 if (string[a]=='!') strcpy(&string[a],&string[a+1]);
426 if (string[a]=='@') strcpy(&string[a],&string[a+1]);
427 if (string[a]=='_') strcpy(&string[a],&string[a+1]);
428 if (string[a]==',') strcpy(&string[a],&string[a+1]);
429 if (string[a]=='%') strcpy(&string[a],&string[a+1]);
430 if (string[a]=='|') strcpy(&string[a],&string[a+1]);
436 #ifndef HAVE_STRERROR
438 * replacement strerror() for systems that don't have it
440 char *strerror(int e)
442 static char buf[128];
444 snprintf(buf, sizeof buf, "errno = %d",e);
450 void progress(CtdlIPC* ipc, unsigned long curr, unsigned long cmax)
453 "**************************************************";
454 char dots_printed[51];
459 scr_printf("\r%79s\r","");
461 /* a will be range 0-50 rather than 0-100 */
462 a=(curr * 50) / cmax;
463 sprintf(fmt, "[%%s%%%lds] %%3ld%%%% %%10ld/%%10ld\r", 50 - a);
464 strncpy(dots_printed, dots, a);
466 scr_printf(fmt, dots_printed, "",
467 curr * 100 / cmax, curr, cmax);
474 * NOT the same locate_host() in locate_host.c. This one just does a
475 * 'who am i' to try to discover where the user is...
477 void locate_host(CtdlIPC* ipc, char *hbuf)
484 who = (FILE *)popen("who am i","r");
486 strcpy(hbuf, ipc->ServInfo.fqdn);
489 fgets(buf,sizeof buf,who);
493 for (a=0; !IsEmptyStr(&buf[a]); ++a) {
494 if ((buf[a]=='(')||(buf[a]==')')) ++b;
497 strcpy(hbuf, ipc->ServInfo.fqdn);
501 for (a=0; a<strlen(buf); ++a) {
503 strcpy(buf,&buf[a+1]);
506 for (a=0; a<strlen(buf); ++a) {
507 if (buf[a]==')') buf[a] = 0;
510 if (IsEmptyStr(buf)) strcpy(hbuf, ipc->ServInfo.fqdn);
511 else strncpy(hbuf,buf,24);
513 char *tty = ttyname(0);
514 #ifdef HAVE_GETUTXLINE
515 struct utmpx ut, *put;
517 struct utmp ut, *put;
522 safestrncpy(hbuf, ipc->ServInfo.fqdn, 24);
526 if (strncmp(tty, "/dev/", 5))
529 safestrncpy(ut.ut_line, &tty[5], sizeof ut.ut_line);
531 #ifdef HAVE_GETUTXLINE /* Solaris uses this */
532 if ((put = getutxline(&ut)) == NULL)
534 if ((put = getutline(&ut)) == NULL)
538 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
539 if (put->ut_type == USER_PROCESS) {
541 #if defined(HAVE_UT_HOST) || defined(HAVE_GETUTXLINE)
543 safestrncpy(hbuf, put->ut_host, 24);
546 safestrncpy(hbuf, put->ut_line, 24);
547 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
551 #endif /* HAVE_UTMP_H */
555 * miscellaneous server commands (testing, etc.)
557 void misc_server_cmd(CtdlIPC *ipc, char *cmd) {
560 CtdlIPC_chat_send(ipc, cmd);
561 CtdlIPC_chat_recv(ipc, buf);
562 scr_printf("%s\n",buf);
564 set_keepalives(KA_HALF);
565 while (CtdlIPC_chat_recv(ipc, buf), strcmp(buf,"000")) {
566 scr_printf("%s\n",buf);
568 set_keepalives(KA_YES);
573 newprompt("> ",buf,255);
574 CtdlIPC_chat_send(ipc, buf);
575 } while(strcmp(buf,"000"));
582 * compute the checksum of a file
584 int file_checksum(char *filename)
590 fp = fopen(filename,"r");
591 if (fp == NULL) return(0);
593 /* yes, this algorithm may allow cksum to overflow, but that's ok
594 * as long as it overflows consistently, which it will.
596 while (ch=getc(fp), ch>=0) {
597 cksum = (cksum + ch);
605 * nuke a directory and its contents
607 int nukedir(char *dirname)
613 dp = opendir(dirname);
618 while (d = readdir(dp), d != NULL) {
619 snprintf(filename, sizeof filename, "%s/%s",
625 return(rmdir(dirname));