2 * settings.c: read and write saved sessions. (platform-independent)
\r
11 /* The cipher order given here is the default order. */
\r
12 static const struct keyvalwhere ciphernames[] = {
\r
13 { "aes", CIPHER_AES, -1, -1 },
\r
14 { "blowfish", CIPHER_BLOWFISH, -1, -1 },
\r
15 { "3des", CIPHER_3DES, -1, -1 },
\r
16 { "WARN", CIPHER_WARN, -1, -1 },
\r
17 { "arcfour", CIPHER_ARCFOUR, -1, -1 },
\r
18 { "des", CIPHER_DES, -1, -1 }
\r
21 static const struct keyvalwhere kexnames[] = {
\r
22 { "dh-gex-sha1", KEX_DHGEX, -1, -1 },
\r
23 { "dh-group14-sha1", KEX_DHGROUP14, -1, -1 },
\r
24 { "dh-group1-sha1", KEX_DHGROUP1, -1, -1 },
\r
25 { "rsa", KEX_RSA, KEX_WARN, -1 },
\r
26 { "WARN", KEX_WARN, -1, -1 }
\r
30 * All the terminal modes that we know about for the "TerminalModes"
\r
31 * setting. (Also used by config.c for the drop-down list.)
\r
32 * This is currently precisely the same as the set in ssh.c, but could
\r
33 * in principle differ if other backends started to support tty modes
\r
34 * (e.g., the pty backend).
\r
36 const char *const ttymodes[] = {
\r
37 "INTR", "QUIT", "ERASE", "KILL", "EOF",
\r
38 "EOL", "EOL2", "START", "STOP", "SUSP",
\r
39 "DSUSP", "REPRINT", "WERASE", "LNEXT", "FLUSH",
\r
40 "SWTCH", "STATUS", "DISCARD", "IGNPAR", "PARMRK",
\r
41 "INPCK", "ISTRIP", "INLCR", "IGNCR", "ICRNL",
\r
42 "IUCLC", "IXON", "IXANY", "IXOFF", "IMAXBEL",
\r
43 "ISIG", "ICANON", "XCASE", "ECHO", "ECHOE",
\r
44 "ECHOK", "ECHONL", "NOFLSH", "TOSTOP", "IEXTEN",
\r
45 "ECHOCTL", "ECHOKE", "PENDIN", "OPOST", "OLCUC",
\r
46 "ONLCR", "OCRNL", "ONOCR", "ONLRET", "CS7",
\r
47 "CS8", "PARENB", "PARODD", NULL
\r
51 * Convenience functions to access the backends[] array
\r
52 * (which is only present in tools that manage settings).
\r
55 Backend *backend_from_name(const char *name)
\r
58 for (p = backends; *p != NULL; p++)
\r
59 if (!strcmp((*p)->name, name))
\r
64 Backend *backend_from_proto(int proto)
\r
67 for (p = backends; *p != NULL; p++)
\r
68 if ((*p)->protocol == proto)
\r
73 int get_remote_username(Config *cfg, char *user, size_t len)
\r
75 if (*cfg->username) {
\r
76 strncpy(user, cfg->username, len);
\r
79 if (cfg->username_from_env) {
\r
80 /* Use local username. */
\r
81 char *luser = get_username();
\r
83 strncpy(user, luser, len);
\r
93 return (*user != '\0');
\r
96 static void gpps(void *handle, const char *name, const char *def,
\r
99 if (!read_setting_s(handle, name, val, len)) {
\r
102 pdef = platform_default_s(name);
\r
104 strncpy(val, pdef, len);
\r
107 strncpy(val, def, len);
\r
110 val[len - 1] = '\0';
\r
115 * gppfont and gppfile cannot have local defaults, since the very
\r
116 * format of a Filename or Font is platform-dependent. So the
\r
117 * platform-dependent functions MUST return some sort of value.
\r
119 static void gppfont(void *handle, const char *name, FontSpec *result)
\r
121 if (!read_setting_fontspec(handle, name, result))
\r
122 *result = platform_default_fontspec(name);
\r
124 static void gppfile(void *handle, const char *name, Filename *result)
\r
126 if (!read_setting_filename(handle, name, result))
\r
127 *result = platform_default_filename(name);
\r
130 static void gppi(void *handle, char *name, int def, int *i)
\r
132 def = platform_default_i(name, def);
\r
133 *i = read_setting_i(handle, name, def);
\r
137 * Read a set of name-value pairs in the format we occasionally use:
\r
138 * NAME\tVALUE\0NAME\tVALUE\0\0 in memory
\r
139 * NAME=VALUE,NAME=VALUE, in storage
\r
140 * `def' is in the storage format.
\r
142 static void gppmap(void *handle, char *name, char *def, char *val, int len)
\r
144 char *buf = snewn(2*len, char), *p, *q;
\r
145 gpps(handle, name, def, buf, 2*len);
\r
149 while (*p && *p != ',') {
\r
166 * Write a set of name/value pairs in the above format.
\r
168 static void wmap(void *handle, char const *key, char const *value, int len)
\r
170 char *buf = snewn(2*len, char), *p;
\r
177 if (c == '=' || c == ',' || c == '\\')
\r
187 write_setting_s(handle, key, buf);
\r
191 static int key2val(const struct keyvalwhere *mapping,
\r
192 int nmaps, char *key)
\r
195 for (i = 0; i < nmaps; i++)
\r
196 if (!strcmp(mapping[i].s, key)) return mapping[i].v;
\r
200 static const char *val2key(const struct keyvalwhere *mapping,
\r
201 int nmaps, int val)
\r
204 for (i = 0; i < nmaps; i++)
\r
205 if (mapping[i].v == val) return mapping[i].s;
\r
210 * Helper function to parse a comma-separated list of strings into
\r
211 * a preference list array of values. Any missing values are added
\r
212 * to the end and duplicates are weeded.
\r
213 * XXX: assumes vals in 'mapping' are small +ve integers
\r
215 static void gprefs(void *sesskey, char *name, char *def,
\r
216 const struct keyvalwhere *mapping, int nvals,
\r
219 char commalist[256];
\r
221 int i, j, n, v, pos;
\r
222 unsigned long seen = 0; /* bitmap for weeding dups etc */
\r
225 * Fetch the string which we'll parse as a comma-separated list.
\r
227 gpps(sesskey, name, def, commalist, sizeof(commalist));
\r
230 * Go through that list and convert it into values.
\r
235 while (*p && *p == ',') p++;
\r
237 break; /* no more words */
\r
240 while (*p && *p != ',') p++;
\r
241 if (*p) *p++ = '\0';
\r
243 v = key2val(mapping, nvals, q);
\r
244 if (v != -1 && !(seen & (1 << v))) {
\r
251 * Now go through 'mapping' and add values that weren't mentioned
\r
252 * in the list we fetched. We may have to loop over it multiple
\r
253 * times so that we add values before other values whose default
\r
254 * positions depend on them.
\r
256 while (n < nvals) {
\r
257 for (i = 0; i < nvals; i++) {
\r
258 assert(mapping[i].v < 32);
\r
260 if (!(seen & (1 << mapping[i].v))) {
\r
262 * This element needs adding. But can we add it yet?
\r
264 if (mapping[i].vrel != -1 && !(seen & (1 << mapping[i].vrel)))
\r
265 continue; /* nope */
\r
268 * OK, we can work out where to add this element, so
\r
271 if (mapping[i].vrel == -1) {
\r
272 pos = (mapping[i].where < 0 ? n : 0);
\r
274 for (j = 0; j < n; j++)
\r
275 if (array[j] == mapping[i].vrel)
\r
277 assert(j < n); /* implied by (seen & (1<<vrel)) */
\r
278 pos = (mapping[i].where < 0 ? j : j+1);
\r
284 for (j = n-1; j >= pos; j--)
\r
285 array[j+1] = array[j];
\r
286 array[pos] = mapping[i].v;
\r
294 * Write out a preference list.
\r
296 static void wprefs(void *sesskey, char *name,
\r
297 const struct keyvalwhere *mapping, int nvals,
\r
303 for (maxlen = i = 0; i < nvals; i++) {
\r
304 const char *s = val2key(mapping, nvals, array[i]);
\r
306 maxlen += (maxlen > 0 ? 1 : 0) + strlen(s);
\r
310 buf = snewn(maxlen + 1, char);
\r
313 for (i = 0; i < nvals; i++) {
\r
314 const char *s = val2key(mapping, nvals, array[i]);
\r
316 p += sprintf(p, "%s%s", (p > buf ? "," : ""), s);
\r
320 assert(p - buf == maxlen);
\r
323 write_setting_s(sesskey, name, buf);
\r
328 char *save_settings(char *section, Config * cfg)
\r
333 sesskey = open_settings_w(section, &errmsg);
\r
336 save_open_settings(sesskey, cfg);
\r
337 close_settings_w(sesskey);
\r
341 void save_open_settings(void *sesskey, Config *cfg)
\r
346 write_setting_i(sesskey, "Present", 1);
\r
347 write_setting_s(sesskey, "HostName", cfg->host);
\r
348 write_setting_filename(sesskey, "LogFileName", cfg->logfilename);
\r
349 write_setting_i(sesskey, "LogType", cfg->logtype);
\r
350 write_setting_i(sesskey, "LogFileClash", cfg->logxfovr);
\r
351 write_setting_i(sesskey, "LogFlush", cfg->logflush);
\r
352 write_setting_i(sesskey, "SSHLogOmitPasswords", cfg->logomitpass);
\r
353 write_setting_i(sesskey, "SSHLogOmitData", cfg->logomitdata);
\r
356 const Backend *b = backend_from_proto(cfg->protocol);
\r
360 write_setting_s(sesskey, "Protocol", p);
\r
361 write_setting_i(sesskey, "PortNumber", cfg->port);
\r
362 /* The CloseOnExit numbers are arranged in a different order from
\r
363 * the standard FORCE_ON / FORCE_OFF / AUTO. */
\r
364 write_setting_i(sesskey, "CloseOnExit", (cfg->close_on_exit+2)%3);
\r
365 write_setting_i(sesskey, "WarnOnClose", !!cfg->warn_on_close);
\r
366 write_setting_i(sesskey, "PingInterval", cfg->ping_interval / 60); /* minutes */
\r
367 write_setting_i(sesskey, "PingIntervalSecs", cfg->ping_interval % 60); /* seconds */
\r
368 write_setting_i(sesskey, "TCPNoDelay", cfg->tcp_nodelay);
\r
369 write_setting_i(sesskey, "TCPKeepalives", cfg->tcp_keepalives);
\r
370 write_setting_s(sesskey, "TerminalType", cfg->termtype);
\r
371 write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed);
\r
372 wmap(sesskey, "TerminalModes", cfg->ttymodes, lenof(cfg->ttymodes));
\r
374 /* Address family selection */
\r
375 write_setting_i(sesskey, "AddressFamily", cfg->addressfamily);
\r
377 /* proxy settings */
\r
378 write_setting_s(sesskey, "ProxyExcludeList", cfg->proxy_exclude_list);
\r
379 write_setting_i(sesskey, "ProxyDNS", (cfg->proxy_dns+2)%3);
\r
380 write_setting_i(sesskey, "ProxyLocalhost", cfg->even_proxy_localhost);
\r
381 write_setting_i(sesskey, "ProxyMethod", cfg->proxy_type);
\r
382 write_setting_s(sesskey, "ProxyHost", cfg->proxy_host);
\r
383 write_setting_i(sesskey, "ProxyPort", cfg->proxy_port);
\r
384 write_setting_s(sesskey, "ProxyUsername", cfg->proxy_username);
\r
385 write_setting_s(sesskey, "ProxyPassword", cfg->proxy_password);
\r
386 write_setting_s(sesskey, "ProxyTelnetCommand", cfg->proxy_telnet_command);
\r
387 wmap(sesskey, "Environment", cfg->environmt, lenof(cfg->environmt));
\r
388 write_setting_s(sesskey, "UserName", cfg->username);
\r
389 write_setting_i(sesskey, "UserNameFromEnvironment", cfg->username_from_env);
\r
390 write_setting_s(sesskey, "LocalUserName", cfg->localusername);
\r
391 write_setting_i(sesskey, "NoPTY", cfg->nopty);
\r
392 write_setting_i(sesskey, "Compression", cfg->compression);
\r
393 write_setting_i(sesskey, "TryAgent", cfg->tryagent);
\r
394 write_setting_i(sesskey, "AgentFwd", cfg->agentfwd);
\r
395 write_setting_i(sesskey, "GssapiFwd", cfg->gssapifwd);
\r
396 write_setting_i(sesskey, "ChangeUsername", cfg->change_username);
\r
397 wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX,
\r
398 cfg->ssh_cipherlist);
\r
399 wprefs(sesskey, "KEX", kexnames, KEX_MAX, cfg->ssh_kexlist);
\r
400 write_setting_i(sesskey, "RekeyTime", cfg->ssh_rekey_time);
\r
401 write_setting_s(sesskey, "RekeyBytes", cfg->ssh_rekey_data);
\r
402 write_setting_i(sesskey, "SshNoAuth", cfg->ssh_no_userauth);
\r
403 write_setting_i(sesskey, "SshBanner", cfg->ssh_show_banner);
\r
404 write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
\r
405 write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
\r
406 write_setting_i(sesskey, "AuthGSSAPI", cfg->try_gssapi_auth);
\r
408 wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs,
\r
410 write_setting_filename(sesskey, "GSSCustom", cfg->ssh_gss_custom);
\r
412 write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell);
\r
413 write_setting_i(sesskey, "SshProt", cfg->sshprot);
\r
414 write_setting_s(sesskey, "LogHost", cfg->loghost);
\r
415 write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc);
\r
416 write_setting_filename(sesskey, "PublicKeyFile", cfg->keyfile);
\r
417 write_setting_s(sesskey, "RemoteCommand", cfg->remote_cmd);
\r
418 write_setting_i(sesskey, "RFCEnviron", cfg->rfc_environ);
\r
419 write_setting_i(sesskey, "PassiveTelnet", cfg->passive_telnet);
\r
420 write_setting_i(sesskey, "BackspaceIsDelete", cfg->bksp_is_delete);
\r
421 write_setting_i(sesskey, "RXVTHomeEnd", cfg->rxvt_homeend);
\r
422 write_setting_i(sesskey, "LinuxFunctionKeys", cfg->funky_type);
\r
423 write_setting_i(sesskey, "NoApplicationKeys", cfg->no_applic_k);
\r
424 write_setting_i(sesskey, "NoApplicationCursors", cfg->no_applic_c);
\r
425 write_setting_i(sesskey, "NoMouseReporting", cfg->no_mouse_rep);
\r
426 write_setting_i(sesskey, "NoRemoteResize", cfg->no_remote_resize);
\r
427 write_setting_i(sesskey, "NoAltScreen", cfg->no_alt_screen);
\r
428 write_setting_i(sesskey, "NoRemoteWinTitle", cfg->no_remote_wintitle);
\r
429 write_setting_i(sesskey, "RemoteQTitleAction", cfg->remote_qtitle_action);
\r
430 write_setting_i(sesskey, "NoDBackspace", cfg->no_dbackspace);
\r
431 write_setting_i(sesskey, "NoRemoteCharset", cfg->no_remote_charset);
\r
432 write_setting_i(sesskey, "ApplicationCursorKeys", cfg->app_cursor);
\r
433 write_setting_i(sesskey, "ApplicationKeypad", cfg->app_keypad);
\r
434 write_setting_i(sesskey, "NetHackKeypad", cfg->nethack_keypad);
\r
435 write_setting_i(sesskey, "AltF4", cfg->alt_f4);
\r
436 write_setting_i(sesskey, "AltSpace", cfg->alt_space);
\r
437 write_setting_i(sesskey, "AltOnly", cfg->alt_only);
\r
438 write_setting_i(sesskey, "ComposeKey", cfg->compose_key);
\r
439 write_setting_i(sesskey, "CtrlAltKeys", cfg->ctrlaltkeys);
\r
440 write_setting_i(sesskey, "TelnetKey", cfg->telnet_keyboard);
\r
441 write_setting_i(sesskey, "TelnetRet", cfg->telnet_newline);
\r
442 write_setting_i(sesskey, "LocalEcho", cfg->localecho);
\r
443 write_setting_i(sesskey, "LocalEdit", cfg->localedit);
\r
444 write_setting_s(sesskey, "Answerback", cfg->answerback);
\r
445 write_setting_i(sesskey, "AlwaysOnTop", cfg->alwaysontop);
\r
446 write_setting_i(sesskey, "FullScreenOnAltEnter", cfg->fullscreenonaltenter);
\r
447 write_setting_i(sesskey, "HideMousePtr", cfg->hide_mouseptr);
\r
448 write_setting_i(sesskey, "SunkenEdge", cfg->sunken_edge);
\r
449 write_setting_i(sesskey, "WindowBorder", cfg->window_border);
\r
450 write_setting_i(sesskey, "CurType", cfg->cursor_type);
\r
451 write_setting_i(sesskey, "BlinkCur", cfg->blink_cur);
\r
452 write_setting_i(sesskey, "Beep", cfg->beep);
\r
453 write_setting_i(sesskey, "BeepInd", cfg->beep_ind);
\r
454 write_setting_filename(sesskey, "BellWaveFile", cfg->bell_wavefile);
\r
455 write_setting_i(sesskey, "BellOverload", cfg->bellovl);
\r
456 write_setting_i(sesskey, "BellOverloadN", cfg->bellovl_n);
\r
457 write_setting_i(sesskey, "BellOverloadT", cfg->bellovl_t
\r
458 #ifdef PUTTY_UNIX_H
\r
462 write_setting_i(sesskey, "BellOverloadS", cfg->bellovl_s
\r
463 #ifdef PUTTY_UNIX_H
\r
467 write_setting_i(sesskey, "ScrollbackLines", cfg->savelines);
\r
468 write_setting_i(sesskey, "DECOriginMode", cfg->dec_om);
\r
469 write_setting_i(sesskey, "AutoWrapMode", cfg->wrap_mode);
\r
470 write_setting_i(sesskey, "LFImpliesCR", cfg->lfhascr);
\r
471 write_setting_i(sesskey, "CRImpliesLF", cfg->crhaslf);
\r
472 write_setting_i(sesskey, "DisableArabicShaping", cfg->arabicshaping);
\r
473 write_setting_i(sesskey, "DisableBidi", cfg->bidi);
\r
474 write_setting_i(sesskey, "WinNameAlways", cfg->win_name_always);
\r
475 write_setting_s(sesskey, "WinTitle", cfg->wintitle);
\r
476 write_setting_i(sesskey, "TermWidth", cfg->width);
\r
477 write_setting_i(sesskey, "TermHeight", cfg->height);
\r
478 write_setting_fontspec(sesskey, "Font", cfg->font);
\r
479 write_setting_i(sesskey, "FontQuality", cfg->font_quality);
\r
480 write_setting_i(sesskey, "FontVTMode", cfg->vtmode);
\r
481 write_setting_i(sesskey, "UseSystemColours", cfg->system_colour);
\r
482 write_setting_i(sesskey, "TryPalette", cfg->try_palette);
\r
483 write_setting_i(sesskey, "ANSIColour", cfg->ansi_colour);
\r
484 write_setting_i(sesskey, "Xterm256Colour", cfg->xterm_256_colour);
\r
485 write_setting_i(sesskey, "BoldAsColour", cfg->bold_colour);
\r
487 for (i = 0; i < 22; i++) {
\r
488 char buf[20], buf2[30];
\r
489 sprintf(buf, "Colour%d", i);
\r
490 sprintf(buf2, "%d,%d,%d", cfg->colours[i][0],
\r
491 cfg->colours[i][1], cfg->colours[i][2]);
\r
492 write_setting_s(sesskey, buf, buf2);
\r
494 write_setting_i(sesskey, "RawCNP", cfg->rawcnp);
\r
495 write_setting_i(sesskey, "PasteRTF", cfg->rtf_paste);
\r
496 write_setting_i(sesskey, "MouseIsXterm", cfg->mouse_is_xterm);
\r
497 write_setting_i(sesskey, "RectSelect", cfg->rect_select);
\r
498 write_setting_i(sesskey, "MouseOverride", cfg->mouse_override);
\r
499 for (i = 0; i < 256; i += 32) {
\r
500 char buf[20], buf2[256];
\r
502 sprintf(buf, "Wordness%d", i);
\r
504 for (j = i; j < i + 32; j++) {
\r
505 sprintf(buf2 + strlen(buf2), "%s%d",
\r
506 (*buf2 ? "," : ""), cfg->wordness[j]);
\r
508 write_setting_s(sesskey, buf, buf2);
\r
510 write_setting_s(sesskey, "LineCodePage", cfg->line_codepage);
\r
511 write_setting_i(sesskey, "CJKAmbigWide", cfg->cjk_ambig_wide);
\r
512 write_setting_i(sesskey, "UTF8Override", cfg->utf8_override);
\r
513 write_setting_s(sesskey, "Printer", cfg->printer);
\r
514 write_setting_i(sesskey, "CapsLockCyr", cfg->xlat_capslockcyr);
\r
515 write_setting_i(sesskey, "ScrollBar", cfg->scrollbar);
\r
516 write_setting_i(sesskey, "ScrollBarFullScreen", cfg->scrollbar_in_fullscreen);
\r
517 write_setting_i(sesskey, "ScrollOnKey", cfg->scroll_on_key);
\r
518 write_setting_i(sesskey, "ScrollOnDisp", cfg->scroll_on_disp);
\r
519 write_setting_i(sesskey, "EraseToScrollback", cfg->erase_to_scrollback);
\r
520 write_setting_i(sesskey, "LockSize", cfg->resize_action);
\r
521 write_setting_i(sesskey, "BCE", cfg->bce);
\r
522 write_setting_i(sesskey, "BlinkText", cfg->blinktext);
\r
523 write_setting_i(sesskey, "X11Forward", cfg->x11_forward);
\r
524 write_setting_s(sesskey, "X11Display", cfg->x11_display);
\r
525 write_setting_i(sesskey, "X11AuthType", cfg->x11_auth);
\r
526 write_setting_filename(sesskey, "X11AuthFile", cfg->xauthfile);
\r
527 write_setting_i(sesskey, "LocalPortAcceptAll", cfg->lport_acceptall);
\r
528 write_setting_i(sesskey, "RemotePortAcceptAll", cfg->rport_acceptall);
\r
529 wmap(sesskey, "PortForwardings", cfg->portfwd, lenof(cfg->portfwd));
\r
530 write_setting_i(sesskey, "BugIgnore1", 2-cfg->sshbug_ignore1);
\r
531 write_setting_i(sesskey, "BugPlainPW1", 2-cfg->sshbug_plainpw1);
\r
532 write_setting_i(sesskey, "BugRSA1", 2-cfg->sshbug_rsa1);
\r
533 write_setting_i(sesskey, "BugIgnore2", 2-cfg->sshbug_ignore2);
\r
534 write_setting_i(sesskey, "BugHMAC2", 2-cfg->sshbug_hmac2);
\r
535 write_setting_i(sesskey, "BugDeriveKey2", 2-cfg->sshbug_derivekey2);
\r
536 write_setting_i(sesskey, "BugRSAPad2", 2-cfg->sshbug_rsapad2);
\r
537 write_setting_i(sesskey, "BugPKSessID2", 2-cfg->sshbug_pksessid2);
\r
538 write_setting_i(sesskey, "BugRekey2", 2-cfg->sshbug_rekey2);
\r
539 write_setting_i(sesskey, "BugMaxPkt2", 2-cfg->sshbug_maxpkt2);
\r
540 write_setting_i(sesskey, "StampUtmp", cfg->stamp_utmp);
\r
541 write_setting_i(sesskey, "LoginShell", cfg->login_shell);
\r
542 write_setting_i(sesskey, "ScrollbarOnLeft", cfg->scrollbar_on_left);
\r
543 write_setting_fontspec(sesskey, "BoldFont", cfg->boldfont);
\r
544 write_setting_fontspec(sesskey, "WideFont", cfg->widefont);
\r
545 write_setting_fontspec(sesskey, "WideBoldFont", cfg->wideboldfont);
\r
546 write_setting_i(sesskey, "ShadowBold", cfg->shadowbold);
\r
547 write_setting_i(sesskey, "ShadowBoldOffset", cfg->shadowboldoffset);
\r
548 write_setting_s(sesskey, "SerialLine", cfg->serline);
\r
549 write_setting_i(sesskey, "SerialSpeed", cfg->serspeed);
\r
550 write_setting_i(sesskey, "SerialDataBits", cfg->serdatabits);
\r
551 write_setting_i(sesskey, "SerialStopHalfbits", cfg->serstopbits);
\r
552 write_setting_i(sesskey, "SerialParity", cfg->serparity);
\r
553 write_setting_i(sesskey, "SerialFlowControl", cfg->serflow);
\r
554 write_setting_s(sesskey, "WindowClass", cfg->winclass);
\r
557 void load_settings(char *section, Config * cfg)
\r
561 sesskey = open_settings_r(section);
\r
562 load_open_settings(sesskey, cfg);
\r
563 close_settings_r(sesskey);
\r
565 if (cfg_launchable(cfg))
\r
566 add_session_to_jumplist(section);
\r
569 void load_open_settings(void *sesskey, Config *cfg)
\r
574 cfg->ssh_subsys = 0; /* FIXME: load this properly */
\r
575 cfg->remote_cmd_ptr = NULL;
\r
576 cfg->remote_cmd_ptr2 = NULL;
\r
577 cfg->ssh_nc_host[0] = '\0';
\r
579 gpps(sesskey, "HostName", "", cfg->host, sizeof(cfg->host));
\r
580 gppfile(sesskey, "LogFileName", &cfg->logfilename);
\r
581 gppi(sesskey, "LogType", 0, &cfg->logtype);
\r
582 gppi(sesskey, "LogFileClash", LGXF_ASK, &cfg->logxfovr);
\r
583 gppi(sesskey, "LogFlush", 1, &cfg->logflush);
\r
584 gppi(sesskey, "SSHLogOmitPasswords", 1, &cfg->logomitpass);
\r
585 gppi(sesskey, "SSHLogOmitData", 0, &cfg->logomitdata);
\r
587 gpps(sesskey, "Protocol", "default", prot, 10);
\r
588 cfg->protocol = default_protocol;
\r
589 cfg->port = default_port;
\r
591 const Backend *b = backend_from_name(prot);
\r
593 cfg->protocol = b->protocol;
\r
594 gppi(sesskey, "PortNumber", default_port, &cfg->port);
\r
598 /* Address family selection */
\r
599 gppi(sesskey, "AddressFamily", ADDRTYPE_UNSPEC, &cfg->addressfamily);
\r
601 /* The CloseOnExit numbers are arranged in a different order from
\r
602 * the standard FORCE_ON / FORCE_OFF / AUTO. */
\r
603 gppi(sesskey, "CloseOnExit", 1, &i); cfg->close_on_exit = (i+1)%3;
\r
604 gppi(sesskey, "WarnOnClose", 1, &cfg->warn_on_close);
\r
606 /* This is two values for backward compatibility with 0.50/0.51 */
\r
607 int pingmin, pingsec;
\r
608 gppi(sesskey, "PingInterval", 0, &pingmin);
\r
609 gppi(sesskey, "PingIntervalSecs", 0, &pingsec);
\r
610 cfg->ping_interval = pingmin * 60 + pingsec;
\r
612 gppi(sesskey, "TCPNoDelay", 1, &cfg->tcp_nodelay);
\r
613 gppi(sesskey, "TCPKeepalives", 0, &cfg->tcp_keepalives);
\r
614 gpps(sesskey, "TerminalType", "xterm", cfg->termtype,
\r
615 sizeof(cfg->termtype));
\r
616 gpps(sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed,
\r
617 sizeof(cfg->termspeed));
\r
619 /* This hardcodes a big set of defaults in any new saved
\r
620 * sessions. Let's hope we don't change our mind. */
\r
622 char *def = dupstr("");
\r
623 /* Default: all set to "auto" */
\r
624 for (i = 0; ttymodes[i]; i++) {
\r
625 char *def2 = dupprintf("%s%s=A,", def, ttymodes[i]);
\r
629 gppmap(sesskey, "TerminalModes", def,
\r
630 cfg->ttymodes, lenof(cfg->ttymodes));
\r
634 /* proxy settings */
\r
635 gpps(sesskey, "ProxyExcludeList", "", cfg->proxy_exclude_list,
\r
636 sizeof(cfg->proxy_exclude_list));
\r
637 gppi(sesskey, "ProxyDNS", 1, &i); cfg->proxy_dns = (i+1)%3;
\r
638 gppi(sesskey, "ProxyLocalhost", 0, &cfg->even_proxy_localhost);
\r
639 gppi(sesskey, "ProxyMethod", -1, &cfg->proxy_type);
\r
640 if (cfg->proxy_type == -1) {
\r
642 gppi(sesskey, "ProxyType", 0, &i);
\r
644 cfg->proxy_type = PROXY_NONE;
\r
646 cfg->proxy_type = PROXY_HTTP;
\r
648 cfg->proxy_type = PROXY_TELNET;
\r
650 cfg->proxy_type = PROXY_CMD;
\r
652 gppi(sesskey, "ProxySOCKSVersion", 5, &i);
\r
654 cfg->proxy_type = PROXY_SOCKS5;
\r
656 cfg->proxy_type = PROXY_SOCKS4;
\r
659 gpps(sesskey, "ProxyHost", "proxy", cfg->proxy_host,
\r
660 sizeof(cfg->proxy_host));
\r
661 gppi(sesskey, "ProxyPort", 80, &cfg->proxy_port);
\r
662 gpps(sesskey, "ProxyUsername", "", cfg->proxy_username,
\r
663 sizeof(cfg->proxy_username));
\r
664 gpps(sesskey, "ProxyPassword", "", cfg->proxy_password,
\r
665 sizeof(cfg->proxy_password));
\r
666 gpps(sesskey, "ProxyTelnetCommand", "connect %host %port\\n",
\r
667 cfg->proxy_telnet_command, sizeof(cfg->proxy_telnet_command));
\r
668 gppmap(sesskey, "Environment", "", cfg->environmt, lenof(cfg->environmt));
\r
669 gpps(sesskey, "UserName", "", cfg->username, sizeof(cfg->username));
\r
670 gppi(sesskey, "UserNameFromEnvironment", 0, &cfg->username_from_env);
\r
671 gpps(sesskey, "LocalUserName", "", cfg->localusername,
\r
672 sizeof(cfg->localusername));
\r
673 gppi(sesskey, "NoPTY", 0, &cfg->nopty);
\r
674 gppi(sesskey, "Compression", 0, &cfg->compression);
\r
675 gppi(sesskey, "TryAgent", 1, &cfg->tryagent);
\r
676 gppi(sesskey, "AgentFwd", 0, &cfg->agentfwd);
\r
677 gppi(sesskey, "ChangeUsername", 0, &cfg->change_username);
\r
678 gppi(sesskey, "GssapiFwd", 0, &cfg->gssapifwd);
\r
679 gprefs(sesskey, "Cipher", "\0",
\r
680 ciphernames, CIPHER_MAX, cfg->ssh_cipherlist);
\r
682 /* Backward-compatibility: we used to have an option to
\r
683 * disable gex under the "bugs" panel after one report of
\r
684 * a server which offered it then choked, but we never got
\r
685 * a server version string or any other reports. */
\r
686 char *default_kexes;
\r
687 gppi(sesskey, "BugDHGEx2", 0, &i); i = 2-i;
\r
689 default_kexes = "dh-group14-sha1,dh-group1-sha1,rsa,WARN,dh-gex-sha1";
\r
691 default_kexes = "dh-gex-sha1,dh-group14-sha1,dh-group1-sha1,rsa,WARN";
\r
692 gprefs(sesskey, "KEX", default_kexes,
\r
693 kexnames, KEX_MAX, cfg->ssh_kexlist);
\r
695 gppi(sesskey, "RekeyTime", 60, &cfg->ssh_rekey_time);
\r
696 gpps(sesskey, "RekeyBytes", "1G", cfg->ssh_rekey_data,
\r
697 sizeof(cfg->ssh_rekey_data));
\r
698 gppi(sesskey, "SshProt", 2, &cfg->sshprot);
\r
699 gpps(sesskey, "LogHost", "", cfg->loghost, sizeof(cfg->loghost));
\r
700 gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
\r
701 gppi(sesskey, "SshNoAuth", 0, &cfg->ssh_no_userauth);
\r
702 gppi(sesskey, "SshBanner", 1, &cfg->ssh_show_banner);
\r
703 gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
\r
704 gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth);
\r
705 gppi(sesskey, "AuthGSSAPI", 1, &cfg->try_gssapi_auth);
\r
707 gprefs(sesskey, "GSSLibs", "\0",
\r
708 gsslibkeywords, ngsslibs, cfg->ssh_gsslist);
\r
709 gppfile(sesskey, "GSSCustom", &cfg->ssh_gss_custom);
\r
711 gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell);
\r
712 gppfile(sesskey, "PublicKeyFile", &cfg->keyfile);
\r
713 gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd,
\r
714 sizeof(cfg->remote_cmd));
\r
715 gppi(sesskey, "RFCEnviron", 0, &cfg->rfc_environ);
\r
716 gppi(sesskey, "PassiveTelnet", 0, &cfg->passive_telnet);
\r
717 gppi(sesskey, "BackspaceIsDelete", 1, &cfg->bksp_is_delete);
\r
718 gppi(sesskey, "RXVTHomeEnd", 0, &cfg->rxvt_homeend);
\r
719 gppi(sesskey, "LinuxFunctionKeys", 0, &cfg->funky_type);
\r
720 gppi(sesskey, "NoApplicationKeys", 0, &cfg->no_applic_k);
\r
721 gppi(sesskey, "NoApplicationCursors", 0, &cfg->no_applic_c);
\r
722 gppi(sesskey, "NoMouseReporting", 0, &cfg->no_mouse_rep);
\r
723 gppi(sesskey, "NoRemoteResize", 0, &cfg->no_remote_resize);
\r
724 gppi(sesskey, "NoAltScreen", 0, &cfg->no_alt_screen);
\r
725 gppi(sesskey, "NoRemoteWinTitle", 0, &cfg->no_remote_wintitle);
\r
727 /* Backward compatibility */
\r
728 int no_remote_qtitle;
\r
729 gppi(sesskey, "NoRemoteQTitle", 1, &no_remote_qtitle);
\r
730 /* We deliberately interpret the old setting of "no response" as
\r
731 * "empty string". This changes the behaviour, but hopefully for
\r
732 * the better; the user can always recover the old behaviour. */
\r
733 gppi(sesskey, "RemoteQTitleAction",
\r
734 no_remote_qtitle ? TITLE_EMPTY : TITLE_REAL,
\r
735 &cfg->remote_qtitle_action);
\r
737 gppi(sesskey, "NoDBackspace", 0, &cfg->no_dbackspace);
\r
738 gppi(sesskey, "NoRemoteCharset", 0, &cfg->no_remote_charset);
\r
739 gppi(sesskey, "ApplicationCursorKeys", 0, &cfg->app_cursor);
\r
740 gppi(sesskey, "ApplicationKeypad", 0, &cfg->app_keypad);
\r
741 gppi(sesskey, "NetHackKeypad", 0, &cfg->nethack_keypad);
\r
742 gppi(sesskey, "AltF4", 1, &cfg->alt_f4);
\r
743 gppi(sesskey, "AltSpace", 0, &cfg->alt_space);
\r
744 gppi(sesskey, "AltOnly", 0, &cfg->alt_only);
\r
745 gppi(sesskey, "ComposeKey", 0, &cfg->compose_key);
\r
746 gppi(sesskey, "CtrlAltKeys", 1, &cfg->ctrlaltkeys);
\r
747 gppi(sesskey, "TelnetKey", 0, &cfg->telnet_keyboard);
\r
748 gppi(sesskey, "TelnetRet", 1, &cfg->telnet_newline);
\r
749 gppi(sesskey, "LocalEcho", AUTO, &cfg->localecho);
\r
750 gppi(sesskey, "LocalEdit", AUTO, &cfg->localedit);
\r
751 gpps(sesskey, "Answerback", "PuTTY", cfg->answerback,
\r
752 sizeof(cfg->answerback));
\r
753 gppi(sesskey, "AlwaysOnTop", 0, &cfg->alwaysontop);
\r
754 gppi(sesskey, "FullScreenOnAltEnter", 0, &cfg->fullscreenonaltenter);
\r
755 gppi(sesskey, "HideMousePtr", 0, &cfg->hide_mouseptr);
\r
756 gppi(sesskey, "SunkenEdge", 0, &cfg->sunken_edge);
\r
757 gppi(sesskey, "WindowBorder", 1, &cfg->window_border);
\r
758 gppi(sesskey, "CurType", 0, &cfg->cursor_type);
\r
759 gppi(sesskey, "BlinkCur", 0, &cfg->blink_cur);
\r
760 /* pedantic compiler tells me I can't use &cfg->beep as an int * :-) */
\r
761 gppi(sesskey, "Beep", 1, &cfg->beep);
\r
762 gppi(sesskey, "BeepInd", 0, &cfg->beep_ind);
\r
763 gppfile(sesskey, "BellWaveFile", &cfg->bell_wavefile);
\r
764 gppi(sesskey, "BellOverload", 1, &cfg->bellovl);
\r
765 gppi(sesskey, "BellOverloadN", 5, &cfg->bellovl_n);
\r
766 gppi(sesskey, "BellOverloadT", 2*TICKSPERSEC
\r
767 #ifdef PUTTY_UNIX_H
\r
772 #ifdef PUTTY_UNIX_H
\r
776 gppi(sesskey, "BellOverloadS", 5*TICKSPERSEC
\r
777 #ifdef PUTTY_UNIX_H
\r
782 #ifdef PUTTY_UNIX_H
\r
786 gppi(sesskey, "ScrollbackLines", 200, &cfg->savelines);
\r
787 gppi(sesskey, "DECOriginMode", 0, &cfg->dec_om);
\r
788 gppi(sesskey, "AutoWrapMode", 1, &cfg->wrap_mode);
\r
789 gppi(sesskey, "LFImpliesCR", 0, &cfg->lfhascr);
\r
790 gppi(sesskey, "CRImpliesLF", 0, &cfg->crhaslf);
\r
791 gppi(sesskey, "DisableArabicShaping", 0, &cfg->arabicshaping);
\r
792 gppi(sesskey, "DisableBidi", 0, &cfg->bidi);
\r
793 gppi(sesskey, "WinNameAlways", 1, &cfg->win_name_always);
\r
794 gpps(sesskey, "WinTitle", "", cfg->wintitle, sizeof(cfg->wintitle));
\r
795 gppi(sesskey, "TermWidth", 80, &cfg->width);
\r
796 gppi(sesskey, "TermHeight", 24, &cfg->height);
\r
797 gppfont(sesskey, "Font", &cfg->font);
\r
798 gppi(sesskey, "FontQuality", FQ_DEFAULT, &cfg->font_quality);
\r
799 gppi(sesskey, "FontVTMode", VT_UNICODE, (int *) &cfg->vtmode);
\r
800 gppi(sesskey, "UseSystemColours", 0, &cfg->system_colour);
\r
801 gppi(sesskey, "TryPalette", 0, &cfg->try_palette);
\r
802 gppi(sesskey, "ANSIColour", 1, &cfg->ansi_colour);
\r
803 gppi(sesskey, "Xterm256Colour", 1, &cfg->xterm_256_colour);
\r
804 gppi(sesskey, "BoldAsColour", 1, &cfg->bold_colour);
\r
806 for (i = 0; i < 22; i++) {
\r
807 static const char *const defaults[] = {
\r
808 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
\r
809 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
\r
810 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
\r
811 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
\r
812 "85,255,255", "187,187,187", "255,255,255"
\r
814 char buf[20], buf2[30];
\r
816 sprintf(buf, "Colour%d", i);
\r
817 gpps(sesskey, buf, defaults[i], buf2, sizeof(buf2));
\r
818 if (sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) {
\r
819 cfg->colours[i][0] = c0;
\r
820 cfg->colours[i][1] = c1;
\r
821 cfg->colours[i][2] = c2;
\r
824 gppi(sesskey, "RawCNP", 0, &cfg->rawcnp);
\r
825 gppi(sesskey, "PasteRTF", 0, &cfg->rtf_paste);
\r
826 gppi(sesskey, "MouseIsXterm", 0, &cfg->mouse_is_xterm);
\r
827 gppi(sesskey, "RectSelect", 0, &cfg->rect_select);
\r
828 gppi(sesskey, "MouseOverride", 1, &cfg->mouse_override);
\r
829 for (i = 0; i < 256; i += 32) {
\r
830 static const char *const defaults[] = {
\r
831 "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",
\r
832 "0,1,2,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1",
\r
833 "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,1,1,1,1,2",
\r
834 "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,1,1,1,1,1",
\r
835 "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
\r
836 "1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1",
\r
837 "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",
\r
838 "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"
\r
840 char buf[20], buf2[256], *p;
\r
842 sprintf(buf, "Wordness%d", i);
\r
843 gpps(sesskey, buf, defaults[i / 32], buf2, sizeof(buf2));
\r
845 for (j = i; j < i + 32; j++) {
\r
847 while (*p && *p != ',')
\r
851 cfg->wordness[j] = atoi(q);
\r
855 * The empty default for LineCodePage will be converted later
\r
856 * into a plausible default for the locale.
\r
858 gpps(sesskey, "LineCodePage", "", cfg->line_codepage,
\r
859 sizeof(cfg->line_codepage));
\r
860 gppi(sesskey, "CJKAmbigWide", 0, &cfg->cjk_ambig_wide);
\r
861 gppi(sesskey, "UTF8Override", 1, &cfg->utf8_override);
\r
862 gpps(sesskey, "Printer", "", cfg->printer, sizeof(cfg->printer));
\r
863 gppi (sesskey, "CapsLockCyr", 0, &cfg->xlat_capslockcyr);
\r
864 gppi(sesskey, "ScrollBar", 1, &cfg->scrollbar);
\r
865 gppi(sesskey, "ScrollBarFullScreen", 0, &cfg->scrollbar_in_fullscreen);
\r
866 gppi(sesskey, "ScrollOnKey", 0, &cfg->scroll_on_key);
\r
867 gppi(sesskey, "ScrollOnDisp", 1, &cfg->scroll_on_disp);
\r
868 gppi(sesskey, "EraseToScrollback", 1, &cfg->erase_to_scrollback);
\r
869 gppi(sesskey, "LockSize", 0, &cfg->resize_action);
\r
870 gppi(sesskey, "BCE", 1, &cfg->bce);
\r
871 gppi(sesskey, "BlinkText", 0, &cfg->blinktext);
\r
872 gppi(sesskey, "X11Forward", 0, &cfg->x11_forward);
\r
873 gpps(sesskey, "X11Display", "", cfg->x11_display,
\r
874 sizeof(cfg->x11_display));
\r
875 gppi(sesskey, "X11AuthType", X11_MIT, &cfg->x11_auth);
\r
876 gppfile(sesskey, "X11AuthFile", &cfg->xauthfile);
\r
878 gppi(sesskey, "LocalPortAcceptAll", 0, &cfg->lport_acceptall);
\r
879 gppi(sesskey, "RemotePortAcceptAll", 0, &cfg->rport_acceptall);
\r
880 gppmap(sesskey, "PortForwardings", "", cfg->portfwd, lenof(cfg->portfwd));
\r
881 gppi(sesskey, "BugIgnore1", 0, &i); cfg->sshbug_ignore1 = 2-i;
\r
882 gppi(sesskey, "BugPlainPW1", 0, &i); cfg->sshbug_plainpw1 = 2-i;
\r
883 gppi(sesskey, "BugRSA1", 0, &i); cfg->sshbug_rsa1 = 2-i;
\r
884 gppi(sesskey, "BugIgnore2", 0, &i); cfg->sshbug_ignore2 = 2-i;
\r
887 gppi(sesskey, "BugHMAC2", 0, &i); cfg->sshbug_hmac2 = 2-i;
\r
888 if (cfg->sshbug_hmac2 == AUTO) {
\r
889 gppi(sesskey, "BuggyMAC", 0, &i);
\r
891 cfg->sshbug_hmac2 = FORCE_ON;
\r
894 gppi(sesskey, "BugDeriveKey2", 0, &i); cfg->sshbug_derivekey2 = 2-i;
\r
895 gppi(sesskey, "BugRSAPad2", 0, &i); cfg->sshbug_rsapad2 = 2-i;
\r
896 gppi(sesskey, "BugPKSessID2", 0, &i); cfg->sshbug_pksessid2 = 2-i;
\r
897 gppi(sesskey, "BugRekey2", 0, &i); cfg->sshbug_rekey2 = 2-i;
\r
898 gppi(sesskey, "BugMaxPkt2", 0, &i); cfg->sshbug_maxpkt2 = 2-i;
\r
899 cfg->ssh_simple = FALSE;
\r
900 gppi(sesskey, "StampUtmp", 1, &cfg->stamp_utmp);
\r
901 gppi(sesskey, "LoginShell", 1, &cfg->login_shell);
\r
902 gppi(sesskey, "ScrollbarOnLeft", 0, &cfg->scrollbar_on_left);
\r
903 gppi(sesskey, "ShadowBold", 0, &cfg->shadowbold);
\r
904 gppfont(sesskey, "BoldFont", &cfg->boldfont);
\r
905 gppfont(sesskey, "WideFont", &cfg->widefont);
\r
906 gppfont(sesskey, "WideBoldFont", &cfg->wideboldfont);
\r
907 gppi(sesskey, "ShadowBoldOffset", 1, &cfg->shadowboldoffset);
\r
908 gpps(sesskey, "SerialLine", "", cfg->serline, sizeof(cfg->serline));
\r
909 gppi(sesskey, "SerialSpeed", 9600, &cfg->serspeed);
\r
910 gppi(sesskey, "SerialDataBits", 8, &cfg->serdatabits);
\r
911 gppi(sesskey, "SerialStopHalfbits", 2, &cfg->serstopbits);
\r
912 gppi(sesskey, "SerialParity", SER_PAR_NONE, &cfg->serparity);
\r
913 gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, &cfg->serflow);
\r
914 gpps(sesskey, "WindowClass", "", cfg->winclass, sizeof(cfg->winclass));
\r
917 void do_defaults(char *session, Config * cfg)
\r
919 load_settings(session, cfg);
\r
922 static int sessioncmp(const void *av, const void *bv)
\r
924 const char *a = *(const char *const *) av;
\r
925 const char *b = *(const char *const *) bv;
\r
928 * Alphabetical order, except that "Default Settings" is a
\r
929 * special case and comes first.
\r
931 if (!strcmp(a, "Default Settings"))
\r
932 return -1; /* a comes first */
\r
933 if (!strcmp(b, "Default Settings"))
\r
934 return +1; /* b comes first */
\r
936 * FIXME: perhaps we should ignore the first & in determining
\r
939 return strcmp(a, b); /* otherwise, compare normally */
\r
942 void get_sesslist(struct sesslist *list, int allocate)
\r
944 char otherbuf[2048];
\r
945 int buflen, bufsize, i;
\r
951 buflen = bufsize = 0;
\r
952 list->buffer = NULL;
\r
953 if ((handle = enum_settings_start()) != NULL) {
\r
955 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
\r
957 int len = strlen(otherbuf) + 1;
\r
958 if (bufsize < buflen + len) {
\r
959 bufsize = buflen + len + 2048;
\r
960 list->buffer = sresize(list->buffer, bufsize, char);
\r
962 strcpy(list->buffer + buflen, otherbuf);
\r
963 buflen += strlen(list->buffer + buflen) + 1;
\r
966 enum_settings_finish(handle);
\r
968 list->buffer = sresize(list->buffer, buflen + 1, char);
\r
969 list->buffer[buflen] = '\0';
\r
972 * Now set up the list of sessions. Note that "Default
\r
973 * Settings" must always be claimed to exist, even if it
\r
978 list->nsessions = 1; /* "Default Settings" counts as one */
\r
980 if (strcmp(p, "Default Settings"))
\r
987 list->sessions = snewn(list->nsessions + 1, char *);
\r
988 list->sessions[0] = "Default Settings";
\r
992 if (strcmp(p, "Default Settings"))
\r
993 list->sessions[i++] = p;
\r
999 qsort(list->sessions, i, sizeof(char *), sessioncmp);
\r
1001 sfree(list->buffer);
\r
1002 sfree(list->sessions);
\r
1003 list->buffer = NULL;
\r
1004 list->sessions = NULL;
\r