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> directory (Consult the Global Address Book)\n");
387 keyopt(" <5> SpamAssassin (Address of SpamAssassin server)\n");
388 keyopt(" <6> RBL (domain suffix of spam hunting RBL)\n");
389 keyopt(" <7> masq domains (Domains as which users are allowed to masquerade)\n");
390 keyopt(" <8> ClamAV (Address of ClamAV clamd server)\n");
391 sel = intprompt("Which one", 1, 1, 8);
393 case 1: strcpy(buf, "localhost");
395 case 2: strcpy(buf, "smarthost");
397 case 3: strcpy(buf, "fallbackhost");
399 case 4: strcpy(buf, "directory");
401 case 5: strcpy(buf, "spamassassin");
403 case 6: strcpy(buf, "rbl");
405 case 7: strcpy(buf, "masqdomain");
407 case 8: strcpy(buf, "clamav");
414 * Internet mail configuration
416 void do_internet_configuration(CtdlIPC *ipc)
428 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
430 while (!IsEmptyStr(resp)) {
431 extract_token(buf, resp, 0, '\n', sizeof buf);
432 remove_token(resp, 0, '\n');
434 if (num_recs == 1) recs = malloc(sizeof(char *));
435 else recs = realloc(recs, (sizeof(char *)) * num_recs);
436 recs[num_recs-1] = malloc(strlen(buf) + 1);
437 strcpy(recs[num_recs-1], buf);
440 if (resp) free(resp);
445 scr_printf("### Host or domain Record type \n");
447 scr_printf("--- -------------------------------------------------- --------------------\n");
448 for (i=0; i<num_recs; ++i) {
450 scr_printf("%3d ", i+1);
451 extract_token(buf, recs[i], 0, '|', sizeof buf);
453 scr_printf("%-50s ", buf);
454 extract_token(buf, recs[i], 1, '|', sizeof buf);
455 color(BRIGHT_MAGENTA);
456 scr_printf("%-20s\n", buf);
460 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
463 newprompt("Enter host name: ",
466 if (!IsEmptyStr(buf)) {
469 recs = malloc(sizeof(char *));
470 else recs = realloc(recs,
471 (sizeof(char *)) * num_recs);
473 get_inet_rec_type(ipc,
475 recs[num_recs-1] = strdup(buf);
480 i = intprompt("Delete which one",
484 for (j=i; j<num_recs; ++j)
490 for (i = 0; i < num_recs; i++)
491 r += 1 + strlen(recs[i]);
492 resp = (char *)calloc(1, r);
494 scr_printf("Can't save config - out of memory!\n");
497 if (num_recs) for (i = 0; i < num_recs; i++) {
498 strcat(resp, recs[i]);
501 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
503 scr_printf("%s\n", buf);
505 scr_printf("Wrote %d records.\n", num_recs);
511 quitting = !modified || boolprompt(
512 "Quit without saving", 0);
520 for (i=0; i<num_recs; ++i) free(recs[i]);
528 * Edit network configuration for room sharing, mailing lists, etc.
530 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
532 char filename[PATH_MAX];
533 char changefile[PATH_MAX];
543 char *listing = NULL;
546 if (IsEmptyStr(editor_path)) {
547 scr_printf("You must have an external editor configured in order to use this function.\n");
551 CtdlMakeTempFileName(filename, sizeof filename);
552 CtdlMakeTempFileName(changefile, sizeof changefile);
554 tempfp = fopen(filename, "w");
555 if (tempfp == NULL) {
556 scr_printf("Cannot open %s: %s\n", filename, strerror(errno));
560 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
561 fprintf(tempfp, "# %s\n", comment);
562 fprintf(tempfp, "# Specify one per line.\n"
565 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
567 while(listing && !IsEmptyStr(listing)) {
568 extract_token(buf, listing, 0, '\n', sizeof buf);
569 remove_token(listing, 0, '\n');
570 extract_token(instr, buf, 0, '|', sizeof instr);
571 if (!strcasecmp(instr, entrytype)) {
572 tokens = num_tokens(buf, '|');
573 for (i=1; i<tokens; ++i) {
574 extract_token(addr, buf, i, '|', sizeof addr);
575 fprintf(tempfp, "%s", addr);
576 if (i < (tokens-1)) {
577 fprintf(tempfp, "|");
580 fprintf(tempfp, "\n");
590 e_ex_code = 1; /* start with a failed exit code */
591 stty_ctdl(SB_RESTORE);
593 cksum = file_checksum(filename);
594 if (editor_pid == 0) {
595 chmod(filename, 0600);
596 putenv("WINDOW_TITLE=Network configuration");
597 execlp(editor_path, editor_path, filename, NULL);
600 if (editor_pid > 0) {
603 b = ka_wait(&e_ex_code);
604 } while ((b != editor_pid) && (b >= 0));
609 if (file_checksum(filename) == cksum) {
610 scr_printf("*** No changes to save.\n");
614 if (e_ex_code == 0) { /* Save changes */
615 changefp = fopen(changefile, "w");
617 /* Load all netconfig entries that are *not* of the type we are editing */
618 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
620 while(listing && !IsEmptyStr(listing)) {
621 extract_token(buf, listing, 0, '\n', sizeof buf);
622 remove_token(listing, 0, '\n');
623 extract_token(instr, buf, 0, '|', sizeof instr);
624 if (strcasecmp(instr, entrytype)) {
625 fprintf(changefp, "%s\n", buf);
634 /* ...and merge that with the data we just edited */
635 tempfp = fopen(filename, "r");
636 while (fgets(buf, sizeof buf, tempfp) != NULL) {
637 for (i=0; i<strlen(buf); ++i) {
638 if (buf[i] == '#') buf[i] = 0;
641 if (!IsEmptyStr(buf)) {
642 fprintf(changefp, "%s|%s\n", entrytype, buf);
648 /* now write it to the server... */
649 changefp = fopen(changefile, "r");
650 if (changefp != NULL) {
651 listing = load_message_from_file(changefp);
653 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
661 unlink(filename); /* Delete the temporary files */
667 * IGnet node configuration
669 void do_ignet_configuration(CtdlIPC *ipc) {
677 char *listing = NULL;
680 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
681 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
682 extract_token(buf, listing, 0, '\n', sizeof buf);
683 remove_token(listing, 0, '\n');
686 if (num_recs == 1) recs = malloc(sizeof(char *));
687 else recs = realloc(recs, (sizeof(char *)) * num_recs);
688 recs[num_recs-1] = malloc(SIZ);
689 strcpy(recs[num_recs-1], buf);
691 if (listing) free(listing);
704 "------------------ "
705 "-------------------------------- "
707 for (i=0; i<num_recs; ++i) {
709 scr_printf("%3d ", i+1);
710 extract_token(buf, recs[i], 0, '|', sizeof buf);
712 scr_printf("%-16s ", buf);
713 extract_token(buf, recs[i], 1, '|', sizeof buf);
714 color(BRIGHT_MAGENTA);
715 scr_printf("%-18s ", buf);
716 extract_token(buf, recs[i], 2, '|', sizeof buf);
718 scr_printf("%-32s ", buf);
719 extract_token(buf, recs[i], 3, '|', sizeof buf);
720 color(BRIGHT_MAGENTA);
721 scr_printf("%-3s\n", buf);
726 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
731 recs = malloc(sizeof(char *));
732 else recs = realloc(recs,
733 (sizeof(char *)) * num_recs);
734 newprompt("Enter node name : ", buf, 16);
736 newprompt("Enter shared secret: ",
737 &buf[strlen(buf)], 18);
739 newprompt("Enter host or IP : ",
740 &buf[strlen(buf)], 32);
742 strprompt("Enter port number : ",
743 &buf[strlen(buf)-3], 5);
744 recs[num_recs-1] = strdup(buf);
748 i = intprompt("Delete which one",
752 for (j=i; j<num_recs; ++j)
758 for (i = 0; i < num_recs; ++i)
759 r += 1 + strlen(recs[i]);
760 listing = (char*) calloc(1, r);
762 scr_printf("Can't save config - out of memory!\n");
765 if (num_recs) for (i = 0; i < num_recs; ++i) {
766 strcat(listing, recs[i]);
767 strcat(listing, "\n");
769 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
771 scr_printf("%s\n", buf);
773 scr_printf("Wrote %d records.\n", num_recs);
779 quitting = !modified || boolprompt(
780 "Quit without saving", 0);
788 for (i=0; i<num_recs; ++i) free(recs[i]);
795 * Filter list configuration
797 void do_filterlist_configuration(CtdlIPC *ipc)
806 char *listing = NULL;
809 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
810 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
811 extract_token(buf, listing, 0, '\n', sizeof buf);
812 remove_token(listing, 0, '\n');
815 if (num_recs == 1) recs = malloc(sizeof(char *));
816 else recs = realloc(recs, (sizeof(char *)) * num_recs);
817 recs[num_recs-1] = malloc(SIZ);
818 strcpy(recs[num_recs-1], buf);
820 if (listing) free(listing);
832 "---------------------------- "
833 "---------------------------- "
836 for (i=0; i<num_recs; ++i) {
838 scr_printf("%3d ", i+1);
839 extract_token(buf, recs[i], 0, '|', sizeof buf);
841 scr_printf("%-28s ", buf);
842 extract_token(buf, recs[i], 1, '|', sizeof buf);
843 color(BRIGHT_MAGENTA);
844 scr_printf("%-28s ", buf);
845 extract_token(buf, recs[i], 2, '|', sizeof buf);
847 scr_printf("%-16s\n", buf);
848 extract_token(buf, recs[i], 3, '|', sizeof buf);
852 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
857 recs = malloc(sizeof(char *));
858 else recs = realloc(recs,
859 (sizeof(char *)) * num_recs);
860 newprompt("Enter user name: ", buf, 28);
862 newprompt("Enter room name: ",
863 &buf[strlen(buf)], 28);
865 newprompt("Enter node name: ",
866 &buf[strlen(buf)], 16);
868 recs[num_recs-1] = strdup(buf);
872 i = intprompt("Delete which one",
876 for (j=i; j<num_recs; ++j)
882 for (i = 0; i < num_recs; ++i)
883 r += 1 + strlen(recs[i]);
884 listing = (char*) calloc(1, r);
886 scr_printf("Can't save config - out of memory!\n");
889 if (num_recs) for (i = 0; i < num_recs; ++i) {
890 strcat(listing, recs[i]);
891 strcat(listing, "\n");
893 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
895 scr_printf("%s\n", buf);
897 scr_printf("Wrote %d records.\n", num_recs);
903 quitting = !modified || boolprompt(
904 "Quit without saving", 0);
912 for (i=0; i<num_recs; ++i) free(recs[i]);
921 * POP3 aggregation client configuration
923 void do_pop3client_configuration(CtdlIPC *ipc)
932 char *listing = NULL;
933 char *other_listing = NULL;
937 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
939 while(listing && !IsEmptyStr(listing)) {
940 extract_token(buf, listing, 0, '\n', sizeof buf);
941 remove_token(listing, 0, '\n');
942 extract_token(instr, buf, 0, '|', sizeof instr);
943 if (!strcasecmp(instr, "pop3client")) {
946 if (num_recs == 1) recs = malloc(sizeof(char *));
947 else recs = realloc(recs, (sizeof(char *)) * num_recs);
948 recs[num_recs-1] = malloc(SIZ);
949 strcpy(recs[num_recs-1], buf);
969 "---------------------------- "
970 "---------------------------- "
973 for (i=0; i<num_recs; ++i) {
975 scr_printf("%3d ", i+1);
977 extract_token(buf, recs[i], 1, '|', sizeof buf);
979 scr_printf("%-28s ", buf);
981 extract_token(buf, recs[i], 2, '|', sizeof buf);
982 color(BRIGHT_MAGENTA);
983 scr_printf("%-28s ", buf);
986 scr_printf("%-15s\n", (extract_int(recs[i], 4) ? "Yes" : "No") );
990 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
995 recs = malloc(sizeof(char *));
998 recs = realloc(recs, (sizeof(char *)) * num_recs);
1000 strcpy(buf, "pop3client|");
1001 newprompt("Enter host name: ", &buf[strlen(buf)], 28);
1003 newprompt("Enter user name: ", &buf[strlen(buf)], 28);
1005 newprompt("Enter password : ", &buf[strlen(buf)], 16);
1007 scr_printf("Keep messages on server instead of deleting them? ");
1008 sprintf(&buf[strlen(buf)], "%d", yesno());
1010 recs[num_recs-1] = strdup(buf);
1014 i = intprompt("Delete which one",
1015 1, 1, num_recs) - 1;
1018 for (j=i; j<num_recs; ++j)
1019 recs[j] = recs[j+1];
1024 for (i = 0; i < num_recs; ++i) {
1025 r += 1 + strlen(recs[i]);
1027 listing = (char*) calloc(1, r);
1029 scr_printf("Can't save config - out of memory!\n");
1032 if (num_recs) for (i = 0; i < num_recs; ++i) {
1033 strcat(listing, recs[i]);
1034 strcat(listing, "\n");
1037 /* Retrieve all the *other* records for merging */
1038 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1040 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1041 extract_token(buf, other_listing, i, '\n', sizeof buf);
1042 if (strncasecmp(buf, "pop3client|", 11)) {
1043 listing = realloc(listing, strlen(listing) +
1045 strcat(listing, buf);
1046 strcat(listing, "\n");
1050 free(other_listing);
1051 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1056 scr_printf("%s\n", buf);
1058 scr_printf("Wrote %d records.\n", num_recs);
1064 quitting = !modified || boolprompt(
1065 "Quit without saving", 0);
1070 } while (!quitting);
1073 for (i=0; i<num_recs; ++i) free(recs[i]);
1084 * RSS feed retrieval client configuration
1086 void do_rssclient_configuration(CtdlIPC *ipc)
1095 char *listing = NULL;
1096 char *other_listing = NULL;
1100 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1102 while(listing && !IsEmptyStr(listing)) {
1103 extract_token(buf, listing, 0, '\n', sizeof buf);
1104 remove_token(listing, 0, '\n');
1105 extract_token(instr, buf, 0, '|', sizeof instr);
1106 if (!strcasecmp(instr, "rssclient")) {
1109 if (num_recs == 1) recs = malloc(sizeof(char *));
1110 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1111 recs[num_recs-1] = malloc(SIZ);
1112 strcpy(recs[num_recs-1], buf);
1124 color(BRIGHT_WHITE);
1125 scr_printf("### Feed URL\n");
1128 "---------------------------------------------------------------------------"
1131 for (i=0; i<num_recs; ++i) {
1133 scr_printf("%3d ", i+1);
1135 extract_token(buf, recs[i], 1, '|', sizeof buf);
1137 scr_printf("%-75s\n", buf);
1142 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1146 if (num_recs == 1) {
1147 recs = malloc(sizeof(char *));
1150 recs = realloc(recs, (sizeof(char *)) * num_recs);
1152 strcpy(buf, "rssclient|");
1153 newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
1155 recs[num_recs-1] = strdup(buf);
1159 i = intprompt("Delete which one", 1, 1, num_recs) - 1;
1162 for (j=i; j<num_recs; ++j)
1163 recs[j] = recs[j+1];
1168 for (i = 0; i < num_recs; ++i) {
1169 r += 1 + strlen(recs[i]);
1171 listing = (char*) calloc(1, r);
1173 scr_printf("Can't save config - out of memory!\n");
1176 if (num_recs) for (i = 0; i < num_recs; ++i) {
1177 strcat(listing, recs[i]);
1178 strcat(listing, "\n");
1181 /* Retrieve all the *other* records for merging */
1182 r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
1184 for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
1185 extract_token(buf, other_listing, i, '\n', sizeof buf);
1186 if (strncasecmp(buf, "rssclient|", 10)) {
1187 listing = realloc(listing, strlen(listing) +
1189 strcat(listing, buf);
1190 strcat(listing, "\n");
1194 free(other_listing);
1195 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1200 scr_printf("%s\n", buf);
1202 scr_printf("Wrote %d records.\n", num_recs);
1208 quitting = !modified || boolprompt(
1209 "Quit without saving", 0);
1214 } while (!quitting);
1217 for (i=0; i<num_recs; ++i) free(recs[i]);