4 * Client-side support functions.
15 #include <sys/types.h>
16 #include <sys/ioctl.h>
22 #if TIME_WITH_SYS_TIME
23 # include <sys/time.h>
27 # include <sys/time.h>
43 #include <libcitadel.h>
45 #include "citadel_ipc.h"
48 #ifndef HAVE_GETUTLINE
49 struct utmp *getutline(struct utmp *ut);
57 #include "citadel_decls.h"
58 #include "routines2.h"
60 #define IFAIDE if(axlevel>=6)
61 #define IFNAIDE if (axlevel<6)
63 extern unsigned userflags;
64 //extern char *axdefs[8];
65 extern char sigcaught;
66 extern char rc_floor_mode;
67 extern int rc_ansi_color;
68 extern int rc_prompt_control;
70 /* Destructive backspace */
71 void back(int spaces) {
73 for (a=0; a<spaces; ++a) {
80 void hit_any_key(CtdlIPC *ipc) { /* hit any key to continue */
85 scr_printf("%s\r", ipc->ServInfo.moreprompt);
89 for (a=0; !IsEmptyStr(&ipc->ServInfo.moreprompt[a]); ++a)
93 if ( (rc_prompt_control == 1)
94 || ((rc_prompt_control == 3) && (userflags & US_PROMPTCTL)) ) {
95 if (b == 'q' || b == 'Q' || b == 's' || b == 'S')
97 if (b == 'n' || b == 'N')
100 if (b==NEXT_KEY) sigcaught = SIGINT;
101 if (b==STOP_KEY) sigcaught = SIGQUIT;
105 * Edit or delete a user (cmd=25 to edit/create, 96 to delete)
107 void edituser(CtdlIPC *ipc, int cmd)
110 char who[USERNAME_SIZE];
111 struct ctdluser *user = NULL;
113 int r; /* IPC response code */
115 newprompt("User name: ", who, 29);
116 while ((r = CtdlIPCAideGetUserParameters(ipc, who, &user, buf)) / 100 != 2) {
117 scr_printf("%s\n", buf);
119 scr_printf("Do you want to create this user? ");
121 r = CtdlIPCCreateUser(ipc, who, 0, buf);
126 scr_printf("%s\n",&buf[4]);
134 val_user(ipc, user->fullname, 0); /* Display registration */
136 if (newnow || boolprompt("Change password", 0)) {
137 strprompt("Password", user->password, -19);
140 user->axlevel = intprompt("Access level", user->axlevel, 0, 6);
141 /* user->flags = set_attr(ipc, user->flags,
142 "Permission to send Internet mail",
144 if (boolprompt("Permission to send Internet mail", (user->flags & US_INTERNET)))
145 user->flags |= US_INTERNET;
147 user->flags &= ~US_INTERNET;
148 if (boolprompt("Ask user to register again", !(user->flags & US_REGIS)))
149 user->flags &= ~US_REGIS;
151 user->flags |= US_REGIS;
152 user->timescalled = intprompt("Times called",
153 user->timescalled, 0, INT_MAX);
154 user->posted = intprompt("Messages posted",
155 user->posted, 0, INT_MAX);
156 user->lastcall = boolprompt("Set last call to now", 0) ?
157 time(NULL) : user->lastcall;
158 user->USuserpurge = intprompt("Purge time (in days, 0 for system default",
159 user->USuserpurge, 0, INT_MAX);
163 scr_printf("Do you want to delete this user? ");
171 r = CtdlIPCAideSetUserParameters(ipc, user, buf);
173 scr_printf("%s\n", buf);
179 /* Display a prompt and flip a bit based on whether the user answers
180 * yes or no. Yes=1 and No=0, unless 'backwards' is set to a nonzero value
181 * in which case No=1 and Yes=0.
183 int set_attr(CtdlIPC *ipc, unsigned int sval, char *prompt, unsigned int sbit, int backwards)
190 scr_printf("%50s ", prompt);
193 color(BRIGHT_MAGENTA);
196 scr_printf("%3s", ((temp&sbit) ? "No":"Yes"));
199 scr_printf("%3s", ((temp&sbit) ? "Yes":"No"));
207 if (backwards) a = 1 - a;
209 if (backwards) a = 1 - a;
212 if (!a) temp = (temp^sbit);
217 * modes are: 0 - .EC command, 1 - .EC for new user,
218 * 2 - toggle Xpert mode 3 - toggle floor mode
220 void enter_config(CtdlIPC *ipc, int mode)
223 struct ctdluser *user = NULL;
224 int r; /* IPC response code */
226 r = CtdlIPCGetConfig(ipc, &user, buf);
228 scr_printf("%s\n", buf);
233 if (mode == 0 || mode == 1) {
235 /* Does anyone still use dialup connections with manual
236 * screen dimensions setting anymore? For now we'll keep
237 * the system's ability to set these, but remove the prompts
238 * because they're spurious for nearly everyone.
240 user->USscreenwidth = intprompt("Enter your screen width",
241 user->USscreenwidth, 20, 255);
242 user->USscreenheight = intprompt("Enter your screen height",
243 user->USscreenheight, 3, 255);
246 user->flags = set_attr(ipc, user->flags,
247 "Are you an experienced Citadel user",
249 if ((user->flags & US_EXPERT) == 0 && mode == 1) {
254 user->flags = set_attr(ipc, user->flags,
255 "Print last old message on New message request",
258 user->flags = set_attr(ipc, user->flags,
259 "Prompt after each message",
262 if ((user->flags & US_NOPROMPT) == 0)
263 user->flags = set_attr(ipc, user->flags,
264 "Use 'disappearing' prompts",
267 user->flags = set_attr(ipc, user->flags,
268 "Pause after each screenful of text",
271 if (rc_prompt_control == 3 && (user->flags & US_PAGINATOR))
272 user->flags = set_attr(ipc, user->flags,
273 "<N>ext and <S>top work at paginator prompt",
276 if (rc_floor_mode == RC_DEFAULT)
277 user->flags = set_attr(ipc, user->flags,
278 "View rooms by floor",
281 if (rc_ansi_color == 3)
282 user->flags = set_attr(ipc, user->flags,
283 "Enable color support",
286 if ((user->flags & US_EXPERT) == 0)
287 formout(ipc, "unlisted");
289 user->flags = set_attr(ipc, user->flags,
290 "Be unlisted in userlog",
293 if (!IsEmptyStr(editor_paths[0])) {
294 user->flags = set_attr(ipc, user->flags,
295 "Always enter messages with the full-screen editor",
302 if (user->flags & US_EXPERT) {
303 user->flags ^= US_EXPERT;
304 scr_printf("Expert mode now OFF\n");
306 user->flags |= US_EXPERT;
307 scr_printf("Expert mode now ON\n");
312 if (user->flags & US_FLOORS) {
313 user->flags ^= US_FLOORS;
314 scr_printf("Floor mode now OFF\n");
316 user->flags |= US_FLOORS;
317 scr_printf("Floor mode now ON\n");
321 r = CtdlIPCSetConfig(ipc, user, buf);
322 if (r / 100 != 2) scr_printf("%s\n", buf);
323 userflags = user->flags;
328 * getstring() - get a line of text from a file
329 * ignores lines beginning with "#"
331 int getstring(FILE *fp, char *string)
346 } while(string[0]=='#');
347 return(strlen(string));
351 /* Searches for patn in search string */
352 int pattern(char *search, char *patn) {
356 for (a=0; !IsEmptyStr(&search[a]); ++a) {
357 b=strncasecmp(&search[a],patn,len);
364 void strproc(char *string)
368 if (IsEmptyStr(string)) return;
370 /* Convert non-printable characters to blanks */
371 for (a=0; !IsEmptyStr(&string[a]); ++a) {
372 if (string[a]<32) string[a]=32;
373 if (string[a]>126) string[a]=32;
376 /* Remove leading and trailing blanks */
377 while(string[0]<33) strcpy(string,&string[1]);
378 while(string[strlen(string)-1]<33) string[strlen(string)-1]=0;
380 /* Remove double blanks */
381 for (a=0; a<strlen(string); ++a) {
382 if ((string[a]==32)&&(string[a+1]==32)) {
383 strcpy(&string[a],&string[a+1]);
388 /* remove characters which would interfere with the network */
389 for (a=0; a<strlen(string); ++a) {
390 if (string[a]=='!') strcpy(&string[a],&string[a+1]);
391 if (string[a]=='@') strcpy(&string[a],&string[a+1]);
392 if (string[a]=='_') strcpy(&string[a],&string[a+1]);
393 if (string[a]==',') strcpy(&string[a],&string[a+1]);
394 if (string[a]=='%') strcpy(&string[a],&string[a+1]);
395 if (string[a]=='|') strcpy(&string[a],&string[a+1]);
401 #ifndef HAVE_STRERROR
403 * replacement strerror() for systems that don't have it
405 char *strerror(int e)
407 static char buf[128];
409 snprintf(buf, sizeof buf, "errno = %d",e);
415 void progress(CtdlIPC* ipc, unsigned long curr, unsigned long cmax)
418 "**************************************************";
419 char dots_printed[51];
424 sln_printf("\r%79s\r","");
425 status_line(ipc->ServInfo.humannode, ipc->ServInfo.site_location,
426 room_name, secure, 0);
428 /* a will be range 0-50 rather than 0-100 */
429 a=(curr * 50) / cmax;
430 sprintf(fmt, "[%%s%%%lds] %%3ld%%%% %%10ld/%%10ld\r", 50 - a);
431 strncpy(dots_printed, dots, a);
433 sln_printf(fmt, dots_printed, "",
434 curr * 100 / cmax, curr, cmax);
441 * NOT the same locate_host() in locate_host.c. This one just does a
442 * 'who am i' to try to discover where the user is...
444 void locate_host(CtdlIPC* ipc, char *hbuf)
451 who = (FILE *)popen("who am i","r");
453 strcpy(hbuf, ipc->ServInfo.fqdn);
456 fgets(buf,sizeof buf,who);
460 for (a=0; !IsEmptyStr(&buf[a]); ++a) {
461 if ((buf[a]=='(')||(buf[a]==')')) ++b;
464 strcpy(hbuf, ipc->ServInfo.fqdn);
468 for (a=0; a<strlen(buf); ++a) {
470 strcpy(buf,&buf[a+1]);
473 for (a=0; a<strlen(buf); ++a) {
474 if (buf[a]==')') buf[a] = 0;
477 if (IsEmptyStr(buf)) strcpy(hbuf, ipc->ServInfo.fqdn);
478 else strncpy(hbuf,buf,24);
480 char *tty = ttyname(0);
481 #ifdef HAVE_GETUTXLINE
482 struct utmpx ut, *put;
484 struct utmp ut, *put;
489 safestrncpy(hbuf, ipc->ServInfo.fqdn, 24);
493 if (strncmp(tty, "/dev/", 5))
496 safestrncpy(ut.ut_line, &tty[5], sizeof ut.ut_line);
498 #ifdef HAVE_GETUTXLINE /* Solaris uses this */
499 if ((put = getutxline(&ut)) == NULL)
501 if ((put = getutline(&ut)) == NULL)
505 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
506 if (put->ut_type == USER_PROCESS) {
508 #if defined(HAVE_UT_HOST) || defined(HAVE_GETUTXLINE)
510 safestrncpy(hbuf, put->ut_host, 24);
513 safestrncpy(hbuf, put->ut_line, 24);
514 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
518 #endif /* HAVE_UTMP_H */
522 * miscellaneous server commands (testing, etc.)
524 void misc_server_cmd(CtdlIPC *ipc, char *cmd) {
527 CtdlIPC_chat_send(ipc, cmd);
528 CtdlIPC_chat_recv(ipc, buf);
529 scr_printf("%s\n",buf);
531 set_keepalives(KA_HALF);
532 while (CtdlIPC_chat_recv(ipc, buf), strcmp(buf,"000")) {
533 scr_printf("%s\n",buf);
535 set_keepalives(KA_YES);
540 newprompt("> ",buf,255);
541 CtdlIPC_chat_send(ipc, buf);
542 } while(strcmp(buf,"000"));
549 * compute the checksum of a file
551 int file_checksum(char *filename)
557 fp = fopen(filename,"r");
558 if (fp == NULL) return(0);
560 /* yes, this algorithm may allow cksum to overflow, but that's ok
561 * as long as it overflows consistently, which it will.
563 while (ch=getc(fp), ch>=0) {
564 cksum = (cksum + ch);
572 * nuke a directory and its contents
574 int nukedir(char *dirname)
580 dp = opendir(dirname);
585 while (d = readdir(dp), d != NULL) {
586 snprintf(filename, sizeof filename, "%s/%s",
592 return(rmdir(dirname));