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;
69 * General system configuration command
71 void do_system_configuration(CtdlIPC *ipc)
74 /* NUM_CONFIGS is now defined in citadel.h */
77 char sc[NUM_CONFIGS][256];
79 struct ExpirePolicy *site_expirepolicy = NULL;
80 struct ExpirePolicy *mbx_expirepolicy = NULL;
83 int r; /* IPC response code */
84 int server_configs = 0;
86 /* Clear out the config buffers */
87 memset(&sc[0][0], 0, sizeof(sc));
89 /* Fetch the current config */
90 r = CtdlIPCGetSystemConfig(ipc, &resp, buf);
92 server_configs = num_tokens(resp, '\n');
93 for (a=0; a<server_configs; ++a) {
94 if (a < NUM_CONFIGS) {
95 extract_token(&sc[a][0], resp, a, '\n', sizeof sc[a]);
101 /* Fetch the expire policy (this will silently fail on old servers,
102 * resulting in "default" policy)
104 r = CtdlIPCGetMessageExpirationPolicy(ipc, 2, &site_expirepolicy, buf);
105 r = CtdlIPCGetMessageExpirationPolicy(ipc, 3, &mbx_expirepolicy, buf);
107 /* Identification parameters */
109 strprompt("Node name", &sc[0][0], 15);
110 strprompt("Fully qualified domain name", &sc[1][0], 63);
111 strprompt("Human readable node name", &sc[2][0], 20);
112 strprompt("Telephone number", &sc[3][0], 15);
113 strprompt("Geographic location of this system", &sc[12][0], 31);
114 strprompt("Name of system administrator", &sc[13][0], 25);
115 strprompt("Paginator prompt", &sc[10][0], 79);
117 /* Security parameters */
119 snprintf(sc[7], sizeof sc[7], "%d", (boolprompt(
120 "Require registration for new users",
122 snprintf(sc[29], sizeof sc[29], "%d", (boolprompt(
123 "Disable self-service user account creation",
125 strprompt("Initial access level for new users", &sc[6][0], 1);
126 strprompt("Access level required to create rooms", &sc[19][0], 1);
127 snprintf(sc[67], sizeof sc[67], "%d", (boolprompt(
128 "Allow anonymous guest logins",
130 snprintf(sc[4], sizeof sc[4], "%d", (boolprompt(
131 "Automatically give room aide privs to a user who creates a private room",
134 snprintf(sc[8], sizeof sc[8], "%d", (boolprompt(
135 "Automatically move problem user messages to twit room",
138 strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
139 snprintf(sc[11], sizeof sc[11], "%d", (boolprompt(
140 "Restrict Internet mail to only those with that privilege",
142 snprintf(sc[26], sizeof sc[26], "%d", (boolprompt(
143 "Allow Aides to Zap (forget) rooms",
146 if (!IsEmptyStr(&sc[18][0])) {
152 logpages = boolprompt("Log all instant messages", logpages);
154 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
160 /* Commented out because this setting isn't really appropriate to
161 * change while the server is running.
163 * snprintf(sc[52], sizeof sc[52], "%d", (boolprompt(
164 * "Use system authentication",
165 * atoi(&sc[52][0]))));
170 strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
171 strprompt("Maximum concurrent sessions", &sc[14][0], 4);
172 strprompt("Maximum message length", &sc[20][0], 20);
173 strprompt("Minimum number of worker threads", &sc[21][0], 3);
174 strprompt("Maximum number of worker threads", &sc[22][0], 3);
175 snprintf(sc[43], sizeof sc[43], "%d", (boolprompt(
176 "Automatically delete committed database logs",
179 strprompt("Server IP address (* for 'any')", &sc[37][0], 15);
180 strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
181 strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5);
182 strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
183 strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5);
184 strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5);
185 strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5);
186 strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5);
187 strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5);
188 strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5);
190 strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5);
191 /* No prompt because we don't implement this service yet, it's just a placeholder */
192 /* strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); */
194 /* This logic flips the question around, because it's one of those
195 * situations where 0=yes and 1=no
199 a = boolprompt("Correct forged From: lines during authenticated SMTP",
202 snprintf(sc[25], sizeof sc[25], "%d", a);
204 snprintf(sc[66], sizeof sc[66], "%d", (boolprompt(
205 "Flag messages as spam instead of rejecting",
208 /* This logic flips the question around, because it's one of those
209 * situations where 0=yes and 1=no
213 a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a);
215 snprintf(sc[61], sizeof sc[61], "%d", a);
217 snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
218 "Allow unauthenticated SMTP clients to spoof my domains",
220 snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
221 "Perform RBL checks at greeting instead of after RCPT",
223 snprintf(sc[44], sizeof sc[44], "%d", (boolprompt(
224 "Instantly expunge deleted IMAP messages",
228 if (ipc->ServInfo.supports_ldap) {
229 a = strlen(&sc[32][0]);
230 a = (a ? 1 : 0); /* Set only to 1 or 0 */
231 a = boolprompt("Do you want to configure LDAP authentication?", a);
233 strprompt("Host name of LDAP server",
235 strprompt("Port number of LDAP service",
237 strprompt("Base DN", &sc[34][0], 255);
238 strprompt("Bind DN (or blank for anonymous bind)", &sc[35][0], 255);
239 strprompt("Password for bind DN (or blank for anonymous bind)", &sc[36][0], 255);
242 strcpy(&sc[32][0], "");
246 /* Expiry settings */
247 strprompt("Default user purge time (days)", &sc[16][0], 5);
248 strprompt("Default room purge time (days)", &sc[17][0], 5);
250 /* Angels and demons dancing in my head... */
252 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
253 strprompt("System default message expire policy (? for list)",
257 "1. Never automatically expire messages\n"
258 "2. Expire by message count\n"
259 "3. Expire by message age\n");
261 } while ((buf[0] < '1') || (buf[0] > '3'));
262 site_expirepolicy->expire_mode = buf[0] - '0';
264 /* ...lunatics and monsters underneath my bed */
265 if (site_expirepolicy->expire_mode == 2) {
266 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
267 strprompt("Keep how many messages online?", buf, 10);
268 site_expirepolicy->expire_value = atol(buf);
270 if (site_expirepolicy->expire_mode == 3) {
271 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
272 strprompt("Keep messages for how many days?", buf, 10);
273 site_expirepolicy->expire_value = atol(buf);
276 /* Media messiahs preying on my fears... */
278 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
279 strprompt("Mailbox default message expire policy (? for list)",
283 "0. Go with the system default\n"
284 "1. Never automatically expire messages\n"
285 "2. Expire by message count\n"
286 "3. Expire by message age\n");
288 } while ((buf[0] < '0') || (buf[0] > '3'));
289 mbx_expirepolicy->expire_mode = buf[0] - '0';
291 /* ...Pop culture prophets playing in my ears */
292 if (mbx_expirepolicy->expire_mode == 2) {
293 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
294 strprompt("Keep how many messages online?", buf, 10);
295 mbx_expirepolicy->expire_value = atol(buf);
297 if (mbx_expirepolicy->expire_mode == 3) {
298 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
299 strprompt("Keep messages for how many days?", buf, 10);
300 mbx_expirepolicy->expire_value = atol(buf);
303 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
304 strprompt("Default frequency to run POP3 collection (in seconds)", &sc[64][0], 5);
305 strprompt("Fastest frequency to run POP3 collection (in seconds)", &sc[65][0], 5);
306 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
307 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
308 "Enable full text search index (warning: resource intensive)",
311 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
312 "Perform journaling of email messages",
314 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
315 "Perform journaling of non-email messages",
317 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
318 strprompt("Email destination of journalized messages",
322 /* Funambol push stuff */
323 int yes_funambol = 0;
324 if (strlen(sc[53]) > 0) yes_funambol = 1;
325 yes_funambol = boolprompt("Connect to an external Funambol sync server", yes_funambol);
327 strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
328 strprompt("Funambol server port", &sc[54][0], 5);
329 strprompt("Funambol sync source", &sc[55][0], 63);
330 strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
339 /* External pager stuff */
341 if (strlen(sc[60]) > 0) yes_pager = 1;
342 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
344 strprompt("External pager tool", &sc[60][0], 255);
350 /* Master user account */
352 if (strlen(sc[58]) > 0) yes_muacct = 1;
353 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
355 strprompt("Master user name", &sc[58][0], 31);
356 strprompt("Master user password", &sc[59][0], -31);
359 strcpy(&sc[58][0], "");
360 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
364 scr_printf("Save this configuration? ");
367 for (a = 0; a < NUM_CONFIGS; a++) {
368 r += 1 + strlen(sc[a]);
370 resp = (char *)calloc(1, r);
372 scr_printf("Can't save config - out of memory!\n");
375 for (a = 0; a < NUM_CONFIGS; a++) {
379 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
381 scr_printf("%s\n", buf);
385 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
387 scr_printf("%s\n", buf);
390 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
392 scr_printf("%s\n", buf);
396 if (site_expirepolicy) free(site_expirepolicy);
397 if (mbx_expirepolicy) free(mbx_expirepolicy);
402 * support function for do_internet_configuration()
404 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
407 keyopt(" <1> localhost (Alias for this computer)\n");
408 keyopt(" <2> smart host (Forward all outbound mail to this host)\n");
409 keyopt(" <3> fallback host (Send mail to this host only if direct delivery fails)\n");
410 keyopt(" <4> directory (Consult the Global Address Book)\n");
411 keyopt(" <5> SpamAssassin (Address of SpamAssassin server)\n");
412 keyopt(" <6> RBL (domain suffix of spam hunting RBL)\n");
413 keyopt(" <7> masq domains (Domains as which users are allowed to masquerade)\n");
414 keyopt(" <8> ClamAV (Address of ClamAV clamd server)\n");
415 sel = intprompt("Which one", 1, 1, 8);
417 case 1: strcpy(buf, "localhost");
419 case 2: strcpy(buf, "smarthost");
421 case 3: strcpy(buf, "fallbackhost");
423 case 4: strcpy(buf, "directory");
425 case 5: strcpy(buf, "spamassassin");
427 case 6: strcpy(buf, "rbl");
429 case 7: strcpy(buf, "masqdomain");
431 case 8: strcpy(buf, "clamav");
438 * Internet mail configuration
440 void do_internet_configuration(CtdlIPC *ipc)
452 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
454 while (!IsEmptyStr(resp)) {
455 extract_token(buf, resp, 0, '\n', sizeof buf);
456 remove_token(resp, 0, '\n');
458 if (num_recs == 1) recs = malloc(sizeof(char *));
459 else recs = realloc(recs, (sizeof(char *)) * num_recs);
460 recs[num_recs-1] = malloc(strlen(buf) + 1);
461 strcpy(recs[num_recs-1], buf);
464 if (resp) free(resp);
469 scr_printf("### Host or domain Record type \n");
471 scr_printf("--- -------------------------------------------------- --------------------\n");
472 for (i=0; i<num_recs; ++i) {
474 scr_printf("%3d ", i+1);
475 extract_token(buf, recs[i], 0, '|', sizeof buf);
477 scr_printf("%-50s ", buf);
478 extract_token(buf, recs[i], 1, '|', sizeof buf);
479 color(BRIGHT_MAGENTA);
480 scr_printf("%-20s\n", buf);
484 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
487 newprompt("Enter host name: ",
490 if (!IsEmptyStr(buf)) {
493 recs = malloc(sizeof(char *));
494 else recs = realloc(recs,
495 (sizeof(char *)) * num_recs);
497 get_inet_rec_type(ipc,
499 recs[num_recs-1] = strdup(buf);
504 i = intprompt("Delete which one",
508 for (j=i; j<num_recs; ++j)
514 for (i = 0; i < num_recs; i++)
515 r += 1 + strlen(recs[i]);
516 resp = (char *)calloc(1, r);
518 scr_printf("Can't save config - out of memory!\n");
521 if (num_recs) for (i = 0; i < num_recs; i++) {
522 strcat(resp, recs[i]);
525 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
527 scr_printf("%s\n", buf);
529 scr_printf("Wrote %d records.\n", num_recs);
535 quitting = !modified || boolprompt(
536 "Quit without saving", 0);
544 for (i=0; i<num_recs; ++i) free(recs[i]);
552 * Edit network configuration for room sharing, mailing lists, etc.
554 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
556 char filename[PATH_MAX];
557 char changefile[PATH_MAX];
567 char *listing = NULL;
570 if (IsEmptyStr(editor_paths[0])) {
571 scr_printf("You must have an external editor configured in"
572 " order to use this function.\n");
576 CtdlMakeTempFileName(filename, sizeof filename);
577 CtdlMakeTempFileName(changefile, sizeof changefile);
579 tempfp = fopen(filename, "w");
580 if (tempfp == NULL) {
581 scr_printf("Cannot open %s: %s\n", filename, strerror(errno));
585 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
586 fprintf(tempfp, "# %s\n", comment);
587 fprintf(tempfp, "# Specify one per line.\n"
590 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
592 while(listing && !IsEmptyStr(listing)) {
593 extract_token(buf, listing, 0, '\n', sizeof buf);
594 remove_token(listing, 0, '\n');
595 extract_token(instr, buf, 0, '|', sizeof instr);
596 if (!strcasecmp(instr, entrytype)) {
597 tokens = num_tokens(buf, '|');
598 for (i=1; i<tokens; ++i) {
599 extract_token(addr, buf, i, '|', sizeof addr);
600 fprintf(tempfp, "%s", addr);
601 if (i < (tokens-1)) {
602 fprintf(tempfp, "|");
605 fprintf(tempfp, "\n");
615 e_ex_code = 1; /* start with a failed exit code */
616 stty_ctdl(SB_RESTORE);
618 cksum = file_checksum(filename);
619 if (editor_pid == 0) {
620 chmod(filename, 0600);
621 putenv("WINDOW_TITLE=Network configuration");
622 execlp(editor_paths[0], editor_paths[0], filename, NULL);
625 if (editor_pid > 0) {
628 b = ka_wait(&e_ex_code);
629 } while ((b != editor_pid) && (b >= 0));
634 if (file_checksum(filename) == cksum) {
635 scr_printf("*** No changes to save.\n");
639 if (e_ex_code == 0) { /* Save changes */
640 changefp = fopen(changefile, "w");
642 /* Load all netconfig entries that are *not* of the type we are editing */
643 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
645 while(listing && !IsEmptyStr(listing)) {
646 extract_token(buf, listing, 0, '\n', sizeof buf);
647 remove_token(listing, 0, '\n');
648 extract_token(instr, buf, 0, '|', sizeof instr);
649 if (strcasecmp(instr, entrytype)) {
650 fprintf(changefp, "%s\n", buf);
659 /* ...and merge that with the data we just edited */
660 tempfp = fopen(filename, "r");
661 while (fgets(buf, sizeof buf, tempfp) != NULL) {
662 for (i=0; i<strlen(buf); ++i) {
663 if (buf[i] == '#') buf[i] = 0;
666 if (!IsEmptyStr(buf)) {
667 fprintf(changefp, "%s|%s\n", entrytype, buf);
673 /* now write it to the server... */
674 changefp = fopen(changefile, "r");
675 if (changefp != NULL) {
676 listing = load_message_from_file(changefp);
678 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
686 unlink(filename); /* Delete the temporary files */
692 * IGnet node configuration
694 void do_ignet_configuration(CtdlIPC *ipc) {
702 char *listing = NULL;
705 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
706 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
707 extract_token(buf, listing, 0, '\n', sizeof buf);
708 remove_token(listing, 0, '\n');
711 if (num_recs == 1) recs = malloc(sizeof(char *));
712 else recs = realloc(recs, (sizeof(char *)) * num_recs);
713 recs[num_recs-1] = malloc(SIZ);
714 strcpy(recs[num_recs-1], buf);
716 if (listing) free(listing);
729 "------------------ "
730 "-------------------------------- "
732 for (i=0; i<num_recs; ++i) {
734 scr_printf("%3d ", i+1);
735 extract_token(buf, recs[i], 0, '|', sizeof buf);
737 scr_printf("%-16s ", buf);
738 extract_token(buf, recs[i], 1, '|', sizeof buf);
739 color(BRIGHT_MAGENTA);
740 scr_printf("%-18s ", buf);
741 extract_token(buf, recs[i], 2, '|', sizeof buf);
743 scr_printf("%-32s ", buf);
744 extract_token(buf, recs[i], 3, '|', sizeof buf);
745 color(BRIGHT_MAGENTA);
746 scr_printf("%-3s\n", buf);
751 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
756 recs = malloc(sizeof(char *));
757 else recs = realloc(recs,
758 (sizeof(char *)) * num_recs);
759 newprompt("Enter node name : ", buf, 16);
761 newprompt("Enter shared secret: ",
762 &buf[strlen(buf)], 18);
764 newprompt("Enter host or IP : ",
765 &buf[strlen(buf)], 32);
767 strprompt("Enter port number : ",
768 &buf[strlen(buf)-3], 5);
769 recs[num_recs-1] = strdup(buf);
773 i = intprompt("Delete which one",
777 for (j=i; j<num_recs; ++j)
783 for (i = 0; i < num_recs; ++i)
784 r += 1 + strlen(recs[i]);
785 listing = (char*) calloc(1, r);
787 scr_printf("Can't save config - out of memory!\n");
790 if (num_recs) for (i = 0; i < num_recs; ++i) {
791 strcat(listing, recs[i]);
792 strcat(listing, "\n");
794 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
796 scr_printf("%s\n", buf);
798 scr_printf("Wrote %d records.\n", num_recs);
804 quitting = !modified || boolprompt(
805 "Quit without saving", 0);
813 for (i=0; i<num_recs; ++i) free(recs[i]);
820 * Filter list configuration
822 void do_filterlist_configuration(CtdlIPC *ipc)
831 char *listing = NULL;
834 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
835 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
836 extract_token(buf, listing, 0, '\n', sizeof buf);
837 remove_token(listing, 0, '\n');
840 if (num_recs == 1) recs = malloc(sizeof(char *));
841 else recs = realloc(recs, (sizeof(char *)) * num_recs);
842 recs[num_recs-1] = malloc(SIZ);
843 strcpy(recs[num_recs-1], buf);
845 if (listing) free(listing);
857 "---------------------------- "
858 "---------------------------- "
861 for (i=0; i<num_recs; ++i) {
863 scr_printf("%3d ", i+1);
864 extract_token(buf, recs[i], 0, '|', sizeof buf);
866 scr_printf("%-28s ", buf);
867 extract_token(buf, recs[i], 1, '|', sizeof buf);
868 color(BRIGHT_MAGENTA);
869 scr_printf("%-28s ", buf);
870 extract_token(buf, recs[i], 2, '|', sizeof buf);
872 scr_printf("%-16s\n", buf);
873 extract_token(buf, recs[i], 3, '|', sizeof buf);
877 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
882 recs = malloc(sizeof(char *));
883 else recs = realloc(recs,
884 (sizeof(char *)) * num_recs);
885 newprompt("Enter user name: ", buf, 28);
887 newprompt("Enter room name: ",
888 &buf[strlen(buf)], 28);
890 newprompt("Enter node name: ",
891 &buf[strlen(buf)], 16);
893 recs[num_recs-1] = strdup(buf);
897 i = intprompt("Delete which one",
901 for (j=i; j<num_recs; ++j)
907 for (i = 0; i < num_recs; ++i)
908 r += 1 + strlen(recs[i]);
909 listing = (char*) calloc(1, r);
911 scr_printf("Can't save config - out of memory!\n");
914 if (num_recs) for (i = 0; i < num_recs; ++i) {
915 strcat(listing, recs[i]);
916 strcat(listing, "\n");
918 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
920 scr_printf("%s\n", buf);
922 scr_printf("Wrote %d records.\n", num_recs);
928 quitting = !modified || boolprompt(
929 "Quit without saving", 0);
937 for (i=0; i<num_recs; ++i) free(recs[i]);
946 * POP3 aggregation client configuration
948 void do_pop3client_configuration(CtdlIPC *ipc)
957 char *listing = NULL;
958 char *other_listing = NULL;
962 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
964 while(listing && !IsEmptyStr(listing)) {
965 extract_token(buf, listing, 0, '\n', sizeof buf);
966 remove_token(listing, 0, '\n');
967 extract_token(instr, buf, 0, '|', sizeof instr);
968 if (!strcasecmp(instr, "pop3client")) {
971 if (num_recs == 1) recs = malloc(sizeof(char *));
972 else recs = realloc(recs, (sizeof(char *)) * num_recs);
973 recs[num_recs-1] = malloc(SIZ);
974 strcpy(recs[num_recs-1], buf);
995 "---------------------------- "
996 "---------------------------- "
1000 for (i=0; i<num_recs; ++i) {
1002 scr_printf("%3d ", i+1);
1004 extract_token(buf, recs[i], 1, '|', sizeof buf);
1006 scr_printf("%-28s ", buf);
1008 extract_token(buf, recs[i], 2, '|', sizeof buf);
1009 color(BRIGHT_MAGENTA);
1010 scr_printf("%-28s ", buf);
1013 scr_printf("%-15s ", (extract_int(recs[i], 4) ? "Yes" : "No") );
1014 color(BRIGHT_MAGENTA);
1015 scr_printf("%ld\n", extract_long(recs[i], 5) );
1019 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1023 if (num_recs == 1) {
1024 recs = malloc(sizeof(char *));
1027 recs = realloc(recs, (sizeof(char *)) * num_recs);
1029 strcpy(buf, "pop3client|");
1030 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1032 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1034 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1036 scr_printf("Keep messages on server instead of deleting them? ");
1037 sprintf(&buf[strlen(buf)], "%d", yesno());
1039 newprompt("Enter interval : ", &buf[strlen(buf)], 5);
1041 recs[num_recs-1] = strdup(buf);
1045 i = intprompt("Delete which one",
1046 1, 1, num_recs) - 1;
1049 for (j=i; j<num_recs; ++j)
1050 recs[j] = recs[j+1];
1055 for (i = 0; i < num_recs; ++i) {
1056 r += 1 + strlen(recs[i]);
1058 listing = (char*) calloc(1, r);
1060 scr_printf("Can't save config - out of memory!\n");
1063 if (num_recs) for (i = 0; i < num_recs; ++i) {
1064 strcat(listing, recs[i]);
1065 strcat(listing, "\n");
1068 /* Retrieve all the *other* records for merging */
1069 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1071 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1072 extract_token(buf, other_listing, i, '\n', sizeof buf);
1073 if (strncasecmp(buf, "pop3client|", 11)) {
1074 listing = realloc(listing, strlen(listing) +
1076 strcat(listing, buf);
1077 strcat(listing, "\n");
1081 free(other_listing);
1082 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1087 scr_printf("%s\n", buf);
1089 scr_printf("Wrote %d records.\n", num_recs);
1095 quitting = !modified || boolprompt(
1096 "Quit without saving", 0);
1101 } while (!quitting);
1104 for (i=0; i<num_recs; ++i) free(recs[i]);
1115 * RSS feed retrieval client configuration
1117 void do_rssclient_configuration(CtdlIPC *ipc)
1126 char *listing = NULL;
1127 char *other_listing = NULL;
1131 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1133 while(listing && !IsEmptyStr(listing)) {
1134 extract_token(buf, listing, 0, '\n', sizeof buf);
1135 remove_token(listing, 0, '\n');
1136 extract_token(instr, buf, 0, '|', sizeof instr);
1137 if (!strcasecmp(instr, "rssclient")) {
1140 if (num_recs == 1) recs = malloc(sizeof(char *));
1141 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1142 recs[num_recs-1] = malloc(SIZ);
1143 strcpy(recs[num_recs-1], buf);
1155 color(BRIGHT_WHITE);
1156 scr_printf("### Feed URL\n");
1159 "---------------------------------------------------------------------------"
1162 for (i=0; i<num_recs; ++i) {
1164 scr_printf("%3d ", i+1);
1166 extract_token(buf, recs[i], 1, '|', sizeof buf);
1168 scr_printf("%-75s\n", buf);
1173 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1177 if (num_recs == 1) {
1178 recs = malloc(sizeof(char *));
1181 recs = realloc(recs, (sizeof(char *)) * num_recs);
1183 strcpy(buf, "rssclient|");
1184 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1186 recs[num_recs-1] = strdup(buf);
1190 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1193 for (j=i; j<num_recs; ++j)
1194 recs[j] = recs[j+1];
1199 for (i = 0; i < num_recs; ++i) {
1200 r += 1 + strlen(recs[i]);
1202 listing = (char*) calloc(1, r);
1204 scr_printf("Can't save config - out of memory!\n");
1207 if (num_recs) for (i = 0; i < num_recs; ++i) {
1208 strcat(listing, recs[i]);
1209 strcat(listing, "\n");
1212 /* Retrieve all the *other* records for merging */
1213 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1215 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1216 extract_token(buf, other_listing, i, '\n', sizeof buf);
1217 if (strncasecmp(buf, "rssclient|", 10)) {
1218 listing = realloc(listing, strlen(listing) +
1220 strcat(listing, buf);
1221 strcat(listing, "\n");
1225 free(other_listing);
1226 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1231 scr_printf("%s\n", buf);
1233 scr_printf("Wrote %d records.\n", num_recs);
1239 quitting = !modified || boolprompt(
1240 "Quit without saving", 0);
1245 } while (!quitting);
1248 for (i=0; i<num_recs; ++i) free(recs[i]);