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 67
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])) {
141 logpages = boolprompt("Log all instant messages", logpages);
143 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
149 /* Commented out because this setting isn't really appropriate to
150 * change while the server is running.
152 * snprintf(sc[52], sizeof sc[52], "%d", (boolprompt(
153 * "Use system authentication",
154 * atoi(&sc[52][0]))));
159 strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
160 strprompt("Maximum concurrent sessions", &sc[14][0], 4);
161 strprompt("Maximum message length", &sc[20][0], 20);
162 strprompt("Minimum number of worker threads", &sc[21][0], 3);
163 strprompt("Maximum number of worker threads", &sc[22][0], 3);
164 snprintf(sc[43], sizeof sc[43], "%d", (boolprompt(
165 "Automatically delete committed database logs",
168 strprompt("Server IP address (0.0.0.0 for 'any')", &sc[37][0], 15);
169 strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
170 strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5);
171 strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
172 strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5);
173 strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5);
174 strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5);
175 strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5);
176 strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5);
177 strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5);
179 strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5);
180 /* No prompt because we don't implement this service yet, it's just a placeholder */
181 /* strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); */
183 /* This logic flips the question around, because it's one of those
184 * situations where 0=yes and 1=no
188 a = boolprompt("Correct forged From: lines during authenticated SMTP",
191 snprintf(sc[25], sizeof sc[25], "%d", a);
193 snprintf(sc[66], sizeof sc[66], "%d", (boolprompt(
194 "Flag messages as spam instead of rejecting",
197 /* This logic flips the question around, because it's one of those
198 * situations where 0=yes and 1=no
202 a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a);
204 snprintf(sc[61], sizeof sc[61], "%d", a);
206 snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
207 "Allow unauthenticated SMTP clients to spoof my domains",
209 snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
210 "Perform RBL checks at greeting instead of after RCPT",
212 snprintf(sc[44], sizeof sc[44], "%d", (boolprompt(
213 "Instantly expunge deleted IMAP messages",
217 if (ipc->ServInfo.supports_ldap) {
218 a = strlen(&sc[32][0]);
219 a = (a ? 1 : 0); /* Set only to 1 or 0 */
220 a = boolprompt("Do you want to configure LDAP authentication?", a);
222 strprompt("Host name of LDAP server",
224 strprompt("Port number of LDAP service",
226 strprompt("Base DN", &sc[34][0], 255);
227 strprompt("Bind DN (or blank for anonymous bind)", &sc[35][0], 255);
228 strprompt("Password for bind DN (or blank for anonymous bind)", &sc[36][0], 255);
231 strcpy(&sc[32][0], "");
235 /* Expiry settings */
236 strprompt("Default user purge time (days)", &sc[16][0], 5);
237 strprompt("Default room purge time (days)", &sc[17][0], 5);
239 /* Angels and demons dancing in my head... */
241 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
242 strprompt("System default message expire policy (? for list)",
246 "1. Never automatically expire messages\n"
247 "2. Expire by message count\n"
248 "3. Expire by message age\n");
250 } while ((buf[0] < '1') || (buf[0] > '3'));
251 site_expirepolicy->expire_mode = buf[0] - '0';
253 /* ...lunatics and monsters underneath my bed */
254 if (site_expirepolicy->expire_mode == 2) {
255 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
256 strprompt("Keep how many messages online?", buf, 10);
257 site_expirepolicy->expire_value = atol(buf);
259 if (site_expirepolicy->expire_mode == 3) {
260 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
261 strprompt("Keep messages for how many days?", buf, 10);
262 site_expirepolicy->expire_value = atol(buf);
265 /* Media messiahs preying on my fears... */
267 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
268 strprompt("Mailbox default message expire policy (? for list)",
272 "0. Go with the system default\n"
273 "1. Never automatically expire messages\n"
274 "2. Expire by message count\n"
275 "3. Expire by message age\n");
277 } while ((buf[0] < '0') || (buf[0] > '3'));
278 mbx_expirepolicy->expire_mode = buf[0] - '0';
280 /* ...Pop culture prophets playing in my ears */
281 if (mbx_expirepolicy->expire_mode == 2) {
282 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
283 strprompt("Keep how many messages online?", buf, 10);
284 mbx_expirepolicy->expire_value = atol(buf);
286 if (mbx_expirepolicy->expire_mode == 3) {
287 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
288 strprompt("Keep messages for how many days?", buf, 10);
289 mbx_expirepolicy->expire_value = atol(buf);
292 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
293 strprompt("Default frequency to run POP3 collection (in seconds)", &sc[64][0], 5);
294 strprompt("Fastest frequency to run POP3 collection (in seconds)", &sc[65][0], 5);
295 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
296 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
297 "Enable full text search index (warning: resource intensive)",
300 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
301 "Perform journaling of email messages",
303 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
304 "Perform journaling of non-email messages",
306 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
307 strprompt("Email destination of journalized messages",
311 /* Funambol push stuff */
312 int yes_funambol = 0;
313 if (strlen(sc[53]) > 0) yes_funambol = 1;
314 yes_funambol = boolprompt("Connect to an external Funambol sync server", yes_funambol);
316 strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
317 strprompt("Funambol server port", &sc[54][0], 5);
318 strprompt("Funambol sync source", &sc[55][0], 63);
319 strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
328 /* External pager stuff */
330 if (strlen(sc[60]) > 0) yes_pager = 1;
331 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
333 strprompt("External pager tool", &sc[60][0], 255);
339 /* Master user account */
341 if (strlen(sc[58]) > 0) yes_muacct = 1;
342 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
344 strprompt("Master user name", &sc[58][0], 31);
345 strprompt("Master user password", &sc[59][0], -31);
348 strcpy(&sc[58][0], "");
349 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
353 scr_printf("Save this configuration? ");
356 for (a = 0; a < NUM_CONFIGS; a++)
357 r += 1 + strlen(sc[a]);
358 resp = (char *)calloc(1, r);
360 err_printf("Can't save config - out of memory!\n");
363 for (a = 0; a < NUM_CONFIGS; a++) {
367 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
369 err_printf("%s\n", buf);
373 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
375 err_printf("%s\n", buf);
378 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
380 err_printf("%s\n", buf);
384 if (site_expirepolicy) free(site_expirepolicy);
385 if (mbx_expirepolicy) free(mbx_expirepolicy);
390 * support function for do_internet_configuration()
392 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
395 keyopt(" <1> localhost (Alias for this computer)\n");
396 keyopt(" <2> smart-host (Forward all outbound mail to this host)\n");
397 keyopt(" <3> directory (Consult the Global Address Book)\n");
398 keyopt(" <4> SpamAssassin (Address of SpamAssassin server)\n");
399 keyopt(" <5> RBL (domain suffix of spam hunting RBL)\n");
400 keyopt(" <6> masq domains (Domains as which users are allowed to masquerade)\n");
401 keyopt(" <7> ClamAV (Address of ClamAV clamd server)\n");
402 sel = intprompt("Which one", 1, 1, 7);
404 case 1: strcpy(buf, "localhost");
406 case 2: strcpy(buf, "smarthost");
408 case 3: strcpy(buf, "directory");
410 case 4: strcpy(buf, "spamassassin");
412 case 5: strcpy(buf, "rbl");
414 case 6: strcpy(buf, "masqdomain");
416 case 7: strcpy(buf, "clamav");
423 * Internet mail configuration
425 void do_internet_configuration(CtdlIPC *ipc)
438 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
440 while (!IsEmptyStr(resp)) {
441 extract_token(buf, resp, 0, '\n', sizeof buf);
442 remove_token(resp, 0, '\n');
444 if (num_recs == 1) recs = malloc(sizeof(char *));
445 else recs = realloc(recs, (sizeof(char *)) * num_recs);
446 recs[num_recs-1] = malloc(strlen(buf) + 1);
447 strcpy(recs[num_recs-1], buf);
450 if (resp) free(resp);
455 scr_printf("### Host or domain Record type \n");
457 scr_printf("--- -------------------------------------------------- --------------------\n");
458 for (i=0; i<num_recs; ++i) {
460 scr_printf("%3d ", i+1);
461 extract_token(buf, recs[i], 0, '|', sizeof buf);
463 scr_printf("%-50s ", buf);
464 extract_token(buf, recs[i], 1, '|', sizeof buf);
465 color(BRIGHT_MAGENTA);
466 scr_printf("%-20s\n", buf);
470 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
473 newprompt("Enter host name: ",
476 if (!IsEmptyStr(buf)) {
479 recs = malloc(sizeof(char *));
480 else recs = realloc(recs,
481 (sizeof(char *)) * num_recs);
483 get_inet_rec_type(ipc,
485 recs[num_recs-1] = strdup(buf);
490 i = intprompt("Delete which one",
494 for (j=i; j<num_recs; ++j)
500 for (i = 0; i < num_recs; i++)
501 r += 1 + strlen(recs[i]);
502 resp = (char *)calloc(1, r);
504 err_printf("Can't save config - out of memory!\n");
507 if (num_recs) for (i = 0; i < num_recs; i++) {
508 strcat(resp, recs[i]);
511 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
513 err_printf("%s\n", buf);
515 scr_printf("Wrote %d records.\n", num_recs);
521 quitting = !modified || boolprompt(
522 "Quit without saving", 0);
530 for (i=0; i<num_recs; ++i) free(recs[i]);
538 * Edit network configuration for room sharing, mailing lists, etc.
540 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
542 char filename[PATH_MAX];
543 char changefile[PATH_MAX];
553 char *listing = NULL;
556 if (IsEmptyStr(editor_paths[0])) {
557 scr_printf("You must have an external editor configured in"
558 " order to use this function.\n");
562 CtdlMakeTempFileName(filename, sizeof filename);
563 CtdlMakeTempFileName(changefile, sizeof changefile);
565 tempfp = fopen(filename, "w");
566 if (tempfp == NULL) {
567 err_printf("Cannot open %s: %s\n", filename, strerror(errno));
571 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
572 fprintf(tempfp, "# %s\n", comment);
573 fprintf(tempfp, "# Specify one per line.\n"
576 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
578 while(listing && !IsEmptyStr(listing)) {
579 extract_token(buf, listing, 0, '\n', sizeof buf);
580 remove_token(listing, 0, '\n');
581 extract_token(instr, buf, 0, '|', sizeof instr);
582 if (!strcasecmp(instr, entrytype)) {
583 tokens = num_tokens(buf, '|');
584 for (i=1; i<tokens; ++i) {
585 extract_token(addr, buf, i, '|', sizeof addr);
586 fprintf(tempfp, "%s", addr);
587 if (i < (tokens-1)) {
588 fprintf(tempfp, "|");
591 fprintf(tempfp, "\n");
601 e_ex_code = 1; /* start with a failed exit code */
603 stty_ctdl(SB_RESTORE);
605 cksum = file_checksum(filename);
606 if (editor_pid == 0) {
607 chmod(filename, 0600);
608 putenv("WINDOW_TITLE=Network configuration");
609 execlp(editor_paths[0], editor_paths[0], filename, NULL);
612 if (editor_pid > 0) {
615 b = ka_wait(&e_ex_code);
616 } while ((b != editor_pid) && (b >= 0));
622 if (file_checksum(filename) == cksum) {
623 err_printf("*** No changes to save.\n");
627 if (e_ex_code == 0) { /* Save changes */
628 changefp = fopen(changefile, "w");
630 /* Load all netconfig entries that are *not* of the type we are editing */
631 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
633 while(listing && !IsEmptyStr(listing)) {
634 extract_token(buf, listing, 0, '\n', sizeof buf);
635 remove_token(listing, 0, '\n');
636 extract_token(instr, buf, 0, '|', sizeof instr);
637 if (strcasecmp(instr, entrytype)) {
638 fprintf(changefp, "%s\n", buf);
647 /* ...and merge that with the data we just edited */
648 tempfp = fopen(filename, "r");
649 while (fgets(buf, sizeof buf, tempfp) != NULL) {
650 for (i=0; i<strlen(buf); ++i) {
651 if (buf[i] == '#') buf[i] = 0;
654 if (!IsEmptyStr(buf)) {
655 fprintf(changefp, "%s|%s\n", entrytype, buf);
661 /* now write it to the server... */
662 changefp = fopen(changefile, "r");
663 if (changefp != NULL) {
664 listing = load_message_from_file(changefp);
666 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
674 unlink(filename); /* Delete the temporary files */
680 * IGnet node configuration
682 void do_ignet_configuration(CtdlIPC *ipc) {
691 char *listing = NULL;
694 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
695 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
696 extract_token(buf, listing, 0, '\n', sizeof buf);
697 remove_token(listing, 0, '\n');
700 if (num_recs == 1) recs = malloc(sizeof(char *));
701 else recs = realloc(recs, (sizeof(char *)) * num_recs);
702 recs[num_recs-1] = malloc(SIZ);
703 strcpy(recs[num_recs-1], buf);
705 if (listing) free(listing);
718 "------------------ "
719 "-------------------------------- "
721 for (i=0; i<num_recs; ++i) {
723 scr_printf("%3d ", i+1);
724 extract_token(buf, recs[i], 0, '|', sizeof buf);
726 scr_printf("%-16s ", buf);
727 extract_token(buf, recs[i], 1, '|', sizeof buf);
728 color(BRIGHT_MAGENTA);
729 scr_printf("%-18s ", buf);
730 extract_token(buf, recs[i], 2, '|', sizeof buf);
732 scr_printf("%-32s ", buf);
733 extract_token(buf, recs[i], 3, '|', sizeof buf);
734 color(BRIGHT_MAGENTA);
735 scr_printf("%-3s\n", buf);
740 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
745 recs = malloc(sizeof(char *));
746 else recs = realloc(recs,
747 (sizeof(char *)) * num_recs);
748 newprompt("Enter node name : ", buf, 16);
750 newprompt("Enter shared secret: ",
751 &buf[strlen(buf)], 18);
753 newprompt("Enter host or IP : ",
754 &buf[strlen(buf)], 32);
756 strprompt("Enter port number : ",
757 &buf[strlen(buf)-3], 5);
758 recs[num_recs-1] = strdup(buf);
762 i = intprompt("Delete which one",
766 for (j=i; j<num_recs; ++j)
772 for (i = 0; i < num_recs; ++i)
773 r += 1 + strlen(recs[i]);
774 listing = (char*) calloc(1, r);
776 err_printf("Can't save config - out of memory!\n");
779 if (num_recs) for (i = 0; i < num_recs; ++i) {
780 strcat(listing, recs[i]);
781 strcat(listing, "\n");
783 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
785 scr_printf("%s\n", buf);
787 scr_printf("Wrote %d records.\n", num_recs);
793 quitting = !modified || boolprompt(
794 "Quit without saving", 0);
802 for (i=0; i<num_recs; ++i) free(recs[i]);
809 * Filter list configuration
811 void do_filterlist_configuration(CtdlIPC *ipc)
821 char *listing = NULL;
824 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
825 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
826 extract_token(buf, listing, 0, '\n', sizeof buf);
827 remove_token(listing, 0, '\n');
830 if (num_recs == 1) recs = malloc(sizeof(char *));
831 else recs = realloc(recs, (sizeof(char *)) * num_recs);
832 recs[num_recs-1] = malloc(SIZ);
833 strcpy(recs[num_recs-1], buf);
835 if (listing) free(listing);
847 "---------------------------- "
848 "---------------------------- "
851 for (i=0; i<num_recs; ++i) {
853 scr_printf("%3d ", i+1);
854 extract_token(buf, recs[i], 0, '|', sizeof buf);
856 scr_printf("%-28s ", buf);
857 extract_token(buf, recs[i], 1, '|', sizeof buf);
858 color(BRIGHT_MAGENTA);
859 scr_printf("%-28s ", buf);
860 extract_token(buf, recs[i], 2, '|', sizeof buf);
862 scr_printf("%-16s\n", buf);
863 extract_token(buf, recs[i], 3, '|', sizeof buf);
867 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
872 recs = malloc(sizeof(char *));
873 else recs = realloc(recs,
874 (sizeof(char *)) * num_recs);
875 newprompt("Enter user name: ", buf, 28);
877 newprompt("Enter room name: ",
878 &buf[strlen(buf)], 28);
880 newprompt("Enter node name: ",
881 &buf[strlen(buf)], 16);
883 recs[num_recs-1] = strdup(buf);
887 i = intprompt("Delete which one",
891 for (j=i; j<num_recs; ++j)
897 for (i = 0; i < num_recs; ++i)
898 r += 1 + strlen(recs[i]);
899 listing = (char*) calloc(1, r);
901 err_printf("Can't save config - out of memory!\n");
904 if (num_recs) for (i = 0; i < num_recs; ++i) {
905 strcat(listing, recs[i]);
906 strcat(listing, "\n");
908 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
910 scr_printf("%s\n", buf);
912 scr_printf("Wrote %d records.\n", num_recs);
918 quitting = !modified || boolprompt(
919 "Quit without saving", 0);
927 for (i=0; i<num_recs; ++i) free(recs[i]);
936 * POP3 aggregation client configuration
938 void do_pop3client_configuration(CtdlIPC *ipc)
948 char *listing = NULL;
949 char *other_listing = NULL;
953 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
955 while(listing && !IsEmptyStr(listing)) {
956 extract_token(buf, listing, 0, '\n', sizeof buf);
957 remove_token(listing, 0, '\n');
958 extract_token(instr, buf, 0, '|', sizeof instr);
959 if (!strcasecmp(instr, "pop3client")) {
962 if (num_recs == 1) recs = malloc(sizeof(char *));
963 else recs = realloc(recs, (sizeof(char *)) * num_recs);
964 recs[num_recs-1] = malloc(SIZ);
965 strcpy(recs[num_recs-1], buf);
986 "---------------------------- "
987 "---------------------------- "
991 for (i=0; i<num_recs; ++i) {
993 scr_printf("%3d ", i+1);
995 extract_token(buf, recs[i], 1, '|', sizeof buf);
997 scr_printf("%-28s ", buf);
999 extract_token(buf, recs[i], 2, '|', sizeof buf);
1000 color(BRIGHT_MAGENTA);
1001 scr_printf("%-28s ", buf);
1004 scr_printf("%-15s ", (extract_int(recs[i], 4) ? "Yes" : "No") );
1005 color(BRIGHT_MAGENTA);
1006 scr_printf("%ld\n", extract_long(recs[i], 5) );
1010 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1014 if (num_recs == 1) {
1015 recs = malloc(sizeof(char *));
1018 recs = realloc(recs, (sizeof(char *)) * num_recs);
1020 strcpy(buf, "pop3client|");
1021 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1023 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1025 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1027 scr_printf("Keep messages on server instead of deleting them? ");
1028 sprintf(&buf[strlen(buf)], "%d", yesno());
1030 newprompt("Enter interval : ", &buf[strlen(buf)], 5);
1032 recs[num_recs-1] = strdup(buf);
1036 i = intprompt("Delete which one",
1037 1, 1, num_recs) - 1;
1040 for (j=i; j<num_recs; ++j)
1041 recs[j] = recs[j+1];
1046 for (i = 0; i < num_recs; ++i) {
1047 r += 1 + strlen(recs[i]);
1049 listing = (char*) calloc(1, r);
1051 err_printf("Can't save config - out of memory!\n");
1054 if (num_recs) for (i = 0; i < num_recs; ++i) {
1055 strcat(listing, recs[i]);
1056 strcat(listing, "\n");
1059 /* Retrieve all the *other* records for merging */
1060 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1062 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1063 extract_token(buf, other_listing, i, '\n', sizeof buf);
1064 if (strncasecmp(buf, "pop3client|", 11)) {
1065 listing = realloc(listing, strlen(listing) +
1067 strcat(listing, buf);
1068 strcat(listing, "\n");
1072 free(other_listing);
1073 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1078 scr_printf("%s\n", buf);
1080 scr_printf("Wrote %d records.\n", num_recs);
1086 quitting = !modified || boolprompt(
1087 "Quit without saving", 0);
1092 } while (!quitting);
1095 for (i=0; i<num_recs; ++i) free(recs[i]);
1106 * RSS feed retrieval client configuration
1108 void do_rssclient_configuration(CtdlIPC *ipc)
1118 char *listing = NULL;
1119 char *other_listing = NULL;
1123 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1125 while(listing && !IsEmptyStr(listing)) {
1126 extract_token(buf, listing, 0, '\n', sizeof buf);
1127 remove_token(listing, 0, '\n');
1128 extract_token(instr, buf, 0, '|', sizeof instr);
1129 if (!strcasecmp(instr, "rssclient")) {
1132 if (num_recs == 1) recs = malloc(sizeof(char *));
1133 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1134 recs[num_recs-1] = malloc(SIZ);
1135 strcpy(recs[num_recs-1], buf);
1147 color(BRIGHT_WHITE);
1148 scr_printf("### Feed URL\n");
1151 "---------------------------------------------------------------------------"
1154 for (i=0; i<num_recs; ++i) {
1156 scr_printf("%3d ", i+1);
1158 extract_token(buf, recs[i], 1, '|', sizeof buf);
1160 scr_printf("%-75s\n", buf);
1165 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1169 if (num_recs == 1) {
1170 recs = malloc(sizeof(char *));
1173 recs = realloc(recs, (sizeof(char *)) * num_recs);
1175 strcpy(buf, "rssclient|");
1176 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1178 recs[num_recs-1] = strdup(buf);
1182 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1185 for (j=i; j<num_recs; ++j)
1186 recs[j] = recs[j+1];
1191 for (i = 0; i < num_recs; ++i) {
1192 r += 1 + strlen(recs[i]);
1194 listing = (char*) calloc(1, r);
1196 err_printf("Can't save config - out of memory!\n");
1199 if (num_recs) for (i = 0; i < num_recs; ++i) {
1200 strcat(listing, recs[i]);
1201 strcat(listing, "\n");
1204 /* Retrieve all the *other* records for merging */
1205 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1207 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1208 extract_token(buf, other_listing, i, '\n', sizeof buf);
1209 if (strncasecmp(buf, "rssclient|", 10)) {
1210 listing = realloc(listing, strlen(listing) +
1212 strcat(listing, buf);
1213 strcat(listing, "\n");
1217 free(other_listing);
1218 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1223 scr_printf("%s\n", buf);
1225 scr_printf("Wrote %d records.\n", num_recs);
1231 quitting = !modified || boolprompt(
1232 "Quit without saving", 0);
1237 } while (!quitting);
1240 for (i=0; i<num_recs; ++i) free(recs[i]);