2 * Configuration screens that are part of the text mode client.
4 * Copyright (c) 1987-2017 by the citadel.org team
6 * This program is open source software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
17 #include <sys/types.h>
25 #if TIME_WITH_SYS_TIME
26 # include <sys/time.h>
30 # include <sys/time.h>
40 #include <libcitadel.h>
42 #include "citadel_ipc.h"
43 #include "citadel_decls.h"
44 #include "tuiconfig.h"
50 /* work around solaris include files */
56 extern char tempdir[];
57 extern char *axdefs[8];
58 extern long highest_msg_read;
59 extern long maxmsgnum;
60 extern unsigned room_flags;
61 extern int screenwidth;
62 char editor_path[PATH_MAX];
66 * General system configuration command
68 void do_system_configuration(CtdlIPC *ipc)
71 /* NUM_CONFIGS is now defined in citadel.h */
74 char sc[NUM_CONFIGS][256];
76 struct ExpirePolicy *site_expirepolicy = NULL;
77 struct ExpirePolicy *mbx_expirepolicy = NULL;
80 int r; /* IPC response code */
81 int server_configs = 0;
83 /* Clear out the config buffers */
84 memset(&sc[0][0], 0, sizeof(sc));
86 /* Fetch the current config */
87 r = CtdlIPCGetSystemConfig(ipc, &resp, buf);
89 server_configs = num_tokens(resp, '\n');
90 for (a=0; a<server_configs; ++a) {
91 if (a < NUM_CONFIGS) {
92 extract_token(&sc[a][0], resp, a, '\n', sizeof sc[a]);
98 /* Fetch the expire policy (this will silently fail on old servers,
99 * resulting in "default" policy)
101 r = CtdlIPCGetMessageExpirationPolicy(ipc, 2, &site_expirepolicy, buf);
102 r = CtdlIPCGetMessageExpirationPolicy(ipc, 3, &mbx_expirepolicy, buf);
104 /* Identification parameters */
106 strprompt("Node name", &sc[0][0], 15);
107 strprompt("Fully qualified domain name", &sc[1][0], 63);
108 strprompt("Human readable node name", &sc[2][0], 20);
109 strprompt("Telephone number", &sc[3][0], 15);
110 strprompt("Geographic location of this system", &sc[12][0], 31);
111 strprompt("Name of system administrator", &sc[13][0], 25);
112 strprompt("Paginator prompt", &sc[10][0], 79);
114 /* Security parameters */
116 snprintf(sc[7], sizeof sc[7], "%d", (boolprompt("Require registration for new users", atoi(&sc[7][0]))));
117 snprintf(sc[29], sizeof sc[29], "%d", (boolprompt("Disable self-service user account creation", atoi(&sc[29][0]))));
118 strprompt("Initial access level for new users", &sc[6][0], 1);
119 strprompt("Access level required to create rooms", &sc[19][0], 1);
120 snprintf(sc[67], sizeof sc[67], "%d", (boolprompt("Allow anonymous guest logins", atoi(&sc[67][0]))));
121 snprintf(sc[4], sizeof sc[4], "%d", (boolprompt(
122 "Automatically give room admin privs to a user who creates a private room",
125 snprintf(sc[8], sizeof sc[8], "%d", (boolprompt(
126 "Automatically move problem user messages to twit room",
129 strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
130 snprintf(sc[11], sizeof sc[11], "%d", (boolprompt(
131 "Restrict Internet mail to only those with that privilege",
133 snprintf(sc[26], sizeof sc[26], "%d", (boolprompt(
134 "Allow admins to Zap (forget) rooms",
137 if (!IsEmptyStr(&sc[18][0])) {
143 logpages = boolprompt("Log all instant messages", logpages);
145 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
151 /* Commented out because this setting isn't really appropriate to
152 * change while the server is running.
154 * snprintf(sc[52], sizeof sc[52], "%d", (boolprompt(
155 * "Use system authentication",
156 * atoi(&sc[52][0]))));
161 strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
162 strprompt("Maximum concurrent sessions", &sc[14][0], 4);
163 strprompt("Maximum message length", &sc[20][0], 20);
164 strprompt("Minimum number of worker threads", &sc[21][0], 3);
165 strprompt("Maximum number of worker threads", &sc[22][0], 3);
166 snprintf(sc[43], sizeof sc[43], "%d", (boolprompt(
167 "Automatically delete committed database logs",
170 strprompt("Server IP address (* for 'any')", &sc[37][0], 15);
171 strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
172 strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5);
173 strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
174 strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5);
175 strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5);
176 strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5);
177 strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5);
178 strprompt("NNTP server port (-1 to disable)", &sc[70][0], 5);
179 strprompt("NNTPS server port (-1 to disable)", &sc[71][0], 5);
180 strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5);
181 strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5);
183 strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5);
184 /* No prompt because we don't implement this service yet, it's just a placeholder */
185 /* strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); */
187 /* This logic flips the question around, because it's one of those
188 * situations where 0=yes and 1=no
192 a = boolprompt("Correct forged From: lines during authenticated SMTP", a);
194 snprintf(sc[25], sizeof sc[25], "%d", a);
196 snprintf(sc[66], sizeof sc[66], "%d", (boolprompt(
197 "Flag messages as spam instead of rejecting",
200 /* This logic flips the question around, because it's one of those
201 * situations where 0=yes and 1=no
205 a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a);
207 snprintf(sc[61], sizeof sc[61], "%d", a);
209 snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
210 "Allow unauthenticated SMTP clients to spoof my domains",
212 snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
213 "Perform RBL checks at greeting instead of after RCPT",
217 if (ipc->ServInfo.supports_ldap) {
218 a = strlen(&sc[32][0]);
219 a = (a ? 1 : 0); /* Set only to 1 or 0 */
220 a = boolprompt("Do you want to configure LDAP authentication?", a);
222 strprompt("Host name of LDAP server", &sc[32][0], 127);
223 strprompt("Port number of LDAP service", &sc[33][0], 5);
224 strprompt("Base DN", &sc[34][0], 255);
225 strprompt("Bind DN (or blank for anonymous bind)", &sc[35][0], 255);
226 strprompt("Password for bind DN (or blank for anonymous bind)", &sc[36][0], 255);
229 strcpy(&sc[32][0], "");
233 /* Expiry settings */
234 strprompt("Default user purge time (days)", &sc[16][0], 5);
235 strprompt("Default room purge time (days)", &sc[17][0], 5);
237 /* Angels and demons dancing in my head... */
239 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
240 strprompt("System default message expire policy (? for list)",
244 "1. Never automatically expire messages\n"
245 "2. Expire by message count\n"
246 "3. Expire by message age\n");
248 } while ((buf[0] < '1') || (buf[0] > '3'));
249 site_expirepolicy->expire_mode = buf[0] - '0';
251 /* ...lunatics and monsters underneath my bed */
252 if (site_expirepolicy->expire_mode == 2) {
253 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
254 strprompt("Keep how many messages online?", buf, 10);
255 site_expirepolicy->expire_value = atol(buf);
257 if (site_expirepolicy->expire_mode == 3) {
258 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
259 strprompt("Keep messages for how many days?", buf, 10);
260 site_expirepolicy->expire_value = atol(buf);
263 /* Media messiahs preying on my fears... */
265 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
266 strprompt("Mailbox default message expire policy (? for list)",
270 "0. Go with the system default\n"
271 "1. Never automatically expire messages\n"
272 "2. Expire by message count\n"
273 "3. Expire by message age\n");
275 } while ((buf[0] < '0') || (buf[0] > '3'));
276 mbx_expirepolicy->expire_mode = buf[0] - '0';
278 /* ...Pop culture prophets playing in my ears */
279 if (mbx_expirepolicy->expire_mode == 2) {
280 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
281 strprompt("Keep how many messages online?", buf, 10);
282 mbx_expirepolicy->expire_value = atol(buf);
284 if (mbx_expirepolicy->expire_mode == 3) {
285 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
286 strprompt("Keep messages for how many days?", buf, 10);
287 mbx_expirepolicy->expire_value = atol(buf);
290 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
291 strprompt("Default frequency to run POP3 collection (in seconds)", &sc[64][0], 5);
292 strprompt("Fastest frequency to run POP3 collection (in seconds)", &sc[65][0], 5);
293 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
294 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
295 "Enable full text search index (warning: resource intensive)",
298 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
299 "Perform journaling of email messages",
301 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
302 "Perform journaling of non-email messages",
304 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
305 strprompt("Email destination of journalized messages",
309 /* No more Funambol */
315 /* External pager stuff */
317 if (strlen(sc[60]) > 0) yes_pager = 1;
318 yes_pager = boolprompt("Configure an external pager tool", yes_pager);
320 strprompt("External pager tool", &sc[60][0], 255);
326 /* Master user account */
328 if (strlen(sc[58]) > 0) yes_muacct = 1;
329 yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
331 strprompt("Master user name", &sc[58][0], 31);
332 strprompt("Master user password", &sc[59][0], -31);
335 strcpy(&sc[58][0], "");
336 strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
340 scr_printf("Save this configuration? ");
343 for (a = 0; a < NUM_CONFIGS; a++) {
344 r += 1 + strlen(sc[a]);
346 resp = (char *)calloc(1, r);
348 scr_printf("Can't save config - out of memory!\n");
351 for (a = 0; a < NUM_CONFIGS; a++) {
355 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
357 scr_printf("%s\n", buf);
361 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
363 scr_printf("%s\n", buf);
366 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
368 scr_printf("%s\n", buf);
372 if (site_expirepolicy) free(site_expirepolicy);
373 if (mbx_expirepolicy) free(mbx_expirepolicy);
378 * support function for do_internet_configuration()
380 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
383 keyopt(" <1> localhost (Alias for this computer)\n");
384 keyopt(" <2> smart host (Forward all outbound mail to this host)\n");
385 keyopt(" <3> fallback host (Send mail to this host only if direct delivery fails)\n");
386 keyopt(" <4> SpamAssassin (Address of SpamAssassin server)\n");
387 keyopt(" <5> RBL (domain suffix of spam hunting RBL)\n");
388 keyopt(" <6> masq domains (Domains as which users are allowed to masquerade)\n");
389 keyopt(" <7> ClamAV (Address of ClamAV clamd server)\n");
390 sel = intprompt("Which one", 1, 1, 8);
392 case 1: strcpy(buf, "localhost");
394 case 2: strcpy(buf, "smarthost");
396 case 3: strcpy(buf, "fallbackhost");
398 case 4: strcpy(buf, "spamassassin");
400 case 5: strcpy(buf, "rbl");
402 case 6: strcpy(buf, "masqdomain");
404 case 7: strcpy(buf, "clamav");
411 * Internet mail configuration
413 void do_internet_configuration(CtdlIPC *ipc)
425 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
427 while (!IsEmptyStr(resp)) {
428 extract_token(buf, resp, 0, '\n', sizeof buf);
429 remove_token(resp, 0, '\n');
431 if (num_recs == 1) recs = malloc(sizeof(char *));
432 else recs = realloc(recs, (sizeof(char *)) * num_recs);
433 recs[num_recs-1] = malloc(strlen(buf) + 1);
434 strcpy(recs[num_recs-1], buf);
437 if (resp) free(resp);
442 scr_printf("### Host or domain Record type \n");
444 scr_printf("--- -------------------------------------------------- --------------------\n");
445 for (i=0; i<num_recs; ++i) {
447 scr_printf("%3d ", i+1);
448 extract_token(buf, recs[i], 0, '|', sizeof buf);
450 scr_printf("%-50s ", buf);
451 extract_token(buf, recs[i], 1, '|', sizeof buf);
452 color(BRIGHT_MAGENTA);
453 scr_printf("%-20s\n", buf);
457 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
460 newprompt("Enter host name: ", buf, 50);
462 if (!IsEmptyStr(buf)) {
465 recs = malloc(sizeof(char *));
468 recs = realloc(recs, (sizeof(char *)) * num_recs);
471 get_inet_rec_type(ipc, &buf[strlen(buf)]);
472 recs[num_recs-1] = strdup(buf);
477 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
480 for (j=i; j<num_recs; ++j) {
487 for (i = 0; i < num_recs; i++)
488 r += 1 + strlen(recs[i]);
489 resp = (char *)calloc(1, r);
491 scr_printf("Can't save config - out of memory!\n");
494 if (num_recs) for (i = 0; i < num_recs; i++) {
495 strcat(resp, recs[i]);
498 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
500 scr_printf("%s\n", buf);
502 scr_printf("Wrote %d records.\n", num_recs);
508 quitting = !modified || boolprompt(
509 "Quit without saving", 0);
517 for (i=0; i<num_recs; ++i) free(recs[i]);
525 * Edit network configuration for room sharing, mailing lists, etc.
527 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
529 char filename[PATH_MAX];
530 char changefile[PATH_MAX];
540 char *listing = NULL;
543 if (IsEmptyStr(editor_path)) {
544 scr_printf("You must have an external editor configured in order to use this function.\n");
548 CtdlMakeTempFileName(filename, sizeof filename);
549 CtdlMakeTempFileName(changefile, sizeof changefile);
551 tempfp = fopen(filename, "w");
552 if (tempfp == NULL) {
553 scr_printf("Cannot open %s: %s\n", filename, strerror(errno));
557 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
558 fprintf(tempfp, "# %s\n", comment);
559 fprintf(tempfp, "# Specify one per line.\n"
562 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
564 while(listing && !IsEmptyStr(listing)) {
565 extract_token(buf, listing, 0, '\n', sizeof buf);
566 remove_token(listing, 0, '\n');
567 extract_token(instr, buf, 0, '|', sizeof instr);
568 if (!strcasecmp(instr, entrytype)) {
569 tokens = num_tokens(buf, '|');
570 for (i=1; i<tokens; ++i) {
571 extract_token(addr, buf, i, '|', sizeof addr);
572 fprintf(tempfp, "%s", addr);
573 if (i < (tokens-1)) {
574 fprintf(tempfp, "|");
577 fprintf(tempfp, "\n");
587 e_ex_code = 1; /* start with a failed exit code */
588 stty_ctdl(SB_RESTORE);
590 cksum = file_checksum(filename);
591 if (editor_pid == 0) {
592 chmod(filename, 0600);
593 putenv("WINDOW_TITLE=Network configuration");
594 execlp(editor_path, editor_path, filename, NULL);
597 if (editor_pid > 0) {
600 b = ka_wait(&e_ex_code);
601 } while ((b != editor_pid) && (b >= 0));
606 if (file_checksum(filename) == cksum) {
607 scr_printf("*** No changes to save.\n");
611 if (e_ex_code == 0) { /* Save changes */
612 changefp = fopen(changefile, "w");
614 /* Load all netconfig entries that are *not* of the type we are editing */
615 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
617 while(listing && !IsEmptyStr(listing)) {
618 extract_token(buf, listing, 0, '\n', sizeof buf);
619 remove_token(listing, 0, '\n');
620 extract_token(instr, buf, 0, '|', sizeof instr);
621 if (strcasecmp(instr, entrytype)) {
622 fprintf(changefp, "%s\n", buf);
631 /* ...and merge that with the data we just edited */
632 tempfp = fopen(filename, "r");
633 while (fgets(buf, sizeof buf, tempfp) != NULL) {
634 for (i=0; i<strlen(buf); ++i) {
635 if (buf[i] == '#') buf[i] = 0;
638 if (!IsEmptyStr(buf)) {
639 fprintf(changefp, "%s|%s\n", entrytype, buf);
645 /* now write it to the server... */
646 changefp = fopen(changefile, "r");
647 if (changefp != NULL) {
648 listing = load_message_from_file(changefp);
650 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
658 unlink(filename); /* Delete the temporary files */
664 * IGnet node configuration
666 void do_ignet_configuration(CtdlIPC *ipc) {
674 char *listing = NULL;
677 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
678 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
679 extract_token(buf, listing, 0, '\n', sizeof buf);
680 remove_token(listing, 0, '\n');
683 if (num_recs == 1) recs = malloc(sizeof(char *));
684 else recs = realloc(recs, (sizeof(char *)) * num_recs);
685 recs[num_recs-1] = malloc(SIZ);
686 strcpy(recs[num_recs-1], buf);
688 if (listing) free(listing);
701 "------------------ "
702 "-------------------------------- "
704 for (i=0; i<num_recs; ++i) {
706 scr_printf("%3d ", i+1);
707 extract_token(buf, recs[i], 0, '|', sizeof buf);
709 scr_printf("%-16s ", buf);
710 extract_token(buf, recs[i], 1, '|', sizeof buf);
711 color(BRIGHT_MAGENTA);
712 scr_printf("%-18s ", buf);
713 extract_token(buf, recs[i], 2, '|', sizeof buf);
715 scr_printf("%-32s ", buf);
716 extract_token(buf, recs[i], 3, '|', sizeof buf);
717 color(BRIGHT_MAGENTA);
718 scr_printf("%-3s\n", buf);
723 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
728 recs = malloc(sizeof(char *));
729 else recs = realloc(recs,
730 (sizeof(char *)) * num_recs);
731 newprompt("Enter node name : ", buf, 16);
733 newprompt("Enter shared secret: ",
734 &buf[strlen(buf)], 18);
736 newprompt("Enter host or IP : ",
737 &buf[strlen(buf)], 32);
739 strprompt("Enter port number : ",
740 &buf[strlen(buf)-3], 5);
741 recs[num_recs-1] = strdup(buf);
745 i = intprompt("Delete which one",
749 for (j=i; j<num_recs; ++j)
755 for (i = 0; i < num_recs; ++i)
756 r += 1 + strlen(recs[i]);
757 listing = (char*) calloc(1, r);
759 scr_printf("Can't save config - out of memory!\n");
762 if (num_recs) for (i = 0; i < num_recs; ++i) {
763 strcat(listing, recs[i]);
764 strcat(listing, "\n");
766 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
768 scr_printf("%s\n", buf);
770 scr_printf("Wrote %d records.\n", num_recs);
776 quitting = !modified || boolprompt(
777 "Quit without saving", 0);
785 for (i=0; i<num_recs; ++i) free(recs[i]);
792 * Filter list configuration
794 void do_filterlist_configuration(CtdlIPC *ipc)
803 char *listing = NULL;
806 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
807 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
808 extract_token(buf, listing, 0, '\n', sizeof buf);
809 remove_token(listing, 0, '\n');
812 if (num_recs == 1) recs = malloc(sizeof(char *));
813 else recs = realloc(recs, (sizeof(char *)) * num_recs);
814 recs[num_recs-1] = malloc(SIZ);
815 strcpy(recs[num_recs-1], buf);
817 if (listing) free(listing);
829 "---------------------------- "
830 "---------------------------- "
833 for (i=0; i<num_recs; ++i) {
835 scr_printf("%3d ", i+1);
836 extract_token(buf, recs[i], 0, '|', sizeof buf);
838 scr_printf("%-28s ", buf);
839 extract_token(buf, recs[i], 1, '|', sizeof buf);
840 color(BRIGHT_MAGENTA);
841 scr_printf("%-28s ", buf);
842 extract_token(buf, recs[i], 2, '|', sizeof buf);
844 scr_printf("%-16s\n", buf);
845 extract_token(buf, recs[i], 3, '|', sizeof buf);
849 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
854 recs = malloc(sizeof(char *));
855 else recs = realloc(recs,
856 (sizeof(char *)) * num_recs);
857 newprompt("Enter user name: ", buf, 28);
859 newprompt("Enter room name: ",
860 &buf[strlen(buf)], 28);
862 newprompt("Enter node name: ",
863 &buf[strlen(buf)], 16);
865 recs[num_recs-1] = strdup(buf);
869 i = intprompt("Delete which one",
873 for (j=i; j<num_recs; ++j)
879 for (i = 0; i < num_recs; ++i)
880 r += 1 + strlen(recs[i]);
881 listing = (char*) calloc(1, r);
883 scr_printf("Can't save config - out of memory!\n");
886 if (num_recs) for (i = 0; i < num_recs; ++i) {
887 strcat(listing, recs[i]);
888 strcat(listing, "\n");
890 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
892 scr_printf("%s\n", buf);
894 scr_printf("Wrote %d records.\n", num_recs);
900 quitting = !modified || boolprompt(
901 "Quit without saving", 0);
909 for (i=0; i<num_recs; ++i) free(recs[i]);
918 * POP3 aggregation client configuration
920 void do_pop3client_configuration(CtdlIPC *ipc)
929 char *listing = NULL;
930 char *other_listing = NULL;
934 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
936 while(listing && !IsEmptyStr(listing)) {
937 extract_token(buf, listing, 0, '\n', sizeof buf);
938 remove_token(listing, 0, '\n');
939 extract_token(instr, buf, 0, '|', sizeof instr);
940 if (!strcasecmp(instr, "pop3client")) {
943 if (num_recs == 1) recs = malloc(sizeof(char *));
944 else recs = realloc(recs, (sizeof(char *)) * num_recs);
945 recs[num_recs-1] = malloc(SIZ);
946 strcpy(recs[num_recs-1], buf);
966 "---------------------------- "
967 "---------------------------- "
970 for (i=0; i<num_recs; ++i) {
972 scr_printf("%3d ", i+1);
974 extract_token(buf, recs[i], 1, '|', sizeof buf);
976 scr_printf("%-28s ", buf);
978 extract_token(buf, recs[i], 2, '|', sizeof buf);
979 color(BRIGHT_MAGENTA);
980 scr_printf("%-28s ", buf);
983 scr_printf("%-15s\n", (extract_int(recs[i], 4) ? "Yes" : "No") );
987 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
992 recs = malloc(sizeof(char *));
995 recs = realloc(recs, (sizeof(char *)) * num_recs);
997 strcpy(buf, "pop3client|");
998 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1000 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1002 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1004 scr_printf("Keep messages on server instead of deleting them? ");
1005 sprintf(&buf[strlen(buf)], "%d", yesno());
1007 recs[num_recs-1] = strdup(buf);
1011 i = intprompt("Delete which one",
1012 1, 1, num_recs) - 1;
1015 for (j=i; j<num_recs; ++j)
1016 recs[j] = recs[j+1];
1021 for (i = 0; i < num_recs; ++i) {
1022 r += 1 + strlen(recs[i]);
1024 listing = (char*) calloc(1, r);
1026 scr_printf("Can't save config - out of memory!\n");
1029 if (num_recs) for (i = 0; i < num_recs; ++i) {
1030 strcat(listing, recs[i]);
1031 strcat(listing, "\n");
1034 /* Retrieve all the *other* records for merging */
1035 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1037 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1038 extract_token(buf, other_listing, i, '\n', sizeof buf);
1039 if (strncasecmp(buf, "pop3client|", 11)) {
1040 listing = realloc(listing, strlen(listing) +
1042 strcat(listing, buf);
1043 strcat(listing, "\n");
1047 free(other_listing);
1048 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1053 scr_printf("%s\n", buf);
1055 scr_printf("Wrote %d records.\n", num_recs);
1061 quitting = !modified || boolprompt(
1062 "Quit without saving", 0);
1067 } while (!quitting);
1070 for (i=0; i<num_recs; ++i) free(recs[i]);
1081 * RSS feed retrieval client configuration
1083 void do_rssclient_configuration(CtdlIPC *ipc)
1092 char *listing = NULL;
1093 char *other_listing = NULL;
1097 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1099 while(listing && !IsEmptyStr(listing)) {
1100 extract_token(buf, listing, 0, '\n', sizeof buf);
1101 remove_token(listing, 0, '\n');
1102 extract_token(instr, buf, 0, '|', sizeof instr);
1103 if (!strcasecmp(instr, "rssclient")) {
1106 if (num_recs == 1) recs = malloc(sizeof(char *));
1107 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1108 recs[num_recs-1] = malloc(SIZ);
1109 strcpy(recs[num_recs-1], buf);
1121 color(BRIGHT_WHITE);
1122 scr_printf("### Feed URL\n");
1125 "---------------------------------------------------------------------------"
1128 for (i=0; i<num_recs; ++i) {
1130 scr_printf("%3d ", i+1);
1132 extract_token(buf, recs[i], 1, '|', sizeof buf);
1134 scr_printf("%-75s\n", buf);
1139 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1143 if (num_recs == 1) {
1144 recs = malloc(sizeof(char *));
1147 recs = realloc(recs, (sizeof(char *)) * num_recs);
1149 strcpy(buf, "rssclient|");
1150 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1152 recs[num_recs-1] = strdup(buf);
1156 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1159 for (j=i; j<num_recs; ++j)
1160 recs[j] = recs[j+1];
1165 for (i = 0; i < num_recs; ++i) {
1166 r += 1 + strlen(recs[i]);
1168 listing = (char*) calloc(1, r);
1170 scr_printf("Can't save config - out of memory!\n");
1173 if (num_recs) for (i = 0; i < num_recs; ++i) {
1174 strcat(listing, recs[i]);
1175 strcat(listing, "\n");
1178 /* Retrieve all the *other* records for merging */
1179 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1181 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1182 extract_token(buf, other_listing, i, '\n', sizeof buf);
1183 if (strncasecmp(buf, "rssclient|", 10)) {
1184 listing = realloc(listing, strlen(listing) +
1186 strcat(listing, buf);
1187 strcat(listing, "\n");
1191 free(other_listing);
1192 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1197 scr_printf("%s\n", buf);
1199 scr_printf("Wrote %d records.\n", num_recs);
1205 quitting = !modified || boolprompt(
1206 "Quit without saving", 0);
1211 } while (!quitting);
1214 for (i=0; i<num_recs; ++i) free(recs[i]);