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>
42 ///#include "citadel.h"
43 #include "citadel_ipc.h"
44 #include "citadel_decls.h"
45 #include "tuiconfig.h"
49 ///#ifndef HAVE_SNPRINTF
50 ///#include "snprintf.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 admin 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 admins 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",
226 if (ipc->ServInfo.supports_ldap) {
227 a = strlen(&sc[32][0]);
228 a = (a ? 1 : 0); /* Set only to 1 or 0 */
229 a = boolprompt("Do you want to configure LDAP authentication?", a);
231 strprompt("Host name of LDAP server",
233 strprompt("Port number of LDAP service",
235 strprompt("Base DN", &sc[34][0], 255);
236 strprompt("Bind DN (or blank for anonymous bind)", &sc[35][0], 255);
237 strprompt("Password for bind DN (or blank for anonymous bind)", &sc[36][0], 255);
240 strcpy(&sc[32][0], "");
244 /* Expiry settings */
245 strprompt("Default user purge time (days)", &sc[16][0], 5);
246 strprompt("Default room purge time (days)", &sc[17][0], 5);
248 /* Angels and demons dancing in my head... */
250 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
251 strprompt("System default message expire policy (? for list)",
255 "1. Never automatically expire messages\n"
256 "2. Expire by message count\n"
257 "3. Expire by message age\n");
259 } while ((buf[0] < '1') || (buf[0] > '3'));
260 site_expirepolicy->expire_mode = buf[0] - '0';
262 /* ...lunatics and monsters underneath my bed */
263 if (site_expirepolicy->expire_mode == 2) {
264 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
265 strprompt("Keep how many messages online?", buf, 10);
266 site_expirepolicy->expire_value = atol(buf);
268 if (site_expirepolicy->expire_mode == 3) {
269 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
270 strprompt("Keep messages for how many days?", buf, 10);
271 site_expirepolicy->expire_value = atol(buf);
274 /* Media messiahs preying on my fears... */
276 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
277 strprompt("Mailbox default message expire policy (? for list)",
281 "0. Go with the system default\n"
282 "1. Never automatically expire messages\n"
283 "2. Expire by message count\n"
284 "3. Expire by message age\n");
286 } while ((buf[0] < '0') || (buf[0] > '3'));
287 mbx_expirepolicy->expire_mode = buf[0] - '0';
289 /* ...Pop culture prophets playing in my ears */
290 if (mbx_expirepolicy->expire_mode == 2) {
291 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
292 strprompt("Keep how many messages online?", buf, 10);
293 mbx_expirepolicy->expire_value = atol(buf);
295 if (mbx_expirepolicy->expire_mode == 3) {
296 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
297 strprompt("Keep messages for how many days?", buf, 10);
298 mbx_expirepolicy->expire_value = atol(buf);
301 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
302 strprompt("Default frequency to run POP3 collection (in seconds)", &sc[64][0], 5);
303 strprompt("Fastest frequency to run POP3 collection (in seconds)", &sc[65][0], 5);
304 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
305 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
306 "Enable full text search index (warning: resource intensive)",
309 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
310 "Perform journaling of email messages",
312 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
313 "Perform journaling of non-email messages",
315 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
316 strprompt("Email destination of journalized messages",
320 /* Funambol push stuff */
321 int yes_funambol = 0;
322 if (strlen(sc[53]) > 0) yes_funambol = 1;
323 yes_funambol = boolprompt("Connect to an external Funambol sync server", yes_funambol);
325 strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
326 strprompt("Funambol server port", &sc[54][0], 5);
327 strprompt("Funambol sync source", &sc[55][0], 63);
328 strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
337 /* External pager stuff */
339 if (strlen(sc[60]) > 0) yes_pager = 1;
340 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
342 strprompt("External pager tool", &sc[60][0], 255);
348 /* Master user account */
350 if (strlen(sc[58]) > 0) yes_muacct = 1;
351 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
353 strprompt("Master user name", &sc[58][0], 31);
354 strprompt("Master user password", &sc[59][0], -31);
357 strcpy(&sc[58][0], "");
358 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
362 scr_printf("Save this configuration? ");
365 for (a = 0; a < NUM_CONFIGS; a++) {
366 r += 1 + strlen(sc[a]);
368 resp = (char *)calloc(1, r);
370 scr_printf("Can't save config - out of memory!\n");
373 for (a = 0; a < NUM_CONFIGS; a++) {
377 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
379 scr_printf("%s\n", buf);
383 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
385 scr_printf("%s\n", buf);
388 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
390 scr_printf("%s\n", buf);
394 if (site_expirepolicy) free(site_expirepolicy);
395 if (mbx_expirepolicy) free(mbx_expirepolicy);
400 * support function for do_internet_configuration()
402 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
405 keyopt(" <1> localhost (Alias for this computer)\n");
406 keyopt(" <2> smart host (Forward all outbound mail to this host)\n");
407 keyopt(" <3> fallback host (Send mail to this host only if direct delivery fails)\n");
408 keyopt(" <4> directory (Consult the Global Address Book)\n");
409 keyopt(" <5> SpamAssassin (Address of SpamAssassin server)\n");
410 keyopt(" <6> RBL (domain suffix of spam hunting RBL)\n");
411 keyopt(" <7> masq domains (Domains as which users are allowed to masquerade)\n");
412 keyopt(" <8> ClamAV (Address of ClamAV clamd server)\n");
413 sel = intprompt("Which one", 1, 1, 8);
415 case 1: strcpy(buf, "localhost");
417 case 2: strcpy(buf, "smarthost");
419 case 3: strcpy(buf, "fallbackhost");
421 case 4: strcpy(buf, "directory");
423 case 5: strcpy(buf, "spamassassin");
425 case 6: strcpy(buf, "rbl");
427 case 7: strcpy(buf, "masqdomain");
429 case 8: strcpy(buf, "clamav");
436 * Internet mail configuration
438 void do_internet_configuration(CtdlIPC *ipc)
450 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
452 while (!IsEmptyStr(resp)) {
453 extract_token(buf, resp, 0, '\n', sizeof buf);
454 remove_token(resp, 0, '\n');
456 if (num_recs == 1) recs = malloc(sizeof(char *));
457 else recs = realloc(recs, (sizeof(char *)) * num_recs);
458 recs[num_recs-1] = malloc(strlen(buf) + 1);
459 strcpy(recs[num_recs-1], buf);
462 if (resp) free(resp);
467 scr_printf("### Host or domain Record type \n");
469 scr_printf("--- -------------------------------------------------- --------------------\n");
470 for (i=0; i<num_recs; ++i) {
472 scr_printf("%3d ", i+1);
473 extract_token(buf, recs[i], 0, '|', sizeof buf);
475 scr_printf("%-50s ", buf);
476 extract_token(buf, recs[i], 1, '|', sizeof buf);
477 color(BRIGHT_MAGENTA);
478 scr_printf("%-20s\n", buf);
482 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
485 newprompt("Enter host name: ",
488 if (!IsEmptyStr(buf)) {
491 recs = malloc(sizeof(char *));
492 else recs = realloc(recs,
493 (sizeof(char *)) * num_recs);
495 get_inet_rec_type(ipc,
497 recs[num_recs-1] = strdup(buf);
502 i = intprompt("Delete which one",
506 for (j=i; j<num_recs; ++j)
512 for (i = 0; i < num_recs; i++)
513 r += 1 + strlen(recs[i]);
514 resp = (char *)calloc(1, r);
516 scr_printf("Can't save config - out of memory!\n");
519 if (num_recs) for (i = 0; i < num_recs; i++) {
520 strcat(resp, recs[i]);
523 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
525 scr_printf("%s\n", buf);
527 scr_printf("Wrote %d records.\n", num_recs);
533 quitting = !modified || boolprompt(
534 "Quit without saving", 0);
542 for (i=0; i<num_recs; ++i) free(recs[i]);
550 * Edit network configuration for room sharing, mailing lists, etc.
552 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
554 char filename[PATH_MAX];
555 char changefile[PATH_MAX];
565 char *listing = NULL;
568 if (IsEmptyStr(editor_path)) {
569 scr_printf("You must have an external editor configured in"
570 " order to use this function.\n");
574 CtdlMakeTempFileName(filename, sizeof filename);
575 CtdlMakeTempFileName(changefile, sizeof changefile);
577 tempfp = fopen(filename, "w");
578 if (tempfp == NULL) {
579 scr_printf("Cannot open %s: %s\n", filename, strerror(errno));
583 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
584 fprintf(tempfp, "# %s\n", comment);
585 fprintf(tempfp, "# Specify one per line.\n"
588 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
590 while(listing && !IsEmptyStr(listing)) {
591 extract_token(buf, listing, 0, '\n', sizeof buf);
592 remove_token(listing, 0, '\n');
593 extract_token(instr, buf, 0, '|', sizeof instr);
594 if (!strcasecmp(instr, entrytype)) {
595 tokens = num_tokens(buf, '|');
596 for (i=1; i<tokens; ++i) {
597 extract_token(addr, buf, i, '|', sizeof addr);
598 fprintf(tempfp, "%s", addr);
599 if (i < (tokens-1)) {
600 fprintf(tempfp, "|");
603 fprintf(tempfp, "\n");
613 e_ex_code = 1; /* start with a failed exit code */
614 stty_ctdl(SB_RESTORE);
616 cksum = file_checksum(filename);
617 if (editor_pid == 0) {
618 chmod(filename, 0600);
619 putenv("WINDOW_TITLE=Network configuration");
620 execlp(editor_path, editor_path, filename, NULL);
623 if (editor_pid > 0) {
626 b = ka_wait(&e_ex_code);
627 } while ((b != editor_pid) && (b >= 0));
632 if (file_checksum(filename) == cksum) {
633 scr_printf("*** No changes to save.\n");
637 if (e_ex_code == 0) { /* Save changes */
638 changefp = fopen(changefile, "w");
640 /* Load all netconfig entries that are *not* of the type we are editing */
641 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
643 while(listing && !IsEmptyStr(listing)) {
644 extract_token(buf, listing, 0, '\n', sizeof buf);
645 remove_token(listing, 0, '\n');
646 extract_token(instr, buf, 0, '|', sizeof instr);
647 if (strcasecmp(instr, entrytype)) {
648 fprintf(changefp, "%s\n", buf);
657 /* ...and merge that with the data we just edited */
658 tempfp = fopen(filename, "r");
659 while (fgets(buf, sizeof buf, tempfp) != NULL) {
660 for (i=0; i<strlen(buf); ++i) {
661 if (buf[i] == '#') buf[i] = 0;
664 if (!IsEmptyStr(buf)) {
665 fprintf(changefp, "%s|%s\n", entrytype, buf);
671 /* now write it to the server... */
672 changefp = fopen(changefile, "r");
673 if (changefp != NULL) {
674 listing = load_message_from_file(changefp);
676 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
684 unlink(filename); /* Delete the temporary files */
690 * IGnet node configuration
692 void do_ignet_configuration(CtdlIPC *ipc) {
700 char *listing = NULL;
703 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
704 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
705 extract_token(buf, listing, 0, '\n', sizeof buf);
706 remove_token(listing, 0, '\n');
709 if (num_recs == 1) recs = malloc(sizeof(char *));
710 else recs = realloc(recs, (sizeof(char *)) * num_recs);
711 recs[num_recs-1] = malloc(SIZ);
712 strcpy(recs[num_recs-1], buf);
714 if (listing) free(listing);
727 "------------------ "
728 "-------------------------------- "
730 for (i=0; i<num_recs; ++i) {
732 scr_printf("%3d ", i+1);
733 extract_token(buf, recs[i], 0, '|', sizeof buf);
735 scr_printf("%-16s ", buf);
736 extract_token(buf, recs[i], 1, '|', sizeof buf);
737 color(BRIGHT_MAGENTA);
738 scr_printf("%-18s ", buf);
739 extract_token(buf, recs[i], 2, '|', sizeof buf);
741 scr_printf("%-32s ", buf);
742 extract_token(buf, recs[i], 3, '|', sizeof buf);
743 color(BRIGHT_MAGENTA);
744 scr_printf("%-3s\n", buf);
749 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
754 recs = malloc(sizeof(char *));
755 else recs = realloc(recs,
756 (sizeof(char *)) * num_recs);
757 newprompt("Enter node name : ", buf, 16);
759 newprompt("Enter shared secret: ",
760 &buf[strlen(buf)], 18);
762 newprompt("Enter host or IP : ",
763 &buf[strlen(buf)], 32);
765 strprompt("Enter port number : ",
766 &buf[strlen(buf)-3], 5);
767 recs[num_recs-1] = strdup(buf);
771 i = intprompt("Delete which one",
775 for (j=i; j<num_recs; ++j)
781 for (i = 0; i < num_recs; ++i)
782 r += 1 + strlen(recs[i]);
783 listing = (char*) calloc(1, r);
785 scr_printf("Can't save config - out of memory!\n");
788 if (num_recs) for (i = 0; i < num_recs; ++i) {
789 strcat(listing, recs[i]);
790 strcat(listing, "\n");
792 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
794 scr_printf("%s\n", buf);
796 scr_printf("Wrote %d records.\n", num_recs);
802 quitting = !modified || boolprompt(
803 "Quit without saving", 0);
811 for (i=0; i<num_recs; ++i) free(recs[i]);
818 * Filter list configuration
820 void do_filterlist_configuration(CtdlIPC *ipc)
829 char *listing = NULL;
832 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
833 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
834 extract_token(buf, listing, 0, '\n', sizeof buf);
835 remove_token(listing, 0, '\n');
838 if (num_recs == 1) recs = malloc(sizeof(char *));
839 else recs = realloc(recs, (sizeof(char *)) * num_recs);
840 recs[num_recs-1] = malloc(SIZ);
841 strcpy(recs[num_recs-1], buf);
843 if (listing) free(listing);
855 "---------------------------- "
856 "---------------------------- "
859 for (i=0; i<num_recs; ++i) {
861 scr_printf("%3d ", i+1);
862 extract_token(buf, recs[i], 0, '|', sizeof buf);
864 scr_printf("%-28s ", buf);
865 extract_token(buf, recs[i], 1, '|', sizeof buf);
866 color(BRIGHT_MAGENTA);
867 scr_printf("%-28s ", buf);
868 extract_token(buf, recs[i], 2, '|', sizeof buf);
870 scr_printf("%-16s\n", buf);
871 extract_token(buf, recs[i], 3, '|', sizeof buf);
875 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
880 recs = malloc(sizeof(char *));
881 else recs = realloc(recs,
882 (sizeof(char *)) * num_recs);
883 newprompt("Enter user name: ", buf, 28);
885 newprompt("Enter room name: ",
886 &buf[strlen(buf)], 28);
888 newprompt("Enter node name: ",
889 &buf[strlen(buf)], 16);
891 recs[num_recs-1] = strdup(buf);
895 i = intprompt("Delete which one",
899 for (j=i; j<num_recs; ++j)
905 for (i = 0; i < num_recs; ++i)
906 r += 1 + strlen(recs[i]);
907 listing = (char*) calloc(1, r);
909 scr_printf("Can't save config - out of memory!\n");
912 if (num_recs) for (i = 0; i < num_recs; ++i) {
913 strcat(listing, recs[i]);
914 strcat(listing, "\n");
916 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
918 scr_printf("%s\n", buf);
920 scr_printf("Wrote %d records.\n", num_recs);
926 quitting = !modified || boolprompt(
927 "Quit without saving", 0);
935 for (i=0; i<num_recs; ++i) free(recs[i]);
944 * POP3 aggregation client configuration
946 void do_pop3client_configuration(CtdlIPC *ipc)
955 char *listing = NULL;
956 char *other_listing = NULL;
960 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
962 while(listing && !IsEmptyStr(listing)) {
963 extract_token(buf, listing, 0, '\n', sizeof buf);
964 remove_token(listing, 0, '\n');
965 extract_token(instr, buf, 0, '|', sizeof instr);
966 if (!strcasecmp(instr, "pop3client")) {
969 if (num_recs == 1) recs = malloc(sizeof(char *));
970 else recs = realloc(recs, (sizeof(char *)) * num_recs);
971 recs[num_recs-1] = malloc(SIZ);
972 strcpy(recs[num_recs-1], buf);
993 "---------------------------- "
994 "---------------------------- "
998 for (i=0; i<num_recs; ++i) {
1000 scr_printf("%3d ", i+1);
1002 extract_token(buf, recs[i], 1, '|', sizeof buf);
1004 scr_printf("%-28s ", buf);
1006 extract_token(buf, recs[i], 2, '|', sizeof buf);
1007 color(BRIGHT_MAGENTA);
1008 scr_printf("%-28s ", buf);
1011 scr_printf("%-15s ", (extract_int(recs[i], 4) ? "Yes" : "No") );
1012 color(BRIGHT_MAGENTA);
1013 scr_printf("%ld\n", extract_long(recs[i], 5) );
1017 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1021 if (num_recs == 1) {
1022 recs = malloc(sizeof(char *));
1025 recs = realloc(recs, (sizeof(char *)) * num_recs);
1027 strcpy(buf, "pop3client|");
1028 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1030 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1032 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1034 scr_printf("Keep messages on server instead of deleting them? ");
1035 sprintf(&buf[strlen(buf)], "%d", yesno());
1037 newprompt("Enter interval : ", &buf[strlen(buf)], 5);
1039 recs[num_recs-1] = strdup(buf);
1043 i = intprompt("Delete which one",
1044 1, 1, num_recs) - 1;
1047 for (j=i; j<num_recs; ++j)
1048 recs[j] = recs[j+1];
1053 for (i = 0; i < num_recs; ++i) {
1054 r += 1 + strlen(recs[i]);
1056 listing = (char*) calloc(1, r);
1058 scr_printf("Can't save config - out of memory!\n");
1061 if (num_recs) for (i = 0; i < num_recs; ++i) {
1062 strcat(listing, recs[i]);
1063 strcat(listing, "\n");
1066 /* Retrieve all the *other* records for merging */
1067 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1069 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1070 extract_token(buf, other_listing, i, '\n', sizeof buf);
1071 if (strncasecmp(buf, "pop3client|", 11)) {
1072 listing = realloc(listing, strlen(listing) +
1074 strcat(listing, buf);
1075 strcat(listing, "\n");
1079 free(other_listing);
1080 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1085 scr_printf("%s\n", buf);
1087 scr_printf("Wrote %d records.\n", num_recs);
1093 quitting = !modified || boolprompt(
1094 "Quit without saving", 0);
1099 } while (!quitting);
1102 for (i=0; i<num_recs; ++i) free(recs[i]);
1113 * RSS feed retrieval client configuration
1115 void do_rssclient_configuration(CtdlIPC *ipc)
1124 char *listing = NULL;
1125 char *other_listing = NULL;
1129 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1131 while(listing && !IsEmptyStr(listing)) {
1132 extract_token(buf, listing, 0, '\n', sizeof buf);
1133 remove_token(listing, 0, '\n');
1134 extract_token(instr, buf, 0, '|', sizeof instr);
1135 if (!strcasecmp(instr, "rssclient")) {
1138 if (num_recs == 1) recs = malloc(sizeof(char *));
1139 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1140 recs[num_recs-1] = malloc(SIZ);
1141 strcpy(recs[num_recs-1], buf);
1153 color(BRIGHT_WHITE);
1154 scr_printf("### Feed URL\n");
1157 "---------------------------------------------------------------------------"
1160 for (i=0; i<num_recs; ++i) {
1162 scr_printf("%3d ", i+1);
1164 extract_token(buf, recs[i], 1, '|', sizeof buf);
1166 scr_printf("%-75s\n", buf);
1171 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1175 if (num_recs == 1) {
1176 recs = malloc(sizeof(char *));
1179 recs = realloc(recs, (sizeof(char *)) * num_recs);
1181 strcpy(buf, "rssclient|");
1182 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1184 recs[num_recs-1] = strdup(buf);
1188 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1191 for (j=i; j<num_recs; ++j)
1192 recs[j] = recs[j+1];
1197 for (i = 0; i < num_recs; ++i) {
1198 r += 1 + strlen(recs[i]);
1200 listing = (char*) calloc(1, r);
1202 scr_printf("Can't save config - out of memory!\n");
1205 if (num_recs) for (i = 0; i < num_recs; ++i) {
1206 strcat(listing, recs[i]);
1207 strcat(listing, "\n");
1210 /* Retrieve all the *other* records for merging */
1211 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1213 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1214 extract_token(buf, other_listing, i, '\n', sizeof buf);
1215 if (strncasecmp(buf, "rssclient|", 10)) {
1216 listing = realloc(listing, strlen(listing) +
1218 strcat(listing, buf);
1219 strcat(listing, "\n");
1223 free(other_listing);
1224 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1229 scr_printf("%s\n", buf);
1231 scr_printf("Wrote %d records.\n", num_recs);
1237 quitting = !modified || boolprompt(
1238 "Quit without saving", 0);
1243 } while (!quitting);
1246 for (i=0; i<num_recs; ++i) free(recs[i]);