2 * Client-side support functions.
4 * Copyright (c) 1987-2016 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.
15 #include "textclient.h"
17 #define IFAIDE if(axlevel>=AxAideU)
18 #define IFNAIDE if (axlevel<AxAideU)
20 extern unsigned userflags;
21 extern char sigcaught;
22 extern char rc_floor_mode;
23 extern int rc_ansi_color;
24 extern int rc_prompt_control;
26 /* Destructive backspace */
27 void back(int spaces) {
29 for (a=0; a<spaces; ++a) {
37 * Edit a user's Internet email addresses
39 void edit_user_internet_email_addresses(CtdlIPC *ipc, char *who)
52 r = CtdlIPCAideGetEmailAddresses(ipc, who, emailaddrs, buf);
54 while (!IsEmptyStr(emailaddrs)) {
55 extract_token(buf, emailaddrs, 0, '\n', sizeof buf);
56 remove_token(emailaddrs, 0, '\n');
57 if (!IsEmptyStr(buf)) {
59 if (num_recs == 1) recs = malloc(sizeof(char *));
60 else recs = realloc(recs, (sizeof(char *)) * num_recs);
61 recs[num_recs-1] = malloc(strlen(buf) + 1);
62 strcpy(recs[num_recs-1], buf);
70 scr_printf(" Internet email addresses for %s\n", who);
72 scr_printf("--- --------------------------------------------------\n");
73 for (i=0; i<num_recs; ++i) {
75 scr_printf("%3d ", i+1);
77 scr_printf("%s\n", recs[i]);
81 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
84 newprompt("Enter new email address: ", buf, 50);
86 if (!IsEmptyStr(buf)) {
87 // FIXME validate the email address (format, our own domain, addr does not belong to another user)
90 recs = malloc(sizeof(char *));
93 recs = realloc(recs, (sizeof(char *)) * num_recs);
95 recs[num_recs-1] = strdup(buf);
100 i = intprompt("Delete which address", 1, 1, num_recs) - 1;
103 for (j=i; j<num_recs; ++j) {
110 for (i = 0; i < num_recs; i++)
111 r += 1 + strlen(recs[i]);
112 resp = (char *)calloc(1, r);
114 scr_printf("Can't save config - out of memory!\n");
117 if (num_recs) for (i = 0; i < num_recs; i++) {
118 strcat(resp, recs[i]);
121 r = CtdlIPCAideSetEmailAddresses(ipc, who, resp, buf);
123 scr_printf("%s\n", buf);
125 scr_printf("Saved %d addresses.\n", num_recs);
132 quitting = !modified || boolprompt("Quit without saving", 0);
140 for (i=0; i<num_recs; ++i) free(recs[i]);
147 * Edit or delete a user (cmd=25 to edit/create, 96 to delete)
149 void edituser(CtdlIPC *ipc, int cmd)
152 char who[USERNAME_SIZE];
153 char newname[USERNAME_SIZE];
154 struct ctdluser *user = NULL;
156 int r; /* IPC response code */
161 newprompt("User name: ", who, 29);
162 while ((r = CtdlIPCAideGetUserParameters(ipc, who, &user, buf)) / 100 != 2) {
163 scr_printf("%s\n", buf);
165 scr_printf("Do you want to create this user? ");
167 r = CtdlIPCCreateUser(ipc, who, 0, buf);
172 scr_printf("%s\n", buf);
179 if (cmd == 25) { // user edit
181 /* val_user(ipc, user->fullname, 0); we used to display the vCard here but there's really no need */
185 while (change_name == 1) {
186 if (boolprompt("Change name", 0)) {
187 strprompt("New name", newname, USERNAME_SIZE-1);
188 r = CtdlIPCRenameUser(ipc, user->fullname, newname, buf);
190 scr_printf("%s\n", buf);
193 strcpy(user->fullname, newname);
203 if (newnow || boolprompt("Change password", 0)) {
204 strprompt("Password", user->password, -19);
207 user->axlevel = intprompt("Access level", user->axlevel, 0, 6);
208 if (boolprompt("Permission to send Internet mail", (user->flags & US_INTERNET))) {
209 user->flags |= US_INTERNET;
212 user->flags &= ~US_INTERNET;
214 if (boolprompt("Ask user to register again", !(user->flags & US_REGIS))) {
215 user->flags &= ~US_REGIS;
218 user->flags |= US_REGIS;
220 user->timescalled = intprompt("Times called", user->timescalled, 0, INT_MAX);
221 user->posted = intprompt("Messages posted", user->posted, 0, INT_MAX);
222 user->lastcall = boolprompt("Set last login to now", 0) ? time(NULL) : user->lastcall;
223 user->USuserpurge = intprompt("Purge time (in days, 0 for system default", user->USuserpurge, 0, INT_MAX);
227 scr_printf("Do you want to delete this user? ");
232 user->axlevel = AxDeleted;
235 r = CtdlIPCAideSetUserParameters(ipc, user, buf);
237 scr_printf("%s\n", buf);
241 if (boolprompt("Edit this user's Internet email addresses", 0)) {
242 edit_user_internet_email_addresses(ipc, who);
248 /* Display a prompt and flip a bit based on whether the user answers
249 * yes or no. Yes=1 and No=0, unless 'backwards' is set to a nonzero value
250 * in which case No=1 and Yes=0.
252 int set_attr(CtdlIPC *ipc, unsigned int sval, char *prompt, unsigned int sbit, int backwards)
259 scr_printf("%50s ", prompt);
262 color(BRIGHT_MAGENTA);
265 scr_printf("%3s", ((temp&sbit) ? "No":"Yes"));
268 scr_printf("%3s", ((temp&sbit) ? "Yes":"No"));
276 if (backwards) a = 1 - a;
278 if (backwards) a = 1 - a;
281 if (!a) temp = (temp^sbit);
286 * modes are: 0 - .EC command, 1 - .EC for new user,
287 * 2 - toggle Xpert mode 3 - toggle floor mode
289 void enter_config(CtdlIPC *ipc, int mode)
292 struct ctdluser *user = NULL;
293 int r; /* IPC response code */
295 r = CtdlIPCGetConfig(ipc, &user, buf);
297 scr_printf("%s\n", buf);
302 if (mode == 0 || mode == 1) {
304 user->flags = set_attr(ipc, user->flags,
305 "Are you an experienced Citadel user",
307 if ((user->flags & US_EXPERT) == 0 && mode == 1) {
312 user->flags = set_attr(
315 "Print last old message on New message request",
320 user->flags = set_attr(
323 "Prompt after each message",
328 if ((user->flags & US_NOPROMPT) == 0) {
329 user->flags = set_attr(
332 "Use 'disappearing' prompts",
338 user->flags = set_attr(
341 "Pause after each screenful of text",
346 if (rc_prompt_control == 3 && (user->flags & US_PAGINATOR)) {
347 user->flags = set_attr(
350 "<N>ext and <S>top work at paginator prompt",
356 if (rc_floor_mode == RC_DEFAULT) {
357 user->flags = set_attr(
360 "View rooms by floor",
366 if (rc_ansi_color == 3) {
367 user->flags = set_attr(
370 "Enable color support",
376 if ((user->flags & US_EXPERT) == 0) {
377 formout(ipc, "unlisted");
380 user->flags = set_attr(
383 "Be unlisted in userlog",
388 if (!IsEmptyStr(editor_path)) {
389 user->flags = set_attr(
392 "Always enter messages with the full-screen editor",
401 if (user->flags & US_EXPERT) {
402 user->flags ^= US_EXPERT;
403 scr_printf("Expert mode now OFF\n");
405 user->flags |= US_EXPERT;
406 scr_printf("Expert mode now ON\n");
411 if (user->flags & US_FLOORS) {
412 user->flags ^= US_FLOORS;
413 scr_printf("Floor mode now OFF\n");
415 user->flags |= US_FLOORS;
416 scr_printf("Floor mode now ON\n");
420 r = CtdlIPCSetConfig(ipc, user, buf);
421 if (r / 100 != 2) scr_printf("%s\n", buf);
422 userflags = user->flags;
427 * getstring() - get a line of text from a file
428 * ignores lines beginning with "#"
430 int getstring(FILE *fp, char *string)
445 } while(string[0]=='#');
446 return(strlen(string));
450 /* Searches for patn in search string */
451 int pattern(char *search, char *patn) {
455 for (a=0; !IsEmptyStr(&search[a]); ++a) {
456 b=strncasecmp(&search[a],patn,len);
463 void strproc(char *string)
467 if (IsEmptyStr(string)) return;
469 /* Convert non-printable characters to blanks */
470 for (a=0; !IsEmptyStr(&string[a]); ++a) {
471 if (string[a]<32) string[a]=32;
472 if (string[a]>126) string[a]=32;
475 /* Remove leading and trailing blanks */
476 while(string[0]<33) strcpy(string,&string[1]);
477 while(string[strlen(string)-1]<33) string[strlen(string)-1]=0;
479 /* Remove double blanks */
480 for (a=0; a<strlen(string); ++a) {
481 if ((string[a]==32)&&(string[a+1]==32)) {
482 strcpy(&string[a],&string[a+1]);
487 /* remove characters which would interfere with the network */
488 for (a=0; a<strlen(string); ++a) {
489 if (string[a]=='!') strcpy(&string[a],&string[a+1]);
490 if (string[a]=='@') strcpy(&string[a],&string[a+1]);
491 if (string[a]=='_') strcpy(&string[a],&string[a+1]);
492 if (string[a]==',') strcpy(&string[a],&string[a+1]);
493 if (string[a]=='%') strcpy(&string[a],&string[a+1]);
494 if (string[a]=='|') strcpy(&string[a],&string[a+1]);
500 void progress(CtdlIPC* ipc, unsigned long curr, unsigned long cmax)
503 "**************************************************";
504 char dots_printed[51];
509 scr_printf("\r%79s\r","");
511 /* a will be range 0-50 rather than 0-100 */
512 a=(curr * 50) / cmax;
513 sprintf(fmt, "[%%s%%%lds] %%3ld%%%% %%10ld/%%10ld\r", 50 - a);
514 strncpy(dots_printed, dots, a);
516 scr_printf(fmt, dots_printed, "",
517 curr * 100 / cmax, curr, cmax);
524 * NOT the same locate_host() in locate_host.c. This one just does a
525 * 'who am i' to try to discover where the user is...
527 void locate_host(CtdlIPC* ipc, char *hbuf)
529 FILE *who = (FILE *)popen("who am i","r");
531 strcpy(hbuf, ipc->ServInfo.fqdn);
534 fgets(hbuf, SIZ, who);
536 stripallbut(hbuf, '(' , ')' );
540 * miscellaneous server commands (testing, etc.)
542 void misc_server_cmd(CtdlIPC *ipc, char *cmd) {
545 CtdlIPC_chat_send(ipc, cmd);
546 CtdlIPC_chat_recv(ipc, buf);
547 scr_printf("%s\n",buf);
549 set_keepalives(KA_HALF);
550 while (CtdlIPC_chat_recv(ipc, buf), strcmp(buf,"000")) {
551 scr_printf("%s\n",buf);
553 set_keepalives(KA_YES);
558 newprompt("> ",buf,255);
559 CtdlIPC_chat_send(ipc, buf);
560 } while(strcmp(buf,"000"));
567 * compute the checksum of a file
569 int file_checksum(char *filename)
575 fp = fopen(filename,"r");
576 if (fp == NULL) return(0);
578 /* yes, this algorithm may allow cksum to overflow, but that's ok
579 * as long as it overflows consistently, which it will.
581 while (ch=getc(fp), ch>=0) {
582 cksum = (cksum + ch);
590 * nuke a directory and its contents
592 int nukedir(char *dirname)
598 dp = opendir(dirname);
603 while (d = readdir(dp), d != NULL) {
604 snprintf(filename, sizeof filename, "%s/%s",
610 return(rmdir(dirname));