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);
176 strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5);
177 /* No prompt because we don't implement this service yet, it's just a placeholder */
178 /* strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); */
181 /* This logic flips the question around, because it's one of those
182 * situations where 0=yes and 1=no
186 a = boolprompt("Correct forged From: lines during authenticated SMTP",
189 snprintf(sc[25], sizeof sc[25], "%d", a);
191 /* This logic flips the question around, because it's one of those
192 * situations where 0=yes and 1=no
196 a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a);
198 snprintf(sc[61], sizeof sc[61], "%d", a);
200 snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
201 "Allow unauthenticated SMTP clients to spoof my domains",
203 snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
204 "Perform RBL checks at greeting instead of after RCPT",
206 snprintf(sc[44], sizeof sc[44], "%d", (boolprompt(
207 "Instantly expunge deleted IMAP messages",
211 if (ipc->ServInfo.supports_ldap) {
212 a = strlen(&sc[32][0]);
213 a = (a ? 1 : 0); /* Set only to 1 or 0 */
214 a = boolprompt("Connect this Citadel to an external LDAP directory", a);
216 strprompt("Host name of LDAP server",
218 strprompt("Port number of LDAP service",
220 strprompt("Base DN", &sc[34][0], 255);
221 strprompt("Bind DN", &sc[35][0], 255);
222 strprompt("Password for bind DN", &sc[36][0], 255);
225 strcpy(&sc[32][0], "");
229 /* Expiry settings */
230 strprompt("Default user purge time (days)", &sc[16][0], 5);
231 strprompt("Default room purge time (days)", &sc[17][0], 5);
233 /* Angels and demons dancing in my head... */
235 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
236 strprompt("System default message expire policy (? for list)",
240 "1. Never automatically expire messages\n"
241 "2. Expire by message count\n"
242 "3. Expire by message age\n");
244 } while ((buf[0] < '1') || (buf[0] > '3'));
245 site_expirepolicy->expire_mode = buf[0] - '0';
247 /* ...lunatics and monsters underneath my bed */
248 if (site_expirepolicy->expire_mode == 2) {
249 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
250 strprompt("Keep how many messages online?", buf, 10);
251 site_expirepolicy->expire_value = atol(buf);
253 if (site_expirepolicy->expire_mode == 3) {
254 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
255 strprompt("Keep messages for how many days?", buf, 10);
256 site_expirepolicy->expire_value = atol(buf);
259 /* Media messiahs preying on my fears... */
261 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
262 strprompt("Mailbox default message expire policy (? for list)",
266 "0. Go with the system default\n"
267 "1. Never automatically expire messages\n"
268 "2. Expire by message count\n"
269 "3. Expire by message age\n");
271 } while ((buf[0] < '0') || (buf[0] > '3'));
272 mbx_expirepolicy->expire_mode = buf[0] - '0';
274 /* ...Pop culture prophets playing in my ears */
275 if (mbx_expirepolicy->expire_mode == 2) {
276 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
277 strprompt("Keep how many messages online?", buf, 10);
278 mbx_expirepolicy->expire_value = atol(buf);
280 if (mbx_expirepolicy->expire_mode == 3) {
281 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
282 strprompt("Keep messages for how many days?", buf, 10);
283 mbx_expirepolicy->expire_value = atol(buf);
286 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
287 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
288 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
289 "Enable full text search index (warning: resource intensive)",
292 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
293 "Perform journaling of email messages",
295 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
296 "Perform journaling of non-email messages",
298 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
299 strprompt("Email destination of journalized messages",
303 /* Funambol push stuff */
304 int yes_funambol = 0;
305 if (strlen(sc[53]) > 0) yes_funambol = 1;
306 yes_funambol = boolprompt("Connect to an external Funambol sync server", yes_funambol);
308 strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
309 strprompt("Funambol server port", &sc[54][0], 5);
310 strprompt("Funambol sync source", &sc[55][0], 63);
311 strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
320 /* External pager stuff */
322 if (strlen(sc[60]) > 0) yes_pager = 1;
323 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
325 strprompt("External pager tool", &sc[60][0], 255);
331 /* Master user account */
333 if (strlen(sc[58]) > 0) yes_muacct = 1;
334 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
336 strprompt("Master user name", &sc[58][0], 31);
337 strprompt("Master user password", &sc[59][0], -31);
340 strcpy(&sc[58][0], "");
341 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
345 scr_printf("Save this configuration? ");
348 for (a = 0; a < NUM_CONFIGS; a++)
349 r += 1 + strlen(sc[a]);
350 resp = (char *)calloc(1, r);
352 err_printf("Can't save config - out of memory!\n");
355 for (a = 0; a < NUM_CONFIGS; a++) {
359 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
361 err_printf("%s\n", buf);
365 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
367 err_printf("%s\n", buf);
370 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
372 err_printf("%s\n", buf);
376 if (site_expirepolicy) free(site_expirepolicy);
377 if (mbx_expirepolicy) free(mbx_expirepolicy);
382 * support function for do_internet_configuration()
384 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
387 keyopt(" <1> localhost (Alias for this computer)\n");
388 keyopt(" <2> gateway domain (Domain for all Citadel systems)\n");
389 keyopt(" <3> smart-host (Forward all outbound mail to this host)\n");
390 keyopt(" <4> directory (Consult the Global Address Book)\n");
391 keyopt(" <5> SpamAssassin (Address of SpamAssassin server)\n");
392 keyopt(" <6> RBL (domain suffix of spam hunting RBL)\n");
393 keyopt(" <7> masq domains (Domains as which users are allowed to masquerade)\n");
394 sel = intprompt("Which one", 1, 1, 6);
396 case 1: strcpy(buf, "localhost");
398 case 2: strcpy(buf, "gatewaydomain");
400 case 3: strcpy(buf, "smarthost");
402 case 4: strcpy(buf, "directory");
404 case 5: strcpy(buf, "spamassassin");
406 case 6: strcpy(buf, "rbl");
408 case 7: strcpy(buf, "masqdomain");
415 * Internet mail configuration
417 void do_internet_configuration(CtdlIPC *ipc)
430 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
432 while (!IsEmptyStr(resp)) {
433 extract_token(buf, resp, 0, '\n', sizeof buf);
434 remove_token(resp, 0, '\n');
436 if (num_recs == 1) recs = malloc(sizeof(char *));
437 else recs = realloc(recs, (sizeof(char *)) * num_recs);
438 recs[num_recs-1] = malloc(strlen(buf) + 1);
439 strcpy(recs[num_recs-1], buf);
442 if (resp) free(resp);
447 scr_printf("### Host or domain Record type \n");
449 scr_printf("--- -------------------------------------------------- --------------------\n");
450 for (i=0; i<num_recs; ++i) {
452 scr_printf("%3d ", i+1);
453 extract_token(buf, recs[i], 0, '|', sizeof buf);
455 scr_printf("%-50s ", buf);
456 extract_token(buf, recs[i], 1, '|', sizeof buf);
457 color(BRIGHT_MAGENTA);
458 scr_printf("%-20s\n", buf);
462 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
465 newprompt("Enter host name: ",
468 if (!IsEmptyStr(buf)) {
471 recs = malloc(sizeof(char *));
472 else recs = realloc(recs,
473 (sizeof(char *)) * num_recs);
475 get_inet_rec_type(ipc,
477 recs[num_recs-1] = strdup(buf);
482 i = intprompt("Delete which one",
486 for (j=i; j<num_recs; ++j)
492 for (i = 0; i < num_recs; i++)
493 r += 1 + strlen(recs[i]);
494 resp = (char *)calloc(1, r);
496 err_printf("Can't save config - out of memory!\n");
499 if (num_recs) for (i = 0; i < num_recs; i++) {
500 strcat(resp, recs[i]);
503 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
505 err_printf("%s\n", buf);
507 scr_printf("Wrote %d records.\n", num_recs);
513 quitting = !modified || boolprompt(
514 "Quit without saving", 0);
522 for (i=0; i<num_recs; ++i) free(recs[i]);
530 * Edit network configuration for room sharing, mailing lists, etc.
532 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
534 char filename[PATH_MAX];
535 char changefile[PATH_MAX];
545 char *listing = NULL;
548 if (IsEmptyStr(editor_paths[0])) {
549 scr_printf("You must have an external editor configured in"
550 " order to use this function.\n");
554 CtdlMakeTempFileName(filename, sizeof filename);
555 CtdlMakeTempFileName(changefile, sizeof changefile);
557 tempfp = fopen(filename, "w");
558 if (tempfp == NULL) {
559 err_printf("Cannot open %s: %s\n", filename, strerror(errno));
563 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
564 fprintf(tempfp, "# %s\n", comment);
565 fprintf(tempfp, "# Specify one per line.\n"
568 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
570 while(listing && !IsEmptyStr(listing)) {
571 extract_token(buf, listing, 0, '\n', sizeof buf);
572 remove_token(listing, 0, '\n');
573 extract_token(instr, buf, 0, '|', sizeof instr);
574 if (!strcasecmp(instr, entrytype)) {
575 tokens = num_tokens(buf, '|');
576 for (i=1; i<tokens; ++i) {
577 extract_token(addr, buf, i, '|', sizeof addr);
578 fprintf(tempfp, "%s", addr);
579 if (i < (tokens-1)) {
580 fprintf(tempfp, "|");
583 fprintf(tempfp, "\n");
593 e_ex_code = 1; /* start with a failed exit code */
595 stty_ctdl(SB_RESTORE);
597 cksum = file_checksum(filename);
598 if (editor_pid == 0) {
599 chmod(filename, 0600);
600 putenv("WINDOW_TITLE=Network configuration");
601 execlp(editor_paths[0], editor_paths[0], filename, NULL);
604 if (editor_pid > 0) {
607 b = ka_wait(&e_ex_code);
608 } while ((b != editor_pid) && (b >= 0));
614 if (file_checksum(filename) == cksum) {
615 err_printf("*** No changes to save.\n");
619 if (e_ex_code == 0) { /* Save changes */
620 changefp = fopen(changefile, "w");
622 /* Load all netconfig entries that are *not* of the type we are editing */
623 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
625 while(listing && !IsEmptyStr(listing)) {
626 extract_token(buf, listing, 0, '\n', sizeof buf);
627 remove_token(listing, 0, '\n');
628 extract_token(instr, buf, 0, '|', sizeof instr);
629 if (strcasecmp(instr, entrytype)) {
630 fprintf(changefp, "%s\n", buf);
639 /* ...and merge that with the data we just edited */
640 tempfp = fopen(filename, "r");
641 while (fgets(buf, sizeof buf, tempfp) != NULL) {
642 for (i=0; i<strlen(buf); ++i) {
643 if (buf[i] == '#') buf[i] = 0;
646 if (!IsEmptyStr(buf)) {
647 fprintf(changefp, "%s|%s\n", entrytype, buf);
653 /* now write it to the server... */
654 changefp = fopen(changefile, "r");
655 if (changefp != NULL) {
656 listing = load_message_from_file(changefp);
658 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
666 unlink(filename); /* Delete the temporary files */
672 * IGnet node configuration
674 void do_ignet_configuration(CtdlIPC *ipc) {
683 char *listing = NULL;
686 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
687 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
688 extract_token(buf, listing, 0, '\n', sizeof buf);
689 remove_token(listing, 0, '\n');
692 if (num_recs == 1) recs = malloc(sizeof(char *));
693 else recs = realloc(recs, (sizeof(char *)) * num_recs);
694 recs[num_recs-1] = malloc(SIZ);
695 strcpy(recs[num_recs-1], buf);
697 if (listing) free(listing);
710 "------------------ "
711 "-------------------------------- "
713 for (i=0; i<num_recs; ++i) {
715 scr_printf("%3d ", i+1);
716 extract_token(buf, recs[i], 0, '|', sizeof buf);
718 scr_printf("%-16s ", buf);
719 extract_token(buf, recs[i], 1, '|', sizeof buf);
720 color(BRIGHT_MAGENTA);
721 scr_printf("%-18s ", buf);
722 extract_token(buf, recs[i], 2, '|', sizeof buf);
724 scr_printf("%-32s ", buf);
725 extract_token(buf, recs[i], 3, '|', sizeof buf);
726 color(BRIGHT_MAGENTA);
727 scr_printf("%-3s\n", buf);
732 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
737 recs = malloc(sizeof(char *));
738 else recs = realloc(recs,
739 (sizeof(char *)) * num_recs);
740 newprompt("Enter node name : ", buf, 16);
742 newprompt("Enter shared secret: ",
743 &buf[strlen(buf)], 18);
745 newprompt("Enter host or IP : ",
746 &buf[strlen(buf)], 32);
748 strprompt("Enter port number : ",
749 &buf[strlen(buf)-3], 5);
750 recs[num_recs-1] = strdup(buf);
754 i = intprompt("Delete which one",
758 for (j=i; j<num_recs; ++j)
764 for (i = 0; i < num_recs; ++i)
765 r += 1 + strlen(recs[i]);
766 listing = (char*) calloc(1, r);
768 err_printf("Can't save config - out of memory!\n");
771 if (num_recs) for (i = 0; i < num_recs; ++i) {
772 strcat(listing, recs[i]);
773 strcat(listing, "\n");
775 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
777 scr_printf("%s\n", buf);
779 scr_printf("Wrote %d records.\n", num_recs);
785 quitting = !modified || boolprompt(
786 "Quit without saving", 0);
794 for (i=0; i<num_recs; ++i) free(recs[i]);
801 * Filter list configuration
803 void do_filterlist_configuration(CtdlIPC *ipc)
813 char *listing = NULL;
816 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
817 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
818 extract_token(buf, listing, 0, '\n', sizeof buf);
819 remove_token(listing, 0, '\n');
822 if (num_recs == 1) recs = malloc(sizeof(char *));
823 else recs = realloc(recs, (sizeof(char *)) * num_recs);
824 recs[num_recs-1] = malloc(SIZ);
825 strcpy(recs[num_recs-1], buf);
827 if (listing) free(listing);
839 "---------------------------- "
840 "---------------------------- "
843 for (i=0; i<num_recs; ++i) {
845 scr_printf("%3d ", i+1);
846 extract_token(buf, recs[i], 0, '|', sizeof buf);
848 scr_printf("%-28s ", buf);
849 extract_token(buf, recs[i], 1, '|', sizeof buf);
850 color(BRIGHT_MAGENTA);
851 scr_printf("%-28s ", buf);
852 extract_token(buf, recs[i], 2, '|', sizeof buf);
854 scr_printf("%-16s\n", buf);
855 extract_token(buf, recs[i], 3, '|', sizeof buf);
859 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
864 recs = malloc(sizeof(char *));
865 else recs = realloc(recs,
866 (sizeof(char *)) * num_recs);
867 newprompt("Enter user name: ", buf, 28);
869 newprompt("Enter room name: ",
870 &buf[strlen(buf)], 28);
872 newprompt("Enter node name: ",
873 &buf[strlen(buf)], 16);
875 recs[num_recs-1] = strdup(buf);
879 i = intprompt("Delete which one",
883 for (j=i; j<num_recs; ++j)
889 for (i = 0; i < num_recs; ++i)
890 r += 1 + strlen(recs[i]);
891 listing = (char*) calloc(1, r);
893 err_printf("Can't save config - out of memory!\n");
896 if (num_recs) for (i = 0; i < num_recs; ++i) {
897 strcat(listing, recs[i]);
898 strcat(listing, "\n");
900 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
902 scr_printf("%s\n", buf);
904 scr_printf("Wrote %d records.\n", num_recs);
910 quitting = !modified || boolprompt(
911 "Quit without saving", 0);
919 for (i=0; i<num_recs; ++i) free(recs[i]);
928 * POP3 aggregation client configuration
930 void do_pop3client_configuration(CtdlIPC *ipc)
940 char *listing = NULL;
941 char *other_listing = NULL;
945 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
947 while(listing && !IsEmptyStr(listing)) {
948 extract_token(buf, listing, 0, '\n', sizeof buf);
949 remove_token(listing, 0, '\n');
950 extract_token(instr, buf, 0, '|', sizeof instr);
951 if (!strcasecmp(instr, "pop3client")) {
954 if (num_recs == 1) recs = malloc(sizeof(char *));
955 else recs = realloc(recs, (sizeof(char *)) * num_recs);
956 recs[num_recs-1] = malloc(SIZ);
957 strcpy(recs[num_recs-1], buf);
977 "---------------------------- "
978 "---------------------------- "
981 for (i=0; i<num_recs; ++i) {
983 scr_printf("%3d ", i+1);
985 extract_token(buf, recs[i], 1, '|', sizeof buf);
987 scr_printf("%-28s ", buf);
989 extract_token(buf, recs[i], 2, '|', sizeof buf);
990 color(BRIGHT_MAGENTA);
991 scr_printf("%-28s ", buf);
994 scr_printf("%-15s\n", (extract_int(recs[i], 4) ? "Yes" : "No") );
998 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1002 if (num_recs == 1) {
1003 recs = malloc(sizeof(char *));
1006 recs = realloc(recs, (sizeof(char *)) * num_recs);
1008 strcpy(buf, "pop3client|");
1009 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1011 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1013 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1015 scr_printf("Keep messages on server instead of deleting them? ");
1016 sprintf(&buf[strlen(buf)], "%d", yesno());
1018 recs[num_recs-1] = strdup(buf);
1022 i = intprompt("Delete which one",
1023 1, 1, num_recs) - 1;
1026 for (j=i; j<num_recs; ++j)
1027 recs[j] = recs[j+1];
1032 for (i = 0; i < num_recs; ++i) {
1033 r += 1 + strlen(recs[i]);
1035 listing = (char*) calloc(1, r);
1037 err_printf("Can't save config - out of memory!\n");
1040 if (num_recs) for (i = 0; i < num_recs; ++i) {
1041 strcat(listing, recs[i]);
1042 strcat(listing, "\n");
1045 /* Retrieve all the *other* records for merging */
1046 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1048 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1049 extract_token(buf, other_listing, i, '\n', sizeof buf);
1050 if (strncasecmp(buf, "pop3client|", 11)) {
1051 listing = realloc(listing, strlen(listing) +
1053 strcat(listing, buf);
1054 strcat(listing, "\n");
1058 free(other_listing);
1059 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1064 scr_printf("%s\n", buf);
1066 scr_printf("Wrote %d records.\n", num_recs);
1072 quitting = !modified || boolprompt(
1073 "Quit without saving", 0);
1078 } while (!quitting);
1081 for (i=0; i<num_recs; ++i) free(recs[i]);
1092 * RSS feed retrieval client configuration
1094 void do_rssclient_configuration(CtdlIPC *ipc)
1104 char *listing = NULL;
1105 char *other_listing = NULL;
1109 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1111 while(listing && !IsEmptyStr(listing)) {
1112 extract_token(buf, listing, 0, '\n', sizeof buf);
1113 remove_token(listing, 0, '\n');
1114 extract_token(instr, buf, 0, '|', sizeof instr);
1115 if (!strcasecmp(instr, "rssclient")) {
1118 if (num_recs == 1) recs = malloc(sizeof(char *));
1119 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1120 recs[num_recs-1] = malloc(SIZ);
1121 strcpy(recs[num_recs-1], buf);
1133 color(BRIGHT_WHITE);
1134 scr_printf("### Feed URL\n");
1137 "---------------------------------------------------------------------------"
1140 for (i=0; i<num_recs; ++i) {
1142 scr_printf("%3d ", i+1);
1144 extract_token(buf, recs[i], 1, '|', sizeof buf);
1146 scr_printf("%-75s\n", buf);
1151 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1155 if (num_recs == 1) {
1156 recs = malloc(sizeof(char *));
1159 recs = realloc(recs, (sizeof(char *)) * num_recs);
1161 strcpy(buf, "rssclient|");
1162 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1164 recs[num_recs-1] = strdup(buf);
1168 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1171 for (j=i; j<num_recs; ++j)
1172 recs[j] = recs[j+1];
1177 for (i = 0; i < num_recs; ++i) {
1178 r += 1 + strlen(recs[i]);
1180 listing = (char*) calloc(1, r);
1182 err_printf("Can't save config - out of memory!\n");
1185 if (num_recs) for (i = 0; i < num_recs; ++i) {
1186 strcat(listing, recs[i]);
1187 strcat(listing, "\n");
1190 /* Retrieve all the *other* records for merging */
1191 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1193 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1194 extract_token(buf, other_listing, i, '\n', sizeof buf);
1195 if (strncasecmp(buf, "rssclient|", 10)) {
1196 listing = realloc(listing, strlen(listing) +
1198 strcat(listing, buf);
1199 strcat(listing, "\n");
1203 free(other_listing);
1204 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1209 scr_printf("%s\n", buf);
1211 scr_printf("Wrote %d records.\n", num_recs);
1217 quitting = !modified || boolprompt(
1218 "Quit without saving", 0);
1223 } while (!quitting);
1226 for (i=0; i<num_recs; ++i) free(recs[i]);