Back to index

citadel  8.12
tuiconfig.c
Go to the documentation of this file.
00001 /*
00002  * Configuration screens that are part of the text mode client.
00003  *
00004  * Copyright (c) 1987-2012 by the citadel.org team
00005  *
00006  * This program is open source software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License version 3.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  */
00014 
00015 #include <stdlib.h>
00016 #include <unistd.h>
00017 #include <sys/types.h>
00018 #include <sys/stat.h>
00019 #include <fcntl.h>
00020 #include <stdio.h>
00021 #include <ctype.h>
00022 #include <string.h>
00023 #include <limits.h>
00024 
00025 #if TIME_WITH_SYS_TIME
00026 # include <sys/time.h>
00027 # include <time.h>
00028 #else
00029 # if HAVE_SYS_TIME_H
00030 #  include <sys/time.h>
00031 # else
00032 #  include <time.h>
00033 # endif
00034 #endif
00035 
00036 #include <signal.h>
00037 #include <pwd.h>
00038 #include <errno.h>
00039 #include <stdarg.h>
00040 #include <libcitadel.h>
00041 #include "sysdep.h"
00042 #include "citadel.h"
00043 #include "citadel_ipc.h"
00044 #include "citadel_decls.h"
00045 #include "tuiconfig.h"
00046 #include "messages.h"
00047 #include "routines.h"
00048 #include "commands.h"
00049 #ifndef HAVE_SNPRINTF
00050 #include "snprintf.h"
00051 #endif
00052 #include "screen.h"
00053 
00054 /* work around solaris include files */
00055 #ifdef reg
00056 #undef reg
00057 #endif
00058 
00059 extern char temp[];
00060 extern char tempdir[];
00061 extern char *axdefs[8];
00062 extern long highest_msg_read;
00063 extern long maxmsgnum;
00064 extern unsigned room_flags;
00065 extern int screenwidth;
00066 char editor_path[PATH_MAX];
00067 
00068 
00069 /* 
00070  * General system configuration command
00071  */
00072 void do_system_configuration(CtdlIPC *ipc)
00073 {
00074 
00075        /* NUM_CONFIGS is now defined in citadel.h */
00076 
00077        char buf[256];
00078        char sc[NUM_CONFIGS][256];
00079        char *resp = NULL;
00080        struct ExpirePolicy *site_expirepolicy = NULL;
00081        struct ExpirePolicy *mbx_expirepolicy = NULL;
00082        int a;
00083        int logpages = 0;
00084        int r;               /* IPC response code */
00085        int server_configs = 0;
00086 
00087        /* Clear out the config buffers */
00088        memset(&sc[0][0], 0, sizeof(sc));
00089 
00090        /* Fetch the current config */
00091        r = CtdlIPCGetSystemConfig(ipc, &resp, buf);
00092        if (r / 100 == 1) {
00093               server_configs = num_tokens(resp, '\n');
00094               for (a=0; a<server_configs; ++a) {
00095                      if (a < NUM_CONFIGS) {
00096                             extract_token(&sc[a][0], resp, a, '\n', sizeof sc[a]);
00097                      }
00098               }
00099        }
00100        if (resp) free(resp);
00101        resp = NULL;
00102        /* Fetch the expire policy (this will silently fail on old servers,
00103         * resulting in "default" policy)
00104         */
00105        r = CtdlIPCGetMessageExpirationPolicy(ipc, 2, &site_expirepolicy, buf);
00106        r = CtdlIPCGetMessageExpirationPolicy(ipc, 3, &mbx_expirepolicy, buf);
00107 
00108        /* Identification parameters */
00109 
00110        strprompt("Node name", &sc[0][0], 15);
00111        strprompt("Fully qualified domain name", &sc[1][0], 63);
00112        strprompt("Human readable node name", &sc[2][0], 20);
00113        strprompt("Telephone number", &sc[3][0], 15);
00114        strprompt("Geographic location of this system", &sc[12][0], 31);
00115        strprompt("Name of system administrator", &sc[13][0], 25);
00116        strprompt("Paginator prompt", &sc[10][0], 79);
00117 
00118        /* Security parameters */
00119 
00120        snprintf(sc[7], sizeof sc[7], "%d", (boolprompt(
00121               "Require registration for new users",
00122               atoi(&sc[7][0]))));
00123        snprintf(sc[29], sizeof sc[29], "%d", (boolprompt(
00124               "Disable self-service user account creation",
00125               atoi(&sc[29][0]))));
00126        strprompt("Initial access level for new users", &sc[6][0], 1);
00127        strprompt("Access level required to create rooms", &sc[19][0], 1);
00128        snprintf(sc[67], sizeof sc[67], "%d", (boolprompt(
00129               "Allow anonymous guest logins",
00130               atoi(&sc[67][0]))));
00131        snprintf(sc[4], sizeof sc[4], "%d", (boolprompt(
00132               "Automatically give room aide privs to a user who creates a private room",
00133               atoi(&sc[4][0]))));
00134 
00135        snprintf(sc[8], sizeof sc[8], "%d", (boolprompt(
00136               "Automatically move problem user messages to twit room",
00137               atoi(&sc[8][0]))));
00138 
00139        strprompt("Name of twit room", &sc[9][0], ROOMNAMELEN);
00140        snprintf(sc[11], sizeof sc[11], "%d", (boolprompt(
00141               "Restrict Internet mail to only those with that privilege",
00142               atoi(&sc[11][0]))));
00143        snprintf(sc[26], sizeof sc[26], "%d", (boolprompt(
00144               "Allow Aides to Zap (forget) rooms",
00145               atoi(&sc[26][0]))));
00146 
00147        if (!IsEmptyStr(&sc[18][0])) {
00148               logpages = 1;
00149        }
00150        else {
00151               logpages = 0;
00152        }
00153        logpages = boolprompt("Log all instant messages", logpages);
00154        if (logpages) {
00155               strprompt("Name of logging room", &sc[18][0], ROOMNAMELEN);
00156        }
00157        else {
00158               sc[18][0] = 0;
00159        }
00160 
00161        /* Commented out because this setting isn't really appropriate to
00162         * change while the server is running.
00163         *
00164         * snprintf(sc[52], sizeof sc[52], "%d", (boolprompt(
00165         *     "Use system authentication",
00166         *     atoi(&sc[52][0]))));
00167         */
00168 
00169        /* Server tuning */
00170 
00171        strprompt("Server connection idle timeout (in seconds)", &sc[5][0], 4);
00172        strprompt("Maximum concurrent sessions", &sc[14][0], 4);
00173        strprompt("Maximum message length", &sc[20][0], 20);
00174        strprompt("Minimum number of worker threads", &sc[21][0], 3);
00175        strprompt("Maximum number of worker threads", &sc[22][0], 3);
00176        snprintf(sc[43], sizeof sc[43], "%d", (boolprompt(
00177               "Automatically delete committed database logs",
00178               atoi(&sc[43][0]))));
00179 
00180        strprompt("Server IP address (* for 'any')", &sc[37][0], 15);
00181        strprompt("POP3 server port (-1 to disable)", &sc[23][0], 5);
00182        strprompt("POP3S server port (-1 to disable)", &sc[40][0], 5);
00183        strprompt("IMAP server port (-1 to disable)", &sc[27][0], 5);
00184        strprompt("IMAPS server port (-1 to disable)", &sc[39][0], 5);
00185        strprompt("SMTP MTA server port (-1 to disable)", &sc[24][0], 5);
00186        strprompt("SMTP MSA server port (-1 to disable)", &sc[38][0], 5);
00187        strprompt("SMTPS server port (-1 to disable)", &sc[41][0], 5);
00188        strprompt("Postfix TCP Dictionary Port server port (-1 to disable)", &sc[50][0], 5);
00189        strprompt("ManageSieve server port (-1 to disable)", &sc[51][0], 5);
00190 
00191        strprompt("XMPP (Jabber) client to server port (-1 to disable)", &sc[62][0], 5);
00192        /* No prompt because we don't implement this service yet, it's just a placeholder */
00193        /* strprompt("XMPP (Jabber) server to server port (-1 to disable)", &sc[63][0], 5); */
00194 
00195        /* This logic flips the question around, because it's one of those
00196         * situations where 0=yes and 1=no
00197         */
00198        a = atoi(sc[25]);
00199        a = (a ? 0 : 1);
00200        a = boolprompt("Correct forged From: lines during authenticated SMTP",
00201               a);
00202        a = (a ? 0 : 1);
00203        snprintf(sc[25], sizeof sc[25], "%d", a);
00204 
00205        snprintf(sc[66], sizeof sc[66], "%d", (boolprompt(
00206               "Flag messages as spam instead of rejecting",
00207               atoi(&sc[66][0]))));
00208 
00209        /* This logic flips the question around, because it's one of those
00210         * situations where 0=yes and 1=no
00211         */
00212        a = atoi(sc[61]);
00213        a = (a ? 0 : 1);
00214        a = boolprompt("Force IMAP posts in public rooms to be from the user who submitted them", a);
00215        a = (a ? 0 : 1);
00216        snprintf(sc[61], sizeof sc[61], "%d", a);
00217 
00218        snprintf(sc[45], sizeof sc[45], "%d", (boolprompt(
00219               "Allow unauthenticated SMTP clients to spoof my domains",
00220               atoi(&sc[45][0]))));
00221        snprintf(sc[57], sizeof sc[57], "%d", (boolprompt(
00222               "Perform RBL checks at greeting instead of after RCPT",
00223               atoi(&sc[57][0]))));
00224        snprintf(sc[44], sizeof sc[44], "%d", (boolprompt(
00225               "Instantly expunge deleted IMAP messages",
00226               atoi(&sc[44][0]))));
00227 
00228        /* LDAP settings */
00229        if (ipc->ServInfo.supports_ldap) {
00230               a = strlen(&sc[32][0]);
00231               a = (a ? 1 : 0);     /* Set only to 1 or 0 */
00232               a = boolprompt("Do you want to configure LDAP authentication?", a);
00233               if (a) {
00234                      strprompt("Host name of LDAP server",
00235                             &sc[32][0], 127);
00236                      strprompt("Port number of LDAP service",
00237                             &sc[33][0], 5);
00238                      strprompt("Base DN", &sc[34][0], 255);
00239                      strprompt("Bind DN (or blank for anonymous bind)", &sc[35][0], 255);
00240                      strprompt("Password for bind DN (or blank for anonymous bind)", &sc[36][0], 255);
00241               }
00242               else {
00243                      strcpy(&sc[32][0], "");
00244               }
00245        }
00246 
00247        /* Expiry settings */
00248        strprompt("Default user purge time (days)", &sc[16][0], 5);
00249        strprompt("Default room purge time (days)", &sc[17][0], 5);
00250 
00251        /* Angels and demons dancing in my head... */
00252        do {
00253               snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_mode);
00254               strprompt("System default message expire policy (? for list)",
00255                        buf, 1);
00256               if (buf[0] == '?') {
00257                      scr_printf("\n"
00258                             "1. Never automatically expire messages\n"
00259                             "2. Expire by message count\n"
00260                             "3. Expire by message age\n");
00261               }
00262        } while ((buf[0] < '1') || (buf[0] > '3'));
00263        site_expirepolicy->expire_mode = buf[0] - '0';
00264 
00265        /* ...lunatics and monsters underneath my bed */
00266        if (site_expirepolicy->expire_mode == 2) {
00267               snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
00268               strprompt("Keep how many messages online?", buf, 10);
00269               site_expirepolicy->expire_value = atol(buf);
00270        }
00271        if (site_expirepolicy->expire_mode == 3) {
00272               snprintf(buf, sizeof buf, "%d", site_expirepolicy->expire_value);
00273               strprompt("Keep messages for how many days?", buf, 10);
00274               site_expirepolicy->expire_value = atol(buf);
00275        }
00276 
00277        /* Media messiahs preying on my fears... */
00278        do {
00279               snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_mode);
00280               strprompt("Mailbox default message expire policy (? for list)",
00281                        buf, 1);
00282               if (buf[0] == '?') {
00283                      scr_printf("\n"
00284                             "0. Go with the system default\n"
00285                             "1. Never automatically expire messages\n"
00286                             "2. Expire by message count\n"
00287                             "3. Expire by message age\n");
00288               }
00289        } while ((buf[0] < '0') || (buf[0] > '3'));
00290        mbx_expirepolicy->expire_mode = buf[0] - '0';
00291 
00292        /* ...Pop culture prophets playing in my ears */
00293        if (mbx_expirepolicy->expire_mode == 2) {
00294               snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
00295               strprompt("Keep how many messages online?", buf, 10);
00296               mbx_expirepolicy->expire_value = atol(buf);
00297        }
00298        if (mbx_expirepolicy->expire_mode == 3) {
00299               snprintf(buf, sizeof buf, "%d", mbx_expirepolicy->expire_value);
00300               strprompt("Keep messages for how many days?", buf, 10);
00301               mbx_expirepolicy->expire_value = atol(buf);
00302        }
00303 
00304        strprompt("How often to run network jobs (in seconds)", &sc[28][0], 5);
00305        strprompt("Default frequency to run POP3 collection (in seconds)", &sc[64][0], 5);
00306        strprompt("Fastest frequency to run POP3 collection (in seconds)", &sc[65][0], 5);
00307        strprompt("Hour to run purges (0-23)", &sc[31][0], 2);
00308        snprintf(sc[42], sizeof sc[42], "%d", (boolprompt(
00309               "Enable full text search index (warning: resource intensive)",
00310               atoi(&sc[42][0]))));
00311 
00312        snprintf(sc[46], sizeof sc[46], "%d", (boolprompt(
00313               "Perform journaling of email messages",
00314               atoi(&sc[46][0]))));
00315        snprintf(sc[47], sizeof sc[47], "%d", (boolprompt(
00316               "Perform journaling of non-email messages",
00317               atoi(&sc[47][0]))));
00318        if ( (atoi(&sc[46][0])) || (atoi(&sc[47][0])) ) {
00319               strprompt("Email destination of journalized messages",
00320                      &sc[48][0], 127);
00321        }
00322 
00323        /* Funambol push stuff */
00324        int yes_funambol = 0;
00325        if (strlen(sc[53]) > 0) yes_funambol = 1;
00326        yes_funambol = boolprompt("Connect to an external Funambol sync server", yes_funambol);
00327        if (yes_funambol) {
00328               strprompt("Funambol server (blank to disable)", &sc[53][0], 63);
00329               strprompt("Funambol server port", &sc[54][0], 5);
00330               strprompt("Funambol sync source", &sc[55][0], 63);
00331               strprompt("Funambol authentication details (user:pass in Base64)", &sc[56][0],63);
00332        }
00333        else {
00334               sc[53][0] = 0;
00335               sc[54][0] = 0;
00336               sc[55][0] = 0;
00337               sc[56][0] = 0;
00338        }
00339 
00340        /* External pager stuff */
00341        int yes_pager = 0;
00342        if (strlen(sc[60]) > 0) yes_pager = 1;
00343        yes_pager = boolprompt("Configure an external pager tool", yes_pager);
00344        if (yes_pager) {
00345               strprompt("External pager tool", &sc[60][0], 255);
00346        }
00347        else {
00348               sc[60][0] = 0;
00349        }
00350 
00351        /* Master user account */
00352        int yes_muacct = 0;
00353        if (strlen(sc[58]) > 0) yes_muacct = 1;
00354        yes_muacct = boolprompt("Enable a 'master user' account", yes_muacct);
00355        if (yes_muacct) {
00356               strprompt("Master user name", &sc[58][0], 31);
00357               strprompt("Master user password", &sc[59][0], -31);
00358        }
00359        else {
00360               strcpy(&sc[58][0], "");
00361               strcpy(&sc[59][0], "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
00362        }
00363 
00364        /* Save it */
00365        scr_printf("Save this configuration? ");
00366        if (yesno()) {
00367               r = 1;
00368               for (a = 0; a < NUM_CONFIGS; a++) {
00369                      r += 1 + strlen(sc[a]);
00370               }
00371               resp = (char *)calloc(1, r);
00372               if (!resp) {
00373                      scr_printf("Can't save config - out of memory!\n");
00374                      logoff(ipc, 1);
00375               }
00376               for (a = 0; a < NUM_CONFIGS; a++) {
00377                      strcat(resp, sc[a]);
00378                      strcat(resp, "\n");
00379               }
00380               r = CtdlIPCSetSystemConfig(ipc, resp, buf);
00381               if (r / 100 != 4) {
00382                      scr_printf("%s\n", buf);
00383               }
00384               free(resp);
00385 
00386               r = CtdlIPCSetMessageExpirationPolicy(ipc, 2, site_expirepolicy, buf);
00387               if (r / 100 != 2) {
00388                      scr_printf("%s\n", buf);
00389               }
00390 
00391               r = CtdlIPCSetMessageExpirationPolicy(ipc, 3, mbx_expirepolicy, buf);
00392               if (r / 100 != 2) {
00393                      scr_printf("%s\n", buf);
00394               }
00395 
00396        }
00397     if (site_expirepolicy) free(site_expirepolicy);
00398     if (mbx_expirepolicy) free(mbx_expirepolicy);
00399 }
00400 
00401 
00402 /*
00403  * support function for do_internet_configuration()
00404  */
00405 void get_inet_rec_type(CtdlIPC *ipc, char *buf) {
00406        int sel;
00407 
00408        keyopt(" <1> localhost      (Alias for this computer)\n");
00409        keyopt(" <2> smart host     (Forward all outbound mail to this host)\n");
00410        keyopt(" <3> fallback host  (Send mail to this host only if direct delivery fails)\n");
00411        keyopt(" <4> directory      (Consult the Global Address Book)\n");
00412        keyopt(" <5> SpamAssassin   (Address of SpamAssassin server)\n");
00413        keyopt(" <6> RBL            (domain suffix of spam hunting RBL)\n");
00414        keyopt(" <7> masq domains   (Domains as which users are allowed to masquerade)\n");
00415        keyopt(" <8> ClamAV         (Address of ClamAV clamd server)\n");
00416        sel = intprompt("Which one", 1, 1, 8);
00417        switch(sel) {
00418               case 1:       strcpy(buf, "localhost");
00419                      return;
00420               case 2:       strcpy(buf, "smarthost");
00421                      return;
00422               case 3:       strcpy(buf, "fallbackhost");
00423                      return;
00424               case 4:       strcpy(buf, "directory");
00425                      return;
00426               case 5:       strcpy(buf, "spamassassin");
00427                      return;
00428               case 6:       strcpy(buf, "rbl");
00429                      return;
00430               case 7:       strcpy(buf, "masqdomain");
00431                      return;
00432               case 8:       strcpy(buf, "clamav");
00433                      return;
00434        }
00435 }
00436 
00437 
00438 /*
00439  * Internet mail configuration
00440  */
00441 void do_internet_configuration(CtdlIPC *ipc)
00442 {
00443        char buf[256];
00444        char *resp = NULL;
00445        int num_recs = 0;
00446        char **recs = NULL;
00447        char ch;
00448        int i, j;
00449        int quitting = 0;
00450        int modified = 0;
00451        int r;
00452        
00453        r = CtdlIPCGetSystemConfigByType(ipc, INTERNETCFG, &resp, buf);
00454        if (r / 100 == 1) {
00455               while (!IsEmptyStr(resp)) {
00456                      extract_token(buf, resp, 0, '\n', sizeof buf);
00457                      remove_token(resp, 0, '\n');
00458                      ++num_recs;
00459                      if (num_recs == 1) recs = malloc(sizeof(char *));
00460                      else recs = realloc(recs, (sizeof(char *)) * num_recs);
00461                      recs[num_recs-1] = malloc(strlen(buf) + 1);
00462                      strcpy(recs[num_recs-1], buf);
00463               }
00464        }
00465        if (resp) free(resp);
00466 
00467        do {
00468               scr_printf("\n");
00469               color(BRIGHT_WHITE);
00470               scr_printf("###                    Host or domain                     Record type      \n");
00471               color(DIM_WHITE);
00472               scr_printf("--- -------------------------------------------------- --------------------\n");
00473               for (i=0; i<num_recs; ++i) {
00474               color(DIM_WHITE);
00475               scr_printf("%3d ", i+1);
00476               extract_token(buf, recs[i], 0, '|', sizeof buf);
00477               color(BRIGHT_CYAN);
00478               scr_printf("%-50s ", buf);
00479               extract_token(buf, recs[i], 1, '|', sizeof buf);
00480               color(BRIGHT_MAGENTA);
00481               scr_printf("%-20s\n", buf);
00482               color(DIM_WHITE);
00483               }
00484 
00485               ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
00486               switch(ch) {
00487                      case 'a':
00488                             newprompt("Enter host name: ",
00489                                    buf, 50);
00490                             striplt(buf);
00491                             if (!IsEmptyStr(buf)) {
00492                                    ++num_recs;
00493                                    if (num_recs == 1)
00494                                           recs = malloc(sizeof(char *));
00495                                    else recs = realloc(recs,
00496                                           (sizeof(char *)) * num_recs);
00497                                    strcat(buf, "|");
00498                                    get_inet_rec_type(ipc,
00499                                                  &buf[strlen(buf)]);
00500                                    recs[num_recs-1] = strdup(buf);
00501                             }
00502                             modified = 1;
00503                             break;
00504                      case 'd':
00505                             i = intprompt("Delete which one",
00506                                    1, 1, num_recs) - 1;
00507                             free(recs[i]);
00508                             --num_recs;
00509                             for (j=i; j<num_recs; ++j)
00510                                    recs[j] = recs[j+1];
00511                             modified = 1;
00512                             break;
00513                      case 's':
00514                             r = 1;
00515                             for (i = 0; i < num_recs; i++)
00516                                    r += 1 + strlen(recs[i]);
00517                             resp = (char *)calloc(1, r);
00518                             if (!resp) {
00519                                    scr_printf("Can't save config - out of memory!\n");
00520                                    logoff(ipc, 1);
00521                             }
00522                             if (num_recs) for (i = 0; i < num_recs; i++) {
00523                                    strcat(resp, recs[i]);
00524                                    strcat(resp, "\n");
00525                             }
00526                             r = CtdlIPCSetSystemConfigByType(ipc, INTERNETCFG, resp, buf);
00527                             if (r / 100 != 4) {
00528                                    scr_printf("%s\n", buf);
00529                             } else {
00530                                    scr_printf("Wrote %d records.\n", num_recs);
00531                                    modified = 0;
00532                             }
00533                 free(resp);
00534                             break;
00535                      case 'q':
00536                             quitting = !modified || boolprompt(
00537                                    "Quit without saving", 0);
00538                             break;
00539                      default:
00540                             break;
00541               }
00542        } while (!quitting);
00543 
00544        if (recs != NULL) {
00545               for (i=0; i<num_recs; ++i) free(recs[i]);
00546               free(recs);
00547        }
00548 }
00549 
00550 
00551 
00552 /*
00553  * Edit network configuration for room sharing, mailing lists, etc.
00554  */
00555 void network_config_management(CtdlIPC *ipc, char *entrytype, char *comment)
00556 {
00557        char filename[PATH_MAX];
00558        char changefile[PATH_MAX];
00559        int e_ex_code;
00560        pid_t editor_pid;
00561        int cksum;
00562        int b, i, tokens;
00563        char buf[1024];
00564        char instr[1024];
00565        char addr[1024];
00566        FILE *tempfp;
00567        FILE *changefp;
00568        char *listing = NULL;
00569        int r;
00570 
00571        if (IsEmptyStr(editor_path)) {
00572               scr_printf("You must have an external editor configured in"
00573                      " order to use this function.\n");
00574               return;
00575        }
00576 
00577        CtdlMakeTempFileName(filename, sizeof filename);
00578        CtdlMakeTempFileName(changefile, sizeof changefile);
00579 
00580        tempfp = fopen(filename, "w");
00581        if (tempfp == NULL) {
00582               scr_printf("Cannot open %s: %s\n", filename, strerror(errno));
00583               return;
00584        }
00585 
00586        fprintf(tempfp, "# Configuration for room: %s\n", room_name);
00587        fprintf(tempfp, "# %s\n", comment);
00588        fprintf(tempfp, "# Specify one per line.\n"
00589                      "\n\n");
00590 
00591        r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
00592        if (r / 100 == 1) {
00593               while(listing && !IsEmptyStr(listing)) {
00594                      extract_token(buf, listing, 0, '\n', sizeof buf);
00595                      remove_token(listing, 0, '\n');
00596                      extract_token(instr, buf, 0, '|', sizeof instr);
00597                      if (!strcasecmp(instr, entrytype)) {
00598                             tokens = num_tokens(buf, '|');
00599                             for (i=1; i<tokens; ++i) {
00600                                    extract_token(addr, buf, i, '|', sizeof addr);
00601                                    fprintf(tempfp, "%s", addr);
00602                                    if (i < (tokens-1)) {
00603                                           fprintf(tempfp, "|");
00604                                    }
00605                             }
00606                             fprintf(tempfp, "\n");
00607                      }
00608               }
00609        }
00610        if (listing) {
00611               free(listing);
00612               listing = NULL;
00613        }
00614        fclose(tempfp);
00615 
00616        e_ex_code = 1;       /* start with a failed exit code */
00617        stty_ctdl(SB_RESTORE);
00618        editor_pid = fork();
00619        cksum = file_checksum(filename);
00620        if (editor_pid == 0) {
00621               chmod(filename, 0600);
00622               putenv("WINDOW_TITLE=Network configuration");
00623               execlp(editor_path, editor_path, filename, NULL);
00624               exit(1);
00625        }
00626        if (editor_pid > 0) {
00627               do {
00628                      e_ex_code = 0;
00629                      b = ka_wait(&e_ex_code);
00630               } while ((b != editor_pid) && (b >= 0));
00631        editor_pid = (-1);
00632        stty_ctdl(0);
00633        }
00634 
00635        if (file_checksum(filename) == cksum) {
00636               scr_printf("*** No changes to save.\n");
00637               e_ex_code = 1;
00638        }
00639 
00640        if (e_ex_code == 0) {              /* Save changes */
00641               changefp = fopen(changefile, "w");
00642 
00643               /* Load all netconfig entries that are *not* of the type we are editing */
00644               r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
00645               if (r / 100 == 1) {
00646                      while(listing && !IsEmptyStr(listing)) {
00647                             extract_token(buf, listing, 0, '\n', sizeof buf);
00648                             remove_token(listing, 0, '\n');
00649                             extract_token(instr, buf, 0, '|', sizeof instr);
00650                             if (strcasecmp(instr, entrytype)) {
00651                                    fprintf(changefp, "%s\n", buf);
00652                             }
00653                      }
00654               }
00655               if (listing) {
00656                      free(listing);
00657                      listing = NULL;
00658               }
00659 
00660               /* ...and merge that with the data we just edited */
00661               tempfp = fopen(filename, "r");
00662               while (fgets(buf, sizeof buf, tempfp) != NULL) {
00663                      for (i=0; i<strlen(buf); ++i) {
00664                             if (buf[i] == '#') buf[i] = 0;
00665                      }
00666                      striplt(buf);
00667                      if (!IsEmptyStr(buf)) {
00668                             fprintf(changefp, "%s|%s\n", entrytype, buf);
00669                      }
00670               }
00671               fclose(tempfp);
00672               fclose(changefp);
00673 
00674               /* now write it to the server... */
00675               changefp = fopen(changefile, "r");
00676               if (changefp != NULL) {
00677                      listing = load_message_from_file(changefp);
00678                      if (listing) {
00679                             r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
00680                             free(listing);
00681                             listing = NULL;
00682                      }
00683                      fclose(changefp);
00684               }
00685        }
00686 
00687        unlink(filename);           /* Delete the temporary files */
00688        unlink(changefile);
00689 }
00690 
00691 
00692 /*
00693  * IGnet node configuration
00694  */
00695 void do_ignet_configuration(CtdlIPC *ipc) {
00696        char buf[SIZ];
00697        int num_recs = 0;
00698        char **recs = NULL;
00699        char ch;
00700        int i, j;
00701        int quitting = 0;
00702        int modified = 0;
00703        char *listing = NULL;
00704        int r;
00705 
00706        r = CtdlIPCGetSystemConfigByType(ipc, IGNETCFG, &listing, buf);
00707        if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
00708               extract_token(buf, listing, 0, '\n', sizeof buf);
00709               remove_token(listing, 0, '\n');
00710 
00711               ++num_recs;
00712               if (num_recs == 1) recs = malloc(sizeof(char *));
00713               else recs = realloc(recs, (sizeof(char *)) * num_recs);
00714               recs[num_recs-1] = malloc(SIZ);
00715               strcpy(recs[num_recs-1], buf);
00716        }
00717        if (listing) free(listing);
00718 
00719        do {
00720               scr_printf("\n");
00721               color(BRIGHT_WHITE);
00722               scr_printf(   "### "
00723                      "   Node          "
00724                      "  Secret           "
00725                      "          Host or IP             "
00726                      "Port#\n");
00727               color(DIM_WHITE);
00728               scr_printf(   "--- "
00729                      "---------------- "
00730                      "------------------ "
00731                      "-------------------------------- "
00732                      "-----\n");
00733               for (i=0; i<num_recs; ++i) {
00734               color(DIM_WHITE);
00735               scr_printf("%3d ", i+1);
00736               extract_token(buf, recs[i], 0, '|', sizeof buf);
00737               color(BRIGHT_CYAN);
00738               scr_printf("%-16s ", buf);
00739               extract_token(buf, recs[i], 1, '|', sizeof buf);
00740               color(BRIGHT_MAGENTA);
00741               scr_printf("%-18s ", buf);
00742               extract_token(buf, recs[i], 2, '|', sizeof buf);
00743               color(BRIGHT_CYAN);
00744               scr_printf("%-32s ", buf);
00745               extract_token(buf, recs[i], 3, '|', sizeof buf);
00746               color(BRIGHT_MAGENTA);
00747               scr_printf("%-3s\n", buf);
00748               color(DIM_WHITE);
00749               }
00750               scr_printf("\n");
00751 
00752               ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
00753               switch(ch) {
00754                      case 'a':
00755                             ++num_recs;
00756                             if (num_recs == 1)
00757                                    recs = malloc(sizeof(char *));
00758                             else recs = realloc(recs,
00759                                    (sizeof(char *)) * num_recs);
00760                             newprompt("Enter node name    : ", buf, 16);
00761                             strcat(buf, "|");
00762                             newprompt("Enter shared secret: ",
00763                                    &buf[strlen(buf)], 18);
00764                             strcat(buf, "|");
00765                             newprompt("Enter host or IP   : ",
00766                                    &buf[strlen(buf)], 32);
00767                             strcat(buf, "|504");
00768                             strprompt("Enter port number  : ",
00769                                    &buf[strlen(buf)-3], 5);
00770                             recs[num_recs-1] = strdup(buf);
00771                             modified = 1;
00772                             break;
00773                      case 'd':
00774                             i = intprompt("Delete which one",
00775                                    1, 1, num_recs) - 1;
00776                             free(recs[i]);
00777                             --num_recs;
00778                             for (j=i; j<num_recs; ++j)
00779                                    recs[j] = recs[j+1];
00780                             modified = 1;
00781                             break;
00782                      case 's':
00783                             r = 1;
00784                             for (i = 0; i < num_recs; ++i)
00785                                    r += 1 + strlen(recs[i]);
00786                             listing = (char*) calloc(1, r);
00787                             if (!listing) {
00788                                    scr_printf("Can't save config - out of memory!\n");
00789                                    logoff(ipc, 1);
00790                             }
00791                             if (num_recs) for (i = 0; i < num_recs; ++i) {
00792                                    strcat(listing, recs[i]);
00793                                    strcat(listing, "\n");
00794                             }
00795                             r = CtdlIPCSetSystemConfigByType(ipc, IGNETCFG, listing, buf);
00796                             if (r / 100 != 4) {
00797                                    scr_printf("%s\n", buf);
00798                             } else {
00799                                    scr_printf("Wrote %d records.\n", num_recs);
00800                                    modified = 0;
00801                             }
00802                 free(listing);
00803                             break;
00804                      case 'q':
00805                             quitting = !modified || boolprompt(
00806                                    "Quit without saving", 0);
00807                             break;
00808                      default:
00809                             break;
00810               }
00811        } while (!quitting);
00812 
00813        if (recs != NULL) {
00814               for (i=0; i<num_recs; ++i) free(recs[i]);
00815               free(recs);
00816        }
00817 }
00818 
00819 
00820 /*
00821  * Filter list configuration
00822  */
00823 void do_filterlist_configuration(CtdlIPC *ipc)
00824 {
00825        char buf[SIZ];
00826        int num_recs = 0;
00827        char **recs = NULL;
00828        char ch;
00829        int i, j;
00830        int quitting = 0;
00831        int modified = 0;
00832        char *listing = NULL;
00833        int r;
00834 
00835        r = CtdlIPCGetSystemConfigByType(ipc, FILTERLIST, &listing, buf);
00836        if (r / 100 == 1) while (*listing && !IsEmptyStr(listing)) {
00837               extract_token(buf, listing, 0, '\n', sizeof buf);
00838               remove_token(listing, 0, '\n');
00839 
00840               ++num_recs;
00841               if (num_recs == 1) recs = malloc(sizeof(char *));
00842               else recs = realloc(recs, (sizeof(char *)) * num_recs);
00843               recs[num_recs-1] = malloc(SIZ);
00844               strcpy(recs[num_recs-1], buf);
00845        }
00846        if (listing) free(listing);
00847 
00848        do {
00849               scr_printf("\n");
00850               color(BRIGHT_WHITE);
00851               scr_printf(   "### "
00852                      "         User name           "
00853                      "         Room name           "
00854                      "    Node name    "
00855                      "\n");
00856               color(DIM_WHITE);
00857               scr_printf(   "--- "
00858                      "---------------------------- "
00859                      "---------------------------- "
00860                      "---------------- "
00861                      "\n");
00862               for (i=0; i<num_recs; ++i) {
00863               color(DIM_WHITE);
00864               scr_printf("%3d ", i+1);
00865               extract_token(buf, recs[i], 0, '|', sizeof buf);
00866               color(BRIGHT_CYAN);
00867               scr_printf("%-28s ", buf);
00868               extract_token(buf, recs[i], 1, '|', sizeof buf);
00869               color(BRIGHT_MAGENTA);
00870               scr_printf("%-28s ", buf);
00871               extract_token(buf, recs[i], 2, '|', sizeof buf);
00872               color(BRIGHT_CYAN);
00873               scr_printf("%-16s\n", buf);
00874               extract_token(buf, recs[i], 3, '|', sizeof buf);
00875               color(DIM_WHITE);
00876               }
00877 
00878               ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
00879               switch(ch) {
00880                      case 'a':
00881                             ++num_recs;
00882                             if (num_recs == 1)
00883                                    recs = malloc(sizeof(char *));
00884                             else recs = realloc(recs,
00885                                    (sizeof(char *)) * num_recs);
00886                             newprompt("Enter user name: ", buf, 28);
00887                             strcat(buf, "|");
00888                             newprompt("Enter room name: ",
00889                                    &buf[strlen(buf)], 28);
00890                             strcat(buf, "|");
00891                             newprompt("Enter node name: ",
00892                                    &buf[strlen(buf)], 16);
00893                             strcat(buf, "|");
00894                             recs[num_recs-1] = strdup(buf);
00895                             modified = 1;
00896                             break;
00897                      case 'd':
00898                             i = intprompt("Delete which one",
00899                                    1, 1, num_recs) - 1;
00900                             free(recs[i]);
00901                             --num_recs;
00902                             for (j=i; j<num_recs; ++j)
00903                                    recs[j] = recs[j+1];
00904                             modified = 1;
00905                             break;
00906                      case 's':
00907                             r = 1;
00908                             for (i = 0; i < num_recs; ++i)
00909                                    r += 1 + strlen(recs[i]);
00910                             listing = (char*) calloc(1, r);
00911                             if (!listing) {
00912                                    scr_printf("Can't save config - out of memory!\n");
00913                                    logoff(ipc, 1);
00914                             }
00915                             if (num_recs) for (i = 0; i < num_recs; ++i) {
00916                                    strcat(listing, recs[i]);
00917                                    strcat(listing, "\n");
00918                             }
00919                             r = CtdlIPCSetSystemConfigByType(ipc, FILTERLIST, listing, buf);
00920                             if (r / 100 != 4) {
00921                                    scr_printf("%s\n", buf);
00922                             } else {
00923                                    scr_printf("Wrote %d records.\n", num_recs);
00924                                    modified = 0;
00925                             }
00926                 free(listing);
00927                             break;
00928                      case 'q':
00929                             quitting = !modified || boolprompt(
00930                                    "Quit without saving", 0);
00931                             break;
00932                      default:
00933                             break;
00934               }
00935        } while (!quitting);
00936 
00937        if (recs != NULL) {
00938               for (i=0; i<num_recs; ++i) free(recs[i]);
00939               free(recs);
00940        }
00941 }
00942 
00943 
00944 
00945 
00946 /*
00947  * POP3 aggregation client configuration
00948  */
00949 void do_pop3client_configuration(CtdlIPC *ipc)
00950 {
00951        char buf[SIZ];
00952        int num_recs = 0;
00953        char **recs = NULL;
00954        char ch;
00955        int i, j;
00956        int quitting = 0;
00957        int modified = 0;
00958        char *listing = NULL;
00959        char *other_listing = NULL;
00960        int r;
00961        char instr[SIZ];
00962 
00963        r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
00964        if (r / 100 == 1) {
00965               while(listing && !IsEmptyStr(listing)) {
00966                      extract_token(buf, listing, 0, '\n', sizeof buf);
00967                      remove_token(listing, 0, '\n');
00968                      extract_token(instr, buf, 0, '|', sizeof instr);
00969                      if (!strcasecmp(instr, "pop3client")) {
00970 
00971                             ++num_recs;
00972                             if (num_recs == 1) recs = malloc(sizeof(char *));
00973                             else recs = realloc(recs, (sizeof(char *)) * num_recs);
00974                             recs[num_recs-1] = malloc(SIZ);
00975                             strcpy(recs[num_recs-1], buf);
00976 
00977                      }
00978               }
00979        }
00980        if (listing) {
00981               free(listing);
00982               listing = NULL;
00983        }
00984 
00985        do {
00986               scr_printf("\n");
00987               color(BRIGHT_WHITE);
00988               scr_printf(   "### "
00989                      "      Remote POP3 host       "
00990                      "         User name           "
00991                      "Keep on server? "
00992                      "Fetching inteval"
00993                      "\n");
00994               color(DIM_WHITE);
00995               scr_printf(   "--- "
00996                      "---------------------------- "
00997                      "---------------------------- "
00998                      "--------------- "
00999                      "---------------- "
01000                      "\n");
01001               for (i=0; i<num_recs; ++i) {
01002               color(DIM_WHITE);
01003               scr_printf("%3d ", i+1);
01004 
01005               extract_token(buf, recs[i], 1, '|', sizeof buf);
01006               color(BRIGHT_CYAN);
01007               scr_printf("%-28s ", buf);
01008 
01009               extract_token(buf, recs[i], 2, '|', sizeof buf);
01010               color(BRIGHT_MAGENTA);
01011               scr_printf("%-28s ", buf);
01012 
01013               color(BRIGHT_CYAN);
01014               scr_printf("%-15s ", (extract_int(recs[i], 4) ? "Yes" : "No") );
01015               color(BRIGHT_MAGENTA);
01016               scr_printf("%ld\n", extract_long(recs[i], 5) );
01017               color(DIM_WHITE);
01018               }
01019 
01020               ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
01021               switch(ch) {
01022                      case 'a':
01023                             ++num_recs;
01024                             if (num_recs == 1) {
01025                                    recs = malloc(sizeof(char *));
01026                             }
01027                             else {
01028                                    recs = realloc(recs, (sizeof(char *)) * num_recs);
01029                             }
01030                             strcpy(buf, "pop3client|");
01031                             newprompt("Enter host name: ", &buf[strlen(buf)], 28);
01032                             strcat(buf, "|");
01033                             newprompt("Enter user name: ", &buf[strlen(buf)], 28);
01034                             strcat(buf, "|");
01035                             newprompt("Enter password : ", &buf[strlen(buf)], 16);
01036                             strcat(buf, "|");
01037                             scr_printf("Keep messages on server instead of deleting them? ");
01038                             sprintf(&buf[strlen(buf)], "%d", yesno());
01039                             strcat(buf, "|");
01040                             newprompt("Enter interval : ", &buf[strlen(buf)], 5);
01041                             strcat(buf, "|");
01042                             recs[num_recs-1] = strdup(buf);
01043                             modified = 1;
01044                             break;
01045                      case 'd':
01046                             i = intprompt("Delete which one",
01047                                    1, 1, num_recs) - 1;
01048                             free(recs[i]);
01049                             --num_recs;
01050                             for (j=i; j<num_recs; ++j)
01051                                    recs[j] = recs[j+1];
01052                             modified = 1;
01053                             break;
01054                      case 's':
01055                             r = 1;
01056                             for (i = 0; i < num_recs; ++i) {
01057                                    r += 1 + strlen(recs[i]);
01058                             }
01059                             listing = (char*) calloc(1, r);
01060                             if (!listing) {
01061                                    scr_printf("Can't save config - out of memory!\n");
01062                                    logoff(ipc, 1);
01063                             }
01064                             if (num_recs) for (i = 0; i < num_recs; ++i) {
01065                                    strcat(listing, recs[i]);
01066                                    strcat(listing, "\n");
01067                             }
01068 
01069                             /* Retrieve all the *other* records for merging */
01070                             r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
01071                             if (r / 100 == 1) {
01072                                    for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
01073                                           extract_token(buf, other_listing, i, '\n', sizeof buf);
01074                                           if (strncasecmp(buf, "pop3client|", 11)) {
01075                                                  listing = realloc(listing, strlen(listing) +
01076                                                         strlen(buf) + 10);
01077                                                  strcat(listing, buf);
01078                                                  strcat(listing, "\n");
01079                                           }
01080                                    }
01081                             }
01082                             free(other_listing);
01083                             r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
01084                             free(listing);
01085                             listing = NULL;
01086 
01087                             if (r / 100 != 4) {
01088                                    scr_printf("%s\n", buf);
01089                             } else {
01090                                    scr_printf("Wrote %d records.\n", num_recs);
01091                                    modified = 0;
01092                             }
01093                             quitting = 1;
01094                             break;
01095                      case 'q':
01096                             quitting = !modified || boolprompt(
01097                                    "Quit without saving", 0);
01098                             break;
01099                      default:
01100                             break;
01101               }
01102        } while (!quitting);
01103 
01104        if (recs != NULL) {
01105               for (i=0; i<num_recs; ++i) free(recs[i]);
01106               free(recs);
01107        }
01108 }
01109 
01110 
01111 
01112 
01113 
01114 
01115 /*
01116  * RSS feed retrieval client configuration
01117  */
01118 void do_rssclient_configuration(CtdlIPC *ipc)
01119 {
01120        char buf[SIZ];
01121        int num_recs = 0;
01122        char **recs = NULL;
01123        char ch;
01124        int i, j;
01125        int quitting = 0;
01126        int modified = 0;
01127        char *listing = NULL;
01128        char *other_listing = NULL;
01129        int r;
01130        char instr[SIZ];
01131 
01132        r = CtdlIPCGetRoomNetworkConfig(ipc, &listing, buf);
01133        if (r / 100 == 1) {
01134               while(listing && !IsEmptyStr(listing)) {
01135                      extract_token(buf, listing, 0, '\n', sizeof buf);
01136                      remove_token(listing, 0, '\n');
01137                      extract_token(instr, buf, 0, '|', sizeof instr);
01138                      if (!strcasecmp(instr, "rssclient")) {
01139 
01140                             ++num_recs;
01141                             if (num_recs == 1) recs = malloc(sizeof(char *));
01142                             else recs = realloc(recs, (sizeof(char *)) * num_recs);
01143                             recs[num_recs-1] = malloc(SIZ);
01144                             strcpy(recs[num_recs-1], buf);
01145 
01146                      }
01147               }
01148        }
01149        if (listing) {
01150               free(listing);
01151               listing = NULL;
01152        }
01153 
01154        do {
01155               scr_printf("\n");
01156               color(BRIGHT_WHITE);
01157               scr_printf("### Feed URL\n");
01158               color(DIM_WHITE);
01159               scr_printf("--- "
01160                      "---------------------------------------------------------------------------"
01161                      "\n");
01162               
01163               for (i=0; i<num_recs; ++i) {
01164               color(DIM_WHITE);
01165               scr_printf("%3d ", i+1);
01166 
01167               extract_token(buf, recs[i], 1, '|', sizeof buf);
01168               color(BRIGHT_CYAN);
01169               scr_printf("%-75s\n", buf);
01170 
01171               color(DIM_WHITE);
01172               }
01173 
01174               ch = keymenu("", "<A>dd|<D>elete|<S>ave|<Q>uit");
01175               switch(ch) {
01176                      case 'a':
01177                             ++num_recs;
01178                             if (num_recs == 1) {
01179                                    recs = malloc(sizeof(char *));
01180                             }
01181                             else {
01182                                    recs = realloc(recs, (sizeof(char *)) * num_recs);
01183                             }
01184                             strcpy(buf, "rssclient|");
01185                             newprompt("Enter feed URL: ", &buf[strlen(buf)], 75);
01186                             strcat(buf, "|");
01187                             recs[num_recs-1] = strdup(buf);
01188                             modified = 1;
01189                             break;
01190                      case 'd':
01191                             i = intprompt("Delete which one", 1, 1, num_recs) - 1;
01192                             free(recs[i]);
01193                             --num_recs;
01194                             for (j=i; j<num_recs; ++j)
01195                                    recs[j] = recs[j+1];
01196                             modified = 1;
01197                             break;
01198                      case 's':
01199                             r = 1;
01200                             for (i = 0; i < num_recs; ++i) {
01201                                    r += 1 + strlen(recs[i]);
01202                             }
01203                             listing = (char*) calloc(1, r);
01204                             if (!listing) {
01205                                    scr_printf("Can't save config - out of memory!\n");
01206                                    logoff(ipc, 1);
01207                             }
01208                             if (num_recs) for (i = 0; i < num_recs; ++i) {
01209                                    strcat(listing, recs[i]);
01210                                    strcat(listing, "\n");
01211                             }
01212 
01213                             /* Retrieve all the *other* records for merging */
01214                             r = CtdlIPCGetRoomNetworkConfig(ipc, &other_listing, buf);
01215                             if (r / 100 == 1) {
01216                                    for (i=0; i<num_tokens(other_listing, '\n'); ++i) {
01217                                           extract_token(buf, other_listing, i, '\n', sizeof buf);
01218                                           if (strncasecmp(buf, "rssclient|", 10)) {
01219                                                  listing = realloc(listing, strlen(listing) +
01220                                                         strlen(buf) + 10);
01221                                                  strcat(listing, buf);
01222                                                  strcat(listing, "\n");
01223                                           }
01224                                    }
01225                             }
01226                             free(other_listing);
01227                             r = CtdlIPCSetRoomNetworkConfig(ipc, listing, buf);
01228                             free(listing);
01229                             listing = NULL;
01230 
01231                             if (r / 100 != 4) {
01232                                    scr_printf("%s\n", buf);
01233                             } else {
01234                                    scr_printf("Wrote %d records.\n", num_recs);
01235                                    modified = 0;
01236                             }
01237                             quitting = 1;
01238                             break;
01239                      case 'q':
01240                             quitting = !modified || boolprompt(
01241                                    "Quit without saving", 0);
01242                             break;
01243                      default:
01244                             break;
01245               }
01246        } while (!quitting);
01247 
01248        if (recs != NULL) {
01249               for (i=0; i<num_recs; ++i) free(recs[i]);
01250               free(recs);
01251        }
01252 }
01253 
01254