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 char newname
[USERNAME_SIZE
];
112 struct ctdluser
*user
= NULL
;
114 int r
; /* IPC response code */
119 newprompt("User name: ", who
, 29);
120 while ((r
= CtdlIPCAideGetUserParameters(ipc
, who
, &user
, buf
)) / 100 != 2) {
121 scr_printf("%s\n", buf
);
123 scr_printf("Do you want to create this user? ");
125 r
= CtdlIPCCreateUser(ipc
, who
, 0, buf
);
130 scr_printf("%s\n", buf
);
138 val_user(ipc
, user
->fullname
, 0); /* Display registration */
142 while (change_name
== 1) {
143 if (boolprompt("Change name", 0)) {
144 strprompt("New name", newname
, USERNAME_SIZE
-1);
145 r
= CtdlIPCRenameUser(ipc
, user
->fullname
, newname
, buf
);
147 scr_printf("%s\n", buf
);
150 strcpy(user
->fullname
, newname
);
160 if (newnow
|| boolprompt("Change password", 0)) {
161 strprompt("Password", user
->password
, -19);
164 user
->axlevel
= intprompt("Access level", user
->axlevel
, 0, 6);
165 if (boolprompt("Permission to send Internet mail", (user
->flags
& US_INTERNET
)))
166 user
->flags
|= US_INTERNET
;
168 user
->flags
&= ~US_INTERNET
;
169 if (boolprompt("Ask user to register again", !(user
->flags
& US_REGIS
)))
170 user
->flags
&= ~US_REGIS
;
172 user
->flags
|= US_REGIS
;
173 user
->timescalled
= intprompt("Times called",
174 user
->timescalled
, 0, INT_MAX
);
175 user
->posted
= intprompt("Messages posted",
176 user
->posted
, 0, INT_MAX
);
177 user
->lastcall
= boolprompt("Set last call to now", 0) ?
178 time(NULL
) : user
->lastcall
;
179 user
->USuserpurge
= intprompt("Purge time (in days, 0 for system default",
180 user
->USuserpurge
, 0, INT_MAX
);
184 scr_printf("Do you want to delete this user? ");
192 r
= CtdlIPCAideSetUserParameters(ipc
, user
, buf
);
194 scr_printf("%s\n", buf
);
200 /* Display a prompt and flip a bit based on whether the user answers
201 * yes or no. Yes=1 and No=0, unless 'backwards' is set to a nonzero value
202 * in which case No=1 and Yes=0.
204 int set_attr(CtdlIPC
*ipc
, unsigned int sval
, char *prompt
, unsigned int sbit
, int backwards
)
211 scr_printf("%50s ", prompt
);
214 color(BRIGHT_MAGENTA
);
217 scr_printf("%3s", ((temp
&sbit
) ? "No":"Yes"));
220 scr_printf("%3s", ((temp
&sbit
) ? "Yes":"No"));
228 if (backwards
) a
= 1 - a
;
230 if (backwards
) a
= 1 - a
;
233 if (!a
) temp
= (temp
^sbit
);
238 * modes are: 0 - .EC command, 1 - .EC for new user,
239 * 2 - toggle Xpert mode 3 - toggle floor mode
241 void enter_config(CtdlIPC
*ipc
, int mode
)
244 struct ctdluser
*user
= NULL
;
245 int r
; /* IPC response code */
247 r
= CtdlIPCGetConfig(ipc
, &user
, buf
);
249 scr_printf("%s\n", buf
);
254 if (mode
== 0 || mode
== 1) {
256 /* Does anyone still use dialup connections with manual
257 * screen dimensions setting anymore? For now we'll keep
258 * the system's ability to set these, but remove the prompts
259 * because they're spurious for nearly everyone.
261 user->USscreenwidth = intprompt("Enter your screen width",
262 user->USscreenwidth, 20, 255);
263 user->USscreenheight = intprompt("Enter your screen height",
264 user->USscreenheight, 3, 255);
267 user
->flags
= set_attr(ipc
, user
->flags
,
268 "Are you an experienced Citadel user",
270 if ((user
->flags
& US_EXPERT
) == 0 && mode
== 1) {
275 user
->flags
= set_attr(ipc
, user
->flags
,
276 "Print last old message on New message request",
279 user
->flags
= set_attr(ipc
, user
->flags
,
280 "Prompt after each message",
283 if ((user
->flags
& US_NOPROMPT
) == 0)
284 user
->flags
= set_attr(ipc
, user
->flags
,
285 "Use 'disappearing' prompts",
288 user
->flags
= set_attr(ipc
, user
->flags
,
289 "Pause after each screenful of text",
292 if (rc_prompt_control
== 3 && (user
->flags
& US_PAGINATOR
))
293 user
->flags
= set_attr(ipc
, user
->flags
,
294 "<N>ext and <S>top work at paginator prompt",
297 if (rc_floor_mode
== RC_DEFAULT
)
298 user
->flags
= set_attr(ipc
, user
->flags
,
299 "View rooms by floor",
302 if (rc_ansi_color
== 3)
303 user
->flags
= set_attr(ipc
, user
->flags
,
304 "Enable color support",
307 if ((user
->flags
& US_EXPERT
) == 0)
308 formout(ipc
, "unlisted");
310 user
->flags
= set_attr(ipc
, user
->flags
,
311 "Be unlisted in userlog",
314 if (!IsEmptyStr(editor_paths
[0])) {
315 user
->flags
= set_attr(ipc
, user
->flags
,
316 "Always enter messages with the full-screen editor",
323 if (user
->flags
& US_EXPERT
) {
324 user
->flags
^= US_EXPERT
;
325 scr_printf("Expert mode now OFF\n");
327 user
->flags
|= US_EXPERT
;
328 scr_printf("Expert mode now ON\n");
333 if (user
->flags
& US_FLOORS
) {
334 user
->flags
^= US_FLOORS
;
335 scr_printf("Floor mode now OFF\n");
337 user
->flags
|= US_FLOORS
;
338 scr_printf("Floor mode now ON\n");
342 r
= CtdlIPCSetConfig(ipc
, user
, buf
);
343 if (r
/ 100 != 2) scr_printf("%s\n", buf
);
344 userflags
= user
->flags
;
349 * getstring() - get a line of text from a file
350 * ignores lines beginning with "#"
352 int getstring(FILE *fp
, char *string
)
367 } while(string
[0]=='#');
368 return(strlen(string
));
372 /* Searches for patn in search string */
373 int pattern(char *search
, char *patn
) {
377 for (a
=0; !IsEmptyStr(&search
[a
]); ++a
) {
378 b
=strncasecmp(&search
[a
],patn
,len
);
385 void strproc(char *string
)
389 if (IsEmptyStr(string
)) return;
391 /* Convert non-printable characters to blanks */
392 for (a
=0; !IsEmptyStr(&string
[a
]); ++a
) {
393 if (string
[a
]<32) string
[a
]=32;
394 if (string
[a
]>126) string
[a
]=32;
397 /* Remove leading and trailing blanks */
398 while(string
[0]<33) strcpy(string
,&string
[1]);
399 while(string
[strlen(string
)-1]<33) string
[strlen(string
)-1]=0;
401 /* Remove double blanks */
402 for (a
=0; a
<strlen(string
); ++a
) {
403 if ((string
[a
]==32)&&(string
[a
+1]==32)) {
404 strcpy(&string
[a
],&string
[a
+1]);
409 /* remove characters which would interfere with the network */
410 for (a
=0; a
<strlen(string
); ++a
) {
411 if (string
[a
]=='!') strcpy(&string
[a
],&string
[a
+1]);
412 if (string
[a
]=='@') strcpy(&string
[a
],&string
[a
+1]);
413 if (string
[a
]=='_') strcpy(&string
[a
],&string
[a
+1]);
414 if (string
[a
]==',') strcpy(&string
[a
],&string
[a
+1]);
415 if (string
[a
]=='%') strcpy(&string
[a
],&string
[a
+1]);
416 if (string
[a
]=='|') strcpy(&string
[a
],&string
[a
+1]);
422 #ifndef HAVE_STRERROR
424 * replacement strerror() for systems that don't have it
426 char *strerror(int e
)
428 static char buf
[128];
430 snprintf(buf
, sizeof buf
, "errno = %d",e
);
436 void progress(CtdlIPC
* ipc
, unsigned long curr
, unsigned long cmax
)
439 "**************************************************";
440 char dots_printed
[51];
445 sln_printf("\r%79s\r","");
446 status_line(ipc
->ServInfo
.humannode
, ipc
->ServInfo
.site_location
,
447 room_name
, secure
, 0);
449 /* a will be range 0-50 rather than 0-100 */
450 a
=(curr
* 50) / cmax
;
451 sprintf(fmt
, "[%%s%%%lds] %%3ld%%%% %%10ld/%%10ld\r", 50 - a
);
452 strncpy(dots_printed
, dots
, a
);
454 sln_printf(fmt
, dots_printed
, "",
455 curr
* 100 / cmax
, curr
, cmax
);
462 * NOT the same locate_host() in locate_host.c. This one just does a
463 * 'who am i' to try to discover where the user is...
465 void locate_host(CtdlIPC
* ipc
, char *hbuf
)
472 who
= (FILE *)popen("who am i","r");
474 strcpy(hbuf
, ipc
->ServInfo
.fqdn
);
477 fgets(buf
,sizeof buf
,who
);
481 for (a
=0; !IsEmptyStr(&buf
[a
]); ++a
) {
482 if ((buf
[a
]=='(')||(buf
[a
]==')')) ++b
;
485 strcpy(hbuf
, ipc
->ServInfo
.fqdn
);
489 for (a
=0; a
<strlen(buf
); ++a
) {
491 strcpy(buf
,&buf
[a
+1]);
494 for (a
=0; a
<strlen(buf
); ++a
) {
495 if (buf
[a
]==')') buf
[a
] = 0;
498 if (IsEmptyStr(buf
)) strcpy(hbuf
, ipc
->ServInfo
.fqdn
);
499 else strncpy(hbuf
,buf
,24);
501 char *tty
= ttyname(0);
502 #ifdef HAVE_GETUTXLINE
503 struct utmpx ut
, *put
;
505 struct utmp ut
, *put
;
510 safestrncpy(hbuf
, ipc
->ServInfo
.fqdn
, 24);
514 if (strncmp(tty
, "/dev/", 5))
517 safestrncpy(ut
.ut_line
, &tty
[5], sizeof ut
.ut_line
);
519 #ifdef HAVE_GETUTXLINE /* Solaris uses this */
520 if ((put
= getutxline(&ut
)) == NULL
)
522 if ((put
= getutline(&ut
)) == NULL
)
526 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
527 if (put
->ut_type
== USER_PROCESS
) {
529 #if defined(HAVE_UT_HOST) || defined(HAVE_GETUTXLINE)
531 safestrncpy(hbuf
, put
->ut_host
, 24);
534 safestrncpy(hbuf
, put
->ut_line
, 24);
535 #if defined(HAVE_UT_TYPE) || defined(HAVE_GETUTXLINE)
539 #endif /* HAVE_UTMP_H */
543 * miscellaneous server commands (testing, etc.)
545 void misc_server_cmd(CtdlIPC
*ipc
, char *cmd
) {
548 CtdlIPC_chat_send(ipc
, cmd
);
549 CtdlIPC_chat_recv(ipc
, buf
);
550 scr_printf("%s\n",buf
);
552 set_keepalives(KA_HALF
);
553 while (CtdlIPC_chat_recv(ipc
, buf
), strcmp(buf
,"000")) {
554 scr_printf("%s\n",buf
);
556 set_keepalives(KA_YES
);
561 newprompt("> ",buf
,255);
562 CtdlIPC_chat_send(ipc
, buf
);
563 } while(strcmp(buf
,"000"));
570 * compute the checksum of a file
572 int file_checksum(char *filename
)
578 fp
= fopen(filename
,"r");
579 if (fp
== NULL
) return(0);
581 /* yes, this algorithm may allow cksum to overflow, but that's ok
582 * as long as it overflows consistently, which it will.
584 while (ch
=getc(fp
), ch
>=0) {
585 cksum
= (cksum
+ ch
);
593 * nuke a directory and its contents
595 int nukedir(char *dirname
)
601 dp
= opendir(dirname
);
606 while (d
= readdir(dp
), d
!= NULL
) {
607 snprintf(filename
, sizeof filename
, "%s/%s",
613 return(rmdir(dirname
));