2 * Configuration screens that are part of the text mode client.
4 * Copyright (c) 1987-2016 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 /* Funambol push stuff */
310 int yes_funambol = 0;
311 if (strlen(sc[53]) > 0) yes_funambol = 1;
312 yes_funambol = boolprompt("Connect to an external Funambol sync server", yes_funambol);
314 strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
315 strprompt("Funambol server port", &sc[54][0], 5);
316 strprompt("Funambol sync source", &sc[55][0], 63);
317 strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
326 /* External pager stuff */
328 if (strlen(sc[60]) > 0) yes_pager = 1;
329 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
331 strprompt("External pager tool", &sc[60][0], 255);
337 /* Master user account */
339 if (strlen(sc[58]) > 0) yes_muacct = 1;
340 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
342 strprompt("Master user name", &sc[58][0], 31);
343 strprompt("Master user password", &sc[59][0], -31);
346 strcpy(&sc[58][0], "");
347 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
351 scr_printf("Save this configuration? ");
354 for (a = 0; a < NUM_CONFIGS; a++) {
355 r += 1 + strlen(sc[a]);
357 resp = (char *)calloc(1, r);
359 scr_printf("Can't save config - out of memory!\n");
362 for (a = 0; a < NUM_CONFIGS; a++) {
366 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
368 scr_printf("%s\n", buf);
372 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
374 scr_printf("%s\n", buf);
377 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
379 scr_printf("%s\n", buf);
383 if (site_expirepolicy) free(site_expirepolicy);
384 if (mbx_expirepolicy) free(mbx_expirepolicy);
389 * support function for do_internet_configuration()
391 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
394 keyopt(" <1> localhost (Alias for this computer)\n");
395 keyopt(" <2> smart host (Forward all outbound mail to this host)\n");
396 keyopt(" <3> fallback host (Send mail to this host only if direct delivery fails)\n");
397 keyopt(" <4> directory (Consult the Global Address Book)\n");
398 keyopt(" <5> SpamAssassin (Address of SpamAssassin server)\n");
399 keyopt(" <6> RBL (domain suffix of spam hunting RBL)\n");
400 keyopt(" <7> masq domains (Domains as which users are allowed to masquerade)\n");
401 keyopt(" <8> ClamAV (Address of ClamAV clamd server)\n");
402 sel = intprompt("Which one", 1, 1, 8);
404 case 1: strcpy(buf, "localhost");
406 case 2: strcpy(buf, "smarthost");
408 case 3: strcpy(buf, "fallbackhost");
410 case 4: strcpy(buf, "directory");
412 case 5: strcpy(buf, "spamassassin");
414 case 6: strcpy(buf, "rbl");
416 case 7: strcpy(buf, "masqdomain");
418 case 8: strcpy(buf, "clamav");
425 * Internet mail configuration
427 void do_internet_configuration(CtdlIPC *ipc)
439 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
441 while (!IsEmptyStr(resp)) {
442 extract_token(buf, resp, 0, '\n', sizeof buf);
443 remove_token(resp, 0, '\n');
445 if (num_recs == 1) recs = malloc(sizeof(char *));
446 else recs = realloc(recs, (sizeof(char *)) * num_recs);
447 recs[num_recs-1] = malloc(strlen(buf) + 1);
448 strcpy(recs[num_recs-1], buf);
451 if (resp) free(resp);
456 scr_printf("### Host or domain Record type \n");
458 scr_printf("--- -------------------------------------------------- --------------------\n");
459 for (i=0; i<num_recs; ++i) {
461 scr_printf("%3d ", i+1);
462 extract_token(buf, recs[i], 0, '|', sizeof buf);
464 scr_printf("%-50s ", buf);
465 extract_token(buf, recs[i], 1, '|', sizeof buf);
466 color(BRIGHT_MAGENTA);
467 scr_printf("%-20s\n", buf);
471 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
474 newprompt("Enter host name: ",
477 if (!IsEmptyStr(buf)) {
480 recs = malloc(sizeof(char *));
481 else recs = realloc(recs,
482 (sizeof(char *)) * num_recs);
484 get_inet_rec_type(ipc,
486 recs[num_recs-1] = strdup(buf);
491 i = intprompt("Delete which one",
495 for (j=i; j<num_recs; ++j)
501 for (i = 0; i < num_recs; i++)
502 r += 1 + strlen(recs[i]);
503 resp = (char *)calloc(1, r);
505 scr_printf("Can't save config - out of memory!\n");
508 if (num_recs) for (i = 0; i < num_recs; i++) {
509 strcat(resp, recs[i]);
512 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
514 scr_printf("%s\n", buf);
516 scr_printf("Wrote %d records.\n", num_recs);
522 quitting = !modified || boolprompt(
523 "Quit without saving", 0);
531 for (i=0; i<num_recs; ++i) free(recs[i]);
539 * Edit network configuration for room sharing, mailing lists, etc.
541 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
543 char filename[PATH_MAX];
544 char changefile[PATH_MAX];
554 char *listing = NULL;
557 if (IsEmptyStr(editor_path)) {
558 scr_printf("You must have an external editor configured in"
559 " order to use this function.\n");
563 CtdlMakeTempFileName(filename, sizeof filename);
564 CtdlMakeTempFileName(changefile, sizeof changefile);
566 tempfp = fopen(filename, "w");
567 if (tempfp == NULL) {
568 scr_printf("Cannot open %s: %s\n", filename, strerror(errno));
572 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
573 fprintf(tempfp, "# %s\n", comment);
574 fprintf(tempfp, "# Specify one per line.\n"
577 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
579 while(listing && !IsEmptyStr(listing)) {
580 extract_token(buf, listing, 0, '\n', sizeof buf);
581 remove_token(listing, 0, '\n');
582 extract_token(instr, buf, 0, '|', sizeof instr);
583 if (!strcasecmp(instr, entrytype)) {
584 tokens = num_tokens(buf, '|');
585 for (i=1; i<tokens; ++i) {
586 extract_token(addr, buf, i, '|', sizeof addr);
587 fprintf(tempfp, "%s", addr);
588 if (i < (tokens-1)) {
589 fprintf(tempfp, "|");
592 fprintf(tempfp, "\n");
602 e_ex_code = 1; /* start with a failed exit code */
603 stty_ctdl(SB_RESTORE);
605 cksum = file_checksum(filename);
606 if (editor_pid == 0) {
607 chmod(filename, 0600);
608 putenv("WINDOW_TITLE=Network configuration");
609 execlp(editor_path, editor_path, filename, NULL);
612 if (editor_pid > 0) {
615 b = ka_wait(&e_ex_code);
616 } while ((b != editor_pid) && (b >= 0));
621 if (file_checksum(filename) == cksum) {
622 scr_printf("*** No changes to save.\n");
626 if (e_ex_code == 0) { /* Save changes */
627 changefp = fopen(changefile, "w");
629 /* Load all netconfig entries that are *not* of the type we are editing */
630 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
632 while(listing && !IsEmptyStr(listing)) {
633 extract_token(buf, listing, 0, '\n', sizeof buf);
634 remove_token(listing, 0, '\n');
635 extract_token(instr, buf, 0, '|', sizeof instr);
636 if (strcasecmp(instr, entrytype)) {
637 fprintf(changefp, "%s\n", buf);
646 /* ...and merge that with the data we just edited */
647 tempfp = fopen(filename, "r");
648 while (fgets(buf, sizeof buf, tempfp) != NULL) {
649 for (i=0; i<strlen(buf); ++i) {
650 if (buf[i] == '#') buf[i] = 0;
653 if (!IsEmptyStr(buf)) {
654 fprintf(changefp, "%s|%s\n", entrytype, buf);
660 /* now write it to the server... */
661 changefp = fopen(changefile, "r");
662 if (changefp != NULL) {
663 listing = load_message_from_file(changefp);
665 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
673 unlink(filename); /* Delete the temporary files */
679 * IGnet node configuration
681 void do_ignet_configuration(CtdlIPC *ipc) {
689 char *listing = NULL;
692 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
693 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
694 extract_token(buf, listing, 0, '\n', sizeof buf);
695 remove_token(listing, 0, '\n');
698 if (num_recs == 1) recs = malloc(sizeof(char *));
699 else recs = realloc(recs, (sizeof(char *)) * num_recs);
700 recs[num_recs-1] = malloc(SIZ);
701 strcpy(recs[num_recs-1], buf);
703 if (listing) free(listing);
716 "------------------ "
717 "-------------------------------- "
719 for (i=0; i<num_recs; ++i) {
721 scr_printf("%3d ", i+1);
722 extract_token(buf, recs[i], 0, '|', sizeof buf);
724 scr_printf("%-16s ", buf);
725 extract_token(buf, recs[i], 1, '|', sizeof buf);
726 color(BRIGHT_MAGENTA);
727 scr_printf("%-18s ", buf);
728 extract_token(buf, recs[i], 2, '|', sizeof buf);
730 scr_printf("%-32s ", buf);
731 extract_token(buf, recs[i], 3, '|', sizeof buf);
732 color(BRIGHT_MAGENTA);
733 scr_printf("%-3s\n", buf);
738 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
743 recs = malloc(sizeof(char *));
744 else recs = realloc(recs,
745 (sizeof(char *)) * num_recs);
746 newprompt("Enter node name : ", buf, 16);
748 newprompt("Enter shared secret: ",
749 &buf[strlen(buf)], 18);
751 newprompt("Enter host or IP : ",
752 &buf[strlen(buf)], 32);
754 strprompt("Enter port number : ",
755 &buf[strlen(buf)-3], 5);
756 recs[num_recs-1] = strdup(buf);
760 i = intprompt("Delete which one",
764 for (j=i; j<num_recs; ++j)
770 for (i = 0; i < num_recs; ++i)
771 r += 1 + strlen(recs[i]);
772 listing = (char*) calloc(1, r);
774 scr_printf("Can't save config - out of memory!\n");
777 if (num_recs) for (i = 0; i < num_recs; ++i) {
778 strcat(listing, recs[i]);
779 strcat(listing, "\n");
781 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
783 scr_printf("%s\n", buf);
785 scr_printf("Wrote %d records.\n", num_recs);
791 quitting = !modified || boolprompt(
792 "Quit without saving", 0);
800 for (i=0; i<num_recs; ++i) free(recs[i]);
807 * Filter list configuration
809 void do_filterlist_configuration(CtdlIPC *ipc)
818 char *listing = NULL;
821 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
822 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
823 extract_token(buf, listing, 0, '\n', sizeof buf);
824 remove_token(listing, 0, '\n');
827 if (num_recs == 1) recs = malloc(sizeof(char *));
828 else recs = realloc(recs, (sizeof(char *)) * num_recs);
829 recs[num_recs-1] = malloc(SIZ);
830 strcpy(recs[num_recs-1], buf);
832 if (listing) free(listing);
844 "---------------------------- "
845 "---------------------------- "
848 for (i=0; i<num_recs; ++i) {
850 scr_printf("%3d ", i+1);
851 extract_token(buf, recs[i], 0, '|', sizeof buf);
853 scr_printf("%-28s ", buf);
854 extract_token(buf, recs[i], 1, '|', sizeof buf);
855 color(BRIGHT_MAGENTA);
856 scr_printf("%-28s ", buf);
857 extract_token(buf, recs[i], 2, '|', sizeof buf);
859 scr_printf("%-16s\n", buf);
860 extract_token(buf, recs[i], 3, '|', sizeof buf);
864 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
869 recs = malloc(sizeof(char *));
870 else recs = realloc(recs,
871 (sizeof(char *)) * num_recs);
872 newprompt("Enter user name: ", buf, 28);
874 newprompt("Enter room name: ",
875 &buf[strlen(buf)], 28);
877 newprompt("Enter node name: ",
878 &buf[strlen(buf)], 16);
880 recs[num_recs-1] = strdup(buf);
884 i = intprompt("Delete which one",
888 for (j=i; j<num_recs; ++j)
894 for (i = 0; i < num_recs; ++i)
895 r += 1 + strlen(recs[i]);
896 listing = (char*) calloc(1, r);
898 scr_printf("Can't save config - out of memory!\n");
901 if (num_recs) for (i = 0; i < num_recs; ++i) {
902 strcat(listing, recs[i]);
903 strcat(listing, "\n");
905 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
907 scr_printf("%s\n", buf);
909 scr_printf("Wrote %d records.\n", num_recs);
915 quitting = !modified || boolprompt(
916 "Quit without saving", 0);
924 for (i=0; i<num_recs; ++i) free(recs[i]);
933 * POP3 aggregation client configuration
935 void do_pop3client_configuration(CtdlIPC *ipc)
944 char *listing = NULL;
945 char *other_listing = NULL;
949 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
951 while(listing && !IsEmptyStr(listing)) {
952 extract_token(buf, listing, 0, '\n', sizeof buf);
953 remove_token(listing, 0, '\n');
954 extract_token(instr, buf, 0, '|', sizeof instr);
955 if (!strcasecmp(instr, "pop3client")) {
958 if (num_recs == 1) recs = malloc(sizeof(char *));
959 else recs = realloc(recs, (sizeof(char *)) * num_recs);
960 recs[num_recs-1] = malloc(SIZ);
961 strcpy(recs[num_recs-1], buf);
982 "---------------------------- "
983 "---------------------------- "
987 for (i=0; i<num_recs; ++i) {
989 scr_printf("%3d ", i+1);
991 extract_token(buf, recs[i], 1, '|', sizeof buf);
993 scr_printf("%-28s ", buf);
995 extract_token(buf, recs[i], 2, '|', sizeof buf);
996 color(BRIGHT_MAGENTA);
997 scr_printf("%-28s ", buf);
1000 scr_printf("%-15s ", (extract_int(recs[i], 4) ? "Yes" : "No") );
1001 color(BRIGHT_MAGENTA);
1002 scr_printf("%ld\n", extract_long(recs[i], 5) );
1006 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1010 if (num_recs == 1) {
1011 recs = malloc(sizeof(char *));
1014 recs = realloc(recs, (sizeof(char *)) * num_recs);
1016 strcpy(buf, "pop3client|");
1017 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1019 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1021 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1023 scr_printf("Keep messages on server instead of deleting them? ");
1024 sprintf(&buf[strlen(buf)], "%d", yesno());
1026 newprompt("Enter interval : ", &buf[strlen(buf)], 5);
1028 recs[num_recs-1] = strdup(buf);
1032 i = intprompt("Delete which one",
1033 1, 1, num_recs) - 1;
1036 for (j=i; j<num_recs; ++j)
1037 recs[j] = recs[j+1];
1042 for (i = 0; i < num_recs; ++i) {
1043 r += 1 + strlen(recs[i]);
1045 listing = (char*) calloc(1, r);
1047 scr_printf("Can't save config - out of memory!\n");
1050 if (num_recs) for (i = 0; i < num_recs; ++i) {
1051 strcat(listing, recs[i]);
1052 strcat(listing, "\n");
1055 /* Retrieve all the *other* records for merging */
1056 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1058 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1059 extract_token(buf, other_listing, i, '\n', sizeof buf);
1060 if (strncasecmp(buf, "pop3client|", 11)) {
1061 listing = realloc(listing, strlen(listing) +
1063 strcat(listing, buf);
1064 strcat(listing, "\n");
1068 free(other_listing);
1069 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1074 scr_printf("%s\n", buf);
1076 scr_printf("Wrote %d records.\n", num_recs);
1082 quitting = !modified || boolprompt(
1083 "Quit without saving", 0);
1088 } while (!quitting);
1091 for (i=0; i<num_recs; ++i) free(recs[i]);
1102 * RSS feed retrieval client configuration
1104 void do_rssclient_configuration(CtdlIPC *ipc)
1113 char *listing = NULL;
1114 char *other_listing = NULL;
1118 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1120 while(listing && !IsEmptyStr(listing)) {
1121 extract_token(buf, listing, 0, '\n', sizeof buf);
1122 remove_token(listing, 0, '\n');
1123 extract_token(instr, buf, 0, '|', sizeof instr);
1124 if (!strcasecmp(instr, "rssclient")) {
1127 if (num_recs == 1) recs = malloc(sizeof(char *));
1128 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1129 recs[num_recs-1] = malloc(SIZ);
1130 strcpy(recs[num_recs-1], buf);
1142 color(BRIGHT_WHITE);
1143 scr_printf("### Feed URL\n");
1146 "---------------------------------------------------------------------------"
1149 for (i=0; i<num_recs; ++i) {
1151 scr_printf("%3d ", i+1);
1153 extract_token(buf, recs[i], 1, '|', sizeof buf);
1155 scr_printf("%-75s\n", buf);
1160 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1164 if (num_recs == 1) {
1165 recs = malloc(sizeof(char *));
1168 recs = realloc(recs, (sizeof(char *)) * num_recs);
1170 strcpy(buf, "rssclient|");
1171 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1173 recs[num_recs-1] = strdup(buf);
1177 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1180 for (j=i; j<num_recs; ++j)
1181 recs[j] = recs[j+1];
1186 for (i = 0; i < num_recs; ++i) {
1187 r += 1 + strlen(recs[i]);
1189 listing = (char*) calloc(1, r);
1191 scr_printf("Can't save config - out of memory!\n");
1194 if (num_recs) for (i = 0; i < num_recs; ++i) {
1195 strcat(listing, recs[i]);
1196 strcat(listing, "\n");
1199 /* Retrieve all the *other* records for merging */
1200 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1202 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1203 extract_token(buf, other_listing, i, '\n', sizeof buf);
1204 if (strncasecmp(buf, "rssclient|", 10)) {
1205 listing = realloc(listing, strlen(listing) +
1207 strcat(listing, buf);
1208 strcat(listing, "\n");
1212 free(other_listing);
1213 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1218 scr_printf("%s\n", buf);
1220 scr_printf("Wrote %d records.\n", num_recs);
1226 quitting = !modified || boolprompt(
1227 "Quit without saving", 0);
1232 } while (!quitting);
1235 for (i=0; i<num_recs; ++i) free(recs[i]);