diff --git a/Recipe b/Recipe index 1a34bb86..698d42d9 100644 --- a/Recipe +++ b/Recipe @@ -245,7 +245,7 @@ CFLAGS += -DWINVER=0x0500 -D_WIN32_WINDOWS=0x0410 -D_WIN32_WINNT=0x0500 # Terminal emulator and its (platform-independent) dependencies. TERMINAL = terminal wcwidth ldiscucs logging tree234 minibidi - + config dialog + + config dialog conf # GUI front end and terminal emulator (putty, puttytel). GUITERM = TERMINAL window windlg winctrls sizetip winucs winprint @@ -272,7 +272,7 @@ SFTP = sftp int64 logging # Miscellaneous objects appearing in all the network utilities (not # Pageant or PuTTYgen). -MISC = timing misc version settings tree234 proxy +MISC = timing misc version settings tree234 proxy conf WINMISC = MISC winstore winnet winhandl cmdline windefs winmisc winproxy + wintime UXMISC = MISC uxstore uxsel uxnet cmdline uxmisc uxproxy time @@ -315,12 +315,12 @@ psftp : [C] psftp winsftp wincons WINSSH BE_SSH SFTP wildcard WINMISC pageant : [G] winpgnt sshrsa sshpubk sshdes sshbn sshmd5 version tree234 + misc sshaes sshsha winpgntc sshdss sshsh256 sshsh512 winutils - + winmisc winhelp pageant.res LIBS + + winmisc winhelp conf pageant.res LIBS puttygen : [G] winpgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version + sshrand winnoise sshsha winstore misc winctrls sshrsa sshdss winmisc + sshpubk sshaes sshsh256 sshsh512 import winutils puttygen.res - + tree234 notiming winhelp winnojmp LIBS wintime + + tree234 notiming winhelp winnojmp conf LIBS wintime pterm : [X] GTKTERM uxmisc misc ldisc settings uxpty uxsel BE_NONE uxstore + uxsignal CHARSET cmdline uxpterm version time xpmpterm xpmptcfg @@ -338,7 +338,7 @@ plink : [U] uxplink uxcons NONSSH UXSSH U_BE_ALL logging UXMISC uxsignal puttygen : [U] cmdgen sshrsag sshdssg sshprime sshdes sshbn sshmd5 version + sshrand uxnoise sshsha misc sshrsa sshdss uxcons uxstore uxmisc + sshpubk sshaes sshsh256 sshsh512 import puttygen.res time tree234 - + uxgen notiming + + uxgen notiming conf pscp : [U] pscp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC psftp : [U] psftp uxsftp uxcons UXSSH BE_SSH SFTP wildcard UXMISC diff --git a/cmdline.c b/cmdline.c index bfb2b426..acd3c662 100644 --- a/cmdline.c +++ b/cmdline.c @@ -162,7 +162,7 @@ static int cmdline_check_unavailable(int flag, char *p) if (need_save < 0) return x; \ } while (0) -int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) +int cmdline_process_param(char *p, char *value, int need_save, Conf *conf) { int ret = 0; @@ -170,7 +170,7 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) RETURN(2); /* This parameter must be processed immediately rather than being * saved. */ - do_defaults(value, cfg); + do_defaults(value, conf); loaded_session = TRUE; cmdline_session_name = dupstr(value); return 2; @@ -179,41 +179,49 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - default_protocol = cfg->protocol = PROT_SSH; - default_port = cfg->port = 22; + default_protocol = PROT_SSH; + default_port = 22; + conf_set_int(conf, CONF_protocol, default_protocol); + conf_set_int(conf, CONF_port, default_port); return 1; } if (!strcmp(p, "-telnet")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - default_protocol = cfg->protocol = PROT_TELNET; - default_port = cfg->port = 23; + default_protocol = PROT_TELNET; + default_port = 23; + conf_set_int(conf, CONF_protocol, default_protocol); + conf_set_int(conf, CONF_port, default_port); return 1; } if (!strcmp(p, "-rlogin")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - default_protocol = cfg->protocol = PROT_RLOGIN; - default_port = cfg->port = 513; + default_protocol = PROT_RLOGIN; + default_port = 513; + conf_set_int(conf, CONF_protocol, default_protocol); + conf_set_int(conf, CONF_port, default_port); return 1; } if (!strcmp(p, "-raw")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - default_protocol = cfg->protocol = PROT_RAW; + default_protocol = PROT_RAW; + conf_set_int(conf, CONF_protocol, default_protocol); } if (!strcmp(p, "-serial")) { RETURN(1); /* Serial is not NONNETWORK in an odd sense of the word */ UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - default_protocol = cfg->protocol = PROT_SERIAL; - /* The host parameter will already be loaded into cfg->host, so copy it across */ - strncpy(cfg->serline, cfg->host, sizeof(cfg->serline) - 1); - cfg->serline[sizeof(cfg->serline) - 1] = '\0'; + default_protocol = PROT_SERIAL; + conf_set_int(conf, CONF_protocol, default_protocol); + /* The host parameter will already be loaded into CONF_host, + * so copy it across */ + conf_set_str(conf, CONF_serline, conf_get_str(conf, CONF_host)); } if (!strcmp(p, "-v")) { RETURN(1); @@ -223,41 +231,23 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - strncpy(cfg->username, value, sizeof(cfg->username)); - cfg->username[sizeof(cfg->username) - 1] = '\0'; + conf_set_str(conf, CONF_username, value); } if (!strcmp(p, "-loghost")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - strncpy(cfg->loghost, value, sizeof(cfg->loghost)); - cfg->loghost[sizeof(cfg->loghost) - 1] = '\0'; + conf_set_str(conf, CONF_loghost, value); } if ((!strcmp(p, "-L") || !strcmp(p, "-R") || !strcmp(p, "-D"))) { - char *fwd, *ptr, *q, *qq; - int dynamic, i=0; + char type, *q, *qq, *key, *val; RETURN(2); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - dynamic = !strcmp(p, "-D"); - fwd = value; - ptr = cfg->portfwd; - /* if existing forwards, find end of list */ - while (*ptr) { - while (*ptr) - ptr++; - ptr++; - } - i = ptr - cfg->portfwd; - ptr[0] = p[1]; /* insert a 'L', 'R' or 'D' at the start */ - ptr++; - if (1 + strlen(fwd) + 2 > sizeof(cfg->portfwd) - i) { - cmdline_error("out of space for port forwardings"); - return ret; - } - strncpy(ptr, fwd, sizeof(cfg->portfwd) - i - 2); - if (!dynamic) { + if (strcmp(p, "-D")) { /* + * For -L or -R forwarding types: + * * We expect _at least_ two colons in this string. The * possible formats are `sourceport:desthost:destport', * or `sourceip:sourceport:desthost:destport' if you're @@ -265,19 +255,47 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) * replace the one between source and dest with a \t; * this means we must find the second-to-last colon in * the string. + * + * (This looks like a foolish way of doing it given the + * existence of strrchr, but it's more efficient than + * two strrchrs - not to mention that the second strrchr + * would require us to modify the input string!) */ - q = qq = strchr(ptr, ':'); + + type = p[1]; /* 'L' or 'R' */ + + q = qq = strchr(value, ':'); while (qq) { char *qqq = strchr(qq+1, ':'); if (qqq) q = qq; qq = qqq; } - if (q) *q = '\t'; /* replace second-last colon with \t */ + + if (!q) { + cmdline_error("-%c expects at least two colons in its" + " argument", type); + return ret; + } + + key = dupprintf("%c%.*s", type, q - value, value); + val = dupstr(q+1); + } else { + /* + * Dynamic port forwardings are entered under the same key + * as if they were local (because they occupy the same + * port space - a local and a dynamic forwarding on the + * same local port are mutually exclusive), with the + * special value "D" (which can be distinguished from + * anything in the ordinary -L case by containing no + * colon). + */ + key = dupprintf("L%s", value); + val = dupstr("D"); } - cfg->portfwd[sizeof(cfg->portfwd) - 1] = '\0'; - cfg->portfwd[sizeof(cfg->portfwd) - 2] = '\0'; - ptr[strlen(ptr)+1] = '\000'; /* append 2nd '\000' */ + conf_set_str_str(conf, CONF_portfwd, key, val); + sfree(key); + sfree(val); } if ((!strcmp(p, "-nc"))) { char *host, *portp; @@ -286,20 +304,15 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - host = portp = value; - while (*portp && *portp != ':') - portp++; - if (*portp) { - unsigned len = portp - host; - if (len >= sizeof(cfg->ssh_nc_host)) - len = sizeof(cfg->ssh_nc_host) - 1; - memcpy(cfg->ssh_nc_host, value, len); - cfg->ssh_nc_host[len] = '\0'; - cfg->ssh_nc_port = atoi(portp+1); - } else { + portp = strchr(value, ':'); + if (!portp) { cmdline_error("-nc expects argument of form 'host:port'"); return ret; } + + host = dupprintf("%.*s", portp - value, value); + conf_set_str(conf, CONF_ssh_nc_host, host); + conf_set_int(conf, CONF_ssh_nc_port, atoi(portp + 1)); } if (!strcmp(p, "-m")) { char *filename, *command; @@ -317,8 +330,7 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) command = NULL; fp = fopen(filename, "r"); if (!fp) { - cmdline_error("unable to open command " - "file \"%s\"", filename); + cmdline_error("unable to open command file \"%s\"", filename); return ret; } do { @@ -332,16 +344,17 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) } command[cmdlen++] = d; } while (c != EOF); - cfg->remote_cmd_ptr = command; - cfg->remote_cmd_ptr2 = NULL; - cfg->nopty = TRUE; /* command => no terminal */ fclose(fp); + conf_set_str(conf, CONF_remote_cmd, command); + conf_set_str(conf, CONF_remote_cmd2, ""); + conf_set_int(conf, CONF_nopty, TRUE); /* command => no terminal */ + sfree(command); } if (!strcmp(p, "-P")) { RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(1); /* lower priority than -ssh,-telnet */ - cfg->port = atoi(value); + conf_set_int(conf, CONF_port, atoi(value)); } if (!strcmp(p, "-pw")) { RETURN(2); @@ -349,7 +362,7 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) SAVEABLE(1); /* We delay evaluating this until after the protocol is decided, * so that we can warn if it's of no use with the selected protocol */ - if (cfg->protocol != PROT_SSH) + if (conf_get_int(conf, CONF_protocol) != PROT_SSH) cmdline_error("the -pw option can only be used with the " "SSH protocol"); else { @@ -366,105 +379,107 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->tryagent = TRUE; + conf_set_int(conf, CONF_tryagent, TRUE); } if (!strcmp(p, "-noagent") || !strcmp(p, "-nopagent") || !strcmp(p, "-nopageant")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->tryagent = FALSE; + conf_set_int(conf, CONF_tryagent, FALSE); } if (!strcmp(p, "-A")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->agentfwd = 1; + conf_set_int(conf, CONF_agentfwd, 1); } if (!strcmp(p, "-a")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->agentfwd = 0; + conf_set_int(conf, CONF_agentfwd, 0); } if (!strcmp(p, "-X")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->x11_forward = 1; + conf_set_int(conf, CONF_x11_forward, 1); } if (!strcmp(p, "-x")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->x11_forward = 0; + conf_set_int(conf, CONF_x11_forward, 0); } if (!strcmp(p, "-t")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(1); /* lower priority than -m */ - cfg->nopty = 0; + conf_set_int(conf, CONF_nopty, 0); } if (!strcmp(p, "-T")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(1); - cfg->nopty = 1; + conf_set_int(conf, CONF_nopty, 1); } if (!strcmp(p, "-N")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->ssh_no_shell = 1; + conf_set_int(conf, CONF_ssh_no_shell, 1); } if (!strcmp(p, "-C")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->compression = 1; + conf_set_int(conf, CONF_compression, 1); } if (!strcmp(p, "-1")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->sshprot = 0; /* ssh protocol 1 only */ + conf_set_int(conf, CONF_sshprot, 0); /* ssh protocol 1 only */ } if (!strcmp(p, "-2")) { RETURN(1); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->sshprot = 3; /* ssh protocol 2 only */ + conf_set_int(conf, CONF_sshprot, 3); /* ssh protocol 2 only */ } if (!strcmp(p, "-i")) { + Filename fn; RETURN(2); UNAVAILABLE_IN(TOOLTYPE_NONNETWORK); SAVEABLE(0); - cfg->keyfile = filename_from_str(value); + fn = filename_from_str(value); + conf_set_filename(conf, CONF_keyfile, &fn); } if (!strcmp(p, "-4") || !strcmp(p, "-ipv4")) { RETURN(1); SAVEABLE(1); - cfg->addressfamily = ADDRTYPE_IPV4; + conf_set_int(conf, CONF_addressfamily, ADDRTYPE_IPV4); } if (!strcmp(p, "-6") || !strcmp(p, "-ipv6")) { RETURN(1); SAVEABLE(1); - cfg->addressfamily = ADDRTYPE_IPV6; + conf_set_int(conf, CONF_addressfamily, ADDRTYPE_IPV6); } if (!strcmp(p, "-sercfg")) { char* nextitem; RETURN(2); UNAVAILABLE_IN(TOOLTYPE_FILETRANSFER | TOOLTYPE_NONNETWORK); SAVEABLE(1); - if (cfg->protocol != PROT_SERIAL) + if (conf_get_int(conf, CONF_protocol) != PROT_SERIAL) cmdline_error("the -sercfg option can only be used with the " "serial protocol"); /* Value[0] contains one or more , separated values, like 19200,8,n,1,X */ @@ -483,55 +498,41 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) if (length == 1) { switch (*nextitem) { case '1': - cfg->serstopbits = 2; - break; case '2': - cfg->serstopbits = 4; + conf_set_int(conf, CONF_serstopbits, 2 * (*nextitem-'0')); break; case '5': - cfg->serdatabits = 5; - break; - case '6': - cfg->serdatabits = 6; - break; - case '7': - cfg->serdatabits = 7; - break; - case '8': - cfg->serdatabits = 8; - break; - case '9': - cfg->serdatabits = 9; + conf_set_int(conf, CONF_serdatabits, *nextitem-'0'); break; case 'n': - cfg->serparity = SER_PAR_NONE; + conf_set_int(conf, CONF_serparity, SER_PAR_NONE); break; case 'o': - cfg->serparity = SER_PAR_ODD; + conf_set_int(conf, CONF_serparity, SER_PAR_ODD); break; case 'e': - cfg->serparity = SER_PAR_EVEN; + conf_set_int(conf, CONF_serparity, SER_PAR_EVEN); break; case 'm': - cfg->serparity = SER_PAR_MARK; + conf_set_int(conf, CONF_serparity, SER_PAR_MARK); break; case 's': - cfg->serparity = SER_PAR_SPACE; + conf_set_int(conf, CONF_serparity, SER_PAR_SPACE); break; case 'N': - cfg->serflow = SER_FLOW_NONE; + conf_set_int(conf, CONF_serflow, SER_FLOW_NONE); break; case 'X': - cfg->serflow = SER_FLOW_XONXOFF; + conf_set_int(conf, CONF_serflow, SER_FLOW_XONXOFF); break; case 'R': - cfg->serflow = SER_FLOW_RTSCTS; + conf_set_int(conf, CONF_serflow, SER_FLOW_RTSCTS); break; case 'D': - cfg->serflow = SER_FLOW_DSRDTR; + conf_set_int(conf, CONF_serflow, SER_FLOW_DSRDTR); break; default: @@ -540,11 +541,11 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) } } else if (length == 3 && !strncmp(nextitem,"1.5",3)) { /* Messy special case */ - cfg->serstopbits = 3; + conf_set_int(conf, CONF_serstopbits, 3); } else { int serspeed = atoi(nextitem); if (serspeed != 0) { - cfg->serspeed = serspeed; + conf_set_int(conf, CONF_serspeed, serspeed); } else { cmdline_error("Unrecognised suboption \"-sercfg %s\"", nextitem); @@ -556,11 +557,11 @@ int cmdline_process_param(char *p, char *value, int need_save, Config *cfg) return ret; /* unrecognised */ } -void cmdline_run_saved(Config *cfg) +void cmdline_run_saved(Conf *conf) { int pri, i; for (pri = 0; pri < NPRIORITIES; pri++) for (i = 0; i < saves[pri].nsaved; i++) cmdline_process_param(saves[pri].params[i].p, - saves[pri].params[i].value, 0, cfg); + saves[pri].params[i].value, 0, conf); } diff --git a/conf.c b/conf.c new file mode 100644 index 00000000..89bf5c3b --- /dev/null +++ b/conf.c @@ -0,0 +1,610 @@ +/* + * conf.c: implementation of the internal storage format used for + * the configuration of a PuTTY session. + */ + +#include +#include +#include + +#include "tree234.h" +#include "putty.h" + +/* + * Enumeration of types used in keys and values. + */ +typedef enum { TYPE_NONE, TYPE_INT, TYPE_STR, TYPE_FILENAME, TYPE_FONT } Type; + +/* + * Arrays which allow us to look up the subkey and value types for a + * given primary key id. + */ +#define CONF_SUBKEYTYPE_DEF(valtype, keytype, keyword) TYPE_ ## keytype, +static int subkeytypes[] = { CONFIG_OPTIONS(CONF_SUBKEYTYPE_DEF) }; +#define CONF_VALUETYPE_DEF(valtype, keytype, keyword) TYPE_ ## valtype, +static int valuetypes[] = { CONFIG_OPTIONS(CONF_VALUETYPE_DEF) }; + +/* + * Configuration keys are primarily integers (big enum of all the + * different configurable options); some keys have string-designated + * subkeys, such as the list of environment variables (subkeys + * defined by the variable names); some have integer-designated + * subkeys (wordness, colours, preference lists). + */ +struct key { + int primary; + union { + int i; + char *s; + } secondary; +}; + +struct value { + union { + int intval; + char *stringval; + Filename fileval; + FontSpec fontval; + } u; +}; + +struct conf_entry { + struct key key; + struct value value; +}; + +struct conf_tag { + tree234 *tree; +}; + +/* + * Because 'struct key' is the first element in 'struct conf_entry', + * it's safe (guaranteed by the C standard) to cast arbitrarily back + * and forth between the two types. Therefore, we only need one + * comparison function, which can double as a main sort function for + * the tree (comparing two conf_entry structures with each other) + * and a search function (looking up an externally supplied key). + */ +static int conf_cmp(void *av, void *bv) +{ + struct key *a = (struct key *)av; + struct key *b = (struct key *)bv; + + if (a->primary < b->primary) + return -1; + else if (a->primary > b->primary) + return +1; + switch (subkeytypes[a->primary]) { + case TYPE_INT: + if (a->secondary.i < b->secondary.i) + return -1; + else if (a->secondary.i > b->secondary.i) + return +1; + return 0; + case TYPE_STR: + return strcmp(a->secondary.s, b->secondary.s); + default: + return 0; + } +} + +/* + * Free any dynamic data items pointed to by a 'struct key'. We + * don't free the structure itself, since it's probably part of a + * larger allocated block. + */ +static void free_key(struct key *key) +{ + if (subkeytypes[key->primary] == TYPE_STR) + sfree(key->secondary.s); +} + +/* + * Copy a 'struct key' into another one, copying its dynamic data + * if necessary. + */ +static void copy_key(struct key *to, struct key *from) +{ + to->primary = from->primary; + switch (subkeytypes[to->primary]) { + case TYPE_INT: + to->secondary.i = from->secondary.i; + break; + case TYPE_STR: + to->secondary.s = dupstr(from->secondary.s); + break; + } +} + +/* + * Free any dynamic data items pointed to by a 'struct value'. We + * don't free the value itself, since it's probably part of a larger + * allocated block. + */ +static void free_value(struct value *val, int type) +{ + if (type == TYPE_STR) + sfree(val->u.stringval); +} + +/* + * Copy a 'struct value' into another one, copying its dynamic data + * if necessary. + */ +static void copy_value(struct value *to, struct value *from, int type) +{ + switch (type) { + case TYPE_INT: + to->u.intval = from->u.intval; + break; + case TYPE_STR: + to->u.stringval = dupstr(from->u.stringval); + break; + case TYPE_FILENAME: + to->u.fileval = from->u.fileval; + break; + case TYPE_FONT: + to->u.fontval = from->u.fontval; + break; + } +} + +/* + * Free an entire 'struct conf_entry' and its dynamic data. + */ +static void free_entry(struct conf_entry *entry) +{ + free_key(&entry->key); + free_value(&entry->value, valuetypes[entry->key.primary]); + sfree(entry); +} + +Conf *conf_new(void) +{ + Conf *conf = snew(struct conf_tag); + + conf->tree = newtree234(conf_cmp); + + return conf; +} + +static void conf_clear(Conf *conf) +{ + struct conf_entry *entry; + + while ((entry = delpos234(conf->tree, 0)) != NULL) + free_entry(entry); +} + +void conf_free(Conf *conf) +{ + conf_clear(conf); + freetree234(conf->tree); + sfree(conf); +} + +static void conf_insert(Conf *conf, struct conf_entry *entry) +{ + struct conf_entry *oldentry = add234(conf->tree, entry); + if (oldentry && oldentry != entry) { + del234(conf->tree, oldentry); + free_entry(oldentry); + oldentry = add234(conf->tree, entry); + assert(oldentry == entry); + } +} + +void conf_copy_into(Conf *newconf, Conf *oldconf) +{ + struct conf_entry *entry, *entry2; + int i; + + for (i = 0; (entry = index234(oldconf->tree, i)) != NULL; i++) { + entry2 = snew(struct conf_entry); + copy_key(&entry2->key, &entry->key); + copy_value(&entry2->value, &entry->value, + valuetypes[entry->key.primary]); + add234(newconf->tree, entry2); + } +} + +Conf *conf_copy(Conf *oldconf) +{ + Conf *newconf = conf_new(); + + conf_copy_into(newconf, oldconf); + + return newconf; +} + +int conf_get_int(Conf *conf, int primary) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_INT); + key.primary = primary; + entry = find234(conf->tree, &key, NULL); + assert(entry); + return entry->value.u.intval; +} + +int conf_get_int_int(Conf *conf, int primary, int secondary) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_INT); + assert(valuetypes[primary] == TYPE_INT); + key.primary = primary; + key.secondary.i = secondary; + entry = find234(conf->tree, &key, NULL); + assert(entry); + return entry->value.u.intval; +} + +char *conf_get_str(Conf *conf, int primary) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_STR); + key.primary = primary; + entry = find234(conf->tree, &key, NULL); + assert(entry); + return entry->value.u.stringval; +} + +char *conf_get_str_str_opt(Conf *conf, int primary, const char *secondary) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_STR); + assert(valuetypes[primary] == TYPE_STR); + key.primary = primary; + key.secondary.s = (char *)secondary; + entry = find234(conf->tree, &key, NULL); + return entry ? entry->value.u.stringval : NULL; +} + +char *conf_get_str_str(Conf *conf, int primary, const char *secondary) +{ + char *ret = conf_get_str_str_opt(conf, primary, secondary); + assert(ret); + return ret; +} + +char *conf_get_str_strs(Conf *conf, int primary, + char *subkeyin, char **subkeyout) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_STR); + assert(valuetypes[primary] == TYPE_STR); + key.primary = primary; + if (subkeyin) { + key.secondary.s = subkeyin; + entry = findrel234(conf->tree, &key, NULL, REL234_GT); + } else { + key.secondary.s = ""; + entry = findrel234(conf->tree, &key, NULL, REL234_GE); + } + if (!entry || entry->key.primary != primary) + return NULL; + *subkeyout = entry->key.secondary.s; + return entry->value.u.stringval; +} + +char *conf_get_str_nthstrkey(Conf *conf, int primary, int n) +{ + struct key key; + struct conf_entry *entry; + int index; + + assert(subkeytypes[primary] == TYPE_STR); + assert(valuetypes[primary] == TYPE_STR); + key.primary = primary; + key.secondary.s = ""; + entry = findrelpos234(conf->tree, &key, NULL, REL234_GE, &index); + if (!entry || entry->key.primary != primary) + return NULL; + entry = index234(conf->tree, index + n); + if (!entry || entry->key.primary != primary) + return NULL; + return entry->key.secondary.s; +} + +Filename *conf_get_filename(Conf *conf, int primary) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_FILENAME); + key.primary = primary; + entry = find234(conf->tree, &key, NULL); + assert(entry); + return &entry->value.u.fileval; +} + +FontSpec *conf_get_fontspec(Conf *conf, int primary) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_FONT); + key.primary = primary; + entry = find234(conf->tree, &key, NULL); + assert(entry); + return &entry->value.u.fontval; +} + +void conf_set_int(Conf *conf, int primary, int value) +{ + struct conf_entry *entry = snew(struct conf_entry); + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_INT); + entry->key.primary = primary; + entry->value.u.intval = value; + conf_insert(conf, entry); +} + +void conf_set_int_int(Conf *conf, int primary, int secondary, int value) +{ + struct conf_entry *entry = snew(struct conf_entry); + + assert(subkeytypes[primary] == TYPE_INT); + assert(valuetypes[primary] == TYPE_INT); + entry->key.primary = primary; + entry->key.secondary.i = secondary; + entry->value.u.intval = value; + conf_insert(conf, entry); +} + +void conf_set_str(Conf *conf, int primary, const char *value) +{ + struct conf_entry *entry = snew(struct conf_entry); + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_STR); + entry->key.primary = primary; + entry->value.u.stringval = dupstr(value); + conf_insert(conf, entry); +} + +void conf_set_str_str(Conf *conf, int primary, const char *secondary, + const char *value) +{ + struct conf_entry *entry = snew(struct conf_entry); + + assert(subkeytypes[primary] == TYPE_STR); + assert(valuetypes[primary] == TYPE_STR); + entry->key.primary = primary; + entry->key.secondary.s = dupstr(secondary); + entry->value.u.stringval = dupstr(value); + conf_insert(conf, entry); +} + +void conf_del_str_str(Conf *conf, int primary, const char *secondary) +{ + struct key key; + struct conf_entry *entry; + + assert(subkeytypes[primary] == TYPE_STR); + assert(valuetypes[primary] == TYPE_STR); + key.primary = primary; + key.secondary.s = (char *)secondary; + entry = find234(conf->tree, &key, NULL); + if (entry) { + del234(conf->tree, entry); + free_entry(entry); + } + } + +void conf_set_filename(Conf *conf, int primary, const Filename *value) +{ + struct conf_entry *entry = snew(struct conf_entry); + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_FILENAME); + entry->key.primary = primary; + entry->value.u.fileval = *value; /* structure copy */ + conf_insert(conf, entry); +} + +void conf_set_fontspec(Conf *conf, int primary, const FontSpec *value) +{ + struct conf_entry *entry = snew(struct conf_entry); + + assert(subkeytypes[primary] == TYPE_NONE); + assert(valuetypes[primary] == TYPE_FONT); + entry->key.primary = primary; + entry->value.u.fontval = *value; /* structure copy */ + conf_insert(conf, entry); +} + +int conf_serialised_size(Conf *conf) +{ + int i; + struct conf_entry *entry; + int size = 0; + + for (i = 0; (entry = index234(conf->tree, i)) != NULL; i++) { + size += 4; /* primary key */ + switch (subkeytypes[entry->key.primary]) { + case TYPE_INT: + size += 4; + break; + case TYPE_STR: + size += 1 + strlen(entry->key.secondary.s); + break; + } + switch (valuetypes[entry->key.primary]) { + case TYPE_INT: + size += 4; + break; + case TYPE_STR: + size += 1 + strlen(entry->value.u.stringval); + break; + case TYPE_FILENAME: + size += sizeof(entry->value.u.fileval); + break; + case TYPE_FONT: + size += sizeof(entry->value.u.fontval); + break; + } + } + + size += 4; /* terminator value */ + + return size; +} + +void conf_serialise(Conf *conf, void *vdata) +{ + unsigned char *data = (unsigned char *)vdata; + int i, len; + struct conf_entry *entry; + + for (i = 0; (entry = index234(conf->tree, i)) != NULL; i++) { + PUT_32BIT_MSB_FIRST(data, entry->key.primary); + data += 4; + + switch (subkeytypes[entry->key.primary]) { + case TYPE_INT: + PUT_32BIT_MSB_FIRST(data, entry->key.secondary.i); + data += 4; + break; + case TYPE_STR: + len = strlen(entry->key.secondary.s); + memcpy(data, entry->key.secondary.s, len); + data += len; + *data++ = 0; + break; + } + switch (valuetypes[entry->key.primary]) { + case TYPE_INT: + PUT_32BIT_MSB_FIRST(data, entry->value.u.intval); + data += 4; + break; + case TYPE_STR: + len = strlen(entry->value.u.stringval); + memcpy(data, entry->value.u.stringval, len); + data += len; + *data++ = 0; + break; + case TYPE_FILENAME: + memcpy(data, &entry->value.u.fileval, + sizeof(entry->value.u.fileval)); + data += sizeof(entry->value.u.fileval); + break; + case TYPE_FONT: + memcpy(data, &entry->value.u.fontval, + sizeof(entry->value.u.fontval)); + data += sizeof(entry->value.u.fontval); + break; + } + } + + PUT_32BIT_MSB_FIRST(data, 0xFFFFFFFFU); +} + +int conf_deserialise(Conf *conf, void *vdata, int maxsize) +{ + unsigned char *data = (unsigned char *)vdata; + unsigned char *start = data; + struct conf_entry *entry; + int primary; + unsigned char *zero; + + while (maxsize >= 4) { + primary = GET_32BIT_MSB_FIRST(data); + data += 4, maxsize -= 4; + + if ((unsigned)primary >= N_CONFIG_OPTIONS) + break; + + entry = snew(struct conf_entry); + entry->key.primary = primary; + + switch (subkeytypes[entry->key.primary]) { + case TYPE_INT: + if (maxsize < 4) { + sfree(entry); + goto done; + } + entry->key.secondary.i = GET_32BIT_MSB_FIRST(data); + data += 4, maxsize -= 4; + break; + case TYPE_STR: + zero = memchr(data, 0, maxsize); + if (!zero) { + sfree(entry); + goto done; + } + entry->key.secondary.s = dupstr((char *)data); + maxsize -= (zero + 1 - data); + data = zero + 1; + break; + } + + switch (valuetypes[entry->key.primary]) { + case TYPE_INT: + if (maxsize < 4) { + if (subkeytypes[entry->key.primary] == TYPE_STR) + sfree(entry->key.secondary.s); + sfree(entry); + goto done; + } + entry->value.u.intval = GET_32BIT_MSB_FIRST(data); + data += 4, maxsize -= 4; + break; + case TYPE_STR: + zero = memchr(data, 0, maxsize); + if (!zero) { + if (subkeytypes[entry->key.primary] == TYPE_STR) + sfree(entry->key.secondary.s); + sfree(entry); + goto done; + } + entry->value.u.stringval = dupstr((char *)data); + maxsize -= (zero + 1 - data); + data = zero + 1; + break; + case TYPE_FILENAME: + if (maxsize < sizeof(entry->value.u.fileval)) { + if (subkeytypes[entry->key.primary] == TYPE_STR) + sfree(entry->key.secondary.s); + sfree(entry); + goto done; + } + memcpy(&entry->value.u.fileval, data, + sizeof(entry->value.u.fileval)); + data += sizeof(entry->value.u.fileval); + maxsize -= sizeof(entry->value.u.fileval); + break; + case TYPE_FONT: + if (maxsize < sizeof(entry->value.u.fontval)) { + if (subkeytypes[entry->key.primary] == TYPE_STR) + sfree(entry->key.secondary.s); + sfree(entry); + goto done; + } + memcpy(&entry->value.u.fontval, data, + sizeof(entry->value.u.fontval)); + data += sizeof(entry->value.u.fontval); + maxsize -= sizeof(entry->value.u.fontval); + break; + } + conf_insert(conf, entry); + } + + done: + return (int)(data - start); +} diff --git a/config.c b/config.c index a1454b4d..a03116b9 100644 --- a/config.c +++ b/config.c @@ -15,10 +15,151 @@ #define HOST_BOX_TITLE "Host Name (or IP address)" #define PORT_BOX_TITLE "Port" +void conf_radiobutton_handler(union control *ctrl, void *dlg, + void *data, int event) +{ + int button; + Conf *conf = (Conf *)data; + + /* + * For a standard radio button set, the context parameter gives + * the primary key (CONF_foo), and the extra data per button + * gives the value the target field should take if that button + * is the one selected. + */ + if (event == EVENT_REFRESH) { + int val = conf_get_int(conf, ctrl->radio.context.i); + for (button = 0; button < ctrl->radio.nbuttons; button++) + if (val == ctrl->radio.buttondata[button].i) + break; + /* We expected that `break' to happen, in all circumstances. */ + assert(button < ctrl->radio.nbuttons); + dlg_radiobutton_set(ctrl, dlg, button); + } else if (event == EVENT_VALCHANGE) { + button = dlg_radiobutton_get(ctrl, dlg); + assert(button >= 0 && button < ctrl->radio.nbuttons); + conf_set_int(conf, ctrl->radio.context.i, + ctrl->radio.buttondata[button].i); + } +} + +#define CHECKBOX_INVERT (1<<30) +void conf_checkbox_handler(union control *ctrl, void *dlg, + void *data, int event) +{ + int key, invert; + Conf *conf = (Conf *)data; + + /* + * For a standard checkbox, the context parameter gives the + * primary key (CONF_foo), optionally ORed with CHECKBOX_INVERT. + */ + key = ctrl->checkbox.context.i; + if (key & CHECKBOX_INVERT) { + key &= ~CHECKBOX_INVERT; + invert = 1; + } else + invert = 0; + + /* + * C lacks a logical XOR, so the following code uses the idiom + * (!a ^ !b) to obtain the logical XOR of a and b. (That is, 1 + * iff exactly one of a and b is nonzero, otherwise 0.) + */ + + if (event == EVENT_REFRESH) { + int val = conf_get_int(conf, key); + dlg_checkbox_set(ctrl, dlg, (!val ^ !invert)); + } else if (event == EVENT_VALCHANGE) { + conf_set_int(conf, key, !dlg_checkbox_get(ctrl,dlg) ^ !invert); + } +} + +void conf_editbox_handler(union control *ctrl, void *dlg, + void *data, int event) +{ + /* + * The standard edit-box handler expects the main `context' + * field to contain the primary key. The secondary `context2' + * field indicates the type of this field: + * + * - if context2 > 0, the field is a string. + * - if context2 == -1, the field is an int and the edit box + * is numeric. + * - if context2 < -1, the field is an int and the edit box is + * _floating_, and (-context2) gives the scale. (E.g. if + * context2 == -1000, then typing 1.2 into the box will set + * the field to 1200.) + */ + int key = ctrl->editbox.context.i; + int length = ctrl->editbox.context2.i; + Conf *conf = (Conf *)data; + + if (length > 0) { + if (event == EVENT_REFRESH) { + char *field = conf_get_str(conf, key); + dlg_editbox_set(ctrl, dlg, field); + } else if (event == EVENT_VALCHANGE) { + char *field = dlg_editbox_get(ctrl, dlg); + conf_set_str(conf, key, field); + sfree(field); + } + } else if (length < 0) { + if (event == EVENT_REFRESH) { + char str[80]; + int value = conf_get_int(conf, key); + if (length == -1) + sprintf(str, "%d", value); + else + sprintf(str, "%g", (double)value / (double)(-length)); + dlg_editbox_set(ctrl, dlg, str); + } else if (event == EVENT_VALCHANGE) { + char *str = dlg_editbox_get(ctrl, dlg); + if (length == -1) + conf_set_int(conf, key, atoi(str)); + else + conf_set_int(conf, key, (int)((-length) * atof(str))); + sfree(str); + } + } +} + +void conf_filesel_handler(union control *ctrl, void *dlg, + void *data, int event) +{ + int key = ctrl->fileselect.context.i; + Conf *conf = (Conf *)data; + + if (event == EVENT_REFRESH) { + dlg_filesel_set(ctrl, dlg, *conf_get_filename(conf, key)); + } else if (event == EVENT_VALCHANGE) { + Filename filename; + dlg_filesel_get(ctrl, dlg, &filename); + conf_set_filename(conf, key, &filename); + /* If Filenames ever become dynamic, free this one. */ + } +} + +void conf_fontsel_handler(union control *ctrl, void *dlg, + void *data, int event) +{ + int key = ctrl->fontselect.context.i; + Conf *conf = (Conf *)data; + + if (event == EVENT_REFRESH) { + dlg_fontsel_set(ctrl, dlg, *conf_get_fontspec(conf, key)); + } else if (event == EVENT_VALCHANGE) { + FontSpec fontspec; + dlg_fontsel_get(ctrl, dlg, &fontspec); + conf_set_fontspec(conf, key, &fontspec); + /* If FontSpecs ever become dynamic, free this one. */ + } +} + static void config_host_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; /* * This function works just like the standard edit box handler, @@ -26,29 +167,31 @@ static void config_host_handler(union control *ctrl, void *dlg, * different places depending on the protocol. */ if (event == EVENT_REFRESH) { - if (cfg->protocol == PROT_SERIAL) { + if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) { /* * This label text is carefully chosen to contain an n, * since that's the shortcut for the host name control. */ dlg_label_change(ctrl, dlg, "Serial line"); - dlg_editbox_set(ctrl, dlg, cfg->serline); + dlg_editbox_set(ctrl, dlg, conf_get_str(conf, CONF_serline)); } else { dlg_label_change(ctrl, dlg, HOST_BOX_TITLE); - dlg_editbox_set(ctrl, dlg, cfg->host); + dlg_editbox_set(ctrl, dlg, conf_get_str(conf, CONF_host)); } } else if (event == EVENT_VALCHANGE) { - if (cfg->protocol == PROT_SERIAL) - dlg_editbox_get(ctrl, dlg, cfg->serline, lenof(cfg->serline)); + char *s = dlg_editbox_get(ctrl, dlg); + if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) + conf_set_str(conf, CONF_serline, s); else - dlg_editbox_get(ctrl, dlg, cfg->host, lenof(cfg->host)); + conf_set_str(conf, CONF_host, s); + sfree(s); } } static void config_port_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; char buf[80]; /* @@ -57,28 +200,31 @@ static void config_port_handler(union control *ctrl, void *dlg, * different places depending on the protocol. */ if (event == EVENT_REFRESH) { - if (cfg->protocol == PROT_SERIAL) { + if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) { /* * This label text is carefully chosen to contain a p, * since that's the shortcut for the port control. */ dlg_label_change(ctrl, dlg, "Speed"); - sprintf(buf, "%d", cfg->serspeed); + sprintf(buf, "%d", conf_get_int(conf, CONF_serspeed)); } else { dlg_label_change(ctrl, dlg, PORT_BOX_TITLE); - if (cfg->port != 0) - sprintf(buf, "%d", cfg->port); + if (conf_get_int(conf, CONF_port) != 0) + sprintf(buf, "%d", conf_get_int(conf, CONF_port)); else /* Display an (invalid) port of 0 as blank */ buf[0] = '\0'; } dlg_editbox_set(ctrl, dlg, buf); } else if (event == EVENT_VALCHANGE) { - dlg_editbox_get(ctrl, dlg, buf, lenof(buf)); - if (cfg->protocol == PROT_SERIAL) - cfg->serspeed = atoi(buf); + char *s = dlg_editbox_get(ctrl, dlg); + int i = atoi(s); + sfree(s); + + if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) + conf_set_int(conf, CONF_serspeed, i); else - cfg->port = atoi(buf); + conf_set_int(conf, CONF_port, i); } } @@ -95,7 +241,7 @@ void config_protocolbuttons_handler(union control *ctrl, void *dlg, void *data, int event) { int button; - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; struct hostport *hp = (struct hostport *)ctrl->radio.context.p; /* @@ -106,20 +252,25 @@ void config_protocolbuttons_handler(union control *ctrl, void *dlg, * structure giving the `union control's for both. */ if (event == EVENT_REFRESH) { + int protocol = conf_get_int(conf, CONF_protocol); for (button = 0; button < ctrl->radio.nbuttons; button++) - if (cfg->protocol == ctrl->radio.buttondata[button].i) + if (protocol == ctrl->radio.buttondata[button].i) break; /* We expected that `break' to happen, in all circumstances. */ assert(button < ctrl->radio.nbuttons); dlg_radiobutton_set(ctrl, dlg, button); } else if (event == EVENT_VALCHANGE) { - int oldproto = cfg->protocol; + int oldproto = conf_get_int(conf, CONF_protocol); + int newproto, port; + button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); - cfg->protocol = ctrl->radio.buttondata[button].i; - if (oldproto != cfg->protocol) { + newproto = ctrl->radio.buttondata[button].i; + conf_set_int(conf, CONF_protocol, newproto); + + if (oldproto != newproto) { Backend *ob = backend_from_proto(oldproto); - Backend *nb = backend_from_proto(cfg->protocol); + Backend *nb = backend_from_proto(newproto); assert(ob); assert(nb); /* Iff the user hasn't changed the port from the old protocol's @@ -131,8 +282,9 @@ void config_protocolbuttons_handler(union control *ctrl, void *dlg, * controls in order and setting a non-default port before * getting to the protocol; we want that non-default port * to be preserved. */ - if (cfg->port == ob->default_port) - cfg->port = nb->default_port; + port = conf_get_int(conf, CONF_port); + if (port == ob->default_port) + conf_set_int(conf, CONF_port, nb->default_port); } dlg_refresh(hp->host, dlg); dlg_refresh(hp->port, dlg); @@ -143,26 +295,28 @@ static void loggingbuttons_handler(union control *ctrl, void *dlg, void *data, int event) { int button; - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; /* This function works just like the standard radio-button handler, * but it has to fall back to "no logging" in situations where the * configured logging type isn't applicable. */ if (event == EVENT_REFRESH) { + int logtype = conf_get_int(conf, CONF_logtype); + for (button = 0; button < ctrl->radio.nbuttons; button++) - if (cfg->logtype == ctrl->radio.buttondata[button].i) + if (logtype == ctrl->radio.buttondata[button].i) break; - - /* We fell off the end, so we lack the configured logging type */ - if (button == ctrl->radio.nbuttons) { - button=0; - cfg->logtype=LGTYP_NONE; - } - dlg_radiobutton_set(ctrl, dlg, button); + + /* We fell off the end, so we lack the configured logging type */ + if (button == ctrl->radio.nbuttons) { + button = 0; + conf_set_int(conf, CONF_logtype, LGTYP_NONE); + } + dlg_radiobutton_set(ctrl, dlg, button); } else if (event == EVENT_VALCHANGE) { button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); - cfg->logtype = ctrl->radio.buttondata[button].i; + conf_set_int(conf, CONF_logtype, ctrl->radio.buttondata[button].i); } } @@ -170,15 +324,15 @@ static void numeric_keypad_handler(union control *ctrl, void *dlg, void *data, int event) { int button; - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; /* * This function works much like the standard radio button - * handler, but it has to handle two fields in Config. + * handler, but it has to handle two fields in Conf. */ if (event == EVENT_REFRESH) { - if (cfg->nethack_keypad) + if (conf_get_int(conf, CONF_nethack_keypad)) button = 2; - else if (cfg->app_keypad) + else if (conf_get_int(conf, CONF_app_keypad)) button = 1; else button = 0; @@ -188,11 +342,11 @@ static void numeric_keypad_handler(union control *ctrl, void *dlg, button = dlg_radiobutton_get(ctrl, dlg); assert(button >= 0 && button < ctrl->radio.nbuttons); if (button == 2) { - cfg->app_keypad = FALSE; - cfg->nethack_keypad = TRUE; + conf_set_int(conf, CONF_app_keypad, FALSE); + conf_set_int(conf, CONF_nethack_keypad, TRUE); } else { - cfg->app_keypad = (button != 0); - cfg->nethack_keypad = FALSE; + conf_set_int(conf, CONF_app_keypad, (button != 0)); + conf_set_int(conf, CONF_nethack_keypad, FALSE); } } } @@ -200,7 +354,7 @@ static void numeric_keypad_handler(union control *ctrl, void *dlg, static void cipherlist_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { int i; @@ -218,7 +372,7 @@ static void cipherlist_handler(union control *ctrl, void *dlg, dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < CIPHER_MAX; i++) { - int c = cfg->ssh_cipherlist[i]; + int c = conf_get_int_int(conf, CONF_ssh_cipherlist, i); int j; char *cstr = NULL; for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) { @@ -236,8 +390,8 @@ static void cipherlist_handler(union control *ctrl, void *dlg, /* Update array to match the list box. */ for (i=0; i < CIPHER_MAX; i++) - cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i); - + conf_set_int_int(conf, CONF_ssh_cipherlist, i, + dlg_listbox_getid(ctrl, dlg, i)); } } @@ -245,14 +399,14 @@ static void cipherlist_handler(union control *ctrl, void *dlg, static void gsslist_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { int i; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < ngsslibs; i++) { - int id = cfg->ssh_gsslist[i]; + int id = conf_get_int_int(conf, CONF_ssh_gsslist, i); assert(id >= 0 && id < ngsslibs); dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id); } @@ -263,7 +417,8 @@ static void gsslist_handler(union control *ctrl, void *dlg, /* Update array to match the list box. */ for (i=0; i < ngsslibs; i++) - cfg->ssh_gsslist[i] = dlg_listbox_getid(ctrl, dlg, i); + conf_set_int_int(conf, CONF_ssh_gsslist, i, + dlg_listbox_getid(ctrl, dlg, i)); } } #endif @@ -271,7 +426,7 @@ static void gsslist_handler(union control *ctrl, void *dlg, static void kexlist_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { int i; @@ -288,7 +443,7 @@ static void kexlist_handler(union control *ctrl, void *dlg, dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < KEX_MAX; i++) { - int k = cfg->ssh_kexlist[i]; + int k = conf_get_int_int(conf, CONF_ssh_kexlist, i); int j; char *kstr = NULL; for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) { @@ -306,18 +461,19 @@ static void kexlist_handler(union control *ctrl, void *dlg, /* Update array to match the list box. */ for (i=0; i < KEX_MAX; i++) - cfg->ssh_kexlist[i] = dlg_listbox_getid(ctrl, dlg, i); - + conf_set_int_int(conf, CONF_ssh_kexlist, i, + dlg_listbox_getid(ctrl, dlg, i)); } } static void printerbox_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { int nprinters, i; printer_enum *pe; + char *printer; dlg_update_start(ctrl, dlg); /* @@ -332,50 +488,55 @@ static void printerbox_handler(union control *ctrl, void *dlg, dlg_listbox_add(ctrl, dlg, printer_get_name(pe, i)); printer_finish_enum(pe); } - dlg_editbox_set(ctrl, dlg, - (*cfg->printer ? cfg->printer : - PRINTER_DISABLED_STRING)); + printer = conf_get_str(conf, CONF_printer); + if (!printer) + printer = PRINTER_DISABLED_STRING; + dlg_editbox_set(ctrl, dlg, printer); dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { - dlg_editbox_get(ctrl, dlg, cfg->printer, sizeof(cfg->printer)); - if (!strcmp(cfg->printer, PRINTER_DISABLED_STRING)) - *cfg->printer = '\0'; + char *printer = dlg_editbox_get(ctrl, dlg); + if (!strcmp(printer, PRINTER_DISABLED_STRING)) + printer[0] = '\0'; + conf_set_str(conf, CONF_printer, printer); + sfree(printer); } } static void codepage_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { int i; const char *cp, *thiscp; dlg_update_start(ctrl, dlg); - thiscp = cp_name(decode_codepage(cfg->line_codepage)); + thiscp = cp_name(decode_codepage(conf_get_str(conf, + CONF_line_codepage))); dlg_listbox_clear(ctrl, dlg); for (i = 0; (cp = cp_enumerate(i)) != NULL; i++) dlg_listbox_add(ctrl, dlg, cp); dlg_editbox_set(ctrl, dlg, thiscp); - strcpy(cfg->line_codepage, thiscp); + conf_set_str(conf, CONF_line_codepage, thiscp); dlg_update_done(ctrl, dlg); } else if (event == EVENT_VALCHANGE) { - dlg_editbox_get(ctrl, dlg, cfg->line_codepage, - sizeof(cfg->line_codepage)); - strcpy(cfg->line_codepage, - cp_name(decode_codepage(cfg->line_codepage))); + char *codepage = dlg_editbox_get(ctrl, dlg); + conf_set_str(conf, CONF_line_codepage, + cp_name(decode_codepage(codepage))); + sfree(codepage); } } static void sshbug_handler(union control *ctrl, void *dlg, void *data, int event) { + Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); dlg_listbox_addwithid(ctrl, dlg, "Auto", AUTO); dlg_listbox_addwithid(ctrl, dlg, "Off", FORCE_OFF); dlg_listbox_addwithid(ctrl, dlg, "On", FORCE_ON); - switch (*(int *)ATOFFSET(data, ctrl->listbox.context.i)) { + switch (conf_get_int(conf, ctrl->listbox.context.i)) { case AUTO: dlg_listbox_select(ctrl, dlg, 0); break; case FORCE_OFF: dlg_listbox_select(ctrl, dlg, 1); break; case FORCE_ON: dlg_listbox_select(ctrl, dlg, 2); break; @@ -387,7 +548,7 @@ static void sshbug_handler(union control *ctrl, void *dlg, i = AUTO; else i = dlg_listbox_getid(ctrl, dlg, i); - *(int *)ATOFFSET(data, ctrl->listbox.context.i) = i; + conf_set_int(conf, ctrl->listbox.context.i, i); } } @@ -407,7 +568,7 @@ struct sessionsaver_data { */ static int load_selected_session(struct sessionsaver_data *ssd, char *savedsession, - void *dlg, Config *cfg, int *maybe_launch) + void *dlg, Conf *conf, int *maybe_launch) { int i = dlg_listbox_index(ssd->listbox, dlg); int isdef; @@ -416,7 +577,7 @@ static int load_selected_session(struct sessionsaver_data *ssd, return 0; } isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings"); - load_settings(ssd->sesslist.sessions[i], cfg); + load_settings(ssd->sesslist.sessions[i], conf); if (!isdef) { strncpy(savedsession, ssd->sesslist.sessions[i], SAVEDSESSION_LEN); @@ -438,7 +599,7 @@ static int load_selected_session(struct sessionsaver_data *ssd, static void sessionsaver_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; struct sessionsaver_data *ssd = (struct sessionsaver_data *)ctrl->generic.context.p; char *savedsession; @@ -447,7 +608,13 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, * The first time we're called in a new dialog, we must * allocate space to store the current contents of the saved * session edit box (since it must persist even when we switch - * panels, but is not part of the Config). + * panels, but is not part of the Conf). + * + * FIXME: this is disgusting, and we'd do much better to have + * the persistent storage be dynamically allocated and get rid + * of the arbitrary limit SAVEDSESSION_LEN. To do that would + * require a means of making sure the memory gets freed at the + * appropriate moment. */ if (!ssd->editbox) { savedsession = NULL; @@ -473,8 +640,9 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, } else if (event == EVENT_VALCHANGE) { int top, bottom, halfway, i; if (ctrl == ssd->editbox) { - dlg_editbox_get(ctrl, dlg, savedsession, - SAVEDSESSION_LEN); + char *tmp = dlg_editbox_get(ctrl, dlg); + strncpy(savedsession, tmp, SAVEDSESSION_LEN); + sfree(tmp); top = ssd->sesslist.nsessions; bottom = -1; while (top-bottom > 1) { @@ -503,8 +671,8 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, * double-click on the list box _and_ that session * contains a hostname. */ - if (load_selected_session(ssd, savedsession, dlg, cfg, &mbl) && - (mbl && ctrl == ssd->listbox && cfg_launchable(cfg))) { + if (load_selected_session(ssd, savedsession, dlg, conf, &mbl) && + (mbl && ctrl == ssd->listbox && conf_launchable(conf))) { dlg_end(dlg, 1); /* it's all over, and succeeded */ } } else if (ctrl == ssd->savebutton) { @@ -525,7 +693,7 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, } } { - char *errmsg = save_settings(savedsession, cfg); + char *errmsg = save_settings(savedsession, conf); if (errmsg) { dlg_error_msg(dlg, errmsg); sfree(errmsg); @@ -560,21 +728,23 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, * valid host name in it, then load it and go. */ if (dlg_last_focused(ctrl, dlg) == ssd->listbox && - !cfg_launchable(cfg)) { - Config cfg2; + !conf_launchable(conf)) { + Conf *conf2 = conf_new(); int mbl = FALSE; if (!load_selected_session(ssd, savedsession, dlg, - &cfg2, &mbl)) { + conf2, &mbl)) { dlg_beep(dlg); + conf_free(conf2); return; } /* If at this point we have a valid session, go! */ - if (mbl && cfg_launchable(&cfg2)) { - *cfg = cfg2; /* structure copy */ - cfg->remote_cmd_ptr = NULL; + if (mbl && conf_launchable(conf2)) { + conf_copy_into(conf, conf2); dlg_end(dlg, 1); } else dlg_beep(dlg); + + conf_free(conf2); return; } @@ -582,7 +752,7 @@ static void sessionsaver_handler(union control *ctrl, void *dlg, * Otherwise, do the normal thing: if we have a valid * session, get going. */ - if (cfg_launchable(cfg)) { + if (conf_launchable(conf)) { dlg_end(dlg, 1); } else dlg_beep(dlg); @@ -599,7 +769,7 @@ struct charclass_data { static void charclass_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; struct charclass_data *ccd = (struct charclass_data *)ctrl->generic.context.p; @@ -611,20 +781,22 @@ static void charclass_handler(union control *ctrl, void *dlg, for (i = 0; i < 128; i++) { char str[100]; sprintf(str, "%d\t(0x%02X)\t%c\t%d", i, i, - (i >= 0x21 && i != 0x7F) ? i : ' ', cfg->wordness[i]); + (i >= 0x21 && i != 0x7F) ? i : ' ', + conf_get_int_int(conf, CONF_wordness, i)); dlg_listbox_add(ctrl, dlg, str); } dlg_update_done(ctrl, dlg); } } else if (event == EVENT_ACTION) { if (ctrl == ccd->button) { - char str[100]; + char *str; int i, n; - dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str)); + str = dlg_editbox_get(ccd->editbox, dlg); n = atoi(str); + sfree(str); for (i = 0; i < 128; i++) { if (dlg_listbox_issel(ccd->listbox, dlg, i)) - cfg->wordness[i] = n; + conf_set_int_int(conf, CONF_wordness, i, n); } dlg_refresh(ccd->listbox, dlg); } @@ -652,7 +824,7 @@ static const char *const colours[] = { static void colour_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; struct colour_data *cd = (struct colour_data *)ctrl->generic.context.p; int update = FALSE, clear = FALSE, r, g, b; @@ -676,31 +848,32 @@ static void colour_handler(union control *ctrl, void *dlg, clear = TRUE; } else { clear = FALSE; - r = cfg->colours[i][0]; - g = cfg->colours[i][1]; - b = cfg->colours[i][2]; + r = conf_get_int_int(conf, CONF_colours, i*3+0); + g = conf_get_int_int(conf, CONF_colours, i*3+0); + b = conf_get_int_int(conf, CONF_colours, i*3+0); } update = TRUE; } } else if (event == EVENT_VALCHANGE) { if (ctrl == cd->redit || ctrl == cd->gedit || ctrl == cd->bedit) { /* The user has changed the colour using the edit boxes. */ - char buf[80]; + char *str; int i, cval; - dlg_editbox_get(ctrl, dlg, buf, lenof(buf)); - cval = atoi(buf); + str = dlg_editbox_get(ctrl, dlg); + cval = atoi(str); + sfree(str); if (cval > 255) cval = 255; if (cval < 0) cval = 0; i = dlg_listbox_index(cd->listbox, dlg); if (i >= 0) { if (ctrl == cd->redit) - cfg->colours[i][0] = cval; + conf_set_int_int(conf, CONF_colours, i*3+0, cval); else if (ctrl == cd->gedit) - cfg->colours[i][1] = cval; + conf_set_int_int(conf, CONF_colours, i*3+1, cval); else if (ctrl == cd->bedit) - cfg->colours[i][2] = cval; + conf_set_int_int(conf, CONF_colours, i*3+2, cval); } } } else if (event == EVENT_ACTION) { @@ -716,9 +889,9 @@ static void colour_handler(union control *ctrl, void *dlg, * pick up the results. */ dlg_coloursel_start(ctrl, dlg, - cfg->colours[i][0], - cfg->colours[i][1], - cfg->colours[i][2]); + conf_get_int_int(conf, CONF_colours, i*3+0), + conf_get_int_int(conf, CONF_colours, i*3+1), + conf_get_int_int(conf, CONF_colours, i*3+2)); } } else if (event == EVENT_CALLBACK) { if (ctrl == cd->button) { @@ -729,9 +902,9 @@ static void colour_handler(union control *ctrl, void *dlg, * selector did nothing (user hit Cancel, for example). */ if (dlg_coloursel_results(ctrl, dlg, &r, &g, &b)) { - cfg->colours[i][0] = r; - cfg->colours[i][1] = g; - cfg->colours[i][2] = b; + conf_set_int_int(conf, CONF_colours, i*3+0, r); + conf_set_int_int(conf, CONF_colours, i*3+0, g); + conf_set_int_int(conf, CONF_colours, i*3+0, b); clear = FALSE; update = TRUE; } @@ -760,22 +933,21 @@ struct ttymodes_data { static void ttymodes_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; struct ttymodes_data *td = (struct ttymodes_data *)ctrl->generic.context.p; if (event == EVENT_REFRESH) { if (ctrl == td->listbox) { - char *p = cfg->ttymodes; + char *key, *val; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); - while (*p) { - int tabpos = strchr(p, '\t') - p; - char *disp = dupprintf("%.*s\t%s", tabpos, p, - (p[tabpos+1] == 'A') ? "(auto)" : - p+tabpos+2); + for (val = conf_get_str_strs(conf, CONF_ttymodes, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, CONF_ttymodes, key, &key)) { + char *disp = dupprintf("%s\t%s", key, + (val[0] == 'A') ? "(auto)" : val+1); dlg_listbox_add(ctrl, dlg, disp); - p += strlen(p) + 1; sfree(disp); } dlg_update_done(ctrl, dlg); @@ -795,73 +967,47 @@ static void ttymodes_handler(union control *ctrl, void *dlg, int ind = dlg_listbox_index(td->modelist, dlg); if (ind >= 0) { char type = dlg_radiobutton_get(td->valradio, dlg) ? 'V' : 'A'; - int slen, left; - char *p, str[lenof(cfg->ttymodes)]; + const char *key; + char *str, *val; /* Construct new entry */ - memset(str, 0, lenof(str)); - strncpy(str, ttymodes[ind], lenof(str)-3); - slen = strlen(str); - str[slen] = '\t'; - str[slen+1] = type; - slen += 2; - if (type == 'V') { - dlg_editbox_get(td->valbox, dlg, str+slen, lenof(str)-slen); - } - /* Find end of list, deleting any existing instance */ - p = cfg->ttymodes; - left = lenof(cfg->ttymodes); - while (*p) { - int t = strchr(p, '\t') - p; - if (t == strlen(ttymodes[ind]) && - strncmp(p, ttymodes[ind], t) == 0) { - memmove(p, p+strlen(p)+1, left - (strlen(p)+1)); - continue; - } - left -= strlen(p) + 1; - p += strlen(p) + 1; - } - /* Append new entry */ - memset(p, 0, left); - strncpy(p, str, left - 2); + key = ttymodes[ind]; + str = dlg_editbox_get(td->valbox, dlg); + val = dupprintf("%c%s", type, str); + sfree(str); + conf_set_str_str(conf, CONF_ttymodes, key, val); + sfree(val); dlg_refresh(td->listbox, dlg); } else dlg_beep(dlg); } else if (ctrl == td->rembutton) { - char *p = cfg->ttymodes; - int i = 0, len = lenof(cfg->ttymodes); - while (*p) { - int multisel = dlg_listbox_index(td->listbox, dlg) < 0; + int i = 0; + char *key, *val; + int multisel = dlg_listbox_index(td->listbox, dlg) < 0; + for (val = conf_get_str_strs(conf, CONF_ttymodes, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, CONF_ttymodes, key, &key)) { if (dlg_listbox_issel(td->listbox, dlg, i)) { if (!multisel) { /* Populate controls with entry we're about to * delete, for ease of editing. * (If multiple entries were selected, don't * touch the controls.) */ - char *val = strchr(p, '\t'); - if (val) { - int ind = 0; - val++; - while (ttymodes[ind]) { - if (strlen(ttymodes[ind]) == val-p-1 && - !strncmp(ttymodes[ind], p, val-p-1)) - break; - ind++; - } - dlg_listbox_select(td->modelist, dlg, ind); - dlg_radiobutton_set(td->valradio, dlg, - (*val == 'V')); - dlg_editbox_set(td->valbox, dlg, val+1); + int ind = 0; + val++; + while (ttymodes[ind]) { + if (!strcmp(ttymodes[ind], key)) + break; + ind++; } + dlg_listbox_select(td->modelist, dlg, ind); + dlg_radiobutton_set(td->valradio, dlg, + (*val == 'V')); + dlg_editbox_set(td->valbox, dlg, val+1); } - memmove(p, p+strlen(p)+1, len - (strlen(p)+1)); - i++; - continue; + conf_del_str_str(conf, CONF_ttymodes, key); } - len -= strlen(p) + 1; - p += strlen(p) + 1; i++; } - memset(p, 0, lenof(cfg->ttymodes) - len); dlg_refresh(td->listbox, dlg); } } @@ -874,96 +1020,67 @@ struct environ_data { static void environ_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; struct environ_data *ed = (struct environ_data *)ctrl->generic.context.p; if (event == EVENT_REFRESH) { if (ctrl == ed->listbox) { - char *p = cfg->environmt; + char *key, *val; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); - while (*p) { + for (val = conf_get_str_strs(conf, CONF_environmt, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, CONF_environmt, key, &key)) { + char *p = dupprintf("%s\t%s", key, val); dlg_listbox_add(ctrl, dlg, p); - p += strlen(p) + 1; + sfree(p); } dlg_update_done(ctrl, dlg); } } else if (event == EVENT_ACTION) { if (ctrl == ed->addbutton) { - char str[sizeof(cfg->environmt)]; - char *p; - dlg_editbox_get(ed->varbox, dlg, str, sizeof(str)-1); - if (!*str) { + char *key, *val, *str; + key = dlg_editbox_get(ed->varbox, dlg); + if (!*key) { + sfree(key); dlg_beep(dlg); return; } - p = str + strlen(str); - *p++ = '\t'; - dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str)); - if (!*p) { + val = dlg_editbox_get(ed->valbox, dlg); + if (!*val) { + sfree(key); + sfree(val); dlg_beep(dlg); return; } - p = cfg->environmt; - while (*p) { - while (*p) - p++; - p++; - } - if ((p - cfg->environmt) + strlen(str) + 2 < - sizeof(cfg->environmt)) { - strcpy(p, str); - p[strlen(str) + 1] = '\0'; - dlg_listbox_add(ed->listbox, dlg, str); - dlg_editbox_set(ed->varbox, dlg, ""); - dlg_editbox_set(ed->valbox, dlg, ""); - } else { - dlg_error_msg(dlg, "Environment too big"); - } + conf_set_str_str(conf, CONF_environmt, key, val); + str = dupcat(key, "\t", val, NULL); + dlg_editbox_set(ed->varbox, dlg, ""); + dlg_editbox_set(ed->valbox, dlg, ""); + sfree(str); + sfree(key); + sfree(val); + dlg_refresh(ed->listbox, dlg); } else if (ctrl == ed->rembutton) { int i = dlg_listbox_index(ed->listbox, dlg); if (i < 0) { dlg_beep(dlg); } else { - char *p, *q, *str; + char *key, *val; - dlg_listbox_del(ed->listbox, dlg, i); - p = cfg->environmt; - while (i > 0) { - if (!*p) - goto disaster; - while (*p) - p++; - p++; - i--; + key = conf_get_str_nthstrkey(conf, CONF_environmt, i); + if (key) { + /* Populate controls with the entry we're about to delete + * for ease of editing */ + val = conf_get_str_str(conf, CONF_environmt, key); + dlg_editbox_set(ed->varbox, dlg, key); + dlg_editbox_set(ed->valbox, dlg, val); + /* And delete it */ + conf_del_str_str(conf, CONF_environmt, key); } - q = p; - if (!*p) - goto disaster; - /* Populate controls with the entry we're about to delete - * for ease of editing */ - str = p; - p = strchr(p, '\t'); - if (!p) - goto disaster; - *p = '\0'; - dlg_editbox_set(ed->varbox, dlg, str); - p++; - str = p; - dlg_editbox_set(ed->valbox, dlg, str); - p = strchr(p, '\0'); - if (!p) - goto disaster; - p++; - while (*p) { - while (*p) - *q++ = *p++; - *q++ = *p++; - } - *q = '\0'; - disaster:; } + dlg_refresh(ed->listbox, dlg); } } } @@ -979,18 +1096,25 @@ struct portfwd_data { static void portfwd_handler(union control *ctrl, void *dlg, void *data, int event) { - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; struct portfwd_data *pfd = (struct portfwd_data *)ctrl->generic.context.p; if (event == EVENT_REFRESH) { if (ctrl == pfd->listbox) { - char *p = cfg->portfwd; + char *key, *val; dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); - while (*p) { + for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) { + char *p; + if (!strcmp(val, "D")) + p = dupprintf("D%s\t", key+1); + else + p = dupprintf("%s\t%s", key, val); dlg_listbox_add(ctrl, dlg, p); - p += strlen(p) + 1; + sfree(p); } dlg_update_done(ctrl, dlg); } else if (ctrl == pfd->direction) { @@ -1005,137 +1129,111 @@ static void portfwd_handler(union control *ctrl, void *dlg, } } else if (event == EVENT_ACTION) { if (ctrl == pfd->addbutton) { - char str[sizeof(cfg->portfwd)]; - char *p; - int i, type; - int whichbutton; + char *family, *type, *src, *key, *val; + int i, whichbutton; i = 0; #ifndef NO_IPV6 whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg); if (whichbutton == 1) - str[i++] = '4'; + family = "4"; else if (whichbutton == 2) - str[i++] = '6'; + family = "6"; + else + family = ""; #endif whichbutton = dlg_radiobutton_get(pfd->direction, dlg); if (whichbutton == 0) - type = 'L'; + type = "L"; else if (whichbutton == 1) - type = 'R'; + type = "R"; else - type = 'D'; - str[i++] = type; + type = "D"; - dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i); - if (!str[i]) { + src = dlg_editbox_get(pfd->sourcebox, dlg); + if (!*src) { dlg_error_msg(dlg, "You need to specify a source port number"); + sfree(src); return; } - p = str + strlen(str); - if (type != 'D') { - *p++ = '\t'; - dlg_editbox_get(pfd->destbox, dlg, p, - sizeof(str) - (p - str)); - if (!*p || !strchr(p, ':')) { + if (*type != 'D') { + val = dlg_editbox_get(pfd->destbox, dlg); + if (!*val || !strchr(val, ':')) { dlg_error_msg(dlg, "You need to specify a destination address\n" "in the form \"host.name:port\""); + sfree(src); + sfree(val); return; } - } else - *p = '\0'; - p = cfg->portfwd; - while (*p) { - if (strcmp(p,str) == 0) { - dlg_error_msg(dlg, "Specified forwarding already exists"); - break; - } - while (*p) - p++; - p++; - } - if (!*p) { - if ((p - cfg->portfwd) + strlen(str) + 2 <= - sizeof(cfg->portfwd)) { - strcpy(p, str); - p[strlen(str) + 1] = '\0'; - dlg_listbox_add(pfd->listbox, dlg, str); - dlg_editbox_set(pfd->sourcebox, dlg, ""); - dlg_editbox_set(pfd->destbox, dlg, ""); - } else { - dlg_error_msg(dlg, "Too many forwardings"); - } + } else { + type = "L"; + val = dupstr("D"); /* special case */ + } + + key = dupcat(family, type, src, NULL); + sfree(src); + + if (conf_get_str_str_opt(conf, CONF_portfwd, key)) { + dlg_error_msg(dlg, "Specified forwarding already exists"); + } else { + conf_set_str_str(conf, CONF_portfwd, key, val); } + + sfree(key); + sfree(val); + dlg_refresh(pfd->listbox, dlg); } else if (ctrl == pfd->rembutton) { int i = dlg_listbox_index(pfd->listbox, dlg); - if (i < 0) + if (i < 0) { dlg_beep(dlg); - else { - char *p, *q, *src, *dst; - char dir; + } else { + char *key, *val, *p; - dlg_listbox_del(pfd->listbox, dlg, i); - p = cfg->portfwd; - while (i > 0) { - if (!*p) - goto disaster2; - while (*p) - p++; - p++; - i--; - } - q = p; - if (!*p) - goto disaster2; - /* Populate the controls with the entry we're about to - * delete, for ease of editing. */ - { + key = conf_get_str_nthstrkey(conf, CONF_portfwd, i); + if (key) { static const char *const afs = "A46"; - char *afp = strchr(afs, *p); + static const char *const dirs = "LRD"; + char *afp; + int dir; #ifndef NO_IPV6 - int idx = afp ? afp-afs : 0; + int idx; +#endif + + /* Populate controls with the entry we're about to delete + * for ease of editing */ + p = key; + + afp = strchr(afs, *p); +#ifndef NO_IPV6 + idx = afp ? afp-afs : 0; #endif if (afp) p++; #ifndef NO_IPV6 dlg_radiobutton_set(pfd->addressfamily, dlg, idx); #endif - } - { - static const char *const dirs = "LRD"; + dir = *p; + + val = conf_get_str_str(conf, CONF_portfwd, key); + if (!strcmp(val, "D")) { + dir = 'D'; + val = ""; + } + dlg_radiobutton_set(pfd->direction, dlg, strchr(dirs, dir) - dirs); - } - p++; - if (dir != 'D') { - src = p; - p = strchr(p, '\t'); - if (!p) - goto disaster2; - *p = '\0'; p++; - dst = p; - } else { - src = p; - dst = ""; + + dlg_editbox_set(pfd->sourcebox, dlg, p); + dlg_editbox_set(pfd->destbox, dlg, val); + /* And delete it */ + conf_del_str_str(conf, CONF_portfwd, key); } - p = strchr(p, '\0'); - if (!p) - goto disaster2; - dlg_editbox_set(pfd->sourcebox, dlg, src); - dlg_editbox_set(pfd->destbox, dlg, dst); - p++; - while (*p) { - while (*p) - *q++ = *p++; - *q++ = *p++; - } - *q = '\0'; - disaster2:; } + dlg_refresh(pfd->listbox, dlg); } } } @@ -1276,8 +1374,8 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Session", "otheropts", NULL); c = ctrl_radiobuttons(s, "Close window on exit:", 'x', 4, HELPCTX(session_coe), - dlg_stdradiobutton_handler, - I(offsetof(Config, close_on_exit)), + conf_radiobutton_handler, + I(CONF_close_on_exit), "Always", I(FORCE_ON), "Never", I(FORCE_OFF), "Only on clean exit", I(AUTO), NULL); @@ -1305,7 +1403,7 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_radiobuttons(s, "Session logging:", NO_SHORTCUT, 2, HELPCTX(logging_main), loggingbuttons_handler, - I(offsetof(Config, logtype)), + I(CONF_logtype), "None", 't', I(LGTYP_NONE), "Printable output", 'p', I(LGTYP_ASCII), "All session output", 'l', I(LGTYP_DEBUG), @@ -1316,19 +1414,19 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_filesel(s, "Log file name:", 'f', NULL, TRUE, "Select session log file name", HELPCTX(logging_filename), - dlg_stdfilesel_handler, I(offsetof(Config, logfilename))); + conf_filesel_handler, I(CONF_logfilename)); ctrl_text(s, "(Log file name can contain &Y, &M, &D for date," " &T for time, and &H for host name)", HELPCTX(logging_filename)); ctrl_radiobuttons(s, "What to do if the log file already exists:", 'e', 1, HELPCTX(logging_exists), - dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)), + conf_radiobutton_handler, I(CONF_logxfovr), "Always overwrite it", I(LGXF_OVR), "Always append to the end of it", I(LGXF_APN), "Ask the user every time", I(LGXF_ASK), NULL); ctrl_checkbox(s, "Flush log file frequently", 'u', HELPCTX(logging_flush), - dlg_stdcheckbox_handler, I(offsetof(Config,logflush))); + conf_checkbox_handler, I(CONF_logflush)); if ((midsession && protocol == PROT_SSH) || (!midsession && backend_from_proto(PROT_SSH))) { @@ -1336,10 +1434,10 @@ void setup_config_box(struct controlbox *b, int midsession, "Options specific to SSH packet logging"); ctrl_checkbox(s, "Omit known password fields", 'k', HELPCTX(logging_ssh_omit_password), - dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass))); + conf_checkbox_handler, I(CONF_logomitpass)); ctrl_checkbox(s, "Omit session data", 'd', HELPCTX(logging_ssh_omit_data), - dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata))); + conf_checkbox_handler, I(CONF_logomitdata)); } /* @@ -1350,37 +1448,36 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Terminal", "general", "Set various terminal options"); ctrl_checkbox(s, "Auto wrap mode initially on", 'w', HELPCTX(terminal_autowrap), - dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode))); + conf_checkbox_handler, I(CONF_wrap_mode)); ctrl_checkbox(s, "DEC Origin Mode initially on", 'd', HELPCTX(terminal_decom), - dlg_stdcheckbox_handler, I(offsetof(Config,dec_om))); + conf_checkbox_handler, I(CONF_dec_om)); ctrl_checkbox(s, "Implicit CR in every LF", 'r', HELPCTX(terminal_lfhascr), - dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr))); + conf_checkbox_handler, I(CONF_lfhascr)); ctrl_checkbox(s, "Implicit LF in every CR", 'f', HELPCTX(terminal_crhaslf), - dlg_stdcheckbox_handler, I(offsetof(Config,crhaslf))); + conf_checkbox_handler, I(CONF_crhaslf)); ctrl_checkbox(s, "Use background colour to erase screen", 'e', HELPCTX(terminal_bce), - dlg_stdcheckbox_handler, I(offsetof(Config,bce))); + conf_checkbox_handler, I(CONF_bce)); ctrl_checkbox(s, "Enable blinking text", 'n', HELPCTX(terminal_blink), - dlg_stdcheckbox_handler, I(offsetof(Config,blinktext))); + conf_checkbox_handler, I(CONF_blinktext)); ctrl_editbox(s, "Answerback to ^E:", 's', 100, HELPCTX(terminal_answerback), - dlg_stdeditbox_handler, I(offsetof(Config,answerback)), - I(sizeof(((Config *)0)->answerback))); + conf_editbox_handler, I(CONF_answerback), I(1)); s = ctrl_getset(b, "Terminal", "ldisc", "Line discipline options"); ctrl_radiobuttons(s, "Local echo:", 'l', 3, HELPCTX(terminal_localecho), - dlg_stdradiobutton_handler,I(offsetof(Config,localecho)), + conf_radiobutton_handler,I(CONF_localecho), "Auto", I(AUTO), "Force on", I(FORCE_ON), "Force off", I(FORCE_OFF), NULL); ctrl_radiobuttons(s, "Local line editing:", 't', 3, HELPCTX(terminal_localedit), - dlg_stdradiobutton_handler,I(offsetof(Config,localedit)), + conf_radiobutton_handler,I(CONF_localedit), "Auto", I(AUTO), "Force on", I(FORCE_ON), "Force off", I(FORCE_OFF), NULL); @@ -1400,18 +1497,18 @@ void setup_config_box(struct controlbox *b, int midsession, "Change the sequences sent by:"); ctrl_radiobuttons(s, "The Backspace key", 'b', 2, HELPCTX(keyboard_backspace), - dlg_stdradiobutton_handler, - I(offsetof(Config, bksp_is_delete)), + conf_radiobutton_handler, + I(CONF_bksp_is_delete), "Control-H", I(0), "Control-? (127)", I(1), NULL); ctrl_radiobuttons(s, "The Home and End keys", 'e', 2, HELPCTX(keyboard_homeend), - dlg_stdradiobutton_handler, - I(offsetof(Config, rxvt_homeend)), + conf_radiobutton_handler, + I(CONF_rxvt_homeend), "Standard", I(0), "rxvt", I(1), NULL); ctrl_radiobuttons(s, "The Function keys and keypad", 'f', 3, HELPCTX(keyboard_funkeys), - dlg_stdradiobutton_handler, - I(offsetof(Config, funky_type)), + conf_radiobutton_handler, + I(CONF_funky_type), "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2), "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL); @@ -1419,8 +1516,8 @@ void setup_config_box(struct controlbox *b, int midsession, "Application keypad settings:"); ctrl_radiobuttons(s, "Initial state of cursor keys:", 'r', 3, HELPCTX(keyboard_appcursor), - dlg_stdradiobutton_handler, - I(offsetof(Config, app_cursor)), + conf_radiobutton_handler, + I(CONF_app_cursor), "Normal", I(0), "Application", I(1), NULL); ctrl_radiobuttons(s, "Initial state of numeric keypad:", 'n', 3, HELPCTX(keyboard_appkeypad), @@ -1437,7 +1534,7 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Terminal/Bell", "style", "Set the style of bell"); ctrl_radiobuttons(s, "Action to happen when a bell occurs:", 'b', 1, HELPCTX(bell_style), - dlg_stdradiobutton_handler, I(offsetof(Config, beep)), + conf_radiobutton_handler, I(CONF_beep), "None (bell disabled)", I(BELL_DISABLED), "Make default system alert sound", I(BELL_DEFAULT), "Visual bell (flash window)", I(BELL_VISUAL), NULL); @@ -1446,19 +1543,19 @@ void setup_config_box(struct controlbox *b, int midsession, "Control the bell overload behaviour"); ctrl_checkbox(s, "Bell is temporarily disabled when over-used", 'd', HELPCTX(bell_overload), - dlg_stdcheckbox_handler, I(offsetof(Config,bellovl))); + conf_checkbox_handler, I(CONF_bellovl)); ctrl_editbox(s, "Over-use means this many bells...", 'm', 20, HELPCTX(bell_overload), - dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1)); + conf_editbox_handler, I(CONF_bellovl_n), I(-1)); ctrl_editbox(s, "... in this many seconds", 't', 20, HELPCTX(bell_overload), - dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)), + conf_editbox_handler, I(CONF_bellovl_t), I(-TICKSPERSEC)); ctrl_text(s, "The bell is re-enabled after a few seconds of silence.", HELPCTX(bell_overload)); ctrl_editbox(s, "Seconds of silence required", 's', 20, HELPCTX(bell_overload), - dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)), + conf_editbox_handler, I(CONF_bellovl_s), I(-TICKSPERSEC)); /* @@ -1470,43 +1567,43 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Terminal/Features", "main", NULL); ctrl_checkbox(s, "Disable application cursor keys mode", 'u', HELPCTX(features_application), - dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c))); + conf_checkbox_handler, I(CONF_no_applic_c)); ctrl_checkbox(s, "Disable application keypad mode", 'k', HELPCTX(features_application), - dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k))); + conf_checkbox_handler, I(CONF_no_applic_k)); ctrl_checkbox(s, "Disable xterm-style mouse reporting", 'x', HELPCTX(features_mouse), - dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep))); + conf_checkbox_handler, I(CONF_no_mouse_rep)); ctrl_checkbox(s, "Disable remote-controlled terminal resizing", 's', HELPCTX(features_resize), - dlg_stdcheckbox_handler, - I(offsetof(Config,no_remote_resize))); + conf_checkbox_handler, + I(CONF_no_remote_resize)); ctrl_checkbox(s, "Disable switching to alternate terminal screen", 'w', HELPCTX(features_altscreen), - dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen))); + conf_checkbox_handler, I(CONF_no_alt_screen)); ctrl_checkbox(s, "Disable remote-controlled window title changing", 't', HELPCTX(features_retitle), - dlg_stdcheckbox_handler, - I(offsetof(Config,no_remote_wintitle))); + conf_checkbox_handler, + I(CONF_no_remote_wintitle)); ctrl_radiobuttons(s, "Response to remote title query (SECURITY):", 'q', 3, HELPCTX(features_qtitle), - dlg_stdradiobutton_handler, - I(offsetof(Config,remote_qtitle_action)), + conf_radiobutton_handler, + I(CONF_remote_qtitle_action), "None", I(TITLE_NONE), "Empty string", I(TITLE_EMPTY), "Window title", I(TITLE_REAL), NULL); ctrl_checkbox(s, "Disable destructive backspace on server sending ^?",'b', HELPCTX(features_dbackspace), - dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace))); + conf_checkbox_handler, I(CONF_no_dbackspace)); ctrl_checkbox(s, "Disable remote-controlled character set configuration", - 'r', HELPCTX(features_charset), dlg_stdcheckbox_handler, - I(offsetof(Config,no_remote_charset))); + 'r', HELPCTX(features_charset), conf_checkbox_handler, + I(CONF_no_remote_charset)); ctrl_checkbox(s, "Disable Arabic text shaping", - 'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler, - I(offsetof(Config, arabicshaping))); + 'l', HELPCTX(features_arabicshaping), conf_checkbox_handler, + I(CONF_arabicshaping)); ctrl_checkbox(s, "Disable bidirectional text display", - 'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler, - I(offsetof(Config, bidi))); + 'd', HELPCTX(features_bidi), conf_checkbox_handler, + I(CONF_bidi)); /* * The Window panel. @@ -1519,11 +1616,11 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_columns(s, 2, 50, 50); c = ctrl_editbox(s, "Columns", 'm', 100, HELPCTX(window_size), - dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1)); + conf_editbox_handler, I(CONF_width), I(-1)); c->generic.column = 0; c = ctrl_editbox(s, "Rows", 'r', 100, HELPCTX(window_size), - dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1)); + conf_editbox_handler, I(CONF_height),I(-1)); c->generic.column = 1; ctrl_columns(s, 1, 100); @@ -1531,20 +1628,20 @@ void setup_config_box(struct controlbox *b, int midsession, "Control the scrollback in the window"); ctrl_editbox(s, "Lines of scrollback", 's', 50, HELPCTX(window_scrollback), - dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1)); + conf_editbox_handler, I(CONF_savelines), I(-1)); ctrl_checkbox(s, "Display scrollbar", 'd', HELPCTX(window_scrollback), - dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar))); + conf_checkbox_handler, I(CONF_scrollbar)); ctrl_checkbox(s, "Reset scrollback on keypress", 'k', HELPCTX(window_scrollback), - dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key))); + conf_checkbox_handler, I(CONF_scroll_on_key)); ctrl_checkbox(s, "Reset scrollback on display activity", 'p', HELPCTX(window_scrollback), - dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp))); + conf_checkbox_handler, I(CONF_scroll_on_disp)); ctrl_checkbox(s, "Push erased text into scrollback", 'e', HELPCTX(window_erased), - dlg_stdcheckbox_handler, - I(offsetof(Config,erase_to_scrollback))); + conf_checkbox_handler, + I(CONF_erase_to_scrollback)); /* * The Window/Appearance panel. @@ -1557,33 +1654,33 @@ void setup_config_box(struct controlbox *b, int midsession, "Adjust the use of the cursor"); ctrl_radiobuttons(s, "Cursor appearance:", NO_SHORTCUT, 3, HELPCTX(appearance_cursor), - dlg_stdradiobutton_handler, - I(offsetof(Config, cursor_type)), + conf_radiobutton_handler, + I(CONF_cursor_type), "Block", 'l', I(0), "Underline", 'u', I(1), "Vertical line", 'v', I(2), NULL); ctrl_checkbox(s, "Cursor blinks", 'b', HELPCTX(appearance_cursor), - dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur))); + conf_checkbox_handler, I(CONF_blink_cur)); s = ctrl_getset(b, "Window/Appearance", "font", "Font settings"); ctrl_fontsel(s, "Font used in the terminal window", 'n', HELPCTX(appearance_font), - dlg_stdfontsel_handler, I(offsetof(Config, font))); + conf_fontsel_handler, I(CONF_font)); s = ctrl_getset(b, "Window/Appearance", "mouse", "Adjust the use of the mouse pointer"); ctrl_checkbox(s, "Hide mouse pointer when typing in window", 'p', HELPCTX(appearance_hidemouse), - dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr))); + conf_checkbox_handler, I(CONF_hide_mouseptr)); s = ctrl_getset(b, "Window/Appearance", "border", "Adjust the window border"); ctrl_editbox(s, "Gap between text and window edge:", 'e', 20, HELPCTX(appearance_border), - dlg_stdeditbox_handler, - I(offsetof(Config,window_border)), I(-1)); + conf_editbox_handler, + I(CONF_window_border), I(-1)); /* * The Window/Behaviour panel. @@ -1596,17 +1693,16 @@ void setup_config_box(struct controlbox *b, int midsession, "Adjust the behaviour of the window title"); ctrl_editbox(s, "Window title:", 't', 100, HELPCTX(appearance_title), - dlg_stdeditbox_handler, I(offsetof(Config,wintitle)), - I(sizeof(((Config *)0)->wintitle))); + conf_editbox_handler, I(CONF_wintitle), I(1)); ctrl_checkbox(s, "Separate window and icon titles", 'i', HELPCTX(appearance_title), - dlg_stdcheckbox_handler, - I(CHECKBOX_INVERT | offsetof(Config,win_name_always))); + conf_checkbox_handler, + I(CHECKBOX_INVERT | CONF_win_name_always)); s = ctrl_getset(b, "Window/Behaviour", "main", NULL); ctrl_checkbox(s, "Warn before closing window", 'w', HELPCTX(behaviour_closewarn), - dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close))); + conf_checkbox_handler, I(CONF_warn_on_close)); /* * The Window/Translation panel. @@ -1623,21 +1719,21 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Window/Translation", "tweaks", NULL); ctrl_checkbox(s, "Treat CJK ambiguous characters as wide", 'w', HELPCTX(translation_cjk_ambig_wide), - dlg_stdcheckbox_handler, I(offsetof(Config,cjk_ambig_wide))); + conf_checkbox_handler, I(CONF_cjk_ambig_wide)); str = dupprintf("Adjust how %s handles line drawing characters", appname); s = ctrl_getset(b, "Window/Translation", "linedraw", str); sfree(str); ctrl_radiobuttons(s, "Handling of line drawing characters:", NO_SHORTCUT,1, HELPCTX(translation_linedraw), - dlg_stdradiobutton_handler, - I(offsetof(Config, vtmode)), + conf_radiobutton_handler, + I(CONF_vtmode), "Use Unicode line drawing code points",'u',I(VT_UNICODE), "Poor man's line drawing (+, - and |)",'p',I(VT_POORMAN), NULL); ctrl_checkbox(s, "Copy and paste line drawing characters as lqqqk",'d', HELPCTX(selection_linedraw), - dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp))); + conf_checkbox_handler, I(CONF_rawcnp)); /* * The Window/Selection panel. @@ -1648,13 +1744,13 @@ void setup_config_box(struct controlbox *b, int midsession, "Control use of mouse"); ctrl_checkbox(s, "Shift overrides application's use of mouse", 'p', HELPCTX(selection_shiftdrag), - dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override))); + conf_checkbox_handler, I(CONF_mouse_override)); ctrl_radiobuttons(s, "Default selection mode (Alt+drag does the other one):", NO_SHORTCUT, 2, HELPCTX(selection_rect), - dlg_stdradiobutton_handler, - I(offsetof(Config, rect_select)), + conf_radiobutton_handler, + I(CONF_rect_select), "Normal", 'n', I(0), "Rectangular block", 'r', I(1), NULL); @@ -1692,13 +1788,13 @@ void setup_config_box(struct controlbox *b, int midsession, "General options for colour usage"); ctrl_checkbox(s, "Allow terminal to specify ANSI colours", 'i', HELPCTX(colours_ansi), - dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour))); + conf_checkbox_handler, I(CONF_ansi_colour)); ctrl_checkbox(s, "Allow terminal to use xterm 256-colour mode", '2', - HELPCTX(colours_xterm256), dlg_stdcheckbox_handler, - I(offsetof(Config,xterm_256_colour))); + HELPCTX(colours_xterm256), conf_checkbox_handler, + I(CONF_xterm_256_colour)); ctrl_checkbox(s, "Bolded text is a different colour", 'b', HELPCTX(colours_bold), - dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour))); + conf_checkbox_handler, I(CONF_bold_colour)); str = dupprintf("Adjust the precise colours %s displays", appname); s = ctrl_getset(b, "Window/Colours", "adjust", str); @@ -1740,7 +1836,7 @@ void setup_config_box(struct controlbox *b, int midsession, "Sending of null packets to keep session active"); ctrl_editbox(s, "Seconds between keepalives (0 to turn off)", 'k', 20, HELPCTX(connection_keepalive), - dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)), + conf_editbox_handler, I(CONF_ping_interval), I(-1)); if (!midsession) { @@ -1748,19 +1844,19 @@ void setup_config_box(struct controlbox *b, int midsession, "Low-level TCP connection options"); ctrl_checkbox(s, "Disable Nagle's algorithm (TCP_NODELAY option)", 'n', HELPCTX(connection_nodelay), - dlg_stdcheckbox_handler, - I(offsetof(Config,tcp_nodelay))); + conf_checkbox_handler, + I(CONF_tcp_nodelay)); ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)", 'p', HELPCTX(connection_tcpkeepalive), - dlg_stdcheckbox_handler, - I(offsetof(Config,tcp_keepalives))); + conf_checkbox_handler, + I(CONF_tcp_keepalives)); #ifndef NO_IPV6 s = ctrl_getset(b, "Connection", "ipversion", "Internet protocol version"); ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3, HELPCTX(connection_ipversion), - dlg_stdradiobutton_handler, - I(offsetof(Config, addressfamily)), + conf_radiobutton_handler, + I(CONF_addressfamily), "Auto", 'u', I(ADDRTYPE_UNSPEC), "IPv4", '4', I(ADDRTYPE_IPV4), "IPv6", '6', I(ADDRTYPE_IPV6), @@ -1775,8 +1871,7 @@ void setup_config_box(struct controlbox *b, int midsession, "Logical name of remote host"); ctrl_editbox(s, label, 'm', 100, HELPCTX(connection_loghost), - dlg_stdeditbox_handler, I(offsetof(Config,loghost)), - I(sizeof(((Config *)0)->loghost))); + conf_editbox_handler, I(CONF_loghost), I(1)); } } @@ -1791,8 +1886,7 @@ void setup_config_box(struct controlbox *b, int midsession, "Login details"); ctrl_editbox(s, "Auto-login username", 'u', 50, HELPCTX(connection_username), - dlg_stdeditbox_handler, I(offsetof(Config,username)), - I(sizeof(((Config *)0)->username))); + conf_editbox_handler, I(CONF_username), I(1)); { /* We assume the local username is sufficiently stable * to include on the dialog box. */ @@ -1802,8 +1896,8 @@ void setup_config_box(struct controlbox *b, int midsession, sfree(user); ctrl_radiobuttons(s, "When username is not specified:", 'n', 4, HELPCTX(connection_username_from_env), - dlg_stdradiobutton_handler, - I(offsetof(Config, username_from_env)), + conf_radiobutton_handler, + I(CONF_username_from_env), "Prompt", I(FALSE), userlabel, I(TRUE), NULL); @@ -1814,12 +1908,10 @@ void setup_config_box(struct controlbox *b, int midsession, "Terminal details"); ctrl_editbox(s, "Terminal-type string", 't', 50, HELPCTX(connection_termtype), - dlg_stdeditbox_handler, I(offsetof(Config,termtype)), - I(sizeof(((Config *)0)->termtype))); + conf_editbox_handler, I(CONF_termtype), I(1)); ctrl_editbox(s, "Terminal speeds", 's', 50, HELPCTX(connection_termspeed), - dlg_stdeditbox_handler, I(offsetof(Config,termspeed)), - I(sizeof(((Config *)0)->termspeed))); + conf_editbox_handler, I(CONF_termspeed), I(1)); s = ctrl_getset(b, "Connection/Data", "env", "Environment variables"); @@ -1865,8 +1957,8 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Connection/Proxy", "basics", NULL); ctrl_radiobuttons(s, "Proxy type:", 't', 3, HELPCTX(proxy_type), - dlg_stdradiobutton_handler, - I(offsetof(Config, proxy_type)), + conf_radiobutton_handler, + I(CONF_proxy_type), "None", I(PROXY_NONE), "SOCKS 4", I(PROXY_SOCKS4), "SOCKS 5", I(PROXY_SOCKS5), @@ -1876,49 +1968,44 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_columns(s, 2, 80, 20); c = ctrl_editbox(s, "Proxy hostname", 'y', 100, HELPCTX(proxy_main), - dlg_stdeditbox_handler, - I(offsetof(Config,proxy_host)), - I(sizeof(((Config *)0)->proxy_host))); + conf_editbox_handler, + I(CONF_proxy_host), I(1)); c->generic.column = 0; c = ctrl_editbox(s, "Port", 'p', 100, HELPCTX(proxy_main), - dlg_stdeditbox_handler, - I(offsetof(Config,proxy_port)), + conf_editbox_handler, + I(CONF_proxy_port), I(-1)); c->generic.column = 1; ctrl_columns(s, 1, 100); ctrl_editbox(s, "Exclude Hosts/IPs", 'e', 100, HELPCTX(proxy_exclude), - dlg_stdeditbox_handler, - I(offsetof(Config,proxy_exclude_list)), - I(sizeof(((Config *)0)->proxy_exclude_list))); + conf_editbox_handler, + I(CONF_proxy_exclude_list), I(1)); ctrl_checkbox(s, "Consider proxying local host connections", 'x', HELPCTX(proxy_exclude), - dlg_stdcheckbox_handler, - I(offsetof(Config,even_proxy_localhost))); + conf_checkbox_handler, + I(CONF_even_proxy_localhost)); ctrl_radiobuttons(s, "Do DNS name lookup at proxy end:", 'd', 3, HELPCTX(proxy_dns), - dlg_stdradiobutton_handler, - I(offsetof(Config, proxy_dns)), + conf_radiobutton_handler, + I(CONF_proxy_dns), "No", I(FORCE_OFF), "Auto", I(AUTO), "Yes", I(FORCE_ON), NULL); ctrl_editbox(s, "Username", 'u', 60, HELPCTX(proxy_auth), - dlg_stdeditbox_handler, - I(offsetof(Config,proxy_username)), - I(sizeof(((Config *)0)->proxy_username))); + conf_editbox_handler, + I(CONF_proxy_username), I(1)); c = ctrl_editbox(s, "Password", 'w', 60, HELPCTX(proxy_auth), - dlg_stdeditbox_handler, - I(offsetof(Config,proxy_password)), - I(sizeof(((Config *)0)->proxy_password))); + conf_editbox_handler, + I(CONF_proxy_password), I(1)); c->editbox.password = 1; ctrl_editbox(s, "Telnet command", 'm', 100, HELPCTX(proxy_command), - dlg_stdeditbox_handler, - I(offsetof(Config,proxy_telnet_command)), - I(sizeof(((Config *)0)->proxy_telnet_command))); + conf_editbox_handler, + I(CONF_proxy_telnet_command), I(1)); } /* @@ -1939,24 +2026,24 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_radiobuttons(s, "Handling of OLD_ENVIRON ambiguity:", NO_SHORTCUT, 2, HELPCTX(telnet_oldenviron), - dlg_stdradiobutton_handler, - I(offsetof(Config, rfc_environ)), + conf_radiobutton_handler, + I(CONF_rfc_environ), "BSD (commonplace)", 'b', I(0), "RFC 1408 (unusual)", 'f', I(1), NULL); ctrl_radiobuttons(s, "Telnet negotiation mode:", 't', 2, HELPCTX(telnet_passive), - dlg_stdradiobutton_handler, - I(offsetof(Config, passive_telnet)), + conf_radiobutton_handler, + I(CONF_passive_telnet), "Passive", I(1), "Active", I(0), NULL); } ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k', HELPCTX(telnet_specialkeys), - dlg_stdcheckbox_handler, - I(offsetof(Config,telnet_keyboard))); + conf_checkbox_handler, + I(CONF_telnet_keyboard)); ctrl_checkbox(s, "Return key sends Telnet New Line instead of ^M", 'm', HELPCTX(telnet_newline), - dlg_stdcheckbox_handler, - I(offsetof(Config,telnet_newline))); + conf_checkbox_handler, + I(CONF_telnet_newline)); } if (!midsession) { @@ -1971,8 +2058,7 @@ void setup_config_box(struct controlbox *b, int midsession, "Data to send to the server"); ctrl_editbox(s, "Local username:", 'l', 50, HELPCTX(rlogin_localuser), - dlg_stdeditbox_handler, I(offsetof(Config,localusername)), - I(sizeof(((Config *)0)->localusername))); + conf_editbox_handler, I(CONF_localusername), I(1)); } @@ -2002,14 +2088,13 @@ void setup_config_box(struct controlbox *b, int midsession, "Data to send to the server"); ctrl_editbox(s, "Remote command:", 'r', 100, HELPCTX(ssh_command), - dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)), - I(sizeof(((Config *)0)->remote_cmd))); + conf_editbox_handler, I(CONF_remote_cmd), I(1)); s = ctrl_getset(b, "Connection/SSH", "protocol", "Protocol options"); ctrl_checkbox(s, "Don't start a shell or command at all", 'n', HELPCTX(ssh_noshell), - dlg_stdcheckbox_handler, - I(offsetof(Config,ssh_no_shell))); + conf_checkbox_handler, + I(CONF_ssh_no_shell)); } if (!midsession || protcfginfo != 1) { @@ -2017,8 +2102,8 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_checkbox(s, "Enable compression", 'e', HELPCTX(ssh_compress), - dlg_stdcheckbox_handler, - I(offsetof(Config,compression))); + conf_checkbox_handler, + I(CONF_compression)); } if (!midsession) { @@ -2026,8 +2111,8 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_radiobuttons(s, "Preferred SSH protocol version:", NO_SHORTCUT, 4, HELPCTX(ssh_protocol), - dlg_stdradiobutton_handler, - I(offsetof(Config, sshprot)), + conf_radiobutton_handler, + I(CONF_sshprot), "1 only", 'l', I(0), "1", '1', I(1), "2", '2', I(2), @@ -2043,8 +2128,8 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_checkbox(s, "Enable legacy use of single-DES in SSH-2", 'i', HELPCTX(ssh_ciphers), - dlg_stdcheckbox_handler, - I(offsetof(Config,ssh2_des_cbc))); + conf_checkbox_handler, + I(CONF_ssh2_des_cbc)); } /* @@ -2068,13 +2153,13 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_editbox(s, "Max minutes before rekey (0 for no limit)", 't', 20, HELPCTX(ssh_kex_repeat), - dlg_stdeditbox_handler, - I(offsetof(Config,ssh_rekey_time)), + conf_editbox_handler, + I(CONF_ssh_rekey_time), I(-1)); ctrl_editbox(s, "Max data before rekey (0 for no limit)", 'x', 20, HELPCTX(ssh_kex_repeat), - dlg_stdeditbox_handler, - I(offsetof(Config,ssh_rekey_data)), + conf_editbox_handler, + I(CONF_ssh_rekey_data), I(16)); ctrl_text(s, "(Use 1M for 1 megabyte, 1G for 1 gigabyte etc)", HELPCTX(ssh_kex_repeat)); @@ -2091,41 +2176,41 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Connection/SSH/Auth", "main", NULL); ctrl_checkbox(s, "Bypass authentication entirely (SSH-2 only)", 'b', HELPCTX(ssh_auth_bypass), - dlg_stdcheckbox_handler, - I(offsetof(Config,ssh_no_userauth))); + conf_checkbox_handler, + I(CONF_ssh_no_userauth)); ctrl_checkbox(s, "Display pre-authentication banner (SSH-2 only)", 'd', HELPCTX(ssh_auth_banner), - dlg_stdcheckbox_handler, - I(offsetof(Config,ssh_show_banner))); + conf_checkbox_handler, + I(CONF_ssh_show_banner)); s = ctrl_getset(b, "Connection/SSH/Auth", "methods", "Authentication methods"); ctrl_checkbox(s, "Attempt authentication using Pageant", 'p', HELPCTX(ssh_auth_pageant), - dlg_stdcheckbox_handler, - I(offsetof(Config,tryagent))); + conf_checkbox_handler, + I(CONF_tryagent)); ctrl_checkbox(s, "Attempt TIS or CryptoCard auth (SSH-1)", 'm', HELPCTX(ssh_auth_tis), - dlg_stdcheckbox_handler, - I(offsetof(Config,try_tis_auth))); + conf_checkbox_handler, + I(CONF_try_tis_auth)); ctrl_checkbox(s, "Attempt \"keyboard-interactive\" auth (SSH-2)", 'i', HELPCTX(ssh_auth_ki), - dlg_stdcheckbox_handler, - I(offsetof(Config,try_ki_auth))); + conf_checkbox_handler, + I(CONF_try_ki_auth)); s = ctrl_getset(b, "Connection/SSH/Auth", "params", "Authentication parameters"); ctrl_checkbox(s, "Allow agent forwarding", 'f', HELPCTX(ssh_auth_agentfwd), - dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd))); + conf_checkbox_handler, I(CONF_agentfwd)); ctrl_checkbox(s, "Allow attempted changes of username in SSH-2", NO_SHORTCUT, HELPCTX(ssh_auth_changeuser), - dlg_stdcheckbox_handler, - I(offsetof(Config,change_username))); + conf_checkbox_handler, + I(CONF_change_username)); ctrl_filesel(s, "Private key file for authentication:", 'k', FILTER_KEY_FILES, FALSE, "Select private key file", HELPCTX(ssh_auth_privkey), - dlg_stdfilesel_handler, I(offsetof(Config, keyfile))); + conf_filesel_handler, I(CONF_keyfile)); #ifndef NO_GSSAPI /* @@ -2138,13 +2223,13 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_checkbox(s, "Attempt GSSAPI authentication (SSH-2 only)", 't', HELPCTX(ssh_gssapi), - dlg_stdcheckbox_handler, - I(offsetof(Config,try_gssapi_auth))); + conf_checkbox_handler, + I(CONF_try_gssapi_auth)); ctrl_checkbox(s, "Allow GSSAPI credential delegation", 'l', HELPCTX(ssh_gssapi_delegation), - dlg_stdcheckbox_handler, - I(offsetof(Config,gssapifwd))); + conf_checkbox_handler, + I(CONF_gssapifwd)); /* * GSSAPI library selection. @@ -2177,8 +2262,8 @@ void setup_config_box(struct controlbox *b, int midsession, ctrl_filesel(s, "User-supplied GSSAPI library path:", 's', FILTER_DYNLIB_FILES, FALSE, "Select library file", HELPCTX(ssh_gssapi_libraries), - dlg_stdfilesel_handler, - I(offsetof(Config, ssh_gss_custom))); + conf_filesel_handler, + I(CONF_ssh_gss_custom)); } #endif } @@ -2192,8 +2277,8 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Connection/SSH/TTY", "sshtty", NULL); ctrl_checkbox(s, "Don't allocate a pseudo-terminal", 'p', HELPCTX(ssh_nopty), - dlg_stdcheckbox_handler, - I(offsetof(Config,nopty))); + conf_checkbox_handler, + I(CONF_nopty)); s = ctrl_getset(b, "Connection/SSH/TTY", "ttymodes", "Terminal modes"); @@ -2259,15 +2344,14 @@ void setup_config_box(struct controlbox *b, int midsession, s = ctrl_getset(b, "Connection/SSH/X11", "x11", "X11 forwarding"); ctrl_checkbox(s, "Enable X11 forwarding", 'e', HELPCTX(ssh_tunnels_x11), - dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward))); + conf_checkbox_handler,I(CONF_x11_forward)); ctrl_editbox(s, "X display location", 'x', 50, HELPCTX(ssh_tunnels_x11), - dlg_stdeditbox_handler, I(offsetof(Config,x11_display)), - I(sizeof(((Config *)0)->x11_display))); + conf_editbox_handler, I(CONF_x11_display), I(1)); ctrl_radiobuttons(s, "Remote X11 authentication protocol", 'u', 2, HELPCTX(ssh_tunnels_x11auth), - dlg_stdradiobutton_handler, - I(offsetof(Config, x11_auth)), + conf_radiobutton_handler, + I(CONF_x11_auth), "MIT-Magic-Cookie-1", I(X11_MIT), "XDM-Authorization-1", I(X11_XDM), NULL); } @@ -2282,12 +2366,12 @@ void setup_config_box(struct controlbox *b, int midsession, "Port forwarding"); ctrl_checkbox(s, "Local ports accept connections from other hosts",'t', HELPCTX(ssh_tunnels_portfwd_localhost), - dlg_stdcheckbox_handler, - I(offsetof(Config,lport_acceptall))); + conf_checkbox_handler, + I(CONF_lport_acceptall)); ctrl_checkbox(s, "Remote ports do the same (SSH-2 only)", 'p', HELPCTX(ssh_tunnels_portfwd_localhost), - dlg_stdcheckbox_handler, - I(offsetof(Config,rport_acceptall))); + conf_checkbox_handler, + I(CONF_rport_acceptall)); ctrl_columns(s, 3, 55, 20, 25); c = ctrl_text(s, "Forwarded ports:", HELPCTX(ssh_tunnels_portfwd)); @@ -2355,34 +2439,34 @@ void setup_config_box(struct controlbox *b, int midsession, "Detection of known bugs in SSH servers"); ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20, HELPCTX(ssh_bugs_ignore1), - sshbug_handler, I(offsetof(Config,sshbug_ignore1))); + sshbug_handler, I(CONF_sshbug_ignore1)); ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20, HELPCTX(ssh_bugs_plainpw1), - sshbug_handler, I(offsetof(Config,sshbug_plainpw1))); + sshbug_handler, I(CONF_sshbug_plainpw1)); ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20, HELPCTX(ssh_bugs_rsa1), - sshbug_handler, I(offsetof(Config,sshbug_rsa1))); + sshbug_handler, I(CONF_sshbug_rsa1)); ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20, HELPCTX(ssh_bugs_ignore2), - sshbug_handler, I(offsetof(Config,sshbug_ignore2))); + sshbug_handler, I(CONF_sshbug_ignore2)); ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20, HELPCTX(ssh_bugs_hmac2), - sshbug_handler, I(offsetof(Config,sshbug_hmac2))); + sshbug_handler, I(CONF_sshbug_hmac2)); ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20, HELPCTX(ssh_bugs_derivekey2), - sshbug_handler, I(offsetof(Config,sshbug_derivekey2))); + sshbug_handler, I(CONF_sshbug_derivekey2)); ctrl_droplist(s, "Requires padding on SSH-2 RSA signatures", 'p', 20, HELPCTX(ssh_bugs_rsapad2), - sshbug_handler, I(offsetof(Config,sshbug_rsapad2))); + sshbug_handler, I(CONF_sshbug_rsapad2)); ctrl_droplist(s, "Misuses the session ID in SSH-2 PK auth", 'n', 20, HELPCTX(ssh_bugs_pksessid2), - sshbug_handler, I(offsetof(Config,sshbug_pksessid2))); + sshbug_handler, I(CONF_sshbug_pksessid2)); ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20, HELPCTX(ssh_bugs_rekey2), - sshbug_handler, I(offsetof(Config,sshbug_rekey2))); + sshbug_handler, I(CONF_sshbug_rekey2)); ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20, HELPCTX(ssh_bugs_maxpkt2), - sshbug_handler, I(offsetof(Config,sshbug_maxpkt2))); + sshbug_handler, I(CONF_sshbug_maxpkt2)); } } } diff --git a/cproxy.c b/cproxy.c index bf5eed5d..934ce3dc 100644 --- a/cproxy.c +++ b/cproxy.c @@ -130,7 +130,8 @@ int proxy_socks5_handlechap (Proxy_Socket p) outbuf[2] = 0x04; /* Response */ outbuf[3] = 0x10; /* Length */ hmacmd5_chap(data, p->chap_current_datalen, - p->cfg.proxy_password, &outbuf[4]); + conf_get_str(p->conf, CONF_proxy_password), + &outbuf[4]); sk_write(p->sub_socket, (char *)outbuf, 20); break; case 0x11: @@ -159,7 +160,9 @@ int proxy_socks5_handlechap (Proxy_Socket p) int proxy_socks5_selectchap(Proxy_Socket p) { - if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { + char *username = conf_get_str(p->conf, CONF_proxy_username); + char *password = conf_get_str(p->conf, CONF_proxy_password); + if (username[0] || password[0]) { char chapbuf[514]; int ulen; chapbuf[0] = '\x01'; /* Version */ @@ -169,11 +172,11 @@ int proxy_socks5_selectchap(Proxy_Socket p) chapbuf[4] = '\x85'; /* ...and it's HMAC-MD5, the core one */ chapbuf[5] = '\x02'; /* Second attribute - username */ - ulen = strlen(p->cfg.proxy_username); + ulen = strlen(username); if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1; chapbuf[6] = ulen; - memcpy(chapbuf+7, p->cfg.proxy_username, ulen); + memcpy(chapbuf+7, username, ulen); sk_write(p->sub_socket, chapbuf, ulen + 7); p->chap_num_attributes = 0; diff --git a/dialog.c b/dialog.c index 53b64298..127783a3 100644 --- a/dialog.c +++ b/dialog.c @@ -456,140 +456,3 @@ void ctrl_free(union control *ctrl) } sfree(ctrl); } - -void dlg_stdradiobutton_handler(union control *ctrl, void *dlg, - void *data, int event) -{ - int button; - /* - * For a standard radio button set, the context parameter gives - * offsetof(targetfield, Config), and the extra data per button - * gives the value the target field should take if that button - * is the one selected. - */ - if (event == EVENT_REFRESH) { - for (button = 0; button < ctrl->radio.nbuttons; button++) - if (*(int *)ATOFFSET(data, ctrl->radio.context.i) == - ctrl->radio.buttondata[button].i) - break; - /* We expected that `break' to happen, in all circumstances. */ - assert(button < ctrl->radio.nbuttons); - dlg_radiobutton_set(ctrl, dlg, button); - } else if (event == EVENT_VALCHANGE) { - button = dlg_radiobutton_get(ctrl, dlg); - assert(button >= 0 && button < ctrl->radio.nbuttons); - *(int *)ATOFFSET(data, ctrl->radio.context.i) = - ctrl->radio.buttondata[button].i; - } -} - -void dlg_stdcheckbox_handler(union control *ctrl, void *dlg, - void *data, int event) -{ - int offset, invert; - - /* - * For a standard checkbox, the context parameter gives - * offsetof(targetfield, Config), optionally ORed with - * CHECKBOX_INVERT. - */ - offset = ctrl->checkbox.context.i; - if (offset & CHECKBOX_INVERT) { - offset &= ~CHECKBOX_INVERT; - invert = 1; - } else - invert = 0; - - /* - * C lacks a logical XOR, so the following code uses the idiom - * (!a ^ !b) to obtain the logical XOR of a and b. (That is, 1 - * iff exactly one of a and b is nonzero, otherwise 0.) - */ - - if (event == EVENT_REFRESH) { - dlg_checkbox_set(ctrl,dlg, (!*(int *)ATOFFSET(data,offset) ^ !invert)); - } else if (event == EVENT_VALCHANGE) { - *(int *)ATOFFSET(data, offset) = !dlg_checkbox_get(ctrl,dlg) ^ !invert; - } -} - -void dlg_stdeditbox_handler(union control *ctrl, void *dlg, - void *data, int event) -{ - /* - * The standard edit-box handler expects the main `context' - * field to contain the `offsetof' a field in the structure - * pointed to by `data'. The secondary `context2' field - * indicates the type of this field: - * - * - if context2 > 0, the field is a char array and context2 - * gives its size. - * - if context2 == -1, the field is an int and the edit box - * is numeric. - * - if context2 < -1, the field is an int and the edit box is - * _floating_, and (-context2) gives the scale. (E.g. if - * context2 == -1000, then typing 1.2 into the box will set - * the field to 1200.) - */ - int offset = ctrl->editbox.context.i; - int length = ctrl->editbox.context2.i; - - if (length > 0) { - char *field = (char *)ATOFFSET(data, offset); - if (event == EVENT_REFRESH) { - dlg_editbox_set(ctrl, dlg, field); - } else if (event == EVENT_VALCHANGE) { - dlg_editbox_get(ctrl, dlg, field, length); - } - } else if (length < 0) { - int *field = (int *)ATOFFSET(data, offset); - char data[80]; - if (event == EVENT_REFRESH) { - if (length == -1) - sprintf(data, "%d", *field); - else - sprintf(data, "%g", (double)*field / (double)(-length)); - dlg_editbox_set(ctrl, dlg, data); - } else if (event == EVENT_VALCHANGE) { - dlg_editbox_get(ctrl, dlg, data, lenof(data)); - if (length == -1) - *field = atoi(data); - else - *field = (int)((-length) * atof(data)); - } - } -} - -void dlg_stdfilesel_handler(union control *ctrl, void *dlg, - void *data, int event) -{ - /* - * The standard file-selector handler expects the `context' - * field to contain the `offsetof' a Filename field in the - * structure pointed to by `data'. - */ - int offset = ctrl->fileselect.context.i; - - if (event == EVENT_REFRESH) { - dlg_filesel_set(ctrl, dlg, *(Filename *)ATOFFSET(data, offset)); - } else if (event == EVENT_VALCHANGE) { - dlg_filesel_get(ctrl, dlg, (Filename *)ATOFFSET(data, offset)); - } -} - -void dlg_stdfontsel_handler(union control *ctrl, void *dlg, - void *data, int event) -{ - /* - * The standard file-selector handler expects the `context' - * field to contain the `offsetof' a FontSpec field in the - * structure pointed to by `data'. - */ - int offset = ctrl->fontselect.context.i; - - if (event == EVENT_REFRESH) { - dlg_fontsel_set(ctrl, dlg, *(FontSpec *)ATOFFSET(data, offset)); - } else if (event == EVENT_VALCHANGE) { - dlg_fontsel_get(ctrl, dlg, (FontSpec *)ATOFFSET(data, offset)); - } -} diff --git a/dialog.h b/dialog.h index 0cabb3d3..fb89b6bb 100644 --- a/dialog.h +++ b/dialog.h @@ -162,7 +162,7 @@ union control { * * The `data' parameter points to the writable data being * modified as a result of the configuration activity; for - * example, the PuTTY `Config' structure, although not + * example, the PuTTY `Conf' structure, although not * necessarily. * * The `dlg' parameter is passed back to the platform- @@ -521,45 +521,6 @@ union control *ctrl_checkbox(struct controlset *, char *label, char shortcut, handler_fn handler, intorptr context); union control *ctrl_tabdelay(struct controlset *, union control *); -/* - * Standard handler routines to cover most of the common cases in - * the config box. - */ -/* - * The standard radio-button handler expects the main `context' - * field to contain the `offsetof' of an int field in the structure - * pointed to by `data', and expects each of the individual button - * data to give a value for that int field. - */ -void dlg_stdradiobutton_handler(union control *ctrl, void *dlg, - void *data, int event); -/* - * The standard checkbox handler expects the main `context' field - * to contain the `offsetof' an int field in the structure pointed - * to by `data', optionally ORed with CHECKBOX_INVERT to indicate - * that the sense of the datum is opposite to the sense of the - * checkbox. - */ -#define CHECKBOX_INVERT (1<<30) -void dlg_stdcheckbox_handler(union control *ctrl, void *dlg, - void *data, int event); -/* - * The standard edit-box handler expects the main `context' field - * to contain the `offsetof' a field in the structure pointed to by - * `data'. The secondary `context2' field indicates the type of - * this field: - * - * - if context2 > 0, the field is a char array and context2 gives - * its size. - * - if context2 == -1, the field is an int and the edit box is - * numeric. - * - if context2 < -1, the field is an int and the edit box is - * _floating_, and (-context2) gives the scale. (E.g. if - * context2 == -1000, then typing 1.2 into the box will set the - * field to 1200.) - */ -void dlg_stdeditbox_handler(union control *ctrl, void *dlg, - void *data, int event); /* * The standard file-selector handler expects the main `context' * field to contain the `offsetof' a Filename field in the @@ -584,7 +545,7 @@ int dlg_radiobutton_get(union control *ctrl, void *dlg); void dlg_checkbox_set(union control *ctrl, void *dlg, int checked); int dlg_checkbox_get(union control *ctrl, void *dlg); void dlg_editbox_set(union control *ctrl, void *dlg, char const *text); -void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length); +char *dlg_editbox_get(union control *ctrl, void *dlg); /* result must be freed by caller */ /* The `listbox' functions can also apply to combo boxes. */ void dlg_listbox_clear(union control *ctrl, void *dlg); void dlg_listbox_del(union control *ctrl, void *dlg, int index); diff --git a/ldisc.c b/ldisc.c index f2853f4b..efbb8714 100644 --- a/ldisc.c +++ b/ldisc.c @@ -12,12 +12,12 @@ #include "terminal.h" #include "ldisc.h" -#define ECHOING (ldisc->cfg->localecho == FORCE_ON || \ - (ldisc->cfg->localecho == AUTO && \ +#define ECHOING (ldisc->localecho == FORCE_ON || \ + (ldisc->localecho == AUTO && \ (ldisc->back->ldisc(ldisc->backhandle, LD_ECHO) || \ term_ldisc(ldisc->term, LD_ECHO)))) -#define EDITING (ldisc->cfg->localedit == FORCE_ON || \ - (ldisc->cfg->localedit == AUTO && \ +#define EDITING (ldisc->localedit == FORCE_ON || \ + (ldisc->localedit == AUTO && \ (ldisc->back->ldisc(ldisc->backhandle, LD_EDIT) || \ term_ldisc(ldisc->term, LD_EDIT)))) @@ -76,7 +76,7 @@ static void bsb(Ldisc ldisc, int n) #define CTRL(x) (x^'@') #define KCTRL(x) ((x^'@') | 0x100) -void *ldisc_create(Config *mycfg, Terminal *term, +void *ldisc_create(Conf *conf, Terminal *term, Backend *back, void *backhandle, void *frontend) { @@ -87,12 +87,13 @@ void *ldisc_create(Config *mycfg, Terminal *term, ldisc->bufsiz = 0; ldisc->quotenext = 0; - ldisc->cfg = mycfg; ldisc->back = back; ldisc->backhandle = backhandle; ldisc->term = term; ldisc->frontend = frontend; + ldisc_configure(ldisc, conf); + /* Link ourselves into the backend and the terminal */ if (term) term->ldisc = ldisc; @@ -102,6 +103,17 @@ void *ldisc_create(Config *mycfg, Terminal *term, return ldisc; } +void ldisc_configure(void *handle, Conf *conf) +{ + Ldisc ldisc = (Ldisc) handle; + + ldisc->telnet_keyboard = conf_get_int(conf, CONF_telnet_keyboard); + ldisc->telnet_newline = conf_get_int(conf, CONF_telnet_newline); + ldisc->protocol = conf_get_int(conf, CONF_protocol); + ldisc->localecho = conf_get_int(conf, CONF_localecho); + ldisc->localedit = conf_get_int(conf, CONF_localedit); +} + void ldisc_free(void *handle) { Ldisc ldisc = (Ldisc) handle; @@ -203,7 +215,7 @@ void ldisc_send(void *handle, char *buf, int len, int interactive) * configured telnet specials off! This breaks * talkers otherwise. */ - if (!ldisc->cfg->telnet_keyboard) + if (!ldisc->telnet_keyboard) goto default_case; if (c == CTRL('C')) ldisc->back->special(ldisc->backhandle, TS_IP); @@ -255,7 +267,7 @@ void ldisc_send(void *handle, char *buf, int len, int interactive) * default clause because of the break. */ case CTRL('J'): - if (ldisc->cfg->protocol == PROT_RAW && + if (ldisc->protocol == PROT_RAW && ldisc->buflen > 0 && ldisc->buf[ldisc->buflen - 1] == '\r') { if (ECHOING) bsb(ldisc, plen(ldisc, ldisc->buf[ldisc->buflen - 1])); @@ -264,9 +276,9 @@ void ldisc_send(void *handle, char *buf, int len, int interactive) case KCTRL('M'): /* send with newline */ if (ldisc->buflen > 0) ldisc->back->send(ldisc->backhandle, ldisc->buf, ldisc->buflen); - if (ldisc->cfg->protocol == PROT_RAW) + if (ldisc->protocol == PROT_RAW) ldisc->back->send(ldisc->backhandle, "\r\n", 2); - else if (ldisc->cfg->protocol == PROT_TELNET && ldisc->cfg->telnet_newline) + else if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline) ldisc->back->special(ldisc->backhandle, TS_EOL); else ldisc->back->send(ldisc->backhandle, "\r", 1); @@ -300,27 +312,27 @@ void ldisc_send(void *handle, char *buf, int len, int interactive) if (len > 0) { if (ECHOING) c_write(ldisc, buf, len); - if (keyflag && ldisc->cfg->protocol == PROT_TELNET && len == 1) { + if (keyflag && ldisc->protocol == PROT_TELNET && len == 1) { switch (buf[0]) { case CTRL('M'): - if (ldisc->cfg->protocol == PROT_TELNET && ldisc->cfg->telnet_newline) + if (ldisc->protocol == PROT_TELNET && ldisc->telnet_newline) ldisc->back->special(ldisc->backhandle, TS_EOL); else ldisc->back->send(ldisc->backhandle, "\r", 1); break; case CTRL('?'): case CTRL('H'): - if (ldisc->cfg->telnet_keyboard) { + if (ldisc->telnet_keyboard) { ldisc->back->special(ldisc->backhandle, TS_EC); break; } case CTRL('C'): - if (ldisc->cfg->telnet_keyboard) { + if (ldisc->telnet_keyboard) { ldisc->back->special(ldisc->backhandle, TS_IP); break; } case CTRL('Z'): - if (ldisc->cfg->telnet_keyboard) { + if (ldisc->telnet_keyboard) { ldisc->back->special(ldisc->backhandle, TS_SUSP); break; } diff --git a/ldisc.h b/ldisc.h index 2bca86d9..5dbe2a76 100644 --- a/ldisc.h +++ b/ldisc.h @@ -11,10 +11,14 @@ typedef struct ldisc_tag { Terminal *term; Backend *back; - Config *cfg; void *backhandle; void *frontend; + /* + * Values cached out of conf. + */ + int telnet_keyboard, telnet_newline, protocol, localecho, localedit; + char *buf; int buflen, bufsiz, quotenext; } *Ldisc; diff --git a/logging.c b/logging.c index 74654804..b2401c38 100644 --- a/logging.c +++ b/logging.c @@ -18,7 +18,8 @@ struct LogContext { bufchain queue; Filename currlogfilename; void *frontend; - Config cfg; + Conf *conf; + int logtype; /* cached out of conf */ }; static void xlatlognam(Filename *d, Filename s, char *hostname, struct tm *tm); @@ -75,7 +76,7 @@ static void logprintf(struct LogContext *ctx, const char *fmt, ...) */ void logflush(void *handle) { struct LogContext *ctx = (struct LogContext *)handle; - if (ctx->cfg.logtype > 0) + if (ctx->logtype > 0) if (ctx->state == L_OPEN) fflush(ctx->lgfp); } @@ -110,10 +111,10 @@ static void logfopen_callback(void *handle, int mode) ctx->state == L_ERROR ? (mode == 0 ? "Disabled writing" : "Error writing") : (mode == 1 ? "Appending" : "Writing new"), - (ctx->cfg.logtype == LGTYP_ASCII ? "ASCII" : - ctx->cfg.logtype == LGTYP_DEBUG ? "raw" : - ctx->cfg.logtype == LGTYP_PACKETS ? "SSH packets" : - ctx->cfg.logtype == LGTYP_SSHRAW ? "SSH raw data" : + (ctx->logtype == LGTYP_ASCII ? "ASCII" : + ctx->logtype == LGTYP_DEBUG ? "raw" : + ctx->logtype == LGTYP_PACKETS ? "SSH packets" : + ctx->logtype == LGTYP_SSHRAW ? "SSH raw data" : "unknown"), filename_to_str(&ctx->currlogfilename)); logevent(ctx->frontend, event); @@ -148,19 +149,22 @@ void logfopen(void *handle) if (ctx->state != L_CLOSED) return; - if (!ctx->cfg.logtype) + if (!ctx->logtype) return; tm = ltime(); /* substitute special codes in file name */ - xlatlognam(&ctx->currlogfilename, ctx->cfg.logfilename,ctx->cfg.host, &tm); + xlatlognam(&ctx->currlogfilename, + *conf_get_filename(ctx->conf, CONF_logfilename), + conf_get_str(ctx->conf, CONF_host), &tm); ctx->lgfp = f_open(ctx->currlogfilename, "r", FALSE); /* file already present? */ if (ctx->lgfp) { + int logxfovr = conf_get_int(ctx->conf, CONF_logxfovr); fclose(ctx->lgfp); - if (ctx->cfg.logxfovr != LGXF_ASK) { - mode = ((ctx->cfg.logxfovr == LGXF_OVR) ? 2 : 1); + if (logxfovr != LGXF_ASK) { + mode = ((logxfovr == LGXF_OVR) ? 2 : 1); } else mode = askappend(ctx->frontend, ctx->currlogfilename, logfopen_callback, ctx); @@ -189,8 +193,8 @@ void logfclose(void *handle) void logtraffic(void *handle, unsigned char c, int logmode) { struct LogContext *ctx = (struct LogContext *)handle; - if (ctx->cfg.logtype > 0) { - if (ctx->cfg.logtype == logmode) + if (ctx->logtype > 0) { + if (ctx->logtype == logmode) logwrite(ctx, &c, 1); } } @@ -214,8 +218,8 @@ void log_eventlog(void *handle, const char *event) /* If we don't have a context yet (eg winnet.c init) then skip entirely */ if (!ctx) return; - if (ctx->cfg.logtype != LGTYP_PACKETS && - ctx->cfg.logtype != LGTYP_SSHRAW) + if (ctx->logtype != LGTYP_PACKETS && + ctx->logtype != LGTYP_SSHRAW) return; logprintf(ctx, "Event Log: %s\r\n", event); logflush(ctx); @@ -236,8 +240,8 @@ void log_packet(void *handle, int direction, int type, int p = 0, b = 0, omitted = 0; int output_pos = 0; /* NZ if pending output in dumpdata */ - if (!(ctx->cfg.logtype == LGTYP_SSHRAW || - (ctx->cfg.logtype == LGTYP_PACKETS && texttype))) + if (!(ctx->logtype == LGTYP_SSHRAW || + (ctx->logtype == LGTYP_PACKETS && texttype))) return; /* Packet header. */ @@ -326,13 +330,14 @@ void log_packet(void *handle, int direction, int type, logflush(ctx); } -void *log_init(void *frontend, Config *cfg) +void *log_init(void *frontend, Conf *conf) { struct LogContext *ctx = snew(struct LogContext); ctx->lgfp = NULL; ctx->state = L_CLOSED; ctx->frontend = frontend; - ctx->cfg = *cfg; /* STRUCTURE COPY */ + ctx->conf = conf_copy(conf); + ctx->logtype = conf_get_int(ctx->conf, CONF_logtype); bufchain_init(&ctx->queue); return ctx; } @@ -346,13 +351,15 @@ void log_free(void *handle) sfree(ctx); } -void log_reconfig(void *handle, Config *cfg) +void log_reconfig(void *handle, Conf *conf) { struct LogContext *ctx = (struct LogContext *)handle; int reset_logging; - if (!filename_equal(ctx->cfg.logfilename, cfg->logfilename) || - ctx->cfg.logtype != cfg->logtype) + if (!filename_equal(*conf_get_filename(ctx->conf, CONF_logfilename), + *conf_get_filename(conf, CONF_logfilename)) || + conf_get_int(ctx->conf, CONF_logtype) != + conf_get_int(conf, CONF_logtype)) reset_logging = TRUE; else reset_logging = FALSE; @@ -360,7 +367,10 @@ void log_reconfig(void *handle, Config *cfg) if (reset_logging) logfclose(ctx); - ctx->cfg = *cfg; /* STRUCTURE COPY */ + conf_free(ctx->conf); + ctx->conf = conf_copy(conf); + + ctx->logtype = conf_get_int(ctx->conf, CONF_logtype); if (reset_logging) logfopen(ctx); diff --git a/macosx/README.OSX b/macosx/README.OSX index 7076e0e7..084671ad 100644 --- a/macosx/README.OSX +++ b/macosx/README.OSX @@ -20,6 +20,15 @@ say you weren't warned! Other ways in which the port is currently unfinished include: +Bit rot +------- + + - the conversion of the old fixed-size 'Config' structure to the + new dynamic 'Conf' was never applied to this directory + + - probably other things are out of date too; it would need some + work to make it compile again + Missing terminal window features -------------------------------- diff --git a/misc.c b/misc.c index 8f728eea..cf97c049 100644 --- a/misc.c +++ b/misc.c @@ -635,21 +635,21 @@ void debug_memdump(void *buf, int len, int L) #endif /* def DEBUG */ /* - * Determine whether or not a Config structure represents a session - * which can sensibly be launched right now. + * Determine whether or not a Conf represents a session which can + * sensibly be launched right now. */ -int cfg_launchable(const Config *cfg) +int conf_launchable(Conf *conf) { - if (cfg->protocol == PROT_SERIAL) - return cfg->serline[0] != 0; + if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) + return conf_get_str(conf, CONF_serline)[0] != 0; else - return cfg->host[0] != 0; + return conf_get_str(conf, CONF_host)[0] != 0; } -char const *cfg_dest(const Config *cfg) +char const *conf_dest(Conf *conf) { - if (cfg->protocol == PROT_SERIAL) - return cfg->serline; + if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL) + return conf_get_str(conf, CONF_serline); else - return cfg->host; + return conf_get_str(conf, CONF_host); } diff --git a/network.h b/network.h index 6ee7081e..d9f48865 100644 --- a/network.h +++ b/network.h @@ -15,7 +15,7 @@ #ifndef DONE_TYPEDEFS #define DONE_TYPEDEFS -typedef struct config_tag Config; +typedef struct conf_tag Conf; typedef struct backend_tag Backend; typedef struct terminal_tag Terminal; #endif @@ -94,18 +94,18 @@ struct plug_function_table { Socket new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, - Plug plug, const Config *cfg); + Plug plug, Conf *conf); Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only, - const Config *cfg, int addressfamily); + Conf *conf, int addressfamily); SockAddr name_lookup(char *host, int port, char **canonicalname, - const Config *cfg, int addressfamily); + Conf *conf, int addressfamily); /* platform-dependent callback from new_connection() */ /* (same caveat about addr as new_connection()) */ Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, - Plug plug, const Config *cfg); + Plug plug, Conf *conf); /* socket functions */ diff --git a/pinger.c b/pinger.c index c9b75033..3e2626f5 100644 --- a/pinger.c +++ b/pinger.c @@ -43,11 +43,11 @@ static void pinger_schedule(Pinger pinger) } } -Pinger pinger_new(Config *cfg, Backend *back, void *backhandle) +Pinger pinger_new(Conf *conf, Backend *back, void *backhandle) { Pinger pinger = snew(struct pinger_tag); - pinger->interval = cfg->ping_interval; + pinger->interval = conf_get_int(conf, CONF_ping_interval); pinger->pending = FALSE; pinger->back = back; pinger->backhandle = backhandle; @@ -56,10 +56,11 @@ Pinger pinger_new(Config *cfg, Backend *back, void *backhandle) return pinger; } -void pinger_reconfig(Pinger pinger, Config *oldcfg, Config *newcfg) +void pinger_reconfig(Pinger pinger, Conf *oldconf, Conf *newconf) { - if (oldcfg->ping_interval != newcfg->ping_interval) { - pinger->interval = newcfg->ping_interval; + int newinterval = conf_get_int(newconf, CONF_ping_interval); + if (conf_get_int(oldconf, CONF_ping_interval) != newinterval) { + pinger->interval = newinterval; pinger_schedule(pinger); } } diff --git a/portfwd.c b/portfwd.c index 662d995d..e7e9d638 100644 --- a/portfwd.c +++ b/portfwd.c @@ -325,7 +325,7 @@ static void pfd_sent(Plug plug, int bufsize) * Called when receiving a PORT OPEN from the server */ const char *pfd_newconnect(Socket *s, char *hostname, int port, - void *c, const Config *cfg, int addressfamily) + void *c, Conf *conf, int addressfamily) { static const struct plug_function_table fn_table = { pfd_log, @@ -343,7 +343,7 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port, /* * Try to find host. */ - addr = name_lookup(hostname, port, &dummy_realhost, cfg, addressfamily); + addr = name_lookup(hostname, port, &dummy_realhost, conf, addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -362,7 +362,7 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port, pr->dynamic = 0; pr->s = *s = new_connection(addr, dummy_realhost, port, - 0, 1, 0, 0, (Plug) pr, cfg); + 0, 1, 0, 0, (Plug) pr, conf); if ((err = sk_socket_error(*s)) != NULL) { sfree(pr); return err; @@ -435,7 +435,7 @@ static int pfd_accepting(Plug p, OSSocket sock) sets up a listener on the local machine on (srcaddr:)port */ const char *pfd_addforward(char *desthost, int destport, char *srcaddr, - int port, void *backhandle, const Config *cfg, + int port, void *backhandle, Conf *conf, void **sockdata, int address_family) { static const struct plug_function_table fn_table = { @@ -468,7 +468,8 @@ const char *pfd_addforward(char *desthost, int destport, char *srcaddr, pr->backhandle = backhandle; pr->s = s = new_listener(srcaddr, port, (Plug) pr, - !cfg->lport_acceptall, cfg, address_family); + !conf_get_int(conf, CONF_lport_acceptall), + conf, address_family); if ((err = sk_socket_error(s)) != NULL) { sfree(pr); return err; diff --git a/pproxy.c b/pproxy.c index 9c4c2d89..1bea6fb8 100644 --- a/pproxy.c +++ b/pproxy.c @@ -11,7 +11,7 @@ Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, - Plug plug, const Config *cfg) + Plug plug, Conf *conf) { return NULL; } diff --git a/proxy.c b/proxy.c index c6008a59..0b6d9d58 100644 --- a/proxy.c +++ b/proxy.c @@ -14,9 +14,10 @@ #include "network.h" #include "proxy.h" -#define do_proxy_dns(cfg) \ - (cfg->proxy_dns == FORCE_ON || \ - (cfg->proxy_dns == AUTO && cfg->proxy_type != PROXY_SOCKS4)) +#define do_proxy_dns(conf) \ + (conf_get_int(conf, CONF_proxy_dns) == FORCE_ON || \ + (conf_get_int(conf, CONF_proxy_dns) == AUTO && \ + conf_get_int(conf, CONF_proxy_type) != PROXY_SOCKS4)) /* * Call this when proxy negotiation is complete, so that this @@ -263,7 +264,7 @@ static int plug_proxy_accepting (Plug p, OSSocket sock) * it will only check the host name. */ static int proxy_for_destination (SockAddr addr, char *hostname, int port, - const Config *cfg) + Conf *conf) { int s = 0, e = 0; char hostip[64]; @@ -274,7 +275,7 @@ static int proxy_for_destination (SockAddr addr, char *hostname, int port, * Check the host name and IP against the hard-coded * representations of `localhost'. */ - if (!cfg->even_proxy_localhost && + if (!conf_get_int(conf, CONF_even_proxy_localhost) && (sk_hostname_is_local(hostname) || (addr && sk_address_is_local(addr)))) return 0; /* do not proxy */ @@ -288,7 +289,7 @@ static int proxy_for_destination (SockAddr addr, char *hostname, int port, hostname_len = strlen(hostname); - exclude_list = cfg->proxy_exclude_list; + exclude_list = conf_get_str(conf, CONF_proxy_exclude_list); /* now parse the exclude list, and see if either our IP * or hostname matches anything in it. @@ -349,11 +350,11 @@ static int proxy_for_destination (SockAddr addr, char *hostname, int port, } SockAddr name_lookup(char *host, int port, char **canonicalname, - const Config *cfg, int addressfamily) + Conf *conf, int addressfamily) { - if (cfg->proxy_type != PROXY_NONE && - do_proxy_dns(cfg) && - proxy_for_destination(NULL, host, port, cfg)) { + if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && + do_proxy_dns(conf) && + proxy_for_destination(NULL, host, port, conf)) { *canonicalname = dupstr(host); return sk_nonamelookup(host); } @@ -364,7 +365,7 @@ SockAddr name_lookup(char *host, int port, char **canonicalname, Socket new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, - Plug plug, const Config *cfg) + Plug plug, Conf *conf) { static const struct socket_function_table socket_fn_table = { sk_proxy_plug, @@ -386,24 +387,25 @@ Socket new_connection(SockAddr addr, char *hostname, plug_proxy_accepting }; - if (cfg->proxy_type != PROXY_NONE && - proxy_for_destination(addr, hostname, port, cfg)) + if (conf_get_int(conf, CONF_proxy_type) != PROXY_NONE && + proxy_for_destination(addr, hostname, port, conf)) { Proxy_Socket ret; Proxy_Plug pplug; SockAddr proxy_addr; char *proxy_canonical_name; Socket sret; + int type; if ((sret = platform_new_connection(addr, hostname, port, privport, oobinline, nodelay, keepalive, - plug, cfg)) != + plug, conf)) != NULL) return sret; ret = snew(struct Socket_proxy_tag); ret->fn = &socket_fn_table; - ret->cfg = *cfg; /* STRUCTURE COPY */ + ret->conf = conf_copy(conf); ret->plug = plug; ret->remote_addr = addr; /* will need to be freed on close */ ret->remote_port = port; @@ -419,14 +421,15 @@ Socket new_connection(SockAddr addr, char *hostname, ret->sub_socket = NULL; ret->state = PROXY_STATE_NEW; ret->negotiate = NULL; - - if (cfg->proxy_type == PROXY_HTTP) { + + type = conf_get_int(conf, CONF_proxy_type); + if (type == PROXY_HTTP) { ret->negotiate = proxy_http_negotiate; - } else if (cfg->proxy_type == PROXY_SOCKS4) { + } else if (type == PROXY_SOCKS4) { ret->negotiate = proxy_socks4_negotiate; - } else if (cfg->proxy_type == PROXY_SOCKS5) { + } else if (type == PROXY_SOCKS5) { ret->negotiate = proxy_socks5_negotiate; - } else if (cfg->proxy_type == PROXY_TELNET) { + } else if (type == PROXY_TELNET) { ret->negotiate = proxy_telnet_negotiate; } else { ret->error = "Proxy error: Unknown proxy method"; @@ -440,8 +443,9 @@ Socket new_connection(SockAddr addr, char *hostname, pplug->proxy_socket = ret; /* look-up proxy */ - proxy_addr = sk_namelookup(cfg->proxy_host, - &proxy_canonical_name, cfg->addressfamily); + proxy_addr = sk_namelookup(conf_get_str(conf, CONF_proxy_host), + &proxy_canonical_name, + conf_get_int(conf, CONF_addressfamily)); if (sk_addr_error(proxy_addr) != NULL) { ret->error = "Proxy error: Unable to resolve proxy host name"; return (Socket)ret; @@ -451,7 +455,8 @@ Socket new_connection(SockAddr addr, char *hostname, /* create the actual socket we will be using, * connected to our proxy server and port. */ - ret->sub_socket = sk_new(proxy_addr, cfg->proxy_port, + ret->sub_socket = sk_new(proxy_addr, + conf_get_int(conf, CONF_proxy_port), privport, oobinline, nodelay, keepalive, (Plug) pplug); if (sk_socket_error(ret->sub_socket) != NULL) @@ -469,7 +474,7 @@ Socket new_connection(SockAddr addr, char *hostname, } Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only, - const Config *cfg, int addressfamily) + Conf *conf, int addressfamily) { /* TODO: SOCKS (and potentially others) support inbound * TODO: connections via the proxy. support them. @@ -525,6 +530,7 @@ int proxy_http_negotiate (Proxy_Socket p, int change) * request */ char *buf, dest[512]; + char *username, *password; sk_getaddr(p->remote_addr, dest, lenof(dest)); @@ -533,18 +539,22 @@ int proxy_http_negotiate (Proxy_Socket p, int change) sk_write(p->sub_socket, buf, strlen(buf)); sfree(buf); - if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { - char buf[sizeof(p->cfg.proxy_username)+sizeof(p->cfg.proxy_password)]; - char buf2[sizeof(buf)*4/3 + 100]; + username = conf_get_str(p->conf, CONF_proxy_username); + password = conf_get_str(p->conf, CONF_proxy_password); + if (username[0] || password[0]) { + char *buf, *buf2; int i, j, len; - sprintf(buf, "%s:%s", p->cfg.proxy_username, p->cfg.proxy_password); + buf = dupprintf("%s:%s", username, password); len = strlen(buf); + buf2 = snewn(len * 4 / 3 + 100, char); sprintf(buf2, "Proxy-Authorization: Basic "); for (i = 0, j = strlen(buf2); i < len; i += 3, j += 4) base64_encode_atom((unsigned char *)(buf+i), (len-i > 3 ? 3 : len-i), buf2+j); strcpy(buf2+j, "\r\n"); sk_write(p->sub_socket, buf2, strlen(buf2)); + sfree(buf); + sfree(buf2); } sk_write(p->sub_socket, "\r\n", 2); @@ -711,6 +721,7 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change) int length, type, namelen; char *command, addr[4], hostname[512]; + char *username; type = sk_addrtype(p->remote_addr); if (type == ADDRTYPE_IPV6) { @@ -728,9 +739,10 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change) addr[3] = 1; } - length = strlen(p->cfg.proxy_username) + namelen + 9; + username = conf_get_str(p->conf, CONF_proxy_username); + length = strlen(username) + namelen + 9; command = snewn(length, char); - strcpy(command + 8, p->cfg.proxy_username); + strcpy(command + 8, username); command[0] = 4; /* version 4 */ command[1] = 1; /* CONNECT command */ @@ -743,10 +755,11 @@ int proxy_socks4_negotiate (Proxy_Socket p, int change) memcpy(command + 4, addr, 4); /* hostname */ - memcpy(command + 8 + strlen(p->cfg.proxy_username) + 1, + memcpy(command + 8 + strlen(username) + 1, hostname, namelen); sk_write(p->sub_socket, command, length); + sfree(username); sfree(command); p->state = 1; @@ -868,10 +881,13 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change) */ char command[5]; + char *username, *password; int len; command[0] = 5; /* version 5 */ - if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { + username = conf_get_str(p->conf, CONF_proxy_username); + password = conf_get_str(p->conf, CONF_proxy_password); + if (username[0] || password[0]) { command[2] = 0x00; /* no authentication */ len = 3; proxy_socks5_offerencryptedauth (command, &len); @@ -1148,18 +1164,20 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change) } if (p->state == 5) { - if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) { - char userpwbuf[514]; + char *username = conf_get_str(p->conf, CONF_proxy_username); + char *password = conf_get_str(p->conf, CONF_proxy_password); + if (username[0] || password[0]) { + char userpwbuf[255 + 255 + 3]; int ulen, plen; - ulen = strlen(p->cfg.proxy_username); + ulen = strlen(username); if (ulen > 255) ulen = 255; if (ulen < 1) ulen = 1; - plen = strlen(p->cfg.proxy_password); + plen = strlen(password); if (plen > 255) plen = 255; if (plen < 1) plen = 1; userpwbuf[0] = 1; /* version number of subnegotiation */ userpwbuf[1] = ulen; - memcpy(userpwbuf+2, p->cfg.proxy_username, ulen); + memcpy(userpwbuf+2, username, ulen); userpwbuf[ulen+2] = plen; - memcpy(userpwbuf+ulen+3, p->cfg.proxy_password, plen); + memcpy(userpwbuf+ulen+3, password, plen); sk_write(p->sub_socket, userpwbuf, ulen + plen + 3); p->state = 7; } else @@ -1192,8 +1210,9 @@ int proxy_socks5_negotiate (Proxy_Socket p, int change) * standardised or at all well-defined.) */ -char *format_telnet_command(SockAddr addr, int port, const Config *cfg) +char *format_telnet_command(SockAddr addr, int port, Conf *conf) { + char *fmt = conf_get_str(conf, CONF_proxy_telnet_command); char *ret = NULL; int retlen = 0, retsize = 0; int so = 0, eo = 0; @@ -1208,22 +1227,21 @@ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) * %%, %host, %port, %user, and %pass */ - while (cfg->proxy_telnet_command[eo] != 0) { + while (fmt[eo] != 0) { /* scan forward until we hit end-of-line, * or an escape character (\ or %) */ - while (cfg->proxy_telnet_command[eo] != 0 && - cfg->proxy_telnet_command[eo] != '%' && - cfg->proxy_telnet_command[eo] != '\\') eo++; + while (fmt[eo] != 0 && fmt[eo] != '%' && fmt[eo] != '\\') + eo++; /* if we hit eol, break out of our escaping loop */ - if (cfg->proxy_telnet_command[eo] == 0) break; + if (fmt[eo] == 0) break; /* if there was any unescaped text before the escape * character, send that now */ if (eo != so) { ENSURE(eo - so); - memcpy(ret + retlen, cfg->proxy_telnet_command + so, eo - so); + memcpy(ret + retlen, fmt + so, eo - so); retlen += eo - so; } @@ -1231,15 +1249,15 @@ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) /* if the escape character was the last character of * the line, we'll just stop and send it. */ - if (cfg->proxy_telnet_command[eo] == 0) break; + if (fmt[eo] == 0) break; - if (cfg->proxy_telnet_command[so] == '\\') { + if (fmt[so] == '\\') { /* we recognize \\, \%, \r, \n, \t, \x??. * anything else, we just send unescaped (including the \). */ - switch (cfg->proxy_telnet_command[eo]) { + switch (fmt[eo]) { case '\\': ENSURE(1); @@ -1280,15 +1298,12 @@ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) for (;;) { eo++; - if (cfg->proxy_telnet_command[eo] >= '0' && - cfg->proxy_telnet_command[eo] <= '9') - v += cfg->proxy_telnet_command[eo] - '0'; - else if (cfg->proxy_telnet_command[eo] >= 'a' && - cfg->proxy_telnet_command[eo] <= 'f') - v += cfg->proxy_telnet_command[eo] - 'a' + 10; - else if (cfg->proxy_telnet_command[eo] >= 'A' && - cfg->proxy_telnet_command[eo] <= 'F') - v += cfg->proxy_telnet_command[eo] - 'A' + 10; + if (fmt[eo] >= '0' && fmt[eo] <= '9') + v += fmt[eo] - '0'; + else if (fmt[eo] >= 'a' && fmt[eo] <= 'f') + v += fmt[eo] - 'a' + 10; + else if (fmt[eo] >= 'A' && fmt[eo] <= 'F') + v += fmt[eo] - 'A' + 10; else { /* non hex character, so we abort and just * send the whole thing unescaped (including \x) @@ -1315,7 +1330,7 @@ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) default: ENSURE(2); - memcpy(ret+retlen, cfg->proxy_telnet_command + so, 2); + memcpy(ret+retlen, fmt + so, 2); retlen += 2; eo++; break; @@ -1327,13 +1342,12 @@ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) * unescaped (including the %). */ - if (cfg->proxy_telnet_command[eo] == '%') { + if (fmt[eo] == '%') { ENSURE(1); ret[retlen++] = '%'; eo++; } - else if (strnicmp(cfg->proxy_telnet_command + eo, - "host", 4) == 0) { + else if (strnicmp(fmt + eo, "host", 4) == 0) { char dest[512]; int destlen; sk_getaddr(addr, dest, lenof(dest)); @@ -1343,8 +1357,7 @@ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) retlen += destlen; eo += 4; } - else if (strnicmp(cfg->proxy_telnet_command + eo, - "port", 4) == 0) { + else if (strnicmp(fmt + eo, "port", 4) == 0) { char portstr[8], portlen; portlen = sprintf(portstr, "%i", port); ENSURE(portlen); @@ -1352,35 +1365,35 @@ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) retlen += portlen; eo += 4; } - else if (strnicmp(cfg->proxy_telnet_command + eo, - "user", 4) == 0) { - int userlen = strlen(cfg->proxy_username); + else if (strnicmp(fmt + eo, "user", 4) == 0) { + char *username = conf_get_str(conf, CONF_proxy_username); + int userlen = strlen(username); ENSURE(userlen); - memcpy(ret+retlen, cfg->proxy_username, userlen); + memcpy(ret+retlen, username, userlen); retlen += userlen; eo += 4; } - else if (strnicmp(cfg->proxy_telnet_command + eo, - "pass", 4) == 0) { - int passlen = strlen(cfg->proxy_password); + else if (strnicmp(fmt + eo, "pass", 4) == 0) { + char *password = conf_get_str(conf, CONF_proxy_password); + int passlen = strlen(password); ENSURE(passlen); - memcpy(ret+retlen, cfg->proxy_password, passlen); + memcpy(ret+retlen, password, passlen); retlen += passlen; eo += 4; } - else if (strnicmp(cfg->proxy_telnet_command + eo, - "proxyhost", 9) == 0) { - int phlen = strlen(cfg->proxy_host); + else if (strnicmp(fmt + eo, "proxyhost", 9) == 0) { + char *host = conf_get_str(conf, CONF_proxy_host); + int phlen = strlen(host); ENSURE(phlen); - memcpy(ret+retlen, cfg->proxy_host, phlen); + memcpy(ret+retlen, host, phlen); retlen += phlen; eo += 9; } - else if (strnicmp(cfg->proxy_telnet_command + eo, - "proxyport", 9) == 0) { + else if (strnicmp(fmt + eo, "proxyport", 9) == 0) { + int port = conf_get_int(conf, CONF_proxy_port); char pport[50]; int pplen; - sprintf(pport, "%d", cfg->proxy_port); + sprintf(pport, "%d", port); pplen = strlen(pport); ENSURE(pplen); memcpy(ret+retlen, pport, pplen); @@ -1404,7 +1417,7 @@ char *format_telnet_command(SockAddr addr, int port, const Config *cfg) /* if there is any unescaped text at the end of the line, send it */ if (eo != so) { ENSURE(eo - so); - memcpy(ret + retlen, cfg->proxy_telnet_command + so, eo - so); + memcpy(ret + retlen, fmt + so, eo - so); retlen += eo - so; } @@ -1421,7 +1434,7 @@ int proxy_telnet_negotiate (Proxy_Socket p, int change) char *formatted_cmd; formatted_cmd = format_telnet_command(p->remote_addr, p->remote_port, - &p->cfg); + p->conf); sk_write(p->sub_socket, formatted_cmd, strlen(formatted_cmd)); sfree(formatted_cmd); diff --git a/proxy.h b/proxy.h index 35c57982..3df21c71 100644 --- a/proxy.h +++ b/proxy.h @@ -80,7 +80,7 @@ struct Socket_proxy_tag { OSSocket accepting_sock; /* configuration, used to look up proxy settings */ - Config cfg; + Conf *conf; /* CHAP transient data */ int chap_num_attributes; @@ -110,7 +110,7 @@ extern int proxy_socks5_negotiate (Proxy_Socket, int); * This may be reused by local-command proxies on individual * platforms. */ -char *format_telnet_command(SockAddr addr, int port, const Config *cfg); +char *format_telnet_command(SockAddr addr, int port, Conf *conf); /* * These are implemented in cproxy.c or nocproxy.c, depending on diff --git a/pscp.c b/pscp.c index 451bdb03..a0910c7a 100644 --- a/pscp.c +++ b/pscp.c @@ -44,7 +44,7 @@ static int using_sftp = 0; static Backend *back; static void *backhandle; -static Config cfg; +static Conf *conf; static void source(char *src); static void rsource(char *src); @@ -333,88 +333,90 @@ static void do_cmd(char *host, char *user, char *cmd) */ if (!loaded_session) { /* Try to load settings for `host' into a temporary config */ - Config cfg2; - cfg2.host[0] = '\0'; - do_defaults(host, &cfg2); - if (cfg2.host[0] != '\0') { + Conf *conf2 = conf_new(); + conf_set_str(conf2, CONF_host, ""); + do_defaults(host, conf2); + if (conf_get_str(conf2, CONF_host)[0] != '\0') { /* Settings present and include hostname */ /* Re-load data into the real config. */ - do_defaults(host, &cfg); + do_defaults(host, conf); } else { /* Session doesn't exist or mention a hostname. */ /* Use `host' as a bare hostname. */ - strncpy(cfg.host, host, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; + conf_set_str(conf, CONF_host, host); } } else { /* Patch in hostname `host' to session details. */ - strncpy(cfg.host, host, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; + conf_set_str(conf, CONF_host, host); } /* * Force use of SSH. (If they got the protocol wrong we assume the * port is useless too.) */ - if (cfg.protocol != PROT_SSH) { - cfg.protocol = PROT_SSH; - cfg.port = 22; + if (conf_get_int(conf, CONF_protocol) != PROT_SSH) { + conf_set_int(conf, CONF_protocol, PROT_SSH); + conf_set_int(conf, CONF_port, 22); } /* * Enact command-line overrides. */ - cmdline_run_saved(&cfg); + cmdline_run_saved(conf); /* - * Trim leading whitespace off the hostname if it's there. + * Muck about with the hostname in various ways. */ { - int space = strspn(cfg.host, " \t"); - memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); - } + char *hostbuf = dupstr(conf_get_str(conf, CONF_host)); + char *host = hostbuf; + char *p, *q; - /* See if host is of the form user@host */ - if (cfg.host[0] != '\0') { - char *atsign = strrchr(cfg.host, '@'); - /* Make sure we're not overflowing the user field */ - if (atsign) { - if (atsign - cfg.host < sizeof cfg.username) { - strncpy(cfg.username, cfg.host, atsign - cfg.host); - cfg.username[atsign - cfg.host] = '\0'; - } - memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); - } - } + /* + * Trim leading whitespace. + */ + host += strspn(host, " \t"); - /* - * Remove any remaining whitespace from the hostname. - */ - { - int p1 = 0, p2 = 0; - while (cfg.host[p2] != '\0') { - if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { - cfg.host[p1] = cfg.host[p2]; - p1++; + /* + * See if host is of the form user@host, and separate out + * the username if so. + */ + if (host[0] != '\0') { + char *atsign = strrchr(host, '@'); + if (atsign) { + *atsign = '\0'; + conf_set_str(conf, CONF_username, host); + host = atsign + 1; } - p2++; } - cfg.host[p1] = '\0'; + + /* + * Remove any remaining whitespace. + */ + p = hostbuf; + q = host; + while (*q) { + if (*q != ' ' && *q != '\t') + *p++ = *q; + q++; + } + *p = '\0'; + + conf_set_str(conf, CONF_host, hostbuf); + sfree(hostbuf); } /* Set username */ if (user != NULL && user[0] != '\0') { - strncpy(cfg.username, user, sizeof(cfg.username) - 1); - cfg.username[sizeof(cfg.username) - 1] = '\0'; - } else if (cfg.username[0] == '\0') { + conf_set_str(conf, CONF_username, user); + } else if (conf_get_str(conf, CONF_username)[0] == '\0') { user = get_username(); if (!user) bump("Empty user name"); else { if (verbose) tell_user(stderr, "Guessing user name: %s", user); - strncpy(cfg.username, user, sizeof(cfg.username) - 1); - cfg.username[sizeof(cfg.username) - 1] = '\0'; + conf_set_str(conf, CONF_username, user); sfree(user); } } @@ -424,10 +426,14 @@ static void do_cmd(char *host, char *user, char *cmd) * things like SCP and SFTP: agent forwarding, port forwarding, * X forwarding. */ - cfg.x11_forward = 0; - cfg.agentfwd = 0; - cfg.portfwd[0] = cfg.portfwd[1] = '\0'; - cfg.ssh_simple = TRUE; + conf_set_int(conf, CONF_x11_forward, 0); + conf_set_int(conf, CONF_agentfwd, 0); + conf_set_int(conf, CONF_ssh_simple, TRUE); + { + char *key; + while ((key = conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) != NULL) + conf_del_str_str(conf, CONF_portfwd, key); + } /* * Set up main and possibly fallback command depending on @@ -435,44 +441,49 @@ static void do_cmd(char *host, char *user, char *cmd) * Attempt to start the SFTP subsystem as a first choice, * falling back to the provided scp command if that fails. */ - cfg.remote_cmd_ptr2 = NULL; + conf_set_str(conf, CONF_remote_cmd2, ""); if (try_sftp) { /* First choice is SFTP subsystem. */ main_cmd_is_sftp = 1; - strcpy(cfg.remote_cmd, "sftp"); - cfg.ssh_subsys = TRUE; + conf_set_str(conf, CONF_remote_cmd, "sftp"); + conf_set_int(conf, CONF_ssh_subsys, TRUE); if (try_scp) { /* Fallback is to use the provided scp command. */ fallback_cmd_is_sftp = 0; - cfg.remote_cmd_ptr2 = cmd; - cfg.ssh_subsys2 = FALSE; + conf_set_str(conf, CONF_remote_cmd2, "sftp"); + conf_set_int(conf, CONF_ssh_subsys2, FALSE); } else { /* Since we're not going to try SCP, we may as well try * harder to find an SFTP server, since in the current * implementation we have a spare slot. */ fallback_cmd_is_sftp = 1; /* see psftp.c for full explanation of this kludge */ - cfg.remote_cmd_ptr2 = - "test -x /usr/lib/sftp-server && exec /usr/lib/sftp-server\n" - "test -x /usr/local/lib/sftp-server && exec /usr/local/lib/sftp-server\n" - "exec sftp-server"; - cfg.ssh_subsys2 = FALSE; + conf_set_str(conf, CONF_remote_cmd2, + "test -x /usr/lib/sftp-server &&" + " exec /usr/lib/sftp-server\n" + "test -x /usr/local/lib/sftp-server &&" + " exec /usr/local/lib/sftp-server\n" + "exec sftp-server"); + conf_set_int(conf, CONF_ssh_subsys2, FALSE); } } else { /* Don't try SFTP at all; just try the scp command. */ main_cmd_is_sftp = 0; - cfg.remote_cmd_ptr = cmd; - cfg.ssh_subsys = FALSE; + conf_set_str(conf, CONF_remote_cmd, cmd); + conf_set_int(conf, CONF_ssh_subsys, FALSE); } - cfg.nopty = TRUE; + conf_set_int(conf, CONF_nopty, TRUE); back = &ssh_backend; - err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, - 0, cfg.tcp_keepalives); + err = back->init(NULL, &backhandle, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, 0, + conf_get_int(conf, CONF_tcp_keepalives)); if (err != NULL) bump("ssh_init: %s", err); - logctx = log_init(NULL, &cfg); + logctx = log_init(NULL, conf); back->provide_logctx(backhandle, logctx); console_provide_logctx(logctx); ssh_scp_init(); @@ -2221,14 +2232,15 @@ int psftp_main(int argc, char *argv[]) sk_init(); /* Load Default Settings before doing anything else. */ - do_defaults(NULL, &cfg); + conf = conf_new(); + do_defaults(NULL, conf); loaded_session = FALSE; for (i = 1; i < argc; i++) { int ret; if (argv[i][0] != '-') break; - ret = cmdline_process_param(argv[i], i+1init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, - 0, cfg.tcp_keepalives); + err = back->init(NULL, &backhandle, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, 0, + conf_get_int(conf, CONF_tcp_keepalives)); if (err != NULL) { fprintf(stderr, "ssh_init: %s\n", err); return 1; } - logctx = log_init(NULL, &cfg); + logctx = log_init(NULL, conf); back->provide_logctx(backhandle, logctx); console_provide_logctx(logctx); while (!back->sendok(backhandle)) { @@ -2854,7 +2861,8 @@ int psftp_main(int argc, char *argv[]) userhost = user = NULL; /* Load Default Settings before doing anything else. */ - do_defaults(NULL, &cfg); + conf = conf_new(); + do_defaults(NULL, conf); loaded_session = FALSE; for (i = 1; i < argc; i++) { @@ -2866,7 +2874,7 @@ int psftp_main(int argc, char *argv[]) userhost = dupstr(argv[i]); continue; } - ret = cmdline_process_param(argv[i], i+1reconfig() passes in a replacement configuration. */ - void (*reconfig) (void *handle, Config *cfg); + void (*reconfig) (void *handle, Conf *conf); /* back->send() returns the current amount of buffered data. */ int (*send) (void *handle, char *buf, int len); /* back->sendbuffer() does the same thing but without attempting a send */ @@ -461,214 +460,6 @@ extern const int be_default_protocol; */ extern const char *const appname; -/* - * IMPORTANT POLICY POINT: everything in this structure which wants - * to be treated like an integer must be an actual, honest-to- - * goodness `int'. No enum-typed variables. This is because parts - * of the code will want to pass around `int *' pointers to them - * and we can't run the risk of porting to some system on which the - * enum comes out as a different size from int. - */ -struct config_tag { - /* Basic options */ - char host[512]; - int port; - int protocol; - int addressfamily; - int close_on_exit; - int warn_on_close; - int ping_interval; /* in seconds */ - int tcp_nodelay; - int tcp_keepalives; - char loghost[512]; /* logical host being contacted, for host key check */ - /* Proxy options */ - char proxy_exclude_list[512]; - int proxy_dns; - int even_proxy_localhost; - int proxy_type; - char proxy_host[512]; - int proxy_port; - char proxy_username[128]; - char proxy_password[128]; - char proxy_telnet_command[512]; - /* SSH options */ - char remote_cmd[512]; - char *remote_cmd_ptr; /* might point to a larger command - * but never for loading/saving */ - char *remote_cmd_ptr2; /* might point to a larger command - * but never for loading/saving */ - int nopty; - int compression; - int ssh_kexlist[KEX_MAX]; - int ssh_rekey_time; /* in minutes */ - char ssh_rekey_data[16]; - int tryagent; - int agentfwd; - int change_username; /* allow username switching in SSH-2 */ - int ssh_cipherlist[CIPHER_MAX]; - Filename keyfile; - int sshprot; /* use v1 or v2 when both available */ - int ssh2_des_cbc; /* "des-cbc" unrecommended SSH-2 cipher */ - int ssh_no_userauth; /* bypass "ssh-userauth" (SSH-2 only) */ - int ssh_show_banner; /* show USERAUTH_BANNERs (SSH-2 only) */ - int try_tis_auth; - int try_ki_auth; - int try_gssapi_auth; /* attempt gssapi auth */ - int gssapifwd; /* forward tgt via gss */ - int ssh_gsslist[4]; /* preference order for local GSS libs */ - Filename ssh_gss_custom; - int ssh_subsys; /* run a subsystem rather than a command */ - int ssh_subsys2; /* fallback to go with remote_cmd_ptr2 */ - int ssh_no_shell; /* avoid running a shell */ - char ssh_nc_host[512]; /* host to connect to in `nc' mode */ - int ssh_nc_port; /* port to connect to in `nc' mode */ - /* Telnet options */ - char termtype[32]; - char termspeed[32]; - char ttymodes[768]; /* MODE\tVvalue\0MODE\tA\0\0 */ - char environmt[1024]; /* VAR\tvalue\0VAR\tvalue\0\0 */ - char username[100]; - int username_from_env; - char localusername[100]; - int rfc_environ; - int passive_telnet; - /* Serial port options */ - char serline[256]; - int serspeed; - int serdatabits, serstopbits; - int serparity; - int serflow; - /* Keyboard options */ - int bksp_is_delete; - int rxvt_homeend; - int funky_type; - int no_applic_c; /* totally disable app cursor keys */ - int no_applic_k; /* totally disable app keypad */ - int no_mouse_rep; /* totally disable mouse reporting */ - int no_remote_resize; /* disable remote resizing */ - int no_alt_screen; /* disable alternate screen */ - int no_remote_wintitle; /* disable remote retitling */ - int no_dbackspace; /* disable destructive backspace */ - int no_remote_charset; /* disable remote charset config */ - int remote_qtitle_action; /* remote win title query action */ - int app_cursor; - int app_keypad; - int nethack_keypad; - int telnet_keyboard; - int telnet_newline; - int alt_f4; /* is it special? */ - int alt_space; /* is it special? */ - int alt_only; /* is it special? */ - int localecho; - int localedit; - int alwaysontop; - int fullscreenonaltenter; - int scroll_on_key; - int scroll_on_disp; - int erase_to_scrollback; - int compose_key; - int ctrlaltkeys; - char wintitle[256]; /* initial window title */ - /* Terminal options */ - int savelines; - int dec_om; - int wrap_mode; - int lfhascr; - int cursor_type; /* 0=block 1=underline 2=vertical */ - int blink_cur; - int beep; - int beep_ind; - int bellovl; /* bell overload protection active? */ - int bellovl_n; /* number of bells to cause overload */ - int bellovl_t; /* time interval for overload (seconds) */ - int bellovl_s; /* period of silence to re-enable bell (s) */ - Filename bell_wavefile; - int scrollbar; - int scrollbar_in_fullscreen; - int resize_action; - int bce; - int blinktext; - int win_name_always; - int width, height; - FontSpec font; - int font_quality; - Filename logfilename; - int logtype; - int logxfovr; - int logflush; - int logomitpass; - int logomitdata; - int hide_mouseptr; - int sunken_edge; - int window_border; - char answerback[256]; - char printer[128]; - int arabicshaping; - int bidi; - /* Colour options */ - int ansi_colour; - int xterm_256_colour; - int system_colour; - int try_palette; - int bold_colour; - unsigned char colours[22][3]; - /* Selection options */ - int mouse_is_xterm; - int rect_select; - int rawcnp; - int rtf_paste; - int mouse_override; - short wordness[256]; - /* translations */ - int vtmode; - char line_codepage[128]; - int cjk_ambig_wide; - int utf8_override; - int xlat_capslockcyr; - /* X11 forwarding */ - int x11_forward; - char x11_display[128]; - int x11_auth; - Filename xauthfile; - /* port forwarding */ - int lport_acceptall; /* accept conns from hosts other than localhost */ - int rport_acceptall; /* same for remote forwarded ports (SSH-2 only) */ - /* - * The port forwarding string contains a number of - * NUL-terminated substrings, terminated in turn by an empty - * string (i.e. a second NUL immediately after the previous - * one). Each string can be of one of the following forms: - * - * [LR]localport\thost:port - * [LR]localaddr:localport\thost:port - * Dlocalport - * Dlocaladdr:localport - */ - char portfwd[1024]; - /* SSH bug compatibility modes */ - int sshbug_ignore1, sshbug_plainpw1, sshbug_rsa1, - sshbug_hmac2, sshbug_derivekey2, sshbug_rsapad2, - sshbug_pksessid2, sshbug_rekey2, sshbug_maxpkt2, - sshbug_ignore2; - /* - * ssh_simple means that we promise never to open any channel other - * than the main one, which means it can safely use a very large - * window in SSH-2. - */ - int ssh_simple; - /* Options for pterm. Should split out into platform-dependent part. */ - int stamp_utmp; - int login_shell; - int scrollbar_on_left; - int shadowbold; - FontSpec boldfont; - FontSpec widefont; - FontSpec wideboldfont; - int shadowboldoffset; - int crhaslf; - char winclass[256]; -}; - /* * Some global flags denoting the type of application. * @@ -838,6 +629,255 @@ void set_busy_status(void *frontend, int status); void cleanup_exit(int); +/* + * Exports from conf.c, and a big enum (via parametric macro) of + * configuration option keys. + */ +#define CONFIG_OPTIONS(X) \ + /* X(value-type, subkey-type, keyword) */ \ + X(STR, NONE, host) \ + X(INT, NONE, port) \ + X(INT, NONE, protocol) \ + X(INT, NONE, addressfamily) \ + X(INT, NONE, close_on_exit) \ + X(INT, NONE, warn_on_close) \ + X(INT, NONE, ping_interval) /* in seconds */ \ + X(INT, NONE, tcp_nodelay) \ + X(INT, NONE, tcp_keepalives) \ + X(STR, NONE, loghost) /* logical host being contacted, for host key check */ \ + /* Proxy options */ \ + X(STR, NONE, proxy_exclude_list) \ + X(INT, NONE, proxy_dns) \ + X(INT, NONE, even_proxy_localhost) \ + X(INT, NONE, proxy_type) \ + X(STR, NONE, proxy_host) \ + X(INT, NONE, proxy_port) \ + X(STR, NONE, proxy_username) \ + X(STR, NONE, proxy_password) \ + X(STR, NONE, proxy_telnet_command) \ + /* SSH options */ \ + X(STR, NONE, remote_cmd) \ + X(STR, NONE, remote_cmd2) /* fallback if remote_cmd fails; never loaded or saved */ \ + X(INT, NONE, nopty) \ + X(INT, NONE, compression) \ + X(INT, INT, ssh_kexlist) \ + X(INT, NONE, ssh_rekey_time) /* in minutes */ \ + X(STR, NONE, ssh_rekey_data) /* string encoding e.g. "100K", "2M", "1G" */ \ + X(INT, NONE, tryagent) \ + X(INT, NONE, agentfwd) \ + X(INT, NONE, change_username) /* allow username switching in SSH-2 */ \ + X(INT, INT, ssh_cipherlist) \ + X(FILENAME, NONE, keyfile) \ + X(INT, NONE, sshprot) /* use v1 or v2 when both available */ \ + X(INT, NONE, ssh2_des_cbc) /* "des-cbc" unrecommended SSH-2 cipher */ \ + X(INT, NONE, ssh_no_userauth) /* bypass "ssh-userauth" (SSH-2 only) */ \ + X(INT, NONE, ssh_show_banner) /* show USERAUTH_BANNERs (SSH-2 only) */ \ + X(INT, NONE, try_tis_auth) \ + X(INT, NONE, try_ki_auth) \ + X(INT, NONE, try_gssapi_auth) /* attempt gssapi auth */ \ + X(INT, NONE, gssapifwd) /* forward tgt via gss */ \ + X(INT, INT, ssh_gsslist) /* preference order for local GSS libs */ \ + X(FILENAME, NONE, ssh_gss_custom) \ + X(INT, NONE, ssh_subsys) /* run a subsystem rather than a command */ \ + X(INT, NONE, ssh_subsys2) /* fallback to go with remote_cmd_ptr2 */ \ + X(INT, NONE, ssh_no_shell) /* avoid running a shell */ \ + X(STR, NONE, ssh_nc_host) /* host to connect to in `nc' mode */ \ + X(INT, NONE, ssh_nc_port) /* port to connect to in `nc' mode */ \ + /* Telnet options */ \ + X(STR, NONE, termtype) \ + X(STR, NONE, termspeed) \ + X(STR, STR, ttymodes) /* values are "Vvalue" or "A" */ \ + X(STR, STR, environmt) \ + X(STR, NONE, username) \ + X(INT, NONE, username_from_env) \ + X(STR, NONE, localusername) \ + X(INT, NONE, rfc_environ) \ + X(INT, NONE, passive_telnet) \ + /* Serial port options */ \ + X(STR, NONE, serline) \ + X(INT, NONE, serspeed) \ + X(INT, NONE, serdatabits) \ + X(INT, NONE, serstopbits) \ + X(INT, NONE, serparity) \ + X(INT, NONE, serflow) \ + /* Keyboard options */ \ + X(INT, NONE, bksp_is_delete) \ + X(INT, NONE, rxvt_homeend) \ + X(INT, NONE, funky_type) \ + X(INT, NONE, no_applic_c) /* totally disable app cursor keys */ \ + X(INT, NONE, no_applic_k) /* totally disable app keypad */ \ + X(INT, NONE, no_mouse_rep) /* totally disable mouse reporting */ \ + X(INT, NONE, no_remote_resize) /* disable remote resizing */ \ + X(INT, NONE, no_alt_screen) /* disable alternate screen */ \ + X(INT, NONE, no_remote_wintitle) /* disable remote retitling */ \ + X(INT, NONE, no_dbackspace) /* disable destructive backspace */ \ + X(INT, NONE, no_remote_charset) /* disable remote charset config */ \ + X(INT, NONE, remote_qtitle_action) /* remote win title query action */ \ + X(INT, NONE, app_cursor) \ + X(INT, NONE, app_keypad) \ + X(INT, NONE, nethack_keypad) \ + X(INT, NONE, telnet_keyboard) \ + X(INT, NONE, telnet_newline) \ + X(INT, NONE, alt_f4) /* is it special? */ \ + X(INT, NONE, alt_space) /* is it special? */ \ + X(INT, NONE, alt_only) /* is it special? */ \ + X(INT, NONE, localecho) \ + X(INT, NONE, localedit) \ + X(INT, NONE, alwaysontop) \ + X(INT, NONE, fullscreenonaltenter) \ + X(INT, NONE, scroll_on_key) \ + X(INT, NONE, scroll_on_disp) \ + X(INT, NONE, erase_to_scrollback) \ + X(INT, NONE, compose_key) \ + X(INT, NONE, ctrlaltkeys) \ + X(STR, NONE, wintitle) /* initial window title */ \ + /* Terminal options */ \ + X(INT, NONE, savelines) \ + X(INT, NONE, dec_om) \ + X(INT, NONE, wrap_mode) \ + X(INT, NONE, lfhascr) \ + X(INT, NONE, cursor_type) /* 0=block 1=underline 2=vertical */ \ + X(INT, NONE, blink_cur) \ + X(INT, NONE, beep) \ + X(INT, NONE, beep_ind) \ + X(INT, NONE, bellovl) /* bell overload protection active? */ \ + X(INT, NONE, bellovl_n) /* number of bells to cause overload */ \ + X(INT, NONE, bellovl_t) /* time interval for overload (seconds) */ \ + X(INT, NONE, bellovl_s) /* period of silence to re-enable bell (s) */ \ + X(FILENAME, NONE, bell_wavefile) \ + X(INT, NONE, scrollbar) \ + X(INT, NONE, scrollbar_in_fullscreen) \ + X(INT, NONE, resize_action) \ + X(INT, NONE, bce) \ + X(INT, NONE, blinktext) \ + X(INT, NONE, win_name_always) \ + X(INT, NONE, width) \ + X(INT, NONE, height) \ + X(FONT, NONE, font) \ + X(INT, NONE, font_quality) \ + X(FILENAME, NONE, logfilename) \ + X(INT, NONE, logtype) \ + X(INT, NONE, logxfovr) \ + X(INT, NONE, logflush) \ + X(INT, NONE, logomitpass) \ + X(INT, NONE, logomitdata) \ + X(INT, NONE, hide_mouseptr) \ + X(INT, NONE, sunken_edge) \ + X(INT, NONE, window_border) \ + X(STR, NONE, answerback) \ + X(STR, NONE, printer) \ + X(INT, NONE, arabicshaping) \ + X(INT, NONE, bidi) \ + /* Colour options */ \ + X(INT, NONE, ansi_colour) \ + X(INT, NONE, xterm_256_colour) \ + X(INT, NONE, system_colour) \ + X(INT, NONE, try_palette) \ + X(INT, NONE, bold_colour) \ + X(INT, INT, colours) \ + /* Selection options */ \ + X(INT, NONE, mouse_is_xterm) \ + X(INT, NONE, rect_select) \ + X(INT, NONE, rawcnp) \ + X(INT, NONE, rtf_paste) \ + X(INT, NONE, mouse_override) \ + X(INT, INT, wordness) \ + /* translations */ \ + X(INT, NONE, vtmode) \ + X(STR, NONE, line_codepage) \ + X(INT, NONE, cjk_ambig_wide) \ + X(INT, NONE, utf8_override) \ + X(INT, NONE, xlat_capslockcyr) \ + /* X11 forwarding */ \ + X(INT, NONE, x11_forward) \ + X(STR, NONE, x11_display) \ + X(INT, NONE, x11_auth) \ + X(FILENAME, NONE, xauthfile) \ + /* port forwarding */ \ + X(INT, NONE, lport_acceptall) /* accept conns from hosts other than localhost */ \ + X(INT, NONE, rport_acceptall) /* same for remote forwarded ports (SSH-2 only) */ \ + /* \ + * Subkeys for 'portfwd' can have the following forms: \ + * \ + * [LR]localport \ + * [LR]localaddr:localport \ + * \ + * Dynamic forwardings are indicated by an 'L' key, and the \ + * special value "D". For all other forwardings, the value \ + * should be of the form 'host:port'. \ + */ \ + X(STR, STR, portfwd) \ + /* SSH bug compatibility modes */ \ + X(INT, NONE, sshbug_ignore1) \ + X(INT, NONE, sshbug_plainpw1) \ + X(INT, NONE, sshbug_rsa1) \ + X(INT, NONE, sshbug_hmac2) \ + X(INT, NONE, sshbug_derivekey2) \ + X(INT, NONE, sshbug_rsapad2) \ + X(INT, NONE, sshbug_pksessid2) \ + X(INT, NONE, sshbug_rekey2) \ + X(INT, NONE, sshbug_maxpkt2) \ + X(INT, NONE, sshbug_ignore2) \ + /* \ + * ssh_simple means that we promise never to open any channel \ + * other than the main one, which means it can safely use a very \ + * large window in SSH-2. \ + */ \ + X(INT, NONE, ssh_simple) \ + /* Options for pterm. Should split out into platform-dependent part. */ \ + X(INT, NONE, stamp_utmp) \ + X(INT, NONE, login_shell) \ + X(INT, NONE, scrollbar_on_left) \ + X(INT, NONE, shadowbold) \ + X(FONT, NONE, boldfont) \ + X(FONT, NONE, widefont) \ + X(FONT, NONE, wideboldfont) \ + X(INT, NONE, shadowboldoffset) \ + X(INT, NONE, crhaslf) \ + X(STR, NONE, winclass) \ + +/* Now define the actual enum of option keywords using that macro. */ +#define CONF_ENUM_DEF(valtype, keytype, keyword) CONF_ ## keyword, +enum config_primary_key { CONFIG_OPTIONS(CONF_ENUM_DEF) N_CONFIG_OPTIONS }; +#undef CONF_ENUM_DEF + +#define NCFGCOLOURS 22 /* number of colours in CONF_colours above */ + +/* Functions handling configuration structures. */ +Conf *conf_new(void); /* create an empty configuration */ +void conf_free(Conf *conf); +Conf *conf_copy(Conf *oldconf); +void conf_copy_into(Conf *dest, Conf *src); +/* Mandatory accessor functions: enforce by assertion that keys exist. */ +int conf_get_int(Conf *conf, int key); +int conf_get_int_int(Conf *conf, int key, int subkey); +char *conf_get_str(Conf *conf, int key); /* result still owned by conf */ +char *conf_get_str_str(Conf *conf, int key, const char *subkey); +Filename *conf_get_filename(Conf *conf, int key); +FontSpec *conf_get_fontspec(Conf *conf, int key); +/* Optional accessor function: return NULL if key does not exist. */ +char *conf_get_str_str_opt(Conf *conf, int key, const char *subkey); +/* Accessor function to step through a string-subkeyed list. + * Returns the next subkey after the provided one, or the first if NULL. + * Returns NULL if there are none left. + * Both the return value and *subkeyout are still owned by conf. */ +char *conf_get_str_strs(Conf *conf, int key, char *subkeyin, char **subkeyout); +/* Return the nth string subkey in a list. Owned by conf. NULL if beyond end */ +char *conf_get_str_nthstrkey(Conf *conf, int key, int n); +/* Functions to set entries in configuration. Always copy their inputs. */ +void conf_set_int(Conf *conf, int key, int value); +void conf_set_int_int(Conf *conf, int key, int subkey, int value); +void conf_set_str(Conf *conf, int key, const char *value); +void conf_set_str_str(Conf *conf, int key, + const char *subkey, const char *val); +void conf_del_str_str(Conf *conf, int key, const char *subkey); +void conf_set_filename(Conf *conf, int key, const Filename *val); +void conf_set_fontspec(Conf *conf, int key, const FontSpec *val); +/* Serialisation functions for Duplicate Session */ +int conf_serialised_size(Conf *conf); +void conf_serialise(Conf *conf, void *data); +int conf_deserialise(Conf *conf, void *data, int maxsize);/*returns size used*/ + /* * Exports from noise.c. */ @@ -853,13 +893,13 @@ void random_destroy_seed(void); */ Backend *backend_from_name(const char *name); Backend *backend_from_proto(int proto); -int get_remote_username(Config *cfg, char *user, size_t len); -char *save_settings(char *section, Config * cfg); -void save_open_settings(void *sesskey, Config *cfg); -void load_settings(char *section, Config * cfg); -void load_open_settings(void *sesskey, Config *cfg); +char *get_remote_username(Conf *conf); /* dynamically allocated */ +char *save_settings(char *section, Conf *conf); +void save_open_settings(void *sesskey, Conf *conf); +void load_settings(char *section, Conf *conf); +void load_open_settings(void *sesskey, Conf *conf); void get_sesslist(struct sesslist *, int allocate); -void do_defaults(char *, Config *); +void do_defaults(char *, Conf *); void registry_cleanup(void); /* @@ -882,7 +922,7 @@ FontSpec platform_default_fontspec(const char *name); * Exports from terminal.c. */ -Terminal *term_init(Config *, struct unicode_data *, void *); +Terminal *term_init(Conf *, struct unicode_data *, void *); void term_free(Terminal *); void term_size(Terminal *, int, int, int); void term_paint(Terminal *, Context, int, int, int, int, int); @@ -904,7 +944,7 @@ void term_paste(Terminal *); void term_nopaste(Terminal *); int term_ldisc(Terminal *, int option); void term_copyall(Terminal *); -void term_reconfig(Terminal *, Config *); +void term_reconfig(Terminal *, Conf *); void term_seen_key_event(Terminal *); int term_data(Terminal *, int is_stderr, const char *data, int len); int term_data_untrusted(Terminal *, const char *data, int len); @@ -922,9 +962,9 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl); /* * Exports from logging.c. */ -void *log_init(void *frontend, Config *cfg); +void *log_init(void *frontend, Conf *conf); void log_free(void *logctx); -void log_reconfig(void *logctx, Config *cfg); +void log_reconfig(void *logctx, Conf *conf); void logfopen(void *logctx); void logfclose(void *logctx); void logtraffic(void *logctx, unsigned char c, int logmode); @@ -975,7 +1015,8 @@ extern Backend ssh_backend; /* * Exports from ldisc.c. */ -void *ldisc_create(Config *, Terminal *, Backend *, void *, void *); +void *ldisc_create(Conf *, Terminal *, Backend *, void *, void *); +void ldisc_configure(void *, Conf *); void ldisc_free(void *); void ldisc_send(void *handle, char *buf, int len, int interactive); @@ -1003,8 +1044,8 @@ void random_unref(void); * Exports from pinger.c. */ typedef struct pinger_tag *Pinger; -Pinger pinger_new(Config *cfg, Backend *back, void *backhandle); -void pinger_reconfig(Pinger, Config *oldcfg, Config *newcfg); +Pinger pinger_new(Conf *conf, Backend *back, void *backhandle); +void pinger_reconfig(Pinger, Conf *oldconf, Conf *newconf); void pinger_free(Pinger); /* @@ -1012,8 +1053,8 @@ void pinger_free(Pinger); */ #include "misc.h" -int cfg_launchable(const Config *cfg); -char const *cfg_dest(const Config *cfg); +int conf_launchable(Conf *conf); +char const *conf_dest(Conf *conf); /* * Exports from sercfg.c. @@ -1147,8 +1188,8 @@ void printer_finish_job(printer_job *); * defined differently in various places and required _by_ * cmdline.c). */ -int cmdline_process_param(char *, char *, int, Config *); -void cmdline_run_saved(Config *); +int cmdline_process_param(char *, char *, int, Conf *); +void cmdline_run_saved(Conf *); void cmdline_cleanup(void); int cmdline_get_passwd_input(prompts_t *p, unsigned char *in, int inlen); #define TOOLTYPE_FILETRANSFER 1 @@ -1161,6 +1202,18 @@ void cmdline_error(char *, ...); * Exports from config.c. */ struct controlbox; +union control; +void conf_radiobutton_handler(union control *ctrl, void *dlg, + void *data, int event); +#define CHECKBOX_INVERT (1<<30) +void conf_checkbox_handler(union control *ctrl, void *dlg, + void *data, int event); +void conf_editbox_handler(union control *ctrl, void *dlg, + void *data, int event); +void conf_filesel_handler(union control *ctrl, void *dlg, + void *data, int event); +void conf_fontsel_handler(union control *ctrl, void *dlg, + void *data, int event); void setup_config_box(struct controlbox *b, int midsession, int protocol, int protcfginfo); diff --git a/raw.c b/raw.c index b2676a93..6eb605d9 100644 --- a/raw.c +++ b/raw.c @@ -89,7 +89,7 @@ static void raw_sent(Plug plug, int bufsize) * freed by the caller. */ static const char *raw_init(void *frontend_handle, void **backend_handle, - Config *cfg, + Conf *conf, char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -102,6 +102,8 @@ static const char *raw_init(void *frontend_handle, void **backend_handle, SockAddr addr; const char *err; Raw raw; + int addressfamily; + char *loghost; raw = snew(struct raw_backend_data); raw->fn = &fn_table; @@ -110,19 +112,20 @@ static const char *raw_init(void *frontend_handle, void **backend_handle, raw->frontend = frontend_handle; + addressfamily = conf_get_int(conf, CONF_addressfamily); /* * Try to find host. */ { char *buf; buf = dupprintf("Looking up host \"%s\"%s", host, - (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : - (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : + (addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : + (addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); logevent(raw->frontend, buf); sfree(buf); } - addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily); + addr = name_lookup(host, port, realhost, conf, addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -135,15 +138,16 @@ static const char *raw_init(void *frontend_handle, void **backend_handle, * Open socket. */ raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive, - (Plug) raw, cfg); + (Plug) raw, conf); if ((err = sk_socket_error(raw->s)) != NULL) return err; - if (*cfg->loghost) { + loghost = conf_get_str(conf, CONF_loghost); + if (*loghost) { char *colon; sfree(*realhost); - *realhost = dupstr(cfg->loghost); + *realhost = dupstr(loghost); colon = strrchr(*realhost, ':'); if (colon) { /* @@ -170,7 +174,7 @@ static void raw_free(void *handle) /* * Stub routine (we don't have any need to reconfigure this backend). */ -static void raw_reconfig(void *handle, Config *cfg) +static void raw_reconfig(void *handle, Conf *conf) { } diff --git a/rlogin.c b/rlogin.c index 6841fc6e..7cfe7837 100644 --- a/rlogin.c +++ b/rlogin.c @@ -28,7 +28,7 @@ typedef struct rlogin_tag { int term_width, term_height; void *frontend; - Config cfg; + Conf *conf; /* In case we need to read a username from the terminal before starting */ prompts_t *prompt; @@ -122,18 +122,18 @@ static void rlogin_startup(Rlogin rlogin, const char *ruser) { char z = 0; char *p; + sk_write(rlogin->s, &z, 1); - sk_write(rlogin->s, rlogin->cfg.localusername, - strlen(rlogin->cfg.localusername)); + p = conf_get_str(rlogin->conf, CONF_localusername); + sk_write(rlogin->s, p, strlen(p)); sk_write(rlogin->s, &z, 1); - sk_write(rlogin->s, ruser, - strlen(ruser)); + sk_write(rlogin->s, ruser, strlen(ruser)); sk_write(rlogin->s, &z, 1); - sk_write(rlogin->s, rlogin->cfg.termtype, - strlen(rlogin->cfg.termtype)); + p = conf_get_str(rlogin->conf, CONF_termtype); + sk_write(rlogin->s, p, strlen(p)); sk_write(rlogin->s, "/", 1); - for (p = rlogin->cfg.termspeed; isdigit((unsigned char)*p); p++) continue; - sk_write(rlogin->s, rlogin->cfg.termspeed, p - rlogin->cfg.termspeed); + p = conf_get_str(rlogin->conf, CONF_termspeed); + sk_write(rlogin->s, p, strspn(p, "0123456789")); rlogin->bufsize = sk_write(rlogin->s, &z, 1); rlogin->prompt = NULL; @@ -148,7 +148,7 @@ static void rlogin_startup(Rlogin rlogin, const char *ruser) * freed by the caller. */ static const char *rlogin_init(void *frontend_handle, void **backend_handle, - Config *cfg, + Conf *conf, char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -161,33 +161,36 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle, SockAddr addr; const char *err; Rlogin rlogin; - char ruser[sizeof(cfg->username)]; + char *ruser; + int addressfamily; + char *loghost; rlogin = snew(struct rlogin_tag); rlogin->fn = &fn_table; rlogin->s = NULL; rlogin->frontend = frontend_handle; - rlogin->term_width = cfg->width; - rlogin->term_height = cfg->height; + rlogin->term_width = conf_get_int(conf, CONF_width); + rlogin->term_height = conf_get_int(conf, CONF_height); rlogin->firstbyte = 1; rlogin->cansize = 0; rlogin->prompt = NULL; - rlogin->cfg = *cfg; /* STRUCTURE COPY */ + rlogin->conf = conf_copy(conf); *backend_handle = rlogin; + addressfamily = conf_get_int(conf, CONF_addressfamily); /* * Try to find host. */ { char *buf; buf = dupprintf("Looking up host \"%s\"%s", host, - (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : - (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : + (addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : + (addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); logevent(rlogin->frontend, buf); sfree(buf); } - addr = name_lookup(host, port, realhost, cfg, cfg->addressfamily); + addr = name_lookup(host, port, realhost, conf, addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -200,15 +203,16 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle, * Open socket. */ rlogin->s = new_connection(addr, *realhost, port, 1, 0, - nodelay, keepalive, (Plug) rlogin, cfg); + nodelay, keepalive, (Plug) rlogin, conf); if ((err = sk_socket_error(rlogin->s)) != NULL) return err; - if (*cfg->loghost) { + loghost = conf_get_str(conf, CONF_loghost); + if (*loghost) { char *colon; sfree(*realhost); - *realhost = dupstr(cfg->loghost); + *realhost = dupstr(loghost); colon = strrchr(*realhost, ':'); if (colon) { /* @@ -226,16 +230,17 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle, * in which case we prompt for it and may end up deferring doing * anything else until the local prompt mechanism returns. */ - if (get_remote_username(cfg, ruser, sizeof(ruser))) { + if ((ruser = get_remote_username(conf)) == NULL) { rlogin_startup(rlogin, ruser); + sfree(ruser); } else { int ret; rlogin->prompt = new_prompts(rlogin->frontend); rlogin->prompt->to_server = TRUE; rlogin->prompt->name = dupstr("Rlogin login name"); - add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE, - sizeof(cfg->username)); + /* 512 is an arbitrary limit :-( */ + add_prompt(rlogin->prompt, dupstr("rlogin username: "), TRUE, 512); ret = get_userpass_input(rlogin->prompt, NULL, 0); if (ret >= 0) { rlogin_startup(rlogin, rlogin->prompt->prompts[0]->result); @@ -253,13 +258,14 @@ static void rlogin_free(void *handle) free_prompts(rlogin->prompt); if (rlogin->s) sk_close(rlogin->s); + conf_free(rlogin->conf); sfree(rlogin); } /* * Stub routine (we don't have any need to reconfigure this backend). */ -static void rlogin_reconfig(void *handle, Config *cfg) +static void rlogin_reconfig(void *handle, Conf *conf) { } diff --git a/sercfg.c b/sercfg.c index fc267370..fef910f3 100644 --- a/sercfg.c +++ b/sercfg.c @@ -31,10 +31,14 @@ static void serial_parity_handler(union control *ctrl, void *dlg, }; int mask = ctrl->listbox.context.i; int i, j; - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { - int oldparity = cfg->serparity;/* preserve past reentrant calls */ + /* Fetching this once at the start of the function ensures we + * remember what the right value is supposed to be when + * operations below cause reentrant calls to this function. */ + int oldparity = conf_get_int(conf, CONF_serparity); + dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < lenof(parities); i++) { @@ -56,14 +60,14 @@ static void serial_parity_handler(union control *ctrl, void *dlg, oldparity = SER_PAR_NONE; } dlg_update_done(ctrl, dlg); - cfg->serparity = oldparity; /* restore */ + conf_set_int(conf, CONF_serparity, oldparity); /* restore */ } else if (event == EVENT_SELCHANGE) { int i = dlg_listbox_index(ctrl, dlg); if (i < 0) i = SER_PAR_NONE; else i = dlg_listbox_getid(ctrl, dlg, i); - cfg->serparity = i; + conf_set_int(conf, CONF_serparity, i); } } @@ -81,10 +85,14 @@ static void serial_flow_handler(union control *ctrl, void *dlg, }; int mask = ctrl->listbox.context.i; int i, j; - Config *cfg = (Config *)data; + Conf *conf = (Conf *)data; if (event == EVENT_REFRESH) { - int oldflow = cfg->serflow; /* preserve past reentrant calls */ + /* Fetching this once at the start of the function ensures we + * remember what the right value is supposed to be when + * operations below cause reentrant calls to this function. */ + int oldflow = conf_get_int(conf, CONF_serflow); + dlg_update_start(ctrl, dlg); dlg_listbox_clear(ctrl, dlg); for (i = 0; i < lenof(flows); i++) { @@ -105,14 +113,14 @@ static void serial_flow_handler(union control *ctrl, void *dlg, oldflow = SER_FLOW_NONE; } dlg_update_done(ctrl, dlg); - cfg->serflow = oldflow; /* restore */ + conf_set_int(conf, CONF_serflow, oldflow);/* restore */ } else if (event == EVENT_SELCHANGE) { int i = dlg_listbox_index(ctrl, dlg); if (i < 0) i = SER_FLOW_NONE; else i = dlg_listbox_getid(ctrl, dlg, i); - cfg->serflow = i; + conf_set_int(conf, CONF_serflow, i); } } @@ -173,23 +181,22 @@ void ser_setup_config_box(struct controlbox *b, int midsession, "Select a serial line"); ctrl_editbox(s, "Serial line to connect to", 'l', 40, HELPCTX(serial_line), - dlg_stdeditbox_handler, I(offsetof(Config,serline)), - I(sizeof(((Config *)0)->serline))); + conf_editbox_handler, I(CONF_serline), I(1)); } s = ctrl_getset(b, "Connection/Serial", "sercfg", "Configure the serial line"); ctrl_editbox(s, "Speed (baud)", 's', 40, HELPCTX(serial_speed), - dlg_stdeditbox_handler, I(offsetof(Config,serspeed)), I(-1)); + conf_editbox_handler, I(CONF_serspeed), I(-1)); ctrl_editbox(s, "Data bits", 'b', 40, HELPCTX(serial_databits), - dlg_stdeditbox_handler,I(offsetof(Config,serdatabits)),I(-1)); + conf_editbox_handler, I(CONF_serdatabits), I(-1)); /* * Stop bits come in units of one half. */ ctrl_editbox(s, "Stop bits", 't', 40, HELPCTX(serial_stopbits), - dlg_stdeditbox_handler,I(offsetof(Config,serstopbits)),I(-2)); + conf_editbox_handler, I(CONF_serstopbits), I(-2)); ctrl_droplist(s, "Parity", 'p', 40, HELPCTX(serial_parity), serial_parity_handler, I(parity_mask)); diff --git a/settings.c b/settings.c index 943fbf3e..de69d660 100644 --- a/settings.c +++ b/settings.c @@ -70,45 +70,35 @@ Backend *backend_from_proto(int proto) return NULL; } -int get_remote_username(Config *cfg, char *user, size_t len) +char *get_remote_username(Conf *conf) { - if (*cfg->username) { - strncpy(user, cfg->username, len); - user[len-1] = '\0'; + char *username = conf_get_str(conf, CONF_username); + if (*username) { + return dupstr(username); + } else if (conf_get_int(conf, CONF_username_from_env)) { + /* Use local username. */ + return get_username(); /* might still be NULL */ } else { - if (cfg->username_from_env) { - /* Use local username. */ - char *luser = get_username(); - if (luser) { - strncpy(user, luser, len); - user[len-1] = '\0'; - sfree(luser); - } else { - *user = '\0'; - } - } else { - *user = '\0'; - } + return NULL; } - return (*user != '\0'); +} + +static char *gpps_raw(void *handle, const char *name, const char *def) +{ + char *ret = read_setting_s(handle, name); + if (!ret) + ret = platform_default_s(name); + if (!ret) + ret = def ? dupstr(def) : NULL; /* permit NULL as final fallback */ + return ret; } static void gpps(void *handle, const char *name, const char *def, - char *val, int len) + Conf *conf, int primary) { - if (!read_setting_s(handle, name, val, len)) { - char *pdef; - - pdef = platform_default_s(name); - if (pdef) { - strncpy(val, pdef, len); - sfree(pdef); - } else { - strncpy(val, def, len); - } - - val[len - 1] = '\0'; - } + char *val = gpps_raw(handle, name, def); + conf_set_str(conf, primary, val); + sfree(val); } /* @@ -116,21 +106,30 @@ static void gpps(void *handle, const char *name, const char *def, * format of a Filename or Font is platform-dependent. So the * platform-dependent functions MUST return some sort of value. */ -static void gppfont(void *handle, const char *name, FontSpec *result) +static void gppfont(void *handle, const char *name, Conf *conf, int primary) { - if (!read_setting_fontspec(handle, name, result)) - *result = platform_default_fontspec(name); + FontSpec result; + if (!read_setting_fontspec(handle, name, &result)) + result = platform_default_fontspec(name); + conf_set_fontspec(conf, primary, &result); } -static void gppfile(void *handle, const char *name, Filename *result) +static void gppfile(void *handle, const char *name, Conf *conf, int primary) { - if (!read_setting_filename(handle, name, result)) - *result = platform_default_filename(name); + Filename result; + if (!read_setting_filename(handle, name, &result)) + result = platform_default_filename(name); + conf_set_filename(conf, primary, &result); } -static void gppi(void *handle, char *name, int def, int *i) +static int gppi_raw(void *handle, char *name, int def) { def = platform_default_i(name, def); - *i = read_setting_i(handle, name, def); + return read_setting_i(handle, name, def); +} + +static void gppi(void *handle, char *name, int def, Conf *conf, int primary) +{ + conf_set_int(conf, primary, gppi_raw(handle, name, def)); } /* @@ -139,52 +138,128 @@ static void gppi(void *handle, char *name, int def, int *i) * NAME=VALUE,NAME=VALUE, in storage * `def' is in the storage format. */ -static void gppmap(void *handle, char *name, char *def, char *val, int len) +static int gppmap(void *handle, char *name, Conf *conf, int primary) { - char *buf = snewn(2*len, char), *p, *q; - gpps(handle, name, def, buf, 2*len); + char *buf, *p, *q, *key, *val; + + /* + * Start by clearing any existing subkeys of this key from conf. + */ + for (val = conf_get_str_strs(conf, primary, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, primary, key, &key)) + conf_del_str_str(conf, primary, key); + + /* + * Now read a serialised list from the settings and unmarshal it + * into its components. + */ + buf = gpps_raw(handle, name, NULL); + if (!buf) + return FALSE; + p = buf; - q = val; while (*p) { + q = buf; + val = NULL; while (*p && *p != ',') { int c = *p++; if (c == '=') - c = '\t'; + c = '\0'; if (c == '\\') c = *p++; *q++ = c; + if (!c) + val = q; } if (*p == ',') p++; - *q++ = '\0'; + if (!val) + val = q; + *q = '\0'; + + if (primary == CONF_portfwd && buf[0] == 'D') { + /* + * Backwards-compatibility hack: dynamic forwardings are + * indexed in the data store as a third type letter in the + * key, 'D' alongside 'L' and 'R' - but really, they + * should be filed under 'L' with a special _value_, + * because local and dynamic forwardings both involve + * _listening_ on a local port, and are hence mutually + * exclusive on the same port number. So here we translate + * the legacy storage format into the sensible internal + * form. + */ + char *newkey = dupcat("L", buf+1, NULL); + conf_set_str_str(conf, primary, newkey, "D"); + sfree(newkey); + } else { + conf_set_str_str(conf, primary, buf, val); + } } - *q = '\0'; sfree(buf); + + return TRUE; } /* * Write a set of name/value pairs in the above format. */ -static void wmap(void *handle, char const *key, char const *value, int len) +static void wmap(void *handle, char const *outkey, Conf *conf, int primary) { - char *buf = snewn(2*len, char), *p; - const char *q; + char *buf, *p, *q, *key, *realkey, *val; + int len; + + len = 1; /* allow for NUL */ + + for (val = conf_get_str_strs(conf, primary, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, primary, key, &key)) + len += 2 + 2 * (strlen(key) + strlen(val)); /* allow for escaping */ + + buf = snewn(len, char); p = buf; - q = value; - while (*q) { - while (*q) { - int c = *q++; - if (c == '=' || c == ',' || c == '\\') + + for (val = conf_get_str_strs(conf, primary, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, primary, key, &key)) { + + if (primary == CONF_portfwd && !strcmp(val, "D")) { + /* + * Backwards-compatibility hack, as above: translate from + * the sensible internal representation of dynamic + * forwardings (key "L", value "D") to the + * conceptually incoherent legacy storage format (key + * "D", value empty). + */ + realkey = key; /* restore it at end of loop */ + val = ""; + key = dupcat("D", key+1, NULL); + } else { + realkey = NULL; + } + + if (p != buf) + *p++ = ','; + for (q = key; *q; q++) { + if (*q == '=' || *q == ',' || *q == '\\') *p++ = '\\'; - if (c == '\t') - c = '='; - *p++ = c; + *p++ = *q; } - *p++ = ','; - q++; + *p++ = '='; + for (q = val; *q; q++) { + if (*q == '=' || *q == ',' || *q == '\\') + *p++ = '\\'; + *p++ = *q; + } + + if (realkey) { + free(key); + key = realkey; + } } *p = '\0'; - write_setting_s(handle, key, buf); + write_setting_s(handle, outkey, buf); sfree(buf); } @@ -214,9 +289,9 @@ static const char *val2key(const struct keyvalwhere *mapping, */ static void gprefs(void *sesskey, char *name, char *def, const struct keyvalwhere *mapping, int nvals, - int *array) + Conf *conf, int primary) { - char commalist[256]; + char *commalist; char *p, *q; int i, j, n, v, pos; unsigned long seen = 0; /* bitmap for weeding dups etc */ @@ -224,7 +299,7 @@ static void gprefs(void *sesskey, char *name, char *def, /* * Fetch the string which we'll parse as a comma-separated list. */ - gpps(sesskey, name, def, commalist, sizeof(commalist)); + commalist = gpps_raw(sesskey, name, def); /* * Go through that list and convert it into values. @@ -243,10 +318,13 @@ static void gprefs(void *sesskey, char *name, char *def, v = key2val(mapping, nvals, q); if (v != -1 && !(seen & (1 << v))) { seen |= (1 << v); - array[n++] = v; + conf_set_int_int(conf, primary, n, v); + n++; } } + sfree(commalist); + /* * Now go through 'mapping' and add values that weren't mentioned * in the list we fetched. We may have to loop over it multiple @@ -272,7 +350,8 @@ static void gprefs(void *sesskey, char *name, char *def, pos = (mapping[i].where < 0 ? n : 0); } else { for (j = 0; j < n; j++) - if (array[j] == mapping[i].vrel) + if (conf_get_int_int(conf, primary, j) == + mapping[i].vrel) break; assert(j < n); /* implied by (seen & (1<= pos; j--) - array[j+1] = array[j]; - array[pos] = mapping[i].v; + conf_set_int_int(conf, primary, j+1, + conf_get_int_int(conf, primary, j)); + conf_set_int_int(conf, primary, pos, mapping[i].v); n++; } } @@ -295,13 +375,14 @@ static void gprefs(void *sesskey, char *name, char *def, */ static void wprefs(void *sesskey, char *name, const struct keyvalwhere *mapping, int nvals, - int *array) + Conf *conf, int primary) { char *buf, *p; int i, maxlen; for (maxlen = i = 0; i < nvals; i++) { - const char *s = val2key(mapping, nvals, array[i]); + const char *s = val2key(mapping, nvals, + conf_get_int_int(conf, primary, i)); if (s) { maxlen += 1 + strlen(s); } @@ -311,7 +392,8 @@ static void wprefs(void *sesskey, char *name, p = buf; for (i = 0; i < nvals; i++) { - const char *s = val2key(mapping, nvals, array[i]); + const char *s = val2key(mapping, nvals, + conf_get_int_int(conf, primary, i)); if (s) { p += sprintf(p, "%s%s", (p > buf ? "," : ""), s); } @@ -324,7 +406,7 @@ static void wprefs(void *sesskey, char *name, sfree(buf); } -char *save_settings(char *section, Config * cfg) +char *save_settings(char *section, Conf *conf) { void *sesskey; char *errmsg; @@ -332,169 +414,169 @@ char *save_settings(char *section, Config * cfg) sesskey = open_settings_w(section, &errmsg); if (!sesskey) return errmsg; - save_open_settings(sesskey, cfg); + save_open_settings(sesskey, conf); close_settings_w(sesskey); return NULL; } -void save_open_settings(void *sesskey, Config *cfg) +void save_open_settings(void *sesskey, Conf *conf) { int i; char *p; write_setting_i(sesskey, "Present", 1); - write_setting_s(sesskey, "HostName", cfg->host); - write_setting_filename(sesskey, "LogFileName", cfg->logfilename); - write_setting_i(sesskey, "LogType", cfg->logtype); - write_setting_i(sesskey, "LogFileClash", cfg->logxfovr); - write_setting_i(sesskey, "LogFlush", cfg->logflush); - write_setting_i(sesskey, "SSHLogOmitPasswords", cfg->logomitpass); - write_setting_i(sesskey, "SSHLogOmitData", cfg->logomitdata); + write_setting_s(sesskey, "HostName", conf_get_str(conf, CONF_host)); + write_setting_filename(sesskey, "LogFileName", *conf_get_filename(conf, CONF_logfilename)); + write_setting_i(sesskey, "LogType", conf_get_int(conf, CONF_logtype)); + write_setting_i(sesskey, "LogFileClash", conf_get_int(conf, CONF_logxfovr)); + write_setting_i(sesskey, "LogFlush", conf_get_int(conf, CONF_logflush)); + write_setting_i(sesskey, "SSHLogOmitPasswords", conf_get_int(conf, CONF_logomitpass)); + write_setting_i(sesskey, "SSHLogOmitData", conf_get_int(conf, CONF_logomitdata)); p = "raw"; { - const Backend *b = backend_from_proto(cfg->protocol); + const Backend *b = backend_from_proto(conf_get_int(conf, CONF_protocol)); if (b) p = b->name; } write_setting_s(sesskey, "Protocol", p); - write_setting_i(sesskey, "PortNumber", cfg->port); + write_setting_i(sesskey, "PortNumber", conf_get_int(conf, CONF_port)); /* The CloseOnExit numbers are arranged in a different order from * the standard FORCE_ON / FORCE_OFF / AUTO. */ - write_setting_i(sesskey, "CloseOnExit", (cfg->close_on_exit+2)%3); - write_setting_i(sesskey, "WarnOnClose", !!cfg->warn_on_close); - write_setting_i(sesskey, "PingInterval", cfg->ping_interval / 60); /* minutes */ - write_setting_i(sesskey, "PingIntervalSecs", cfg->ping_interval % 60); /* seconds */ - write_setting_i(sesskey, "TCPNoDelay", cfg->tcp_nodelay); - write_setting_i(sesskey, "TCPKeepalives", cfg->tcp_keepalives); - write_setting_s(sesskey, "TerminalType", cfg->termtype); - write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed); - wmap(sesskey, "TerminalModes", cfg->ttymodes, lenof(cfg->ttymodes)); + write_setting_i(sesskey, "CloseOnExit", (conf_get_int(conf, CONF_close_on_exit)+2)%3); + write_setting_i(sesskey, "WarnOnClose", !!conf_get_int(conf, CONF_warn_on_close)); + write_setting_i(sesskey, "PingInterval", conf_get_int(conf, CONF_ping_interval) / 60); /* minutes */ + write_setting_i(sesskey, "PingIntervalSecs", conf_get_int(conf, CONF_ping_interval) % 60); /* seconds */ + write_setting_i(sesskey, "TCPNoDelay", conf_get_int(conf, CONF_tcp_nodelay)); + write_setting_i(sesskey, "TCPKeepalives", conf_get_int(conf, CONF_tcp_keepalives)); + write_setting_s(sesskey, "TerminalType", conf_get_str(conf, CONF_termtype)); + write_setting_s(sesskey, "TerminalSpeed", conf_get_str(conf, CONF_termspeed)); + wmap(sesskey, "TerminalModes", conf, CONF_ttymodes); /* Address family selection */ - write_setting_i(sesskey, "AddressFamily", cfg->addressfamily); + write_setting_i(sesskey, "AddressFamily", conf_get_int(conf, CONF_addressfamily)); /* proxy settings */ - write_setting_s(sesskey, "ProxyExcludeList", cfg->proxy_exclude_list); - write_setting_i(sesskey, "ProxyDNS", (cfg->proxy_dns+2)%3); - write_setting_i(sesskey, "ProxyLocalhost", cfg->even_proxy_localhost); - write_setting_i(sesskey, "ProxyMethod", cfg->proxy_type); - write_setting_s(sesskey, "ProxyHost", cfg->proxy_host); - write_setting_i(sesskey, "ProxyPort", cfg->proxy_port); - write_setting_s(sesskey, "ProxyUsername", cfg->proxy_username); - write_setting_s(sesskey, "ProxyPassword", cfg->proxy_password); - write_setting_s(sesskey, "ProxyTelnetCommand", cfg->proxy_telnet_command); - wmap(sesskey, "Environment", cfg->environmt, lenof(cfg->environmt)); - write_setting_s(sesskey, "UserName", cfg->username); - write_setting_i(sesskey, "UserNameFromEnvironment", cfg->username_from_env); - write_setting_s(sesskey, "LocalUserName", cfg->localusername); - write_setting_i(sesskey, "NoPTY", cfg->nopty); - write_setting_i(sesskey, "Compression", cfg->compression); - write_setting_i(sesskey, "TryAgent", cfg->tryagent); - write_setting_i(sesskey, "AgentFwd", cfg->agentfwd); - write_setting_i(sesskey, "GssapiFwd", cfg->gssapifwd); - write_setting_i(sesskey, "ChangeUsername", cfg->change_username); - wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX, - cfg->ssh_cipherlist); - wprefs(sesskey, "KEX", kexnames, KEX_MAX, cfg->ssh_kexlist); - write_setting_i(sesskey, "RekeyTime", cfg->ssh_rekey_time); - write_setting_s(sesskey, "RekeyBytes", cfg->ssh_rekey_data); - write_setting_i(sesskey, "SshNoAuth", cfg->ssh_no_userauth); - write_setting_i(sesskey, "SshBanner", cfg->ssh_show_banner); - write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth); - write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth); - write_setting_i(sesskey, "AuthGSSAPI", cfg->try_gssapi_auth); + write_setting_s(sesskey, "ProxyExcludeList", conf_get_str(conf, CONF_proxy_exclude_list)); + write_setting_i(sesskey, "ProxyDNS", (conf_get_int(conf, CONF_proxy_dns)+2)%3); + write_setting_i(sesskey, "ProxyLocalhost", conf_get_int(conf, CONF_even_proxy_localhost)); + write_setting_i(sesskey, "ProxyMethod", conf_get_int(conf, CONF_proxy_type)); + write_setting_s(sesskey, "ProxyHost", conf_get_str(conf, CONF_proxy_host)); + write_setting_i(sesskey, "ProxyPort", conf_get_int(conf, CONF_proxy_port)); + write_setting_s(sesskey, "ProxyUsername", conf_get_str(conf, CONF_proxy_username)); + write_setting_s(sesskey, "ProxyPassword", conf_get_str(conf, CONF_proxy_password)); + write_setting_s(sesskey, "ProxyTelnetCommand", conf_get_str(conf, CONF_proxy_telnet_command)); + wmap(sesskey, "Environment", conf, CONF_environmt); + write_setting_s(sesskey, "UserName", conf_get_str(conf, CONF_username)); + write_setting_i(sesskey, "UserNameFromEnvironment", conf_get_int(conf, CONF_username_from_env)); + write_setting_s(sesskey, "LocalUserName", conf_get_str(conf, CONF_localusername)); + write_setting_i(sesskey, "NoPTY", conf_get_int(conf, CONF_nopty)); + write_setting_i(sesskey, "Compression", conf_get_int(conf, CONF_compression)); + write_setting_i(sesskey, "TryAgent", conf_get_int(conf, CONF_tryagent)); + write_setting_i(sesskey, "AgentFwd", conf_get_int(conf, CONF_agentfwd)); + write_setting_i(sesskey, "GssapiFwd", conf_get_int(conf, CONF_gssapifwd)); + write_setting_i(sesskey, "ChangeUsername", conf_get_int(conf, CONF_change_username)); + wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist); + wprefs(sesskey, "KEX", kexnames, KEX_MAX, conf, CONF_ssh_kexlist); + write_setting_i(sesskey, "RekeyTime", conf_get_int(conf, CONF_ssh_rekey_time)); + write_setting_s(sesskey, "RekeyBytes", conf_get_str(conf, CONF_ssh_rekey_data)); + write_setting_i(sesskey, "SshNoAuth", conf_get_int(conf, CONF_ssh_no_userauth)); + write_setting_i(sesskey, "SshBanner", conf_get_int(conf, CONF_ssh_show_banner)); + write_setting_i(sesskey, "AuthTIS", conf_get_int(conf, CONF_try_tis_auth)); + write_setting_i(sesskey, "AuthKI", conf_get_int(conf, CONF_try_ki_auth)); + write_setting_i(sesskey, "AuthGSSAPI", conf_get_int(conf, CONF_try_gssapi_auth)); #ifndef NO_GSSAPI - wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs, - cfg->ssh_gsslist); - write_setting_filename(sesskey, "GSSCustom", cfg->ssh_gss_custom); + wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs, conf, CONF_ssh_gsslist); + write_setting_filename(sesskey, "GSSCustom", *conf_get_filename(conf, CONF_ssh_gss_custom)); #endif - write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell); - write_setting_i(sesskey, "SshProt", cfg->sshprot); - write_setting_s(sesskey, "LogHost", cfg->loghost); - write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc); - write_setting_filename(sesskey, "PublicKeyFile", cfg->keyfile); - write_setting_s(sesskey, "RemoteCommand", cfg->remote_cmd); - write_setting_i(sesskey, "RFCEnviron", cfg->rfc_environ); - write_setting_i(sesskey, "PassiveTelnet", cfg->passive_telnet); - write_setting_i(sesskey, "BackspaceIsDelete", cfg->bksp_is_delete); - write_setting_i(sesskey, "RXVTHomeEnd", cfg->rxvt_homeend); - write_setting_i(sesskey, "LinuxFunctionKeys", cfg->funky_type); - write_setting_i(sesskey, "NoApplicationKeys", cfg->no_applic_k); - write_setting_i(sesskey, "NoApplicationCursors", cfg->no_applic_c); - write_setting_i(sesskey, "NoMouseReporting", cfg->no_mouse_rep); - write_setting_i(sesskey, "NoRemoteResize", cfg->no_remote_resize); - write_setting_i(sesskey, "NoAltScreen", cfg->no_alt_screen); - write_setting_i(sesskey, "NoRemoteWinTitle", cfg->no_remote_wintitle); - write_setting_i(sesskey, "RemoteQTitleAction", cfg->remote_qtitle_action); - write_setting_i(sesskey, "NoDBackspace", cfg->no_dbackspace); - write_setting_i(sesskey, "NoRemoteCharset", cfg->no_remote_charset); - write_setting_i(sesskey, "ApplicationCursorKeys", cfg->app_cursor); - write_setting_i(sesskey, "ApplicationKeypad", cfg->app_keypad); - write_setting_i(sesskey, "NetHackKeypad", cfg->nethack_keypad); - write_setting_i(sesskey, "AltF4", cfg->alt_f4); - write_setting_i(sesskey, "AltSpace", cfg->alt_space); - write_setting_i(sesskey, "AltOnly", cfg->alt_only); - write_setting_i(sesskey, "ComposeKey", cfg->compose_key); - write_setting_i(sesskey, "CtrlAltKeys", cfg->ctrlaltkeys); - write_setting_i(sesskey, "TelnetKey", cfg->telnet_keyboard); - write_setting_i(sesskey, "TelnetRet", cfg->telnet_newline); - write_setting_i(sesskey, "LocalEcho", cfg->localecho); - write_setting_i(sesskey, "LocalEdit", cfg->localedit); - write_setting_s(sesskey, "Answerback", cfg->answerback); - write_setting_i(sesskey, "AlwaysOnTop", cfg->alwaysontop); - write_setting_i(sesskey, "FullScreenOnAltEnter", cfg->fullscreenonaltenter); - write_setting_i(sesskey, "HideMousePtr", cfg->hide_mouseptr); - write_setting_i(sesskey, "SunkenEdge", cfg->sunken_edge); - write_setting_i(sesskey, "WindowBorder", cfg->window_border); - write_setting_i(sesskey, "CurType", cfg->cursor_type); - write_setting_i(sesskey, "BlinkCur", cfg->blink_cur); - write_setting_i(sesskey, "Beep", cfg->beep); - write_setting_i(sesskey, "BeepInd", cfg->beep_ind); - write_setting_filename(sesskey, "BellWaveFile", cfg->bell_wavefile); - write_setting_i(sesskey, "BellOverload", cfg->bellovl); - write_setting_i(sesskey, "BellOverloadN", cfg->bellovl_n); - write_setting_i(sesskey, "BellOverloadT", cfg->bellovl_t + write_setting_i(sesskey, "SshNoShell", conf_get_int(conf, CONF_ssh_no_shell)); + write_setting_i(sesskey, "SshProt", conf_get_int(conf, CONF_sshprot)); + write_setting_s(sesskey, "LogHost", conf_get_str(conf, CONF_loghost)); + write_setting_i(sesskey, "SSH2DES", conf_get_int(conf, CONF_ssh2_des_cbc)); + write_setting_filename(sesskey, "PublicKeyFile", *conf_get_filename(conf, CONF_keyfile)); + write_setting_s(sesskey, "RemoteCommand", conf_get_str(conf, CONF_remote_cmd)); + write_setting_i(sesskey, "RFCEnviron", conf_get_int(conf, CONF_rfc_environ)); + write_setting_i(sesskey, "PassiveTelnet", conf_get_int(conf, CONF_passive_telnet)); + write_setting_i(sesskey, "BackspaceIsDelete", conf_get_int(conf, CONF_bksp_is_delete)); + write_setting_i(sesskey, "RXVTHomeEnd", conf_get_int(conf, CONF_rxvt_homeend)); + write_setting_i(sesskey, "LinuxFunctionKeys", conf_get_int(conf, CONF_funky_type)); + write_setting_i(sesskey, "NoApplicationKeys", conf_get_int(conf, CONF_no_applic_k)); + write_setting_i(sesskey, "NoApplicationCursors", conf_get_int(conf, CONF_no_applic_c)); + write_setting_i(sesskey, "NoMouseReporting", conf_get_int(conf, CONF_no_mouse_rep)); + write_setting_i(sesskey, "NoRemoteResize", conf_get_int(conf, CONF_no_remote_resize)); + write_setting_i(sesskey, "NoAltScreen", conf_get_int(conf, CONF_no_alt_screen)); + write_setting_i(sesskey, "NoRemoteWinTitle", conf_get_int(conf, CONF_no_remote_wintitle)); + write_setting_i(sesskey, "RemoteQTitleAction", conf_get_int(conf, CONF_remote_qtitle_action)); + write_setting_i(sesskey, "NoDBackspace", conf_get_int(conf, CONF_no_dbackspace)); + write_setting_i(sesskey, "NoRemoteCharset", conf_get_int(conf, CONF_no_remote_charset)); + write_setting_i(sesskey, "ApplicationCursorKeys", conf_get_int(conf, CONF_app_cursor)); + write_setting_i(sesskey, "ApplicationKeypad", conf_get_int(conf, CONF_app_keypad)); + write_setting_i(sesskey, "NetHackKeypad", conf_get_int(conf, CONF_nethack_keypad)); + write_setting_i(sesskey, "AltF4", conf_get_int(conf, CONF_alt_f4)); + write_setting_i(sesskey, "AltSpace", conf_get_int(conf, CONF_alt_space)); + write_setting_i(sesskey, "AltOnly", conf_get_int(conf, CONF_alt_only)); + write_setting_i(sesskey, "ComposeKey", conf_get_int(conf, CONF_compose_key)); + write_setting_i(sesskey, "CtrlAltKeys", conf_get_int(conf, CONF_ctrlaltkeys)); + write_setting_i(sesskey, "TelnetKey", conf_get_int(conf, CONF_telnet_keyboard)); + write_setting_i(sesskey, "TelnetRet", conf_get_int(conf, CONF_telnet_newline)); + write_setting_i(sesskey, "LocalEcho", conf_get_int(conf, CONF_localecho)); + write_setting_i(sesskey, "LocalEdit", conf_get_int(conf, CONF_localedit)); + write_setting_s(sesskey, "Answerback", conf_get_str(conf, CONF_answerback)); + write_setting_i(sesskey, "AlwaysOnTop", conf_get_int(conf, CONF_alwaysontop)); + write_setting_i(sesskey, "FullScreenOnAltEnter", conf_get_int(conf, CONF_fullscreenonaltenter)); + write_setting_i(sesskey, "HideMousePtr", conf_get_int(conf, CONF_hide_mouseptr)); + write_setting_i(sesskey, "SunkenEdge", conf_get_int(conf, CONF_sunken_edge)); + write_setting_i(sesskey, "WindowBorder", conf_get_int(conf, CONF_window_border)); + write_setting_i(sesskey, "CurType", conf_get_int(conf, CONF_cursor_type)); + write_setting_i(sesskey, "BlinkCur", conf_get_int(conf, CONF_blink_cur)); + write_setting_i(sesskey, "Beep", conf_get_int(conf, CONF_beep)); + write_setting_i(sesskey, "BeepInd", conf_get_int(conf, CONF_beep_ind)); + write_setting_filename(sesskey, "BellWaveFile", *conf_get_filename(conf, CONF_bell_wavefile)); + write_setting_i(sesskey, "BellOverload", conf_get_int(conf, CONF_bellovl)); + write_setting_i(sesskey, "BellOverloadN", conf_get_int(conf, CONF_bellovl_n)); + write_setting_i(sesskey, "BellOverloadT", conf_get_int(conf, CONF_bellovl_t) #ifdef PUTTY_UNIX_H * 1000 #endif ); - write_setting_i(sesskey, "BellOverloadS", cfg->bellovl_s + write_setting_i(sesskey, "BellOverloadS", conf_get_int(conf, CONF_bellovl_s) #ifdef PUTTY_UNIX_H * 1000 #endif ); - write_setting_i(sesskey, "ScrollbackLines", cfg->savelines); - write_setting_i(sesskey, "DECOriginMode", cfg->dec_om); - write_setting_i(sesskey, "AutoWrapMode", cfg->wrap_mode); - write_setting_i(sesskey, "LFImpliesCR", cfg->lfhascr); - write_setting_i(sesskey, "CRImpliesLF", cfg->crhaslf); - write_setting_i(sesskey, "DisableArabicShaping", cfg->arabicshaping); - write_setting_i(sesskey, "DisableBidi", cfg->bidi); - write_setting_i(sesskey, "WinNameAlways", cfg->win_name_always); - write_setting_s(sesskey, "WinTitle", cfg->wintitle); - write_setting_i(sesskey, "TermWidth", cfg->width); - write_setting_i(sesskey, "TermHeight", cfg->height); - write_setting_fontspec(sesskey, "Font", cfg->font); - write_setting_i(sesskey, "FontQuality", cfg->font_quality); - write_setting_i(sesskey, "FontVTMode", cfg->vtmode); - write_setting_i(sesskey, "UseSystemColours", cfg->system_colour); - write_setting_i(sesskey, "TryPalette", cfg->try_palette); - write_setting_i(sesskey, "ANSIColour", cfg->ansi_colour); - write_setting_i(sesskey, "Xterm256Colour", cfg->xterm_256_colour); - write_setting_i(sesskey, "BoldAsColour", cfg->bold_colour); + write_setting_i(sesskey, "ScrollbackLines", conf_get_int(conf, CONF_savelines)); + write_setting_i(sesskey, "DECOriginMode", conf_get_int(conf, CONF_dec_om)); + write_setting_i(sesskey, "AutoWrapMode", conf_get_int(conf, CONF_wrap_mode)); + write_setting_i(sesskey, "LFImpliesCR", conf_get_int(conf, CONF_lfhascr)); + write_setting_i(sesskey, "CRImpliesLF", conf_get_int(conf, CONF_crhaslf)); + write_setting_i(sesskey, "DisableArabicShaping", conf_get_int(conf, CONF_arabicshaping)); + write_setting_i(sesskey, "DisableBidi", conf_get_int(conf, CONF_bidi)); + write_setting_i(sesskey, "WinNameAlways", conf_get_int(conf, CONF_win_name_always)); + write_setting_s(sesskey, "WinTitle", conf_get_str(conf, CONF_wintitle)); + write_setting_i(sesskey, "TermWidth", conf_get_int(conf, CONF_width)); + write_setting_i(sesskey, "TermHeight", conf_get_int(conf, CONF_height)); + write_setting_fontspec(sesskey, "Font", *conf_get_fontspec(conf, CONF_font)); + write_setting_i(sesskey, "FontQuality", conf_get_int(conf, CONF_font_quality)); + write_setting_i(sesskey, "FontVTMode", conf_get_int(conf, CONF_vtmode)); + write_setting_i(sesskey, "UseSystemColours", conf_get_int(conf, CONF_system_colour)); + write_setting_i(sesskey, "TryPalette", conf_get_int(conf, CONF_try_palette)); + write_setting_i(sesskey, "ANSIColour", conf_get_int(conf, CONF_ansi_colour)); + write_setting_i(sesskey, "Xterm256Colour", conf_get_int(conf, CONF_xterm_256_colour)); + write_setting_i(sesskey, "BoldAsColour", conf_get_int(conf, CONF_bold_colour)); for (i = 0; i < 22; i++) { char buf[20], buf2[30]; sprintf(buf, "Colour%d", i); - sprintf(buf2, "%d,%d,%d", cfg->colours[i][0], - cfg->colours[i][1], cfg->colours[i][2]); + sprintf(buf2, "%d,%d,%d", + conf_get_int_int(conf, CONF_colours, i*3+0), + conf_get_int_int(conf, CONF_colours, i*3+1), + conf_get_int_int(conf, CONF_colours, i*3+2)); write_setting_s(sesskey, buf, buf2); } - write_setting_i(sesskey, "RawCNP", cfg->rawcnp); - write_setting_i(sesskey, "PasteRTF", cfg->rtf_paste); - write_setting_i(sesskey, "MouseIsXterm", cfg->mouse_is_xterm); - write_setting_i(sesskey, "RectSelect", cfg->rect_select); - write_setting_i(sesskey, "MouseOverride", cfg->mouse_override); + write_setting_i(sesskey, "RawCNP", conf_get_int(conf, CONF_rawcnp)); + write_setting_i(sesskey, "PasteRTF", conf_get_int(conf, CONF_rtf_paste)); + write_setting_i(sesskey, "MouseIsXterm", conf_get_int(conf, CONF_mouse_is_xterm)); + write_setting_i(sesskey, "RectSelect", conf_get_int(conf, CONF_rect_select)); + write_setting_i(sesskey, "MouseOverride", conf_get_int(conf, CONF_mouse_override)); for (i = 0; i < 256; i += 32) { char buf[20], buf2[256]; int j; @@ -502,305 +584,287 @@ void save_open_settings(void *sesskey, Config *cfg) *buf2 = '\0'; for (j = i; j < i + 32; j++) { sprintf(buf2 + strlen(buf2), "%s%d", - (*buf2 ? "," : ""), cfg->wordness[j]); + (*buf2 ? "," : ""), + conf_get_int_int(conf, CONF_wordness, j)); } write_setting_s(sesskey, buf, buf2); } - write_setting_s(sesskey, "LineCodePage", cfg->line_codepage); - write_setting_i(sesskey, "CJKAmbigWide", cfg->cjk_ambig_wide); - write_setting_i(sesskey, "UTF8Override", cfg->utf8_override); - write_setting_s(sesskey, "Printer", cfg->printer); - write_setting_i(sesskey, "CapsLockCyr", cfg->xlat_capslockcyr); - write_setting_i(sesskey, "ScrollBar", cfg->scrollbar); - write_setting_i(sesskey, "ScrollBarFullScreen", cfg->scrollbar_in_fullscreen); - write_setting_i(sesskey, "ScrollOnKey", cfg->scroll_on_key); - write_setting_i(sesskey, "ScrollOnDisp", cfg->scroll_on_disp); - write_setting_i(sesskey, "EraseToScrollback", cfg->erase_to_scrollback); - write_setting_i(sesskey, "LockSize", cfg->resize_action); - write_setting_i(sesskey, "BCE", cfg->bce); - write_setting_i(sesskey, "BlinkText", cfg->blinktext); - write_setting_i(sesskey, "X11Forward", cfg->x11_forward); - write_setting_s(sesskey, "X11Display", cfg->x11_display); - write_setting_i(sesskey, "X11AuthType", cfg->x11_auth); - write_setting_filename(sesskey, "X11AuthFile", cfg->xauthfile); - write_setting_i(sesskey, "LocalPortAcceptAll", cfg->lport_acceptall); - write_setting_i(sesskey, "RemotePortAcceptAll", cfg->rport_acceptall); - wmap(sesskey, "PortForwardings", cfg->portfwd, lenof(cfg->portfwd)); - write_setting_i(sesskey, "BugIgnore1", 2-cfg->sshbug_ignore1); - write_setting_i(sesskey, "BugPlainPW1", 2-cfg->sshbug_plainpw1); - write_setting_i(sesskey, "BugRSA1", 2-cfg->sshbug_rsa1); - write_setting_i(sesskey, "BugIgnore2", 2-cfg->sshbug_ignore2); - write_setting_i(sesskey, "BugHMAC2", 2-cfg->sshbug_hmac2); - write_setting_i(sesskey, "BugDeriveKey2", 2-cfg->sshbug_derivekey2); - write_setting_i(sesskey, "BugRSAPad2", 2-cfg->sshbug_rsapad2); - write_setting_i(sesskey, "BugPKSessID2", 2-cfg->sshbug_pksessid2); - write_setting_i(sesskey, "BugRekey2", 2-cfg->sshbug_rekey2); - write_setting_i(sesskey, "BugMaxPkt2", 2-cfg->sshbug_maxpkt2); - write_setting_i(sesskey, "StampUtmp", cfg->stamp_utmp); - write_setting_i(sesskey, "LoginShell", cfg->login_shell); - write_setting_i(sesskey, "ScrollbarOnLeft", cfg->scrollbar_on_left); - write_setting_fontspec(sesskey, "BoldFont", cfg->boldfont); - write_setting_fontspec(sesskey, "WideFont", cfg->widefont); - write_setting_fontspec(sesskey, "WideBoldFont", cfg->wideboldfont); - write_setting_i(sesskey, "ShadowBold", cfg->shadowbold); - write_setting_i(sesskey, "ShadowBoldOffset", cfg->shadowboldoffset); - write_setting_s(sesskey, "SerialLine", cfg->serline); - write_setting_i(sesskey, "SerialSpeed", cfg->serspeed); - write_setting_i(sesskey, "SerialDataBits", cfg->serdatabits); - write_setting_i(sesskey, "SerialStopHalfbits", cfg->serstopbits); - write_setting_i(sesskey, "SerialParity", cfg->serparity); - write_setting_i(sesskey, "SerialFlowControl", cfg->serflow); - write_setting_s(sesskey, "WindowClass", cfg->winclass); + write_setting_s(sesskey, "LineCodePage", conf_get_str(conf, CONF_line_codepage)); + write_setting_i(sesskey, "CJKAmbigWide", conf_get_int(conf, CONF_cjk_ambig_wide)); + write_setting_i(sesskey, "UTF8Override", conf_get_int(conf, CONF_utf8_override)); + write_setting_s(sesskey, "Printer", conf_get_str(conf, CONF_printer)); + write_setting_i(sesskey, "CapsLockCyr", conf_get_int(conf, CONF_xlat_capslockcyr)); + write_setting_i(sesskey, "ScrollBar", conf_get_int(conf, CONF_scrollbar)); + write_setting_i(sesskey, "ScrollBarFullScreen", conf_get_int(conf, CONF_scrollbar_in_fullscreen)); + write_setting_i(sesskey, "ScrollOnKey", conf_get_int(conf, CONF_scroll_on_key)); + write_setting_i(sesskey, "ScrollOnDisp", conf_get_int(conf, CONF_scroll_on_disp)); + write_setting_i(sesskey, "EraseToScrollback", conf_get_int(conf, CONF_erase_to_scrollback)); + write_setting_i(sesskey, "LockSize", conf_get_int(conf, CONF_resize_action)); + write_setting_i(sesskey, "BCE", conf_get_int(conf, CONF_bce)); + write_setting_i(sesskey, "BlinkText", conf_get_int(conf, CONF_blinktext)); + write_setting_i(sesskey, "X11Forward", conf_get_int(conf, CONF_x11_forward)); + write_setting_s(sesskey, "X11Display", conf_get_str(conf, CONF_x11_display)); + write_setting_i(sesskey, "X11AuthType", conf_get_int(conf, CONF_x11_auth)); + write_setting_filename(sesskey, "X11AuthFile", *conf_get_filename(conf, CONF_xauthfile)); + write_setting_i(sesskey, "LocalPortAcceptAll", conf_get_int(conf, CONF_lport_acceptall)); + write_setting_i(sesskey, "RemotePortAcceptAll", conf_get_int(conf, CONF_rport_acceptall)); + wmap(sesskey, "PortForwardings", conf, CONF_portfwd); + write_setting_i(sesskey, "BugIgnore1", 2-conf_get_int(conf, CONF_sshbug_ignore1)); + write_setting_i(sesskey, "BugPlainPW1", 2-conf_get_int(conf, CONF_sshbug_plainpw1)); + write_setting_i(sesskey, "BugRSA1", 2-conf_get_int(conf, CONF_sshbug_rsa1)); + write_setting_i(sesskey, "BugIgnore2", 2-conf_get_int(conf, CONF_sshbug_ignore2)); + write_setting_i(sesskey, "BugHMAC2", 2-conf_get_int(conf, CONF_sshbug_hmac2)); + write_setting_i(sesskey, "BugDeriveKey2", 2-conf_get_int(conf, CONF_sshbug_derivekey2)); + write_setting_i(sesskey, "BugRSAPad2", 2-conf_get_int(conf, CONF_sshbug_rsapad2)); + write_setting_i(sesskey, "BugPKSessID2", 2-conf_get_int(conf, CONF_sshbug_pksessid2)); + write_setting_i(sesskey, "BugRekey2", 2-conf_get_int(conf, CONF_sshbug_rekey2)); + write_setting_i(sesskey, "BugMaxPkt2", 2-conf_get_int(conf, CONF_sshbug_maxpkt2)); + write_setting_i(sesskey, "StampUtmp", conf_get_int(conf, CONF_stamp_utmp)); + write_setting_i(sesskey, "LoginShell", conf_get_int(conf, CONF_login_shell)); + write_setting_i(sesskey, "ScrollbarOnLeft", conf_get_int(conf, CONF_scrollbar_on_left)); + write_setting_fontspec(sesskey, "BoldFont", *conf_get_fontspec(conf, CONF_boldfont)); + write_setting_fontspec(sesskey, "WideFont", *conf_get_fontspec(conf, CONF_widefont)); + write_setting_fontspec(sesskey, "WideBoldFont", *conf_get_fontspec(conf, CONF_wideboldfont)); + write_setting_i(sesskey, "ShadowBold", conf_get_int(conf, CONF_shadowbold)); + write_setting_i(sesskey, "ShadowBoldOffset", conf_get_int(conf, CONF_shadowboldoffset)); + write_setting_s(sesskey, "SerialLine", conf_get_str(conf, CONF_serline)); + write_setting_i(sesskey, "SerialSpeed", conf_get_int(conf, CONF_serspeed)); + write_setting_i(sesskey, "SerialDataBits", conf_get_int(conf, CONF_serdatabits)); + write_setting_i(sesskey, "SerialStopHalfbits", conf_get_int(conf, CONF_serstopbits)); + write_setting_i(sesskey, "SerialParity", conf_get_int(conf, CONF_serparity)); + write_setting_i(sesskey, "SerialFlowControl", conf_get_int(conf, CONF_serflow)); + write_setting_s(sesskey, "WindowClass", conf_get_str(conf, CONF_winclass)); } -void load_settings(char *section, Config * cfg) +void load_settings(char *section, Conf *conf) { void *sesskey; sesskey = open_settings_r(section); - load_open_settings(sesskey, cfg); + load_open_settings(sesskey, conf); close_settings_r(sesskey); - if (cfg_launchable(cfg)) + if (conf_launchable(conf)) add_session_to_jumplist(section); } -void load_open_settings(void *sesskey, Config *cfg) +void load_open_settings(void *sesskey, Conf *conf) { int i; - char prot[10]; + char *prot; - cfg->ssh_subsys = 0; /* FIXME: load this properly */ - cfg->remote_cmd_ptr = NULL; - cfg->remote_cmd_ptr2 = NULL; - cfg->ssh_nc_host[0] = '\0'; + conf_set_int(conf, CONF_ssh_subsys, 0); /* FIXME: load this properly */ + conf_set_str(conf, CONF_remote_cmd, ""); + conf_set_str(conf, CONF_remote_cmd2, ""); + conf_set_str(conf, CONF_ssh_nc_host, ""); - gpps(sesskey, "HostName", "", cfg->host, sizeof(cfg->host)); - gppfile(sesskey, "LogFileName", &cfg->logfilename); - gppi(sesskey, "LogType", 0, &cfg->logtype); - gppi(sesskey, "LogFileClash", LGXF_ASK, &cfg->logxfovr); - gppi(sesskey, "LogFlush", 1, &cfg->logflush); - gppi(sesskey, "SSHLogOmitPasswords", 1, &cfg->logomitpass); - gppi(sesskey, "SSHLogOmitData", 0, &cfg->logomitdata); + gpps(sesskey, "HostName", "", conf, CONF_host); + gppfile(sesskey, "LogFileName", conf, CONF_logfilename); + gppi(sesskey, "LogType", 0, conf, CONF_logtype); + gppi(sesskey, "LogFileClash", LGXF_ASK, conf, CONF_logxfovr); + gppi(sesskey, "LogFlush", 1, conf, CONF_logflush); + gppi(sesskey, "SSHLogOmitPasswords", 1, conf, CONF_logomitpass); + gppi(sesskey, "SSHLogOmitData", 0, conf, CONF_logomitdata); - gpps(sesskey, "Protocol", "default", prot, 10); - cfg->protocol = default_protocol; - cfg->port = default_port; + prot = gpps_raw(sesskey, "Protocol", "default"); + conf_set_int(conf, CONF_protocol, default_protocol); + conf_set_int(conf, CONF_port, default_port); { const Backend *b = backend_from_name(prot); if (b) { - cfg->protocol = b->protocol; - gppi(sesskey, "PortNumber", default_port, &cfg->port); + conf_set_int(conf, CONF_protocol, b->protocol); + gppi(sesskey, "PortNumber", default_port, conf, CONF_port); } } + sfree(prot); /* Address family selection */ - gppi(sesskey, "AddressFamily", ADDRTYPE_UNSPEC, &cfg->addressfamily); + gppi(sesskey, "AddressFamily", ADDRTYPE_UNSPEC, conf, CONF_addressfamily); /* The CloseOnExit numbers are arranged in a different order from * the standard FORCE_ON / FORCE_OFF / AUTO. */ - gppi(sesskey, "CloseOnExit", 1, &i); cfg->close_on_exit = (i+1)%3; - gppi(sesskey, "WarnOnClose", 1, &cfg->warn_on_close); + i = gppi_raw(sesskey, "CloseOnExit", 1); conf_set_int(conf, CONF_close_on_exit, (i+1)%3); + gppi(sesskey, "WarnOnClose", 1, conf, CONF_warn_on_close); { /* This is two values for backward compatibility with 0.50/0.51 */ int pingmin, pingsec; - gppi(sesskey, "PingInterval", 0, &pingmin); - gppi(sesskey, "PingIntervalSecs", 0, &pingsec); - cfg->ping_interval = pingmin * 60 + pingsec; + pingmin = gppi_raw(sesskey, "PingInterval", 0); + pingsec = gppi_raw(sesskey, "PingIntervalSecs", 0); + conf_set_int(conf, CONF_ping_interval, pingmin * 60 + pingsec); } - gppi(sesskey, "TCPNoDelay", 1, &cfg->tcp_nodelay); - gppi(sesskey, "TCPKeepalives", 0, &cfg->tcp_keepalives); - gpps(sesskey, "TerminalType", "xterm", cfg->termtype, - sizeof(cfg->termtype)); - gpps(sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed, - sizeof(cfg->termspeed)); - { + gppi(sesskey, "TCPNoDelay", 1, conf, CONF_tcp_nodelay); + gppi(sesskey, "TCPKeepalives", 0, conf, CONF_tcp_keepalives); + gpps(sesskey, "TerminalType", "xterm", conf, CONF_termtype); + gpps(sesskey, "TerminalSpeed", "38400,38400", conf, CONF_termspeed); + if (!gppmap(sesskey, "TerminalModes", conf, CONF_ttymodes)) { /* This hardcodes a big set of defaults in any new saved * sessions. Let's hope we don't change our mind. */ - int i; - char *def = dupstr(""); - /* Default: all set to "auto" */ - for (i = 0; ttymodes[i]; i++) { - char *def2 = dupprintf("%s%s=A,", def, ttymodes[i]); - sfree(def); - def = def2; - } - gppmap(sesskey, "TerminalModes", def, - cfg->ttymodes, lenof(cfg->ttymodes)); - sfree(def); + for (i = 0; ttymodes[i]; i++) + conf_set_str_str(conf, CONF_ttymodes, ttymodes[i], "A"); } /* proxy settings */ - gpps(sesskey, "ProxyExcludeList", "", cfg->proxy_exclude_list, - sizeof(cfg->proxy_exclude_list)); - gppi(sesskey, "ProxyDNS", 1, &i); cfg->proxy_dns = (i+1)%3; - gppi(sesskey, "ProxyLocalhost", 0, &cfg->even_proxy_localhost); - gppi(sesskey, "ProxyMethod", -1, &cfg->proxy_type); - if (cfg->proxy_type == -1) { + gpps(sesskey, "ProxyExcludeList", "", conf, CONF_proxy_exclude_list); + i = gppi_raw(sesskey, "ProxyDNS", 1); conf_set_int(conf, CONF_proxy_dns, (i+1)%3); + gppi(sesskey, "ProxyLocalhost", 0, conf, CONF_even_proxy_localhost); + gppi(sesskey, "ProxyMethod", -1, conf, CONF_proxy_type); + if (conf_get_int(conf, CONF_proxy_type) == -1) { int i; - gppi(sesskey, "ProxyType", 0, &i); + i = gppi_raw(sesskey, "ProxyType", 0); if (i == 0) - cfg->proxy_type = PROXY_NONE; + conf_set_int(conf, CONF_proxy_type, PROXY_NONE); else if (i == 1) - cfg->proxy_type = PROXY_HTTP; + conf_set_int(conf, CONF_proxy_type, PROXY_HTTP); else if (i == 3) - cfg->proxy_type = PROXY_TELNET; + conf_set_int(conf, CONF_proxy_type, PROXY_TELNET); else if (i == 4) - cfg->proxy_type = PROXY_CMD; + conf_set_int(conf, CONF_proxy_type, PROXY_CMD); else { - gppi(sesskey, "ProxySOCKSVersion", 5, &i); + i = gppi_raw(sesskey, "ProxySOCKSVersion", 5); if (i == 5) - cfg->proxy_type = PROXY_SOCKS5; + conf_set_int(conf, CONF_proxy_type, PROXY_SOCKS5); else - cfg->proxy_type = PROXY_SOCKS4; + conf_set_int(conf, CONF_proxy_type, PROXY_SOCKS4); } } - gpps(sesskey, "ProxyHost", "proxy", cfg->proxy_host, - sizeof(cfg->proxy_host)); - gppi(sesskey, "ProxyPort", 80, &cfg->proxy_port); - gpps(sesskey, "ProxyUsername", "", cfg->proxy_username, - sizeof(cfg->proxy_username)); - gpps(sesskey, "ProxyPassword", "", cfg->proxy_password, - sizeof(cfg->proxy_password)); + gpps(sesskey, "ProxyHost", "proxy", conf, CONF_proxy_host); + gppi(sesskey, "ProxyPort", 80, conf, CONF_proxy_port); + gpps(sesskey, "ProxyUsername", "", conf, CONF_proxy_username); + gpps(sesskey, "ProxyPassword", "", conf, CONF_proxy_password); gpps(sesskey, "ProxyTelnetCommand", "connect %host %port\\n", - cfg->proxy_telnet_command, sizeof(cfg->proxy_telnet_command)); - gppmap(sesskey, "Environment", "", cfg->environmt, lenof(cfg->environmt)); - gpps(sesskey, "UserName", "", cfg->username, sizeof(cfg->username)); - gppi(sesskey, "UserNameFromEnvironment", 0, &cfg->username_from_env); - gpps(sesskey, "LocalUserName", "", cfg->localusername, - sizeof(cfg->localusername)); - gppi(sesskey, "NoPTY", 0, &cfg->nopty); - gppi(sesskey, "Compression", 0, &cfg->compression); - gppi(sesskey, "TryAgent", 1, &cfg->tryagent); - gppi(sesskey, "AgentFwd", 0, &cfg->agentfwd); - gppi(sesskey, "ChangeUsername", 0, &cfg->change_username); - gppi(sesskey, "GssapiFwd", 0, &cfg->gssapifwd); + conf, CONF_proxy_telnet_command); + gppmap(sesskey, "Environment", conf, CONF_environmt); + gpps(sesskey, "UserName", "", conf, CONF_username); + gppi(sesskey, "UserNameFromEnvironment", 0, conf, CONF_username_from_env); + gpps(sesskey, "LocalUserName", "", conf, CONF_localusername); + gppi(sesskey, "NoPTY", 0, conf, CONF_nopty); + gppi(sesskey, "Compression", 0, conf, CONF_compression); + gppi(sesskey, "TryAgent", 1, conf, CONF_tryagent); + gppi(sesskey, "AgentFwd", 0, conf, CONF_agentfwd); + gppi(sesskey, "ChangeUsername", 0, conf, CONF_change_username); + gppi(sesskey, "GssapiFwd", 0, conf, CONF_gssapifwd); gprefs(sesskey, "Cipher", "\0", - ciphernames, CIPHER_MAX, cfg->ssh_cipherlist); + ciphernames, CIPHER_MAX, conf, CONF_ssh_cipherlist); { /* Backward-compatibility: we used to have an option to * disable gex under the "bugs" panel after one report of * a server which offered it then choked, but we never got * a server version string or any other reports. */ char *default_kexes; - gppi(sesskey, "BugDHGEx2", 0, &i); i = 2-i; + i = 2 - gppi_raw(sesskey, "BugDHGEx2", 0); if (i == FORCE_ON) default_kexes = "dh-group14-sha1,dh-group1-sha1,rsa,WARN,dh-gex-sha1"; else default_kexes = "dh-gex-sha1,dh-group14-sha1,dh-group1-sha1,rsa,WARN"; gprefs(sesskey, "KEX", default_kexes, - kexnames, KEX_MAX, cfg->ssh_kexlist); + kexnames, KEX_MAX, conf, CONF_ssh_kexlist); } - gppi(sesskey, "RekeyTime", 60, &cfg->ssh_rekey_time); - gpps(sesskey, "RekeyBytes", "1G", cfg->ssh_rekey_data, - sizeof(cfg->ssh_rekey_data)); - gppi(sesskey, "SshProt", 2, &cfg->sshprot); - gpps(sesskey, "LogHost", "", cfg->loghost, sizeof(cfg->loghost)); - gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc); - gppi(sesskey, "SshNoAuth", 0, &cfg->ssh_no_userauth); - gppi(sesskey, "SshBanner", 1, &cfg->ssh_show_banner); - gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth); - gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth); - gppi(sesskey, "AuthGSSAPI", 1, &cfg->try_gssapi_auth); + gppi(sesskey, "RekeyTime", 60, conf, CONF_ssh_rekey_time); + gpps(sesskey, "RekeyBytes", "1G", conf, CONF_ssh_rekey_data); + gppi(sesskey, "SshProt", 2, conf, CONF_sshprot); + gpps(sesskey, "LogHost", "", conf, CONF_loghost); + gppi(sesskey, "SSH2DES", 0, conf, CONF_ssh2_des_cbc); + gppi(sesskey, "SshNoAuth", 0, conf, CONF_ssh_no_userauth); + gppi(sesskey, "SshBanner", 1, conf, CONF_ssh_show_banner); + gppi(sesskey, "AuthTIS", 0, conf, CONF_try_tis_auth); + gppi(sesskey, "AuthKI", 1, conf, CONF_try_ki_auth); + gppi(sesskey, "AuthGSSAPI", 1, conf, CONF_try_gssapi_auth); #ifndef NO_GSSAPI gprefs(sesskey, "GSSLibs", "\0", - gsslibkeywords, ngsslibs, cfg->ssh_gsslist); - gppfile(sesskey, "GSSCustom", &cfg->ssh_gss_custom); + gsslibkeywords, ngsslibs, conf, CONF_ssh_gsslist); + gppfile(sesskey, "GSSCustom", conf, CONF_ssh_gss_custom); #endif - gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell); - gppfile(sesskey, "PublicKeyFile", &cfg->keyfile); - gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd, - sizeof(cfg->remote_cmd)); - gppi(sesskey, "RFCEnviron", 0, &cfg->rfc_environ); - gppi(sesskey, "PassiveTelnet", 0, &cfg->passive_telnet); - gppi(sesskey, "BackspaceIsDelete", 1, &cfg->bksp_is_delete); - gppi(sesskey, "RXVTHomeEnd", 0, &cfg->rxvt_homeend); - gppi(sesskey, "LinuxFunctionKeys", 0, &cfg->funky_type); - gppi(sesskey, "NoApplicationKeys", 0, &cfg->no_applic_k); - gppi(sesskey, "NoApplicationCursors", 0, &cfg->no_applic_c); - gppi(sesskey, "NoMouseReporting", 0, &cfg->no_mouse_rep); - gppi(sesskey, "NoRemoteResize", 0, &cfg->no_remote_resize); - gppi(sesskey, "NoAltScreen", 0, &cfg->no_alt_screen); - gppi(sesskey, "NoRemoteWinTitle", 0, &cfg->no_remote_wintitle); + gppi(sesskey, "SshNoShell", 0, conf, CONF_ssh_no_shell); + gppfile(sesskey, "PublicKeyFile", conf, CONF_keyfile); + gpps(sesskey, "RemoteCommand", "", conf, CONF_remote_cmd); + gppi(sesskey, "RFCEnviron", 0, conf, CONF_rfc_environ); + gppi(sesskey, "PassiveTelnet", 0, conf, CONF_passive_telnet); + gppi(sesskey, "BackspaceIsDelete", 1, conf, CONF_bksp_is_delete); + gppi(sesskey, "RXVTHomeEnd", 0, conf, CONF_rxvt_homeend); + gppi(sesskey, "LinuxFunctionKeys", 0, conf, CONF_funky_type); + gppi(sesskey, "NoApplicationKeys", 0, conf, CONF_no_applic_k); + gppi(sesskey, "NoApplicationCursors", 0, conf, CONF_no_applic_c); + gppi(sesskey, "NoMouseReporting", 0, conf, CONF_no_mouse_rep); + gppi(sesskey, "NoRemoteResize", 0, conf, CONF_no_remote_resize); + gppi(sesskey, "NoAltScreen", 0, conf, CONF_no_alt_screen); + gppi(sesskey, "NoRemoteWinTitle", 0, conf, CONF_no_remote_wintitle); { /* Backward compatibility */ - int no_remote_qtitle; - gppi(sesskey, "NoRemoteQTitle", 1, &no_remote_qtitle); + int no_remote_qtitle = gppi_raw(sesskey, "NoRemoteQTitle", 1); /* We deliberately interpret the old setting of "no response" as * "empty string". This changes the behaviour, but hopefully for * the better; the user can always recover the old behaviour. */ gppi(sesskey, "RemoteQTitleAction", no_remote_qtitle ? TITLE_EMPTY : TITLE_REAL, - &cfg->remote_qtitle_action); + conf, CONF_remote_qtitle_action); } - gppi(sesskey, "NoDBackspace", 0, &cfg->no_dbackspace); - gppi(sesskey, "NoRemoteCharset", 0, &cfg->no_remote_charset); - gppi(sesskey, "ApplicationCursorKeys", 0, &cfg->app_cursor); - gppi(sesskey, "ApplicationKeypad", 0, &cfg->app_keypad); - gppi(sesskey, "NetHackKeypad", 0, &cfg->nethack_keypad); - gppi(sesskey, "AltF4", 1, &cfg->alt_f4); - gppi(sesskey, "AltSpace", 0, &cfg->alt_space); - gppi(sesskey, "AltOnly", 0, &cfg->alt_only); - gppi(sesskey, "ComposeKey", 0, &cfg->compose_key); - gppi(sesskey, "CtrlAltKeys", 1, &cfg->ctrlaltkeys); - gppi(sesskey, "TelnetKey", 0, &cfg->telnet_keyboard); - gppi(sesskey, "TelnetRet", 1, &cfg->telnet_newline); - gppi(sesskey, "LocalEcho", AUTO, &cfg->localecho); - gppi(sesskey, "LocalEdit", AUTO, &cfg->localedit); - gpps(sesskey, "Answerback", "PuTTY", cfg->answerback, - sizeof(cfg->answerback)); - gppi(sesskey, "AlwaysOnTop", 0, &cfg->alwaysontop); - gppi(sesskey, "FullScreenOnAltEnter", 0, &cfg->fullscreenonaltenter); - gppi(sesskey, "HideMousePtr", 0, &cfg->hide_mouseptr); - gppi(sesskey, "SunkenEdge", 0, &cfg->sunken_edge); - gppi(sesskey, "WindowBorder", 1, &cfg->window_border); - gppi(sesskey, "CurType", 0, &cfg->cursor_type); - gppi(sesskey, "BlinkCur", 0, &cfg->blink_cur); - /* pedantic compiler tells me I can't use &cfg->beep as an int * :-) */ - gppi(sesskey, "Beep", 1, &cfg->beep); - gppi(sesskey, "BeepInd", 0, &cfg->beep_ind); - gppfile(sesskey, "BellWaveFile", &cfg->bell_wavefile); - gppi(sesskey, "BellOverload", 1, &cfg->bellovl); - gppi(sesskey, "BellOverloadN", 5, &cfg->bellovl_n); - gppi(sesskey, "BellOverloadT", 2*TICKSPERSEC + gppi(sesskey, "NoDBackspace", 0, conf, CONF_no_dbackspace); + gppi(sesskey, "NoRemoteCharset", 0, conf, CONF_no_remote_charset); + gppi(sesskey, "ApplicationCursorKeys", 0, conf, CONF_app_cursor); + gppi(sesskey, "ApplicationKeypad", 0, conf, CONF_app_keypad); + gppi(sesskey, "NetHackKeypad", 0, conf, CONF_nethack_keypad); + gppi(sesskey, "AltF4", 1, conf, CONF_alt_f4); + gppi(sesskey, "AltSpace", 0, conf, CONF_alt_space); + gppi(sesskey, "AltOnly", 0, conf, CONF_alt_only); + gppi(sesskey, "ComposeKey", 0, conf, CONF_compose_key); + gppi(sesskey, "CtrlAltKeys", 1, conf, CONF_ctrlaltkeys); + gppi(sesskey, "TelnetKey", 0, conf, CONF_telnet_keyboard); + gppi(sesskey, "TelnetRet", 1, conf, CONF_telnet_newline); + gppi(sesskey, "LocalEcho", AUTO, conf, CONF_localecho); + gppi(sesskey, "LocalEdit", AUTO, conf, CONF_localedit); + gpps(sesskey, "Answerback", "PuTTY", conf, CONF_answerback); + gppi(sesskey, "AlwaysOnTop", 0, conf, CONF_alwaysontop); + gppi(sesskey, "FullScreenOnAltEnter", 0, conf, CONF_fullscreenonaltenter); + gppi(sesskey, "HideMousePtr", 0, conf, CONF_hide_mouseptr); + gppi(sesskey, "SunkenEdge", 0, conf, CONF_sunken_edge); + gppi(sesskey, "WindowBorder", 1, conf, CONF_window_border); + gppi(sesskey, "CurType", 0, conf, CONF_cursor_type); + gppi(sesskey, "BlinkCur", 0, conf, CONF_blink_cur); + /* pedantic compiler tells me I can't use conf, CONF_beep as an int * :-) */ + gppi(sesskey, "Beep", 1, conf, CONF_beep); + gppi(sesskey, "BeepInd", 0, conf, CONF_beep_ind); + gppfile(sesskey, "BellWaveFile", conf, CONF_bell_wavefile); + gppi(sesskey, "BellOverload", 1, conf, CONF_bellovl); + gppi(sesskey, "BellOverloadN", 5, conf, CONF_bellovl_n); + i = gppi_raw(sesskey, "BellOverloadT", 2*TICKSPERSEC #ifdef PUTTY_UNIX_H *1000 #endif - , &i); - cfg->bellovl_t = i + ); + conf_set_int(conf, CONF_bellovl_t, i #ifdef PUTTY_UNIX_H - / 1000 + / 1000 #endif - ; - gppi(sesskey, "BellOverloadS", 5*TICKSPERSEC + ); + i = gppi_raw(sesskey, "BellOverloadS", 5*TICKSPERSEC #ifdef PUTTY_UNIX_H *1000 #endif - , &i); - cfg->bellovl_s = i + ); + conf_set_int(conf, CONF_bellovl_s, i #ifdef PUTTY_UNIX_H - / 1000 + / 1000 #endif - ; - gppi(sesskey, "ScrollbackLines", 200, &cfg->savelines); - gppi(sesskey, "DECOriginMode", 0, &cfg->dec_om); - gppi(sesskey, "AutoWrapMode", 1, &cfg->wrap_mode); - gppi(sesskey, "LFImpliesCR", 0, &cfg->lfhascr); - gppi(sesskey, "CRImpliesLF", 0, &cfg->crhaslf); - gppi(sesskey, "DisableArabicShaping", 0, &cfg->arabicshaping); - gppi(sesskey, "DisableBidi", 0, &cfg->bidi); - gppi(sesskey, "WinNameAlways", 1, &cfg->win_name_always); - gpps(sesskey, "WinTitle", "", cfg->wintitle, sizeof(cfg->wintitle)); - gppi(sesskey, "TermWidth", 80, &cfg->width); - gppi(sesskey, "TermHeight", 24, &cfg->height); - gppfont(sesskey, "Font", &cfg->font); - gppi(sesskey, "FontQuality", FQ_DEFAULT, &cfg->font_quality); - gppi(sesskey, "FontVTMode", VT_UNICODE, (int *) &cfg->vtmode); - gppi(sesskey, "UseSystemColours", 0, &cfg->system_colour); - gppi(sesskey, "TryPalette", 0, &cfg->try_palette); - gppi(sesskey, "ANSIColour", 1, &cfg->ansi_colour); - gppi(sesskey, "Xterm256Colour", 1, &cfg->xterm_256_colour); - gppi(sesskey, "BoldAsColour", 1, &cfg->bold_colour); + ); + gppi(sesskey, "ScrollbackLines", 200, conf, CONF_savelines); + gppi(sesskey, "DECOriginMode", 0, conf, CONF_dec_om); + gppi(sesskey, "AutoWrapMode", 1, conf, CONF_wrap_mode); + gppi(sesskey, "LFImpliesCR", 0, conf, CONF_lfhascr); + gppi(sesskey, "CRImpliesLF", 0, conf, CONF_crhaslf); + gppi(sesskey, "DisableArabicShaping", 0, conf, CONF_arabicshaping); + gppi(sesskey, "DisableBidi", 0, conf, CONF_bidi); + gppi(sesskey, "WinNameAlways", 1, conf, CONF_win_name_always); + gpps(sesskey, "WinTitle", "", conf, CONF_wintitle); + gppi(sesskey, "TermWidth", 80, conf, CONF_width); + gppi(sesskey, "TermHeight", 24, conf, CONF_height); + gppfont(sesskey, "Font", conf, CONF_font); + gppi(sesskey, "FontQuality", FQ_DEFAULT, conf, CONF_font_quality); + gppi(sesskey, "FontVTMode", VT_UNICODE, conf, CONF_vtmode); + gppi(sesskey, "UseSystemColours", 0, conf, CONF_system_colour); + gppi(sesskey, "TryPalette", 0, conf, CONF_try_palette); + gppi(sesskey, "ANSIColour", 1, conf, CONF_ansi_colour); + gppi(sesskey, "Xterm256Colour", 1, conf, CONF_xterm_256_colour); + gppi(sesskey, "BoldAsColour", 1, conf, CONF_bold_colour); for (i = 0; i < 22; i++) { static const char *const defaults[] = { @@ -810,21 +874,22 @@ void load_open_settings(void *sesskey, Config *cfg) "85,85,255", "187,0,187", "255,85,255", "0,187,187", "85,255,255", "187,187,187", "255,255,255" }; - char buf[20], buf2[30]; + char buf[20], *buf2; int c0, c1, c2; sprintf(buf, "Colour%d", i); - gpps(sesskey, buf, defaults[i], buf2, sizeof(buf2)); + buf2 = gpps_raw(sesskey, buf, defaults[i]); if (sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) { - cfg->colours[i][0] = c0; - cfg->colours[i][1] = c1; - cfg->colours[i][2] = c2; + conf_set_int_int(conf, CONF_colours, i*3+0, c0); + conf_set_int_int(conf, CONF_colours, i*3+1, c1); + conf_set_int_int(conf, CONF_colours, i*3+2, c2); } + sfree(buf2); } - gppi(sesskey, "RawCNP", 0, &cfg->rawcnp); - gppi(sesskey, "PasteRTF", 0, &cfg->rtf_paste); - gppi(sesskey, "MouseIsXterm", 0, &cfg->mouse_is_xterm); - gppi(sesskey, "RectSelect", 0, &cfg->rect_select); - gppi(sesskey, "MouseOverride", 1, &cfg->mouse_override); + gppi(sesskey, "RawCNP", 0, conf, CONF_rawcnp); + gppi(sesskey, "PasteRTF", 0, conf, CONF_rtf_paste); + gppi(sesskey, "MouseIsXterm", 0, conf, CONF_mouse_is_xterm); + gppi(sesskey, "RectSelect", 0, conf, CONF_rect_select); + gppi(sesskey, "MouseOverride", 1, conf, CONF_mouse_override); for (i = 0; i < 256; i += 32) { static const char *const defaults[] = { "0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0", @@ -836,10 +901,10 @@ void load_open_settings(void *sesskey, Config *cfg) "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2", "2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2" }; - char buf[20], buf2[256], *p; + char buf[20], *buf2, *p; int j; sprintf(buf, "Wordness%d", i); - gpps(sesskey, buf, defaults[i / 32], buf2, sizeof(buf2)); + buf2 = gpps_raw(sesskey, buf, defaults[i / 32]); p = buf2; for (j = i; j < i + 32; j++) { char *q = p; @@ -847,75 +912,74 @@ void load_open_settings(void *sesskey, Config *cfg) p++; if (*p == ',') *p++ = '\0'; - cfg->wordness[j] = atoi(q); + conf_set_int_int(conf, CONF_wordness, j, atoi(q)); } + sfree(buf2); } /* * The empty default for LineCodePage will be converted later * into a plausible default for the locale. */ - gpps(sesskey, "LineCodePage", "", cfg->line_codepage, - sizeof(cfg->line_codepage)); - gppi(sesskey, "CJKAmbigWide", 0, &cfg->cjk_ambig_wide); - gppi(sesskey, "UTF8Override", 1, &cfg->utf8_override); - gpps(sesskey, "Printer", "", cfg->printer, sizeof(cfg->printer)); - gppi (sesskey, "CapsLockCyr", 0, &cfg->xlat_capslockcyr); - gppi(sesskey, "ScrollBar", 1, &cfg->scrollbar); - gppi(sesskey, "ScrollBarFullScreen", 0, &cfg->scrollbar_in_fullscreen); - gppi(sesskey, "ScrollOnKey", 0, &cfg->scroll_on_key); - gppi(sesskey, "ScrollOnDisp", 1, &cfg->scroll_on_disp); - gppi(sesskey, "EraseToScrollback", 1, &cfg->erase_to_scrollback); - gppi(sesskey, "LockSize", 0, &cfg->resize_action); - gppi(sesskey, "BCE", 1, &cfg->bce); - gppi(sesskey, "BlinkText", 0, &cfg->blinktext); - gppi(sesskey, "X11Forward", 0, &cfg->x11_forward); - gpps(sesskey, "X11Display", "", cfg->x11_display, - sizeof(cfg->x11_display)); - gppi(sesskey, "X11AuthType", X11_MIT, &cfg->x11_auth); - gppfile(sesskey, "X11AuthFile", &cfg->xauthfile); + gpps(sesskey, "LineCodePage", "", conf, CONF_line_codepage); + gppi(sesskey, "CJKAmbigWide", 0, conf, CONF_cjk_ambig_wide); + gppi(sesskey, "UTF8Override", 1, conf, CONF_utf8_override); + gpps(sesskey, "Printer", "", conf, CONF_printer); + gppi(sesskey, "CapsLockCyr", 0, conf, CONF_xlat_capslockcyr); + gppi(sesskey, "ScrollBar", 1, conf, CONF_scrollbar); + gppi(sesskey, "ScrollBarFullScreen", 0, conf, CONF_scrollbar_in_fullscreen); + gppi(sesskey, "ScrollOnKey", 0, conf, CONF_scroll_on_key); + gppi(sesskey, "ScrollOnDisp", 1, conf, CONF_scroll_on_disp); + gppi(sesskey, "EraseToScrollback", 1, conf, CONF_erase_to_scrollback); + gppi(sesskey, "LockSize", 0, conf, CONF_resize_action); + gppi(sesskey, "BCE", 1, conf, CONF_bce); + gppi(sesskey, "BlinkText", 0, conf, CONF_blinktext); + gppi(sesskey, "X11Forward", 0, conf, CONF_x11_forward); + gpps(sesskey, "X11Display", "", conf, CONF_x11_display); + gppi(sesskey, "X11AuthType", X11_MIT, conf, CONF_x11_auth); + gppfile(sesskey, "X11AuthFile", conf, CONF_xauthfile); - gppi(sesskey, "LocalPortAcceptAll", 0, &cfg->lport_acceptall); - gppi(sesskey, "RemotePortAcceptAll", 0, &cfg->rport_acceptall); - gppmap(sesskey, "PortForwardings", "", cfg->portfwd, lenof(cfg->portfwd)); - gppi(sesskey, "BugIgnore1", 0, &i); cfg->sshbug_ignore1 = 2-i; - gppi(sesskey, "BugPlainPW1", 0, &i); cfg->sshbug_plainpw1 = 2-i; - gppi(sesskey, "BugRSA1", 0, &i); cfg->sshbug_rsa1 = 2-i; - gppi(sesskey, "BugIgnore2", 0, &i); cfg->sshbug_ignore2 = 2-i; + gppi(sesskey, "LocalPortAcceptAll", 0, conf, CONF_lport_acceptall); + gppi(sesskey, "RemotePortAcceptAll", 0, conf, CONF_rport_acceptall); + gppmap(sesskey, "PortForwardings", conf, CONF_portfwd); + i = gppi_raw(sesskey, "BugIgnore1", 0); conf_set_int(conf, CONF_sshbug_ignore1, 2-i); + i = gppi_raw(sesskey, "BugPlainPW1", 0); conf_set_int(conf, CONF_sshbug_plainpw1, 2-i); + i = gppi_raw(sesskey, "BugRSA1", 0); conf_set_int(conf, CONF_sshbug_rsa1, 2-i); + i = gppi_raw(sesskey, "BugIgnore2", 0); conf_set_int(conf, CONF_sshbug_ignore2, 2-i); { int i; - gppi(sesskey, "BugHMAC2", 0, &i); cfg->sshbug_hmac2 = 2-i; - if (cfg->sshbug_hmac2 == AUTO) { - gppi(sesskey, "BuggyMAC", 0, &i); + i = gppi_raw(sesskey, "BugHMAC2", 0); conf_set_int(conf, CONF_sshbug_hmac2, 2-i); + if (2-i == AUTO) { + i = gppi_raw(sesskey, "BuggyMAC", 0); if (i == 1) - cfg->sshbug_hmac2 = FORCE_ON; + conf_set_int(conf, CONF_sshbug_hmac2, FORCE_ON); } } - gppi(sesskey, "BugDeriveKey2", 0, &i); cfg->sshbug_derivekey2 = 2-i; - gppi(sesskey, "BugRSAPad2", 0, &i); cfg->sshbug_rsapad2 = 2-i; - gppi(sesskey, "BugPKSessID2", 0, &i); cfg->sshbug_pksessid2 = 2-i; - gppi(sesskey, "BugRekey2", 0, &i); cfg->sshbug_rekey2 = 2-i; - gppi(sesskey, "BugMaxPkt2", 0, &i); cfg->sshbug_maxpkt2 = 2-i; - cfg->ssh_simple = FALSE; - gppi(sesskey, "StampUtmp", 1, &cfg->stamp_utmp); - gppi(sesskey, "LoginShell", 1, &cfg->login_shell); - gppi(sesskey, "ScrollbarOnLeft", 0, &cfg->scrollbar_on_left); - gppi(sesskey, "ShadowBold", 0, &cfg->shadowbold); - gppfont(sesskey, "BoldFont", &cfg->boldfont); - gppfont(sesskey, "WideFont", &cfg->widefont); - gppfont(sesskey, "WideBoldFont", &cfg->wideboldfont); - gppi(sesskey, "ShadowBoldOffset", 1, &cfg->shadowboldoffset); - gpps(sesskey, "SerialLine", "", cfg->serline, sizeof(cfg->serline)); - gppi(sesskey, "SerialSpeed", 9600, &cfg->serspeed); - gppi(sesskey, "SerialDataBits", 8, &cfg->serdatabits); - gppi(sesskey, "SerialStopHalfbits", 2, &cfg->serstopbits); - gppi(sesskey, "SerialParity", SER_PAR_NONE, &cfg->serparity); - gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, &cfg->serflow); - gpps(sesskey, "WindowClass", "", cfg->winclass, sizeof(cfg->winclass)); + i = gppi_raw(sesskey, "BugDeriveKey2", 0); conf_set_int(conf, CONF_sshbug_derivekey2, 2-i); + i = gppi_raw(sesskey, "BugRSAPad2", 0); conf_set_int(conf, CONF_sshbug_rsapad2, 2-i); + i = gppi_raw(sesskey, "BugPKSessID2", 0); conf_set_int(conf, CONF_sshbug_pksessid2, 2-i); + i = gppi_raw(sesskey, "BugRekey2", 0); conf_set_int(conf, CONF_sshbug_rekey2, 2-i); + i = gppi_raw(sesskey, "BugMaxPkt2", 0); conf_set_int(conf, CONF_sshbug_maxpkt2, 2-i); + conf_set_int(conf, CONF_ssh_simple, FALSE); + gppi(sesskey, "StampUtmp", 1, conf, CONF_stamp_utmp); + gppi(sesskey, "LoginShell", 1, conf, CONF_login_shell); + gppi(sesskey, "ScrollbarOnLeft", 0, conf, CONF_scrollbar_on_left); + gppi(sesskey, "ShadowBold", 0, conf, CONF_shadowbold); + gppfont(sesskey, "BoldFont", conf, CONF_boldfont); + gppfont(sesskey, "WideFont", conf, CONF_widefont); + gppfont(sesskey, "WideBoldFont", conf, CONF_wideboldfont); + gppi(sesskey, "ShadowBoldOffset", 1, conf, CONF_shadowboldoffset); + gpps(sesskey, "SerialLine", "", conf, CONF_serline); + gppi(sesskey, "SerialSpeed", 9600, conf, CONF_serspeed); + gppi(sesskey, "SerialDataBits", 8, conf, CONF_serdatabits); + gppi(sesskey, "SerialStopHalfbits", 2, conf, CONF_serstopbits); + gppi(sesskey, "SerialParity", SER_PAR_NONE, conf, CONF_serparity); + gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, conf, CONF_serflow); + gpps(sesskey, "WindowClass", "", conf, CONF_winclass); } -void do_defaults(char *session, Config * cfg) +void do_defaults(char *session, Conf *conf) { - load_settings(session, cfg); + load_settings(session, conf); } static int sessioncmp(const void *av, const void *bv) diff --git a/ssh.c b/ssh.c index 017b48bf..e3b8a334 100644 --- a/ssh.c +++ b/ssh.c @@ -884,12 +884,26 @@ struct ssh_tag { struct Packet *(*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen); /* - * We maintain a full _copy_ of a Config structure here, not - * merely a pointer to it. That way, when we're passed a new - * one for reconfiguration, we can check the differences and - * potentially reconfigure port forwardings etc in mid-session. + * We maintain our own copy of a Conf structure here. That way, + * when we're passed a new one for reconfiguration, we can check + * the differences and potentially reconfigure port forwardings + * etc in mid-session. */ - Config cfg; + Conf *conf; + + /* + * Values cached out of conf so as to avoid the tree234 lookup + * cost every time they're used. + */ + int logomitdata; + + /* + * Dynamically allocated username string created during SSH + * login. Stored in here rather than in the coroutine state so + * that it'll be reliably freed if we shut down the SSH session + * at some unexpected moment. + */ + char *username; /* * Used to transfer data back from async callbacks. @@ -978,13 +992,13 @@ static void logeventf(Ssh ssh, const char *fmt, ...) static void dont_log_password(Ssh ssh, struct Packet *pkt, int blanktype) { - if (ssh->cfg.logomitpass) + if (conf_get_int(ssh->conf, CONF_logomitpass)) pkt->logmode = blanktype; } static void dont_log_data(Ssh ssh, struct Packet *pkt, int blanktype) { - if (ssh->cfg.logomitdata) + if (ssh->logomitdata) pkt->logmode = blanktype; } @@ -993,26 +1007,27 @@ static void end_log_omission(Ssh ssh, struct Packet *pkt) pkt->logmode = PKTLOG_EMIT; } -/* Helper function for common bits of parsing cfg.ttymodes. */ -static void parse_ttymodes(Ssh ssh, char *modes, +/* Helper function for common bits of parsing ttymodes. */ +static void parse_ttymodes(Ssh ssh, void (*do_mode)(void *data, char *mode, char *val), void *data) { - while (*modes) { - char *t = strchr(modes, '\t'); - char *m = snewn(t-modes+1, char); - char *val; - strncpy(m, modes, t-modes); - m[t-modes] = '\0'; - if (*(t+1) == 'A') - val = get_ttymode(ssh->frontend, m); + char *key, *val; + + for (val = conf_get_str_strs(ssh->conf, CONF_ttymodes, NULL, &key); + val != NULL; + val = conf_get_str_strs(ssh->conf, CONF_ttymodes, key, &key)) { + /* + * val[0] is either 'V', indicating that an explicit value + * follows it, or 'A' indicating that we should pass the + * value through from the local environment via get_ttymode. + */ + if (val[0] == 'A') + val = get_ttymode(ssh->frontend, key); else - val = dupstr(t+2); + val++; /* skip the 'V' */ if (val) - do_mode(data, m, val); - sfree(m); - sfree(val); - modes += strlen(modes) + 1; + do_mode(data, key, val); } } @@ -1300,7 +1315,7 @@ static struct Packet *ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) if (ssh->logctx) { int nblanks = 0; struct logblank_t blank; - if (ssh->cfg.logomitdata) { + if (ssh->logomitdata) { int do_blank = FALSE, blank_prefix = 0; /* "Session data" packets - omit the data field */ if ((st->pktin->type == SSH1_SMSG_STDOUT_DATA) || @@ -1533,7 +1548,7 @@ static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) if (ssh->logctx) { int nblanks = 0; struct logblank_t blank; - if (ssh->cfg.logomitdata) { + if (ssh->logomitdata) { int do_blank = FALSE, blank_prefix = 0; /* "Session data" packets - omit the data field */ if (st->pktin->type == SSH2_MSG_CHANNEL_DATA) { @@ -2417,8 +2432,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) * with SSH1_MSG_IGNOREs -- but this string never seems to change, * so we can't distinguish them. */ - if (ssh->cfg.sshbug_ignore1 == FORCE_ON || - (ssh->cfg.sshbug_ignore1 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_ignore1) == AUTO && (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") || !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") || !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") || @@ -2432,8 +2447,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH-1 ignore bug"); } - if (ssh->cfg.sshbug_plainpw1 == FORCE_ON || - (ssh->cfg.sshbug_plainpw1 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_plainpw1) == AUTO && (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) { /* * These versions need a plain password sent; they can't @@ -2444,8 +2459,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version needs a plain SSH-1 password"); } - if (ssh->cfg.sshbug_rsa1 == FORCE_ON || - (ssh->cfg.sshbug_rsa1 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_rsa1) == AUTO && (!strcmp(imp, "Cisco-1.25")))) { /* * These versions apparently have no clue whatever about @@ -2456,8 +2471,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version can't handle SSH-1 RSA authentication"); } - if (ssh->cfg.sshbug_hmac2 == FORCE_ON || - (ssh->cfg.sshbug_hmac2 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_hmac2) == AUTO && !wc_match("* VShell", imp) && (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) || wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) || @@ -2469,8 +2484,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH-2 HMAC bug"); } - if (ssh->cfg.sshbug_derivekey2 == FORCE_ON || - (ssh->cfg.sshbug_derivekey2 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_derivekey2) == AUTO && !wc_match("* VShell", imp) && (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) { /* @@ -2482,8 +2497,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH-2 key-derivation bug"); } - if (ssh->cfg.sshbug_rsapad2 == FORCE_ON || - (ssh->cfg.sshbug_rsapad2 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_rsapad2) == AUTO && (wc_match("OpenSSH_2.[5-9]*", imp) || wc_match("OpenSSH_3.[0-2]*", imp)))) { /* @@ -2493,8 +2508,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH-2 RSA padding bug"); } - if (ssh->cfg.sshbug_pksessid2 == FORCE_ON || - (ssh->cfg.sshbug_pksessid2 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_pksessid2) == AUTO && wc_match("OpenSSH_2.[0-2]*", imp))) { /* * These versions have the SSH-2 session-ID bug in @@ -2504,8 +2519,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH-2 public-key-session-ID bug"); } - if (ssh->cfg.sshbug_rekey2 == FORCE_ON || - (ssh->cfg.sshbug_rekey2 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_rekey2) == AUTO && (wc_match("DigiSSH_2.0", imp) || wc_match("OpenSSH_2.[0-4]*", imp) || wc_match("OpenSSH_2.5.[0-3]*", imp) || @@ -2520,8 +2535,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version has SSH-2 rekey bug"); } - if (ssh->cfg.sshbug_maxpkt2 == FORCE_ON || - (ssh->cfg.sshbug_maxpkt2 == AUTO && + if (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == FORCE_ON || + (conf_get_int(ssh->conf, CONF_sshbug_maxpkt2) == AUTO && (wc_match("1.36_sshlib GlobalSCAPE", imp) || wc_match("1.36 sshlib: GlobalScape", imp)))) { /* @@ -2531,7 +2546,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) logevent("We believe remote version ignores SSH-2 maximum packet size"); } - if (ssh->cfg.sshbug_ignore2 == FORCE_ON) { + if (conf_get_int(ssh->conf, CONF_sshbug_ignore2) == FORCE_ON) { /* * Servers that don't support SSH2_MSG_IGNORE. Currently, * none detected automatically. @@ -2674,16 +2689,16 @@ static int do_ssh_init(Ssh ssh, unsigned char c) /* Anything greater or equal to "1.99" means protocol 2 is supported. */ s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0; - if (ssh->cfg.sshprot == 0 && !s->proto1) { + if (conf_get_int(ssh->conf, CONF_sshprot) == 0 && !s->proto1) { bombout(("SSH protocol version 1 required by user but not provided by server")); crStop(0); } - if (ssh->cfg.sshprot == 3 && !s->proto2) { + if (conf_get_int(ssh->conf, CONF_sshprot) == 3 && !s->proto2) { bombout(("SSH protocol version 2 required by user but not provided by server")); crStop(0); } - if (s->proto2 && (ssh->cfg.sshprot >= 2 || !s->proto1)) + if (s->proto2 && (conf_get_int(ssh->conf, CONF_sshprot) >= 2 || !s->proto1)) ssh->version = 2; else ssh->version = 1; @@ -2691,7 +2706,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c) logeventf(ssh, "Using SSH protocol version %d", ssh->version); /* Send the version string, if we haven't already */ - if (ssh->cfg.sshprot != 3) + if (conf_get_int(ssh->conf, CONF_sshprot) != 3) ssh_send_verstring(ssh, s->version); if (ssh->version == 2) { @@ -2723,7 +2738,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c) update_specials_menu(ssh->frontend); ssh->state = SSH_STATE_BEFORE_SIZE; - ssh->pinger = pinger_new(&ssh->cfg, &ssh_backend, ssh); + ssh->pinger = pinger_new(ssh->conf, &ssh_backend, ssh); sfree(s->vstring); @@ -2976,11 +2991,14 @@ static const char *connect_to_host(Ssh ssh, char *host, int port, SockAddr addr; const char *err; - - if (*ssh->cfg.loghost) { + char *loghost; + int addressfamily, sshprot; + + loghost = conf_get_str(ssh->conf, CONF_loghost); + if (*loghost) { char *colon; - ssh->savedhost = dupstr(ssh->cfg.loghost); + ssh->savedhost = dupstr(loghost); ssh->savedport = 22; /* default ssh port */ /* @@ -3005,11 +3023,11 @@ static const char *connect_to_host(Ssh ssh, char *host, int port, /* * Try to find host. */ + addressfamily = conf_get_int(ssh->conf, CONF_addressfamily); logeventf(ssh, "Looking up host \"%s\"%s", host, - (ssh->cfg.addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : - (ssh->cfg.addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); - addr = name_lookup(host, port, realhost, &ssh->cfg, - ssh->cfg.addressfamily); + (addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : + (addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); + addr = name_lookup(host, port, realhost, ssh->conf, addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -3021,7 +3039,7 @@ static const char *connect_to_host(Ssh ssh, char *host, int port, */ ssh->fn = &fn_table; ssh->s = new_connection(addr, *realhost, port, - 0, 1, nodelay, keepalive, (Plug) ssh, &ssh->cfg); + 0, 1, nodelay, keepalive, (Plug) ssh, ssh->conf); if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; notify_remote_exit(ssh->frontend); @@ -3032,9 +3050,10 @@ static const char *connect_to_host(Ssh ssh, char *host, int port, * If the SSH version number's fixed, set it now, and if it's SSH-2, * send the version string too. */ - if (ssh->cfg.sshprot == 0) + sshprot = conf_get_int(ssh->conf, CONF_sshprot); + if (sshprot == 0) ssh->version = 1; - if (ssh->cfg.sshprot == 3) { + if (sshprot == 3) { ssh->version = 2; ssh_send_verstring(ssh, NULL); } @@ -3042,9 +3061,9 @@ static const char *connect_to_host(Ssh ssh, char *host, int port, /* * loghost, if configured, overrides realhost. */ - if (*ssh->cfg.loghost) { + if (*loghost) { sfree(*realhost); - *realhost = dupstr(ssh->cfg.loghost); + *realhost = dupstr(loghost); } return NULL; @@ -3209,7 +3228,6 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int tis_auth_refused, ccard_auth_refused; unsigned char session_id[16]; int cipher_type; - char username[100]; void *publickey_blob; int publickey_bloblen; char *publickey_comment; @@ -3226,6 +3244,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, char *commentp; int commentlen; int dlgret; + Filename *keyfile; }; crState(do_ssh1_login_state); @@ -3365,7 +3384,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, char *cipher_string = NULL; int i; for (i = 0; !cipher_chosen && i < CIPHER_MAX; i++) { - int next_cipher = ssh->cfg.ssh_cipherlist[i]; + int next_cipher = conf_get_int_int(ssh->conf, + CONF_ssh_cipherlist, i); if (next_cipher == CIPHER_WARN) { /* If/when we choose a cipher, warn about it */ warn = 1; @@ -3480,14 +3500,13 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, fflush(stdout); /* FIXME eh? */ { - if (!get_remote_username(&ssh->cfg, s->username, - sizeof(s->username))) { + if ((ssh->username = get_remote_username(ssh->conf)) == NULL) { int ret; /* need not be kept over crReturn */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH login name"); - add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, - lenof(s->username)); + /* 512 is an arbitrary upper limit on username size */ + add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, 512); ret = get_userpass_input(s->cur_prompt, NULL, 0); while (ret < 0) { ssh->send_ok = 1; @@ -3503,14 +3522,13 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE); crStop(0); } - memcpy(s->username, s->cur_prompt->prompts[0]->result, - lenof(s->username)); + ssh->username = dupstr(s->cur_prompt->prompts[0]->result); free_prompts(s->cur_prompt); } - send_packet(ssh, SSH1_CMSG_USER, PKT_STR, s->username, PKT_END); + send_packet(ssh, SSH1_CMSG_USER, PKT_STR, ssh->username, PKT_END); { - char *userlog = dupprintf("Sent username \"%s\"", s->username); + char *userlog = dupprintf("Sent username \"%s\"", ssh->username); logevent(userlog); if (flags & FLAG_INTERACTIVE && (!((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)))) { @@ -3533,24 +3551,25 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, /* * Load the public half of any configured keyfile for later use. */ - if (!filename_is_null(ssh->cfg.keyfile)) { + s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); + if (!filename_is_null(*s->keyfile)) { int keytype; logeventf(ssh, "Reading private key file \"%.150s\"", - filename_to_str(&ssh->cfg.keyfile)); - keytype = key_type(&ssh->cfg.keyfile); + filename_to_str(s->keyfile)); + keytype = key_type(s->keyfile); if (keytype == SSH_KEYTYPE_SSH1) { const char *error; - if (rsakey_pubblob(&ssh->cfg.keyfile, + if (rsakey_pubblob(s->keyfile, &s->publickey_blob, &s->publickey_bloblen, &s->publickey_comment, &error)) { - s->publickey_encrypted = rsakey_encrypted(&ssh->cfg.keyfile, + s->publickey_encrypted = rsakey_encrypted(s->keyfile, NULL); } else { char *msgbuf; logeventf(ssh, "Unable to load private key (%s)", error); msgbuf = dupprintf("Unable to load private key file " "\"%.150s\" (%s)\r\n", - filename_to_str(&ssh->cfg.keyfile), + filename_to_str(s->keyfile), error); c_write_str(ssh, msgbuf); sfree(msgbuf); @@ -3562,7 +3581,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, key_type_to_str(keytype)); msgbuf = dupprintf("Unable to use key file \"%.150s\"" " (%s)\r\n", - filename_to_str(&ssh->cfg.keyfile), + filename_to_str(s->keyfile), key_type_to_str(keytype)); c_write_str(ssh, msgbuf); sfree(msgbuf); @@ -3574,7 +3593,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, while (pktin->type == SSH1_SMSG_FAILURE) { s->pwpkt_type = SSH1_CMSG_AUTH_PASSWORD; - if (ssh->cfg.tryagent && agent_exists() && !s->tried_agent) { + if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists() && !s->tried_agent) { /* * Attempt RSA authentication using Pageant. */ @@ -3758,8 +3777,9 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int got_passphrase; /* need not be kept over crReturn */ if (flags & FLAG_VERBOSE) c_write_str(ssh, "Trying public key authentication.\r\n"); + s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); logeventf(ssh, "Trying public key \"%s\"", - filename_to_str(&ssh->cfg.keyfile)); + filename_to_str(s->keyfile)); s->tried_publickey = 1; got_passphrase = FALSE; while (!got_passphrase) { @@ -3801,7 +3821,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, /* * Try decrypting key with passphrase. */ - ret = loadrsakey(&ssh->cfg.keyfile, &s->key, passphrase, + s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); + ret = loadrsakey(s->keyfile, &s->key, passphrase, &error); if (passphrase) { memset(passphrase, 0, strlen(passphrase)); @@ -3812,7 +3833,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, got_passphrase = TRUE; } else if (ret == 0) { c_write_str(ssh, "Couldn't load private key from "); - c_write_str(ssh, filename_to_str(&ssh->cfg.keyfile)); + c_write_str(ssh, filename_to_str(s->keyfile)); c_write_str(ssh, " ("); c_write_str(ssh, error); c_write_str(ssh, ").\r\n"); @@ -3895,7 +3916,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, */ s->cur_prompt = new_prompts(ssh->frontend); - if (ssh->cfg.try_tis_auth && + if (conf_get_int(ssh->conf, CONF_try_tis_auth) && (s->supported_auths_mask & (1 << SSH1_AUTH_TIS)) && !s->tis_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE; @@ -3938,7 +3959,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, sfree(instr_suf); } } - if (ssh->cfg.try_tis_auth && + if (conf_get_int(ssh->conf, CONF_try_tis_auth) && (s->supported_auths_mask & (1 << SSH1_AUTH_CCARD)) && !s->ccard_auth_refused) { s->pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE; @@ -3988,8 +4009,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, } s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH password"); - add_prompt(s->cur_prompt, dupprintf("%.90s@%.90s's password: ", - s->username, ssh->savedhost), + add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", + ssh->username, ssh->savedhost), FALSE, SSH_MAX_PASSWORD_LEN); } @@ -4365,11 +4386,11 @@ static void ssh_rportfwd_succfail(Ssh ssh, struct Packet *pktin, void *ctx) } } -static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) +static void ssh_setup_portfwd(Ssh ssh, Conf *conf) { - const char *portfwd_strptr = cfg->portfwd; struct ssh_portfwd *epf; int i; + char *key, *val; if (!ssh->portfwds) { ssh->portfwds = newtree234(ssh_portcmp); @@ -4387,80 +4408,34 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) epf->status = DESTROY; } - while (*portfwd_strptr) { + for (val = conf_get_str_strs(conf, CONF_portfwd, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, CONF_portfwd, key, &key)) { + char *kp, *kp2, *vp, *vp2; char address_family, type; int sport,dport,sserv,dserv; - char sports[256], dports[256], saddr[256], host[256]; - int n; + char *sports, *dports, *saddr, *host; + + kp = key; address_family = 'A'; type = 'L'; - if (*portfwd_strptr == 'A' || - *portfwd_strptr == '4' || - *portfwd_strptr == '6') - address_family = *portfwd_strptr++; - if (*portfwd_strptr == 'L' || - *portfwd_strptr == 'R' || - *portfwd_strptr == 'D') - type = *portfwd_strptr++; + if (*kp == 'A' || *kp == '4' || *kp == '6') + address_family = *kp++; + if (*kp == 'L' || *kp == 'R') + type = *kp++; - saddr[0] = '\0'; - - n = 0; - while (*portfwd_strptr && *portfwd_strptr != '\t') { - if (*portfwd_strptr == ':') { - /* - * We've seen a colon in the middle of the - * source port number. This means that - * everything we've seen until now is the - * source _address_, so we'll move it into - * saddr and start sports from the beginning - * again. - */ - portfwd_strptr++; - sports[n] = '\0'; - if (ssh->version == 1 && type == 'R') { - logeventf(ssh, "SSH-1 cannot handle remote source address " - "spec \"%s\"; ignoring", sports); - } else - strcpy(saddr, sports); - n = 0; - } - if (n < lenof(sports)-1) sports[n++] = *portfwd_strptr++; - } - sports[n] = 0; - if (type != 'D') { - if (*portfwd_strptr == '\t') - portfwd_strptr++; - n = 0; - while (*portfwd_strptr && *portfwd_strptr != ':') { - if (n < lenof(host)-1) host[n++] = *portfwd_strptr++; - } - host[n] = 0; - if (*portfwd_strptr == ':') - portfwd_strptr++; - n = 0; - while (*portfwd_strptr) { - if (n < lenof(dports)-1) dports[n++] = *portfwd_strptr++; - } - dports[n] = 0; - portfwd_strptr++; - dport = atoi(dports); - dserv = 0; - if (dport == 0) { - dserv = 1; - dport = net_service_lookup(dports); - if (!dport) { - logeventf(ssh, "Service lookup failed for destination" - " port \"%s\"", dports); - } - } + if ((kp2 = strchr(kp, ':')) != NULL) { + /* + * There's a colon in the middle of the source port + * string, which means that the part before it is + * actually a source address. + */ + saddr = dupprintf("%.*s", (int)(kp2 - kp), kp); + sports = kp2+1; } else { - while (*portfwd_strptr) portfwd_strptr++; - host[0] = 0; - dports[0] = 0; - dport = dserv = -1; - portfwd_strptr++; /* eat the NUL and move to next one */ + saddr = NULL; + sports = kp; } sport = atoi(sports); sserv = 0; @@ -4472,16 +4447,44 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) " port \"%s\"", sports); } } + + if (type == 'L' && !strcmp(val, "D")) { + /* dynamic forwarding */ + host = NULL; + dports = NULL; + dport = -1; + dserv = 0; + type = 'D'; + } else { + /* ordinary forwarding */ + vp = val; + vp2 = vp + strcspn(vp, ":"); + host = dupprintf("%.*s", (int)(vp2 - vp), vp); + if (vp2) + vp2++; + dports = vp2; + dport = atoi(dports); + dserv = 0; + if (dport == 0) { + dserv = 1; + dport = net_service_lookup(dports); + if (!dport) { + logeventf(ssh, "Service lookup failed for destination" + " port \"%s\"", dports); + } + } + } + if (sport && dport) { /* Set up a description of the source port. */ struct ssh_portfwd *pfrec, *epfrec; pfrec = snew(struct ssh_portfwd); pfrec->type = type; - pfrec->saddr = *saddr ? dupstr(saddr) : NULL; + pfrec->saddr = saddr; pfrec->sserv = sserv ? dupstr(sports) : NULL; pfrec->sport = sport; - pfrec->daddr = *host ? dupstr(host) : NULL; + pfrec->daddr = host; pfrec->dserv = dserv ? dupstr(dports) : NULL; pfrec->dport = dport; pfrec->local = NULL; @@ -4509,6 +4512,9 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) } else { pfrec->status = CREATE; } + } else { + sfree(saddr); + sfree(host); } } @@ -4562,8 +4568,8 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) ssh2_pkt_addbool(pktout, 0);/* _don't_ want reply */ if (epf->saddr) { ssh2_pkt_addstring(pktout, epf->saddr); - } else if (ssh->cfg.rport_acceptall) { - /* XXX: ssh->cfg.rport_acceptall may not represent + } else if (conf_get_int(conf, CONF_rport_acceptall)) { + /* XXX: rport_acceptall may not represent * what was used to open the original connection, * since it's reconfigurable. */ ssh2_pkt_addstring(pktout, "0.0.0.0"); @@ -4612,7 +4618,7 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) if (epf->type == 'L') { const char *err = pfd_addforward(epf->daddr, epf->dport, epf->saddr, epf->sport, - ssh, cfg, + ssh, conf, &epf->local, epf->addressfamily); @@ -4624,7 +4630,7 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) } else if (epf->type == 'D') { const char *err = pfd_addforward(NULL, -1, epf->saddr, epf->sport, - ssh, cfg, + ssh, conf, &epf->local, epf->addressfamily); @@ -4680,7 +4686,7 @@ static void ssh_setup_portfwd(Ssh ssh, const Config *cfg) ssh2_pkt_addbool(pktout, 1);/* want reply */ if (epf->saddr) { ssh2_pkt_addstring(pktout, epf->saddr); - } else if (cfg->rport_acceptall) { + } else if (conf_get_int(conf, CONF_rport_acceptall)) { ssh2_pkt_addstring(pktout, "0.0.0.0"); } else { ssh2_pkt_addstring(pktout, "127.0.0.1"); @@ -4736,7 +4742,7 @@ static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin) c->ssh = ssh; if (x11_init(&c->u.x11.s, ssh->x11disp, c, - NULL, -1, &ssh->cfg) != NULL) { + NULL, -1, ssh->conf) != NULL) { logevent("Opening X11 forward connection failed"); sfree(c); send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_FAILURE, @@ -4822,7 +4828,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin) logeventf(ssh, "Received remote port open request for %s:%d", pf.dhost, port); e = pfd_newconnect(&c->u.pfd.s, pf.dhost, port, - c, &ssh->cfg, pfp->pfrec->addressfamily); + c, ssh->conf, pfp->pfrec->addressfamily); if (e != NULL) { logeventf(ssh, "Port open failed: %s", e); sfree(c); @@ -5054,7 +5060,7 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen, ssh->packet_dispatch[SSH1_MSG_CHANNEL_DATA] = ssh1_msg_channel_data; ssh->packet_dispatch[SSH1_SMSG_EXIT_STATUS] = ssh1_smsg_exit_status; - if (ssh->cfg.agentfwd && agent_exists()) { + if (conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists()) { logevent("Requesting agent forwarding"); send_packet(ssh, SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END); do { @@ -5073,9 +5079,9 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen, } } - if (ssh->cfg.x11_forward && - (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display, - ssh->cfg.x11_auth, &ssh->cfg))) { + if (conf_get_int(ssh->conf, CONF_x11_forward) && + (ssh->x11disp = x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display), + conf_get_int(ssh->conf, CONF_x11_auth), ssh->conf))) { logevent("Requesting X11 forwarding"); /* * Note that while we blank the X authentication data here, we don't @@ -5116,24 +5122,23 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen, } } - ssh_setup_portfwd(ssh, &ssh->cfg); + ssh_setup_portfwd(ssh, ssh->conf); ssh->packet_dispatch[SSH1_MSG_PORT_OPEN] = ssh1_msg_port_open; - if (!ssh->cfg.nopty) { + if (!conf_get_int(ssh->conf, CONF_nopty)) { struct Packet *pkt; /* Unpick the terminal-speed string. */ /* XXX perhaps we should allow no speeds to be sent. */ ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ - sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed); + sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed); /* Send the pty request. */ pkt = ssh1_pkt_init(SSH1_CMSG_REQUEST_PTY); - ssh_pkt_addstring(pkt, ssh->cfg.termtype); + ssh_pkt_addstring(pkt, conf_get_str(ssh->conf, CONF_termtype)); ssh_pkt_adduint32(pkt, ssh->term_height); ssh_pkt_adduint32(pkt, ssh->term_width); ssh_pkt_adduint32(pkt, 0); /* width in pixels */ ssh_pkt_adduint32(pkt, 0); /* height in pixels */ - parse_ttymodes(ssh, ssh->cfg.ttymodes, - ssh1_send_ttymode, (void *)pkt); + parse_ttymodes(ssh, ssh1_send_ttymode, (void *)pkt); ssh_pkt_addbyte(pkt, SSH1_TTY_OP_ISPEED); ssh_pkt_adduint32(pkt, ssh->ispeed); ssh_pkt_addbyte(pkt, SSH1_TTY_OP_OSPEED); @@ -5158,7 +5163,7 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen, ssh->editing = ssh->echoing = 1; } - if (ssh->cfg.compression) { + if (conf_get_int(ssh->conf, CONF_compression)) { send_packet(ssh, SSH1_CMSG_REQUEST_COMPRESSION, PKT_INT, 6, PKT_END); do { crReturnV; @@ -5186,12 +5191,11 @@ static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen, * exists, we fall straight back to that. */ { - char *cmd = ssh->cfg.remote_cmd_ptr; - - if (!cmd) cmd = ssh->cfg.remote_cmd; + char *cmd = conf_get_str(ssh->conf, CONF_remote_cmd); - if (ssh->cfg.ssh_subsys && ssh->cfg.remote_cmd_ptr2) { - cmd = ssh->cfg.remote_cmd_ptr2; + if (conf_get_int(ssh->conf, CONF_ssh_subsys) && + conf_get_str(ssh->conf, CONF_remote_cmd2)) { + cmd = conf_get_str(ssh->conf, CONF_remote_cmd2); ssh->fallback_cmd = TRUE; } if (*cmd) @@ -5462,7 +5466,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, */ s->n_preferred_kex = 0; for (i = 0; i < KEX_MAX; i++) { - switch (ssh->cfg.ssh_kexlist[i]) { + switch (conf_get_int_int(ssh->conf, CONF_ssh_kexlist, i)) { case KEX_DHGEX: s->preferred_kex[s->n_preferred_kex++] = &ssh_diffiehellman_gex; @@ -5494,12 +5498,12 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, */ s->n_preferred_ciphers = 0; for (i = 0; i < CIPHER_MAX; i++) { - switch (ssh->cfg.ssh_cipherlist[i]) { + switch (conf_get_int_int(ssh->conf, CONF_ssh_cipherlist, i)) { case CIPHER_BLOWFISH: s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_blowfish; break; case CIPHER_DES: - if (ssh->cfg.ssh2_des_cbc) { + if (conf_get_int(ssh->conf, CONF_ssh2_des_cbc)) { s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_des; } break; @@ -5525,7 +5529,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, /* * Set up preferred compression. */ - if (ssh->cfg.compression) + if (conf_get_int(ssh->conf, CONF_compression)) s->preferred_comp = &ssh_zlib; else s->preferred_comp = &ssh_comp_none; @@ -6321,8 +6325,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, */ ssh->kex_in_progress = FALSE; ssh->last_rekey = GETTICKCOUNT(); - if (ssh->cfg.ssh_rekey_time != 0) - ssh->next_rekey = schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC, + if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0) + ssh->next_rekey = schedule_timer(conf_get_int(ssh->conf, CONF_ssh_rekey_time)*60*TICKSPERSEC, ssh2_timer, ssh); /* @@ -6403,9 +6407,9 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen, * hit the event log _too_ often. */ ssh->outgoing_data_size = 0; ssh->incoming_data_size = 0; - if (ssh->cfg.ssh_rekey_time != 0) { + if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0) { ssh->next_rekey = - schedule_timer(ssh->cfg.ssh_rekey_time*60*TICKSPERSEC, + schedule_timer(conf_get_int(ssh->conf, CONF_ssh_rekey_time)*60*TICKSPERSEC, ssh2_timer, ssh); } goto wait_for_rekey; /* this is still utterly horrid */ @@ -6511,7 +6515,7 @@ static void ssh2_channel_init(struct ssh_channel *c) c->pending_close = FALSE; c->throttling_conn = FALSE; c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin = - ssh->cfg.ssh_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE; + conf_get_int(ssh->conf, CONF_ssh_simple) ? OUR_V2_BIGWIN : OUR_V2_WINSIZE; c->v.v2.winadj_head = c->v.v2.winadj_tail = NULL; c->v.v2.throttle_state = UNTHROTTLED; bufchain_init(&c->v.v2.outbuffer); @@ -6796,7 +6800,7 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin) * throttle the whole channel. */ if ((bufsize > c->v.v2.locmaxwin || - (ssh->cfg.ssh_simple && bufsize > 0)) && + (conf_get_int(ssh->conf, CONF_ssh_simple) && bufsize > 0)) && !c->throttling_conn) { c->throttling_conn = 1; ssh_throttle_conn(ssh, +1); @@ -6871,7 +6875,7 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) * (This is only our termination condition if we're * not running in -N mode.) */ - if (!ssh->cfg.ssh_no_shell && count234(ssh->channels) == 0) { + if (!conf_get_int(ssh->conf, CONF_ssh_no_shell) && count234(ssh->channels) == 0) { /* * We used to send SSH_MSG_DISCONNECT here, * because I'd believed that _every_ conforming @@ -7186,7 +7190,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) if (!ssh->X11_fwd_enabled) error = "X11 forwarding is not enabled"; else if ((x11err = x11_init(&c->u.x11.s, ssh->x11disp, c, - addrstr, peerport, &ssh->cfg)) != NULL) { + addrstr, peerport, ssh->conf)) != NULL) { logeventf(ssh, "Local X11 connection failed: %s", x11err); error = "Unable to open an X11 connection"; } else { @@ -7213,7 +7217,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) const char *e = pfd_newconnect(&c->u.pfd.s, realpf->dhost, realpf->dport, c, - &ssh->cfg, + ssh->conf, realpf->pfrec->addressfamily); logeventf(ssh, "Attempting to forward remote port to " "%s:%d", realpf->dhost, realpf->dport); @@ -7269,7 +7273,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin) static void ssh2_msg_userauth_banner(Ssh ssh, struct Packet *pktin) { /* Arbitrary limit to prevent unbounded inflation of buffer */ - if (ssh->cfg.ssh_show_banner && + if (conf_get_int(ssh->conf, CONF_ssh_show_banner) && bufchain_size(&ssh->banner) <= 131072) { char *banner = NULL; int size = 0; @@ -7327,7 +7331,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int we_are_in, userauth_success; prompts_t *cur_prompt; int num_prompts; - char username[100]; + char *username; char *password; int got_username; void *publickey_blob; @@ -7346,6 +7350,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int try_send; int num_env, env_left, env_ok; struct Packet *pktout; + Filename *keyfile; #ifndef NO_GSSAPI struct ssh_gss_library *gsslib; Ssh_gss_ctx gss_ctx; @@ -7365,7 +7370,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, s->tried_gssapi = FALSE; #endif - if (!ssh->cfg.ssh_no_userauth) { + if (!conf_get_int(ssh->conf, CONF_ssh_no_userauth)) { /* * Request userauth protocol, and await a response to it. */ @@ -7408,28 +7413,29 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * Load the public half of any configured public key file * for later use. */ - if (!filename_is_null(ssh->cfg.keyfile)) { + s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); + if (!filename_is_null(*s->keyfile)) { int keytype; logeventf(ssh, "Reading private key file \"%.150s\"", - filename_to_str(&ssh->cfg.keyfile)); - keytype = key_type(&ssh->cfg.keyfile); + filename_to_str(s->keyfile)); + keytype = key_type(s->keyfile); if (keytype == SSH_KEYTYPE_SSH2) { const char *error; s->publickey_blob = - ssh2_userkey_loadpub(&ssh->cfg.keyfile, + ssh2_userkey_loadpub(s->keyfile, &s->publickey_algorithm, &s->publickey_bloblen, &s->publickey_comment, &error); if (s->publickey_blob) { s->publickey_encrypted = - ssh2_userkey_encrypted(&ssh->cfg.keyfile, NULL); + ssh2_userkey_encrypted(s->keyfile, NULL); } else { char *msgbuf; logeventf(ssh, "Unable to load private key (%s)", error); msgbuf = dupprintf("Unable to load private key file " "\"%.150s\" (%s)\r\n", - filename_to_str(&ssh->cfg.keyfile), + filename_to_str(s->keyfile), error); c_write_str(ssh, msgbuf); sfree(msgbuf); @@ -7440,7 +7446,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, key_type_to_str(keytype)); msgbuf = dupprintf("Unable to use key file \"%.150s\"" " (%s)\r\n", - filename_to_str(&ssh->cfg.keyfile), + filename_to_str(s->keyfile), key_type_to_str(keytype)); c_write_str(ssh, msgbuf); sfree(msgbuf); @@ -7455,7 +7461,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, s->nkeys = 0; s->agent_response = NULL; s->pkblob_in_agent = NULL; - if (ssh->cfg.tryagent && agent_exists()) { + if (conf_get_int(ssh->conf, CONF_tryagent) && agent_exists()) { void *r; @@ -7538,26 +7544,24 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * the username they will want to be able to get back and * retype it! */ - s->username[0] = '\0'; s->got_username = FALSE; while (!s->we_are_in) { /* * Get a username. */ - if (s->got_username && !ssh->cfg.change_username) { + if (s->got_username && !conf_get_int(ssh->conf, CONF_change_username)) { /* * We got a username last time round this loop, and * with change_username turned off we don't try to get * it again. */ - } else if (!get_remote_username(&ssh->cfg, s->username, - sizeof(s->username))) { + } else if ((ssh->username = get_remote_username(ssh->conf)) == NULL) { int ret; /* need not be kept over crReturn */ s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH login name"); - add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, - lenof(s->username)); + /* 512 is an arbitrary limit :-( */ + add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, 512); ret = get_userpass_input(s->cur_prompt, NULL, 0); while (ret < 0) { ssh->send_ok = 1; @@ -7574,13 +7578,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh_disconnect(ssh, "No username provided", NULL, 0, TRUE); crStopV; } - memcpy(s->username, s->cur_prompt->prompts[0]->result, - lenof(s->username)); + ssh->username = dupstr(s->cur_prompt->prompts[0]->result); free_prompts(s->cur_prompt); } else { char *stuff; if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) { - stuff = dupprintf("Using username \"%s\".\r\n", s->username); + stuff = dupprintf("Using username \"%s\".\r\n", ssh->username); c_write_str(ssh, stuff); sfree(stuff); } @@ -7595,7 +7598,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh->pkt_actx = SSH2_PKTCTX_NOAUTH; s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection");/* service requested */ ssh2_pkt_addstring(s->pktout, "none"); /* method */ ssh2_pkt_send(ssh, s->pktout); @@ -7707,7 +7710,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, c_write_str(ssh, "Access denied\r\n"); logevent("Access denied"); if (s->type == AUTH_TYPE_PASSWORD && - ssh->cfg.change_username) { + conf_get_int(ssh->conf, CONF_change_username)) { /* XXX perhaps we should allow * keyboard-interactive to do this too? */ s->we_are_in = FALSE; @@ -7723,12 +7726,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, in_commasep_string("publickey", methods, methlen); s->can_passwd = in_commasep_string("password", methods, methlen); - s->can_keyb_inter = ssh->cfg.try_ki_auth && + s->can_keyb_inter = conf_get_int(ssh->conf, CONF_try_ki_auth) && in_commasep_string("keyboard-interactive", methods, methlen); #ifndef NO_GSSAPI if (!ssh->gsslibs) - ssh->gsslibs = ssh_gss_setup(&ssh->cfg); - s->can_gssapi = ssh->cfg.try_gssapi_auth && + ssh->gsslibs = ssh_gss_setup(ssh->conf); + s->can_gssapi = conf_get_int(ssh->conf, CONF_try_gssapi_auth) && in_commasep_string("gssapi-with-mic", methods, methlen) && ssh->gsslibs->nlibraries > 0; #endif @@ -7761,7 +7764,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* See if server will accept it */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "publickey"); @@ -7796,7 +7799,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * Construct a SIGN_REQUEST. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "publickey"); @@ -7900,7 +7903,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * willing to accept it. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "publickey"); /* method */ @@ -7974,8 +7977,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* * Try decrypting the key. */ - key = ssh2_load_userkey(&ssh->cfg.keyfile, passphrase, - &error); + s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile); + key = ssh2_load_userkey(s->keyfile, passphrase, &error); if (passphrase) { /* burn the evidence */ memset(passphrase, 0, strlen(passphrase)); @@ -8008,7 +8011,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * Hallelujah. Generate a signature and send it. */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "publickey"); @@ -8081,7 +8084,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int i, j; s->gsslib = NULL; for (i = 0; i < ngsslibs; i++) { - int want_id = ssh->cfg.ssh_gsslist[i]; + int want_id = conf_get_int_int(ssh->conf, + CONF_ssh_gsslist, i); for (j = 0; j < ssh->gsslibs->nlibraries; j++) if (ssh->gsslibs->libraries[j].id == want_id) { s->gsslib = &ssh->gsslibs->libraries[j]; @@ -8104,7 +8108,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* Sending USERAUTH_REQUEST with "gssapi-with-mic" method */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); ssh2_pkt_addstring(s->pktout, "gssapi-with-mic"); @@ -8175,7 +8179,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, (s->gsslib, &s->gss_ctx, s->gss_srv_name, - ssh->cfg.gssapifwd, + conf_get_int(ssh->conf, CONF_gssapifwd), &s->gss_rcvtok, &s->gss_sndtok); @@ -8231,7 +8235,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh_pkt_addstring_start(s->pktout); ssh_pkt_addstring_data(s->pktout, (char *)ssh->v2_session_id, ssh->v2_session_id_len); ssh_pkt_addbyte(s->pktout, SSH2_MSG_USERAUTH_REQUEST); - ssh_pkt_addstring(s->pktout, s->username); + ssh_pkt_addstring(s->pktout, ssh->username); ssh_pkt_addstring(s->pktout, "ssh-connection"); ssh_pkt_addstring(s->pktout, "gssapi-with-mic"); @@ -8262,7 +8266,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh->pkt_actx = SSH2_PKTCTX_KBDINTER; s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "keyboard-interactive"); @@ -8417,8 +8421,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, s->cur_prompt = new_prompts(ssh->frontend); s->cur_prompt->to_server = TRUE; s->cur_prompt->name = dupstr("SSH password"); - add_prompt(s->cur_prompt, dupprintf("%.90s@%.90s's password: ", - s->username, + add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ", + ssh->username, ssh->savedhost), FALSE, SSH_MAX_PASSWORD_LEN); @@ -8458,7 +8462,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * people who find out how long their password is! */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "password"); @@ -8587,7 +8591,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * (see above for padding rationale) */ s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST); - ssh2_pkt_addstring(s->pktout, s->username); + ssh2_pkt_addstring(s->pktout, ssh->username); ssh2_pkt_addstring(s->pktout, "ssh-connection"); /* service requested */ ssh2_pkt_addstring(s->pktout, "password"); @@ -8692,9 +8696,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* * Create the main session channel. */ - if (ssh->cfg.ssh_no_shell) { + if (conf_get_int(ssh->conf, CONF_ssh_no_shell)) { ssh->mainchan = NULL; - } else if (*ssh->cfg.ssh_nc_host) { + } else if (*conf_get_str(ssh->conf, CONF_ssh_nc_host)) { /* * Just start a direct-tcpip channel and use it as the main * channel. @@ -8704,14 +8708,15 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh2_channel_init(ssh->mainchan); logeventf(ssh, "Opening direct-tcpip channel to %s:%d in place of session", - ssh->cfg.ssh_nc_host, ssh->cfg.ssh_nc_port); + conf_get_str(ssh->conf, CONF_ssh_nc_host), + conf_get_int(ssh->conf, CONF_ssh_nc_port)); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN); ssh2_pkt_addstring(s->pktout, "direct-tcpip"); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */ ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT); /* our max pkt size */ - ssh2_pkt_addstring(s->pktout, ssh->cfg.ssh_nc_host); - ssh2_pkt_adduint32(s->pktout, ssh->cfg.ssh_nc_port); + ssh2_pkt_addstring(s->pktout, conf_get_str(ssh->conf, CONF_ssh_nc_host)); + ssh2_pkt_adduint32(s->pktout, conf_get_int(ssh->conf, CONF_ssh_nc_port)); /* * There's nothing meaningful to put in the originator * fields, but some servers insist on syntactically correct @@ -8789,7 +8794,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_channel_open; - if (ssh->mainchan && ssh->cfg.ssh_simple) { + if (ssh->mainchan && conf_get_int(ssh->conf, CONF_ssh_simple)) { /* * This message indicates to the server that we promise * not to try to run any other channel in parallel with @@ -8806,9 +8811,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* * Potentially enable X11 forwarding. */ - if (ssh->mainchan && !ssh->ncmode && ssh->cfg.x11_forward && - (ssh->x11disp = x11_setup_display(ssh->cfg.x11_display, - ssh->cfg.x11_auth, &ssh->cfg))) { + if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_x11_forward) && + (ssh->x11disp = x11_setup_display(conf_get_str(ssh->conf, CONF_x11_display), + conf_get_int(ssh->conf, CONF_x11_auth), ssh->conf))) { logevent("Requesting X11 forwarding"); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); @@ -8847,12 +8852,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* * Enable port forwardings. */ - ssh_setup_portfwd(ssh, &ssh->cfg); + ssh_setup_portfwd(ssh, ssh->conf); /* * Potentially enable agent forwarding. */ - if (ssh->mainchan && !ssh->ncmode && ssh->cfg.agentfwd && agent_exists()) { + if (ssh->mainchan && !ssh->ncmode && conf_get_int(ssh->conf, CONF_agentfwd) && agent_exists()) { logevent("Requesting OpenSSH-style agent forwarding"); s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); @@ -8878,24 +8883,23 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, /* * Now allocate a pty for the session. */ - if (ssh->mainchan && !ssh->ncmode && !ssh->cfg.nopty) { + if (ssh->mainchan && !ssh->ncmode && !conf_get_int(ssh->conf, CONF_nopty)) { /* Unpick the terminal-speed string. */ /* XXX perhaps we should allow no speeds to be sent. */ ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ - sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed); + sscanf(conf_get_str(ssh->conf, CONF_termspeed), "%d,%d", &ssh->ospeed, &ssh->ispeed); /* Build the pty request. */ s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); /* recipient channel */ ssh2_pkt_addstring(s->pktout, "pty-req"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ - ssh2_pkt_addstring(s->pktout, ssh->cfg.termtype); + ssh2_pkt_addstring(s->pktout, conf_get_str(ssh->conf, CONF_termtype)); ssh2_pkt_adduint32(s->pktout, ssh->term_width); ssh2_pkt_adduint32(s->pktout, ssh->term_height); ssh2_pkt_adduint32(s->pktout, 0); /* pixel width */ ssh2_pkt_adduint32(s->pktout, 0); /* pixel height */ ssh2_pkt_addstring_start(s->pktout); - parse_ttymodes(ssh, ssh->cfg.ttymodes, - ssh2_send_ttymode, (void *)s->pktout); + parse_ttymodes(ssh, ssh2_send_ttymode, (void *)s->pktout); ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_ISPEED); ssh2_pkt_adduint32(s->pktout, ssh->ispeed); ssh2_pkt_addbyte(s->pktout, SSH2_TTY_OP_OSPEED); @@ -8928,63 +8932,57 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * Simplest thing here is to send all the requests at once, and * then wait for a whole bunch of successes or failures. */ - if (ssh->mainchan && !ssh->ncmode && *ssh->cfg.environmt) { - char *e = ssh->cfg.environmt; - char *var, *varend, *val; + if (ssh->mainchan && !ssh->ncmode) { + char *key, *val; s->num_env = 0; - while (*e) { - var = e; - while (*e && *e != '\t') e++; - varend = e; - if (*e == '\t') e++; - val = e; - while (*e) e++; - e++; - + for (val = conf_get_str_strs(ssh->conf, CONF_environmt, NULL, &key); + val != NULL; + val = conf_get_str_strs(ssh->conf, CONF_environmt, key, &key)) { s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(s->pktout, ssh->mainchan->remoteid); ssh2_pkt_addstring(s->pktout, "env"); ssh2_pkt_addbool(s->pktout, 1); /* want reply */ - ssh2_pkt_addstring_start(s->pktout); - ssh2_pkt_addstring_data(s->pktout, var, varend-var); + ssh2_pkt_addstring(s->pktout, key); ssh2_pkt_addstring(s->pktout, val); ssh2_pkt_send(ssh, s->pktout); s->num_env++; } - logeventf(ssh, "Sent %d environment variables", s->num_env); + if (s->num_env) { + logeventf(ssh, "Sent %d environment variables", s->num_env); - s->env_ok = 0; - s->env_left = s->num_env; + s->env_ok = 0; + s->env_left = s->num_env; - while (s->env_left > 0) { - crWaitUntilV(pktin); + while (s->env_left > 0) { + crWaitUntilV(pktin); - if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { - if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { - bombout(("Unexpected response to environment request:" - " packet type %d", pktin->type)); - crStopV; + if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) { + if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) { + bombout(("Unexpected response to environment request:" + " packet type %d", pktin->type)); + crStopV; + } + } else { + s->env_ok++; } - } else { - s->env_ok++; + + s->env_left--; } - s->env_left--; - } - - if (s->env_ok == s->num_env) { - logevent("All environment variables successfully set"); - } else if (s->env_ok == 0) { - logevent("All environment variables refused"); - c_write_str(ssh, "Server refused to set environment variables\r\n"); - } else { - logeventf(ssh, "%d environment variables refused", - s->num_env - s->env_ok); - c_write_str(ssh, "Server refused to set all environment variables\r\n"); + if (s->env_ok == s->num_env) { + logevent("All environment variables successfully set"); + } else if (s->env_ok == 0) { + logevent("All environment variables refused"); + c_write_str(ssh, "Server refused to set environment variables\r\n"); + } else { + logeventf(ssh, "%d environment variables refused", + s->num_env - s->env_ok); + c_write_str(ssh, "Server refused to set all environment variables\r\n"); + } } } @@ -8998,12 +8996,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, char *cmd; if (ssh->fallback_cmd) { - subsys = ssh->cfg.ssh_subsys2; - cmd = ssh->cfg.remote_cmd_ptr2; + subsys = conf_get_int(ssh->conf, CONF_ssh_subsys2); + cmd = conf_get_str(ssh->conf, CONF_remote_cmd2); } else { - subsys = ssh->cfg.ssh_subsys; - cmd = ssh->cfg.remote_cmd_ptr; - if (!cmd) cmd = ssh->cfg.remote_cmd; + subsys = conf_get_int(ssh->conf, CONF_ssh_subsys); + cmd = conf_get_str(ssh->conf, CONF_remote_cmd); } s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST); @@ -9036,7 +9033,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, * not, and if the fallback command exists, try falling * back to it before complaining. */ - if (!ssh->fallback_cmd && ssh->cfg.remote_cmd_ptr2 != NULL) { + if (!ssh->fallback_cmd && + *conf_get_str(ssh->conf, CONF_remote_cmd2)) { logevent("Primary command failed; attempting fallback"); ssh->fallback_cmd = TRUE; continue; @@ -9226,7 +9224,7 @@ static void ssh2_timer(void *ctx, long now) if (ssh->state == SSH_STATE_CLOSED) return; - if (!ssh->kex_in_progress && ssh->cfg.ssh_rekey_time != 0 && + if (!ssh->kex_in_progress && conf_get_int(ssh->conf, CONF_ssh_rekey_time) != 0 && now - ssh->next_rekey >= 0) { do_ssh2_transport(ssh, "timeout", -1, NULL); } @@ -9267,21 +9265,26 @@ static void ssh2_protocol(Ssh ssh, void *vin, int inlen, } } +static void ssh_cache_conf_values(Ssh ssh) +{ + ssh->logomitdata = conf_get_int(ssh->conf, CONF_logomitdata); +} + /* * Called to set up the connection. * * Returns an error message, or NULL on success. */ static const char *ssh_init(void *frontend_handle, void **backend_handle, - Config *cfg, - char *host, int port, char **realhost, int nodelay, - int keepalive) + Conf *conf, char *host, int port, char **realhost, + int nodelay, int keepalive) { const char *p; Ssh ssh; ssh = snew(struct ssh_tag); - ssh->cfg = *cfg; /* STRUCTURE COPY */ + ssh->conf = conf_copy(conf); + ssh_cache_conf_values(ssh); ssh->version = 0; /* when not ready yet */ ssh->s = NULL; ssh->cipher = NULL; @@ -9343,6 +9346,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->deferred_rekey_reason = NULL; bufchain_init(&ssh->queued_incoming_data); ssh->frozen = FALSE; + ssh->username = NULL; *backend_handle = ssh; @@ -9352,8 +9356,8 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, #endif ssh->frontend = frontend_handle; - ssh->term_width = ssh->cfg.width; - ssh->term_height = ssh->cfg.height; + ssh->term_width = conf_get_int(ssh->conf, CONF_width); + ssh->term_height = conf_get_int(ssh->conf, CONF_height); ssh->channels = NULL; ssh->rportfwds = NULL; @@ -9374,7 +9378,8 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle, ssh->incoming_data_size = ssh->outgoing_data_size = ssh->deferred_data_size = 0L; - ssh->max_data_size = parse_blocksize(ssh->cfg.ssh_rekey_data); + ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf, + CONF_ssh_rekey_data)); ssh->kex_in_progress = FALSE; #ifndef NO_GSSAPI @@ -9478,6 +9483,8 @@ static void ssh_free(void *handle) if (ssh->pinger) pinger_free(ssh->pinger); bufchain_clear(&ssh->queued_incoming_data); + sfree(ssh->username); + conf_free(ssh->conf); #ifndef NO_GSSAPI if (ssh->gsslibs) ssh_gss_cleanup(ssh->gsslibs); @@ -9490,19 +9497,21 @@ static void ssh_free(void *handle) /* * Reconfigure the SSH backend. */ -static void ssh_reconfig(void *handle, Config *cfg) +static void ssh_reconfig(void *handle, Conf *conf) { Ssh ssh = (Ssh) handle; char *rekeying = NULL, rekey_mandatory = FALSE; unsigned long old_max_data_size; + int i, rekey_time; - pinger_reconfig(ssh->pinger, &ssh->cfg, cfg); + pinger_reconfig(ssh->pinger, ssh->conf, conf); if (ssh->portfwds) - ssh_setup_portfwd(ssh, cfg); + ssh_setup_portfwd(ssh, conf); - if (ssh->cfg.ssh_rekey_time != cfg->ssh_rekey_time && - cfg->ssh_rekey_time != 0) { - long new_next = ssh->last_rekey + cfg->ssh_rekey_time*60*TICKSPERSEC; + rekey_time = conf_get_int(conf, CONF_ssh_rekey_time); + if (conf_get_int(ssh->conf, CONF_ssh_rekey_time) != rekey_time && + rekey_time != 0) { + long new_next = ssh->last_rekey + rekey_time*60*TICKSPERSEC; long now = GETTICKCOUNT(); if (new_next - now < 0) { @@ -9513,7 +9522,8 @@ static void ssh_reconfig(void *handle, Config *cfg) } old_max_data_size = ssh->max_data_size; - ssh->max_data_size = parse_blocksize(cfg->ssh_rekey_data); + ssh->max_data_size = parse_blocksize(conf_get_str(ssh->conf, + CONF_ssh_rekey_data)); if (old_max_data_size != ssh->max_data_size && ssh->max_data_size != 0) { if (ssh->outgoing_data_size > ssh->max_data_size || @@ -9521,19 +9531,27 @@ static void ssh_reconfig(void *handle, Config *cfg) rekeying = "data limit lowered"; } - if (ssh->cfg.compression != cfg->compression) { + if (conf_get_int(ssh->conf, CONF_compression) != + conf_get_int(conf, CONF_compression)) { rekeying = "compression setting changed"; rekey_mandatory = TRUE; } - if (ssh->cfg.ssh2_des_cbc != cfg->ssh2_des_cbc || - memcmp(ssh->cfg.ssh_cipherlist, cfg->ssh_cipherlist, - sizeof(ssh->cfg.ssh_cipherlist))) { + for (i = 0; i < CIPHER_MAX; i++) + if (conf_get_int_int(ssh->conf, CONF_ssh_cipherlist, i) != + conf_get_int_int(conf, CONF_ssh_cipherlist, i)) { + rekeying = "cipher settings changed"; + rekey_mandatory = TRUE; + } + if (conf_get_int(ssh->conf, CONF_ssh2_des_cbc) != + conf_get_int(conf, CONF_ssh2_des_cbc)) { rekeying = "cipher settings changed"; rekey_mandatory = TRUE; } - ssh->cfg = *cfg; /* STRUCTURE COPY */ + conf_free(ssh->conf); + ssh->conf = conf_copy(conf); + ssh_cache_conf_values(ssh); if (rekeying) { if (!ssh->kex_in_progress) { @@ -9611,7 +9629,7 @@ static void ssh_size(void *handle, int width, int height) ssh->size_needed = TRUE; /* buffer for later */ break; case SSH_STATE_SESSION: - if (!ssh->cfg.nopty) { + if (!conf_get_int(ssh->conf, CONF_nopty)) { if (ssh->version == 1) { send_packet(ssh, SSH1_CMSG_WINDOW_SIZE, PKT_INT, ssh->term_height, @@ -9835,7 +9853,7 @@ static void ssh_unthrottle(void *handle, int bufsize) ssh2_set_window(ssh->mainchan, bufsize < ssh->mainchan->v.v2.locmaxwin ? ssh->mainchan->v.v2.locmaxwin - bufsize : 0); - if (ssh->cfg.ssh_simple) + if (conf_get_int(ssh->conf, CONF_ssh_simple)) buflimit = 0; else buflimit = ssh->mainchan->v.v2.locmaxwin; diff --git a/ssh.h b/ssh.h index 90dafed1..8d288471 100644 --- a/ssh.h +++ b/ssh.h @@ -334,13 +334,11 @@ void ssh_send_port_open(void *channel, char *hostname, int port, char *org); /* Exports from portfwd.c */ extern const char *pfd_newconnect(Socket * s, char *hostname, int port, - void *c, const Config *cfg, - int addressfamily); + void *c, Conf *conf, int addressfamily); /* desthost == NULL indicates dynamic (SOCKS) port forwarding */ extern const char *pfd_addforward(char *desthost, int destport, char *srcaddr, - int port, void *backhandle, - const Config *cfg, void **sockdata, - int address_family); + int port, void *backhandle, Conf *conf, + void **sockdata, int address_family); extern void pfd_close(Socket s); extern void pfd_terminate(void *sockdata); extern int pfd_send(Socket s, char *data, int len); @@ -393,18 +391,17 @@ struct X11Display { * details are looked up by calling platform_get_x11_auth. */ extern struct X11Display *x11_setup_display(char *display, int authtype, - const Config *); + Conf *); void x11_free_display(struct X11Display *disp); extern const char *x11_init(Socket *, struct X11Display *, void *, - const char *, int, const Config *); + const char *, int, Conf *); extern void x11_close(Socket); extern int x11_send(Socket, char *, int); extern void x11_unthrottle(Socket s); extern void x11_override_throttle(Socket s, int enable); char *x11_display(const char *display); /* Platform-dependent X11 functions */ -extern void platform_get_x11_auth(struct X11Display *display, - const Config *); +extern void platform_get_x11_auth(struct X11Display *display, Conf *); /* examine a mostly-filled-in X11Display and fill in localauth* */ extern const int platform_uses_x11_unix_by_default; /* choose default X transport in the absence of a specified one */ diff --git a/sshgss.h b/sshgss.h index ffce0995..32ccb4db 100644 --- a/sshgss.h +++ b/sshgss.h @@ -47,7 +47,7 @@ struct ssh_gss_liblist { struct ssh_gss_library *libraries; int nlibraries; }; -struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg); +struct ssh_gss_liblist *ssh_gss_setup(Conf *conf); void ssh_gss_cleanup(struct ssh_gss_liblist *list); /* diff --git a/sshnogss.c b/sshnogss.c index fd8915ba..fa4ac65f 100644 --- a/sshnogss.c +++ b/sshnogss.c @@ -3,7 +3,7 @@ /* For platforms not supporting GSSAPI */ -struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) +struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) { struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist *); list->libraries = NULL; diff --git a/storage.h b/storage.h index 704f2311..01cfb034 100644 --- a/storage.h +++ b/storage.h @@ -9,9 +9,9 @@ /* ---------------------------------------------------------------------- * Functions to save and restore PuTTY sessions. Note that this is * only the low-level code to do the reading and writing. The - * higher-level code that translates a Config structure into a set - * of (key,value) pairs is elsewhere, since it doesn't (mostly) - * change between platforms. + * higher-level code that translates an internal Conf structure into + * a set of (key,value) pairs in their external storage format is + * elsewhere, since it doesn't (mostly) change between platforms. */ /* @@ -41,8 +41,8 @@ void close_settings_w(void *handle); * number of calls to read_setting_s() and read_setting_i(), and * then close it using close_settings_r(). * - * read_setting_s() writes into the provided buffer and returns a - * pointer to the same buffer. + * read_setting_s() returns a dynamically allocated string which the + * caller must free. * * If a particular string setting is not present in the session, * read_setting_s() can return NULL, in which case the caller @@ -53,7 +53,7 @@ void close_settings_w(void *handle); * the provided buffer, and return zero if they failed to. */ void *open_settings_r(const char *sessionname); -char *read_setting_s(void *handle, const char *key, char *buffer, int buflen); +char *read_setting_s(void *handle, const char *key); int read_setting_i(void *handle, const char *key, int defvalue); int read_setting_filename(void *handle, const char *key, Filename *value); int read_setting_fontspec(void *handle, const char *key, FontSpec *font); diff --git a/telnet.c b/telnet.c index 20ccc83e..05c9bf64 100644 --- a/telnet.c +++ b/telnet.c @@ -201,7 +201,7 @@ typedef struct telnet_tag { SEENSB, SUBNEGOT, SUBNEG_IAC, SEENCR } state; - Config cfg; + Conf *conf; Pinger pinger; } *Telnet; @@ -363,42 +363,46 @@ static void proc_rec_opt(Telnet telnet, int cmd, int option) static void process_subneg(Telnet telnet) { - unsigned char b[2048], *p, *q; - int var, value, n; - char *e; + unsigned char *b, *p, *q; + int var, value, n, bsize; + char *e, *eval, *ekey, *user; switch (telnet->sb_opt) { case TELOPT_TSPEED: if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) { char *logbuf; + char *termspeed = conf_get_str(telnet->conf, CONF_termspeed); + b = snewn(20 + strlen(termspeed), unsigned char); b[0] = IAC; b[1] = SB; b[2] = TELOPT_TSPEED; b[3] = TELQUAL_IS; - strcpy((char *)(b + 4), telnet->cfg.termspeed); - n = 4 + strlen(telnet->cfg.termspeed); + strcpy((char *)(b + 4), termspeed); + n = 4 + strlen(termspeed); b[n] = IAC; b[n + 1] = SE; telnet->bufsize = sk_write(telnet->s, (char *)b, n + 2); logevent(telnet->frontend, "server:\tSB TSPEED SEND"); - logbuf = dupprintf("client:\tSB TSPEED IS %s", telnet->cfg.termspeed); + logbuf = dupprintf("client:\tSB TSPEED IS %s", termspeed); logevent(telnet->frontend, logbuf); sfree(logbuf); + sfree(b); } else logevent(telnet->frontend, "server:\tSB TSPEED "); break; case TELOPT_TTYPE: if (telnet->sb_len == 1 && telnet->sb_buf[0] == TELQUAL_SEND) { char *logbuf; + char *termtype = conf_get_str(telnet->conf, CONF_termtype); + b = snewn(20 + strlen(termtype), unsigned char); b[0] = IAC; b[1] = SB; b[2] = TELOPT_TTYPE; b[3] = TELQUAL_IS; - for (n = 0; telnet->cfg.termtype[n]; n++) - b[n + 4] = (telnet->cfg.termtype[n] >= 'a' - && telnet->cfg.termtype[n] <= - 'z' ? telnet->cfg.termtype[n] + 'A' - - 'a' : telnet->cfg.termtype[n]); + for (n = 0; termtype[n]; n++) + b[n + 4] = (termtype[n] >= 'a' && termtype[n] <= 'z' ? + termtype[n] + 'A' - 'a' : + termtype[n]); b[n + 4] = IAC; b[n + 5] = SE; telnet->bufsize = sk_write(telnet->s, (char *)b, n + 6); @@ -407,6 +411,7 @@ static void process_subneg(Telnet telnet) logbuf = dupprintf("client:\tSB TTYPE IS %s", b + 4); logevent(telnet->frontend, logbuf); sfree(logbuf); + sfree(b); } else logevent(telnet->frontend, "server:\tSB TTYPE \r\n"); break; @@ -421,7 +426,7 @@ static void process_subneg(Telnet telnet) logevent(telnet->frontend, logbuf); sfree(logbuf); if (telnet->sb_opt == TELOPT_OLD_ENVIRON) { - if (telnet->cfg.rfc_environ) { + if (conf_get_str(telnet->conf, CONF_rfc_environ)) { value = RFC_VALUE; var = RFC_VAR; } else { @@ -449,50 +454,75 @@ static void process_subneg(Telnet telnet) value = RFC_VALUE; var = RFC_VAR; } + bsize = 20; + for (eval = conf_get_str_strs(telnet->conf, CONF_environmt, + NULL, &ekey); + eval != NULL; + eval = conf_get_str_strs(telnet->conf, CONF_environmt, + ekey, &ekey)) + bsize += strlen(ekey) + strlen(eval) + 2; + user = get_remote_username(telnet->conf); + if (user) + bsize += 6 + strlen(user); + + b = snewn(bsize, unsigned char); b[0] = IAC; b[1] = SB; b[2] = telnet->sb_opt; b[3] = TELQUAL_IS; n = 4; - e = telnet->cfg.environmt; - while (*e) { + for (eval = conf_get_str_strs(telnet->conf, CONF_environmt, + NULL, &ekey); + eval != NULL; + eval = conf_get_str_strs(telnet->conf, CONF_environmt, + ekey, &ekey)) { b[n++] = var; - while (*e && *e != '\t') - b[n++] = *e++; - if (*e == '\t') - e++; + for (e = ekey; *e; e++) + b[n++] = *e; b[n++] = value; - while (*e) - b[n++] = *e++; - e++; + for (e = eval; *e; e++) + b[n++] = *e; } - { - char user[sizeof(telnet->cfg.username)]; - (void) get_remote_username(&telnet->cfg, user, sizeof(user)); - if (*user) { - b[n++] = var; - b[n++] = 'U'; - b[n++] = 'S'; - b[n++] = 'E'; - b[n++] = 'R'; - b[n++] = value; - e = user; - while (*e) - b[n++] = *e++; - } - b[n++] = IAC; - b[n++] = SE; - telnet->bufsize = sk_write(telnet->s, (char *)b, n); - logbuf = dupprintf("client:\tSB %s IS %s%s%s%s", - telopt(telnet->sb_opt), - *user ? "USER=" : "", - user, - *user ? " " : "", - n == 6 ? "" : - (*telnet->cfg.environmt ? "" : "")); + if (user) { + b[n++] = var; + b[n++] = 'U'; + b[n++] = 'S'; + b[n++] = 'E'; + b[n++] = 'R'; + b[n++] = value; + for (e = user; *e; e++) + b[n++] = *e; + } + b[n++] = IAC; + b[n++] = SE; + telnet->bufsize = sk_write(telnet->s, (char *)b, n); + if (n == 6) { + logbuf = dupprintf("client:\tSB %s IS ", + telopt(telnet->sb_opt)); logevent(telnet->frontend, logbuf); sfree(logbuf); + } else { + logbuf = dupprintf("client:\tSB %s IS:", + telopt(telnet->sb_opt)); + logevent(telnet->frontend, logbuf); + sfree(logbuf); + for (eval = conf_get_str_strs(telnet->conf, CONF_environmt, + NULL, &ekey); + eval != NULL; + eval = conf_get_str_strs(telnet->conf, CONF_environmt, + ekey, &ekey)) { + logbuf = dupprintf("\t%s=%s", ekey, eval); + logevent(telnet->frontend, logbuf); + sfree(logbuf); + } + if (user) { + logbuf = dupprintf("\tUSER=%s", user); + logevent(telnet->frontend, logbuf); + sfree(logbuf); + } } + sfree(b); + sfree(user); } break; } @@ -674,9 +704,8 @@ static void telnet_sent(Plug plug, int bufsize) * freed by the caller. */ static const char *telnet_init(void *frontend_handle, void **backend_handle, - Config *cfg, - char *host, int port, char **realhost, - int nodelay, int keepalive) + Conf *conf, char *host, int port, + char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { telnet_log, @@ -687,10 +716,12 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, SockAddr addr; const char *err; Telnet telnet; + char *loghost; + int addressfamily; telnet = snew(struct telnet_tag); telnet->fn = &fn_table; - telnet->cfg = *cfg; /* STRUCTURE COPY */ + telnet->conf = conf_copy(conf); telnet->s = NULL; telnet->echoing = TRUE; telnet->editing = TRUE; @@ -698,8 +729,8 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, telnet->sb_buf = NULL; telnet->sb_size = 0; telnet->frontend = frontend_handle; - telnet->term_width = telnet->cfg.width; - telnet->term_height = telnet->cfg.height; + telnet->term_width = conf_get_int(telnet->conf, CONF_width); + telnet->term_height = conf_get_int(telnet->conf, CONF_height); telnet->state = TOP_LEVEL; telnet->ldisc = NULL; telnet->pinger = NULL; @@ -710,14 +741,15 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, */ { char *buf; + addressfamily = conf_get_int(telnet->conf, CONF_addressfamily); buf = dupprintf("Looking up host \"%s\"%s", host, - (cfg->addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : - (cfg->addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : + (addressfamily == ADDRTYPE_IPV4 ? " (IPv4)" : + (addressfamily == ADDRTYPE_IPV6 ? " (IPv6)" : ""))); logevent(telnet->frontend, buf); sfree(buf); } - addr = name_lookup(host, port, realhost, &telnet->cfg, cfg->addressfamily); + addr = name_lookup(host, port, realhost, telnet->conf, addressfamily); if ((err = sk_addr_error(addr)) != NULL) { sk_addr_free(addr); return err; @@ -730,16 +762,16 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, * Open socket. */ telnet->s = new_connection(addr, *realhost, port, 0, 1, - nodelay, keepalive, (Plug) telnet, &telnet->cfg); + nodelay, keepalive, (Plug) telnet, telnet->conf); if ((err = sk_socket_error(telnet->s)) != NULL) return err; - telnet->pinger = pinger_new(&telnet->cfg, &telnet_backend, telnet); + telnet->pinger = pinger_new(telnet->conf, &telnet_backend, telnet); /* * Initialise option states. */ - if (telnet->cfg.passive_telnet) { + if (conf_get_int(telnet->conf, CONF_passive_telnet)) { const struct Opt *const *o; for (o = opts; *o; o++) @@ -768,11 +800,12 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle, /* * loghost overrides realhost, if specified. */ - if (*telnet->cfg.loghost) { + loghost = conf_get_str(telnet->conf, CONF_loghost); + if (*loghost) { char *colon; sfree(*realhost); - *realhost = dupstr(telnet->cfg.loghost); + *realhost = dupstr(loghost); colon = strrchr(*realhost, ':'); if (colon) { /* @@ -796,6 +829,7 @@ static void telnet_free(void *handle) sk_close(telnet->s); if (telnet->pinger) pinger_free(telnet->pinger); + conf_free(telnet->conf); sfree(telnet); } /* @@ -803,11 +837,12 @@ static void telnet_free(void *handle) * necessary, in this backend: we just save the fresh config for * any subsequent negotiations. */ -static void telnet_reconfig(void *handle, Config *cfg) +static void telnet_reconfig(void *handle, Conf *conf) { Telnet telnet = (Telnet) handle; - pinger_reconfig(telnet->pinger, &telnet->cfg, cfg); - telnet->cfg = *cfg; /* STRUCTURE COPY */ + pinger_reconfig(telnet->pinger, telnet->conf, conf); + conf_free(telnet->conf); + telnet->conf = conf_copy(conf); } /* diff --git a/terminal.c b/terminal.c index 73ab393e..98653552 100644 --- a/terminal.c +++ b/terminal.c @@ -989,7 +989,7 @@ static void resizeline(Terminal *term, termline *line, int cols) static int sblines(Terminal *term) { int sblines = count234(term->scrollback); - if (term->cfg.erase_to_scrollback && + if (term->erase_to_scrollback && term->alt_which && term->alt_screen) { sblines += term->alt_sblines; } @@ -1015,7 +1015,7 @@ static termline *lineptr(Terminal *term, int y, int lineno, int screen) assert(!screen); - if (term->cfg.erase_to_scrollback && + if (term->erase_to_scrollback && term->alt_which && term->alt_screen) { altlines = term->alt_sblines; } @@ -1133,7 +1133,7 @@ static void term_schedule_tblink(Terminal *term) */ static void term_schedule_cblink(Terminal *term) { - if (term->cfg.blink_cur && term->has_focus) { + if (term->blink_cur && term->has_focus) { if (!term->cblink_pending) term->next_cblink = schedule_timer(CBLINK_DELAY, term_timer, term); term->cblink_pending = TRUE; @@ -1197,11 +1197,11 @@ static void power_on(Terminal *term, int clear) for (i = 0; i < term->cols; i++) term->tabs[i] = (i % 8 == 0 ? TRUE : FALSE); } - term->alt_om = term->dec_om = term->cfg.dec_om; + term->alt_om = term->dec_om = conf_get_int(term->conf, CONF_dec_om); term->alt_ins = term->insert = FALSE; term->alt_wnext = term->wrapnext = term->save_wnext = term->alt_save_wnext = FALSE; - term->alt_wrap = term->wrap = term->cfg.wrap_mode; + term->alt_wrap = term->wrap = conf_get_int(term->conf, CONF_wrap_mode); term->alt_cset = term->cset = term->save_cset = term->alt_save_cset = 0; term->alt_utf = term->utf = term->save_utf = term->alt_save_utf = 0; term->utf_state = 0; @@ -1216,10 +1216,10 @@ static void power_on(Terminal *term, int clear) term->default_attr = term->save_attr = term->alt_save_attr = term->curr_attr = ATTR_DEFAULT; term->term_editing = term->term_echoing = FALSE; - term->app_cursor_keys = term->cfg.app_cursor; - term->app_keypad_keys = term->cfg.app_keypad; - term->use_bce = term->cfg.bce; - term->blink_is_real = term->cfg.blinktext; + term->app_cursor_keys = conf_get_int(term->conf, CONF_app_cursor); + term->app_keypad_keys = conf_get_int(term->conf, CONF_app_keypad); + term->use_bce = conf_get_int(term->conf, CONF_bce); + term->blink_is_real = conf_get_int(term->conf, CONF_blinktext); term->erase_char = term->basic_erase_char; term->alt_which = 0; term_print_finish(term); @@ -1228,7 +1228,7 @@ static void power_on(Terminal *term, int clear) { int i; for (i = 0; i < 256; i++) - term->wordness[i] = term->cfg.wordness[i]; + term->wordness[i] = conf_get_int_int(term->conf, CONF_wordness, i); } if (term->screen) { swap_screen(term, 1, FALSE, FALSE); @@ -1261,7 +1261,7 @@ void term_update(Terminal *term) ctx = get_ctx(term->frontend); if (ctx) { int need_sbar_update = term->seen_disp_event; - if (term->seen_disp_event && term->cfg.scroll_on_disp) { + if (term->seen_disp_event && term->scroll_on_disp) { term->disptop = 0; /* return to main screen */ term->seen_disp_event = 0; need_sbar_update = TRUE; @@ -1300,7 +1300,7 @@ void term_seen_key_event(Terminal *term) /* * Reset the scrollback on keypress, if we're doing that. */ - if (term->cfg.scroll_on_key) { + if (term->scroll_on_key) { term->disptop = 0; /* return to main screen */ seen_disp_event(term); } @@ -1327,13 +1327,83 @@ static void set_erase_char(Terminal *term) (ATTR_FGMASK | ATTR_BGMASK)); } +/* + * We copy a bunch of stuff out of the Conf structure into local + * fields in the Terminal structure, to avoid the repeated tree234 + * lookups which would be involved in fetching them from the former + * every time. + */ +void term_copy_stuff_from_conf(Terminal *term) +{ + term->ansi_colour = conf_get_int(term->conf, CONF_ansi_colour); + term->arabicshaping = conf_get_int(term->conf, CONF_arabicshaping); + term->beep = conf_get_int(term->conf, CONF_beep); + term->bellovl = conf_get_int(term->conf, CONF_bellovl); + term->bellovl_n = conf_get_int(term->conf, CONF_bellovl_n); + term->bellovl_s = conf_get_int(term->conf, CONF_bellovl_s); + term->bellovl_t = conf_get_int(term->conf, CONF_bellovl_t); + term->bidi = conf_get_int(term->conf, CONF_bidi); + term->bksp_is_delete = conf_get_int(term->conf, CONF_bksp_is_delete); + term->blink_cur = conf_get_int(term->conf, CONF_blink_cur); + term->blinktext = conf_get_int(term->conf, CONF_blinktext); + term->cjk_ambig_wide = conf_get_int(term->conf, CONF_cjk_ambig_wide); + term->conf_height = conf_get_int(term->conf, CONF_height); + term->conf_width = conf_get_int(term->conf, CONF_width); + term->crhaslf = conf_get_int(term->conf, CONF_crhaslf); + term->erase_to_scrollback = conf_get_int(term->conf, CONF_erase_to_scrollback); + term->funky_type = conf_get_int(term->conf, CONF_funky_type); + term->lfhascr = conf_get_int(term->conf, CONF_lfhascr); + term->logflush = conf_get_int(term->conf, CONF_logflush); + term->logtype = conf_get_int(term->conf, CONF_logtype); + term->mouse_override = conf_get_int(term->conf, CONF_mouse_override); + term->nethack_keypad = conf_get_int(term->conf, CONF_nethack_keypad); + term->no_alt_screen = conf_get_int(term->conf, CONF_no_alt_screen); + term->no_applic_c = conf_get_int(term->conf, CONF_no_applic_c); + term->no_applic_k = conf_get_int(term->conf, CONF_no_applic_k); + term->no_dbackspace = conf_get_int(term->conf, CONF_no_dbackspace); + term->no_mouse_rep = conf_get_int(term->conf, CONF_no_mouse_rep); + term->no_remote_charset = conf_get_int(term->conf, CONF_no_remote_charset); + term->no_remote_resize = conf_get_int(term->conf, CONF_no_remote_resize); + term->no_remote_wintitle = conf_get_int(term->conf, CONF_no_remote_wintitle); + term->rawcnp = conf_get_int(term->conf, CONF_rawcnp); + term->rect_select = conf_get_int(term->conf, CONF_rect_select); + term->remote_qtitle_action = conf_get_int(term->conf, CONF_remote_qtitle_action); + term->rxvt_homeend = conf_get_int(term->conf, CONF_rxvt_homeend); + term->scroll_on_disp = conf_get_int(term->conf, CONF_scroll_on_disp); + term->scroll_on_key = conf_get_int(term->conf, CONF_scroll_on_key); + term->xterm_256_colour = conf_get_int(term->conf, CONF_xterm_256_colour); + + /* + * Parse the control-character escapes in the configured + * answerback string. + */ + { + char *answerback = conf_get_str(term->conf, CONF_answerback); + int maxlen = strlen(answerback); + + term->answerback = snewn(maxlen, char); + term->answerbacklen = 0; + + while (*answerback) { + char *n; + char c = ctrlparse(answerback, &n); + if (n) { + term->answerback[term->answerbacklen++] = c; + answerback = n; + } else { + term->answerback[term->answerbacklen++] = *answerback++; + } + } + } +} + /* * When the user reconfigures us, we need to check the forbidden- * alternate-screen config option, disable raw mouse mode if the * user has disabled mouse reporting, and abandon a print job if * the user has disabled printing. */ -void term_reconfig(Terminal *term, Config *cfg) +void term_reconfig(Terminal *term, Conf *conf) { /* * Before adopting the new config, check all those terminal @@ -1345,21 +1415,28 @@ void term_reconfig(Terminal *term, Config *cfg) int reset_wrap, reset_decom, reset_bce, reset_tblink, reset_charclass; int i; - reset_wrap = (term->cfg.wrap_mode != cfg->wrap_mode); - reset_decom = (term->cfg.dec_om != cfg->dec_om); - reset_bce = (term->cfg.bce != cfg->bce); - reset_tblink = (term->cfg.blinktext != cfg->blinktext); + reset_wrap = (conf_get_int(term->conf, CONF_wrap_mode) != + conf_get_int(conf, CONF_wrap_mode)); + reset_decom = (conf_get_int(term->conf, CONF_dec_om) != + conf_get_int(conf, CONF_dec_om)); + reset_bce = (conf_get_int(term->conf, CONF_bce) != + conf_get_int(conf, CONF_bce)); + reset_tblink = (conf_get_int(term->conf, CONF_blinktext) != + conf_get_int(conf, CONF_blinktext)); reset_charclass = 0; - for (i = 0; i < lenof(term->cfg.wordness); i++) - if (term->cfg.wordness[i] != cfg->wordness[i]) + for (i = 0; i < 256; i++) + if (conf_get_int_int(term->conf, CONF_wordness, i) != + conf_get_int_int(conf, CONF_wordness, i)) reset_charclass = 1; /* * If the bidi or shaping settings have changed, flush the bidi * cache completely. */ - if (term->cfg.arabicshaping != cfg->arabicshaping || - term->cfg.bidi != cfg->bidi) { + if (conf_get_int(term->conf, CONF_arabicshaping) != + conf_get_int(conf, CONF_arabicshaping) || + conf_get_int(term->conf, CONF_bidi) != + conf_get_int(conf, CONF_bidi)) { for (i = 0; i < term->bidi_cache_size; i++) { sfree(term->pre_bidi_cache[i].chars); sfree(term->post_bidi_cache[i].chars); @@ -1370,39 +1447,41 @@ void term_reconfig(Terminal *term, Config *cfg) } } - term->cfg = *cfg; /* STRUCTURE COPY */ + conf_free(term->conf); + term->conf = conf_copy(conf); if (reset_wrap) - term->alt_wrap = term->wrap = term->cfg.wrap_mode; + term->alt_wrap = term->wrap = conf_get_int(term->conf, CONF_wrap_mode); if (reset_decom) - term->alt_om = term->dec_om = term->cfg.dec_om; + term->alt_om = term->dec_om = conf_get_int(term->conf, CONF_dec_om); if (reset_bce) { - term->use_bce = term->cfg.bce; + term->use_bce = conf_get_int(term->conf, CONF_bce); set_erase_char(term); } if (reset_tblink) { - term->blink_is_real = term->cfg.blinktext; + term->blink_is_real = conf_get_int(term->conf, CONF_blinktext); } if (reset_charclass) for (i = 0; i < 256; i++) - term->wordness[i] = term->cfg.wordness[i]; + term->wordness[i] = conf_get_int_int(term->conf, CONF_wordness, i); - if (term->cfg.no_alt_screen) + if (conf_get_int(term->conf, CONF_no_alt_screen)) swap_screen(term, 0, FALSE, FALSE); - if (term->cfg.no_mouse_rep) { + if (conf_get_int(term->conf, CONF_no_mouse_rep)) { term->xterm_mouse = 0; set_raw_mouse_mode(term->frontend, 0); } - if (term->cfg.no_remote_charset) { + if (conf_get_int(term->conf, CONF_no_remote_charset)) { term->cset_attr[0] = term->cset_attr[1] = CSET_ASCII; term->sco_acs = term->alt_sco_acs = 0; term->utf = 0; } - if (!*term->cfg.printer) { + if (!conf_get_str(term->conf, CONF_printer)) { term_print_finish(term); } term_schedule_tblink(term); term_schedule_cblink(term); + term_copy_stuff_from_conf(term); } /* @@ -1423,7 +1502,7 @@ void term_clrsb(Terminal *term) /* * Initialise the terminal. */ -Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata, +Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, void *frontend) { Terminal *term; @@ -1435,7 +1514,7 @@ Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata, term = snew(Terminal); term->frontend = frontend; term->ucsdata = ucsdata; - term->cfg = *mycfg; /* STRUCTURE COPY */ + term->conf = conf_copy(myconf); term->logctx = NULL; term->compatibility_level = TM_PUTTY; strcpy(term->id_string, "\033[?6c"); @@ -1497,6 +1576,8 @@ Terminal *term_init(Config *mycfg, struct unicode_data *ucsdata, term->basic_erase_char.cc_next = 0; term->erase_char = term->basic_erase_char; + term_copy_stuff_from_conf(term); + return term; } @@ -1543,6 +1624,8 @@ void term_free(Terminal *term) expire_timer_context(term); + conf_free(term->conf); + sfree(term); } @@ -2243,7 +2326,7 @@ static void erase_lots(Terminal *term, if (start.y == 0 && start.x == 0 && end.x == 0 && erase_lattr) erasing_lines_from_top = 1; - if (term->cfg.erase_to_scrollback && erasing_lines_from_top) { + if (term->erase_to_scrollback && erasing_lines_from_top) { /* If it's a whole number of lines, starting at the top, and * we're fully erasing them, erase by scrolling and keep the * lines in the scrollback. */ @@ -2334,13 +2417,13 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) term->blink_is_real = FALSE; term->vt52_bold = FALSE; } else { - term->blink_is_real = term->cfg.blinktext; + term->blink_is_real = term->blinktext; } term_schedule_tblink(term); break; case 3: /* DECCOLM: 80/132 columns */ deselect(term); - if (!term->cfg.no_remote_resize) + if (!term->no_remote_resize) request_resize(term->frontend, state ? 132 : 80, term->rows); term->reset_132 = state; term->alt_t = term->marg_t = 0; @@ -2387,7 +2470,7 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 47: /* alternate screen */ compatibility(OTHER); deselect(term); - swap_screen(term, term->cfg.no_alt_screen ? 0 : state, FALSE, FALSE); + swap_screen(term, term->no_alt_screen ? 0 : state, FALSE, FALSE); term->disptop = 0; break; case 1000: /* xterm mouse 1 (normal) */ @@ -2401,22 +2484,22 @@ static void toggle_mode(Terminal *term, int mode, int query, int state) case 1047: /* alternate screen */ compatibility(OTHER); deselect(term); - swap_screen(term, term->cfg.no_alt_screen ? 0 : state, TRUE, TRUE); + swap_screen(term, term->no_alt_screen ? 0 : state, TRUE, TRUE); term->disptop = 0; break; case 1048: /* save/restore cursor */ - if (!term->cfg.no_alt_screen) + if (!term->no_alt_screen) save_cursor(term, state); if (!state) seen_disp_event(term); break; case 1049: /* cursor & alternate screen */ - if (state && !term->cfg.no_alt_screen) + if (state && !term->no_alt_screen) save_cursor(term, state); if (!state) seen_disp_event(term); compatibility(OTHER); deselect(term); - swap_screen(term, term->cfg.no_alt_screen ? 0 : state, TRUE, FALSE); - if (!state && !term->cfg.no_alt_screen) + swap_screen(term, term->no_alt_screen ? 0 : state, TRUE, FALSE); + if (!state && !term->no_alt_screen) save_cursor(term, state); term->disptop = 0; break; @@ -2454,14 +2537,14 @@ static void do_osc(Terminal *term) switch (term->esc_args[0]) { case 0: case 1: - if (!term->cfg.no_remote_wintitle) + if (!term->no_remote_wintitle) set_icon(term->frontend, term->osc_string); if (term->esc_args[0] == 1) break; /* fall through: parameter 0 means set both */ case 2: case 21: - if (!term->cfg.no_remote_wintitle) + if (!term->no_remote_wintitle) set_title(term->frontend, term->osc_string); break; } @@ -2471,10 +2554,10 @@ static void do_osc(Terminal *term) /* * ANSI printing routines. */ -static void term_print_setup(Terminal *term) +static void term_print_setup(Terminal *term, char *printer) { bufchain_clear(&term->printer_buf); - term->print_job = printer_start_job(term->cfg.printer); + term->print_job = printer_start_job(printer); } static void term_print_flush(Terminal *term) { @@ -2549,7 +2632,7 @@ static void term_out(Terminal *term) * Optionally log the session traffic to a file. Useful for * debugging and possibly also useful for actual logging. */ - if (term->cfg.logtype == LGTYP_DEBUG && term->logctx) + if (term->logtype == LGTYP_DEBUG && term->logctx) logtraffic(term->logctx, (unsigned char) c, LGTYP_DEBUG); } else { c = unget; @@ -2741,7 +2824,7 @@ static void term_out(Terminal *term) term->curs.x--; term->wrapnext = FALSE; /* destructive backspace might be disabled */ - if (!term->cfg.no_dbackspace) { + if (!term->no_dbackspace) { check_boundary(term, term->curs.x, term->curs.y); check_boundary(term, term->curs.x+1, term->curs.y); copy_termchar(scrlineptr(term->curs.y), @@ -2761,19 +2844,8 @@ static void term_out(Terminal *term) */ compatibility(ANSIMIN); if (term->ldisc) { - char abuf[lenof(term->cfg.answerback)], *s, *d; - for (s = term->cfg.answerback, d = abuf; *s;) { - char *n; - char c = ctrlparse(s, &n); - if (n) { - *d++ = c; - s = n; - } else { - *d++ = *s++; - } - } lpage_send(term->ldisc, DEFAULT_CODEPAGE, - abuf, d - abuf, 0); + term->answerback, term->answerbacklen, 0); } break; case '\007': /* BEL: Bell */ @@ -2800,7 +2872,7 @@ static void term_out(Terminal *term) * t seconds ago. */ while (term->beephead && - term->beephead->ticks < ticks - term->cfg.bellovl_t) { + term->beephead->ticks < ticks - term->bellovl_t) { struct beeptime *tmp = term->beephead; term->beephead = tmp->next; sfree(tmp); @@ -2809,16 +2881,16 @@ static void term_out(Terminal *term) term->nbeeps--; } - if (term->cfg.bellovl && term->beep_overloaded && - ticks - term->lastbeep >= (unsigned)term->cfg.bellovl_s) { + if (term->bellovl && term->beep_overloaded && + ticks - term->lastbeep >= (unsigned)term->bellovl_s) { /* * If we're currently overloaded and the * last beep was more than s seconds ago, * leave overload mode. */ term->beep_overloaded = FALSE; - } else if (term->cfg.bellovl && !term->beep_overloaded && - term->nbeeps >= term->cfg.bellovl_n) { + } else if (term->bellovl && !term->beep_overloaded && + term->nbeeps >= term->bellovl_n) { /* * Now, if we have n or more beeps * remaining in the queue, go into overload @@ -2831,10 +2903,10 @@ static void term_out(Terminal *term) /* * Perform an actual beep if we're not overloaded. */ - if (!term->cfg.bellovl || !term->beep_overloaded) { - do_beep(term->frontend, term->cfg.beep); + if (!term->bellovl || !term->beep_overloaded) { + do_beep(term->frontend, term->beep); - if (term->cfg.beep == BELL_VISUAL) { + if (term->beep == BELL_VISUAL) { term_schedule_vbell(term, FALSE, 0); } } @@ -2876,12 +2948,12 @@ static void term_out(Terminal *term) seen_disp_event(term); term->paste_hold = 0; - if (term->cfg.crhaslf) { - if (term->curs.y == term->marg_b) - scroll(term, term->marg_t, term->marg_b, 1, TRUE); - else if (term->curs.y < term->rows - 1) - term->curs.y++; - } + if (term->crhaslf) { + if (term->curs.y == term->marg_b) + scroll(term, term->marg_t, term->marg_b, 1, TRUE); + else if (term->curs.y < term->rows - 1) + term->curs.y++; + } if (term->logctx) logtraffic(term->logctx, (unsigned char) c, LGTYP_ASCII); break; @@ -2901,7 +2973,7 @@ static void term_out(Terminal *term) scroll(term, term->marg_t, term->marg_b, 1, TRUE); else if (term->curs.y < term->rows - 1) term->curs.y++; - if (term->cfg.lfhascr) + if (term->lfhascr) term->curs.x = 0; term->wrapnext = FALSE; seen_disp_event(term); @@ -2943,7 +3015,7 @@ static void term_out(Terminal *term) if (DIRECT_CHAR(c)) width = 1; if (!width) - width = (term->cfg.cjk_ambig_wide ? + width = (term->cjk_ambig_wide ? mk_wcwidth_cjk((wchar_t) c) : mk_wcwidth((wchar_t) c)); @@ -3166,7 +3238,7 @@ static void term_out(Terminal *term) if (term->ldisc) /* cause ldisc to notice changes */ ldisc_send(term->ldisc, NULL, 0, 0); if (term->reset_132) { - if (!term->cfg.no_remote_resize) + if (!term->no_remote_resize) request_resize(term->frontend, 80, term->rows); term->reset_132 = 0; } @@ -3231,55 +3303,55 @@ static void term_out(Terminal *term) /* GZD4: G0 designate 94-set */ case ANSI('A', '('): compatibility(VT100); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->cset_attr[0] = CSET_GBCHR; break; case ANSI('B', '('): compatibility(VT100); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->cset_attr[0] = CSET_ASCII; break; case ANSI('0', '('): compatibility(VT100); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->cset_attr[0] = CSET_LINEDRW; break; case ANSI('U', '('): compatibility(OTHER); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->cset_attr[0] = CSET_SCOACS; break; /* G1D4: G1-designate 94-set */ case ANSI('A', ')'): compatibility(VT100); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->cset_attr[1] = CSET_GBCHR; break; case ANSI('B', ')'): compatibility(VT100); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->cset_attr[1] = CSET_ASCII; break; case ANSI('0', ')'): compatibility(VT100); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->cset_attr[1] = CSET_LINEDRW; break; case ANSI('U', ')'): compatibility(OTHER); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->cset_attr[1] = CSET_SCOACS; break; /* DOCS: Designate other coding system */ case ANSI('8', '%'): /* Old Linux code */ case ANSI('G', '%'): compatibility(OTHER); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->utf = 1; break; case ANSI('@', '%'): compatibility(OTHER); - if (!term->cfg.no_remote_charset) + if (!term->no_remote_charset) term->utf = 0; break; } @@ -3463,12 +3535,15 @@ static void term_out(Terminal *term) case ANSI_QUE('i'): compatibility(VT100); { + char *printer; if (term->esc_nargs != 1) break; - if (term->esc_args[0] == 5 && *term->cfg.printer) { + if (term->esc_args[0] == 5 && + (printer = conf_get_str(term->conf, + CONF_printer))[0]) { term->printing = TRUE; term->only_printing = !term->esc_query; term->print_state = 0; - term_print_setup(term); + term_print_setup(term, printer); } else if (term->esc_args[0] == 4 && term->printing) { term_print_finish(term); @@ -3591,15 +3666,15 @@ static void term_out(Terminal *term) break; case 10: /* SCO acs off */ compatibility(SCOANSI); - if (term->cfg.no_remote_charset) break; + if (term->no_remote_charset) break; term->sco_acs = 0; break; case 11: /* SCO acs on */ compatibility(SCOANSI); - if (term->cfg.no_remote_charset) break; + if (term->no_remote_charset) break; term->sco_acs = 1; break; case 12: /* SCO acs on, |0x80 */ compatibility(SCOANSI); - if (term->cfg.no_remote_charset) break; + if (term->no_remote_charset) break; term->sco_acs = 2; break; case 22: /* disable bold */ compatibility2(OTHER, VT220); @@ -3722,7 +3797,7 @@ static void term_out(Terminal *term) && (term->esc_args[0] < 1 || term->esc_args[0] >= 24)) { compatibility(VT340TEXT); - if (!term->cfg.no_remote_resize) + if (!term->no_remote_resize) request_resize(term->frontend, term->cols, def(term->esc_args[0], 24)); deselect(term); @@ -3742,7 +3817,7 @@ static void term_out(Terminal *term) break; case 3: if (term->esc_nargs >= 3) { - if (!term->cfg.no_remote_resize) + if (!term->no_remote_resize) move_window(term->frontend, def(term->esc_args[1], 0), def(term->esc_args[2], 0)); @@ -3767,10 +3842,10 @@ static void term_out(Terminal *term) break; case 8: if (term->esc_nargs >= 3) { - if (!term->cfg.no_remote_resize) + if (!term->no_remote_resize) request_resize(term->frontend, - def(term->esc_args[2], term->cfg.width), - def(term->esc_args[1], term->cfg.height)); + def(term->esc_args[2], term->conf_width), + def(term->esc_args[1], term->conf_height)); } break; case 9: @@ -3825,8 +3900,8 @@ static void term_out(Terminal *term) break; case 20: if (term->ldisc && - term->cfg.remote_qtitle_action != TITLE_NONE) { - if(term->cfg.remote_qtitle_action == TITLE_REAL) + term->remote_qtitle_action != TITLE_NONE) { + if(term->remote_qtitle_action == TITLE_REAL) p = get_window_title(term->frontend, TRUE); else p = EMPTY_WINDOW_TITLE; @@ -3838,8 +3913,8 @@ static void term_out(Terminal *term) break; case 21: if (term->ldisc && - term->cfg.remote_qtitle_action != TITLE_NONE) { - if(term->cfg.remote_qtitle_action == TITLE_REAL) + term->remote_qtitle_action != TITLE_NONE) { + if(term->remote_qtitle_action == TITLE_REAL) p = get_window_title(term->frontend, FALSE); else p = EMPTY_WINDOW_TITLE; @@ -3875,10 +3950,10 @@ static void term_out(Terminal *term) */ compatibility(VT420); if (term->esc_nargs == 1 && term->esc_args[0] > 0) { - if (!term->cfg.no_remote_resize) + if (!term->no_remote_resize) request_resize(term->frontend, term->cols, def(term->esc_args[0], - term->cfg.height)); + term->conf_height)); deselect(term); } break; @@ -3890,10 +3965,11 @@ static void term_out(Terminal *term) */ compatibility(VT340TEXT); if (term->esc_nargs <= 1) { - if (!term->cfg.no_remote_resize) + if (!term->no_remote_resize) request_resize(term->frontend, def(term->esc_args[0], - term->cfg.width), term->rows); + term->conf_width), + term->rows); deselect(term); } break; @@ -4095,7 +4171,7 @@ static void term_out(Terminal *term) * Well we should do a soft reset at this point ... */ if (!has_compat(VT420) && has_compat(VT100)) { - if (!term->cfg.no_remote_resize) { + if (!term->no_remote_resize) { if (term->reset_132) request_resize(132, 24); else @@ -4330,7 +4406,7 @@ static void term_out(Terminal *term) * emulation. */ term->vt52_mode = FALSE; - term->blink_is_real = term->cfg.blinktext; + term->blink_is_real = term->blinktext; term_schedule_tblink(term); break; #if 0 @@ -4474,7 +4550,7 @@ static void term_out(Terminal *term) } term_print_flush(term); - if (term->cfg.logflush) + if (term->logflush) logflush(term->logctx); } @@ -4577,7 +4653,7 @@ static termchar *term_bidi_line(Terminal *term, struct termline *ldata, int it; /* Do Arabic shaping and bidi. */ - if(!term->cfg.bidi || !term->cfg.arabicshaping) { + if(!term->bidi || !term->arabicshaping) { if (!term_bidi_cache_hit(term, scr_y, ldata->chars, term->cols)) { @@ -4595,7 +4671,7 @@ static termchar *term_bidi_line(Terminal *term, struct termline *ldata, switch (uc & CSET_MASK) { case CSET_LINEDRW: - if (!term->cfg.rawcnp) { + if (!term->rawcnp) { uc = term->ucsdata->unitab_xterm[uc & 0xFF]; break; } @@ -4620,15 +4696,15 @@ static termchar *term_bidi_line(Terminal *term, struct termline *ldata, term->wcFrom[it].index = it; } - if(!term->cfg.bidi) + if(!term->bidi) do_bidi(term->wcFrom, term->cols); /* this is saved iff done from inside the shaping */ - if(!term->cfg.bidi && term->cfg.arabicshaping) + if(!term->bidi && term->arabicshaping) for(it=0; itcols; it++) term->wcTo[it] = term->wcFrom[it]; - if(!term->cfg.arabicshaping) + if(!term->arabicshaping) do_shape(term->wcFrom, term->wcTo, term->cols); if (term->ltemp_size < ldata->size) { @@ -4690,14 +4766,14 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) /* Depends on: * screen array, disptop, scrtop, * selection, rv, - * cfg.blinkpc, blink_is_real, tblinker, - * curs.y, curs.x, cblinker, cfg.blink_cur, cursor_on, has_focus, wrapnext + * blinkpc, blink_is_real, tblinker, + * curs.y, curs.x, cblinker, blink_cur, cursor_on, has_focus, wrapnext */ /* Has the cursor position or type changed ? */ if (term->cursor_on) { if (term->has_focus) { - if (term->cblinker || !term->cfg.blink_cur) + if (term->cblinker || !term->blink_cur) cursor = TATTR_ACTCURS; else cursor = 0; @@ -4805,11 +4881,11 @@ static void do_paint(Terminal *term, Context ctx, int may_optimise) tchar = d->chr; tattr = d->attr; - if (!term->cfg.ansi_colour) + if (!term->ansi_colour) tattr = (tattr & ~(ATTR_FGMASK | ATTR_BGMASK)) | ATTR_DEFFG | ATTR_DEFBG; - if (!term->cfg.xterm_256_colour) { + if (!term->xterm_256_colour) { int colour; colour = (tattr & ATTR_FGMASK) >> ATTR_FGSHIFT; if (colour >= 16 && colour < 256) @@ -5265,7 +5341,7 @@ static void clipme(Terminal *term, pos top, pos bottom, int rect, int desel) switch (uc & CSET_MASK) { case CSET_LINEDRW: - if (!term->cfg.rawcnp) { + if (!term->rawcnp) { uc = term->ucsdata->unitab_xterm[uc & 0xFF]; break; } @@ -5647,8 +5723,8 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, pos selpoint; termline *ldata; int raw_mouse = (term->xterm_mouse && - !term->cfg.no_mouse_rep && - !(term->cfg.mouse_override && shift)); + !term->no_mouse_rep && + !(term->mouse_override && shift)); int default_seltype; if (y < 0) { @@ -5755,7 +5831,7 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked, * Set the selection type (rectangular or normal) at the start * of a selection attempt, from the state of Alt. */ - if (!alt ^ !term->cfg.rect_select) + if (!alt ^ !term->rect_select) default_seltype = RECTANGULAR; else default_seltype = LEXICOGRAPHIC; @@ -5875,7 +5951,7 @@ int format_arrow_key(char *buf, Terminal *term, int xkey, int ctrl) if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", xkey); else { - int app_flg = (term->app_cursor_keys && !term->cfg.no_applic_c); + int app_flg = (term->app_cursor_keys && !term->no_applic_c); #if 0 /* * RDB: VT100 & VT102 manuals both state the app cursor @@ -5992,7 +6068,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, } /* Nethack keypad */ - if (term->cfg.nethack_keypad) { + if (term->nethack_keypad) { char c = 0; switch (keysym) { case PK_KP1: c = 'b'; break; @@ -6026,10 +6102,10 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, * In VT400 mode, PFn always emits an escape sequence. In * Linux and tilde modes, this only happens in app keypad mode. */ - if (term->cfg.funky_type == FUNKY_VT400 || - ((term->cfg.funky_type == FUNKY_LINUX || - term->cfg.funky_type == FUNKY_TILDE) && - term->app_keypad_keys && !term->cfg.no_applic_k)) { + if (term->funky_type == FUNKY_VT400 || + ((term->funky_type == FUNKY_LINUX || + term->funky_type == FUNKY_TILDE) && + term->app_keypad_keys && !term->no_applic_k)) { switch (keysym) { case PK_PF1: xkey = 'P'; break; case PK_PF2: xkey = 'Q'; break; @@ -6038,7 +6114,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, default: break; /* else gcc warns `enum value not used' */ } } - if (term->app_keypad_keys && !term->cfg.no_applic_k) { + if (term->app_keypad_keys && !term->no_applic_k) { switch (keysym) { case PK_KP0: xkey = 'p'; break; case PK_KP1: xkey = 'q'; break; @@ -6054,7 +6130,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, case PK_KPENTER: xkey = 'M'; break; default: break; /* else gcc warns `enum value not used' */ } - if (term->cfg.funky_type == FUNKY_XTERM && tlen > 0) { + if (term->funky_type == FUNKY_XTERM && tlen > 0) { /* * xterm can't see the layout of the keypad, so it has * to rely on the X keysyms returned by the keys. @@ -6126,10 +6202,10 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, goto done; case PK_BACKSPACE: if (modifiers == 0) - *p++ = (term->cfg.bksp_is_delete ? 0x7F : 0x08); + *p++ = (term->bksp_is_delete ? 0x7F : 0x08); else if (modifiers == PKM_SHIFT) /* We do the opposite of what is configured */ - *p++ = (term->cfg.bksp_is_delete ? 0x08 : 0x7F); + *p++ = (term->bksp_is_delete ? 0x08 : 0x7F); else break; goto done; case PK_TAB: @@ -6157,7 +6233,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, } /* SCO function keys and editing keys */ - if (term->cfg.funky_type == FUNKY_SCO) { + if (term->funky_type == FUNKY_SCO) { if (PK_ISFKEY(keysym) && keysym <= PK_F12) { static char const codes[] = "MNOPQRSTUVWX" "YZabcdefghij" "klmnopqrstuv" "wxyz@[\\]^_`{"; @@ -6187,7 +6263,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, if (PK_ISEDITING(keysym) && (modifiers & PKM_SHIFT) == 0) { int code; - if (term->cfg.funky_type == FUNKY_XTERM) { + if (term->funky_type == FUNKY_XTERM) { /* Xterm shuffles these keys, apparently. */ switch (keysym) { case PK_HOME: keysym = PK_INSERT; break; @@ -6201,7 +6277,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, } /* RXVT Home/End */ - if (term->cfg.rxvt_homeend && + if (term->rxvt_homeend && (keysym == PK_HOME || keysym == PK_END)) { p += sprintf((char *) p, keysym == PK_HOME ? "\x1B[H" : "\x1BOw"); goto done; @@ -6244,7 +6320,7 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, /* Map Shift+F1-F10 to F11-F20 */ if (keysym >= PK_F1 && keysym <= PK_F10 && (modifiers & PKM_SHIFT)) keysym += 10; - if ((term->vt52_mode || term->cfg.funky_type == FUNKY_VT100P) && + if ((term->vt52_mode || term->funky_type == FUNKY_VT100P) && keysym <= PK_F14) { /* XXX This overrides the XTERM/VT52 mode below */ int offt = 0; @@ -6254,11 +6330,11 @@ void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen, 'P' + keysym - PK_F1 - offt); goto done; } - if (term->cfg.funky_type == FUNKY_LINUX && keysym <= PK_F5) { + if (term->funky_type == FUNKY_LINUX && keysym <= PK_F5) { p += sprintf((char *) p, "\x1B[[%c", 'A' + keysym - PK_F1); goto done; } - if (term->cfg.funky_type == FUNKY_XTERM && keysym <= PK_F4) { + if (term->funky_type == FUNKY_XTERM && keysym <= PK_F4) { if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", 'P' + keysym - PK_F1); else @@ -6478,9 +6554,9 @@ char *term_get_ttymode(Terminal *term, const char *mode) { char *val = NULL; if (strcmp(mode, "ERASE") == 0) { - val = term->cfg.bksp_is_delete ? "^?" : "^H"; + val = term->bksp_is_delete ? "^?" : "^H"; } - /* FIXME: perhaps we should set ONLCR based on cfg.lfhascr as well? */ + /* FIXME: perhaps we should set ONLCR based on lfhascr as well? */ /* FIXME: or ECHO and friends based on local echo state? */ return dupstr(val); } diff --git a/terminal.h b/terminal.h index aef47a5b..42a67ed6 100644 --- a/terminal.h +++ b/terminal.h @@ -233,13 +233,13 @@ struct terminal_tag { struct unicode_data *ucsdata; /* - * We maintain a full _copy_ of a Config structure here, not - * merely a pointer to it. That way, when we're passed a new - * one for reconfiguration, we can check the differences and - * adjust the _current_ setting of (e.g.) auto wrap mode rather - * than only the default. + * We maintain a full copy of a Conf here, not merely a pointer + * to it. That way, when we're passed a new one for + * reconfiguration, we can check the differences and adjust the + * _current_ setting of (e.g.) auto wrap mode rather than only + * the default. */ - Config cfg; + Conf *conf; /* * from_backend calls term_out, but it can also be called from @@ -273,6 +273,52 @@ struct terminal_tag { int wcFromTo_size; struct bidi_cache_entry *pre_bidi_cache, *post_bidi_cache; int bidi_cache_size; + + /* + * We copy a bunch of stuff out of the Conf structure into local + * fields in the Terminal structure, to avoid the repeated + * tree234 lookups which would be involved in fetching them from + * the former every time. + */ + int ansi_colour; + char *answerback; + int answerbacklen; + int arabicshaping; + int beep; + int bellovl; + int bellovl_n; + int bellovl_s; + int bellovl_t; + int bidi; + int bksp_is_delete; + int blink_cur; + int blinktext; + int cjk_ambig_wide; + int conf_height; + int conf_width; + int crhaslf; + int erase_to_scrollback; + int funky_type; + int lfhascr; + int logflush; + int logtype; + int mouse_override; + int nethack_keypad; + int no_alt_screen; + int no_applic_c; + int no_applic_k; + int no_dbackspace; + int no_mouse_rep; + int no_remote_charset; + int no_remote_resize; + int no_remote_wintitle; + int rawcnp; + int rect_select; + int remote_qtitle_action; + int rxvt_homeend; + int scroll_on_disp; + int scroll_on_key; + int xterm_256_colour; }; #define in_utf(term) ((term)->utf || (term)->ucsdata->line_codepage==CP_UTF8) diff --git a/testback.c b/testback.c index 0175e8e7..be1faf45 100644 --- a/testback.c +++ b/testback.c @@ -33,13 +33,13 @@ #include "putty.h" -static const char *null_init(void *, void **, Config *, char *, int, char **, +static const char *null_init(void *, void **, Conf *, char *, int, char **, int, int); -static const char *loop_init(void *, void **, Config *, char *, int, char **, +static const char *loop_init(void *, void **, Conf *, char *, int, char **, int, int); static void null_free(void *); static void loop_free(void *); -static void null_reconfig(void *, Config *); +static void null_reconfig(void *, Conf *); static int null_send(void *, char *, int); static int loop_send(void *, char *, int); static int null_sendbuffer(void *); @@ -74,14 +74,14 @@ struct loop_state { }; static const char *null_init(void *frontend_handle, void **backend_handle, - Config *cfg, char *host, int port, + Conf *conf, char *host, int port, char **realhost, int nodelay, int keepalive) { return NULL; } static const char *loop_init(void *frontend_handle, void **backend_handle, - Config *cfg, char *host, int port, + Conf *conf, char *host, int port, char **realhost, int nodelay, int keepalive) { struct loop_state *st = snew(struct loop_state); @@ -101,7 +101,7 @@ static void loop_free(void *handle) sfree(handle); } -static void null_reconfig(void *handle, Config *cfg) { +static void null_reconfig(void *handle, Conf *conf) { } diff --git a/unix/gtkcfg.c b/unix/gtkcfg.c index 8cbdd514..ab8ef973 100644 --- a/unix/gtkcfg.c +++ b/unix/gtkcfg.c @@ -42,8 +42,8 @@ void gtk_setup_config_box(struct controlbox *b, int midsession, void *win) "Control the scrollback in the window"); ctrl_checkbox(s, "Scrollbar on left", 'l', HELPCTX(no_help), - dlg_stdcheckbox_handler, - I(offsetof(Config,scrollbar_on_left))); + conf_checkbox_handler, + I(CONF_scrollbar_on_left)); /* * Really this wants to go just after `Display scrollbar'. See * if we can find that control, and do some shuffling. @@ -51,7 +51,7 @@ void gtk_setup_config_box(struct controlbox *b, int midsession, void *win) for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_CHECKBOX && - c->generic.context.i == offsetof(Config,scrollbar)) { + c->generic.context.i == CONF_scrollbar) { /* * Control i is the scrollbar checkbox. * Control s->ncontrols-1 is the scrollbar-on-left one. @@ -89,29 +89,29 @@ void gtk_setup_config_box(struct controlbox *b, int midsession, void *win) "Fonts for displaying non-bold text"); ctrl_fontsel(s, "Font used for ordinary text", 'f', HELPCTX(no_help), - dlg_stdfontsel_handler, I(offsetof(Config,font))); + conf_fontsel_handler, I(CONF_font)); ctrl_fontsel(s, "Font used for wide (CJK) text", 'w', HELPCTX(no_help), - dlg_stdfontsel_handler, I(offsetof(Config,widefont))); + conf_fontsel_handler, I(CONF_widefont)); s = ctrl_getset(b, "Window/Fonts", "fontbold", "Fonts for displaying bolded text"); ctrl_fontsel(s, "Font used for bolded text", 'b', HELPCTX(no_help), - dlg_stdfontsel_handler, I(offsetof(Config,boldfont))); + conf_fontsel_handler, I(CONF_boldfont)); ctrl_fontsel(s, "Font used for bold wide text", 'i', HELPCTX(no_help), - dlg_stdfontsel_handler, I(offsetof(Config,wideboldfont))); + conf_fontsel_handler, I(CONF_wideboldfont)); ctrl_checkbox(s, "Use shadow bold instead of bold fonts", 'u', HELPCTX(no_help), - dlg_stdcheckbox_handler, - I(offsetof(Config,shadowbold))); + conf_checkbox_handler, + I(CONF_shadowbold)); ctrl_text(s, "(Note that bold fonts or shadow bolding are only" " used if you have not requested bolding to be done by" " changing the text colour.)", HELPCTX(no_help)); ctrl_editbox(s, "Horizontal offset for shadow bold:", 'z', 20, - HELPCTX(no_help), dlg_stdeditbox_handler, - I(offsetof(Config,shadowboldoffset)), I(-1)); + HELPCTX(no_help), conf_editbox_handler, + I(CONF_shadowboldoffset), I(-1)); /* * Markus Kuhn feels, not totally unreasonably, that it's good @@ -125,8 +125,8 @@ void gtk_setup_config_box(struct controlbox *b, int midsession, void *win) "Character set translation on received data"); ctrl_checkbox(s, "Override with UTF-8 if locale says so", 'l', HELPCTX(translation_utf8_override), - dlg_stdcheckbox_handler, - I(offsetof(Config,utf8_override))); + conf_checkbox_handler, + I(CONF_utf8_override)); if (!midsession) { /* @@ -137,8 +137,7 @@ void gtk_setup_config_box(struct controlbox *b, int midsession, void *win) s = ctrl_getset(b, "Window/Behaviour", "x11", "X Window System settings"); ctrl_editbox(s, "Window class name:", 'z', 50, - HELPCTX(no_help), dlg_stdeditbox_handler, - I(offsetof(Config,winclass)), - I(sizeof(((Config *)0)->winclass))); + HELPCTX(no_help), conf_editbox_handler, + I(CONF_winclass), I(1)); } } diff --git a/unix/gtkdlg.c b/unix/gtkdlg.c index 5472ca62..ec7ae432 100644 --- a/unix/gtkdlg.c +++ b/unix/gtkdlg.c @@ -330,11 +330,10 @@ void dlg_editbox_set(union control *ctrl, void *dlg, char const *text) * The first call to "changed", if allowed to proceed normally, * will cause an EVENT_VALCHANGE event on the edit box, causing * a call to dlg_editbox_get() which will read the empty string - * out of the GtkEntry - and promptly write it straight into - * the Config structure, which is precisely where our `text' - * pointer is probably pointing, so the second editing - * operation will insert that instead of the string we - * originally asked for. + * out of the GtkEntry - and promptly write it straight into the + * Conf structure, which is precisely where our `text' pointer + * is probably pointing, so the second editing operation will + * insert that instead of the string we originally asked for. * * Hence, we must take our own copy of the text before we do * this. @@ -344,7 +343,7 @@ void dlg_editbox_set(union control *ctrl, void *dlg, char const *text) sfree(tmpstring); } -void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length) +char *dlg_editbox_get(union control *ctrl, void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; struct uctrl *uc = dlg_find_byctrl(dp, ctrl); @@ -353,25 +352,16 @@ void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length) #if GTK_CHECK_VERSION(2,4,0) if (uc->combo) { #if GTK_CHECK_VERSION(2,6,0) - strncpy(buffer, - gtk_combo_box_get_active_text(GTK_COMBO_BOX(uc->combo)), - length); + return dupstr(gtk_combo_box_get_active_text(GTK_COMBO_BOX(uc->combo))); #else - strncpy(buffer, - gtk_entry_get_text - (GTK_ENTRY(gtk_bin_get_child(GTK_BIN(uc->combo)))), - length); + return dupstr(gtk_entry_get_text + (GTK_ENTRY(gtk_bin_get_child(GTK_BIN(uc->combo))))); #endif - buffer[length-1] = '\0'; - return; } #endif if (uc->entry) { - strncpy(buffer, gtk_entry_get_text(GTK_ENTRY(uc->entry)), - length); - buffer[length-1] = '\0'; - return; + return dupstr(gtk_entry_get_text(GTK_ENTRY(uc->entry))); } assert(!"We shouldn't get here"); @@ -2826,12 +2816,12 @@ void set_dialog_action_area(GtkDialog *dlg, GtkWidget *w) #endif } -int do_config_box(const char *title, Config *cfg, int midsession, +int do_config_box(const char *title, Conf *conf, int midsession, int protcfginfo) { GtkWidget *window, *hbox, *vbox, *cols, *label, *tree, *treescroll, *panels, *panelvbox; - int index, level; + int index, level, protocol; struct controlbox *ctrlbox; char *path; #if GTK_CHECK_VERSION(2,0,0) @@ -2859,8 +2849,9 @@ int do_config_box(const char *title, Config *cfg, int midsession, window = gtk_dialog_new(); ctrlbox = ctrl_new_box(); - setup_config_box(ctrlbox, midsession, cfg->protocol, protcfginfo); - unix_setup_config_box(ctrlbox, midsession, cfg->protocol); + protocol = conf_get_int(conf, CONF_protocol); + setup_config_box(ctrlbox, midsession, protocol, protcfginfo); + unix_setup_config_box(ctrlbox, midsession, protocol); gtk_setup_config_box(ctrlbox, midsession, window); gtk_window_set_title(GTK_WINDOW(window), title); @@ -3095,7 +3086,7 @@ int do_config_box(const char *title, Config *cfg, int midsession, } #endif - dp.data = cfg; + dp.data = conf; dlg_refresh(NULL, &dp); dp.shortcuts = &selparams[0].shortcuts; diff --git a/unix/gtkwin.c b/unix/gtkwin.c index be8b2c3b..c43c4e3a 100644 --- a/unix/gtkwin.c +++ b/unix/gtkwin.c @@ -45,7 +45,6 @@ ASSERT(sizeof(long) <= sizeof(gpointer)); #endif /* Colours come in two flavours: configurable, and xterm-extended. */ -#define NCFGCOLOURS (lenof(((Config *)0)->colours)) #define NEXTCOLOURS 240 /* 216 colour-cube plus 24 shades of grey */ #define NALLCOLOURS (NCFGCOLOURS + NEXTCOLOURS) @@ -88,8 +87,8 @@ struct gui_data { guint term_exit_idle_id; int alt_keycode; int alt_digits; - char wintitle[sizeof(((Config *)0)->wintitle)]; - char icontitle[sizeof(((Config *)0)->wintitle)]; + char *wintitle; + char *icontitle; int master_fd, master_func_id; void *ldisc; Backend *back; @@ -98,14 +97,25 @@ struct gui_data { void *logctx; int exited; struct unicode_data ucsdata; - Config cfg; + Conf *conf; void *eventlogstuff; char *progname, **gtkargvstart; int ngtkargs; guint32 input_event_time; /* Timestamp of the most recent input event. */ int reconfiguring; + /* Cached things out of conf that we refer to a lot */ + int bold_colour; + int window_border; + int cursor_type; }; +static void cache_conf_values(struct gui_data *inst) +{ + inst->bold_colour = conf_get_int(inst->conf, CONF_bold_colour); + inst->window_border = conf_get_int(inst->conf, CONF_window_border); + inst->cursor_type = conf_get_int(inst->conf, CONF_cursor_type); +} + struct draw_ctx { GdkGC *gc; struct gui_data *inst; @@ -134,7 +144,7 @@ void connection_fatal(void *frontend, char *p, ...) inst->exited = TRUE; fatal_message_box(inst->window, msg); sfree(msg); - if (inst->cfg.close_on_exit == FORCE_ON) + if (conf_get_int(inst->conf, CONF_close_on_exit) == FORCE_ON) cleanup_exit(1); } @@ -394,7 +404,7 @@ char *get_window_title(void *frontend, int icon) gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data) { struct gui_data *inst = (struct gui_data *)data; - if (!inst->exited && inst->cfg.warn_on_close) { + if (!inst->exited && conf_get_int(inst->conf, CONF_warn_on_close)) { if (!reallyclose(inst)) return TRUE; } @@ -425,7 +435,7 @@ static void update_mouseptr(struct gui_data *inst) static void show_mouseptr(struct gui_data *inst, int show) { - if (!inst->cfg.hide_mouseptr) + if (!conf_get_int(inst->conf, CONF_hide_mouseptr)) show = 1; inst->mouseptr_visible = show; update_mouseptr(inst); @@ -436,8 +446,8 @@ void draw_backing_rect(struct gui_data *inst) GdkGC *gc = gdk_gc_new(inst->area->window); gdk_gc_set_foreground(gc, &inst->cols[258]); /* default background */ gdk_draw_rectangle(inst->pixmap, gc, 1, 0, 0, - inst->cfg.width * inst->font_width + 2*inst->cfg.window_border, - inst->cfg.height * inst->font_height + 2*inst->cfg.window_border); + inst->width * inst->font_width + 2*inst->window_border, + inst->height * inst->font_height + 2*inst->window_border); gdk_gc_unref(gc); } @@ -450,11 +460,13 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data) * See if the terminal size has changed, in which case we must * let the terminal know. */ - w = (event->width - 2*inst->cfg.window_border) / inst->font_width; - h = (event->height - 2*inst->cfg.window_border) / inst->font_height; + w = (event->width - 2*inst->window_border) / inst->font_width; + h = (event->height - 2*inst->window_border) / inst->font_height; if (w != inst->width || h != inst->height) { - inst->cfg.width = inst->width = w; - inst->cfg.height = inst->height = h; + inst->width = w; + inst->height = h; + conf_set_int(inst->conf, CONF_width, inst->width); + conf_set_int(inst->conf, CONF_height, inst->height); need_size = 1; } @@ -464,15 +476,13 @@ gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data) } inst->pixmap = gdk_pixmap_new(widget->window, - (inst->cfg.width * inst->font_width + - 2*inst->cfg.window_border), - (inst->cfg.height * inst->font_height + - 2*inst->cfg.window_border), -1); + (w * inst->font_width + 2*inst->window_border), + (h * inst->font_height + 2*inst->window_border), -1); draw_backing_rect(inst); if (need_size && inst->term) { - term_size(inst->term, h, w, inst->cfg.savelines); + term_size(inst->term, h, w, conf_get_int(inst->conf, CONF_savelines)); } if (inst->term) @@ -618,7 +628,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * at all. */ if (event->keyval == GDK_Page_Up && (event->state & GDK_SHIFT_MASK)) { - term_scroll(inst->term, 0, -inst->cfg.height/2); + term_scroll(inst->term, 0, -inst->height/2); return TRUE; } if (event->keyval == GDK_Page_Up && (event->state & GDK_CONTROL_MASK)) { @@ -626,7 +636,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) return TRUE; } if (event->keyval == GDK_Page_Down && (event->state & GDK_SHIFT_MASK)) { - term_scroll(inst->term, 0, +inst->cfg.height/2); + term_scroll(inst->term, 0, +inst->height/2); return TRUE; } if (event->keyval == GDK_Page_Down && (event->state & GDK_CONTROL_MASK)) { @@ -755,7 +765,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) /* We don't let GTK tell us what Backspace is! We know better. */ if (event->keyval == GDK_BackSpace && !(event->state & GDK_SHIFT_MASK)) { - output[1] = inst->cfg.bksp_is_delete ? '\x7F' : '\x08'; + output[1] = conf_get_int(inst->conf, CONF_bksp_is_delete) ? + '\x7F' : '\x08'; use_ucsoutput = FALSE; end = 2; special = TRUE; @@ -763,7 +774,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) /* For Shift Backspace, do opposite of what is configured. */ if (event->keyval == GDK_BackSpace && (event->state & GDK_SHIFT_MASK)) { - output[1] = inst->cfg.bksp_is_delete ? '\x08' : '\x7F'; + output[1] = conf_get_int(inst->conf, CONF_bksp_is_delete) ? + '\x08' : '\x7F'; use_ucsoutput = FALSE; end = 2; special = TRUE; @@ -786,7 +798,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) /* * NetHack keypad mode. */ - if (inst->cfg.nethack_keypad) { + if (conf_get_int(inst->conf, CONF_nethack_keypad)) { char *keys = NULL; switch (event->keyval) { case GDK_KP_1: case GDK_KP_End: keys = "bB\002"; break; @@ -815,7 +827,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) /* * Application keypad mode. */ - if (inst->term->app_keypad_keys && !inst->cfg.no_applic_k) { + if (inst->term->app_keypad_keys && + !conf_get_int(inst->conf, CONF_no_applic_k)) { int xkey = 0; switch (event->keyval) { case GDK_Num_Lock: xkey = 'P'; break; @@ -829,7 +842,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) * in xterm function key mode we change which two... */ case GDK_KP_Add: - if (inst->cfg.funky_type == FUNKY_XTERM) { + if (conf_get_int(inst->conf, CONF_funky_type) == FUNKY_XTERM) { if (event->state & GDK_SHIFT_MASK) xkey = 'l'; else @@ -876,6 +889,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) */ { int code = 0; + int funky_type = conf_get_int(inst->conf, CONF_funky_type); switch (event->keyval) { case GDK_F1: code = (event->state & GDK_SHIFT_MASK ? 23 : 11); @@ -959,7 +973,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) break; } /* Reorder edit keys to physical order */ - if (inst->cfg.funky_type == FUNKY_VT400 && code <= 6) + if (funky_type == FUNKY_VT400 && code <= 6) code = "\0\2\1\4\5\3\6"[code]; if (inst->term->vt52_mode && code > 0 && code <= 6) { @@ -968,7 +982,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) goto done; } - if (inst->cfg.funky_type == FUNKY_SCO && /* SCO function keys */ + if (funky_type == FUNKY_SCO && /* SCO function keys */ code >= 11 && code <= 34) { char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{"; int index = 0; @@ -992,7 +1006,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) use_ucsoutput = FALSE; goto done; } - if (inst->cfg.funky_type == FUNKY_SCO && /* SCO small keypad */ + if (funky_type == FUNKY_SCO && /* SCO small keypad */ code >= 1 && code <= 6) { char codes[] = "HL.FIG"; if (code == 3) { @@ -1004,7 +1018,7 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) use_ucsoutput = FALSE; goto done; } - if ((inst->term->vt52_mode || inst->cfg.funky_type == FUNKY_VT100P) && + if ((inst->term->vt52_mode || funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) { int offt = 0; if (code > 15) @@ -1020,12 +1034,12 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) use_ucsoutput = FALSE; goto done; } - if (inst->cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { + if (funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { end = 1 + sprintf(output+1, "\x1B[[%c", code + 'A' - 11); use_ucsoutput = FALSE; goto done; } - if (inst->cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { + if (funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { if (inst->term->vt52_mode) end = 1 + sprintf(output+1, "\x1B%c", code + 'P' - 11); else @@ -1033,7 +1047,8 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data) use_ucsoutput = FALSE; goto done; } - if (inst->cfg.rxvt_homeend && (code == 1 || code == 4)) { + if ((code == 1 || code == 4) && + conf_get_int(inst->conf, CONF_rxvt_homeend)) { end = 1 + sprintf(output+1, code == 1 ? "\x1B[H" : "\x1BOw"); use_ucsoutput = FALSE; goto done; @@ -1166,12 +1181,13 @@ gboolean button_internal(struct gui_data *inst, guint32 timestamp, default: return FALSE; /* don't know this event type */ } - if (send_raw_mouse && !(inst->cfg.mouse_override && shift) && + if (send_raw_mouse && !(shift && conf_get_int(inst->conf, + CONF_mouse_override)) && act != MA_CLICK && act != MA_RELEASE) return TRUE; /* we ignore these in raw mouse mode */ - x = (ex - inst->cfg.window_border) / inst->font_width; - y = (ey - inst->cfg.window_border) / inst->font_height; + x = (ex - inst->window_border) / inst->font_width; + y = (ey - inst->window_border) / inst->font_height; term_mouse(inst->term, button, translate_button(button), act, x, y, shift, ctrl, alt); @@ -1231,8 +1247,8 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) else return FALSE; /* don't even know what button! */ - x = (event->x - inst->cfg.window_border) / inst->font_width; - y = (event->y - inst->cfg.window_border) / inst->font_height; + x = (event->x - inst->window_border) / inst->font_width; + y = (event->y - inst->window_border) / inst->font_height; term_mouse(inst->term, button, translate_button(button), MA_DRAG, x, y, shift, ctrl, alt); @@ -1255,13 +1271,14 @@ void frontend_keypress(void *handle) static gint idle_exit_func(gpointer data) { struct gui_data *inst = (struct gui_data *)data; - int exitcode; + int exitcode, close_on_exit; if (!inst->exited && (exitcode = inst->back->exitcode(inst->backhandle)) >= 0) { inst->exited = TRUE; - if (inst->cfg.close_on_exit == FORCE_ON || - (inst->cfg.close_on_exit == AUTO && exitcode == 0)) + close_on_exit = conf_get_int(inst->conf, CONF_close_on_exit); + if (close_on_exit == FORCE_ON || + (close_on_exit == AUTO && exitcode == 0)) gtk_main_quit(); /* just go */ if (inst->ldisc) { ldisc_free(inst->ldisc); @@ -1364,7 +1381,7 @@ void set_busy_status(void *frontend, int status) void set_raw_mouse_mode(void *frontend, int activate) { struct gui_data *inst = (struct gui_data *)frontend; - activate = activate && !inst->cfg.no_mouse_rep; + activate = activate && !conf_get_int(inst->conf, CONF_no_mouse_rep); send_raw_mouse = activate; update_mouseptr(inst); } @@ -1412,8 +1429,8 @@ void request_resize(void *frontend, int w, int h) offset_x = outer.width - inner.width; offset_y = outer.height - inner.height; - area_x = inst->font_width * w + 2*inst->cfg.window_border; - area_y = inst->font_height * h + 2*inst->cfg.window_border; + area_x = inst->font_width * w + 2*inst->window_border; + area_y = inst->font_height * h + 2*inst->window_border; /* * Now we must set the size request on the drawing area back to @@ -1495,7 +1512,7 @@ void palette_set(void *frontend, int n, int r, int g, int b) void palette_reset(void *frontend) { struct gui_data *inst = (struct gui_data *)frontend; - /* This maps colour indices in inst->cfg to those used in inst->cols. */ + /* This maps colour indices in inst->conf to those used in inst->cols. */ static const int ww[] = { 256, 257, 258, 259, 260, 261, 0, 8, 1, 9, 2, 10, 3, 11, @@ -1513,9 +1530,12 @@ void palette_reset(void *frontend) } for (i = 0; i < NCFGCOLOURS; i++) { - inst->cols[ww[i]].red = inst->cfg.colours[i][0] * 0x0101; - inst->cols[ww[i]].green = inst->cfg.colours[i][1] * 0x0101; - inst->cols[ww[i]].blue = inst->cfg.colours[i][2] * 0x0101; + inst->cols[ww[i]].red = + conf_get_int_int(inst->conf, CONF_colours, i*3+0) * 0x0101; + inst->cols[ww[i]].green = + conf_get_int_int(inst->conf, CONF_colours, i*3+1) * 0x0101; + inst->cols[ww[i]].blue = + conf_get_int_int(inst->conf, CONF_colours, i*3+2) * 0x0101; } for (i = 0; i < NEXTCOLOURS; i++) { @@ -1537,8 +1557,10 @@ void palette_reset(void *frontend) for (i = 0; i < NALLCOLOURS; i++) { if (!success[i]) g_error("%s: couldn't allocate colour %d (#%02x%02x%02x)\n", - appname, i, inst->cfg.colours[i][0], - inst->cfg.colours[i][1], inst->cfg.colours[i][2]); + appname, i, + conf_get_int_int(inst->conf, CONF_colours, i*3+0), + conf_get_int_int(inst->conf, CONF_colours, i*3+1), + conf_get_int_int(inst->conf, CONF_colours, i*3+2)); } /* Since Default Background may have changed, ensure that space @@ -1898,30 +1920,40 @@ static void set_window_titles(struct gui_data *inst) * is life. */ gtk_window_set_title(GTK_WINDOW(inst->window), inst->wintitle); - if (!inst->cfg.win_name_always) + if (!conf_get_int(inst->conf, CONF_win_name_always)) gdk_window_set_icon_name(inst->window->window, inst->icontitle); } void set_title(void *frontend, char *title) { struct gui_data *inst = (struct gui_data *)frontend; - strncpy(inst->wintitle, title, lenof(inst->wintitle)); - inst->wintitle[lenof(inst->wintitle)-1] = '\0'; + sfree(inst->wintitle); + inst->wintitle = dupstr(title); set_window_titles(inst); } void set_icon(void *frontend, char *title) { struct gui_data *inst = (struct gui_data *)frontend; - strncpy(inst->icontitle, title, lenof(inst->icontitle)); - inst->icontitle[lenof(inst->icontitle)-1] = '\0'; + sfree(inst->icontitle); + inst->icontitle = dupstr(title); + set_window_titles(inst); +} + +void set_title_and_icon(void *frontend, char *title, char *icon) +{ + struct gui_data *inst = (struct gui_data *)frontend; + sfree(inst->wintitle); + inst->wintitle = dupstr(title); + sfree(inst->icontitle); + inst->icontitle = dupstr(icon); set_window_titles(inst); } void set_sbar(void *frontend, int total, int start, int page) { struct gui_data *inst = (struct gui_data *)frontend; - if (!inst->cfg.scrollbar) + if (!conf_get_int(inst->conf, CONF_scrollbar)) return; inst->sbar_adjust->lower = 0; inst->sbar_adjust->upper = total; @@ -1938,7 +1970,7 @@ void scrollbar_moved(GtkAdjustment *adj, gpointer data) { struct gui_data *inst = (struct gui_data *)data; - if (!inst->cfg.scrollbar) + if (!conf_get_int(inst->conf, CONF_scrollbar)) return; if (!inst->ignore_sbar) term_scroll(inst->term, 1, (int)adj->value); @@ -2027,11 +2059,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, nfg = nbg; nbg = t; } - if (inst->cfg.bold_colour && (attr & ATTR_BOLD)) { + if (inst->bold_colour && (attr & ATTR_BOLD)) { if (nfg < 16) nfg |= 8; else if (nfg >= 256) nfg |= 1; } - if (inst->cfg.bold_colour && (attr & ATTR_BLINK)) { + if (inst->bold_colour && (attr & ATTR_BLINK)) { if (nbg < 16) nbg |= 8; else if (nbg >= 256) nbg |= 1; } @@ -2049,7 +2081,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, widefactor = 1; } - if ((attr & ATTR_BOLD) && !inst->cfg.bold_colour) { + if ((attr & ATTR_BOLD) && !inst->bold_colour) { bold = 1; fontid |= 1; } else { @@ -2086,8 +2118,8 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, { GdkRectangle r; - r.x = x*inst->font_width+inst->cfg.window_border; - r.y = y*inst->font_height+inst->cfg.window_border; + r.x = x*inst->font_width+inst->window_border; + r.y = y*inst->font_height+inst->window_border; r.width = rlen*widefactor*inst->font_width; r.height = inst->font_height; gdk_gc_set_clip_rectangle(gc, &r); @@ -2095,8 +2127,8 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, gdk_gc_set_foreground(gc, &inst->cols[nbg]); gdk_draw_rectangle(inst->pixmap, gc, 1, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border, + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border, rlen*widefactor*inst->font_width, inst->font_height); gdk_gc_set_foreground(gc, &inst->cols[nfg]); @@ -2116,8 +2148,8 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, text + combining, len, gcs, len*10+1, ".", NULL, NULL); unifont_draw_text(inst->pixmap, gc, inst->fonts[fontid], - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border+inst->fonts[0]->ascent, + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border+inst->fonts[0]->ascent, gcs, mblen, widefactor > 1, bold, inst->font_width); } @@ -2128,10 +2160,10 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, int uheight = inst->fonts[0]->ascent + 1; if (uheight >= inst->font_height) uheight = inst->font_height - 1; - gdk_draw_line(inst->pixmap, gc, x*inst->font_width+inst->cfg.window_border, - y*inst->font_height + uheight + inst->cfg.window_border, - (x+len)*widefactor*inst->font_width-1+inst->cfg.window_border, - y*inst->font_height + uheight + inst->cfg.window_border); + gdk_draw_line(inst->pixmap, gc, x*inst->font_width+inst->window_border, + y*inst->font_height + uheight + inst->window_border, + (x+len)*widefactor*inst->font_width-1+inst->window_border, + y*inst->font_height + uheight + inst->window_border); } if ((lattr & LATTR_MODE) != LATTR_NORM) { @@ -2146,10 +2178,10 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, int i; for (i = 0; i < len * widefactor * inst->font_width; i++) { gdk_draw_pixmap(inst->pixmap, gc, inst->pixmap, - x*inst->font_width+inst->cfg.window_border + 2*i, - y*inst->font_height+inst->cfg.window_border, - x*inst->font_width+inst->cfg.window_border + 2*i+1, - y*inst->font_height+inst->cfg.window_border, + x*inst->font_width+inst->window_border + 2*i, + y*inst->font_height+inst->window_border, + x*inst->font_width+inst->window_border + 2*i+1, + y*inst->font_height+inst->window_border, len * widefactor * inst->font_width - i, inst->font_height); } len *= 2; @@ -2162,10 +2194,10 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, dt = 1, db = 0; for (i = 0; i < inst->font_height; i+=2) { gdk_draw_pixmap(inst->pixmap, gc, inst->pixmap, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border+dt*i+db, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border+dt*(i+1), + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border+dt*i+db, + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border+dt*(i+1), len * widefactor * inst->font_width, inst->font_height-i-1); } } @@ -2198,10 +2230,10 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, } gdk_draw_pixmap(inst->area->window, gc, inst->pixmap, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border, + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border, + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border, len*widefactor*inst->font_width, inst->font_height); } @@ -2219,7 +2251,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, passive = 1; } else passive = 0; - if ((attr & TATTR_ACTCURS) && inst->cfg.cursor_type != 0) { + if ((attr & TATTR_ACTCURS) && inst->cursor_type != 0) { attr &= ~TATTR_ACTCURS; active = 1; } else @@ -2244,7 +2276,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, len *= 2; } - if (inst->cfg.cursor_type == 0) { + if (inst->cursor_type == 0) { /* * An active block cursor will already have been done by * the above do_text call, so we only need to do anything @@ -2253,8 +2285,8 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, if (passive) { gdk_gc_set_foreground(gc, &inst->cols[261]); gdk_draw_rectangle(inst->pixmap, gc, 0, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border, + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border, len*widefactor*inst->font_width-1, inst->font_height-1); } } else { @@ -2268,13 +2300,13 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, else char_width = inst->font_width; - if (inst->cfg.cursor_type == 1) { + if (inst->cursor_type == 1) { uheight = inst->fonts[0]->ascent + 1; if (uheight >= inst->font_height) uheight = inst->font_height - 1; - startx = x * inst->font_width + inst->cfg.window_border; - starty = y * inst->font_height + inst->cfg.window_border + uheight; + startx = x * inst->font_width + inst->window_border; + starty = y * inst->font_height + inst->window_border + uheight; dx = 1; dy = 0; length = len * widefactor * char_width; @@ -2282,8 +2314,8 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, int xadjust = 0; if (attr & TATTR_RIGHTCURS) xadjust = char_width - 1; - startx = x * inst->font_width + inst->cfg.window_border + xadjust; - starty = y * inst->font_height + inst->cfg.window_border; + startx = x * inst->font_width + inst->window_border + xadjust; + starty = y * inst->font_height + inst->window_border; dx = 0; dy = 1; length = inst->font_height; @@ -2305,10 +2337,10 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, } gdk_draw_pixmap(inst->area->window, gc, inst->pixmap, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border, - x*inst->font_width+inst->cfg.window_border, - y*inst->font_height+inst->cfg.window_border, + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border, + x*inst->font_width+inst->window_border, + y*inst->font_height+inst->window_border, len*widefactor*inst->font_width, inst->font_height); } @@ -2468,7 +2500,7 @@ static void help(FILE *fp) { } int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, - struct gui_data *inst, Config *cfg) + struct gui_data *inst, Conf *conf) { int err = 0; char *val; @@ -2507,7 +2539,7 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, p = "-title"; ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), - do_everything ? 1 : -1, cfg); + do_everything ? 1 : -1, conf); if (ret == -2) { cmdline_error("option \"%s\" requires an argument", p); @@ -2519,34 +2551,41 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, } if (!strcmp(p, "-fn") || !strcmp(p, "-font")) { + FontSpec fs; EXPECTS_ARG; SECOND_PASS_ONLY; - strncpy(cfg->font.name, val, sizeof(cfg->font.name)); - cfg->font.name[sizeof(cfg->font.name)-1] = '\0'; + strncpy(fs.name, val, sizeof(fs.name)); + fs.name[sizeof(fs.name)-1] = '\0'; + conf_set_fontspec(conf, CONF_font, &fs); } else if (!strcmp(p, "-fb")) { + FontSpec fs; EXPECTS_ARG; SECOND_PASS_ONLY; - strncpy(cfg->boldfont.name, val, sizeof(cfg->boldfont.name)); - cfg->boldfont.name[sizeof(cfg->boldfont.name)-1] = '\0'; + strncpy(fs.name, val, sizeof(fs.name)); + fs.name[sizeof(fs.name)-1] = '\0'; + conf_set_fontspec(conf, CONF_boldfont, &fs); } else if (!strcmp(p, "-fw")) { + FontSpec fs; EXPECTS_ARG; SECOND_PASS_ONLY; - strncpy(cfg->widefont.name, val, sizeof(cfg->widefont.name)); - cfg->widefont.name[sizeof(cfg->widefont.name)-1] = '\0'; + strncpy(fs.name, val, sizeof(fs.name)); + fs.name[sizeof(fs.name)-1] = '\0'; + conf_set_fontspec(conf, CONF_widefont, &fs); } else if (!strcmp(p, "-fwb")) { + FontSpec fs; EXPECTS_ARG; SECOND_PASS_ONLY; - strncpy(cfg->wideboldfont.name, val, sizeof(cfg->wideboldfont.name)); - cfg->wideboldfont.name[sizeof(cfg->wideboldfont.name)-1] = '\0'; + strncpy(fs.name, val, sizeof(fs.name)); + fs.name[sizeof(fs.name)-1] = '\0'; + conf_set_fontspec(conf, CONF_wideboldfont, &fs); } else if (!strcmp(p, "-cs")) { EXPECTS_ARG; SECOND_PASS_ONLY; - strncpy(cfg->line_codepage, val, sizeof(cfg->line_codepage)); - cfg->line_codepage[sizeof(cfg->line_codepage)-1] = '\0'; + conf_set_str(conf, CONF_line_codepage, val); } else if (!strcmp(p, "-geometry")) { int flags, x, y; @@ -2556,9 +2595,9 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, flags = XParseGeometry(val, &x, &y, &w, &h); if (flags & WidthValue) - cfg->width = (int)w; + conf_set_int(conf, CONF_width, w); if (flags & HeightValue) - cfg->height = (int)h; + conf_set_int(conf, CONF_height, h); if (flags & (XValue | YValue)) { inst->xpos = x; @@ -2571,7 +2610,7 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, } else if (!strcmp(p, "-sl")) { EXPECTS_ARG; SECOND_PASS_ONLY; - cfg->savelines = atoi(val); + conf_set_int(conf, CONF_savelines, atoi(val)); } else if (!strcmp(p, "-fg") || !strcmp(p, "-bg") || !strcmp(p, "-bfg") || !strcmp(p, "-bbg") || @@ -2593,9 +2632,9 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, !strcmp(p, "-cfg") ? 4 : !strcmp(p, "-cbg") ? 5 : -1); assert(index != -1); - cfg->colours[index][0] = col.red / 256; - cfg->colours[index][1] = col.green / 256; - cfg->colours[index][2] = col.blue / 256; + conf_set_int_int(conf, CONF_colours, index*3+0, col.red / 256); + conf_set_int_int(conf, CONF_colours, index*3+1,col.green/ 256); + conf_set_int_int(conf, CONF_colours, index*3+2, col.blue/ 256); } } else if (use_pty_argv && !strcmp(p, "-e")) { @@ -2618,43 +2657,44 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, } else if (!strcmp(p, "-title")) { EXPECTS_ARG; SECOND_PASS_ONLY; - strncpy(cfg->wintitle, val, sizeof(cfg->wintitle)); - cfg->wintitle[sizeof(cfg->wintitle)-1] = '\0'; + conf_set_str(conf, CONF_wintitle, val); } else if (!strcmp(p, "-log")) { + Filename fn; EXPECTS_ARG; SECOND_PASS_ONLY; - strncpy(cfg->logfilename.path, val, sizeof(cfg->logfilename.path)); - cfg->logfilename.path[sizeof(cfg->logfilename.path)-1] = '\0'; - cfg->logtype = LGTYP_DEBUG; + strncpy(fn.path, val, sizeof(fn.path)); + fn.path[sizeof(fn.path)-1] = '\0'; + conf_set_filename(conf, CONF_logfilename, &fn); + conf_set_int(conf, CONF_logtype, LGTYP_DEBUG); } else if (!strcmp(p, "-ut-") || !strcmp(p, "+ut")) { SECOND_PASS_ONLY; - cfg->stamp_utmp = 0; + conf_set_int(conf, CONF_stamp_utmp, 0); } else if (!strcmp(p, "-ut")) { SECOND_PASS_ONLY; - cfg->stamp_utmp = 1; + conf_set_int(conf, CONF_stamp_utmp, 1); } else if (!strcmp(p, "-ls-") || !strcmp(p, "+ls")) { SECOND_PASS_ONLY; - cfg->login_shell = 0; + conf_set_int(conf, CONF_login_shell, 0); } else if (!strcmp(p, "-ls")) { SECOND_PASS_ONLY; - cfg->login_shell = 1; + conf_set_int(conf, CONF_login_shell, 1); } else if (!strcmp(p, "-nethack")) { SECOND_PASS_ONLY; - cfg->nethack_keypad = 1; + conf_set_int(conf, CONF_nethack_keypad, 1); } else if (!strcmp(p, "-sb-") || !strcmp(p, "+sb")) { SECOND_PASS_ONLY; - cfg->scrollbar = 0; + conf_set_int(conf, CONF_scrollbar, 0); } else if (!strcmp(p, "-sb")) { SECOND_PASS_ONLY; - cfg->scrollbar = 0; + conf_set_int(conf, CONF_scrollbar, 1); } else if (!strcmp(p, "-name")) { EXPECTS_ARG; @@ -2673,7 +2713,7 @@ int do_cmdline(int argc, char **argv, int do_everything, int *allow_launch, exit(1); } else if(p[0] != '-' && (!do_everything || - process_nonoption_arg(p, cfg, + process_nonoption_arg(p, conf, allow_launch))) { /* do nothing */ @@ -2701,6 +2741,10 @@ void uxsel_input_remove(int id) { void setup_fonts_ucs(struct gui_data *inst) { + int shadowbold = conf_get_int(inst->conf, CONF_shadowbold); + int shadowboldoffset = conf_get_int(inst->conf, CONF_shadowboldoffset); + FontSpec *fs; + if (inst->fonts[0]) unifont_destroy(inst->fonts[0]); if (inst->fonts[1]) @@ -2710,54 +2754,50 @@ void setup_fonts_ucs(struct gui_data *inst) if (inst->fonts[3]) unifont_destroy(inst->fonts[3]); - inst->fonts[0] = unifont_create(inst->area, inst->cfg.font.name, - FALSE, FALSE, - inst->cfg.shadowboldoffset, - inst->cfg.shadowbold); + fs = conf_get_fontspec(inst->conf, CONF_font); + inst->fonts[0] = unifont_create(inst->area, fs->name, FALSE, FALSE, + shadowboldoffset, shadowbold); if (!inst->fonts[0]) { fprintf(stderr, "%s: unable to load font \"%s\"\n", appname, - inst->cfg.font.name); + fs->name); exit(1); } - if (inst->cfg.shadowbold || !inst->cfg.boldfont.name[0]) { + fs = conf_get_fontspec(inst->conf, CONF_boldfont); + if (shadowbold || !fs->name[0]) { inst->fonts[1] = NULL; } else { - inst->fonts[1] = unifont_create(inst->area, inst->cfg.boldfont.name, - FALSE, TRUE, - inst->cfg.shadowboldoffset, - inst->cfg.shadowbold); + inst->fonts[1] = unifont_create(inst->area, fs->name, FALSE, TRUE, + shadowboldoffset, shadowbold); if (!inst->fonts[1]) { fprintf(stderr, "%s: unable to load bold font \"%s\"\n", appname, - inst->cfg.boldfont.name); + fs->name); exit(1); } } - if (inst->cfg.widefont.name[0]) { - inst->fonts[2] = unifont_create(inst->area, inst->cfg.widefont.name, - TRUE, FALSE, - inst->cfg.shadowboldoffset, - inst->cfg.shadowbold); + fs = conf_get_fontspec(inst->conf, CONF_widefont); + if (fs->name[0]) { + inst->fonts[2] = unifont_create(inst->area, fs->name, TRUE, FALSE, + shadowboldoffset, shadowbold); if (!inst->fonts[2]) { fprintf(stderr, "%s: unable to load wide font \"%s\"\n", appname, - inst->cfg.widefont.name); + fs->name); exit(1); } } else { inst->fonts[2] = NULL; } - if (inst->cfg.shadowbold || !inst->cfg.wideboldfont.name[0]) { + fs = conf_get_fontspec(inst->conf, CONF_wideboldfont); + if (shadowbold || !fs->name[0]) { inst->fonts[3] = NULL; } else { - inst->fonts[3] = unifont_create(inst->area, - inst->cfg.wideboldfont.name, TRUE, - TRUE, inst->cfg.shadowboldoffset, - inst->cfg.shadowbold); + inst->fonts[3] = unifont_create(inst->area, fs->name, TRUE, TRUE, + shadowboldoffset, shadowbold); if (!inst->fonts[3]) { fprintf(stderr, "%s: unable to load wide bold font \"%s\"\n", appname, - inst->cfg.boldfont.name); + fs->name); exit(1); } } @@ -2765,20 +2805,21 @@ void setup_fonts_ucs(struct gui_data *inst) inst->font_width = inst->fonts[0]->width; inst->font_height = inst->fonts[0]->height; - inst->direct_to_font = init_ucs(&inst->ucsdata, inst->cfg.line_codepage, - inst->cfg.utf8_override, + inst->direct_to_font = init_ucs(&inst->ucsdata, + conf_get_str(inst->conf, CONF_line_codepage), + conf_get_int(inst->conf, CONF_utf8_override), inst->fonts[0]->public_charset, - inst->cfg.vtmode); + conf_get_int(inst->conf, CONF_vtmode)); } void set_geom_hints(struct gui_data *inst) { GdkGeometry geom; - geom.min_width = inst->font_width + 2*inst->cfg.window_border; - geom.min_height = inst->font_height + 2*inst->cfg.window_border; + geom.min_width = inst->font_width + 2*inst->window_border; + geom.min_height = inst->font_height + 2*inst->window_border; geom.max_width = geom.max_height = -1; - geom.base_width = 2*inst->cfg.window_border; - geom.base_height = 2*inst->cfg.window_border; + geom.base_width = 2*inst->window_border; + geom.base_height = 2*inst->window_border; geom.width_inc = inst->font_width; geom.height_inc = inst->font_height; geom.min_aspect = geom.max_aspect = 0; @@ -2831,7 +2872,7 @@ void event_log_menuitem(GtkMenuItem *item, gpointer data) void change_settings_menuitem(GtkMenuItem *item, gpointer data) { - /* This maps colour indices in inst->cfg to those used in inst->cols. */ + /* This maps colour indices in inst->conf to those used in inst->cols. */ static const int ww[] = { 256, 257, 258, 259, 260, 261, 0, 8, 1, 9, 2, 10, 3, 11, @@ -2839,8 +2880,8 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) }; struct gui_data *inst = (struct gui_data *)data; char *title = dupcat(appname, " Reconfiguration", NULL); - Config cfg2, oldcfg; - int i, need_size; + Conf *oldconf, *newconf; + int i, j, need_size; assert(lenof(ww) == NCFGCOLOURS); @@ -2849,43 +2890,48 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) else inst->reconfiguring = TRUE; - cfg2 = inst->cfg; /* structure copy */ + oldconf = inst->conf; + newconf = conf_copy(inst->conf); - if (do_config_box(title, &cfg2, 1, + if (do_config_box(title, newconf, 1, inst->back?inst->back->cfg_info(inst->backhandle):0)) { - - oldcfg = inst->cfg; /* structure copy */ - inst->cfg = cfg2; /* structure copy */ + inst->conf = newconf; /* Pass new config data to the logging module */ - log_reconfig(inst->logctx, &cfg2); + log_reconfig(inst->logctx, inst->conf); /* * Flush the line discipline's edit buffer in the case * where local editing has just been disabled. */ + ldisc_configure(inst->ldisc, inst->conf); if (inst->ldisc) ldisc_send(inst->ldisc, NULL, 0, 0); /* Pass new config data to the terminal */ - term_reconfig(inst->term, &cfg2); + term_reconfig(inst->term, inst->conf); /* Pass new config data to the back end */ if (inst->back) - inst->back->reconfig(inst->backhandle, &cfg2); + inst->back->reconfig(inst->backhandle, inst->conf); + + cache_conf_values(inst); /* - * Just setting inst->cfg is sufficient to cause colour + * Just setting inst->conf is sufficient to cause colour * setting changes to appear on the next ESC]R palette * reset. But we should also check whether any colour - * settings have been changed, and revert the ones that - * have to the new default, on the assumption that the user - * is most likely to want an immediate update. + * settings have been changed, and revert the ones that have + * to the new default, on the assumption that the user is + * most likely to want an immediate update. */ for (i = 0; i < NCFGCOLOURS; i++) { - if (oldcfg.colours[i][0] != cfg2.colours[i][0] || - oldcfg.colours[i][1] != cfg2.colours[i][1] || - oldcfg.colours[i][2] != cfg2.colours[i][2]) { - real_palette_set(inst, ww[i], cfg2.colours[i][0], - cfg2.colours[i][1], - cfg2.colours[i][2]); + for (j = 0; j < 3; j++) + if (conf_get_int_int(oldconf, CONF_colours, i*3+j) != + conf_get_int_int(newconf, CONF_colours, i*3+j)) + break; + if (j < 3) { + real_palette_set(inst, ww[i], + conf_get_int_int(newconf,CONF_colours,i*3+0), + conf_get_int_int(newconf,CONF_colours,i*3+1), + conf_get_int_int(newconf,CONF_colours,i*3+2)); /* * If the default background has changed, we must @@ -2903,35 +2949,48 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) * If the scrollbar needs to be shown, hidden, or moved * from one end to the other of the window, do so now. */ - if (oldcfg.scrollbar != cfg2.scrollbar) { - if (cfg2.scrollbar) + if (conf_get_int(oldconf, CONF_scrollbar) != + conf_get_int(newconf, CONF_scrollbar)) { + if (conf_get_int(newconf, CONF_scrollbar)) gtk_widget_show(inst->sbar); else gtk_widget_hide(inst->sbar); } - if (oldcfg.scrollbar_on_left != cfg2.scrollbar_on_left) { + if (conf_get_int(oldconf, CONF_scrollbar_on_left) != + conf_get_int(newconf, CONF_scrollbar_on_left)) { gtk_box_reorder_child(inst->hbox, inst->sbar, - cfg2.scrollbar_on_left ? 0 : 1); + conf_get_int(newconf, CONF_scrollbar_on_left) + ? 0 : 1); } /* * Change the window title, if required. */ - if (strcmp(oldcfg.wintitle, cfg2.wintitle)) - set_title(inst, cfg2.wintitle); + if (strcmp(conf_get_str(oldconf, CONF_wintitle), + conf_get_str(newconf, CONF_wintitle))) + set_title(inst, conf_get_str(oldconf, CONF_wintitle)); set_window_titles(inst); /* * Redo the whole tangled fonts and Unicode mess if * necessary. */ - if (strcmp(oldcfg.font.name, cfg2.font.name) || - strcmp(oldcfg.boldfont.name, cfg2.boldfont.name) || - strcmp(oldcfg.widefont.name, cfg2.widefont.name) || - strcmp(oldcfg.wideboldfont.name, cfg2.wideboldfont.name) || - strcmp(oldcfg.line_codepage, cfg2.line_codepage) || - oldcfg.vtmode != cfg2.vtmode || - oldcfg.shadowbold != cfg2.shadowbold) { + if (strcmp(conf_get_fontspec(oldconf, CONF_font)->name, + conf_get_fontspec(newconf, CONF_font)->name) || + strcmp(conf_get_fontspec(oldconf, CONF_boldfont)->name, + conf_get_fontspec(newconf, CONF_boldfont)->name) || + strcmp(conf_get_fontspec(oldconf, CONF_widefont)->name, + conf_get_fontspec(newconf, CONF_widefont)->name) || + strcmp(conf_get_fontspec(oldconf, CONF_wideboldfont)->name, + conf_get_fontspec(newconf, CONF_wideboldfont)->name) || + strcmp(conf_get_str(oldconf, CONF_line_codepage), + conf_get_str(newconf, CONF_line_codepage)) || + conf_get_int(oldconf, CONF_vtmode) != + conf_get_int(newconf, CONF_vtmode) || + conf_get_int(oldconf, CONF_shadowbold) != + conf_get_int(newconf, CONF_shadowbold) || + conf_get_int(oldconf, CONF_shadowboldoffset) != + conf_get_int(newconf, CONF_shadowboldoffset)) { setup_fonts_ucs(inst); need_size = 1; } else @@ -2940,10 +2999,16 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) /* * Resize the window. */ - if (oldcfg.width != cfg2.width || oldcfg.height != cfg2.height || - oldcfg.window_border != cfg2.window_border || need_size) { + if (conf_get_int(oldconf, CONF_width) != + conf_get_int(newconf, CONF_width) || + conf_get_int(oldconf, CONF_height) != + conf_get_int(newconf, CONF_height) || + conf_get_int(oldconf, CONF_window_border) != + conf_get_int(newconf, CONF_window_border) || + need_size) { set_geom_hints(inst); - request_resize(inst, cfg2.width, cfg2.height); + request_resize(inst, conf_get_int(newconf, CONF_width), + conf_get_int(newconf, CONF_height)); } else { /* * The above will have caused a call to term_size() for @@ -2952,9 +3017,10 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) * happened and we will need an explicit term_size() * here. */ - if (oldcfg.savelines != cfg2.savelines) + if (conf_get_int(oldconf, CONF_savelines) != + conf_get_int(newconf, CONF_savelines)) term_size(inst->term, inst->term->rows, inst->term->cols, - cfg2.savelines); + conf_get_int(newconf, CONF_savelines)); } term_invalidate(inst->term); @@ -2964,6 +3030,10 @@ void change_settings_menuitem(GtkMenuItem *item, gpointer data) * border has been redrawn as well as the text area. */ gtk_widget_queue_draw(inst->area); + + conf_free(oldconf); + } else { + conf_free(newconf); } sfree(title); inst->reconfiguring = FALSE; @@ -3056,11 +3126,11 @@ void dup_session_menuitem(GtkMenuItem *item, gpointer gdata) { struct gui_data *inst = (struct gui_data *)gdata; /* - * For this feature we must marshal cfg and (possibly) pty_argv + * For this feature we must marshal conf and (possibly) pty_argv * into a byte stream, create a pipe, and send this byte stream * to the child through the pipe. */ - int i, ret, size; + int i, ret, sersize, size; char *data; char option[80]; int pipefd[2]; @@ -3070,16 +3140,16 @@ void dup_session_menuitem(GtkMenuItem *item, gpointer gdata) return; } - size = sizeof(inst->cfg); + size = sersize = conf_serialised_size(inst->conf); if (use_pty_argv && pty_argv) { for (i = 0; pty_argv[i]; i++) size += strlen(pty_argv[i]) + 1; } data = snewn(size, char); - memcpy(data, &inst->cfg, sizeof(inst->cfg)); + conf_serialise(inst->conf, data); if (use_pty_argv && pty_argv) { - int p = sizeof(inst->cfg); + int p = sersize; for (i = 0; pty_argv[i]; i++) { strcpy(data + p, pty_argv[i]); p += strlen(pty_argv[i]) + 1; @@ -3101,9 +3171,9 @@ void dup_session_menuitem(GtkMenuItem *item, gpointer gdata) sfree(data); } -int read_dupsession_data(struct gui_data *inst, Config *cfg, char *arg) +int read_dupsession_data(struct gui_data *inst, Conf *conf, char *arg) { - int fd, i, ret, size; + int fd, i, ret, size, size_used; char *data; if (sscanf(arg, "---[%d,%d]", &fd, &size) != 2) { @@ -3124,10 +3194,10 @@ int read_dupsession_data(struct gui_data *inst, Config *cfg, char *arg) exit(1); } - memcpy(cfg, data, sizeof(Config)); - if (use_pty_argv && size > sizeof(Config)) { + size_used = conf_deserialise(conf, data, size); + if (use_pty_argv && size > size_used) { int n = 0; - i = sizeof(Config); + i = size_used; while (i < size) { while (i < size && data[i]) i++; if (i >= size) { @@ -3141,7 +3211,7 @@ int read_dupsession_data(struct gui_data *inst, Config *cfg, char *arg) pty_argv = snewn(n+1, char *); pty_argv[n] = NULL; n = 0; - i = sizeof(Config); + i = size_used; while (i < size) { char *p = data + i; while (i < size && data[i]) i++; @@ -3320,33 +3390,36 @@ void update_specials_menu(void *frontend) static void start_backend(struct gui_data *inst) { - extern Backend *select_backend(Config *cfg); + extern Backend *select_backend(Conf *conf); char *realhost; const char *error; + char *s; - inst->back = select_backend(&inst->cfg); + inst->back = select_backend(inst->conf); error = inst->back->init((void *)inst, &inst->backhandle, - &inst->cfg, inst->cfg.host, inst->cfg.port, - &realhost, inst->cfg.tcp_nodelay, - inst->cfg.tcp_keepalives); + inst->conf, + conf_get_str(inst->conf, CONF_host), + conf_get_int(inst->conf, CONF_port), + &realhost, + conf_get_int(inst->conf, CONF_tcp_nodelay), + conf_get_int(inst->conf, CONF_tcp_keepalives)); if (error) { char *msg = dupprintf("Unable to open connection to %s:\n%s", - inst->cfg.host, error); + conf_get_str(inst->conf, CONF_host), error); inst->exited = TRUE; fatal_message_box(inst->window, msg); sfree(msg); exit(0); } - if (inst->cfg.wintitle[0]) { - set_title(inst, inst->cfg.wintitle); - set_icon(inst, inst->cfg.wintitle); + s = conf_get_str(inst->conf, CONF_wintitle); + if (s[0]) { + set_title_and_icon(inst, s, s); } else { char *title = make_default_wintitle(realhost); - set_title(inst, title); - set_icon(inst, title); + set_title_and_icon(inst, title, title); sfree(title); } sfree(realhost); @@ -3356,7 +3429,7 @@ static void start_backend(struct gui_data *inst) term_provide_resize_fn(inst->term, inst->back->size, inst->backhandle); inst->ldisc = - ldisc_create(&inst->cfg, inst->term, inst->back, inst->backhandle, + ldisc_create(inst->conf, inst->term, inst->back, inst->backhandle, inst); gtk_widget_set_sensitive(inst->restartitem, FALSE); @@ -3364,7 +3437,7 @@ static void start_backend(struct gui_data *inst) int pt_main(int argc, char **argv) { - extern int cfgbox(Config *cfg); + extern int cfgbox(Conf *conf); struct gui_data *inst; /* @@ -3374,6 +3447,8 @@ int pt_main(int argc, char **argv) memset(inst, 0, sizeof(*inst)); inst->alt_keycode = -1; /* this one needs _not_ to be zero */ inst->busy_status = BUSY_NOT; + inst->conf = conf_new(); + inst->wintitle = inst->icontitle = NULL; /* defer any child exit handling until we're ready to deal with * it */ @@ -3395,7 +3470,7 @@ int pt_main(int argc, char **argv) } if (argc > 1 && !strncmp(argv[1], "---", 3)) { - read_dupsession_data(inst, &inst->cfg, argv[1]); + read_dupsession_data(inst, inst->conf, argv[1]); /* Splatter this argument so it doesn't clutter a ps listing */ memset(argv[1], 0, strlen(argv[1])); } else { @@ -3403,19 +3478,19 @@ int pt_main(int argc, char **argv) * a session. This gets set to TRUE if something happens to change * that (e.g., a hostname is specified on the command-line). */ int allow_launch = FALSE; - if (do_cmdline(argc, argv, 0, &allow_launch, inst, &inst->cfg)) + if (do_cmdline(argc, argv, 0, &allow_launch, inst, inst->conf)) exit(1); /* pre-defaults pass to get -class */ - do_defaults(NULL, &inst->cfg); - if (do_cmdline(argc, argv, 1, &allow_launch, inst, &inst->cfg)) + do_defaults(NULL, inst->conf); + if (do_cmdline(argc, argv, 1, &allow_launch, inst, inst->conf)) exit(1); /* post-defaults, do everything */ - cmdline_run_saved(&inst->cfg); + cmdline_run_saved(inst->conf); if (loaded_session) allow_launch = TRUE; - if ((!allow_launch || !cfg_launchable(&inst->cfg)) && - !cfgbox(&inst->cfg)) + if ((!allow_launch || !conf_launchable(inst->conf)) && + !cfgbox(inst->conf)) exit(0); /* config box hit Cancel */ } @@ -3430,21 +3505,25 @@ int pt_main(int argc, char **argv) init_cutbuffers(); inst->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - if (inst->cfg.winclass[0]) - gtk_window_set_wmclass(GTK_WINDOW(inst->window), - inst->cfg.winclass, inst->cfg.winclass); + { + const char *winclass = conf_get_str(inst->conf, CONF_winclass); + if (*winclass) + gtk_window_set_wmclass(GTK_WINDOW(inst->window), + winclass, winclass); + } /* * Set up the colour map. */ palette_reset(inst); - inst->width = inst->cfg.width; - inst->height = inst->cfg.height; + inst->width = conf_get_int(inst->conf, CONF_width); + inst->height = conf_get_int(inst->conf, CONF_height); + cache_conf_values(inst); gtk_drawing_area_size(GTK_DRAWING_AREA(inst->area), - inst->font_width * inst->cfg.width + 2*inst->cfg.window_border, - inst->font_height * inst->cfg.height + 2*inst->cfg.window_border); + inst->font_width * inst->width + 2*inst->window_border, + inst->font_height * inst->height + 2*inst->window_border); inst->sbar_adjust = GTK_ADJUSTMENT(gtk_adjustment_new(0,0,0,0,0,0)); inst->sbar = gtk_vscrollbar_new(inst->sbar_adjust); inst->hbox = GTK_BOX(gtk_hbox_new(FALSE, 0)); @@ -3453,10 +3532,10 @@ int pt_main(int argc, char **argv) * unwanted, so we can pop it up quickly if it suddenly becomes * desirable. */ - if (inst->cfg.scrollbar_on_left) + if (conf_get_int(inst->conf, CONF_scrollbar_on_left)) gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); gtk_box_pack_start(inst->hbox, inst->area, TRUE, TRUE, 0); - if (!inst->cfg.scrollbar_on_left) + if (!conf_get_int(inst->conf, CONF_scrollbar_on_left)) gtk_box_pack_start(inst->hbox, inst->sbar, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(inst->window), GTK_WIDGET(inst->hbox)); @@ -3464,7 +3543,7 @@ int pt_main(int argc, char **argv) set_geom_hints(inst); gtk_widget_show(inst->area); - if (inst->cfg.scrollbar) + if (conf_get_int(inst->conf, CONF_scrollbar)) gtk_widget_show(inst->sbar); else gtk_widget_hide(inst->sbar); @@ -3512,7 +3591,7 @@ int pt_main(int argc, char **argv) GTK_SIGNAL_FUNC(selection_get), inst); gtk_signal_connect(GTK_OBJECT(inst->area), "selection_clear_event", GTK_SIGNAL_FUNC(selection_clear), inst); - if (inst->cfg.scrollbar) + if (conf_get_int(inst->conf, CONF_scrollbar)) gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed", GTK_SIGNAL_FUNC(scrollbar_moved), inst); gtk_widget_add_events(GTK_WIDGET(inst->area), @@ -3612,13 +3691,14 @@ int pt_main(int argc, char **argv) inst->eventlogstuff = eventlogstuff_new(); - inst->term = term_init(&inst->cfg, &inst->ucsdata, inst); - inst->logctx = log_init(inst, &inst->cfg); + inst->term = term_init(inst->conf, &inst->ucsdata, inst); + inst->logctx = log_init(inst, inst->conf); term_provide_logctx(inst->term, inst->logctx); uxsel_init(); - term_size(inst->term, inst->cfg.height, inst->cfg.width, inst->cfg.savelines); + term_size(inst->term, inst->height, inst->width, + conf_get_int(inst->conf, CONF_savelines)); start_backend(inst); diff --git a/unix/unix.h b/unix/unix.h index 74f41746..faf56008 100644 --- a/unix/unix.h +++ b/unix/unix.h @@ -89,7 +89,7 @@ long get_windowid(void *frontend); void *get_window(void *frontend); /* void * to avoid depending on gtk.h */ /* Things pterm.c needs from gtkdlg.c */ -int do_config_box(const char *title, Config *cfg, +int do_config_box(const char *title, Conf *conf, int midsession, int protcfginfo); void fatal_message_box(void *window, char *msg); void about_box(void *window); @@ -100,7 +100,7 @@ int reallyclose(void *frontend); /* Things pterm.c needs from {ptermm,uxputty}.c */ char *make_default_wintitle(char *hostname); -int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch); +int process_nonoption_arg(char *arg, Conf *conf, int *allow_launch); /* pterm.c needs this special function in xkeysym.c */ int keysym_to_unicode(int keysym); diff --git a/unix/ux_x11.c b/unix/ux_x11.c index 78a56150..63a92b58 100644 --- a/unix/ux_x11.c +++ b/unix/ux_x11.c @@ -12,7 +12,7 @@ #include "ssh.h" #include "network.h" -void platform_get_x11_auth(struct X11Display *disp, const Config *cfg) +void platform_get_x11_auth(struct X11Display *disp, Conf *conf) { char *xauthfile; int needs_free; diff --git a/unix/uxcfg.c b/unix/uxcfg.c index c7d8d5fb..e48a9b69 100644 --- a/unix/uxcfg.c +++ b/unix/uxcfg.c @@ -16,11 +16,11 @@ void unix_setup_config_box(struct controlbox *b, int midsession, int protocol) union control *c; /* - * The Config structure contains two Unix-specific elements - * which are not configured in here: stamp_utmp and - * login_shell. This is because pterm does not put up a - * configuration box right at the start, which is the only time - * when these elements would be useful to configure. + * The Conf structure contains two Unix-specific elements which + * are not configured in here: stamp_utmp and login_shell. This + * is because pterm does not put up a configuration box right at + * the start, which is the only time when these elements would + * be useful to configure. */ /* @@ -41,8 +41,8 @@ void unix_setup_config_box(struct controlbox *b, int midsession, int protocol) for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && - c->generic.context.i == offsetof(Config, proxy_type)) { - assert(c->generic.handler == dlg_stdradiobutton_handler); + c->generic.context.i == CONF_proxy_type) { + assert(c->generic.handler == conf_radiobutton_handler); c->radio.nbuttons++; c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); @@ -58,9 +58,8 @@ void unix_setup_config_box(struct controlbox *b, int midsession, int protocol) for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_EDITBOX && - c->generic.context.i == - offsetof(Config, proxy_telnet_command)) { - assert(c->generic.handler == dlg_stdeditbox_handler); + c->generic.context.i == CONF_proxy_telnet_command) { + assert(c->generic.handler == conf_editbox_handler); sfree(c->generic.label); c->generic.label = dupstr("Telnet command, or local" " proxy command"); diff --git a/unix/uxgss.c b/unix/uxgss.c index 278fb866..2a9e1296 100644 --- a/unix/uxgss.c +++ b/unix/uxgss.c @@ -53,9 +53,10 @@ static void gss_init(struct ssh_gss_library *lib, void *dlhandle, } /* Dynamically load gssapi libs. */ -struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) +struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) { void *gsslib; + char *gsspath; struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist); list->libraries = snewn(4, struct ssh_gss_library); @@ -77,11 +78,11 @@ struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) 2, "Using GSSAPI from libgss.so.1"); /* User-specified GSSAPI library */ - if (cfg->ssh_gss_custom.path[0] && - (gsslib = dlopen(cfg->ssh_gss_custom.path, RTLD_LAZY)) != NULL) + gsspath = conf_get_filename(conf, CONF_ssh_gss_custom)->path; + if (*gsspath && (gsslib = dlopen(gsspath, RTLD_LAZY)) != NULL) gss_init(&list->libraries[list->nlibraries++], gsslib, 3, dupprintf("Using GSSAPI from user-specified" - " library '%s'", cfg->ssh_gss_custom.path)); + " library '%s'", gsspath)); return list; } @@ -129,7 +130,7 @@ const struct keyvalwhere gsslibkeywords[] = { #include /* Dynamically load gssapi libs. */ -struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) +struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) { struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist); diff --git a/unix/uxplink.c b/unix/uxplink.c index d76bbcaa..4d36e50a 100644 --- a/unix/uxplink.c +++ b/unix/uxplink.c @@ -98,7 +98,7 @@ static int local_tty = FALSE; /* do we have a local tty? */ static Backend *back; static void *backhandle; -static Config cfg; +static Conf *conf; /* * Default settings that are specific to pterm. @@ -605,10 +605,11 @@ int main(int argc, char **argv) /* * Process the command line. */ - do_defaults(NULL, &cfg); + conf = conf_new(); + do_defaults(NULL, conf); loaded_session = FALSE; - default_protocol = cfg.protocol; - default_port = cfg.port; + default_protocol = conf_get_int(conf, CONF_protocol); + default_port = conf_get_int(conf, CONF_port); errors = 0; { /* @@ -618,8 +619,10 @@ int main(int argc, char **argv) if (p) { const Backend *b = backend_from_name(p); if (b) { - default_protocol = cfg.protocol = b->protocol; - default_port = cfg.port = b->default_port; + default_protocol = b->protocol; + default_port = b->default_port; + conf_set_int(conf, CONF_protocol, default_protocol); + conf_set_int(conf, CONF_port, default_port); } } } @@ -627,7 +630,7 @@ int main(int argc, char **argv) char *p = *++argv; if (*p == '-') { int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), - 1, &cfg); + 1, conf); if (ret == -2) { fprintf(stderr, "plink: option \"%s\" requires an argument\n", p); @@ -639,7 +642,7 @@ int main(int argc, char **argv) } else if (!strcmp(p, "-batch")) { console_batch_mode = 1; } else if (!strcmp(p, "-s")) { - /* Save status to write to cfg later. */ + /* Save status to write to conf later. */ use_subsystem = 1; } else if (!strcmp(p, "-V")) { version(); @@ -660,7 +663,7 @@ int main(int argc, char **argv) errors = 1; } } else if (*p) { - if (!cfg_launchable(&cfg) || !(got_host || loaded_session)) { + if (!conf_launchable(conf) || !(got_host || loaded_session)) { char *q = p; /* @@ -674,7 +677,7 @@ int main(int argc, char **argv) q += 7; if (q[0] == '/' && q[1] == '/') q += 2; - cfg.protocol = PROT_TELNET; + conf_set_int(conf, CONF_protocol, PROT_TELNET); p = q; while (*p && *p != ':' && *p != '/') p++; @@ -682,11 +685,10 @@ int main(int argc, char **argv) if (*p) *p++ = '\0'; if (c == ':') - cfg.port = atoi(p); + conf_set_int(conf, CONF_port, atoi(p)); else - cfg.port = -1; - strncpy(cfg.host, q, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; + conf_set_int(conf, CONF_port, -1); + conf_set_str(conf, CONF_host, q); got_host = TRUE; } else { char *r, *user, *host; @@ -701,7 +703,9 @@ int main(int argc, char **argv) *r = '\0'; b = backend_from_name(p); if (b) { - default_protocol = cfg.protocol = b->protocol; + default_protocol = b->protocol; + conf_set_int(conf, CONF_protocol, + default_protocol); portnumber = b->default_port; } p = r + 1; @@ -728,26 +732,24 @@ int main(int argc, char **argv) * same name as the hostname. */ { - Config cfg2; - do_defaults(host, &cfg2); - if (loaded_session || !cfg_launchable(&cfg2)) { + Conf *conf2 = conf_new(); + do_defaults(host, conf2); + if (loaded_session || !conf_launchable(conf2)) { /* No settings for this host; use defaults */ /* (or session was already loaded with -load) */ - strncpy(cfg.host, host, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; - cfg.port = default_port; + conf_set_str(conf, CONF_host, host); + conf_set_int(conf, CONF_port, default_port); got_host = TRUE; } else { - cfg = cfg2; + conf_copy_into(conf, conf2); loaded_session = TRUE; } + conf_free(conf2); } if (user) { /* Patch in specified username. */ - strncpy(cfg.username, user, - sizeof(cfg.username) - 1); - cfg.username[sizeof(cfg.username) - 1] = '\0'; + conf_set_str(conf, CONF_username, user); } } @@ -774,9 +776,9 @@ int main(int argc, char **argv) } if (cmdlen) command[--cmdlen]='\0'; /* change trailing blank to NUL */ - cfg.remote_cmd_ptr = command; - cfg.remote_cmd_ptr2 = NULL; - cfg.nopty = TRUE; /* command => no terminal */ + conf_set_str(conf, CONF_remote_cmd, command); + conf_set_str(conf, CONF_remote_cmd2, ""); + conf_set_int(conf, CONF_nopty, TRUE); /* command => no tty */ break; /* done with cmdline */ } @@ -786,70 +788,78 @@ int main(int argc, char **argv) if (errors) return 1; - if (!cfg_launchable(&cfg) || !(got_host || loaded_session)) { + if (!conf_launchable(conf) || !(got_host || loaded_session)) { usage(); } /* - * Trim leading whitespace off the hostname if it's there. + * Muck about with the hostname in various ways. */ { - int space = strspn(cfg.host, " \t"); - memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); - } + char *hostbuf = dupstr(conf_get_str(conf, CONF_host)); + char *host = hostbuf; + char *p, *q; - /* See if host is of the form user@host */ - if (cfg.host[0] != '\0') { - char *atsign = strrchr(cfg.host, '@'); - /* Make sure we're not overflowing the user field */ - if (atsign) { - if (atsign - cfg.host < sizeof cfg.username) { - strncpy(cfg.username, cfg.host, atsign - cfg.host); - cfg.username[atsign - cfg.host] = '\0'; + /* + * Trim leading whitespace. + */ + host += strspn(host, " \t"); + + /* + * See if host is of the form user@host, and separate out + * the username if so. + */ + if (host[0] != '\0') { + char *atsign = strrchr(host, '@'); + if (atsign) { + *atsign = '\0'; + conf_set_str(conf, CONF_username, host); + host = atsign + 1; } - memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); } + + /* + * Trim off a colon suffix if it's there. + */ + host[strcspn(host, ":")] = '\0'; + + /* + * Remove any remaining whitespace. + */ + p = hostbuf; + q = host; + while (*q) { + if (*q != ' ' && *q != '\t') + *p++ = *q; + q++; + } + *p = '\0'; + + conf_set_str(conf, CONF_host, hostbuf); + sfree(hostbuf); } /* * Perform command-line overrides on session configuration. */ - cmdline_run_saved(&cfg); + cmdline_run_saved(conf); /* * Apply subsystem status. */ if (use_subsystem) - cfg.ssh_subsys = TRUE; + conf_set_int(conf, CONF_ssh_subsys, TRUE); - /* - * Trim a colon suffix off the hostname if it's there. - */ - cfg.host[strcspn(cfg.host, ":")] = '\0'; - - /* - * Remove any remaining whitespace from the hostname. - */ - { - int p1 = 0, p2 = 0; - while (cfg.host[p2] != '\0') { - if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { - cfg.host[p1] = cfg.host[p2]; - p1++; - } - p2++; - } - cfg.host[p1] = '\0'; - } - - if (!cfg.remote_cmd_ptr && !*cfg.remote_cmd && !*cfg.ssh_nc_host) + if (!*conf_get_str(conf, CONF_remote_cmd) && + !*conf_get_str(conf, CONF_remote_cmd2) && + !*conf_get_str(conf, CONF_ssh_nc_host)) flags |= FLAG_INTERACTIVE; /* * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ - back = backend_from_proto(cfg.protocol); + back = backend_from_proto(conf_get_int(conf, CONF_protocol)); if (back == NULL) { fprintf(stderr, "Internal fault: Unsupported protocol found\n"); @@ -860,7 +870,7 @@ int main(int argc, char **argv) * Select port. */ if (portnumber != -1) - cfg.port = portnumber; + conf_set_int(conf, CONF_port, portnumber); /* * Set up the pipe we'll use to tell us about SIGWINCH. @@ -879,28 +889,34 @@ int main(int argc, char **argv) * connection is set up, so if there are none now, we can safely set * the "simple" flag. */ - if (cfg.protocol == PROT_SSH && !cfg.x11_forward && !cfg.agentfwd && - cfg.portfwd[0] == '\0' && cfg.portfwd[1] == '\0') - cfg.ssh_simple = TRUE; + if (conf_get_int(conf, CONF_protocol) == PROT_SSH && + !conf_get_int(conf, CONF_x11_forward) && + !conf_get_int(conf, CONF_agentfwd) && + !conf_get_str_nthstrkey(conf, CONF_portfwd, 0)) + conf_set_int(conf, CONF_ssh_simple, TRUE); + /* * Start up the connection. */ - logctx = log_init(NULL, &cfg); + logctx = log_init(NULL, conf); console_provide_logctx(logctx); { const char *error; char *realhost; /* nodelay is only useful if stdin is a terminal device */ - int nodelay = cfg.tcp_nodelay && isatty(0); + int nodelay = conf_get_int(conf, CONF_tcp_nodelay) && isatty(0); - error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, - &realhost, nodelay, cfg.tcp_keepalives); + error = back->init(NULL, &backhandle, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, nodelay, + conf_get_int(conf, CONF_tcp_keepalives)); if (error) { fprintf(stderr, "Unable to open connection:\n%s\n", error); return 1; } back->provide_logctx(backhandle, logctx); - ldisc_create(&cfg, NULL, back, backhandle, NULL); + ldisc_create(conf, NULL, back, backhandle, NULL); sfree(realhost); } connopen = 1; diff --git a/unix/uxproxy.c b/unix/uxproxy.c index 792bbdc2..b441b802 100644 --- a/unix/uxproxy.c +++ b/unix/uxproxy.c @@ -224,7 +224,7 @@ static int localproxy_select_result(int fd, int event) Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, - Plug plug, const Config *cfg) + Plug plug, Conf *conf) { char *cmd; @@ -243,10 +243,10 @@ Socket platform_new_connection(SockAddr addr, char *hostname, Local_Proxy_Socket ret; int to_cmd_pipe[2], from_cmd_pipe[2], pid; - if (cfg->proxy_type != PROXY_CMD) + if (conf_get_int(conf, CONF_proxy_type) != PROXY_CMD) return NULL; - cmd = format_telnet_command(addr, port, cfg); + cmd = format_telnet_command(addr, port, conf); ret = snew(struct Socket_localproxy_tag); ret->fn = &socket_fn_table; diff --git a/unix/uxpterm.c b/unix/uxpterm.c index c20c14a2..370527a3 100644 --- a/unix/uxpterm.c +++ b/unix/uxpterm.c @@ -12,19 +12,19 @@ const int use_event_log = 0; /* pterm doesn't need it */ const int new_session = 0, saved_sessions = 0; /* or these */ const int use_pty_argv = TRUE; -Backend *select_backend(Config *cfg) +Backend *select_backend(Conf *conf) { return &pty_backend; } -int cfgbox(Config *cfg) +int cfgbox(Conf *conf) { /* * This is a no-op in pterm, except that we'll ensure the * protocol is set to -1 to inhibit the useless Connection * panel in the config box. */ - cfg->protocol = -1; + conf_set_int(conf, CONF_protocol, -1); return 1; } @@ -33,7 +33,7 @@ void cleanup_exit(int code) exit(code); } -int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch) +int process_nonoption_arg(char *arg, Conf *conf, int *allow_launch) { return 0; /* pterm doesn't have any. */ } diff --git a/unix/uxpty.c b/unix/uxpty.c index bdfa5ab1..a9c0676c 100644 --- a/unix/uxpty.c +++ b/unix/uxpty.c @@ -76,7 +76,7 @@ typedef struct pty_tag *Pty; static int pty_signal_pipe[2] = { -1, -1 }; /* obviously bogus initial val */ struct pty_tag { - Config cfg; + Conf *conf; int master_fd, slave_fd; void *frontend; char name[FILENAME_MAX]; @@ -588,6 +588,8 @@ int pty_real_select_result(Pty pty, int event, int status) } if (finished && !pty->finished) { + int close_on_exit; + uxsel_del(pty->master_fd); pty_close(pty); pty->master_fd = -1; @@ -600,8 +602,9 @@ int pty_real_select_result(Pty pty, int event, int status) * Only On Clean and it wasn't a clean exit) do we output a * `terminated' message. */ - if (pty->cfg.close_on_exit == FORCE_OFF || - (pty->cfg.close_on_exit == AUTO && pty->exit_code != 0)) { + close_on_exit = conf_get_int(pty->conf, CONF_close_on_exit); + if (close_on_exit == FORCE_OFF || + (close_on_exit == AUTO && pty->exit_code != 0)) { char message[512]; if (WIFEXITED(pty->exit_code)) sprintf(message, "\r\n[pterm: process terminated with exit" @@ -681,7 +684,7 @@ static void pty_uxsel_setup(Pty pty) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, +static const char *pty_init(void *frontend, void **backend_handle, Conf *conf, char *host, int port, char **realhost, int nodelay, int keepalive) { @@ -705,9 +708,9 @@ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, pty->frontend = frontend; *backend_handle = NULL; /* we can't sensibly use this, sadly */ - pty->cfg = *cfg; /* structure copy */ - pty->term_width = cfg->width; - pty->term_height = cfg->height; + pty->conf = conf_copy(conf); + pty->term_width = conf_get_int(conf, CONF_width); + pty->term_height = conf_get_int(conf, CONF_height); if (pty->master_fd < 0) pty_open_master(pty); @@ -719,7 +722,8 @@ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, { struct termios attrs; tcgetattr(pty->master_fd, &attrs); - attrs.c_cc[VERASE] = cfg->bksp_is_delete ? '\177' : '\010'; + attrs.c_cc[VERASE] = conf_get_int(conf, CONF_bksp_is_delete) + ? '\177' : '\010'; tcsetattr(pty->master_fd, TCSANOW, &attrs); } @@ -728,7 +732,7 @@ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, * Stamp utmp (that is, tell the utmp helper process to do so), * or not. */ - if (!cfg->stamp_utmp) { + if (!conf_get_int(conf, CONF_stamp_utmp)) { close(pty_utmp_helper_pipe); /* just let the child process die */ pty_utmp_helper_pipe = -1; } else { @@ -787,7 +791,8 @@ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, close(open(pty->name, O_WRONLY, 0)); setpgid(pgrp, pgrp); { - char *term_env_var = dupprintf("TERM=%s", cfg->termtype); + char *term_env_var = dupprintf("TERM=%s", + conf_get_str(conf, CONF_termtype)); putenv(term_env_var); /* We mustn't free term_env_var, as putenv links it into the * environment in place. @@ -803,18 +808,12 @@ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, } #endif { - char *e = cfg->environmt; - char *var, *varend, *val, *varval; - while (*e) { - var = e; - while (*e && *e != '\t') e++; - varend = e; - if (*e == '\t') e++; - val = e; - while (*e) e++; - e++; + char *key, *val; - varval = dupprintf("%.*s=%s", varend-var, var, val); + for (val = conf_get_str_strs(conf, CONF_environmt, NULL, &key); + val != NULL; + val = conf_get_str_strs(conf, CONF_environmt, key, &key)) { + char *varval = dupcat(key, "=", val, NULL); putenv(varval); /* * We must not free varval, since putenv links it @@ -841,7 +840,7 @@ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, else { char *shell = getenv("SHELL"); char *shellname; - if (cfg->login_shell) { + if (conf_get_int(conf, CONF_login_shell)) { char *p = strrchr(shell, '/'); shellname = snewn(2+strlen(shell), char); p = p ? p+1 : shell; @@ -884,7 +883,7 @@ static const char *pty_init(void *frontend, void **backend_handle, Config *cfg, return NULL; } -static void pty_reconfig(void *handle, Config *cfg) +static void pty_reconfig(void *handle, Conf *conf) { Pty pty = (Pty)handle; /* @@ -892,7 +891,7 @@ static void pty_reconfig(void *handle, Config *cfg) * unfortunately we do need to pick up the setting of Close On * Exit so we know whether to give a `terminated' message. */ - pty->cfg = *cfg; /* structure copy */ + conf_copy_into(pty->conf, conf); } /* diff --git a/unix/uxputty.c b/unix/uxputty.c index 73e11973..fc718a0c 100644 --- a/unix/uxputty.c +++ b/unix/uxputty.c @@ -31,17 +31,17 @@ void cleanup_exit(int code) exit(code); } -Backend *select_backend(Config *cfg) +Backend *select_backend(Conf *conf) { - Backend *back = backend_from_proto(cfg->protocol); + Backend *back = backend_from_proto(conf_get_int(conf, CONF_protocol)); assert(back != NULL); return back; } -int cfgbox(Config *cfg) +int cfgbox(Conf *conf) { char *title = dupcat(appname, " Configuration", NULL); - int ret = do_config_box(title, cfg, 0, 0); + int ret = do_config_box(title, conf, 0, 0); sfree(title); return ret; } @@ -50,7 +50,7 @@ static int got_host = 0; const int use_event_log = 1, new_session = 1, saved_sessions = 1; -int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch) +int process_nonoption_arg(char *arg, Conf *conf, int *allow_launch) { char *p, *q = arg; @@ -61,7 +61,7 @@ int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch) * argument, so that it will be deferred until it's a good * moment to run it. */ - int ret = cmdline_process_param("-P", arg, 1, cfg); + int ret = cmdline_process_param("-P", arg, 1, conf); assert(ret == 2); } else if (!strncmp(q, "telnet:", 7)) { /* @@ -74,7 +74,7 @@ int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch) q += 7; if (q[0] == '/' && q[1] == '/') q += 2; - cfg->protocol = PROT_TELNET; + conf_set_int(conf, CONF_protocol, PROT_TELNET); p = q; while (*p && *p != ':' && *p != '/') p++; @@ -82,11 +82,10 @@ int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch) if (*p) *p++ = '\0'; if (c == ':') - cfg->port = atoi(p); + conf_set_int(conf, CONF_port, atoi(p)); else - cfg->port = -1; - strncpy(cfg->host, q, sizeof(cfg->host) - 1); - cfg->host[sizeof(cfg->host) - 1] = '\0'; + conf_set_int(conf, CONF_port, -1); + conf_set_str(conf, CONF_host, q); got_host = 1; } else { /* @@ -97,8 +96,7 @@ int process_nonoption_arg(char *arg, Config *cfg, int *allow_launch) p++; if (*p) *p++ = '\0'; - strncpy(cfg->host, q, sizeof(cfg->host) - 1); - cfg->host[sizeof(cfg->host) - 1] = '\0'; + conf_set_str(conf, CONF_host, q); got_host = 1; } if (got_host) diff --git a/unix/uxser.c b/unix/uxser.c index 2155b924..8f4955c4 100644 --- a/unix/uxser.c +++ b/unix/uxser.c @@ -60,10 +60,10 @@ static int serial_select_result(int fd, int event); static void serial_uxsel_setup(Serial serial); static void serial_try_write(Serial serial); -static const char *serial_configure(Serial serial, Config *cfg) +static const char *serial_configure(Serial serial, Conf *conf) { struct termios options; - int bflag, bval; + int bflag, bval, speed, flow, parity; const char *str; char *msg; @@ -75,8 +75,9 @@ static const char *serial_configure(Serial serial, Config *cfg) /* * Find the appropriate baud rate flag. */ + speed = conf_get_int(conf, CONF_serspeed); #define SETBAUD(x) (bflag = B ## x, bval = x) -#define CHECKBAUD(x) do { if (cfg->serspeed >= x) SETBAUD(x); } while (0) +#define CHECKBAUD(x) do { if (speed >= x) SETBAUD(x); } while (0) SETBAUD(50); #ifdef B75 CHECKBAUD(75); @@ -183,18 +184,19 @@ static const char *serial_configure(Serial serial, Config *cfg) sfree(msg); options.c_cflag &= ~CSIZE; - switch (cfg->serdatabits) { + switch (conf_get_int(conf, CONF_serdatabits)) { case 5: options.c_cflag |= CS5; break; case 6: options.c_cflag |= CS6; break; case 7: options.c_cflag |= CS7; break; case 8: options.c_cflag |= CS8; break; default: return "Invalid number of data bits (need 5, 6, 7 or 8)"; } - msg = dupprintf("Configuring %d data bits", cfg->serdatabits); + msg = dupprintf("Configuring %d data bits", + conf_get_int(conf, CONF_serdatabits)); logevent(serial->frontend, msg); sfree(msg); - if (cfg->serstopbits >= 4) { + if (conf_get_int(conf, CONF_serstopbits) >= 4) { options.c_cflag |= CSTOPB; } else { options.c_cflag &= ~CSTOPB; @@ -211,10 +213,11 @@ static const char *serial_configure(Serial serial, Config *cfg) #ifdef CNEW_RTSCTS options.c_cflag &= ~CNEW_RTSCTS; #endif - if (cfg->serflow == SER_FLOW_XONXOFF) { + flow = conf_get_int(conf, CONF_serflow); + if (flow == SER_FLOW_XONXOFF) { options.c_iflag |= IXON | IXOFF; str = "XON/XOFF"; - } else if (cfg->serflow == SER_FLOW_RTSCTS) { + } else if (flow == SER_FLOW_RTSCTS) { #ifdef CRTSCTS options.c_cflag |= CRTSCTS; #endif @@ -229,11 +232,12 @@ static const char *serial_configure(Serial serial, Config *cfg) sfree(msg); /* Parity */ - if (cfg->serparity == SER_PAR_ODD) { + parity = conf_get_int(conf, CONF_serparity); + if (parity == SER_PAR_ODD) { options.c_cflag |= PARENB; options.c_cflag |= PARODD; str = "odd"; - } else if (cfg->serparity == SER_PAR_EVEN) { + } else if (parity == SER_PAR_EVEN) { options.c_cflag |= PARENB; options.c_cflag &= ~PARODD; str = "even"; @@ -284,12 +288,13 @@ static const char *serial_configure(Serial serial, Config *cfg) * freed by the caller. */ static const char *serial_init(void *frontend_handle, void **backend_handle, - Config *cfg, + Conf *conf, char *host, int port, char **realhost, int nodelay, int keepalive) { Serial serial; const char *err; + char *line; serial = snew(struct serial_backend_data); *backend_handle = serial; @@ -299,22 +304,23 @@ static const char *serial_init(void *frontend_handle, void **backend_handle, serial->inbufsize = 0; bufchain_init(&serial->output_data); + line = conf_get_str(conf, CONF_serline); { - char *msg = dupprintf("Opening serial device %s", cfg->serline); + char *msg = dupprintf("Opening serial device %s", line); logevent(serial->frontend, msg); } - serial->fd = open(cfg->serline, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); + serial->fd = open(line, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK); if (serial->fd < 0) return "Unable to open serial port"; cloexec(serial->fd); - err = serial_configure(serial, cfg); + err = serial_configure(serial, conf); if (err) return err; - *realhost = dupstr(cfg->serline); + *realhost = dupstr(line); if (!serial_by_fd) serial_by_fd = newtree234(serial_compare_by_fd); @@ -349,14 +355,14 @@ static void serial_free(void *handle) sfree(serial); } -static void serial_reconfig(void *handle, Config *cfg) +static void serial_reconfig(void *handle, Conf *conf) { Serial serial = (Serial) handle; /* * FIXME: what should we do if this returns an error? */ - serial_configure(serial, cfg); + serial_configure(serial, conf); } static int serial_select_result(int fd, int event) diff --git a/unix/uxsftp.c b/unix/uxsftp.c index b26c4b5a..3170ecf3 100644 --- a/unix/uxsftp.c +++ b/unix/uxsftp.c @@ -34,7 +34,7 @@ char *x_get_default(const char *key) return NULL; /* this is a stub */ } -void platform_get_x11_auth(struct X11Display *display, const Config *cfg) +void platform_get_x11_auth(struct X11Display *display, Conf *conf) { /* Do nothing, therefore no auth. */ } diff --git a/unix/uxstore.c b/unix/uxstore.c index e7b9c158..8d49e484 100644 --- a/unix/uxstore.c +++ b/unix/uxstore.c @@ -317,7 +317,7 @@ void *open_settings_r(const char *sessionname) return ret; } -char *read_setting_s(void *handle, const char *key, char *buffer, int buflen) +char *read_setting_s(void *handle, const char *key) { tree234 *tree = (tree234 *)handle; const char *val; @@ -333,11 +333,8 @@ char *read_setting_s(void *handle, const char *key, char *buffer, int buflen) if (!val) return NULL; - else { - strncpy(buffer, val, buflen); - buffer[buflen-1] = '\0'; - return buffer; - } + else + return dupstr(val); } int read_setting_i(void *handle, const char *key, int defvalue) @@ -375,26 +372,40 @@ int read_setting_fontspec(void *handle, const char *name, FontSpec *result) * ("FontName"). */ char *suffname = dupcat(name, "Name", NULL); - if (read_setting_s(handle, suffname, result->name, sizeof(result->name))) { + char *tmp; + + if ((tmp = read_setting_s(handle, suffname)) != NULL) { + strncpy(result->name, tmp, sizeof(result->name)-1); + result->name[sizeof(result->name)-1] = '\0'; sfree(suffname); + sfree(tmp); return TRUE; /* got new-style name */ } sfree(suffname); /* Fall back to old-style name. */ - memcpy(result->name, "server:", 7); - if (!read_setting_s(handle, name, - result->name + 7, sizeof(result->name) - 7) || - !result->name[7]) { - result->name[0] = '\0'; - return FALSE; - } else { + tmp = read_setting_s(handle, name); + if (tmp && *tmp) { + strcpy(result->name, "server:"); + strncpy(result->name + 7, tmp, sizeof(result->name) - 8); + result->name[sizeof(result->name)-1] = '\0'; + sfree(tmp); return TRUE; + } else { + sfree(tmp); + return FALSE; } } int read_setting_filename(void *handle, const char *name, Filename *result) { - return !!read_setting_s(handle, name, result->path, sizeof(result->path)); + char *tmp = read_setting_s(handle, name); + if (tmp) { + strncpy(result->path, tmp, sizeof(result->path)-1); + result->path[sizeof(result->path)-1] = '\0'; + sfree(tmp); + return TRUE; + } else + return FALSE; } void write_setting_fontspec(void *handle, const char *name, FontSpec result) diff --git a/unix/uxucs.c b/unix/uxucs.c index ec881c51..071ecfc7 100644 --- a/unix/uxucs.c +++ b/unix/uxucs.c @@ -139,7 +139,7 @@ int init_ucs(struct unicode_data *ucsdata, char *linecharset, /* * Failing that, line_codepage should be decoded from the - * specification in cfg. + * specification in conf. */ if (ucsdata->line_codepage == CS_NONE) ucsdata->line_codepage = decode_codepage(linecharset); diff --git a/windows/wincfg.c b/windows/wincfg.c index 1cf56c81..9d3673a6 100644 --- a/windows/wincfg.c +++ b/windows/wincfg.c @@ -70,8 +70,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, "Control the scrollback in the window"); ctrl_checkbox(s, "Display scrollbar in full screen mode", 'i', HELPCTX(window_scrollback), - dlg_stdcheckbox_handler, - I(offsetof(Config,scrollbar_in_fullscreen))); + conf_checkbox_handler, + I(CONF_scrollbar_in_fullscreen)); /* * Really this wants to go just after `Display scrollbar'. See * if we can find that control, and do some shuffling. @@ -81,7 +81,7 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_CHECKBOX && - c->generic.context.i == offsetof(Config,scrollbar)) { + c->generic.context.i == CONF_scrollbar) { /* * Control i is the scrollbar checkbox. * Control s->ncontrols-1 is the scrollbar-in-FS one. @@ -105,10 +105,10 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, "Enable extra keyboard features:"); ctrl_checkbox(s, "AltGr acts as Compose key", 't', HELPCTX(keyboard_compose), - dlg_stdcheckbox_handler, I(offsetof(Config,compose_key))); + conf_checkbox_handler, I(CONF_compose_key)); ctrl_checkbox(s, "Control-Alt is different from AltGr", 'd', HELPCTX(keyboard_ctrlalt), - dlg_stdcheckbox_handler, I(offsetof(Config,ctrlaltkeys))); + conf_checkbox_handler, I(CONF_ctrlaltkeys)); /* * Windows allows an arbitrary .WAV to be played as a bell, and @@ -133,8 +133,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && - c->generic.context.i == offsetof(Config, beep)) { - assert(c->generic.handler == dlg_stdradiobutton_handler); + c->generic.context.i == CONF_beep) { + assert(c->generic.handler == conf_radiobutton_handler); c->radio.nbuttons += 2; c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); @@ -159,7 +159,7 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, ctrl_filesel(s, "Custom sound file to play as a bell:", NO_SHORTCUT, FILTER_WAVE_FILES, FALSE, "Select bell sound file", HELPCTX(bell_style), - dlg_stdfilesel_handler, I(offsetof(Config, bell_wavefile))); + conf_filesel_handler, I(CONF_bell_wavefile)); /* * While we've got this box open, taskbar flashing on a bell is @@ -167,8 +167,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, */ ctrl_radiobuttons(s, "Taskbar/caption indication on bell:", 'i', 3, HELPCTX(bell_taskbar), - dlg_stdradiobutton_handler, - I(offsetof(Config, beep_ind)), + conf_radiobutton_handler, + I(CONF_beep_ind), "Disabled", I(B_IND_DISABLED), "Flashing", I(B_IND_FLASH), "Steady", I(B_IND_STEADY), NULL); @@ -180,7 +180,7 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, "Adjust the window border"); ctrl_checkbox(s, "Sunken-edge border (slightly thicker)", 's', HELPCTX(appearance_border), - dlg_stdcheckbox_handler, I(offsetof(Config,sunken_edge))); + conf_checkbox_handler, I(CONF_sunken_edge)); /* * Configurable font quality settings for Windows. @@ -191,8 +191,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, HELPCTX(appearance_font), variable_pitch_handler, I(0)); ctrl_radiobuttons(s, "Font quality:", 'q', 2, HELPCTX(appearance_font), - dlg_stdradiobutton_handler, - I(offsetof(Config, font_quality)), + conf_radiobutton_handler, + I(CONF_font_quality), "Antialiased", I(FQ_ANTIALIASED), "Non-Antialiased", I(FQ_NONANTIALIASED), "ClearType", I(FQ_CLEARTYPE), @@ -206,8 +206,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, s = ctrl_getset(b, "Window/Translation", "tweaks", NULL); ctrl_checkbox(s, "Caps Lock acts as Cyrillic switch", 's', HELPCTX(translation_cyrillic), - dlg_stdcheckbox_handler, - I(offsetof(Config,xlat_capslockcyr))); + conf_checkbox_handler, + I(CONF_xlat_capslockcyr)); /* * On Windows we can use but not enumerate translation tables @@ -232,8 +232,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && - c->generic.context.i == offsetof(Config, vtmode)) { - assert(c->generic.handler == dlg_stdradiobutton_handler); + c->generic.context.i == CONF_vtmode) { + assert(c->generic.handler == conf_radiobutton_handler); c->radio.nbuttons += 3; c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); @@ -272,7 +272,7 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, "Formatting of pasted characters"); ctrl_checkbox(s, "Paste to clipboard in RTF as well as plain text", 'f', HELPCTX(selection_rtf), - dlg_stdcheckbox_handler, I(offsetof(Config,rtf_paste))); + conf_checkbox_handler, I(CONF_rtf_paste)); /* * Windows often has no middle button, so we supply a selection @@ -283,8 +283,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, "Control use of mouse"); ctrl_radiobuttons(s, "Action of mouse buttons:", 'm', 1, HELPCTX(selection_buttons), - dlg_stdradiobutton_handler, - I(offsetof(Config, mouse_is_xterm)), + conf_radiobutton_handler, + I(CONF_mouse_is_xterm), "Windows (Middle extends, Right brings up menu)", I(2), "Compromise (Middle extends, Right pastes)", I(0), "xterm (Right extends, Middle pastes)", I(1), NULL); @@ -304,10 +304,10 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, "General options for colour usage"); ctrl_checkbox(s, "Attempt to use logical palettes", 'l', HELPCTX(colours_logpal), - dlg_stdcheckbox_handler, I(offsetof(Config,try_palette))); + conf_checkbox_handler, I(CONF_try_palette)); ctrl_checkbox(s, "Use system colours", 's', HELPCTX(colours_system), - dlg_stdcheckbox_handler, I(offsetof(Config,system_colour))); + conf_checkbox_handler, I(CONF_system_colour)); /* @@ -316,8 +316,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, s = ctrl_getset(b, "Window", "size", "Set the size of the window"); ctrl_radiobuttons(s, "When window is resized:", 'z', 1, HELPCTX(window_resize), - dlg_stdradiobutton_handler, - I(offsetof(Config, resize_action)), + conf_radiobutton_handler, + I(CONF_resize_action), "Change the number of rows and columns", I(RESIZE_TERM), "Change the size of the font", I(RESIZE_FONT), "Change font size only when maximised", I(RESIZE_EITHER), @@ -331,20 +331,20 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, s = ctrl_getset(b, "Window/Behaviour", "main", NULL); ctrl_checkbox(s, "Window closes on ALT-F4", '4', HELPCTX(behaviour_altf4), - dlg_stdcheckbox_handler, I(offsetof(Config,alt_f4))); + conf_checkbox_handler, I(CONF_alt_f4)); ctrl_checkbox(s, "System menu appears on ALT-Space", 'y', HELPCTX(behaviour_altspace), - dlg_stdcheckbox_handler, I(offsetof(Config,alt_space))); + conf_checkbox_handler, I(CONF_alt_space)); ctrl_checkbox(s, "System menu appears on ALT alone", 'l', HELPCTX(behaviour_altonly), - dlg_stdcheckbox_handler, I(offsetof(Config,alt_only))); + conf_checkbox_handler, I(CONF_alt_only)); ctrl_checkbox(s, "Ensure window is always on top", 'e', HELPCTX(behaviour_alwaysontop), - dlg_stdcheckbox_handler, I(offsetof(Config,alwaysontop))); + conf_checkbox_handler, I(CONF_alwaysontop)); ctrl_checkbox(s, "Full screen on Alt-Enter", 'f', HELPCTX(behaviour_altenter), - dlg_stdcheckbox_handler, - I(offsetof(Config,fullscreenonaltenter))); + conf_checkbox_handler, + I(CONF_fullscreenonaltenter)); /* * Windows supports a local-command proxy. This also means we @@ -356,8 +356,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_RADIO && - c->generic.context.i == offsetof(Config, proxy_type)) { - assert(c->generic.handler == dlg_stdradiobutton_handler); + c->generic.context.i == CONF_proxy_type) { + assert(c->generic.handler == conf_radiobutton_handler); c->radio.nbuttons++; c->radio.buttons = sresize(c->radio.buttons, c->radio.nbuttons, char *); @@ -373,9 +373,8 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, for (i = 0; i < s->ncontrols; i++) { c = s->ctrls[i]; if (c->generic.type == CTRL_EDITBOX && - c->generic.context.i == - offsetof(Config, proxy_telnet_command)) { - assert(c->generic.handler == dlg_stdeditbox_handler); + c->generic.context.i == CONF_proxy_telnet_command) { + assert(c->generic.handler == conf_editbox_handler); sfree(c->generic.label); c->generic.label = dupstr("Telnet command, or local" " proxy command"); @@ -399,6 +398,6 @@ void win_setup_config_box(struct controlbox *b, HWND *hwndp, int has_help, ctrl_filesel(s, "X authority file for local display", 't', NULL, FALSE, "Select X authority file", HELPCTX(ssh_tunnels_xauthority), - dlg_stdfilesel_handler, I(offsetof(Config, xauthfile))); + conf_filesel_handler, I(CONF_xauthfile)); } } diff --git a/windows/winctrls.c b/windows/winctrls.c index 7c6bf8db..8453e2e6 100644 --- a/windows/winctrls.c +++ b/windows/winctrls.c @@ -2100,13 +2100,23 @@ void dlg_editbox_set(union control *ctrl, void *dlg, char const *text) SetDlgItemText(dp->hwnd, c->base_id+1, text); } -void dlg_editbox_get(union control *ctrl, void *dlg, char *buffer, int length) +char *dlg_editbox_get(union control *ctrl, void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; struct winctrl *c = dlg_findbyctrl(dp, ctrl); + char *ret; + int size; assert(c && c->ctrl->generic.type == CTRL_EDITBOX); - GetDlgItemText(dp->hwnd, c->base_id+1, buffer, length); - buffer[length-1] = '\0'; + + size = 0; + ret = NULL; + do { + size = size * 4 / 3 + 512; + ret = sresize(ret, size, char); + GetDlgItemText(dp->hwnd, c->base_id+1, ret, size); + } while (!memchr(ret, '\0', size-1)); + + return ret; } /* The `listbox' functions can also apply to combo boxes. */ @@ -2471,8 +2481,10 @@ int dlg_coloursel_results(union control *ctrl, void *dlg, void dlg_auto_set_fixed_pitch_flag(void *dlg) { struct dlgparam *dp = (struct dlgparam *)dlg; - Config *cfg = (Config *)dp->data; - HFONT font; + Conf *conf = (Conf *)dp->data; + FontSpec *font; + int quality; + HFONT hfont; HDC hdc; TEXTMETRIC tm; int is_var; @@ -2483,16 +2495,19 @@ void dlg_auto_set_fixed_pitch_flag(void *dlg) * dialog box as false. * * We assume here that any client of the dlg_* mechanism which is - * using font selectors at all is also using a normal 'Config *' + * using font selectors at all is also using a normal 'Conf *' * as dp->data. */ - font = CreateFont(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, - DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg->font_quality), - FIXED_PITCH | FF_DONTCARE, cfg->font.name); + quality = conf_get_int(conf, CONF_font_quality); + font = conf_get_fontspec(conf, CONF_font); + + hfont = CreateFont(0, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, + DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, + CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality), + FIXED_PITCH | FF_DONTCARE, font->name); hdc = GetDC(NULL); - if (font && hdc && SelectObject(hdc, font) && GetTextMetrics(hdc, &tm)) { + if (font && hdc && SelectObject(hdc, hfont) && GetTextMetrics(hdc, &tm)) { /* Note that the TMPF_FIXED_PITCH bit is defined upside down :-( */ is_var = (tm.tmPitchAndFamily & TMPF_FIXED_PITCH); } else { @@ -2500,8 +2515,8 @@ void dlg_auto_set_fixed_pitch_flag(void *dlg) } if (hdc) ReleaseDC(NULL, hdc); - if (font) - DeleteObject(font); + if (hfont) + DeleteObject(hfont); if (is_var) dp->fixed_pitch_fonts = FALSE; diff --git a/windows/windlg.c b/windows/windlg.c index 7377cd3a..c24ec58c 100644 --- a/windows/windlg.c +++ b/windows/windlg.c @@ -44,7 +44,7 @@ static struct dlgparam dp; static char **events = NULL; static int nevents = 0, negsize = 0; -extern Config cfg; /* defined in window.c */ +extern Conf *conf; /* defined in window.c */ #define PRINTER_DISABLED_STRING "None (printing disabled)" @@ -648,7 +648,7 @@ int do_config(void) dp_add_tree(&dp, &ctrls_panel); dp.wintitle = dupprintf("%s Configuration", appname); dp.errtitle = dupprintf("%s Error", appname); - dp.data = &cfg; + dp.data = conf; dlg_auto_set_fixed_pitch_flag(&dp); dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */ @@ -666,15 +666,15 @@ int do_config(void) int do_reconfig(HWND hwnd, int protcfginfo) { - Config backup_cfg; - int ret; + Conf *backup_conf; + int ret, protocol; - backup_cfg = cfg; /* structure copy */ + backup_conf = conf_copy(conf); ctrlbox = ctrl_new_box(); - setup_config_box(ctrlbox, TRUE, cfg.protocol, protcfginfo); - win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), TRUE, - cfg.protocol); + protocol = conf_get_int(conf, CONF_protocol); + setup_config_box(ctrlbox, TRUE, protocol, protcfginfo); + win_setup_config_box(ctrlbox, &dp.hwnd, has_help(), TRUE, protocol); dp_init(&dp); winctrl_init(&ctrls_base); winctrl_init(&ctrls_panel); @@ -682,7 +682,7 @@ int do_reconfig(HWND hwnd, int protcfginfo) dp_add_tree(&dp, &ctrls_panel); dp.wintitle = dupprintf("%s Reconfiguration", appname); dp.errtitle = dupprintf("%s Error", appname); - dp.data = &cfg; + dp.data = conf; dlg_auto_set_fixed_pitch_flag(&dp); dp.shortcuts['g'] = TRUE; /* the treeview: `Cate&gory' */ @@ -695,7 +695,9 @@ int do_reconfig(HWND hwnd, int protcfginfo) dp_cleanup(&dp); if (!ret) - cfg = backup_cfg; /* structure copy */ + conf_copy_into(conf, backup_conf); + + conf_free(backup_conf); return ret; } diff --git a/windows/window.c b/windows/window.c index c8c2b56d..908c1f68 100644 --- a/windows/window.c +++ b/windows/window.c @@ -80,7 +80,7 @@ static Mouse_Button translate_button(Mouse_Button button); static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output); -static void cfgtopalette(void); +static void conftopalette(void); static void systopalette(void); static void init_palette(void); static void init_fonts(int, int); @@ -140,7 +140,11 @@ static struct { enum { SYSMENU, CTXMENU }; static HMENU savedsess_menu; -Config cfg; /* exported to windlg.c */ +Conf *conf; /* exported to windlg.c */ + +static void conf_cache_data(void); +int cursor_type; +int vtmode; static struct sesslist sesslist; /* for saved-session menu */ @@ -223,7 +227,7 @@ static void start_backend(void) * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ - back = backend_from_proto(cfg.protocol); + back = backend_from_proto(conf_get_int(conf, CONF_protocol)); if (back == NULL) { char *str = dupprintf("%s Internal Error", appname); MessageBox(NULL, "Unsupported protocol number found", @@ -232,22 +236,24 @@ static void start_backend(void) cleanup_exit(1); } - error = back->init(NULL, &backhandle, &cfg, - cfg.host, cfg.port, &realhost, cfg.tcp_nodelay, - cfg.tcp_keepalives); + error = back->init(NULL, &backhandle, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, + conf_get_int(conf, CONF_tcp_nodelay), + conf_get_int(conf, CONF_tcp_keepalives)); back->provide_logctx(backhandle, logctx); if (error) { char *str = dupprintf("%s Error", appname); sprintf(msg, "Unable to open connection to\n" - "%.800s\n" "%s", cfg_dest(&cfg), error); + "%.800s\n" "%s", conf_dest(conf), error); MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK); sfree(str); exit(0); } window_name = icon_name = NULL; - if (*cfg.wintitle) { - title = cfg.wintitle; - } else { + title = conf_get_str(conf, CONF_wintitle); + if (!*title) { sprintf(msg, "%s - %s", realhost, appname); title = msg; } @@ -263,7 +269,7 @@ static void start_backend(void) /* * Set up a line discipline. */ - ldisc = ldisc_create(&cfg, term, back, backhandle, NULL); + ldisc = ldisc_create(conf, term, back, backhandle, NULL); /* * Destroy the Restart Session menu item. (This will return @@ -364,6 +370,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) init_flashwindow(); + conf = conf_new(); + /* * Initialize COM. */ @@ -395,9 +403,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) if (b) default_port = b->default_port; } - cfg.logtype = LGTYP_NONE; + conf_set_int(conf, CONF_logtype, LGTYP_NONE); - do_defaults(NULL, &cfg); + do_defaults(NULL, conf); p = cmdline; @@ -422,8 +430,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) while (i > 1 && isspace(p[i - 1])) i--; p[i] = '\0'; - do_defaults(p + 1, &cfg); - if (!cfg_launchable(&cfg) && !do_config()) { + do_defaults(p + 1, conf); + if (!conf_launchable(conf) && !do_config()) { cleanup_exit(0); } allow_launch = TRUE; /* allow it to be launched directly */ @@ -431,15 +439,16 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) /* * An initial & means we've been given a command line * containing the hex value of a HANDLE for a file - * mapping object, which we must then extract as a - * config. + * mapping object, which we must then interpret as a + * serialised Conf. */ HANDLE filemap; - Config *cp; - if (sscanf(p + 1, "%p", &filemap) == 1 && + void *cp; + unsigned cpsize; + if (sscanf(p + 1, "%p:%u", &filemap, &cpsize) == 1 && (cp = MapViewOfFile(filemap, FILE_MAP_READ, - 0, 0, sizeof(Config))) != NULL) { - cfg = *cp; + 0, 0, cpsize)) != NULL) { + conf_deserialise(conf, cp, cpsize); UnmapViewOfFile(cp); CloseHandle(filemap); } else if (!do_config()) { @@ -461,7 +470,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) int ret; ret = cmdline_process_param(p, i+1isbold) { fw_dontcare = FW_BOLD; fw_bold = FW_HEAVY; } else { @@ -1409,7 +1421,7 @@ static void init_fonts(int pick_width, int pick_height) if (pick_height) font_height = pick_height; else { - font_height = cfg.font.height; + font_height = font->height; if (font_height > 0) { font_height = -MulDiv(font_height, GetDeviceCaps(hdc, LOGPIXELSY), 72); @@ -1417,13 +1429,14 @@ static void init_fonts(int pick_width, int pick_height) } font_width = pick_width; + quality = conf_get_int(conf, CONF_font_quality); #define f(i,c,w,u) \ fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \ c, OUT_DEFAULT_PRECIS, \ - CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg.font_quality), \ - FIXED_PITCH | FF_DONTCARE, cfg.font.name) + CLIP_DEFAULT_PRECIS, quality, \ + FIXED_PITCH | FF_DONTCARE, font->name) - f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE); + f(FONT_NORMAL, font->charset, fw_dontcare, FALSE); SelectObject(hdc, fonts[FONT_NORMAL]); GetTextMetrics(hdc, &tm); @@ -1466,7 +1479,7 @@ static void init_fonts(int pick_width, int pick_height) ucsdata.dbcs_screenfont = (cpinfo.MaxCharSize > 1); } - f(FONT_UNDERLINE, cfg.font.charset, fw_dontcare, TRUE); + f(FONT_UNDERLINE, font->charset, fw_dontcare, TRUE); /* * Some fonts, e.g. 9-pt Courier, draw their underlines @@ -1517,7 +1530,7 @@ static void init_fonts(int pick_width, int pick_height) } if (bold_mode == BOLD_FONT) { - f(FONT_BOLD, cfg.font.charset, fw_bold, FALSE); + f(FONT_BOLD, font->charset, fw_bold, FALSE); } #undef f @@ -1551,15 +1564,16 @@ static void init_fonts(int pick_width, int pick_height) } fontflag[0] = fontflag[1] = fontflag[2] = 1; - init_ucs(&cfg, &ucsdata); + init_ucs(conf, &ucsdata); } static void another_font(int fontno) { int basefont; - int fw_dontcare, fw_bold; + int fw_dontcare, fw_bold, quality; int c, u, w, x; char *s; + FontSpec *font; if (fontno < 0 || fontno >= FONT_MAXNO || fontflag[fontno]) return; @@ -1568,7 +1582,9 @@ static void another_font(int fontno) if (basefont != fontno && !fontflag[basefont]) another_font(basefont); - if (cfg.font.isbold) { + font = conf_get_fontspec(conf, CONF_font); + + if (font->isbold) { fw_dontcare = FW_BOLD; fw_bold = FW_HEAVY; } else { @@ -1576,10 +1592,10 @@ static void another_font(int fontno) fw_bold = FW_BOLD; } - c = cfg.font.charset; + c = font->charset; w = fw_dontcare; u = FALSE; - s = cfg.font.name; + s = font->name; x = font_width; if (fontno & FONT_WIDE) @@ -1593,10 +1609,12 @@ static void another_font(int fontno) if (fontno & FONT_UNDERLINE) u = TRUE; + quality = conf_get_int(conf, CONF_font_quality); + fonts[fontno] = CreateFont(font_height * (1 + !!(fontno & FONT_HIGH)), x, 0, 0, w, FALSE, u, FALSE, c, OUT_DEFAULT_PRECIS, - CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg.font_quality), + CLIP_DEFAULT_PRECIS, FONT_QUALITY(quality), DEFAULT_PITCH | FF_DONTCARE, s); fontflag[fontno] = 1; @@ -1619,11 +1637,11 @@ void request_resize(void *frontend, int w, int h) /* If the window is maximized supress resizing attempts */ if (IsZoomed(hwnd)) { - if (cfg.resize_action == RESIZE_TERM) + if (conf_get_int(conf, CONF_resize_action) == RESIZE_TERM) return; } - if (cfg.resize_action == RESIZE_DISABLED) return; + if (conf_get_int(conf, CONF_resize_action) == RESIZE_DISABLED) return; if (h == term->rows && w == term->cols) return; /* Sanity checks ... */ @@ -1654,9 +1672,10 @@ void request_resize(void *frontend, int w, int h) } } - term_size(term, h, w, cfg.savelines); + term_size(term, h, w, conf_get_int(conf, CONF_savelines)); - if (cfg.resize_action != RESIZE_FONT && !IsZoomed(hwnd)) { + if (conf_get_int(conf, CONF_resize_action) != RESIZE_FONT && + !IsZoomed(hwnd)) { width = extra_width + font_width * w; height = extra_height + font_height * h; @@ -1677,7 +1696,7 @@ static void reset_window(int reinit) { * This function doesn't like to change the terminal size but if the * font size is locked that may be it's only soluion. */ - int win_width, win_height; + int win_width, win_height, resize_action, window_border; RECT cr, wr; #ifdef RDB_DEBUG_PATCH @@ -1691,7 +1710,11 @@ static void reset_window(int reinit) { win_width = cr.right - cr.left; win_height = cr.bottom - cr.top; - if (cfg.resize_action == RESIZE_DISABLED) reinit = 2; + resize_action = conf_get_int(conf, CONF_resize_action); + window_border = conf_get_int(conf, CONF_window_border); + + if (resize_action == RESIZE_DISABLED) + reinit = 2; /* Are we being forced to reload the fonts ? */ if (reinit>1) { @@ -1726,9 +1749,9 @@ static void reset_window(int reinit) { extra_width = wr.right - wr.left - cr.right + cr.left; extra_height = wr.bottom - wr.top - cr.bottom + cr.top; - if (cfg.resize_action != RESIZE_TERM) { - if ( font_width != win_width/term->cols || - font_height != win_height/term->rows) { + if (resize_action != RESIZE_TERM) { + if (font_width != win_width/term->cols || + font_height != win_height/term->rows) { deinit_fonts(); init_fonts(win_width/term->cols, win_height/term->rows); offset_width = (win_width-font_width*term->cols)/2; @@ -1740,13 +1763,13 @@ static void reset_window(int reinit) { #endif } } else { - if ( font_width * term->cols != win_width || - font_height * term->rows != win_height) { + if (font_width * term->cols != win_width || + font_height * term->rows != win_height) { /* Our only choice at this point is to change the * size of the terminal; Oh well. */ term_size(term, win_height/font_height, win_width/font_width, - cfg.savelines); + conf_get_int(conf, CONF_savelines)); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; InvalidateRect(hwnd, NULL, TRUE); @@ -1766,7 +1789,7 @@ static void reset_window(int reinit) { debug((27, "reset_window() -> Forced re-init")); #endif - offset_width = offset_height = cfg.window_border; + offset_width = offset_height = window_border; extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2; @@ -1791,10 +1814,10 @@ static void reset_window(int reinit) { * window. But that may be too big for the screen which forces us * to change the terminal. */ - if ((cfg.resize_action == RESIZE_TERM && reinit<=0) || - (cfg.resize_action == RESIZE_EITHER && reinit<0) || + if ((resize_action == RESIZE_TERM && reinit<=0) || + (resize_action == RESIZE_EITHER && reinit<0) || reinit>0) { - offset_width = offset_height = cfg.window_border; + offset_width = offset_height = window_border; extra_width = wr.right - wr.left - cr.right + cr.left + offset_width*2; extra_height = wr.bottom - wr.top - cr.bottom + cr.top +offset_height*2; @@ -1811,7 +1834,7 @@ static void reset_window(int reinit) { /* Grrr too big */ if ( term->rows > height || term->cols > width ) { - if (cfg.resize_action == RESIZE_EITHER) { + if (resize_action == RESIZE_EITHER) { /* Make the font the biggest we can */ if (term->cols > width) font_width = (ss.right - ss.left - extra_width) @@ -1828,7 +1851,8 @@ static void reset_window(int reinit) { } else { if ( height > term->rows ) height = term->rows; if ( width > term->cols ) width = term->cols; - term_size(term, height, width, cfg.savelines); + term_size(term, height, width, + conf_get_int(conf, CONF_savelines)); #ifdef RDB_DEBUG_PATCH debug((27, "reset_window() -> term resize to (%d,%d)", height, width)); @@ -1853,12 +1877,12 @@ static void reset_window(int reinit) { /* We're allowed to or must change the font but do we want to ? */ - if (font_width != (win_width-cfg.window_border*2)/term->cols || - font_height != (win_height-cfg.window_border*2)/term->rows) { + if (font_width != (win_width-window_border*2)/term->cols || + font_height != (win_height-window_border*2)/term->rows) { deinit_fonts(); - init_fonts((win_width-cfg.window_border*2)/term->cols, - (win_height-cfg.window_border*2)/term->rows); + init_fonts((win_width-window_border*2)/term->cols, + (win_height-window_border*2)/term->rows); offset_width = (win_width-font_width*term->cols)/2; offset_height = (win_height-font_height*term->rows)/2; @@ -1887,7 +1911,8 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt) { int thistime = GetMessageTime(); - if (send_raw_mouse && !(cfg.mouse_override && shift)) { + if (send_raw_mouse && + !(shift && conf_get_int(conf, CONF_mouse_override))) { lastbtn = MBT_NOTHING; term_mouse(term, b, translate_button(b), MA_CLICK, x, y, shift, ctrl, alt); @@ -1917,9 +1942,11 @@ static Mouse_Button translate_button(Mouse_Button button) if (button == MBT_LEFT) return MBT_SELECT; if (button == MBT_MIDDLE) - return cfg.mouse_is_xterm == 1 ? MBT_PASTE : MBT_EXTEND; + return conf_get_int(conf, CONF_mouse_is_xterm) == 1 ? + MBT_PASTE : MBT_EXTEND; if (button == MBT_RIGHT) - return cfg.mouse_is_xterm == 1 ? MBT_EXTEND : MBT_PASTE; + return conf_get_int(conf, CONF_mouse_is_xterm) == 1 ? + MBT_EXTEND : MBT_PASTE; return 0; /* shouldn't happen */ } @@ -1928,8 +1955,8 @@ static void show_mouseptr(int show) /* NB that the counter in ShowCursor() is also frobbed by * update_mouse_pointer() */ static int cursor_visible = 1; - if (!cfg.hide_mouseptr) /* override if this feature disabled */ - show = 1; + if (!conf_get_int(conf, CONF_hide_mouseptr)) + show = 1; /* override if this feature disabled */ if (cursor_visible && !show) ShowCursor(FALSE); else if (!cursor_visible && show) @@ -1954,14 +1981,15 @@ static int resizing; void notify_remote_exit(void *fe) { - int exitcode; + int exitcode, close_on_exit; if (!session_closed && (exitcode = back->exitcode(backhandle)) >= 0) { + close_on_exit = conf_get_int(conf, CONF_close_on_exit); /* Abnormal exits will already have set session_closed and taken * appropriate action. */ - if (cfg.close_on_exit == FORCE_ON || - (cfg.close_on_exit == AUTO && exitcode != INT_MAX)) { + if (close_on_exit == FORCE_ON || + (close_on_exit == AUTO && exitcode != INT_MAX)) { PostQuitMessage(0); } else { must_close_session = TRUE; @@ -1985,6 +2013,13 @@ void timer_change_notify(long next) timing_next_time = next; } +static void conf_cache_data(void) +{ + /* Cache some items from conf to speed lookups in very hot code */ + cursor_type = conf_get_int(conf, CONF_cursor_type); + vtmode = conf_get_int(conf, CONF_vtmode); +} + static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { @@ -1994,6 +2029,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, static int fullscr_on_max = FALSE; static int processed_resize = FALSE; static UINT last_mousemove = 0; + int resize_action; switch (message) { case WM_TIMER: @@ -2014,7 +2050,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, char *str; show_mouseptr(1); str = dupprintf("%s Exit Confirmation", appname); - if (!cfg.warn_on_close || session_closed || + if (session_closed || !conf_get_int(conf, CONF_warn_on_close) || MessageBox(hwnd, "Are you sure you want to close this session?", str, MB_ICONWARNING | MB_OKCANCEL | MB_DEFBUTTON1) @@ -2061,7 +2097,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * config structure. */ SECURITY_ATTRIBUTES sa; - Config *p; + void *p; + int size; + + size = conf_serialised_size(conf); sa.nLength = sizeof(sa); sa.lpSecurityDescriptor = NULL; @@ -2069,18 +2108,16 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, filemap = CreateFileMapping(INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE, - 0, sizeof(Config), NULL); + 0, size, NULL); if (filemap && filemap != INVALID_HANDLE_VALUE) { - p = (Config *) MapViewOfFile(filemap, - FILE_MAP_WRITE, - 0, 0, sizeof(Config)); + p = MapViewOfFile(filemap, FILE_MAP_WRITE, 0, 0, size); if (p) { - *p = cfg; /* structure copy */ + conf_serialise(conf, p); UnmapViewOfFile(p); } } inherit_handles = TRUE; - sprintf(c, "putty &%p", filemap); + sprintf(c, "putty &%p:%u", filemap, (unsigned)size); cl = c; } else if (wParam == IDM_SAVEDSESS) { unsigned int sessno = ((lParam - IDM_SAVED_MIN) @@ -2124,7 +2161,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case IDM_RECONF: { - Config prev_cfg; + Conf *prev_conf; int init_lvl = 1; int reconfig_result; @@ -2133,8 +2170,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, else reconfiguring = TRUE; - GetWindowText(hwnd, cfg.wintitle, sizeof(cfg.wintitle)); - prev_cfg = cfg; + /* + * Copy the current window title into the stored + * previous configuration, so that doing nothing to + * the window title field in the config box doesn't + * reset the title to its startup state. + */ + conf_set_str(conf, CONF_wintitle, window_name); + + prev_conf = conf_copy(conf); reconfig_result = do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0); @@ -2142,53 +2186,60 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, if (!reconfig_result) break; + conf_cache_data(); + + resize_action = conf_get_int(conf, CONF_resize_action); { /* Disable full-screen if resizing forbidden */ int i; for (i = 0; i < lenof(popup_menus); i++) EnableMenuItem(popup_menus[i].menu, IDM_FULLSCREEN, MF_BYCOMMAND | - (cfg.resize_action == RESIZE_DISABLED) + (resize_action == RESIZE_DISABLED) ? MF_GRAYED : MF_ENABLED); /* Gracefully unzoom if necessary */ - if (IsZoomed(hwnd) && - (cfg.resize_action == RESIZE_DISABLED)) { + if (IsZoomed(hwnd) && (resize_action == RESIZE_DISABLED)) ShowWindow(hwnd, SW_RESTORE); - } } /* Pass new config data to the logging module */ - log_reconfig(logctx, &cfg); + log_reconfig(logctx, conf); sfree(logpal); /* * Flush the line discipline's edit buffer in the * case where local editing has just been disabled. */ + ldisc_configure(ldisc, conf); if (ldisc) ldisc_send(ldisc, NULL, 0, 0); if (pal) DeleteObject(pal); logpal = NULL; pal = NULL; - cfgtopalette(); + conftopalette(); init_palette(); /* Pass new config data to the terminal */ - term_reconfig(term, &cfg); + term_reconfig(term, conf); /* Pass new config data to the back end */ if (back) - back->reconfig(backhandle, &cfg); + back->reconfig(backhandle, conf); /* Screen size changed ? */ - if (cfg.height != prev_cfg.height || - cfg.width != prev_cfg.width || - cfg.savelines != prev_cfg.savelines || - cfg.resize_action == RESIZE_FONT || - (cfg.resize_action == RESIZE_EITHER && IsZoomed(hwnd)) || - cfg.resize_action == RESIZE_DISABLED) - term_size(term, cfg.height, cfg.width, cfg.savelines); + if (conf_get_int(conf, CONF_height) != + conf_get_int(prev_conf, CONF_height) || + conf_get_int(conf, CONF_width) != + conf_get_int(prev_conf, CONF_width) || + conf_get_int(conf, CONF_savelines) != + conf_get_int(prev_conf, CONF_savelines) || + resize_action == RESIZE_FONT || + (resize_action == RESIZE_EITHER && IsZoomed(hwnd)) || + resize_action == RESIZE_DISABLED) + term_size(term, conf_get_int(conf, CONF_height), + conf_get_int(conf, CONF_width), + conf_get_int(conf, CONF_savelines)); /* Enable or disable the scroll bar, etc */ { @@ -2197,8 +2248,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, GetWindowLongPtr(hwnd, GWL_EXSTYLE); nexflag = exflag; - if (cfg.alwaysontop != prev_cfg.alwaysontop) { - if (cfg.alwaysontop) { + if (conf_get_int(conf, CONF_alwaysontop) != + conf_get_int(prev_conf, CONF_alwaysontop)) { + if (conf_get_int(conf, CONF_alwaysontop)) { nexflag |= WS_EX_TOPMOST; SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); @@ -2208,25 +2260,26 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, SWP_NOMOVE | SWP_NOSIZE); } } - if (cfg.sunken_edge) + if (conf_get_int(conf, CONF_sunken_edge)) nexflag |= WS_EX_CLIENTEDGE; else nexflag &= ~(WS_EX_CLIENTEDGE); nflg = flag; - if (is_full_screen() ? - cfg.scrollbar_in_fullscreen : cfg.scrollbar) + if (conf_get_int(conf, is_full_screen() ? + CONF_scrollbar_in_fullscreen : + CONF_scrollbar)) nflg |= WS_VSCROLL; else nflg &= ~WS_VSCROLL; - if (cfg.resize_action == RESIZE_DISABLED || + if (resize_action == RESIZE_DISABLED || is_full_screen()) nflg &= ~WS_THICKFRAME; else nflg |= WS_THICKFRAME; - if (cfg.resize_action == RESIZE_DISABLED) + if (resize_action == RESIZE_DISABLED) nflg &= ~WS_MAXIMIZEBOX; else nflg |= WS_MAXIMIZEBOX; @@ -2247,34 +2300,47 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } /* Oops */ - if (cfg.resize_action == RESIZE_DISABLED && IsZoomed(hwnd)) { + if (resize_action == RESIZE_DISABLED && IsZoomed(hwnd)) { force_normal(hwnd); init_lvl = 2; } - set_title(NULL, cfg.wintitle); + set_title(NULL, conf_get_str(conf, CONF_wintitle)); if (IsIconic(hwnd)) { SetWindowText(hwnd, - cfg.win_name_always ? window_name : - icon_name); + conf_get_int(conf, CONF_win_name_always) ? + window_name : icon_name); } - if (strcmp(cfg.font.name, prev_cfg.font.name) != 0 || - strcmp(cfg.line_codepage, prev_cfg.line_codepage) != 0 || - cfg.font.isbold != prev_cfg.font.isbold || - cfg.font.height != prev_cfg.font.height || - cfg.font.charset != prev_cfg.font.charset || - cfg.font_quality != prev_cfg.font_quality || - cfg.vtmode != prev_cfg.vtmode || - cfg.bold_colour != prev_cfg.bold_colour || - cfg.resize_action == RESIZE_DISABLED || - cfg.resize_action == RESIZE_EITHER || - (cfg.resize_action != prev_cfg.resize_action)) - init_lvl = 2; + { + FontSpec *font = conf_get_fontspec(conf, CONF_font); + FontSpec *prev_font = conf_get_fontspec(prev_conf, + CONF_font); + + if (!strcmp(font->name, prev_font->name) || + !strcmp(conf_get_str(conf, CONF_line_codepage), + conf_get_str(prev_conf, CONF_line_codepage)) || + font->isbold != prev_font->isbold || + font->height != prev_font->height || + font->charset != prev_font->charset || + conf_get_int(conf, CONF_font_quality) != + conf_get_int(prev_conf, CONF_font_quality) || + conf_get_int(conf, CONF_vtmode) != + conf_get_int(prev_conf, CONF_vtmode) || + conf_get_int(conf, CONF_bold_colour) != + conf_get_int(prev_conf, CONF_bold_colour) || + resize_action == RESIZE_DISABLED || + resize_action == RESIZE_EITHER || + resize_action != conf_get_int(prev_conf, + CONF_resize_action)) + init_lvl = 2; + } InvalidateRect(hwnd, NULL, TRUE); reset_window(init_lvl); net_pending_errors(); + + conf_free(prev_conf); } break; case IDM_COPYALL: @@ -2352,7 +2418,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_MBUTTONUP: case WM_RBUTTONUP: if (message == WM_RBUTTONDOWN && - ((wParam & MK_CONTROL) || (cfg.mouse_is_xterm == 2))) { + ((wParam & MK_CONTROL) || + (conf_get_int(conf, CONF_mouse_is_xterm) == 2))) { POINT cursorpos; show_mouseptr(1); /* make sure pointer is visible */ @@ -2659,7 +2726,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, debug((27, "WM_EXITSIZEMOVE")); #endif if (need_backend_resize) { - term_size(term, cfg.height, cfg.width, cfg.savelines); + term_size(term, conf_get_int(conf, CONF_height), + conf_get_int(conf, CONF_width), + conf_get_int(conf, CONF_savelines)); InvalidateRect(hwnd, NULL, TRUE); } break; @@ -2669,13 +2738,15 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * 1) Keep the sizetip uptodate * 2) Make sure the window size is _stepped_ in units of the font size. */ - if (cfg.resize_action == RESIZE_TERM || - (cfg.resize_action == RESIZE_EITHER && !is_alt_pressed())) { + resize_action = conf_get_int(conf, CONF_resize_action); + if (resize_action == RESIZE_TERM || + (resize_action == RESIZE_EITHER && !is_alt_pressed())) { int width, height, w, h, ew, eh; LPRECT r = (LPRECT) lParam; - if ( !need_backend_resize && cfg.resize_action == RESIZE_EITHER && - (cfg.height != term->rows || cfg.width != term->cols )) { + if (!need_backend_resize && resize_action == RESIZE_EITHER && + (conf_get_int(conf, CONF_height) != term->rows || + conf_get_int(conf, CONF_width) != term->cols)) { /* * Great! It seems that both the terminal size and the * font size have been changed and the user is now dragging. @@ -2684,11 +2755,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * font size! * * This would be easier but it seems to be too confusing. - - term_size(term, cfg.height, cfg.width, cfg.savelines); - reset_window(2); */ - cfg.height=term->rows; cfg.width=term->cols; + conf_set_int(conf, CONF_height, term->rows); + conf_set_int(conf, CONF_width, term->cols); InvalidateRect(hwnd, NULL, TRUE); need_backend_resize = TRUE; @@ -2725,8 +2794,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, return 0; } else { int width, height, w, h, rv = 0; - int ex_width = extra_width + (cfg.window_border - offset_width) * 2; - int ex_height = extra_height + (cfg.window_border - offset_height) * 2; + int window_border = conf_get_int(conf, CONF_window_border); + int ex_width = extra_width + (window_border - offset_width) * 2; + int ex_height = extra_height + (window_border - offset_height) * 2; LPRECT r = (LPRECT) lParam; width = r->right - r->left - ex_width; @@ -2762,6 +2832,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, sys_cursor_update(); break; case WM_SIZE: + resize_action = conf_get_int(conf, CONF_resize_action); #ifdef RDB_DEBUG_PATCH debug((27, "WM_SIZE %s (%d,%d)", (wParam == SIZE_MINIMIZED) ? "SIZE_MINIMIZED": @@ -2773,7 +2844,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, #endif if (wParam == SIZE_MINIMIZED) SetWindowText(hwnd, - cfg.win_name_always ? window_name : icon_name); + conf_get_int(conf, CONF_win_name_always) ? + window_name : icon_name); if (wParam == SIZE_RESTORED || wParam == SIZE_MAXIMIZED) SetWindowText(hwnd, window_name); if (wParam == SIZE_RESTORED) { @@ -2806,12 +2878,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, processed_resize = TRUE; - if (cfg.resize_action == RESIZE_DISABLED) { + if (resize_action == RESIZE_DISABLED) { /* A resize, well it better be a minimize. */ reset_window(-1); } else { int width, height, w, h; + int window_border = conf_get_int(conf, CONF_window_border); width = LOWORD(lParam); height = HIWORD(lParam); @@ -2820,36 +2893,36 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, was_zoomed = 1; prev_rows = term->rows; prev_cols = term->cols; - if (cfg.resize_action == RESIZE_TERM) { + if (resize_action == RESIZE_TERM) { w = width / font_width; if (w < 1) w = 1; h = height / font_height; if (h < 1) h = 1; - term_size(term, h, w, cfg.savelines); + term_size(term, h, w, conf_get_int(conf, CONF_savelines)); } reset_window(0); } else if (wParam == SIZE_RESTORED && was_zoomed) { was_zoomed = 0; - if (cfg.resize_action == RESIZE_TERM) { - w = (width-cfg.window_border*2) / font_width; + if (resize_action == RESIZE_TERM) { + w = (width-window_border*2) / font_width; if (w < 1) w = 1; - h = (height-cfg.window_border*2) / font_height; + h = (height-window_border*2) / font_height; if (h < 1) h = 1; - term_size(term, h, w, cfg.savelines); + term_size(term, h, w, conf_get_int(conf, CONF_savelines)); reset_window(2); - } else if (cfg.resize_action != RESIZE_FONT) + } else if (resize_action != RESIZE_FONT) reset_window(2); else reset_window(0); } else if (wParam == SIZE_MINIMIZED) { /* do nothing */ - } else if (cfg.resize_action == RESIZE_TERM || - (cfg.resize_action == RESIZE_EITHER && + } else if (resize_action == RESIZE_TERM || + (resize_action == RESIZE_EITHER && !is_alt_pressed())) { - w = (width-cfg.window_border*2) / font_width; + w = (width-window_border*2) / font_width; if (w < 1) w = 1; - h = (height-cfg.window_border*2) / font_height; + h = (height-window_border*2) / font_height; if (h < 1) h = 1; if (resizing) { @@ -2860,10 +2933,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * opaque drag.) */ need_backend_resize = TRUE; - cfg.height = h; - cfg.width = w; + conf_set_int(conf, CONF_height, h); + conf_set_int(conf, CONF_height, w); } else { - term_size(term, h, w, cfg.savelines); + term_size(term, h, w, conf_get_int(conf, CONF_savelines)); } } else { reset_window(0); @@ -3060,7 +3133,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_SYSCOLORCHANGE: - if (cfg.system_colour) { + if (conf_get_int(conf, CONF_system_colour)) { /* Refresh palette from system colours. */ /* XXX actually this zaps the entire palette. */ systopalette(); @@ -3111,8 +3184,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } else break; - if (send_raw_mouse && - !(cfg.mouse_override && shift_pressed)) { + if (send_raw_mouse && shift_pressed && + !(conf_get_int(conf, CONF_mouse_override))) { /* Mouse wheel position is in screen coordinates for * some reason */ POINT p; @@ -3239,7 +3312,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, x += offset_width; y += offset_height; - if ((attr & TATTR_ACTCURS) && (cfg.cursor_type == 0 || term->big_cursor)) { + if ((attr & TATTR_ACTCURS) && (cursor_type == 0 || term->big_cursor)) { attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS); if (bold_mode == BOLD_COLOURS) attr &= ~ATTR_BOLD; @@ -3249,7 +3322,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, } nfont = 0; - if (cfg.vtmode == VT_POORMAN && lattr != LATTR_NORM) { + if (vtmode == VT_POORMAN && lattr != LATTR_NORM) { /* Assume a poorman font is borken in other ways too. */ lattr = LATTR_WIDE; } else @@ -3553,7 +3626,7 @@ void do_cursor(Context ctx, int x, int y, wchar_t *text, int len, int fnt_width; int char_width; HDC hdc = ctx; - int ctype = cfg.cursor_type; + int ctype = cursor_type; lattr &= LATTR_MODE; @@ -3698,13 +3771,17 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, int r, i, code; unsigned char *p = output; static int alt_sum = 0; + int funky_type = conf_get_int(conf, CONF_funky_type); + int no_applic_k = conf_get_int(conf, CONF_no_applic_k); + int ctrlaltkeys = conf_get_int(conf, CONF_ctrlaltkeys); + int nethack_keypad = conf_get_int(conf, CONF_nethack_keypad); HKL kbd_layout = GetKeyboardLayout(0); /* keys is for ToAsciiEx. There's some ick here, see below. */ static WORD keys[3]; static int compose_char = 0; - static WPARAM compose_key = 0; + static WPARAM compose_keycode = 0; r = GetKeyboardState(keystate); if (!r) @@ -3791,9 +3868,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Nastyness with NUMLock - Shift-NUMLock is left alone though */ - if ((cfg.funky_type == FUNKY_VT400 || - (cfg.funky_type <= FUNKY_LINUX && term->app_keypad_keys && - !cfg.no_applic_k)) + if ((funky_type == FUNKY_VT400 || + (funky_type <= FUNKY_LINUX && term->app_keypad_keys && + !no_applic_k)) && wParam == VK_NUMLOCK && !(keystate[VK_SHIFT] & 0x80)) { wParam = VK_EXECUTE; @@ -3819,7 +3896,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Make sure Ctrl-ALT is not the same as AltGr for ToAscii unless told. */ if (left_alt && (keystate[VK_CONTROL] & 0x80)) { - if (cfg.ctrlaltkeys) + if (ctrlaltkeys) keystate[VK_MENU] = 0; else { keystate[VK_RMENU] = 0x80; @@ -3833,16 +3910,16 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* Note if AltGr was pressed and if it was used as a compose key */ if (!compose_state) { - compose_key = 0x100; - if (cfg.compose_key) { + compose_keycode = 0x100; + if (conf_get_int(conf, CONF_compose_key)) { if (wParam == VK_MENU && (HIWORD(lParam) & KF_EXTENDED)) - compose_key = wParam; + compose_keycode = wParam; } if (wParam == VK_APPS) - compose_key = wParam; + compose_keycode = wParam; } - if (wParam == compose_key) { + if (wParam == compose_keycode) { if (compose_state == 0 && (HIWORD(lParam) & (KF_UP | KF_REPEAT)) == 0) compose_state = 1; @@ -3857,9 +3934,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, compose_state = 0; /* Sanitize the number pad if not using a PC NumPad */ - if (left_alt || (term->app_keypad_keys && !cfg.no_applic_k - && cfg.funky_type != FUNKY_XTERM) - || cfg.funky_type == FUNKY_VT400 || cfg.nethack_keypad || compose_state) { + if (left_alt || (term->app_keypad_keys && !no_applic_k + && funky_type != FUNKY_XTERM) + || funky_type == FUNKY_VT400 || nethack_keypad || compose_state) { if ((HIWORD(lParam) & KF_EXTENDED) == 0) { int nParam = 0; switch (wParam) { @@ -3936,15 +4013,17 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, request_paste(NULL); return 0; } - if (left_alt && wParam == VK_F4 && cfg.alt_f4) { + if (left_alt && wParam == VK_F4 && conf_get_int(conf, CONF_alt_f4)) { return -1; } - if (left_alt && wParam == VK_SPACE && cfg.alt_space) { + if (left_alt && wParam == VK_SPACE && conf_get_int(conf, + CONF_alt_space)) { SendMessage(hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0); return -1; } - if (left_alt && wParam == VK_RETURN && cfg.fullscreenonaltenter && - (cfg.resize_action != RESIZE_DISABLED)) { + if (left_alt && wParam == VK_RETURN && + conf_get_int(conf, CONF_fullscreenonaltenter) && + (conf_get_int(conf, CONF_resize_action) != RESIZE_DISABLED)) { if ((HIWORD(lParam) & (KF_UP | KF_REPEAT)) != KF_REPEAT) flip_full_screen(); return -1; @@ -3956,7 +4035,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } /* Nethack keypad */ - if (cfg.nethack_keypad && !left_alt) { + if (nethack_keypad && !left_alt) { switch (wParam) { case VK_NUMPAD1: *p++ = "bB\002\002"[shift_state & 3]; @@ -3992,9 +4071,9 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (!left_alt) { int xkey = 0; - if (cfg.funky_type == FUNKY_VT400 || - (cfg.funky_type <= FUNKY_LINUX && - term->app_keypad_keys && !cfg.no_applic_k)) switch (wParam) { + if (funky_type == FUNKY_VT400 || + (funky_type <= FUNKY_LINUX && + term->app_keypad_keys && !no_applic_k)) switch (wParam) { case VK_EXECUTE: xkey = 'P'; break; @@ -4008,7 +4087,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, xkey = 'S'; break; } - if (term->app_keypad_keys && !cfg.no_applic_k) + if (term->app_keypad_keys && !no_applic_k) switch (wParam) { case VK_NUMPAD0: xkey = 'p'; @@ -4045,7 +4124,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, xkey = 'n'; break; case VK_ADD: - if (cfg.funky_type == FUNKY_XTERM) { + if (funky_type == FUNKY_XTERM) { if (shift_state) xkey = 'l'; else @@ -4057,15 +4136,15 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; case VK_DIVIDE: - if (cfg.funky_type == FUNKY_XTERM) + if (funky_type == FUNKY_XTERM) xkey = 'o'; break; case VK_MULTIPLY: - if (cfg.funky_type == FUNKY_XTERM) + if (funky_type == FUNKY_XTERM) xkey = 'j'; break; case VK_SUBTRACT: - if (cfg.funky_type == FUNKY_XTERM) + if (funky_type == FUNKY_XTERM) xkey = 'm'; break; @@ -4087,13 +4166,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } if (wParam == VK_BACK && shift_state == 0) { /* Backspace */ - *p++ = (cfg.bksp_is_delete ? 0x7F : 0x08); + *p++ = (conf_get_int(conf, CONF_bksp_is_delete) ? 0x7F : 0x08); *p++ = 0; return -2; } if (wParam == VK_BACK && shift_state == 1) { /* Shift Backspace */ /* We do the opposite of what is configured */ - *p++ = (cfg.bksp_is_delete ? 0x08 : 0x7F); + *p++ = (conf_get_int(conf, CONF_bksp_is_delete) ? 0x08 : 0x7F); *p++ = 0; return -2; } @@ -4237,7 +4316,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; } /* Reorder edit keys to physical order */ - if (cfg.funky_type == FUNKY_VT400 && code <= 6) + if (funky_type == FUNKY_VT400 && code <= 6) code = "\0\2\1\4\5\3\6"[code]; if (term->vt52_mode && code > 0 && code <= 6) { @@ -4245,8 +4324,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, return p - output; } - if (cfg.funky_type == FUNKY_SCO && /* SCO function keys */ - code >= 11 && code <= 34) { + if (funky_type == FUNKY_SCO && code >= 11 && code <= 34) { + /* SCO function keys */ char codes[] = "MNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz@[\\]^_`{"; int index = 0; switch (wParam) { @@ -4268,7 +4347,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, p += sprintf((char *) p, "\x1B[%c", codes[index]); return p - output; } - if (cfg.funky_type == FUNKY_SCO && /* SCO small keypad */ + if (funky_type == FUNKY_SCO && /* SCO small keypad */ code >= 1 && code <= 6) { char codes[] = "HL.FIG"; if (code == 3) { @@ -4278,7 +4357,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } return p - output; } - if ((term->vt52_mode || cfg.funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) { + if ((term->vt52_mode || funky_type == FUNKY_VT100P) && code >= 11 && code <= 24) { int offt = 0; if (code > 15) offt++; @@ -4291,18 +4370,19 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, sprintf((char *) p, "\x1BO%c", code + 'P' - 11 - offt); return p - output; } - if (cfg.funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { + if (funky_type == FUNKY_LINUX && code >= 11 && code <= 15) { p += sprintf((char *) p, "\x1B[[%c", code + 'A' - 11); return p - output; } - if (cfg.funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { + if (funky_type == FUNKY_XTERM && code >= 11 && code <= 14) { if (term->vt52_mode) p += sprintf((char *) p, "\x1B%c", code + 'P' - 11); else p += sprintf((char *) p, "\x1BO%c", code + 'P' - 11); return p - output; } - if (cfg.rxvt_homeend && (code == 1 || code == 4)) { + if ((code == 1 || code == 4) && + conf_get_int(conf, CONF_rxvt_homeend)) { p += sprintf((char *) p, code == 1 ? "\x1B[H" : "\x1BOw"); return p - output; } @@ -4362,7 +4442,8 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, BOOL capsOn=0; /* helg: clear CAPS LOCK state if caps lock switches to cyrillic */ - if(cfg.xlat_capslockcyr && keystate[VK_CAPITAL] != 0) { + if(keystate[VK_CAPITAL] != 0 && + conf_get_int(conf, CONF_xlat_capslockcyr)) { capsOn= !left_alt; keystate[VK_CAPITAL] = 0; } @@ -4512,7 +4593,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * we return -1, which means Windows will give the keystroke * its default handling (i.e. bring up the System menu). */ - if (wParam == VK_MENU && !cfg.alt_only) + if (wParam == VK_MENU && !conf_get_int(conf, CONF_alt_only)) return 0; return -1; @@ -4523,7 +4604,7 @@ void set_title(void *frontend, char *title) sfree(window_name); window_name = snewn(1 + strlen(title), char); strcpy(window_name, title); - if (cfg.win_name_always || !IsIconic(hwnd)) + if (conf_get_int(conf, CONF_win_name_always) || !IsIconic(hwnd)) SetWindowText(hwnd, title); } @@ -4532,7 +4613,7 @@ void set_icon(void *frontend, char *title) sfree(icon_name); icon_name = snewn(1 + strlen(title), char); strcpy(icon_name, title); - if (!cfg.win_name_always && IsIconic(hwnd)) + if (!conf_get_int(conf, CONF_win_name_always) && IsIconic(hwnd)) SetWindowText(hwnd, title); } @@ -4540,7 +4621,8 @@ void set_sbar(void *frontend, int total, int start, int page) { SCROLLINFO si; - if (is_full_screen() ? !cfg.scrollbar_in_fullscreen : !cfg.scrollbar) + if (!conf_get_int(conf, is_full_screen() ? + CONF_scrollbar_in_fullscreen : CONF_scrollbar)) return; si.cbSize = sizeof(si); @@ -4696,7 +4778,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des memcpy(lock, data, len * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, data, len, lock2, len2, NULL, NULL); - if (cfg.rtf_paste) { + if (conf_get_int(conf, CONF_rtf_paste)) { wchar_t unitab[256]; char *rtf = NULL; unsigned char *tdata = (unsigned char *)lock2; @@ -4711,13 +4793,14 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des int attrUnder, lastAttrUnder = 0; int palette[NALLCOLOURS]; int numcolours; + FontSpec *font = conf_get_fontspec(conf, CONF_font); get_unitab(CP_ACP, unitab, 0); - rtfsize = 100 + strlen(cfg.font.name); + rtfsize = 100 + strlen(font->name); rtf = snewn(rtfsize, char); rtflen = sprintf(rtf, "{\\rtf1\\ansi\\deff0{\\fonttbl\\f0\\fmodern %s;}\\f0\\fs%d", - cfg.font.name, cfg.font.height*2); + font->name, font->height*2); /* * Add colour palette @@ -5176,7 +5259,8 @@ static void flash_window_timer(void *ctx, long now) */ static void flash_window(int mode) { - if ((mode == 0) || (cfg.beep_ind == B_IND_DISABLED)) { + int beep_ind = conf_get_int(conf, CONF_beep_ind); + if ((mode == 0) || (beep_ind == B_IND_DISABLED)) { /* stop */ if (flashing) { flashing = 0; @@ -5198,7 +5282,7 @@ static void flash_window(int mode) * "flashing" mode, although I haven't seen this * documented. */ flash_window_ex(FLASHW_ALL | FLASHW_TIMER, - (cfg.beep_ind == B_IND_FLASH ? 0 : 2), + (beep_ind == B_IND_FLASH ? 0 : 2), 0 /* system cursor blink rate */); /* No need to schedule timer */ } else { @@ -5207,7 +5291,7 @@ static void flash_window(int mode) } } - } else if ((mode == 1) && (cfg.beep_ind == B_IND_FLASH)) { + } else if ((mode == 1) && (beep_ind == B_IND_FLASH)) { /* maintain */ if (flashing && !p_FlashWindowEx) { FlashWindow(hwnd, TRUE); /* toggle */ @@ -5241,16 +5325,17 @@ void do_beep(void *frontend, int mode) */ lastbeep = GetTickCount(); } else if (mode == BELL_WAVEFILE) { - if (!PlaySound(cfg.bell_wavefile.path, NULL, + Filename *bell_wavefile = conf_get_filename(conf, CONF_bell_wavefile); + if (!PlaySound(bell_wavefile->path, NULL, SND_ASYNC | SND_FILENAME)) { - char buf[sizeof(cfg.bell_wavefile.path) + 80]; + char buf[sizeof(bell_wavefile->path) + 80]; char otherbuf[100]; sprintf(buf, "Unable to play sound file\n%s\n" - "Using default sound instead", cfg.bell_wavefile.path); + "Using default sound instead", bell_wavefile->path); sprintf(otherbuf, "%.70s Sound Error", appname); MessageBox(hwnd, buf, otherbuf, MB_OK | MB_ICONEXCLAMATION); - cfg.beep = BELL_DEFAULT; + conf_set_int(conf, CONF_beep, BELL_DEFAULT); } } else if (mode == BELL_PCSPEAKER) { static long lastbeep = 0; @@ -5296,8 +5381,9 @@ void set_iconic(void *frontend, int iconic) */ void move_window(void *frontend, int x, int y) { - if (cfg.resize_action == RESIZE_DISABLED || - cfg.resize_action == RESIZE_FONT || + int resize_action = conf_get_int(conf, CONF_resize_action); + if (resize_action == RESIZE_DISABLED || + resize_action == RESIZE_FONT || IsZoomed(hwnd)) return; @@ -5310,7 +5396,7 @@ void move_window(void *frontend, int x, int y) */ void set_zorder(void *frontend, int top) { - if (cfg.alwaysontop) + if (conf_get_int(conf, CONF_alwaysontop)) return; /* ignore */ SetWindowPos(hwnd, top ? HWND_TOP : HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); @@ -5432,7 +5518,7 @@ static void make_full_screen() /* Remove the window furniture. */ style = GetWindowLongPtr(hwnd, GWL_STYLE); style &= ~(WS_CAPTION | WS_BORDER | WS_THICKFRAME); - if (cfg.scrollbar_in_fullscreen) + if (conf_get_int(conf, CONF_scrollbar_in_fullscreen)) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; @@ -5467,11 +5553,11 @@ static void clear_full_screen() /* Reinstate the window furniture. */ style = oldstyle = GetWindowLongPtr(hwnd, GWL_STYLE); style |= WS_CAPTION | WS_BORDER; - if (cfg.resize_action == RESIZE_DISABLED) + if (conf_get_int(conf, CONF_resize_action) == RESIZE_DISABLED) style &= ~WS_THICKFRAME; else style |= WS_THICKFRAME; - if (cfg.scrollbar) + if (conf_get_int(conf, CONF_scrollbar)) style |= WS_VSCROLL; else style &= ~WS_VSCROLL; diff --git a/windows/wingss.c b/windows/wingss.c index a161ad6e..237b3890 100644 --- a/windows/wingss.c +++ b/windows/wingss.c @@ -65,11 +65,12 @@ const char *gsslogmsg = NULL; static void ssh_sspi_bind_fns(struct ssh_gss_library *lib); -struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) +struct ssh_gss_liblist *ssh_gss_setup(Conf *conf) { HMODULE module; HKEY regkey; struct ssh_gss_liblist *list = snew(struct ssh_gss_liblist); + char *path; list->libraries = snewn(3, struct ssh_gss_library); list->nlibraries = 0; @@ -148,8 +149,9 @@ struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) * Custom GSSAPI DLL. */ module = NULL; - if (cfg->ssh_gss_custom.path[0]) { - module = LoadLibrary(cfg->ssh_gss_custom.path); + path = conf_get_filename(conf, CONF_ssh_gss_custom)->path; + if (*path) { + module = LoadLibrary(path); } if (module) { struct ssh_gss_library *lib = @@ -157,7 +159,7 @@ struct ssh_gss_liblist *ssh_gss_setup(const Config *cfg) lib->id = 2; lib->gsslogmsg = dupprintf("Using GSSAPI from user-specified" - " library '%s'", cfg->ssh_gss_custom.path); + " library '%s'", path); lib->handle = (void *)module; #define BIND_GSS_FN(name) \ diff --git a/windows/winplink.c b/windows/winplink.c index 7eb3aec1..3fe03af3 100644 --- a/windows/winplink.c +++ b/windows/winplink.c @@ -83,7 +83,7 @@ WSAEVENT netevent; static Backend *back; static void *backhandle; -static Config cfg; +static Conf *conf; int term_ldisc(Terminal *term, int mode) { @@ -298,10 +298,11 @@ int main(int argc, char **argv) /* * Process the command line. */ - do_defaults(NULL, &cfg); + conf = conf_new(); + do_defaults(NULL, conf); loaded_session = FALSE; - default_protocol = cfg.protocol; - default_port = cfg.port; + default_protocol = conf_get_int(conf, CONF_protocol); + default_port = conf_get_int(conf, CONF_port); errors = 0; { /* @@ -311,8 +312,10 @@ int main(int argc, char **argv) if (p) { const Backend *b = backend_from_name(p); if (b) { - default_protocol = cfg.protocol = b->protocol; - default_port = cfg.port = b->default_port; + default_protocol = b->protocol; + default_port = b->default_port; + conf_set_int(conf, CONF_protocol, default_protocol); + conf_set_int(conf, CONF_port, default_port); } } } @@ -320,7 +323,7 @@ int main(int argc, char **argv) char *p = *++argv; if (*p == '-') { int ret = cmdline_process_param(p, (argc > 1 ? argv[1] : NULL), - 1, &cfg); + 1, conf); if (ret == -2) { fprintf(stderr, "plink: option \"%s\" requires an argument\n", p); @@ -332,7 +335,7 @@ int main(int argc, char **argv) } else if (!strcmp(p, "-batch")) { console_batch_mode = 1; } else if (!strcmp(p, "-s")) { - /* Save status to write to cfg later. */ + /* Save status to write to conf later. */ use_subsystem = 1; } else if (!strcmp(p, "-V")) { version(); @@ -344,7 +347,7 @@ int main(int argc, char **argv) errors = 1; } } else if (*p) { - if (!cfg_launchable(&cfg) || !(got_host || loaded_session)) { + if (!conf_launchable(conf) || !(got_host || loaded_session)) { char *q = p; /* * If the hostname starts with "telnet:", set the @@ -357,7 +360,7 @@ int main(int argc, char **argv) q += 7; if (q[0] == '/' && q[1] == '/') q += 2; - cfg.protocol = PROT_TELNET; + conf_set_int(conf, CONF_protocol, PROT_TELNET); p = q; while (*p && *p != ':' && *p != '/') p++; @@ -365,11 +368,10 @@ int main(int argc, char **argv) if (*p) *p++ = '\0'; if (c == ':') - cfg.port = atoi(p); + conf_set_int(conf, CONF_port, atoi(p)); else - cfg.port = -1; - strncpy(cfg.host, q, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; + conf_set_int(conf, CONF_port, -1); + conf_set_str(conf, CONF_host, q); got_host = TRUE; } else { char *r, *user, *host; @@ -384,7 +386,9 @@ int main(int argc, char **argv) *r = '\0'; b = backend_from_name(p); if (b) { - default_protocol = cfg.protocol = b->protocol; + default_protocol = b->protocol; + conf_set_int(conf, CONF_protocol, + default_protocol); portnumber = b->default_port; } p = r + 1; @@ -411,26 +415,24 @@ int main(int argc, char **argv) * same name as the hostname. */ { - Config cfg2; - do_defaults(host, &cfg2); - if (loaded_session || !cfg_launchable(&cfg2)) { + Conf *conf2 = conf_new(); + do_defaults(host, conf2); + if (loaded_session || !conf_launchable(conf2)) { /* No settings for this host; use defaults */ /* (or session was already loaded with -load) */ - strncpy(cfg.host, host, sizeof(cfg.host) - 1); - cfg.host[sizeof(cfg.host) - 1] = '\0'; - cfg.port = default_port; + conf_set_str(conf, CONF_host, host); + conf_set_int(conf, CONF_port, default_port); got_host = TRUE; } else { - cfg = cfg2; + conf_copy_into(conf, conf2); loaded_session = TRUE; } + conf_free(conf2); } if (user) { /* Patch in specified username. */ - strncpy(cfg.username, user, - sizeof(cfg.username) - 1); - cfg.username[sizeof(cfg.username) - 1] = '\0'; + conf_set_str(conf, CONF_username, user); } } @@ -457,9 +459,9 @@ int main(int argc, char **argv) } if (cmdlen) command[--cmdlen]='\0'; /* change trailing blank to NUL */ - cfg.remote_cmd_ptr = command; - cfg.remote_cmd_ptr2 = NULL; - cfg.nopty = TRUE; /* command => no terminal */ + conf_set_str(conf, CONF_remote_cmd, command); + conf_set_str(conf, CONF_remote_cmd2, ""); + conf_set_int(conf, CONF_nopty, TRUE); /* command => no tty */ break; /* done with cmdline */ } @@ -469,70 +471,78 @@ int main(int argc, char **argv) if (errors) return 1; - if (!cfg_launchable(&cfg) || !(got_host || loaded_session)) { + if (!conf_launchable(conf) || !(got_host || loaded_session)) { usage(); } /* - * Trim leading whitespace off the hostname if it's there. + * Muck about with the hostname in various ways. */ { - int space = strspn(cfg.host, " \t"); - memmove(cfg.host, cfg.host+space, 1+strlen(cfg.host)-space); - } + char *hostbuf = dupstr(conf_get_str(conf, CONF_host)); + char *host = hostbuf; + char *p, *q; - /* See if host is of the form user@host */ - if (cfg_launchable(&cfg)) { - char *atsign = strrchr(cfg.host, '@'); - /* Make sure we're not overflowing the user field */ - if (atsign) { - if (atsign - cfg.host < sizeof cfg.username) { - strncpy(cfg.username, cfg.host, atsign - cfg.host); - cfg.username[atsign - cfg.host] = '\0'; + /* + * Trim leading whitespace. + */ + host += strspn(host, " \t"); + + /* + * See if host is of the form user@host, and separate out + * the username if so. + */ + if (host[0] != '\0') { + char *atsign = strrchr(host, '@'); + if (atsign) { + *atsign = '\0'; + conf_set_str(conf, CONF_username, host); + host = atsign + 1; } - memmove(cfg.host, atsign + 1, 1 + strlen(atsign + 1)); } + + /* + * Trim off a colon suffix if it's there. + */ + host[strcspn(host, ":")] = '\0'; + + /* + * Remove any remaining whitespace. + */ + p = hostbuf; + q = host; + while (*q) { + if (*q != ' ' && *q != '\t') + *p++ = *q; + q++; + } + *p = '\0'; + + conf_set_str(conf, CONF_host, hostbuf); + sfree(hostbuf); } /* * Perform command-line overrides on session configuration. */ - cmdline_run_saved(&cfg); + cmdline_run_saved(conf); /* * Apply subsystem status. */ if (use_subsystem) - cfg.ssh_subsys = TRUE; + conf_set_int(conf, CONF_ssh_subsys, TRUE); - /* - * Trim a colon suffix off the hostname if it's there. - */ - cfg.host[strcspn(cfg.host, ":")] = '\0'; - - /* - * Remove any remaining whitespace from the hostname. - */ - { - int p1 = 0, p2 = 0; - while (cfg.host[p2] != '\0') { - if (cfg.host[p2] != ' ' && cfg.host[p2] != '\t') { - cfg.host[p1] = cfg.host[p2]; - p1++; - } - p2++; - } - cfg.host[p1] = '\0'; - } - - if (!cfg.remote_cmd_ptr && !*cfg.remote_cmd && !*cfg.ssh_nc_host) + if (!*conf_get_str(conf, CONF_remote_cmd) && + !*conf_get_str(conf, CONF_remote_cmd2) && + !*conf_get_str(conf, CONF_ssh_nc_host)) flags |= FLAG_INTERACTIVE; /* * Select protocol. This is farmed out into a table in a * separate file to enable an ssh-free variant. */ - back = backend_from_proto(cfg.protocol); + back = backend_from_proto(conf_get_int(conf, CONF_protocol)); if (back == NULL) { fprintf(stderr, "Internal fault: Unsupported protocol found\n"); @@ -543,7 +553,7 @@ int main(int argc, char **argv) * Select port. */ if (portnumber != -1) - cfg.port = portnumber; + conf_set_int(conf, CONF_port, portnumber); sk_init(); if (p_WSAEventSelect == NULL) { @@ -551,7 +561,7 @@ int main(int argc, char **argv) return 1; } - logctx = log_init(NULL, &cfg); + logctx = log_init(NULL, conf); console_provide_logctx(logctx); /* @@ -562,11 +572,14 @@ int main(int argc, char **argv) const char *error; char *realhost; /* nodelay is only useful if stdin is a character device (console) */ - int nodelay = cfg.tcp_nodelay && + int nodelay = conf_get_int(conf, CONF_tcp_nodelay) && (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); - error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, - &realhost, nodelay, cfg.tcp_keepalives); + error = back->init(NULL, &backhandle, conf, + conf_get_str(conf, CONF_host), + conf_get_int(conf, CONF_port), + &realhost, nodelay, + conf_get_int(conf, CONF_tcp_keepalives)); if (error) { fprintf(stderr, "Unable to open connection:\n%s", error); return 1; diff --git a/windows/winproxy.c b/windows/winproxy.c index 877dc5e1..b1d3f6e7 100644 --- a/windows/winproxy.c +++ b/windows/winproxy.c @@ -123,7 +123,7 @@ static const char *sk_localproxy_socket_error(Socket s) Socket platform_new_connection(SockAddr addr, char *hostname, int port, int privport, int oobinline, int nodelay, int keepalive, - Plug plug, const Config *cfg) + Plug plug, Conf *conf) { char *cmd; @@ -145,10 +145,10 @@ Socket platform_new_connection(SockAddr addr, char *hostname, STARTUPINFO si; PROCESS_INFORMATION pi; - if (cfg->proxy_type != PROXY_CMD) + if (conf_get_int(conf, CONF_proxy_type) != PROXY_CMD) return NULL; - cmd = format_telnet_command(addr, port, cfg); + cmd = format_telnet_command(addr, port, conf); { char *msg = dupprintf("Starting local proxy command: %s", cmd); diff --git a/windows/winser.c b/windows/winser.c index ab88406d..e0fc20e7 100644 --- a/windows/winser.c +++ b/windows/winser.c @@ -87,7 +87,7 @@ static void serial_sentdata(struct handle *h, int new_backlog) } } -static const char *serial_configure(Serial serial, HANDLE serport, Config *cfg) +static const char *serial_configure(Serial serial, HANDLE serport, Conf *conf) { DCB dcb; COMMTIMEOUTS timeouts; @@ -121,17 +121,17 @@ static const char *serial_configure(Serial serial, HANDLE serport, Config *cfg) /* * Configurable parameters. */ - dcb.BaudRate = cfg->serspeed; - msg = dupprintf("Configuring baud rate %d", cfg->serspeed); + dcb.BaudRate = conf_get_int(conf, CONF_serspeed); + msg = dupprintf("Configuring baud rate %d", dcb.BaudRate); logevent(serial->frontend, msg); sfree(msg); - dcb.ByteSize = cfg->serdatabits; - msg = dupprintf("Configuring %d data bits", cfg->serdatabits); + dcb.ByteSize = conf_get_int(conf, CONF_serdatabits); + msg = dupprintf("Configuring %d data bits", dcb.ByteSize); logevent(serial->frontend, msg); sfree(msg); - switch (cfg->serstopbits) { + switch (conf_get_int(conf, CONF_serstopbits)) { case 2: dcb.StopBits = ONESTOPBIT; str = "1"; break; case 3: dcb.StopBits = ONE5STOPBITS; str = "1.5"; break; case 4: dcb.StopBits = TWOSTOPBITS; str = "2"; break; @@ -141,7 +141,7 @@ static const char *serial_configure(Serial serial, HANDLE serport, Config *cfg) logevent(serial->frontend, msg); sfree(msg); - switch (cfg->serparity) { + switch (conf_get_int(conf, CONF_serparity)) { case SER_PAR_NONE: dcb.Parity = NOPARITY; str = "no"; break; case SER_PAR_ODD: dcb.Parity = ODDPARITY; str = "odd"; break; case SER_PAR_EVEN: dcb.Parity = EVENPARITY; str = "even"; break; @@ -152,7 +152,7 @@ static const char *serial_configure(Serial serial, HANDLE serport, Config *cfg) logevent(serial->frontend, msg); sfree(msg); - switch (cfg->serflow) { + switch (conf_get_int(conf, CONF_serflow)) { case SER_FLOW_NONE: str = "no"; break; @@ -199,13 +199,13 @@ static const char *serial_configure(Serial serial, HANDLE serport, Config *cfg) * freed by the caller. */ static const char *serial_init(void *frontend_handle, void **backend_handle, - Config *cfg, - char *host, int port, char **realhost, int nodelay, - int keepalive) + Conf *conf, char *host, int port, + char **realhost, int nodelay, int keepalive) { Serial serial; HANDLE serport; const char *err; + char *serline; serial = snew(struct serial_backend_data); serial->port = INVALID_HANDLE_VALUE; @@ -216,8 +216,9 @@ static const char *serial_init(void *frontend_handle, void **backend_handle, serial->frontend = frontend_handle; + serline = conf_get_str(conf, CONF_serline); { - char *msg = dupprintf("Opening serial device %s", cfg->serline); + char *msg = dupprintf("Opening serial device %s", serline); logevent(serial->frontend, msg); } @@ -246,9 +247,7 @@ static const char *serial_init(void *frontend_handle, void **backend_handle, * existing configurations using \\.\ continue working.) */ char *serfilename = - dupprintf("%s%s", - strchr(cfg->serline, '\\') ? "" : "\\\\.\\", - cfg->serline); + dupprintf("%s%s", strchr(serline, '\\') ? "" : "\\\\.\\", serline); serport = CreateFile(serfilename, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); sfree(serfilename); @@ -257,7 +256,7 @@ static const char *serial_init(void *frontend_handle, void **backend_handle, if (serport == INVALID_HANDLE_VALUE) return "Unable to open serial port"; - err = serial_configure(serial, serport, cfg); + err = serial_configure(serial, serport, conf); if (err) return err; @@ -269,7 +268,7 @@ static const char *serial_init(void *frontend_handle, void **backend_handle, HANDLE_FLAG_IGNOREEOF | HANDLE_FLAG_UNITBUFFER); - *realhost = dupstr(cfg->serline); + *realhost = dupstr(serline); /* * Specials are always available. @@ -288,12 +287,12 @@ static void serial_free(void *handle) sfree(serial); } -static void serial_reconfig(void *handle, Config *cfg) +static void serial_reconfig(void *handle, Conf *conf) { Serial serial = (Serial) handle; const char *err; - err = serial_configure(serial, serial->port, cfg); + err = serial_configure(serial, serial->port, conf); /* * FIXME: what should we do if err returns something? diff --git a/windows/winsftp.c b/windows/winsftp.c index c5555d53..de84997d 100644 --- a/windows/winsftp.c +++ b/windows/winsftp.c @@ -20,7 +20,7 @@ int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) return ret; } -void platform_get_x11_auth(struct X11Display *display, const Config *cfg) +void platform_get_x11_auth(struct X11Display *display, Conf *conf) { /* Do nothing, therefore no auth. */ } diff --git a/windows/winstore.c b/windows/winstore.c index aae5a4c6..12d6cdda 100644 --- a/windows/winstore.c +++ b/windows/winstore.c @@ -150,17 +150,26 @@ void *open_settings_r(const char *sessionname) return (void *) sesskey; } -char *read_setting_s(void *handle, const char *key, char *buffer, int buflen) +char *read_setting_s(void *handle, const char *key) { DWORD type, size; - size = buflen; + char *ret; - if (!handle || - RegQueryValueEx((HKEY) handle, key, 0, - &type, buffer, &size) != ERROR_SUCCESS || + if (!handle) + return NULL; + + /* Find out the type and size of the data. */ + if (RegQueryValueEx((HKEY) handle, key, 0, + &type, NULL, &size) != ERROR_SUCCESS || + type != REG_SZ) + return NULL; + + ret = snewn(size+1, char); + if (RegQueryValueEx((HKEY) handle, key, 0, + &type, ret, &size) != ERROR_SUCCESS || type != REG_SZ) return NULL; - else - return buffer; + + return ret; } int read_setting_i(void *handle, const char *key, int defvalue) @@ -181,17 +190,25 @@ int read_setting_fontspec(void *handle, const char *name, FontSpec *result) { char *settingname; FontSpec ret; + char *fontname; - if (!read_setting_s(handle, name, ret.name, sizeof(ret.name))) + fontname = read_setting_s(handle, name); + if (!fontname) return 0; + strncpy(ret.name, fontname, sizeof(ret.name)-1); + ret.name[sizeof(ret.name)-1] = '\0'; + sfree(fontname); + settingname = dupcat(name, "IsBold", NULL); ret.isbold = read_setting_i(handle, settingname, -1); sfree(settingname); if (ret.isbold == -1) return 0; + settingname = dupcat(name, "CharSet", NULL); ret.charset = read_setting_i(handle, settingname, -1); sfree(settingname); if (ret.charset == -1) return 0; + settingname = dupcat(name, "Height", NULL); ret.height = read_setting_i(handle, settingname, INT_MIN); sfree(settingname); @@ -218,7 +235,14 @@ void write_setting_fontspec(void *handle, const char *name, FontSpec font) int read_setting_filename(void *handle, const char *name, Filename *result) { - return !!read_setting_s(handle, name, result->path, sizeof(result->path)); + char *tmp = read_setting_s(handle, name); + if (tmp) { + strncpy(result->path, tmp, sizeof(result->path)-1); + result->path[sizeof(result->path)-1] = '\0'; + sfree(tmp); + return TRUE; + } else + return FALSE; } void write_setting_filename(void *handle, const char *name, Filename result) diff --git a/windows/winstuff.h b/windows/winstuff.h index feaf9e9d..2b70ddc1 100644 --- a/windows/winstuff.h +++ b/windows/winstuff.h @@ -115,7 +115,7 @@ struct FontSpec { #ifndef DONE_TYPEDEFS #define DONE_TYPEDEFS -typedef struct config_tag Config; +typedef struct conf_tag Conf; typedef struct backend_tag Backend; typedef struct terminal_tag Terminal; #endif @@ -473,7 +473,7 @@ void EnableSizeTip(int bEnable); * Exports from unicode.c. */ struct unicode_data; -void init_ucs(Config *, struct unicode_data *); +void init_ucs(Conf *, struct unicode_data *); /* * Exports from winhandl.c. diff --git a/windows/winucs.c b/windows/winucs.c index 757a2750..9abd83c7 100644 --- a/windows/winucs.c +++ b/windows/winucs.c @@ -436,24 +436,27 @@ static const struct cp_list_item cp_list[] = { static void link_font(WCHAR * line_tbl, WCHAR * font_tbl, WCHAR attr); -void init_ucs(Config *cfg, struct unicode_data *ucsdata) +void init_ucs(Conf *conf, struct unicode_data *ucsdata) { int i, j; int used_dtf = 0; char tbuf[256]; + int vtmode; for (i = 0; i < 256; i++) tbuf[i] = i; /* Decide on the Line and Font codepages */ - ucsdata->line_codepage = decode_codepage(cfg->line_codepage); + ucsdata->line_codepage = decode_codepage(conf_get_str(conf, + CONF_line_codepage)); if (ucsdata->font_codepage <= 0) { ucsdata->font_codepage=0; ucsdata->dbcs_screenfont=0; } - if (cfg->vtmode == VT_OEMONLY) { + vtmode = conf_get_int(conf, CONF_vtmode); + if (vtmode == VT_OEMONLY) { ucsdata->font_codepage = 437; ucsdata->dbcs_screenfont = 0; if (ucsdata->line_codepage <= 0) @@ -473,7 +476,7 @@ void init_ucs(Config *cfg, struct unicode_data *ucsdata) if (ucsdata->font_codepage == 437) ucsdata->unitab_font[0] = ucsdata->unitab_font[255] = 0xFFFF; } - if (cfg->vtmode == VT_XWINDOWS) + if (vtmode == VT_XWINDOWS) memcpy(ucsdata->unitab_font + 1, unitab_xterm_std, sizeof(unitab_xterm_std)); @@ -481,7 +484,7 @@ void init_ucs(Config *cfg, struct unicode_data *ucsdata) get_unitab(CP_OEMCP, ucsdata->unitab_oemcp, 1); /* Collect CP437 ucs table for SCO acs */ - if (cfg->vtmode == VT_OEMANSI || cfg->vtmode == VT_XWINDOWS) + if (vtmode == VT_OEMANSI || vtmode == VT_XWINDOWS) memcpy(ucsdata->unitab_scoacs, ucsdata->unitab_oemcp, sizeof(ucsdata->unitab_scoacs)); else @@ -490,7 +493,7 @@ void init_ucs(Config *cfg, struct unicode_data *ucsdata) /* Collect line set ucs table */ if (ucsdata->line_codepage == ucsdata->font_codepage && (ucsdata->dbcs_screenfont || - cfg->vtmode == VT_POORMAN || ucsdata->font_codepage==0)) { + vtmode == VT_POORMAN || ucsdata->font_codepage==0)) { /* For DBCS and POOR fonts force direct to font */ used_dtf = 1; @@ -560,14 +563,14 @@ void init_ucs(Config *cfg, struct unicode_data *ucsdata) ucsdata->unitab_ctrl[i] = 0xFF; /* Generate line->screen direct conversion links. */ - if (cfg->vtmode == VT_OEMANSI || cfg->vtmode == VT_XWINDOWS) + if (vtmode == VT_OEMANSI || vtmode == VT_XWINDOWS) link_font(ucsdata->unitab_scoacs, ucsdata->unitab_oemcp, CSET_OEMCP); link_font(ucsdata->unitab_line, ucsdata->unitab_font, CSET_ACP); link_font(ucsdata->unitab_scoacs, ucsdata->unitab_font, CSET_ACP); link_font(ucsdata->unitab_xterm, ucsdata->unitab_font, CSET_ACP); - if (cfg->vtmode == VT_OEMANSI || cfg->vtmode == VT_XWINDOWS) { + if (vtmode == VT_OEMANSI || vtmode == VT_XWINDOWS) { link_font(ucsdata->unitab_line, ucsdata->unitab_oemcp, CSET_OEMCP); link_font(ucsdata->unitab_xterm, ucsdata->unitab_oemcp, CSET_OEMCP); } @@ -581,7 +584,7 @@ void init_ucs(Config *cfg, struct unicode_data *ucsdata) } /* Last chance, if !unicode then try poorman links. */ - if (cfg->vtmode != VT_UNICODE) { + if (vtmode != VT_UNICODE) { static const char poorman_scoacs[] = "CueaaaaceeeiiiAAE**ooouuyOUc$YPsaiounNao?++**!<>###||||++||++++++--|-+||++--|-+----++++++++##||#aBTPEsyt******EN=+><++-=... n2* "; static const char poorman_latin1[] = diff --git a/windows/winx11.c b/windows/winx11.c index c1204ae1..b8c7fa7d 100644 --- a/windows/winx11.c +++ b/windows/winx11.c @@ -9,10 +9,11 @@ #include "putty.h" #include "ssh.h" -void platform_get_x11_auth(struct X11Display *disp, const Config *cfg) +void platform_get_x11_auth(struct X11Display *disp, Conf *conf) { - if (cfg->xauthfile.path[0]) - x11_get_auth_from_authfile(disp, cfg->xauthfile.path); + char *xauthpath = conf_get_filename(conf, CONF_xauthfile)->path; + if (xauthpath[0]) + x11_get_auth_from_authfile(disp, xauthpath); } const int platform_uses_x11_unix_by_default = FALSE; diff --git a/x11fwd.c b/x11fwd.c index d674120a..90824714 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -68,8 +68,7 @@ static const struct plug_function_table dummy_plug = { dummy_plug_sent, dummy_plug_accepting }; -struct X11Display *x11_setup_display(char *display, int authtype, - const Config *cfg) +struct X11Display *x11_setup_display(char *display, int authtype, Conf *conf) { struct X11Display *disp = snew(struct X11Display); char *localcopy; @@ -166,7 +165,7 @@ struct X11Display *x11_setup_display(char *display, int authtype, disp->port = 6000 + disp->displaynum; disp->addr = name_lookup(disp->hostname, disp->port, - &disp->realhost, cfg, ADDRTYPE_UNSPEC); + &disp->realhost, conf, ADDRTYPE_UNSPEC); if ((err = sk_addr_error(disp->addr)) != NULL) { sk_addr_free(disp->addr); @@ -249,7 +248,7 @@ struct X11Display *x11_setup_display(char *display, int authtype, disp->localauthproto = X11_NO_AUTH; disp->localauthdata = NULL; disp->localauthdatalen = 0; - platform_get_x11_auth(disp, cfg); + platform_get_x11_auth(disp, conf); return disp; } @@ -558,8 +557,7 @@ int x11_get_screen_number(char *display) * also, fills the SocketsStructure */ extern const char *x11_init(Socket *s, struct X11Display *disp, void *c, - const char *peeraddr, int peerport, - const Config *cfg) + const char *peeraddr, int peerport, Conf *conf) { static const struct plug_function_table fn_table = { x11_log, @@ -586,7 +584,7 @@ extern const char *x11_init(Socket *s, struct X11Display *disp, void *c, pr->s = *s = new_connection(sk_addr_dup(disp->addr), disp->realhost, disp->port, - 0, 1, 0, 0, (Plug) pr, cfg); + 0, 1, 0, 0, (Plug) pr, conf); if ((err = sk_socket_error(*s)) != NULL) { sfree(pr); return err;