3 * More client-side support functions.
4 * Unlike routines.c, some of these DO use global variables.
10 #include <sys/types.h>
18 #if TIME_WITH_SYS_TIME
19 # include <sys/time.h>
23 # include <sys/time.h>
35 #include "citadel_ipc.h"
36 #include "citadel_decls.h"
37 #include "routines2.h"
47 /* work around solaris include files */
53 extern char tempdir[];
54 extern char *axdefs[7];
55 extern long highest_msg_read;
56 extern long maxmsgnum;
57 extern unsigned room_flags;
58 extern int screenwidth;
62 int eopen(char *name, int mode)
65 ret = open(name, mode);
67 err_printf("Cannot open file '%s', mode=%d, errno=%d\n",
76 int room_prompt(unsigned int qrflags)
77 { /* return proper room prompt character */
80 if (qrflags & QR_DIRECTORY)
82 if ((a == ']') && (qrflags & QR_NETWORK))
84 if ((a == '>') && (qrflags & QR_NETWORK))
89 void entregis(CtdlIPC *ipc)
90 { /* register with name and address */
106 int r; /* IPC response code */
111 strcpy(tmpstate, "");
113 strcpy(tmpphone, "");
114 strcpy(tmpemail, "");
115 strcpy(tmpcountry, "");
117 r = CtdlIPCGetUserRegistration(ipc, NULL, ®, buf);
121 while (reg && !IsEmptyStr(reg)) {
123 extract_token(buf, reg, 0, '\n', sizeof buf);
124 remove_token(reg, 0, '\n');
127 safestrncpy(tmpname, buf, sizeof tmpname);
129 safestrncpy(tmpaddr, buf, sizeof tmpaddr);
131 safestrncpy(tmpcity, buf, sizeof tmpcity);
133 safestrncpy(tmpstate, buf, sizeof tmpstate);
135 safestrncpy(tmpzip, buf, sizeof tmpzip);
137 safestrncpy(tmpphone, buf, sizeof tmpphone);
139 safestrncpy(tmpemail, buf, sizeof tmpemail);
141 safestrncpy(tmpcountry, buf, sizeof tmpcountry);
145 strprompt("REAL name", tmpname, 29);
146 strprompt("Address", tmpaddr, 24);
147 strprompt("City/town", tmpcity, 14);
148 strprompt("State/province", tmpstate, 2);
149 strprompt("ZIP/Postal Code", tmpzip, 10);
150 strprompt("Country", tmpcountry, 31);
151 strprompt("Telephone number", tmpphone, 14);
155 safestrncpy(holdemail, tmpemail, sizeof holdemail);
156 strprompt("Email address", tmpemail, 31);
157 r = CtdlIPCDirectoryLookup(ipc, tmpemail, buf);
159 extract_token(diruser, buf, 0, '@', sizeof diruser);
160 extract_token(dirnode, buf, 1, '@', sizeof dirnode);
163 if ((strcasecmp(diruser, fullname))
164 || (strcasecmp(dirnode, ipc->ServInfo.nodename))) {
166 "\nYou can't use %s as your address.\n",
169 "It is already in use by %s @ %s.\n",
172 safestrncpy(tmpemail, holdemail, sizeof tmpemail);
177 /* now send the registration info back to the server */
178 reg = (char *)realloc(reg, SIZ);
180 sprintf(reg, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
181 tmpname, tmpaddr, tmpcity, tmpstate,
182 tmpzip, tmpphone, tmpemail, tmpcountry);
183 r = CtdlIPCSetRegistration(ipc, reg, buf);
185 scr_printf("%s\n", buf);
191 void updatels(CtdlIPC *ipc)
192 { /* make all messages old in current room */
194 int r; /* IPC response code */
196 if (rc_alt_semantics) {
197 if (maxmsgnum == 0 && highest_msg_read == 0) {
200 r = CtdlIPCSetLastRead(ipc, (maxmsgnum > highest_msg_read) ?
201 maxmsgnum : highest_msg_read, buf);
203 r = CtdlIPCSetLastRead(ipc, (maxmsgnum > highest_msg_read) ?
204 maxmsgnum : highest_msg_read, buf);
205 /* r = CtdlIPCSetLastRead(ipc, maxmsgnum, buf); */
206 /* This is a quick-and-dirty fix to all msgs becoming new in Mail>.
207 * It will need to be rethought when messages.c is rewritten.
211 scr_printf("%s\n", buf);
215 * only make messages old in this room that have been read
217 void updatelsa(CtdlIPC *ipc)
220 int r; /* IPC response code */
222 r = CtdlIPCSetLastRead(ipc, highest_msg_read, buf);
224 scr_printf("%s\n", &buf[4]);
229 * client-based uploads (for users with their own clientware)
231 void cli_upload(CtdlIPC *ipc)
237 int r; /* IPC response code */
241 if ((room_flags & QR_UPLOAD) == 0) {
242 scr_printf("*** You cannot upload to this room.\n");
245 newprompt("File to be uploaded: ", flnm, 55);
246 fd = open(flnm, O_RDONLY);
248 scr_printf("Cannot open '%s': %s\n", flnm, strerror(errno));
251 scr_printf("Enter a description of this file:\n");
252 newprompt(": ", desc, 75);
254 /* Keep generating filenames in hope of finding a unique one */
257 /* basename of filename */
259 if (haschar(tbuf, '/'))
260 extract_token(tbuf, flnm,
261 num_tokens(tbuf, '/') - 1,
264 /* filename.1, filename.2, etc */
266 sprintf(&tbuf[strlen(tbuf)], ".%d", a);
269 r = CtdlIPCFileUpload(ipc, tbuf, desc, flnm, progress, buf);
270 if (r / 100 == 5 || r < 0)
271 scr_printf("%s\n", buf);
276 if (a > 0) scr_printf("Saved as '%s'\n", tbuf);
281 * Function used for various image upload commands
283 void cli_image_upload(CtdlIPC *ipc, char *keyname)
289 /* Can we upload this image? */
290 r = CtdlIPCImageUpload(ipc, 0, NULL, keyname, NULL, buf);
292 err_printf("%s\n", buf);
295 newprompt("Image file to be uploaded: ", flnm, 55);
296 r = CtdlIPCImageUpload(ipc, 1, flnm, keyname, progress, buf);
298 err_printf("%s\n", buf);
300 err_printf("Cannot upload '%s': %s\n", flnm, strerror(errno));
302 /* else upload succeeded */
307 * protocol-based uploads (Xmodem, Ymodem, Zmodem)
309 void upload(CtdlIPC *ipc, int c)
310 { /* c = upload mode */
320 if ((room_flags & QR_UPLOAD) == 0) {
321 scr_printf("*** You cannot upload to this room.\n");
324 /* we don't need a filename when receiving batch y/z modem */
325 if ((c == 2) || (c == 3))
328 newprompt("Enter filename: ", flnm, 15);
330 for (a = 0; a < strlen(flnm); ++a)
331 if ((flnm[a] == '/') || (flnm[a] == '\\') || (flnm[a] == '>')
332 || (flnm[a] == '?') || (flnm[a] == '*')
333 || (flnm[a] == ';') || (flnm[a] == '&'))
336 /* create a temporary directory... */
337 if (mkdir(tempdir, 0700) != 0) {
338 scr_printf("*** Could not create temporary directory %s: %s\n",
339 tempdir, strerror(errno));
342 /* now do the transfer ... in a separate process */
349 scr_printf("Receiving %s - press Ctrl-D to end.\n", flnm);
350 fp = fopen(flnm, "w");
366 execlp("rx", "rx", flnm, NULL);
371 execlp("rb", "rb", NULL);
376 execlp("rz", "rz", NULL);
382 } while ((b != xfer_pid) && (b != (-1)));
387 scr_printf("\r*** Transfer unsuccessful.\n");
391 scr_printf("\r*** Transfer successful.\n");
392 snprintf(buf, sizeof buf, "cd %s; ls", tempdir);
393 lsfp = popen(buf, "r");
395 while (fgets(flnm, sizeof flnm, lsfp) != NULL) {
396 flnm[strlen(flnm) - 1] = 0; /* chop newline */
397 snprintf(buf, sizeof buf,
398 "Enter a short description of '%s':\n: ",
400 newprompt(buf, desc, 150);
401 snprintf(buf, sizeof buf, "%s/%s", tempdir, flnm);
402 r = CtdlIPCFileUpload(ipc, flnm, desc, buf, progress, tbuf);
403 scr_printf("%s\n", tbuf);
411 * validate a user (returns 0 for successful validation, nonzero if quitting)
413 int val_user(CtdlIPC *ipc, char *user, int do_validate)
421 int r; /* IPC response code */
424 r = CtdlIPCGetUserRegistration(ipc, user, &resp, cmd);
428 extract_token(buf, resp, 0, '\n', sizeof buf);
429 remove_token(resp, 0, '\n');
432 scr_printf("User #%s - %s ", buf, cmd);
434 scr_printf("PW: %s\n", buf);
436 scr_printf("%s\n", buf);
438 scr_printf("%s\n", buf);
440 scr_printf("%s, ", buf);
442 scr_printf("%s ", buf);
444 scr_printf("%s\n", buf);
446 scr_printf("%s\n", buf);
450 scr_printf("%s\n", buf);
452 scr_printf("%s\n", buf);
453 } while (!IsEmptyStr(resp));
454 scr_printf("Current access level: %d (%s)\n", ax, axdefs[ax]);
456 scr_printf("%s\n%s\n", user, &cmd[4]);
458 if (resp) free(resp);
461 /* now set the access level */
463 sprintf(answer, "%d", ax);
464 strprompt("New access level (? for help, q to quit)",
466 if ((answer[0] >= '0') && (answer[0] <= '6')) {
468 r = CtdlIPCValidateUser(ipc, user, ax, cmd);
470 scr_printf("%s\n\n", cmd);
473 if (tolower(answer[0]) == 'q') {
474 scr_printf("*** Aborted.\n\n");
477 if (answer[0] == '?') {
478 scr_printf("Available access levels:\n");
479 for (a=0; a<7; ++a) {
480 scr_printf("%d - %s\n",
490 void validate(CtdlIPC *ipc)
491 { /* validate new users */
495 int r; /* IPC response code */
498 r = CtdlIPCNextUnvalidatedUser(ipc, cmd);
502 scr_printf("%s\n", cmd);
504 extract_token(buf, cmd, 0, '|', sizeof buf);
505 if (val_user(ipc, buf, 1) != 0) finished = 1;
507 } while (finished == 0);
515 stty_ctdl(SB_RESTORE);
518 signal(SIGINT, SIG_DFL);
519 signal(SIGQUIT, SIG_DFL);
520 execlp(getenv("SHELL"), getenv("SHELL"), NULL);
521 err_printf("Could not open a shell: %s\n", strerror(errno));
526 } while ((a != b) && (a != (-1)));
532 * <.A>ide <F>ile <D>elete command
534 void deletefile(CtdlIPC *ipc)
539 newprompt("Filename: ", filename, 31);
540 if (IsEmptyStr(filename))
542 CtdlIPCDeleteFile(ipc, filename, buf);
543 err_printf("%s\n", buf);
547 * <.A>ide <F>ile <S>end command
549 void netsendfile(CtdlIPC *ipc)
551 char filename[32], destsys[20], buf[256];
553 newprompt("Filename: ", filename, 31);
554 if (IsEmptyStr(filename))
556 newprompt("System to send to: ", destsys, 19);
557 CtdlIPCNetSendFile(ipc, filename, destsys, buf);
558 err_printf("%s\n", buf);
563 * <.A>ide <F>ile <M>ove command
565 void movefile(CtdlIPC *ipc)
568 char newroom[ROOMNAMELEN];
571 newprompt("Filename: ", filename, 63);
572 if (IsEmptyStr(filename))
574 newprompt("Enter target room: ", newroom, ROOMNAMELEN - 1);
575 CtdlIPCMoveFile(ipc, filename, newroom, buf);
576 err_printf("%s\n", buf);
581 * list of users who have filled out a bio
583 void list_bio(CtdlIPC *ipc)
588 int r; /* IPC response code */
590 r = CtdlIPCListUsersWithBios(ipc, &resp, buf);
592 pprintf("%s\n", buf);
595 while (resp && strlen(resp)) {
596 extract_token(buf, resp, 0, '\n', sizeof buf);
597 remove_token(resp, 0, '\n');
598 if ((pos + strlen(buf) + 5) > screenwidth) {
602 pprintf("%s, ", buf);
603 pos = pos + strlen(buf) + 2;
605 pprintf("%c%c \n\n", 8, 8);
606 if (resp) free(resp);
613 void read_bio(CtdlIPC *ipc)
618 int r; /* IPC response code */
621 newprompt("Read bio for who ('?' for list) : ", who, 25);
623 if (!strcmp(who, "?"))
625 } while (!strcmp(who, "?"));
627 r = CtdlIPCGetBio(ipc, who, &resp, buf);
629 pprintf("%s\n", buf);
632 while (!IsEmptyStr(resp)) {
633 extract_token(buf, resp, 0, '\n', sizeof buf);
634 remove_token(resp, 0, '\n');
635 pprintf("%s\n", buf);
637 if (resp) free(resp);
642 * General system configuration command
644 void do_system_configuration(CtdlIPC *ipc)
647 #define NUM_CONFIGS 58
650 char sc[NUM_CONFIGS][256];
652 struct ExpirePolicy *site_expirepolicy = NULL;
653 struct ExpirePolicy *mbx_expirepolicy = NULL;
656 int r; /* IPC response code */
657 int server_configs = 0;
659 /* Clear out the config buffers */
660 memset(&sc[0][0], 0, sizeof(sc));
662 /* Fetch the current config */
663 r = CtdlIPCGetSystemConfig(ipc, &resp, buf);
665 server_configs = num_tokens(resp, '\n');
666 for (a=0; a<server_configs; ++a) {
667 if (a < NUM_CONFIGS) {
668 extract_token(&sc[a][0], resp, a, '\n', sizeof sc[a]);
672 if (resp) free(resp);
674 /* Fetch the expire policy (this will silently fail on old servers,
675 * resulting in "default" policy)
677 r = CtdlIPCGetMessageExpirationPolicy(ipc, 2, &site_expirepolicy, buf);
678 r = CtdlIPCGetMessageExpirationPolicy(ipc, 3, &mbx_expirepolicy, buf);
680 /* Identification parameters */
682 strprompt("Node name", &sc[0][0], 15);
683 strprompt("Fully qualified domain name", &sc[1][0], 63);
684 strprompt("Human readable node name", &sc[2][0], 20);
685 strprompt("Telephone number", &sc[3][0], 15);
686 strprompt("Geographic location of this system", &sc[12][0], 31);
687 strprompt("Name of system administrator", &sc[13][0], 25);
688 strprompt("Paginator prompt", &sc[10][0], 79);
690 /* Security parameters */
692 snprintf(sc[7], sizeof sc[7], "%d", (boolprompt(
693 "Require registration for new users",
695 snprintf(sc[29], sizeof sc[29], "%d", (boolprompt(
696 "Disable self-service user account creation",
698 strprompt("Initial access level for new users", &sc[6][0], 1);
699 strprompt("Access level required to create rooms", &sc[19][0], 1);
700 snprintf(sc[4], sizeof sc[4], "%d", (boolprompt(
701 "Automatically give room aide privs to a user who creates a private room",
704 snprintf(sc[8], sizeof sc[8], "%d", (boolprompt(
705 "Automatically move problem user messages to twit room",
708 strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
709 snprintf(sc[11], sizeof sc[11], "%d", (boolprompt(
710 "Restrict Internet mail to only those with that privilege",
712 snprintf(sc[26], sizeof sc[26], "%d", (boolprompt(
713 "Allow Aides to Zap (forget) rooms",
716 if (!IsEmptyStr(&sc[18][0])) logpages = 1;
718 logpages = boolprompt("Log all pages", logpages);
720 strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
726 /* Commented out because this setting isn't really appropriate to
727 * change while the server is running.
729 * snprintf(sc[52], sizeof sc[52], "%d", (boolprompt(
730 * "Use system authentication",
731 * atoi(&sc[52][0]))));
736 strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
737 strprompt("Maximum concurrent sessions", &sc[14][0], 4);
738 strprompt("Maximum message length", &sc[20][0], 20);
739 strprompt("Minimum number of worker threads", &sc[21][0], 3);
740 strprompt("Maximum number of worker threads", &sc[22][0], 3);
741 snprintf(sc[43], sizeof sc[43], "%d", (boolprompt(
742 "Automatically delete committed database logs",
745 strprompt("Server IP address (0.0.0.0 for 'any')", &sc[37][0], 15);
746 strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
747 strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5);
748 strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
749 strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5);
750 strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5);
751 strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5);
752 strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5);
753 strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5);
754 strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5);
755 /* This logic flips the question around, because it's one of those
756 * situations where 0=yes and 1=no
760 a = boolprompt("Correct forged From: lines during authenticated SMTP",
763 snprintf(sc[25], sizeof sc[25], "%d", a);
764 snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
765 "Allow unauthenticated SMTP clients to spoof my domains",
767 snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
768 "Perform RBL checks at greeting instead of after RCPT",
770 snprintf(sc[44], sizeof sc[44], "%d", (boolprompt(
771 "Instantly expunge deleted IMAP messages",
775 if (ipc->ServInfo.supports_ldap) {
776 a = strlen(&sc[32][0]);
777 a = (a ? 1 : 0); /* Set only to 1 or 0 */
778 a = boolprompt("Connect this Citadel to an LDAP directory", a);
780 strprompt("Host name of LDAP server",
782 strprompt("Port number of LDAP service",
784 strprompt("Base DN", &sc[34][0], 255);
785 strprompt("Bind DN", &sc[35][0], 255);
786 strprompt("Password for bind DN", &sc[36][0], 255);
789 strcpy(&sc[32][0], "");
793 /* Expiry settings */
794 strprompt("Default user purge time (days)", &sc[16][0], 5);
795 strprompt("Default room purge time (days)", &sc[17][0], 5);
797 /* Angels and demons dancing in my head... */
799 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
800 strprompt("System default message expire policy (? for list)",
804 "1. Never automatically expire messages\n"
805 "2. Expire by message count\n"
806 "3. Expire by message age\n");
808 } while ((buf[0] < '1') || (buf[0] > '3'));
809 site_expirepolicy->expire_mode = buf[0] - '0';
811 /* ...lunatics and monsters underneath my bed */
812 if (site_expirepolicy->expire_mode == 2) {
813 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
814 strprompt("Keep how many messages online?", buf, 10);
815 site_expirepolicy->expire_value = atol(buf);
817 if (site_expirepolicy->expire_mode == 3) {
818 snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
819 strprompt("Keep messages for how many days?", buf, 10);
820 site_expirepolicy->expire_value = atol(buf);
823 /* Media messiahs preying on my fears... */
825 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
826 strprompt("Mailbox default message expire policy (? for list)",
830 "0. Go with the system default\n"
831 "1. Never automatically expire messages\n"
832 "2. Expire by message count\n"
833 "3. Expire by message age\n");
835 } while ((buf[0] < '0') || (buf[0] > '3'));
836 mbx_expirepolicy->expire_mode = buf[0] - '0';
838 /* ...Pop culture prophets playing in my ears */
839 if (mbx_expirepolicy->expire_mode == 2) {
840 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
841 strprompt("Keep how many messages online?", buf, 10);
842 mbx_expirepolicy->expire_value = atol(buf);
844 if (mbx_expirepolicy->expire_mode == 3) {
845 snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
846 strprompt("Keep messages for how many days?", buf, 10);
847 mbx_expirepolicy->expire_value = atol(buf);
850 strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
851 strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
852 snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
853 "Enable full text search index (warning: resource intensive)",
856 snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
857 "Perform journaling of email messages",
859 snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
860 "Perform journaling of non-email messages",
862 if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
863 strprompt("Email destination of journalized messages",
867 /* Funambol push stuff */
868 strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
869 strprompt("Funambol server port", &sc[54][0], 5);
870 strprompt("Funambol sync source", &sc[55][0], 63);
871 strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
874 scr_printf("Save this configuration? ");
877 for (a = 0; a < NUM_CONFIGS; a++)
878 r += 1 + strlen(sc[a]);
879 resp = (char *)calloc(1, r);
881 err_printf("Can't save config - out of memory!\n");
884 for (a = 0; a < NUM_CONFIGS; a++) {
888 r = CtdlIPCSetSystemConfig(ipc, resp, buf);
890 err_printf("%s\n", buf);
894 r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
896 err_printf("%s\n", buf);
899 r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
901 err_printf("%s\n", buf);
905 if (site_expirepolicy) free(site_expirepolicy);
906 if (mbx_expirepolicy) free(mbx_expirepolicy);
911 * support function for do_internet_configuration()
913 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
916 keyopt(" <1> localhost (Alias for this computer)\n");
917 keyopt(" <2> gateway domain (Domain for all Citadel systems)\n");
918 keyopt(" <3> smart-host (Forward all outbound mail to this host)\n");
919 keyopt(" <4> directory (Consult the Global Address Book)\n");
920 keyopt(" <5> SpamAssassin (Address of SpamAssassin server)\n");
921 keyopt(" <6> RBL (domain suffix of spam hunting RBL)\n");
922 keyopt(" <7> masq domains (Domains as which users are allowed to masquerade)\n");
923 sel = intprompt("Which one", 1, 1, 6);
925 case 1: strcpy(buf, "localhost");
927 case 2: strcpy(buf, "gatewaydomain");
929 case 3: strcpy(buf, "smarthost");
931 case 4: strcpy(buf, "directory");
933 case 5: strcpy(buf, "spamassassin");
935 case 6: strcpy(buf, "rbl");
937 case 7: strcpy(buf, "masqdomain");
944 * Internet mail configuration
946 void do_internet_configuration(CtdlIPC *ipc)
959 r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
961 while (!IsEmptyStr(resp)) {
962 extract_token(buf, resp, 0, '\n', sizeof buf);
963 remove_token(resp, 0, '\n');
965 if (num_recs == 1) recs = malloc(sizeof(char *));
966 else recs = realloc(recs, (sizeof(char *)) * num_recs);
967 recs[num_recs-1] = malloc(strlen(buf) + 1);
968 strcpy(recs[num_recs-1], buf);
971 if (resp) free(resp);
976 scr_printf("### Host or domain Record type \n");
978 scr_printf("--- -------------------------------------------------- --------------------\n");
979 for (i=0; i<num_recs; ++i) {
981 scr_printf("%3d ", i+1);
982 extract_token(buf, recs[i], 0, '|', sizeof buf);
984 scr_printf("%-50s ", buf);
985 extract_token(buf, recs[i], 1, '|', sizeof buf);
986 color(BRIGHT_MAGENTA);
987 scr_printf("%-20s\n", buf);
991 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
994 newprompt("Enter host name: ",
997 if (!IsEmptyStr(buf)) {
1000 recs = malloc(sizeof(char *));
1001 else recs = realloc(recs,
1002 (sizeof(char *)) * num_recs);
1004 get_inet_rec_type(ipc,
1006 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]);
1023 resp = (char *)calloc(1, r);
1025 err_printf("Can't save config - out of memory!\n");
1028 if (num_recs) for (i = 0; i < num_recs; i++) {
1029 strcat(resp, recs[i]);
1032 r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
1034 err_printf("%s\n", buf);
1036 scr_printf("Wrote %d records.\n", num_recs);
1042 quitting = !modified || boolprompt(
1043 "Quit without saving", 0);
1048 } while (!quitting);
1051 for (i=0; i<num_recs; ++i) free(recs[i]);
1059 * Edit network configuration for room sharing, mailing lists, etc.
1061 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
1063 char filename[PATH_MAX];
1064 char changefile[PATH_MAX];
1074 char *listing = NULL;
1077 if (IsEmptyStr(editor_paths[0])) {
1078 scr_printf("You must have an external editor configured in"
1079 " order to use this function.\n");
1083 CtdlMakeTempFileName(filename, sizeof filename);
1084 CtdlMakeTempFileName(changefile, sizeof changefile);
1086 tempfp = fopen(filename, "w");
1087 if (tempfp == NULL) {
1088 err_printf("Cannot open %s: %s\n", filename, strerror(errno));
1092 fprintf(tempfp, "# Configuration for room: %s\n", room_name);
1093 fprintf(tempfp, "# %s\n", comment);
1094 fprintf(tempfp, "# Specify one per line.\n"
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, entrytype)) {
1104 tokens = num_tokens(buf, '|');
1105 for (i=1; i<tokens; ++i) {
1106 extract_token(addr, buf, i, '|', sizeof addr);
1107 fprintf(tempfp, "%s", addr);
1108 if (i < (tokens-1)) {
1109 fprintf(tempfp, "|");
1112 fprintf(tempfp, "\n");
1122 e_ex_code = 1; /* start with a failed exit code */
1124 stty_ctdl(SB_RESTORE);
1125 editor_pid = fork();
1126 cksum = file_checksum(filename);
1127 if (editor_pid == 0) {
1128 chmod(filename, 0600);
1129 putenv("WINDOW_TITLE=Network configuration");
1130 execlp(editor_paths[0], editor_paths[0], filename, NULL);
1133 if (editor_pid > 0) {
1136 b = ka_wait(&e_ex_code);
1137 } while ((b != editor_pid) && (b >= 0));
1143 if (file_checksum(filename) == cksum) {
1144 err_printf("*** No changes to save.\n");
1148 if (e_ex_code == 0) { /* Save changes */
1149 changefp = fopen(changefile, "w");
1151 /* Load all netconfig entries that are *not* of the type we are editing */
1152 r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
1154 while(listing && !IsEmptyStr(listing)) {
1155 extract_token(buf, listing, 0, '\n', sizeof buf);
1156 remove_token(listing, 0, '\n');
1157 extract_token(instr, buf, 0, '|', sizeof instr);
1158 if (strcasecmp(instr, entrytype)) {
1159 fprintf(changefp, "%s\n", buf);
1168 /* ...and merge that with the data we just edited */
1169 tempfp = fopen(filename, "r");
1170 while (fgets(buf, sizeof buf, tempfp) != NULL) {
1171 for (i=0; i<strlen(buf); ++i) {
1172 if (buf[i] == '#') buf[i] = 0;
1175 if (!IsEmptyStr(buf)) {
1176 fprintf(changefp, "%s|%s\n", entrytype, buf);
1182 /* now write it to the server... */
1183 changefp = fopen(changefile, "r");
1184 if (changefp != NULL) {
1185 listing = load_message_from_file(changefp);
1187 r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
1195 unlink(filename); /* Delete the temporary files */
1201 * IGnet node configuration
1203 void do_ignet_configuration(CtdlIPC *ipc) {
1212 char *listing = NULL;
1215 r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
1216 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
1217 extract_token(buf, listing, 0, '\n', sizeof buf);
1218 remove_token(listing, 0, '\n');
1221 if (num_recs == 1) recs = malloc(sizeof(char *));
1222 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1223 recs[num_recs-1] = malloc(SIZ);
1224 strcpy(recs[num_recs-1], buf);
1226 if (listing) free(listing);
1230 color(BRIGHT_WHITE);
1239 "------------------ "
1240 "-------------------------------- "
1242 for (i=0; i<num_recs; ++i) {
1244 scr_printf("%3d ", i+1);
1245 extract_token(buf, recs[i], 0, '|', sizeof buf);
1247 scr_printf("%-16s ", buf);
1248 extract_token(buf, recs[i], 1, '|', sizeof buf);
1249 color(BRIGHT_MAGENTA);
1250 scr_printf("%-18s ", buf);
1251 extract_token(buf, recs[i], 2, '|', sizeof buf);
1253 scr_printf("%-32s ", buf);
1254 extract_token(buf, recs[i], 3, '|', sizeof buf);
1255 color(BRIGHT_MAGENTA);
1256 scr_printf("%-3s\n", buf);
1261 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1266 recs = malloc(sizeof(char *));
1267 else recs = realloc(recs,
1268 (sizeof(char *)) * num_recs);
1269 newprompt("Enter node name : ", buf, 16);
1271 newprompt("Enter shared secret: ",
1272 &buf[strlen(buf)], 18);
1274 newprompt("Enter host or IP : ",
1275 &buf[strlen(buf)], 32);
1276 strcat(buf, "|504");
1277 strprompt("Enter port number : ",
1278 &buf[strlen(buf)-3], 5);
1279 recs[num_recs-1] = strdup(buf);
1283 i = intprompt("Delete which one",
1284 1, 1, num_recs) - 1;
1287 for (j=i; j<num_recs; ++j)
1288 recs[j] = recs[j+1];
1293 for (i = 0; i < num_recs; ++i)
1294 r += 1 + strlen(recs[i]);
1295 listing = (char*) calloc(1, r);
1297 err_printf("Can't save config - out of memory!\n");
1300 if (num_recs) for (i = 0; i < num_recs; ++i) {
1301 strcat(listing, recs[i]);
1302 strcat(listing, "\n");
1304 r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
1306 scr_printf("%s\n", buf);
1308 scr_printf("Wrote %d records.\n", num_recs);
1314 quitting = !modified || boolprompt(
1315 "Quit without saving", 0);
1320 } while (!quitting);
1323 for (i=0; i<num_recs; ++i) free(recs[i]);
1329 * Filter list configuration
1331 void do_filterlist_configuration(CtdlIPC *ipc)
1341 char *listing = NULL;
1344 r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
1345 if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
1346 extract_token(buf, listing, 0, '\n', sizeof buf);
1347 remove_token(listing, 0, '\n');
1350 if (num_recs == 1) recs = malloc(sizeof(char *));
1351 else recs = realloc(recs, (sizeof(char *)) * num_recs);
1352 recs[num_recs-1] = malloc(SIZ);
1353 strcpy(recs[num_recs-1], buf);
1355 if (listing) free(listing);
1359 color(BRIGHT_WHITE);
1367 "---------------------------- "
1368 "---------------------------- "
1371 for (i=0; i<num_recs; ++i) {
1373 scr_printf("%3d ", i+1);
1374 extract_token(buf, recs[i], 0, '|', sizeof buf);
1376 scr_printf("%-28s ", buf);
1377 extract_token(buf, recs[i], 1, '|', sizeof buf);
1378 color(BRIGHT_MAGENTA);
1379 scr_printf("%-28s ", buf);
1380 extract_token(buf, recs[i], 2, '|', sizeof buf);
1382 scr_printf("%-16s\n", buf);
1383 extract_token(buf, recs[i], 3, '|', sizeof buf);
1387 ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
1392 recs = malloc(sizeof(char *));
1393 else recs = realloc(recs,
1394 (sizeof(char *)) * num_recs);
1395 newprompt("Enter user name: ", buf, 28);
1397 newprompt("Enter room name: ",
1398 &buf[strlen(buf)], 28);
1400 newprompt("Enter node name: ",
1401 &buf[strlen(buf)], 16);
1403 recs[num_recs-1] = strdup(buf);
1407 i = intprompt("Delete which one",
1408 1, 1, num_recs) - 1;
1411 for (j=i; j<num_recs; ++j)
1412 recs[j] = recs[j+1];
1417 for (i = 0; i < num_recs; ++i)
1418 r += 1 + strlen(recs[i]);
1419 listing = (char*) calloc(1, r);
1421 err_printf("Can't save config - out of memory!\n");
1424 if (num_recs) for (i = 0; i < num_recs; ++i) {
1425 strcat(listing, recs[i]);
1426 strcat(listing, "\n");
1428 r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
1430 scr_printf("%s\n", buf);
1432 scr_printf("Wrote %d records.\n", num_recs);
1438 quitting = !modified || boolprompt(
1439 "Quit without saving", 0);
1444 } while (!quitting);
1447 for (i=0; i<num_recs; ++i) free(recs[i]);