2 * Configuration screens that are part of the text mode client.
4 * Copyright (c) 1987-2012 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>
43 #include "citadel_ipc.h"
44 #include "citadel_decls.h"
45 #include "tuiconfig.h"
54 /* work around solaris include files */
60 extern char tempdir[];
61 extern char *axdefs[8];
62 extern long highest_msg_read;
63 extern long maxmsgnum;
64 extern unsigned room_flags;
65 extern int screenwidth;
66 char editor_path[PATH_MAX];
70 * General system configuration command
72 void do_system_configuration(CtdlIPC *ipc)
75 /* NUM_CONFIGS is now defined in citadel.h */
78 char sc[NUM_CONFIGS][256];
80 struct ExpirePolicy *site_expirepolicy = NULL;
81 struct ExpirePolicy *mbx_expirepolicy = NULL;
84 int r; /* IPC response code */
85 int server_configs = 0;
87 /* Clear out the config buffers */
88 memset(&sc[0][0], 0, sizeof(sc));
90 /* Fetch the current config */
91 r = CtdlIPCGetSystemConfig(ipc, &resp, buf);
93 server_configs = num_tokens(resp, '\n');
94 for (a=0; a<server_configs; ++a) {
95 if (a < NUM_CONFIGS) {
96 extract_token(&sc[a][0], resp, a, '\n', sizeof sc[a]);
100 if (resp) free(resp);
102 /* Fetch the expire policy (this will silently fail on old servers,
103 * resulting in "default" policy)
105 r = CtdlIPCGetMessageExpirationPolicy(ipc, 2, &site_expirepolicy, buf);
106 r = CtdlIPCGetMessageExpirationPolicy(ipc, 3, &mbx_expirepolicy, buf);
108 /* Identification parameters */
110 strprompt("Node name", &sc[0][0], 15);
111 strprompt("Fully qualified domain name", &sc[1][0], 63);
112 strprompt("Human readable node name", &sc[2][0], 20);
113 strprompt("Telephone number", &sc[3][0], 15);
114 strprompt("Geographic location of this system", &sc[12][0], 31);
115 strprompt("Name of system administrator", &sc[13][0], 25);
116 strprompt("Paginator prompt", &sc[10][0], 79);
118 /* Security parameters */
120 snprintf(sc[7], sizeof sc[7], "%d", (boolprompt(
121 "Require registration for new users",
123 snprintf(sc[29], sizeof sc[29], "%d", (boolprompt(
124 "Disable self-service user account creation",
126 strprompt("Initial access level for new users", &sc[6][0], 1);
127 strprompt("Access level required to create rooms", &sc[19][0], 1);
128 snprintf(sc[67], sizeof sc[67], "%d", (boolprompt(
129 "Allow anonymous guest logins",
131 snprintf(sc[4], sizeof sc[4], "%d", (boolprompt(
132 "Automatically give room aide privs to a user who creates a private room",
135 snprintf(sc[8], sizeof sc[8], "%d", (boolprompt(
136 "Automatically move problem user messages to twit room",
139 strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
140 snprintf(sc[11], sizeof sc[11], "%d", (boolprompt(
141 "Restrict Internet mail to only those with that privilege",
143 snprintf(sc[26], sizeof sc[26], "%d", (boolprompt(
144 "Allow Aides to Zap (forget) rooms",
147 if (!IsEmptyStr(&sc[18][0])) {
153 logpages = boolprompt("Log all instant messages", logpages);
155 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
161 /* Commented out because this setting isn't really appropriate to
162 * change while the server is running.
164 * snprintf(sc[52], sizeof sc[52], "%d", (boolprompt(
165 * "Use system authentication",
166 * atoi(&sc[52][0]))));
171 strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
172 strprompt("Maximum concurrent sessions", &sc[14][0], 4);
173 strprompt("Maximum message length", &sc[20][0], 20);
174 strprompt("Minimum number of worker threads", &sc[21][0], 3);
175 strprompt("Maximum number of worker threads", &sc[22][0], 3);
176 snprintf(sc[43], sizeof sc[43], "%d", (boolprompt(
177 "Automatically delete committed database logs",
180 strprompt("Server IP address (* for 'any')", &sc[37][0], 15);
181 strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
182 strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5);
183 strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
184 strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5);
185 strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5);
186 strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5);
187 strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5);
188 strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5);
189 strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5);
191 strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5);
192 /* No prompt because we don't implement this service yet, it's just a placeholder */
193 /* strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); */
195 /* This logic flips the question around, because it's one of those
196 * situations where 0=yes and 1=no
200 a = boolprompt("Correct forged From: lines during authenticated SMTP",
203 snprintf(sc[25], sizeof sc[25], "%d", a);
205 snprintf(sc[66], sizeof sc[66], "%d", (boolprompt(
206 "Flag messages as spam instead of rejecting",
209 /* This logic flips the question around, because it's one of those
210 * situations where 0=yes and 1=no
214 a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a);
216 snprintf(sc[61], sizeof sc[61], "%d", a);
218 snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
219 "Allow unauthenticated SMTP clients to spoof my domains",
221 snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
222 "Perform RBL checks at greeting instead of after RCPT",
224 snprintf(sc[44], sizeof sc[44], "%d", (boolprompt(
225 "Instantly expunge deleted IMAP messages",
229 if (ipc->ServInfo.supports_ldap) {
230 a = strlen(&sc[32][0]);
231 a = (a ? 1 : 0); /* Set only to 1 or 0 */
232 a = boolprompt("Do you want to configure LDAP authentication?", a);
234 strprompt("Host name of LDAP server",
236 strprompt("Port number of LDAP service",
238 strprompt("Base DN", &sc[34][0], 255);
239 strprompt("Bind DN (or blank for anonymous bind)", &sc[35][0], 255);
240 strprompt("Password for bind DN (or blank for anonymous bind)", &sc[36][0], 255);
243 strcpy(&sc[32][0], "");
247 /* Expiry settings */
248 strprompt("Default user purge time (days)", &sc[16][0], 5);
249 strprompt("Default room purge time (days)", &sc[17][0], 5);
251 /* Angels and demons dancing in my head... */
253 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
254 strprompt("System default message expire policy (? for list)",
258 "1. Never automatically expire messages\n"
259 "2. Expire by message count\n"
260 "3. Expire by message age\n");
262 } while ((buf[0] < '1') || (buf[0] > '3'));
263 site_expirepolicy->expire_mode = buf[0] - '0';
265 /* ...lunatics and monsters underneath my bed */
266 if (site_expirepolicy->expire_mode == 2) {
267 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
268 strprompt("Keep how many messages online?", buf, 10);
269 site_expirepolicy->expire_value = atol(buf);
271 if (site_expirepolicy->expire_mode == 3) {
272 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
273 strprompt("Keep messages for how many days?", buf, 10);
274 site_expirepolicy->expire_value = atol(buf);
277 /* Media messiahs preying on my fears... */
279 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
280 strprompt("Mailbox default message expire policy (? for list)",
284 "0. Go with the system default\n"
285 "1. Never automatically expire messages\n"
286 "2. Expire by message count\n"
287 "3. Expire by message age\n");
289 } while ((buf[0] < '0') || (buf[0] > '3'));
290 mbx_expirepolicy->expire_mode = buf[0] - '0';
292 /* ...Pop culture prophets playing in my ears */
293 if (mbx_expirepolicy->expire_mode == 2) {
294 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
295 strprompt("Keep how many messages online?", buf, 10);
296 mbx_expirepolicy->expire_value = atol(buf);
298 if (mbx_expirepolicy->expire_mode == 3) {
299 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
300 strprompt("Keep messages for how many days?", buf, 10);
301 mbx_expirepolicy->expire_value = atol(buf);
304 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
305 strprompt("Default frequency to run POP3 collection (in seconds)", &sc[64][0], 5);
306 strprompt("Fastest frequency to run POP3 collection (in seconds)", &sc[65][0], 5);
307 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
308 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
309 "Enable full text search index (warning: resource intensive)",
312 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
313 "Perform journaling of email messages",
315 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
316 "Perform journaling of non-email messages",
318 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
319 strprompt("Email destination of journalized messages",
323 /* Funambol push stuff */
324 int yes_funambol = 0;
325 if (strlen(sc[53]) > 0) yes_funambol = 1;
326 yes_funambol = boolprompt("Connect to an external Funambol sync server", yes_funambol);
328 strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
329 strprompt("Funambol server port", &sc[54][0], 5);
330 strprompt("Funambol sync source", &sc[55][0], 63);
331 strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
340 /* External pager stuff */
342 if (strlen(sc[60]) > 0) yes_pager = 1;
343 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
345 strprompt("External pager tool", &sc[60][0], 255);
351 /* Master user account */
353 if (strlen(sc[58]) > 0) yes_muacct = 1;
354 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
356 strprompt("Master user name", &sc[58][0], 31);
357 strprompt("Master user password", &sc[59][0], -31);
360 strcpy(&sc[58][0], "");
361 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
365 scr_printf("Save this configuration? ");
368 for (a = 0; a < NUM_CONFIGS; a++) {
369 r += 1 + strlen(sc[a]);
371 resp = (char *)calloc(1, r);
373 scr_printf("Can't save config - out of memory!\n");
376 for (a = 0; a < NUM_CONFIGS; a++) {
380 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
382 scr_printf("%s\n", buf);
386 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
388 scr_printf("%s\n", buf);
391 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
393 scr_printf("%s\n", buf);
397 if (site_expirepolicy) free(site_expirepolicy);
398 if (mbx_expirepolicy) free(mbx_expirepolicy);
403 * support function for do_internet_configuration()
405 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
408 keyopt(" <1> localhost (Alias for this computer)\n");
409 keyopt(" <2> smart host (Forward all outbound mail to this host)\n");
410 keyopt(" <3> fallback host (Send mail to this host only if direct delivery fails)\n");
411 keyopt(" <4> directory (Consult the Global Address Book)\n");
412 keyopt(" <5> SpamAssassin (Address of SpamAssassin server)\n");
413 keyopt(" <6> RBL (domain suffix of spam hunting RBL)\n");
414 keyopt(" <7> masq domains (Domains as which users are allowed to masquerade)\n");
415 keyopt(" <8> ClamAV (Address of ClamAV clamd server)\n");
416 sel = intprompt("Which one", 1, 1, 8);
418 case 1: strcpy(buf, "localhost");
420 case 2: strcpy(buf, "smarthost");
422 case 3: strcpy(buf, "fallbackhost");
424 case 4: strcpy(buf, "directory");
426 case 5: strcpy(buf, "spamassassin");
428 case 6: strcpy(buf, "rbl");
430 case 7: strcpy(buf, "masqdomain");
432 case 8: strcpy(buf, "clamav");
439 * Internet mail configuration
441 void do_internet_configuration(CtdlIPC *ipc)
453 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
455 while (!IsEmptyStr(resp)) {
456 extract_token(buf, resp, 0, '\n', sizeof buf);
457 remove_token(resp, 0, '\n');
459 if (num_recs == 1) recs = malloc(sizeof(char *));
460 else recs = realloc(recs, (sizeof(char *)) * num_recs);
461 recs[num_recs-1] = malloc(strlen(buf) + 1);
462 strcpy(recs[num_recs-1], buf);
465 if (resp) free(resp);
470 scr_printf("### Host or domain Record type \n");
472 scr_printf("--- -------------------------------------------------- --------------------\n");
473 for (i=0; i<num_recs; ++i) {
475 scr_printf("%3d ", i+1);
476 extract_token(buf, recs[i], 0, '|', sizeof buf);
478 scr_printf("%-50s ", buf);
479 extract_token(buf, recs[i], 1, '|', sizeof buf);
480 color(BRIGHT_MAGENTA);
481 scr_printf("%-20s\n", buf);
485 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
488 newprompt("Enter host name: ",
491 if (!IsEmptyStr(buf)) {
494 recs = malloc(sizeof(char *));
495 else recs = realloc(recs,
496 (sizeof(char *)) * num_recs);
498 get_inet_rec_type(ipc,
500 recs[num_recs-1] = strdup(buf);
505 i = intprompt("Delete which one",
509 for (j=i; j<num_recs; ++j)
515 for (i = 0; i < num_recs; i++)
516 r += 1 + strlen(recs[i]);
517 resp = (char *)calloc(1, r);
519 scr_printf("Can't save config - out of memory!\n");
522 if (num_recs) for (i = 0; i < num_recs; i++) {
523 strcat(resp, recs[i]);
526 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
528 scr_printf("%s\n", buf);
530 scr_printf("Wrote %d records.\n", num_recs);
536 quitting = !modified || boolprompt(
537 "Quit without saving", 0);
545 for (i=0; i<num_recs; ++i) free(recs[i]);
553 * Edit network configuration for room sharing, mailing lists, etc.
555 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
557 char filename[PATH_MAX];
558 char changefile[PATH_MAX];
568 char *listing = NULL;
571 if (IsEmptyStr(editor_path)) {
572 scr_printf("You must have an external editor configured in"
573 " order to use this function.\n");
577 CtdlMakeTempFileName(filename, sizeof filename);
578 CtdlMakeTempFileName(changefile, sizeof changefile);
580 tempfp = fopen(filename, "w");
581 if (tempfp == NULL) {
582 scr_printf("Cannot open %s: %s\n", filename, strerror(errno));
586 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
587 fprintf(tempfp, "# %s\n", comment);
588 fprintf(tempfp, "# Specify one per line.\n"
591 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
593 while(listing && !IsEmptyStr(listing)) {
594 extract_token(buf, listing, 0, '\n', sizeof buf);
595 remove_token(listing, 0, '\n');
596 extract_token(instr, buf, 0, '|', sizeof instr);
597 if (!strcasecmp(instr, entrytype)) {
598 tokens = num_tokens(buf, '|');
599 for (i=1; i<tokens; ++i) {
600 extract_token(addr, buf, i, '|', sizeof addr);
601 fprintf(tempfp, "%s", addr);
602 if (i < (tokens-1)) {
603 fprintf(tempfp, "|");
606 fprintf(tempfp, "\n");
616 e_ex_code = 1; /* start with a failed exit code */
617 stty_ctdl(SB_RESTORE);
619 cksum = file_checksum(filename);
620 if (editor_pid == 0) {
621 chmod(filename, 0600);
622 putenv("WINDOW_TITLE=Network configuration");
623 execlp(editor_path, editor_path, filename, NULL);
626 if (editor_pid > 0) {
629 b = ka_wait(&e_ex_code);
630 } while ((b != editor_pid) && (b >= 0));
635 if (file_checksum(filename) == cksum) {
636 scr_printf("*** No changes to save.\n");
640 if (e_ex_code == 0) { /* Save changes */
641 changefp = fopen(changefile, "w");
643 /* Load all netconfig entries that are *not* of the type we are editing */
644 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
646 while(listing && !IsEmptyStr(listing)) {
647 extract_token(buf, listing, 0, '\n', sizeof buf);
648 remove_token(listing, 0, '\n');
649 extract_token(instr, buf, 0, '|', sizeof instr);
650 if (strcasecmp(instr, entrytype)) {
651 fprintf(changefp, "%s\n", buf);
660 /* ...and merge that with the data we just edited */
661 tempfp = fopen(filename, "r");
662 while (fgets(buf, sizeof buf, tempfp) != NULL) {
663 for (i=0; i<strlen(buf); ++i) {
664 if (buf[i] == '#') buf[i] = 0;
667 if (!IsEmptyStr(buf)) {
668 fprintf(changefp, "%s|%s\n", entrytype, buf);
674 /* now write it to the server... */
675 changefp = fopen(changefile, "r");
676 if (changefp != NULL) {
677 listing = load_message_from_file(changefp);
679 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
687 unlink(filename); /* Delete the temporary files */
693 * IGnet node configuration
695 void do_ignet_configuration(CtdlIPC *ipc) {
703 char *listing = NULL;
706 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
707 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
708 extract_token(buf, listing, 0, '\n', sizeof buf);
709 remove_token(listing, 0, '\n');
712 if (num_recs == 1) recs = malloc(sizeof(char *));
713 else recs = realloc(recs, (sizeof(char *)) * num_recs);
714 recs[num_recs-1] = malloc(SIZ);
715 strcpy(recs[num_recs-1], buf);
717 if (listing) free(listing);
730 "------------------ "
731 "-------------------------------- "
733 for (i=0; i<num_recs; ++i) {
735 scr_printf("%3d ", i+1);
736 extract_token(buf, recs[i], 0, '|', sizeof buf);
738 scr_printf("%-16s ", buf);
739 extract_token(buf, recs[i], 1, '|', sizeof buf);
740 color(BRIGHT_MAGENTA);
741 scr_printf("%-18s ", buf);
742 extract_token(buf, recs[i], 2, '|', sizeof buf);
744 scr_printf("%-32s ", buf);
745 extract_token(buf, recs[i], 3, '|', sizeof buf);
746 color(BRIGHT_MAGENTA);
747 scr_printf("%-3s\n", buf);
752 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
757 recs = malloc(sizeof(char *));
758 else recs = realloc(recs,
759 (sizeof(char *)) * num_recs);
760 newprompt("Enter node name : ", buf, 16);
762 newprompt("Enter shared secret: ",
763 &buf[strlen(buf)], 18);
765 newprompt("Enter host or IP : ",
766 &buf[strlen(buf)], 32);
768 strprompt("Enter port number : ",
769 &buf[strlen(buf)-3], 5);
770 recs[num_recs-1] = strdup(buf);
774 i = intprompt("Delete which one",
778 for (j=i; j<num_recs; ++j)
784 for (i = 0; i < num_recs; ++i)
785 r += 1 + strlen(recs[i]);
786 listing = (char*) calloc(1, r);
788 scr_printf("Can't save config - out of memory!\n");
791 if (num_recs) for (i = 0; i < num_recs; ++i) {
792 strcat(listing, recs[i]);
793 strcat(listing, "\n");
795 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
797 scr_printf("%s\n", buf);
799 scr_printf("Wrote %d records.\n", num_recs);
805 quitting = !modified || boolprompt(
806 "Quit without saving", 0);
814 for (i=0; i<num_recs; ++i) free(recs[i]);
821 * Filter list configuration
823 void do_filterlist_configuration(CtdlIPC *ipc)
832 char *listing = NULL;
835 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
836 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
837 extract_token(buf, listing, 0, '\n', sizeof buf);
838 remove_token(listing, 0, '\n');
841 if (num_recs == 1) recs = malloc(sizeof(char *));
842 else recs = realloc(recs, (sizeof(char *)) * num_recs);
843 recs[num_recs-1] = malloc(SIZ);
844 strcpy(recs[num_recs-1], buf);
846 if (listing) free(listing);
858 "---------------------------- "
859 "---------------------------- "
862 for (i=0; i<num_recs; ++i) {
864 scr_printf("%3d ", i+1);
865 extract_token(buf, recs[i], 0, '|', sizeof buf);
867 scr_printf("%-28s ", buf);
868 extract_token(buf, recs[i], 1, '|', sizeof buf);
869 color(BRIGHT_MAGENTA);
870 scr_printf("%-28s ", buf);
871 extract_token(buf, recs[i], 2, '|', sizeof buf);
873 scr_printf("%-16s\n", buf);
874 extract_token(buf, recs[i], 3, '|', sizeof buf);
878 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
883 recs = malloc(sizeof(char *));
884 else recs = realloc(recs,
885 (sizeof(char *)) * num_recs);
886 newprompt("Enter user name: ", buf, 28);
888 newprompt("Enter room name: ",
889 &buf[strlen(buf)], 28);
891 newprompt("Enter node name: ",
892 &buf[strlen(buf)], 16);
894 recs[num_recs-1] = strdup(buf);
898 i = intprompt("Delete which one",
902 for (j=i; j<num_recs; ++j)
908 for (i = 0; i < num_recs; ++i)
909 r += 1 + strlen(recs[i]);
910 listing = (char*) calloc(1, r);
912 scr_printf("Can't save config - out of memory!\n");
915 if (num_recs) for (i = 0; i < num_recs; ++i) {
916 strcat(listing, recs[i]);
917 strcat(listing, "\n");
919 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
921 scr_printf("%s\n", buf);
923 scr_printf("Wrote %d records.\n", num_recs);
929 quitting = !modified || boolprompt(
930 "Quit without saving", 0);
938 for (i=0; i<num_recs; ++i) free(recs[i]);
947 * POP3 aggregation client configuration
949 void do_pop3client_configuration(CtdlIPC *ipc)
958 char *listing = NULL;
959 char *other_listing = NULL;
963 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
965 while(listing && !IsEmptyStr(listing)) {
966 extract_token(buf, listing, 0, '\n', sizeof buf);
967 remove_token(listing, 0, '\n');
968 extract_token(instr, buf, 0, '|', sizeof instr);
969 if (!strcasecmp(instr, "pop3client")) {
972 if (num_recs == 1) recs = malloc(sizeof(char *));
973 else recs = realloc(recs, (sizeof(char *)) * num_recs);
974 recs[num_recs-1] = malloc(SIZ);
975 strcpy(recs[num_recs-1], buf);
996 "---------------------------- "
997 "---------------------------- "
1001 for (i=0; i<num_recs; ++i) {
1003 scr_printf("%3d ", i+1);
1005 extract_token(buf, recs[i], 1, '|', sizeof buf);
1007 scr_printf("%-28s ", buf);
1009 extract_token(buf, recs[i], 2, '|', sizeof buf);
1010 color(BRIGHT_MAGENTA);
1011 scr_printf("%-28s ", buf);
1014 scr_printf("%-15s ", (extract_int(recs[i], 4) ? "Yes" : "No") );
1015 color(BRIGHT_MAGENTA);
1016 scr_printf("%ld\n", extract_long(recs[i], 5) );
1020 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1024 if (num_recs == 1) {
1025 recs = malloc(sizeof(char *));
1028 recs = realloc(recs, (sizeof(char *)) * num_recs);
1030 strcpy(buf, "pop3client|");
1031 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1033 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1035 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1037 scr_printf("Keep messages on server instead of deleting them? ");
1038 sprintf(&buf[strlen(buf)], "%d", yesno());
1040 newprompt("Enter interval : ", &buf[strlen(buf)], 5);
1042 recs[num_recs-1] = strdup(buf);
1046 i = intprompt("Delete which one",
1047 1, 1, num_recs) - 1;
1050 for (j=i; j<num_recs; ++j)
1051 recs[j] = recs[j+1];
1056 for (i = 0; i < num_recs; ++i) {
1057 r += 1 + strlen(recs[i]);
1059 listing = (char*) calloc(1, r);
1061 scr_printf("Can't save config - out of memory!\n");
1064 if (num_recs) for (i = 0; i < num_recs; ++i) {
1065 strcat(listing, recs[i]);
1066 strcat(listing, "\n");
1069 /* Retrieve all the *other* records for merging */
1070 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1072 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1073 extract_token(buf, other_listing, i, '\n', sizeof buf);
1074 if (strncasecmp(buf, "pop3client|", 11)) {
1075 listing = realloc(listing, strlen(listing) +
1077 strcat(listing, buf);
1078 strcat(listing, "\n");
1082 free(other_listing);
1083 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1088 scr_printf("%s\n", buf);
1090 scr_printf("Wrote %d records.\n", num_recs);
1096 quitting = !modified || boolprompt(
1097 "Quit without saving", 0);
1102 } while (!quitting);
1105 for (i=0; i<num_recs; ++i) free(recs[i]);
1116 * RSS feed retrieval client configuration
1118 void do_rssclient_configuration(CtdlIPC *ipc)
1127 char *listing = NULL;
1128 char *other_listing = NULL;
1132 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1134 while(listing && !IsEmptyStr(listing)) {
1135 extract_token(buf, listing, 0, '\n', sizeof buf);
1136 remove_token(listing, 0, '\n');
1137 extract_token(instr, buf, 0, '|', sizeof instr);
1138 if (!strcasecmp(instr, "rssclient")) {
1141 if (num_recs == 1) recs = malloc(sizeof(char *));
1142 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1143 recs[num_recs-1] = malloc(SIZ);
1144 strcpy(recs[num_recs-1], buf);
1156 color(BRIGHT_WHITE);
1157 scr_printf("### Feed URL\n");
1160 "---------------------------------------------------------------------------"
1163 for (i=0; i<num_recs; ++i) {
1165 scr_printf("%3d ", i+1);
1167 extract_token(buf, recs[i], 1, '|', sizeof buf);
1169 scr_printf("%-75s\n", buf);
1174 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1178 if (num_recs == 1) {
1179 recs = malloc(sizeof(char *));
1182 recs = realloc(recs, (sizeof(char *)) * num_recs);
1184 strcpy(buf, "rssclient|");
1185 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1187 recs[num_recs-1] = strdup(buf);
1191 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1194 for (j=i; j<num_recs; ++j)
1195 recs[j] = recs[j+1];
1200 for (i = 0; i < num_recs; ++i) {
1201 r += 1 + strlen(recs[i]);
1203 listing = (char*) calloc(1, r);
1205 scr_printf("Can't save config - out of memory!\n");
1208 if (num_recs) for (i = 0; i < num_recs; ++i) {
1209 strcat(listing, recs[i]);
1210 strcat(listing, "\n");
1213 /* Retrieve all the *other* records for merging */
1214 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1216 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1217 extract_token(buf, other_listing, i, '\n', sizeof buf);
1218 if (strncasecmp(buf, "rssclient|", 10)) {
1219 listing = realloc(listing, strlen(listing) +
1221 strcat(listing, buf);
1222 strcat(listing, "\n");
1226 free(other_listing);
1227 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1232 scr_printf("%s\n", buf);
1234 scr_printf("Wrote %d records.\n", num_recs);
1240 quitting = !modified || boolprompt(
1241 "Quit without saving", 0);
1246 } while (!quitting);
1249 for (i=0; i<num_recs; ++i) free(recs[i]);