3 * Configuration screens that are part of the text mode client.
17 #if TIME_WITH_SYS_TIME
18 # include <sys/time.h>
22 # include <sys/time.h>
32 #include <libcitadel.h>
35 #include "citadel_ipc.h"
36 #include "citadel_decls.h"
37 #include "tuiconfig.h"
46 /* work around solaris include files */
52 extern char tempdir[];
53 extern char *axdefs[8];
54 extern long highest_msg_read;
55 extern long maxmsgnum;
56 extern unsigned room_flags;
57 extern int screenwidth;
61 * General system configuration command
63 void do_system_configuration(CtdlIPC *ipc)
66 #define NUM_CONFIGS 63
69 char sc[NUM_CONFIGS][256];
71 struct ExpirePolicy *site_expirepolicy = NULL;
72 struct ExpirePolicy *mbx_expirepolicy = NULL;
75 int r; /* IPC response code */
76 int server_configs = 0;
78 /* Clear out the config buffers */
79 memset(&sc[0][0], 0, sizeof(sc));
81 /* Fetch the current config */
82 r = CtdlIPCGetSystemConfig(ipc, &resp, buf);
84 server_configs = num_tokens(resp, '\n');
85 for (a=0; a<server_configs; ++a) {
86 if (a < NUM_CONFIGS) {
87 extract_token(&sc[a][0], resp, a, '\n', sizeof sc[a]);
93 /* Fetch the expire policy (this will silently fail on old servers,
94 * resulting in "default" policy)
96 r = CtdlIPCGetMessageExpirationPolicy(ipc, 2, &site_expirepolicy, buf);
97 r = CtdlIPCGetMessageExpirationPolicy(ipc, 3, &mbx_expirepolicy, buf);
99 /* Identification parameters */
101 strprompt("Node name", &sc[0][0], 15);
102 strprompt("Fully qualified domain name", &sc[1][0], 63);
103 strprompt("Human readable node name", &sc[2][0], 20);
104 strprompt("Telephone number", &sc[3][0], 15);
105 strprompt("Geographic location of this system", &sc[12][0], 31);
106 strprompt("Name of system administrator", &sc[13][0], 25);
107 strprompt("Paginator prompt", &sc[10][0], 79);
109 /* Security parameters */
111 snprintf(sc[7], sizeof sc[7], "%d", (boolprompt(
112 "Require registration for new users",
114 snprintf(sc[29], sizeof sc[29], "%d", (boolprompt(
115 "Disable self-service user account creation",
117 strprompt("Initial access level for new users", &sc[6][0], 1);
118 strprompt("Access level required to create rooms", &sc[19][0], 1);
119 snprintf(sc[4], sizeof sc[4], "%d", (boolprompt(
120 "Automatically give room aide privs to a user who creates a private room",
123 snprintf(sc[8], sizeof sc[8], "%d", (boolprompt(
124 "Automatically move problem user messages to twit room",
127 strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
128 snprintf(sc[11], sizeof sc[11], "%d", (boolprompt(
129 "Restrict Internet mail to only those with that privilege",
131 snprintf(sc[26], sizeof sc[26], "%d", (boolprompt(
132 "Allow Aides to Zap (forget) rooms",
135 if (!IsEmptyStr(&sc[18][0])) logpages = 1;
137 logpages = boolprompt("Log all pages", logpages);
139 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
145 /* Commented out because this setting isn't really appropriate to
146 * change while the server is running.
148 * snprintf(sc[52], sizeof sc[52], "%d", (boolprompt(
149 * "Use system authentication",
150 * atoi(&sc[52][0]))));
155 strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
156 strprompt("Maximum concurrent sessions", &sc[14][0], 4);
157 strprompt("Maximum message length", &sc[20][0], 20);
158 strprompt("Minimum number of worker threads", &sc[21][0], 3);
159 strprompt("Maximum number of worker threads", &sc[22][0], 3);
160 snprintf(sc[43], sizeof sc[43], "%d", (boolprompt(
161 "Automatically delete committed database logs",
164 strprompt("Server IP address (0.0.0.0 for 'any')", &sc[37][0], 15);
165 strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
166 strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5);
167 strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
168 strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5);
169 strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5);
170 strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5);
171 strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5);
172 strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5);
173 strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5);
175 strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5);
176 /* No prompt because we don't implement this service yet, it's just a placeholder */
177 /* strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); */
179 /* This logic flips the question around, because it's one of those
180 * situations where 0=yes and 1=no
184 a = boolprompt("Correct forged From: lines during authenticated SMTP",
187 snprintf(sc[25], sizeof sc[25], "%d", a);
189 /* This logic flips the question around, because it's one of those
190 * situations where 0=yes and 1=no
194 a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a);
196 snprintf(sc[61], sizeof sc[61], "%d", a);
198 snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
199 "Allow unauthenticated SMTP clients to spoof my domains",
201 snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
202 "Perform RBL checks at greeting instead of after RCPT",
204 snprintf(sc[44], sizeof sc[44], "%d", (boolprompt(
205 "Instantly expunge deleted IMAP messages",
209 if (ipc->ServInfo.supports_ldap) {
210 a = strlen(&sc[32][0]);
211 a = (a ? 1 : 0); /* Set only to 1 or 0 */
212 a = boolprompt("Connect this Citadel to an external LDAP directory", a);
214 strprompt("Host name of LDAP server",
216 strprompt("Port number of LDAP service",
218 strprompt("Base DN", &sc[34][0], 255);
219 strprompt("Bind DN", &sc[35][0], 255);
220 strprompt("Password for bind DN", &sc[36][0], 255);
223 strcpy(&sc[32][0], "");
227 /* Expiry settings */
228 strprompt("Default user purge time (days)", &sc[16][0], 5);
229 strprompt("Default room purge time (days)", &sc[17][0], 5);
231 /* Angels and demons dancing in my head... */
233 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
234 strprompt("System default message expire policy (? for list)",
238 "1. Never automatically expire messages\n"
239 "2. Expire by message count\n"
240 "3. Expire by message age\n");
242 } while ((buf[0] < '1') || (buf[0] > '3'));
243 site_expirepolicy->expire_mode = buf[0] - '0';
245 /* ...lunatics and monsters underneath my bed */
246 if (site_expirepolicy->expire_mode == 2) {
247 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
248 strprompt("Keep how many messages online?", buf, 10);
249 site_expirepolicy->expire_value = atol(buf);
251 if (site_expirepolicy->expire_mode == 3) {
252 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
253 strprompt("Keep messages for how many days?", buf, 10);
254 site_expirepolicy->expire_value = atol(buf);
257 /* Media messiahs preying on my fears... */
259 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
260 strprompt("Mailbox default message expire policy (? for list)",
264 "0. Go with the system default\n"
265 "1. Never automatically expire messages\n"
266 "2. Expire by message count\n"
267 "3. Expire by message age\n");
269 } while ((buf[0] < '0') || (buf[0] > '3'));
270 mbx_expirepolicy->expire_mode = buf[0] - '0';
272 /* ...Pop culture prophets playing in my ears */
273 if (mbx_expirepolicy->expire_mode == 2) {
274 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
275 strprompt("Keep how many messages online?", buf, 10);
276 mbx_expirepolicy->expire_value = atol(buf);
278 if (mbx_expirepolicy->expire_mode == 3) {
279 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
280 strprompt("Keep messages for how many days?", buf, 10);
281 mbx_expirepolicy->expire_value = atol(buf);
284 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
285 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
286 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
287 "Enable full text search index (warning: resource intensive)",
290 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
291 "Perform journaling of email messages",
293 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
294 "Perform journaling of non-email messages",
296 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
297 strprompt("Email destination of journalized messages",
301 /* Funambol push stuff */
302 int yes_funambol = 0;
303 if (strlen(sc[53]) > 0) yes_funambol = 1;
304 yes_funambol = boolprompt("Connect to an external Funambol sync server", yes_funambol);
306 strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
307 strprompt("Funambol server port", &sc[54][0], 5);
308 strprompt("Funambol sync source", &sc[55][0], 63);
309 strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
318 /* External pager stuff */
320 if (strlen(sc[60]) > 0) yes_pager = 1;
321 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
323 strprompt("External pager tool", &sc[60][0], 255);
329 /* Master user account */
331 if (strlen(sc[58]) > 0) yes_muacct = 1;
332 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
334 strprompt("Master user name", &sc[58][0], 31);
335 strprompt("Master user password", &sc[59][0], -31);
338 strcpy(&sc[58][0], "");
339 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
343 scr_printf("Save this configuration? ");
346 for (a = 0; a < NUM_CONFIGS; a++)
347 r += 1 + strlen(sc[a]);
348 resp = (char *)calloc(1, r);
350 err_printf("Can't save config - out of memory!\n");
353 for (a = 0; a < NUM_CONFIGS; a++) {
357 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
359 err_printf("%s\n", buf);
363 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
365 err_printf("%s\n", buf);
368 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
370 err_printf("%s\n", buf);
374 if (site_expirepolicy) free(site_expirepolicy);
375 if (mbx_expirepolicy) free(mbx_expirepolicy);
380 * support function for do_internet_configuration()
382 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
385 keyopt(" <1> localhost (Alias for this computer)\n");
386 keyopt(" <2> gateway domain (Domain for all Citadel systems)\n");
387 keyopt(" <3> smart-host (Forward all outbound mail to this host)\n");
388 keyopt(" <4> directory (Consult the Global Address Book)\n");
389 keyopt(" <5> SpamAssassin (Address of SpamAssassin server)\n");
390 keyopt(" <6> RBL (domain suffix of spam hunting RBL)\n");
391 keyopt(" <7> masq domains (Domains as which users are allowed to masquerade)\n");
392 sel = intprompt("Which one", 1, 1, 6);
394 case 1: strcpy(buf, "localhost");
396 case 2: strcpy(buf, "gatewaydomain");
398 case 3: strcpy(buf, "smarthost");
400 case 4: strcpy(buf, "directory");
402 case 5: strcpy(buf, "spamassassin");
404 case 6: strcpy(buf, "rbl");
406 case 7: strcpy(buf, "masqdomain");
413 * Internet mail configuration
415 void do_internet_configuration(CtdlIPC *ipc)
428 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
430 while (!IsEmptyStr(resp)) {
431 extract_token(buf, resp, 0, '\n', sizeof buf);
432 remove_token(resp, 0, '\n');
434 if (num_recs == 1) recs = malloc(sizeof(char *));
435 else recs = realloc(recs, (sizeof(char *)) * num_recs);
436 recs[num_recs-1] = malloc(strlen(buf) + 1);
437 strcpy(recs[num_recs-1], buf);
440 if (resp) free(resp);
445 scr_printf("### Host or domain Record type \n");
447 scr_printf("--- -------------------------------------------------- --------------------\n");
448 for (i=0; i<num_recs; ++i) {
450 scr_printf("%3d ", i+1);
451 extract_token(buf, recs[i], 0, '|', sizeof buf);
453 scr_printf("%-50s ", buf);
454 extract_token(buf, recs[i], 1, '|', sizeof buf);
455 color(BRIGHT_MAGENTA);
456 scr_printf("%-20s\n", buf);
460 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
463 newprompt("Enter host name: ",
466 if (!IsEmptyStr(buf)) {
469 recs = malloc(sizeof(char *));
470 else recs = realloc(recs,
471 (sizeof(char *)) * num_recs);
473 get_inet_rec_type(ipc,
475 recs[num_recs-1] = strdup(buf);
480 i = intprompt("Delete which one",
484 for (j=i; j<num_recs; ++j)
490 for (i = 0; i < num_recs; i++)
491 r += 1 + strlen(recs[i]);
492 resp = (char *)calloc(1, r);
494 err_printf("Can't save config - out of memory!\n");
497 if (num_recs) for (i = 0; i < num_recs; i++) {
498 strcat(resp, recs[i]);
501 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
503 err_printf("%s\n", buf);
505 scr_printf("Wrote %d records.\n", num_recs);
511 quitting = !modified || boolprompt(
512 "Quit without saving", 0);
520 for (i=0; i<num_recs; ++i) free(recs[i]);
528 * Edit network configuration for room sharing, mailing lists, etc.
530 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
532 char filename[PATH_MAX];
533 char changefile[PATH_MAX];
543 char *listing = NULL;
546 if (IsEmptyStr(editor_paths[0])) {
547 scr_printf("You must have an external editor configured in"
548 " order to use this function.\n");
552 CtdlMakeTempFileName(filename, sizeof filename);
553 CtdlMakeTempFileName(changefile, sizeof changefile);
555 tempfp = fopen(filename, "w");
556 if (tempfp == NULL) {
557 err_printf("Cannot open %s: %s\n", filename, strerror(errno));
561 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
562 fprintf(tempfp, "# %s\n", comment);
563 fprintf(tempfp, "# Specify one per line.\n"
566 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
568 while(listing && !IsEmptyStr(listing)) {
569 extract_token(buf, listing, 0, '\n', sizeof buf);
570 remove_token(listing, 0, '\n');
571 extract_token(instr, buf, 0, '|', sizeof instr);
572 if (!strcasecmp(instr, entrytype)) {
573 tokens = num_tokens(buf, '|');
574 for (i=1; i<tokens; ++i) {
575 extract_token(addr, buf, i, '|', sizeof addr);
576 fprintf(tempfp, "%s", addr);
577 if (i < (tokens-1)) {
578 fprintf(tempfp, "|");
581 fprintf(tempfp, "\n");
591 e_ex_code = 1; /* start with a failed exit code */
593 stty_ctdl(SB_RESTORE);
595 cksum = file_checksum(filename);
596 if (editor_pid == 0) {
597 chmod(filename, 0600);
598 putenv("WINDOW_TITLE=Network configuration");
599 execlp(editor_paths[0], editor_paths[0], filename, NULL);
602 if (editor_pid > 0) {
605 b = ka_wait(&e_ex_code);
606 } while ((b != editor_pid) && (b >= 0));
612 if (file_checksum(filename) == cksum) {
613 err_printf("*** No changes to save.\n");
617 if (e_ex_code == 0) { /* Save changes */
618 changefp = fopen(changefile, "w");
620 /* Load all netconfig entries that are *not* of the type we are editing */
621 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
623 while(listing && !IsEmptyStr(listing)) {
624 extract_token(buf, listing, 0, '\n', sizeof buf);
625 remove_token(listing, 0, '\n');
626 extract_token(instr, buf, 0, '|', sizeof instr);
627 if (strcasecmp(instr, entrytype)) {
628 fprintf(changefp, "%s\n", buf);
637 /* ...and merge that with the data we just edited */
638 tempfp = fopen(filename, "r");
639 while (fgets(buf, sizeof buf, tempfp) != NULL) {
640 for (i=0; i<strlen(buf); ++i) {
641 if (buf[i] == '#') buf[i] = 0;
644 if (!IsEmptyStr(buf)) {
645 fprintf(changefp, "%s|%s\n", entrytype, buf);
651 /* now write it to the server... */
652 changefp = fopen(changefile, "r");
653 if (changefp != NULL) {
654 listing = load_message_from_file(changefp);
656 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
664 unlink(filename); /* Delete the temporary files */
670 * IGnet node configuration
672 void do_ignet_configuration(CtdlIPC *ipc) {
681 char *listing = NULL;
684 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
685 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
686 extract_token(buf, listing, 0, '\n', sizeof buf);
687 remove_token(listing, 0, '\n');
690 if (num_recs == 1) recs = malloc(sizeof(char *));
691 else recs = realloc(recs, (sizeof(char *)) * num_recs);
692 recs[num_recs-1] = malloc(SIZ);
693 strcpy(recs[num_recs-1], buf);
695 if (listing) free(listing);
708 "------------------ "
709 "-------------------------------- "
711 for (i=0; i<num_recs; ++i) {
713 scr_printf("%3d ", i+1);
714 extract_token(buf, recs[i], 0, '|', sizeof buf);
716 scr_printf("%-16s ", buf);
717 extract_token(buf, recs[i], 1, '|', sizeof buf);
718 color(BRIGHT_MAGENTA);
719 scr_printf("%-18s ", buf);
720 extract_token(buf, recs[i], 2, '|', sizeof buf);
722 scr_printf("%-32s ", buf);
723 extract_token(buf, recs[i], 3, '|', sizeof buf);
724 color(BRIGHT_MAGENTA);
725 scr_printf("%-3s\n", buf);
730 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
735 recs = malloc(sizeof(char *));
736 else recs = realloc(recs,
737 (sizeof(char *)) * num_recs);
738 newprompt("Enter node name : ", buf, 16);
740 newprompt("Enter shared secret: ",
741 &buf[strlen(buf)], 18);
743 newprompt("Enter host or IP : ",
744 &buf[strlen(buf)], 32);
746 strprompt("Enter port number : ",
747 &buf[strlen(buf)-3], 5);
748 recs[num_recs-1] = strdup(buf);
752 i = intprompt("Delete which one",
756 for (j=i; j<num_recs; ++j)
762 for (i = 0; i < num_recs; ++i)
763 r += 1 + strlen(recs[i]);
764 listing = (char*) calloc(1, r);
766 err_printf("Can't save config - out of memory!\n");
769 if (num_recs) for (i = 0; i < num_recs; ++i) {
770 strcat(listing, recs[i]);
771 strcat(listing, "\n");
773 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
775 scr_printf("%s\n", buf);
777 scr_printf("Wrote %d records.\n", num_recs);
783 quitting = !modified || boolprompt(
784 "Quit without saving", 0);
792 for (i=0; i<num_recs; ++i) free(recs[i]);
799 * Filter list configuration
801 void do_filterlist_configuration(CtdlIPC *ipc)
811 char *listing = NULL;
814 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
815 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
816 extract_token(buf, listing, 0, '\n', sizeof buf);
817 remove_token(listing, 0, '\n');
820 if (num_recs == 1) recs = malloc(sizeof(char *));
821 else recs = realloc(recs, (sizeof(char *)) * num_recs);
822 recs[num_recs-1] = malloc(SIZ);
823 strcpy(recs[num_recs-1], buf);
825 if (listing) free(listing);
837 "---------------------------- "
838 "---------------------------- "
841 for (i=0; i<num_recs; ++i) {
843 scr_printf("%3d ", i+1);
844 extract_token(buf, recs[i], 0, '|', sizeof buf);
846 scr_printf("%-28s ", buf);
847 extract_token(buf, recs[i], 1, '|', sizeof buf);
848 color(BRIGHT_MAGENTA);
849 scr_printf("%-28s ", buf);
850 extract_token(buf, recs[i], 2, '|', sizeof buf);
852 scr_printf("%-16s\n", buf);
853 extract_token(buf, recs[i], 3, '|', sizeof buf);
857 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
862 recs = malloc(sizeof(char *));
863 else recs = realloc(recs,
864 (sizeof(char *)) * num_recs);
865 newprompt("Enter user name: ", buf, 28);
867 newprompt("Enter room name: ",
868 &buf[strlen(buf)], 28);
870 newprompt("Enter node name: ",
871 &buf[strlen(buf)], 16);
873 recs[num_recs-1] = strdup(buf);
877 i = intprompt("Delete which one",
881 for (j=i; j<num_recs; ++j)
887 for (i = 0; i < num_recs; ++i)
888 r += 1 + strlen(recs[i]);
889 listing = (char*) calloc(1, r);
891 err_printf("Can't save config - out of memory!\n");
894 if (num_recs) for (i = 0; i < num_recs; ++i) {
895 strcat(listing, recs[i]);
896 strcat(listing, "\n");
898 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
900 scr_printf("%s\n", buf);
902 scr_printf("Wrote %d records.\n", num_recs);
908 quitting = !modified || boolprompt(
909 "Quit without saving", 0);
917 for (i=0; i<num_recs; ++i) free(recs[i]);
926 * POP3 aggregation client configuration
928 void do_pop3client_configuration(CtdlIPC *ipc)
938 char *listing = NULL;
939 char *other_listing = NULL;
943 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
945 while(listing && !IsEmptyStr(listing)) {
946 extract_token(buf, listing, 0, '\n', sizeof buf);
947 remove_token(listing, 0, '\n');
948 extract_token(instr, buf, 0, '|', sizeof instr);
949 if (!strcasecmp(instr, "pop3client")) {
952 if (num_recs == 1) recs = malloc(sizeof(char *));
953 else recs = realloc(recs, (sizeof(char *)) * num_recs);
954 recs[num_recs-1] = malloc(SIZ);
955 strcpy(recs[num_recs-1], buf);
975 "---------------------------- "
976 "---------------------------- "
979 for (i=0; i<num_recs; ++i) {
981 scr_printf("%3d ", i+1);
983 extract_token(buf, recs[i], 1, '|', sizeof buf);
985 scr_printf("%-28s ", buf);
987 extract_token(buf, recs[i], 2, '|', sizeof buf);
988 color(BRIGHT_MAGENTA);
989 scr_printf("%-28s ", buf);
992 scr_printf("%-15s\n", (extract_int(recs[i], 4) ? "Yes" : "No") );
996 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1000 if (num_recs == 1) {
1001 recs = malloc(sizeof(char *));
1004 recs = realloc(recs, (sizeof(char *)) * num_recs);
1006 strcpy(buf, "pop3client|");
1007 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1009 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1011 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1013 scr_printf("Keep messages on server instead of deleting them? ");
1014 sprintf(&buf[strlen(buf)], "%d", yesno());
1016 recs[num_recs-1] = strdup(buf);
1020 i = intprompt("Delete which one",
1021 1, 1, num_recs) - 1;
1024 for (j=i; j<num_recs; ++j)
1025 recs[j] = recs[j+1];
1030 for (i = 0; i < num_recs; ++i) {
1031 r += 1 + strlen(recs[i]);
1033 listing = (char*) calloc(1, r);
1035 err_printf("Can't save config - out of memory!\n");
1038 if (num_recs) for (i = 0; i < num_recs; ++i) {
1039 strcat(listing, recs[i]);
1040 strcat(listing, "\n");
1043 /* Retrieve all the *other* records for merging */
1044 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1046 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1047 extract_token(buf, other_listing, i, '\n', sizeof buf);
1048 if (strncasecmp(buf, "pop3client|", 11)) {
1049 listing = realloc(listing, strlen(listing) +
1051 strcat(listing, buf);
1052 strcat(listing, "\n");
1056 free(other_listing);
1057 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1062 scr_printf("%s\n", buf);
1064 scr_printf("Wrote %d records.\n", num_recs);
1070 quitting = !modified || boolprompt(
1071 "Quit without saving", 0);
1076 } while (!quitting);
1079 for (i=0; i<num_recs; ++i) free(recs[i]);
1090 * RSS feed retrieval client configuration
1092 void do_rssclient_configuration(CtdlIPC *ipc)
1102 char *listing = NULL;
1103 char *other_listing = NULL;
1107 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1109 while(listing && !IsEmptyStr(listing)) {
1110 extract_token(buf, listing, 0, '\n', sizeof buf);
1111 remove_token(listing, 0, '\n');
1112 extract_token(instr, buf, 0, '|', sizeof instr);
1113 if (!strcasecmp(instr, "rssclient")) {
1116 if (num_recs == 1) recs = malloc(sizeof(char *));
1117 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1118 recs[num_recs-1] = malloc(SIZ);
1119 strcpy(recs[num_recs-1], buf);
1131 color(BRIGHT_WHITE);
1132 scr_printf("### Feed URL\n");
1135 "---------------------------------------------------------------------------"
1138 for (i=0; i<num_recs; ++i) {
1140 scr_printf("%3d ", i+1);
1142 extract_token(buf, recs[i], 1, '|', sizeof buf);
1144 scr_printf("%-75s\n", buf);
1149 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1153 if (num_recs == 1) {
1154 recs = malloc(sizeof(char *));
1157 recs = realloc(recs, (sizeof(char *)) * num_recs);
1159 strcpy(buf, "rssclient|");
1160 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1162 recs[num_recs-1] = strdup(buf);
1166 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1169 for (j=i; j<num_recs; ++j)
1170 recs[j] = recs[j+1];
1175 for (i = 0; i < num_recs; ++i) {
1176 r += 1 + strlen(recs[i]);
1178 listing = (char*) calloc(1, r);
1180 err_printf("Can't save config - out of memory!\n");
1183 if (num_recs) for (i = 0; i < num_recs; ++i) {
1184 strcat(listing, recs[i]);
1185 strcat(listing, "\n");
1188 /* Retrieve all the *other* records for merging */
1189 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1191 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1192 extract_token(buf, other_listing, i, '\n', sizeof buf);
1193 if (strncasecmp(buf, "rssclient|", 10)) {
1194 listing = realloc(listing, strlen(listing) +
1196 strcat(listing, buf);
1197 strcat(listing, "\n");
1201 free(other_listing);
1202 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1207 scr_printf("%s\n", buf);
1209 scr_printf("Wrote %d records.\n", num_recs);
1215 quitting = !modified || boolprompt(
1216 "Quit without saving", 0);
1221 } while (!quitting);
1224 for (i=0; i<num_recs; ++i) free(recs[i]);