2 * Configuration screens that are part of the text mode client.
4 * Copyright (c) 1987-2017 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.
17 #include <sys/types.h>
25 #if TIME_WITH_SYS_TIME
26 # include <sys/time.h>
30 # include <sys/time.h>
40 #include <libcitadel.h>
42 #include "citadel_ipc.h"
43 #include "citadel_decls.h"
44 #include "tuiconfig.h"
50 /* work around solaris include files */
56 extern char tempdir[];
57 extern char *axdefs[8];
58 extern long highest_msg_read;
59 extern long maxmsgnum;
60 extern unsigned room_flags;
61 extern int screenwidth;
62 char editor_path[PATH_MAX];
66 * General system configuration command
68 void do_system_configuration(CtdlIPC *ipc)
71 /* NUM_CONFIGS is now defined in citadel.h */
74 char sc[NUM_CONFIGS][256];
76 struct ExpirePolicy *site_expirepolicy = NULL;
77 struct ExpirePolicy *mbx_expirepolicy = NULL;
80 int r; /* IPC response code */
81 int server_configs = 0;
83 /* Clear out the config buffers */
84 memset(&sc[0][0], 0, sizeof(sc));
86 /* Fetch the current config */
87 r = CtdlIPCGetSystemConfig(ipc, &resp, buf);
89 server_configs = num_tokens(resp, '\n');
90 for (a=0; a<server_configs; ++a) {
91 if (a < NUM_CONFIGS) {
92 extract_token(&sc[a][0], resp, a, '\n', sizeof sc[a]);
98 /* Fetch the expire policy (this will silently fail on old servers,
99 * resulting in "default" policy)
101 r = CtdlIPCGetMessageExpirationPolicy(ipc, 2, &site_expirepolicy, buf);
102 r = CtdlIPCGetMessageExpirationPolicy(ipc, 3, &mbx_expirepolicy, buf);
104 /* Identification parameters */
106 strprompt("Node name", &sc[0][0], 15);
107 strprompt("Fully qualified domain name", &sc[1][0], 63);
108 strprompt("Human readable node name", &sc[2][0], 20);
109 strprompt("Telephone number", &sc[3][0], 15);
110 strprompt("Geographic location of this system", &sc[12][0], 31);
111 strprompt("Name of system administrator", &sc[13][0], 25);
112 strprompt("Paginator prompt", &sc[10][0], 79);
114 /* Security parameters */
116 snprintf(sc[7], sizeof sc[7], "%d", (boolprompt("Require registration for new users", atoi(&sc[7][0]))));
117 snprintf(sc[29], sizeof sc[29], "%d", (boolprompt("Disable self-service user account creation", atoi(&sc[29][0]))));
118 strprompt("Initial access level for new users", &sc[6][0], 1);
119 strprompt("Access level required to create rooms", &sc[19][0], 1);
120 snprintf(sc[67], sizeof sc[67], "%d", (boolprompt("Allow anonymous guest logins", atoi(&sc[67][0]))));
121 snprintf(sc[4], sizeof sc[4], "%d", (boolprompt(
122 "Automatically give room admin privs to a user who creates a private room",
125 snprintf(sc[8], sizeof sc[8], "%d", (boolprompt(
126 "Automatically move problem user messages to twit room",
129 strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
130 snprintf(sc[11], sizeof sc[11], "%d", (boolprompt(
131 "Restrict Internet mail to only those with that privilege",
133 snprintf(sc[26], sizeof sc[26], "%d", (boolprompt(
134 "Allow admins to Zap (forget) rooms",
137 if (!IsEmptyStr(&sc[18][0])) {
143 logpages = boolprompt("Log all instant messages", logpages);
145 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
151 /* Commented out because this setting isn't really appropriate to
152 * change while the server is running.
154 * snprintf(sc[52], sizeof sc[52], "%d", (boolprompt(
155 * "Use system authentication",
156 * atoi(&sc[52][0]))));
161 strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
162 strprompt("Maximum concurrent sessions", &sc[14][0], 4);
163 strprompt("Maximum message length", &sc[20][0], 20);
164 strprompt("Minimum number of worker threads", &sc[21][0], 3);
165 strprompt("Maximum number of worker threads", &sc[22][0], 3);
166 snprintf(sc[43], sizeof sc[43], "%d", (boolprompt(
167 "Automatically delete committed database logs",
170 strprompt("Server IP address (* for 'any')", &sc[37][0], 15);
171 strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
172 strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5);
173 strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
174 strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5);
175 strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5);
176 strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5);
177 strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5);
178 strprompt("NNTP server port (-1 to disable)", &sc[70][0], 5);
179 strprompt("NNTPS server port (-1 to disable)", &sc[71][0], 5);
180 strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5);
181 strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5);
183 strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5);
184 /* No prompt because we don't implement this service yet, it's just a placeholder */
185 /* strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); */
187 /* This logic flips the question around, because it's one of those
188 * situations where 0=yes and 1=no
192 a = boolprompt("Correct forged From: lines during authenticated SMTP", a);
194 snprintf(sc[25], sizeof sc[25], "%d", a);
196 snprintf(sc[66], sizeof sc[66], "%d", (boolprompt(
197 "Flag messages as spam instead of rejecting",
200 /* This logic flips the question around, because it's one of those
201 * situations where 0=yes and 1=no
205 a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a);
207 snprintf(sc[61], sizeof sc[61], "%d", a);
209 snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
210 "Allow unauthenticated SMTP clients to spoof my domains",
212 snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
213 "Perform RBL checks at greeting instead of after RCPT",
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", &sc[32][0], 127);
223 strprompt("Port number of LDAP service", &sc[33][0], 5);
224 strprompt("Base DN", &sc[34][0], 255);
225 strprompt("Bind DN (or blank for anonymous bind)", &sc[35][0], 255);
226 strprompt("Password for bind DN (or blank for anonymous bind)", &sc[36][0], 255);
229 strcpy(&sc[32][0], "");
233 /* Expiry settings */
234 strprompt("Default user purge time (days)", &sc[16][0], 5);
235 strprompt("Default room purge time (days)", &sc[17][0], 5);
237 /* Angels and demons dancing in my head... */
239 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
240 strprompt("System default message expire policy (? for list)",
244 "1. Never automatically expire messages\n"
245 "2. Expire by message count\n"
246 "3. Expire by message age\n");
248 } while ((buf[0] < '1') || (buf[0] > '3'));
249 site_expirepolicy->expire_mode = buf[0] - '0';
251 /* ...lunatics and monsters underneath my bed */
252 if (site_expirepolicy->expire_mode == 2) {
253 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
254 strprompt("Keep how many messages online?", buf, 10);
255 site_expirepolicy->expire_value = atol(buf);
257 if (site_expirepolicy->expire_mode == 3) {
258 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
259 strprompt("Keep messages for how many days?", buf, 10);
260 site_expirepolicy->expire_value = atol(buf);
263 /* Media messiahs preying on my fears... */
265 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
266 strprompt("Mailbox default message expire policy (? for list)",
270 "0. Go with the system default\n"
271 "1. Never automatically expire messages\n"
272 "2. Expire by message count\n"
273 "3. Expire by message age\n");
275 } while ((buf[0] < '0') || (buf[0] > '3'));
276 mbx_expirepolicy->expire_mode = buf[0] - '0';
278 /* ...Pop culture prophets playing in my ears */
279 if (mbx_expirepolicy->expire_mode == 2) {
280 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
281 strprompt("Keep how many messages online?", buf, 10);
282 mbx_expirepolicy->expire_value = atol(buf);
284 if (mbx_expirepolicy->expire_mode == 3) {
285 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
286 strprompt("Keep messages for how many days?", buf, 10);
287 mbx_expirepolicy->expire_value = atol(buf);
290 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
291 strprompt("Default frequency to run POP3 collection (in seconds)", &sc[64][0], 5);
292 strprompt("Fastest frequency to run POP3 collection (in seconds)", &sc[65][0], 5);
293 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
294 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
295 "Enable full text search index (warning: resource intensive)",
298 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
299 "Perform journaling of email messages",
301 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
302 "Perform journaling of non-email messages",
304 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
305 strprompt("Email destination of journalized messages",
309 /* No more Funambol */
315 /* External pager stuff */
317 if (strlen(sc[60]) > 0) yes_pager = 1;
318 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
320 strprompt("External pager tool", &sc[60][0], 255);
326 /* Master user account */
328 if (strlen(sc[58]) > 0) yes_muacct = 1;
329 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
331 strprompt("Master user name", &sc[58][0], 31);
332 strprompt("Master user password", &sc[59][0], -31);
335 strcpy(&sc[58][0], "");
336 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
340 scr_printf("Save this configuration? ");
343 for (a = 0; a < NUM_CONFIGS; a++) {
344 r += 1 + strlen(sc[a]);
346 resp = (char *)calloc(1, r);
348 scr_printf("Can't save config - out of memory!\n");
351 for (a = 0; a < NUM_CONFIGS; a++) {
355 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
357 scr_printf("%s\n", buf);
361 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
363 scr_printf("%s\n", buf);
366 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
368 scr_printf("%s\n", buf);
372 if (site_expirepolicy) free(site_expirepolicy);
373 if (mbx_expirepolicy) free(mbx_expirepolicy);
378 * support function for do_internet_configuration()
380 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
383 keyopt(" <1> localhost (Alias for this computer)\n");
384 keyopt(" <2> smart host (Forward all outbound mail to this host)\n");
385 keyopt(" <3> fallback host (Send mail to this host only if direct delivery fails)\n");
386 keyopt(" <4> SpamAssassin (Address of SpamAssassin server)\n");
387 keyopt(" <5> RBL (domain suffix of spam hunting RBL)\n");
388 keyopt(" <6> masq domains (Domains as which users are allowed to masquerade)\n");
389 keyopt(" <7> ClamAV (Address of ClamAV clamd server)\n");
390 sel = intprompt("Which one", 1, 1, 8);
392 case 1: strcpy(buf, "localhost");
394 case 2: strcpy(buf, "smarthost");
396 case 3: strcpy(buf, "fallbackhost");
398 case 4: strcpy(buf, "spamassassin");
400 case 5: strcpy(buf, "rbl");
402 case 6: strcpy(buf, "masqdomain");
404 case 7: strcpy(buf, "clamav");
411 * Internet mail configuration
413 void do_internet_configuration(CtdlIPC *ipc)
425 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
427 while (!IsEmptyStr(resp)) {
428 extract_token(buf, resp, 0, '\n', sizeof buf);
429 remove_token(resp, 0, '\n');
431 // VILE SLEAZY HACK: replace obsolete "directory" domains with "localhost"
432 char *d = strstr(buf, "|directory");
434 strcpy(d, "|localhost");
438 if (num_recs == 1) recs = malloc(sizeof(char *));
439 else recs = realloc(recs, (sizeof(char *)) * num_recs);
440 recs[num_recs-1] = malloc(strlen(buf) + 1);
441 strcpy(recs[num_recs-1], buf);
444 if (resp) free(resp);
449 scr_printf("### Host or domain Record type \n");
451 scr_printf("--- -------------------------------------------------- --------------------\n");
452 for (i=0; i<num_recs; ++i) {
454 scr_printf("%3d ", i+1);
455 extract_token(buf, recs[i], 0, '|', sizeof buf);
457 scr_printf("%-50s ", buf);
458 extract_token(buf, recs[i], 1, '|', sizeof buf);
459 color(BRIGHT_MAGENTA);
460 scr_printf("%-20s\n", buf);
464 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
467 newprompt("Enter host name: ", buf, 50);
469 if (!IsEmptyStr(buf)) {
472 recs = malloc(sizeof(char *));
475 recs = realloc(recs, (sizeof(char *)) * num_recs);
478 get_inet_rec_type(ipc, &buf[strlen(buf)]);
479 recs[num_recs-1] = strdup(buf);
484 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
487 for (j=i; j<num_recs; ++j) {
494 for (i = 0; i < num_recs; i++)
495 r += 1 + strlen(recs[i]);
496 resp = (char *)calloc(1, r);
498 scr_printf("Can't save config - out of memory!\n");
501 if (num_recs) for (i = 0; i < num_recs; i++) {
502 strcat(resp, recs[i]);
505 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
507 scr_printf("%s\n", buf);
509 scr_printf("Wrote %d records.\n", num_recs);
515 quitting = !modified || boolprompt(
516 "Quit without saving", 0);
524 for (i=0; i<num_recs; ++i) free(recs[i]);
532 * Edit network configuration for room sharing, mailing lists, etc.
534 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
536 char filename[PATH_MAX];
537 char changefile[PATH_MAX];
547 char *listing = NULL;
550 if (IsEmptyStr(editor_path)) {
551 scr_printf("You must have an external editor configured in order to use this function.\n");
555 CtdlMakeTempFileName(filename, sizeof filename);
556 CtdlMakeTempFileName(changefile, sizeof changefile);
558 tempfp = fopen(filename, "w");
559 if (tempfp == NULL) {
560 scr_printf("Cannot open %s: %s\n", filename, strerror(errno));
564 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
565 fprintf(tempfp, "# %s\n", comment);
566 fprintf(tempfp, "# Specify one per line.\n"
569 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
571 while(listing && !IsEmptyStr(listing)) {
572 extract_token(buf, listing, 0, '\n', sizeof buf);
573 remove_token(listing, 0, '\n');
574 extract_token(instr, buf, 0, '|', sizeof instr);
575 if (!strcasecmp(instr, entrytype)) {
576 tokens = num_tokens(buf, '|');
577 for (i=1; i<tokens; ++i) {
578 extract_token(addr, buf, i, '|', sizeof addr);
579 fprintf(tempfp, "%s", addr);
580 if (i < (tokens-1)) {
581 fprintf(tempfp, "|");
584 fprintf(tempfp, "\n");
594 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_path, editor_path, filename, NULL);
604 if (editor_pid > 0) {
607 b = ka_wait(&e_ex_code);
608 } while ((b != editor_pid) && (b >= 0));
613 if (file_checksum(filename) == cksum) {
614 scr_printf("*** No changes to save.\n");
618 if (e_ex_code == 0) { /* Save changes */
619 changefp = fopen(changefile, "w");
621 /* Load all netconfig entries that are *not* of the type we are editing */
622 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
624 while(listing && !IsEmptyStr(listing)) {
625 extract_token(buf, listing, 0, '\n', sizeof buf);
626 remove_token(listing, 0, '\n');
627 extract_token(instr, buf, 0, '|', sizeof instr);
628 if (strcasecmp(instr, entrytype)) {
629 fprintf(changefp, "%s\n", buf);
638 /* ...and merge that with the data we just edited */
639 tempfp = fopen(filename, "r");
640 while (fgets(buf, sizeof buf, tempfp) != NULL) {
641 for (i=0; i<strlen(buf); ++i) {
642 if (buf[i] == '#') buf[i] = 0;
645 if (!IsEmptyStr(buf)) {
646 fprintf(changefp, "%s|%s\n", entrytype, buf);
652 /* now write it to the server... */
653 changefp = fopen(changefile, "r");
654 if (changefp != NULL) {
655 listing = load_message_from_file(changefp);
657 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
665 unlink(filename); /* Delete the temporary files */
671 * IGnet node configuration
673 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 scr_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)
810 char *listing = NULL;
813 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
814 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
815 extract_token(buf, listing, 0, '\n', sizeof buf);
816 remove_token(listing, 0, '\n');
819 if (num_recs == 1) recs = malloc(sizeof(char *));
820 else recs = realloc(recs, (sizeof(char *)) * num_recs);
821 recs[num_recs-1] = malloc(SIZ);
822 strcpy(recs[num_recs-1], buf);
824 if (listing) free(listing);
836 "---------------------------- "
837 "---------------------------- "
840 for (i=0; i<num_recs; ++i) {
842 scr_printf("%3d ", i+1);
843 extract_token(buf, recs[i], 0, '|', sizeof buf);
845 scr_printf("%-28s ", buf);
846 extract_token(buf, recs[i], 1, '|', sizeof buf);
847 color(BRIGHT_MAGENTA);
848 scr_printf("%-28s ", buf);
849 extract_token(buf, recs[i], 2, '|', sizeof buf);
851 scr_printf("%-16s\n", buf);
852 extract_token(buf, recs[i], 3, '|', sizeof buf);
856 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
861 recs = malloc(sizeof(char *));
862 else recs = realloc(recs,
863 (sizeof(char *)) * num_recs);
864 newprompt("Enter user name: ", buf, 28);
866 newprompt("Enter room name: ",
867 &buf[strlen(buf)], 28);
869 newprompt("Enter node name: ",
870 &buf[strlen(buf)], 16);
872 recs[num_recs-1] = strdup(buf);
876 i = intprompt("Delete which one",
880 for (j=i; j<num_recs; ++j)
886 for (i = 0; i < num_recs; ++i)
887 r += 1 + strlen(recs[i]);
888 listing = (char*) calloc(1, r);
890 scr_printf("Can't save config - out of memory!\n");
893 if (num_recs) for (i = 0; i < num_recs; ++i) {
894 strcat(listing, recs[i]);
895 strcat(listing, "\n");
897 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
899 scr_printf("%s\n", buf);
901 scr_printf("Wrote %d records.\n", num_recs);
907 quitting = !modified || boolprompt(
908 "Quit without saving", 0);
916 for (i=0; i<num_recs; ++i) free(recs[i]);
925 * POP3 aggregation client configuration
927 void do_pop3client_configuration(CtdlIPC *ipc)
936 char *listing = NULL;
937 char *other_listing = NULL;
941 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
943 while(listing && !IsEmptyStr(listing)) {
944 extract_token(buf, listing, 0, '\n', sizeof buf);
945 remove_token(listing, 0, '\n');
946 extract_token(instr, buf, 0, '|', sizeof instr);
947 if (!strcasecmp(instr, "pop3client")) {
950 if (num_recs == 1) recs = malloc(sizeof(char *));
951 else recs = realloc(recs, (sizeof(char *)) * num_recs);
952 recs[num_recs-1] = malloc(SIZ);
953 strcpy(recs[num_recs-1], buf);
973 "---------------------------- "
974 "---------------------------- "
977 for (i=0; i<num_recs; ++i) {
979 scr_printf("%3d ", i+1);
981 extract_token(buf, recs[i], 1, '|', sizeof buf);
983 scr_printf("%-28s ", buf);
985 extract_token(buf, recs[i], 2, '|', sizeof buf);
986 color(BRIGHT_MAGENTA);
987 scr_printf("%-28s ", buf);
990 scr_printf("%-15s\n", (extract_int(recs[i], 4) ? "Yes" : "No") );
994 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
999 recs = malloc(sizeof(char *));
1002 recs = realloc(recs, (sizeof(char *)) * num_recs);
1004 strcpy(buf, "pop3client|");
1005 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1007 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1009 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1011 scr_printf("Keep messages on server instead of deleting them? ");
1012 sprintf(&buf[strlen(buf)], "%d", yesno());
1014 recs[num_recs-1] = strdup(buf);
1018 i = intprompt("Delete which one",
1019 1, 1, num_recs) - 1;
1022 for (j=i; j<num_recs; ++j)
1023 recs[j] = recs[j+1];
1028 for (i = 0; i < num_recs; ++i) {
1029 r += 1 + strlen(recs[i]);
1031 listing = (char*) calloc(1, r);
1033 scr_printf("Can't save config - out of memory!\n");
1036 if (num_recs) for (i = 0; i < num_recs; ++i) {
1037 strcat(listing, recs[i]);
1038 strcat(listing, "\n");
1041 /* Retrieve all the *other* records for merging */
1042 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1044 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1045 extract_token(buf, other_listing, i, '\n', sizeof buf);
1046 if (strncasecmp(buf, "pop3client|", 11)) {
1047 listing = realloc(listing, strlen(listing) +
1049 strcat(listing, buf);
1050 strcat(listing, "\n");
1054 free(other_listing);
1055 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1060 scr_printf("%s\n", buf);
1062 scr_printf("Wrote %d records.\n", num_recs);
1068 quitting = !modified || boolprompt(
1069 "Quit without saving", 0);
1074 } while (!quitting);
1077 for (i=0; i<num_recs; ++i) free(recs[i]);
1088 * RSS feed retrieval client configuration
1090 void do_rssclient_configuration(CtdlIPC *ipc)
1099 char *listing = NULL;
1100 char *other_listing = NULL;
1104 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1106 while(listing && !IsEmptyStr(listing)) {
1107 extract_token(buf, listing, 0, '\n', sizeof buf);
1108 remove_token(listing, 0, '\n');
1109 extract_token(instr, buf, 0, '|', sizeof instr);
1110 if (!strcasecmp(instr, "rssclient")) {
1113 if (num_recs == 1) recs = malloc(sizeof(char *));
1114 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1115 recs[num_recs-1] = malloc(SIZ);
1116 strcpy(recs[num_recs-1], buf);
1128 color(BRIGHT_WHITE);
1129 scr_printf("### Feed URL\n");
1132 "---------------------------------------------------------------------------"
1135 for (i=0; i<num_recs; ++i) {
1137 scr_printf("%3d ", i+1);
1139 extract_token(buf, recs[i], 1, '|', sizeof buf);
1141 scr_printf("%-75s\n", buf);
1146 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1150 if (num_recs == 1) {
1151 recs = malloc(sizeof(char *));
1154 recs = realloc(recs, (sizeof(char *)) * num_recs);
1156 strcpy(buf, "rssclient|");
1157 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1159 recs[num_recs-1] = strdup(buf);
1163 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1166 for (j=i; j<num_recs; ++j)
1167 recs[j] = recs[j+1];
1172 for (i = 0; i < num_recs; ++i) {
1173 r += 1 + strlen(recs[i]);
1175 listing = (char*) calloc(1, r);
1177 scr_printf("Can't save config - out of memory!\n");
1180 if (num_recs) for (i = 0; i < num_recs; ++i) {
1181 strcat(listing, recs[i]);
1182 strcat(listing, "\n");
1185 /* Retrieve all the *other* records for merging */
1186 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1188 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1189 extract_token(buf, other_listing, i, '\n', sizeof buf);
1190 if (strncasecmp(buf, "rssclient|", 10)) {
1191 listing = realloc(listing, strlen(listing) +
1193 strcat(listing, buf);
1194 strcat(listing, "\n");
1198 free(other_listing);
1199 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1204 scr_printf("%s\n", buf);
1206 scr_printf("Wrote %d records.\n", num_recs);
1212 quitting = !modified || boolprompt(
1213 "Quit without saving", 0);
1218 } while (!quitting);
1221 for (i=0; i<num_recs; ++i) free(recs[i]);