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 += 1 + strlen(s);
\r
310 buf = snewn(maxlen, 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 - 1); /* maxlen counted the NUL */
\r
322 write_setting_s(sesskey, name, buf);
\r
327 char *save_settings(char *section, Config * cfg)
\r
332 sesskey = open_settings_w(section, &errmsg);
\r
335 save_open_settings(sesskey, cfg);
\r
336 close_settings_w(sesskey);
\r
340 void save_open_settings(void *sesskey, Config *cfg)
\r
345 write_setting_i(sesskey, "Present", 1);
\r
346 write_setting_s(sesskey, "HostName", cfg->host);
\r
347 write_setting_filename(sesskey, "LogFileName", cfg->logfilename);
\r
348 write_setting_i(sesskey, "LogType", cfg->logtype);
\r
349 write_setting_i(sesskey, "LogFileClash", cfg->logxfovr);
\r
350 write_setting_i(sesskey, "LogFlush", cfg->logflush);
\r
351 write_setting_i(sesskey, "SSHLogOmitPasswords", cfg->logomitpass);
\r
352 write_setting_i(sesskey, "SSHLogOmitData", cfg->logomitdata);
\r
355 const Backend *b = backend_from_proto(cfg->protocol);
\r
359 write_setting_s(sesskey, "Protocol", p);
\r
360 write_setting_i(sesskey, "PortNumber", cfg->port);
\r
361 /* The CloseOnExit numbers are arranged in a different order from
\r
362 * the standard FORCE_ON / FORCE_OFF / AUTO. */
\r
363 write_setting_i(sesskey, "CloseOnExit", (cfg->close_on_exit+2)%3);
\r
364 write_setting_i(sesskey, "WarnOnClose", !!cfg->warn_on_close);
\r
365 write_setting_i(sesskey, "PingInterval", cfg->ping_interval / 60); /* minutes */
\r
366 write_setting_i(sesskey, "PingIntervalSecs", cfg->ping_interval % 60); /* seconds */
\r
367 write_setting_i(sesskey, "TCPNoDelay", cfg->tcp_nodelay);
\r
368 write_setting_i(sesskey, "TCPKeepalives", cfg->tcp_keepalives);
\r
369 write_setting_s(sesskey, "TerminalType", cfg->termtype);
\r
370 write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed);
\r
371 wmap(sesskey, "TerminalModes", cfg->ttymodes, lenof(cfg->ttymodes));
\r
373 /* Address family selection */
\r
374 write_setting_i(sesskey, "AddressFamily", cfg->addressfamily);
\r
376 /* proxy settings */
\r
377 write_setting_s(sesskey, "ProxyExcludeList", cfg->proxy_exclude_list);
\r
378 write_setting_i(sesskey, "ProxyDNS", (cfg->proxy_dns+2)%3);
\r
379 write_setting_i(sesskey, "ProxyLocalhost", cfg->even_proxy_localhost);
\r
380 write_setting_i(sesskey, "ProxyMethod", cfg->proxy_type);
\r
381 write_setting_s(sesskey, "ProxyHost", cfg->proxy_host);
\r
382 write_setting_i(sesskey, "ProxyPort", cfg->proxy_port);
\r
383 write_setting_s(sesskey, "ProxyUsername", cfg->proxy_username);
\r
384 write_setting_s(sesskey, "ProxyPassword", cfg->proxy_password);
\r
385 write_setting_s(sesskey, "ProxyTelnetCommand", cfg->proxy_telnet_command);
\r
386 wmap(sesskey, "Environment", cfg->environmt, lenof(cfg->environmt));
\r
387 write_setting_s(sesskey, "UserName", cfg->username);
\r
388 write_setting_i(sesskey, "UserNameFromEnvironment", cfg->username_from_env);
\r
389 write_setting_s(sesskey, "LocalUserName", cfg->localusername);
\r
390 write_setting_i(sesskey, "NoPTY", cfg->nopty);
\r
391 write_setting_i(sesskey, "Compression", cfg->compression);
\r
392 write_setting_i(sesskey, "TryAgent", cfg->tryagent);
\r
393 write_setting_i(sesskey, "AgentFwd", cfg->agentfwd);
\r
394 write_setting_i(sesskey, "GssapiFwd", cfg->gssapifwd);
\r
395 write_setting_i(sesskey, "ChangeUsername", cfg->change_username);
\r
396 wprefs(sesskey, "Cipher", ciphernames, CIPHER_MAX,
\r
397 cfg->ssh_cipherlist);
\r
398 wprefs(sesskey, "KEX", kexnames, KEX_MAX, cfg->ssh_kexlist);
\r
399 write_setting_i(sesskey, "RekeyTime", cfg->ssh_rekey_time);
\r
400 write_setting_s(sesskey, "RekeyBytes", cfg->ssh_rekey_data);
\r
401 write_setting_i(sesskey, "SshNoAuth", cfg->ssh_no_userauth);
\r
402 write_setting_i(sesskey, "SshBanner", cfg->ssh_show_banner);
\r
403 write_setting_i(sesskey, "AuthTIS", cfg->try_tis_auth);
\r
404 write_setting_i(sesskey, "AuthKI", cfg->try_ki_auth);
\r
405 write_setting_i(sesskey, "AuthGSSAPI", cfg->try_gssapi_auth);
\r
407 wprefs(sesskey, "GSSLibs", gsslibkeywords, ngsslibs,
\r
409 write_setting_filename(sesskey, "GSSCustom", cfg->ssh_gss_custom);
\r
411 write_setting_i(sesskey, "SshNoShell", cfg->ssh_no_shell);
\r
412 write_setting_i(sesskey, "SshProt", cfg->sshprot);
\r
413 write_setting_s(sesskey, "LogHost", cfg->loghost);
\r
414 write_setting_i(sesskey, "SSH2DES", cfg->ssh2_des_cbc);
\r
415 write_setting_filename(sesskey, "PublicKeyFile", cfg->keyfile);
\r
416 write_setting_s(sesskey, "RemoteCommand", cfg->remote_cmd);
\r
417 write_setting_i(sesskey, "RFCEnviron", cfg->rfc_environ);
\r
418 write_setting_i(sesskey, "PassiveTelnet", cfg->passive_telnet);
\r
419 write_setting_i(sesskey, "BackspaceIsDelete", cfg->bksp_is_delete);
\r
420 write_setting_i(sesskey, "RXVTHomeEnd", cfg->rxvt_homeend);
\r
421 write_setting_i(sesskey, "LinuxFunctionKeys", cfg->funky_type);
\r
422 write_setting_i(sesskey, "NoApplicationKeys", cfg->no_applic_k);
\r
423 write_setting_i(sesskey, "NoApplicationCursors", cfg->no_applic_c);
\r
424 write_setting_i(sesskey, "NoMouseReporting", cfg->no_mouse_rep);
\r
425 write_setting_i(sesskey, "NoRemoteResize", cfg->no_remote_resize);
\r
426 write_setting_i(sesskey, "NoAltScreen", cfg->no_alt_screen);
\r
427 write_setting_i(sesskey, "NoRemoteWinTitle", cfg->no_remote_wintitle);
\r
428 write_setting_i(sesskey, "RemoteQTitleAction", cfg->remote_qtitle_action);
\r
429 write_setting_i(sesskey, "NoDBackspace", cfg->no_dbackspace);
\r
430 write_setting_i(sesskey, "NoRemoteCharset", cfg->no_remote_charset);
\r
431 write_setting_i(sesskey, "ApplicationCursorKeys", cfg->app_cursor);
\r
432 write_setting_i(sesskey, "ApplicationKeypad", cfg->app_keypad);
\r
433 write_setting_i(sesskey, "NetHackKeypad", cfg->nethack_keypad);
\r
434 write_setting_i(sesskey, "AltF4", cfg->alt_f4);
\r
435 write_setting_i(sesskey, "AltSpace", cfg->alt_space);
\r
436 write_setting_i(sesskey, "AltOnly", cfg->alt_only);
\r
437 write_setting_i(sesskey, "ComposeKey", cfg->compose_key);
\r
438 write_setting_i(sesskey, "CtrlAltKeys", cfg->ctrlaltkeys);
\r
439 write_setting_i(sesskey, "TelnetKey", cfg->telnet_keyboard);
\r
440 write_setting_i(sesskey, "TelnetRet", cfg->telnet_newline);
\r
441 write_setting_i(sesskey, "LocalEcho", cfg->localecho);
\r
442 write_setting_i(sesskey, "LocalEdit", cfg->localedit);
\r
443 write_setting_s(sesskey, "Answerback", cfg->answerback);
\r
444 write_setting_i(sesskey, "AlwaysOnTop", cfg->alwaysontop);
\r
445 write_setting_i(sesskey, "FullScreenOnAltEnter", cfg->fullscreenonaltenter);
\r
446 write_setting_i(sesskey, "HideMousePtr", cfg->hide_mouseptr);
\r
447 write_setting_i(sesskey, "SunkenEdge", cfg->sunken_edge);
\r
448 write_setting_i(sesskey, "WindowBorder", cfg->window_border);
\r
449 write_setting_i(sesskey, "CurType", cfg->cursor_type);
\r
450 write_setting_i(sesskey, "BlinkCur", cfg->blink_cur);
\r
451 write_setting_i(sesskey, "Beep", cfg->beep);
\r
452 write_setting_i(sesskey, "BeepInd", cfg->beep_ind);
\r
453 write_setting_filename(sesskey, "BellWaveFile", cfg->bell_wavefile);
\r
454 write_setting_i(sesskey, "BellOverload", cfg->bellovl);
\r
455 write_setting_i(sesskey, "BellOverloadN", cfg->bellovl_n);
\r
456 write_setting_i(sesskey, "BellOverloadT", cfg->bellovl_t
\r
457 #ifdef PUTTY_UNIX_H
\r
461 write_setting_i(sesskey, "BellOverloadS", cfg->bellovl_s
\r
462 #ifdef PUTTY_UNIX_H
\r
466 write_setting_i(sesskey, "ScrollbackLines", cfg->savelines);
\r
467 write_setting_i(sesskey, "DECOriginMode", cfg->dec_om);
\r
468 write_setting_i(sesskey, "AutoWrapMode", cfg->wrap_mode);
\r
469 write_setting_i(sesskey, "LFImpliesCR", cfg->lfhascr);
\r
470 write_setting_i(sesskey, "CRImpliesLF", cfg->crhaslf);
\r
471 write_setting_i(sesskey, "DisableArabicShaping", cfg->arabicshaping);
\r
472 write_setting_i(sesskey, "DisableBidi", cfg->bidi);
\r
473 write_setting_i(sesskey, "WinNameAlways", cfg->win_name_always);
\r
474 write_setting_s(sesskey, "WinTitle", cfg->wintitle);
\r
475 write_setting_i(sesskey, "TermWidth", cfg->width);
\r
476 write_setting_i(sesskey, "TermHeight", cfg->height);
\r
477 write_setting_fontspec(sesskey, "Font", cfg->font);
\r
478 write_setting_i(sesskey, "FontQuality", cfg->font_quality);
\r
479 write_setting_i(sesskey, "FontVTMode", cfg->vtmode);
\r
480 write_setting_i(sesskey, "UseSystemColours", cfg->system_colour);
\r
481 write_setting_i(sesskey, "TryPalette", cfg->try_palette);
\r
482 write_setting_i(sesskey, "ANSIColour", cfg->ansi_colour);
\r
483 write_setting_i(sesskey, "Xterm256Colour", cfg->xterm_256_colour);
\r
484 write_setting_i(sesskey, "BoldAsColour", cfg->bold_colour);
\r
486 for (i = 0; i < 22; i++) {
\r
487 char buf[20], buf2[30];
\r
488 sprintf(buf, "Colour%d", i);
\r
489 sprintf(buf2, "%d,%d,%d", cfg->colours[i][0],
\r
490 cfg->colours[i][1], cfg->colours[i][2]);
\r
491 write_setting_s(sesskey, buf, buf2);
\r
493 write_setting_i(sesskey, "RawCNP", cfg->rawcnp);
\r
494 write_setting_i(sesskey, "PasteRTF", cfg->rtf_paste);
\r
495 write_setting_i(sesskey, "MouseIsXterm", cfg->mouse_is_xterm);
\r
496 write_setting_i(sesskey, "RectSelect", cfg->rect_select);
\r
497 write_setting_i(sesskey, "MouseOverride", cfg->mouse_override);
\r
498 for (i = 0; i < 256; i += 32) {
\r
499 char buf[20], buf2[256];
\r
501 sprintf(buf, "Wordness%d", i);
\r
503 for (j = i; j < i + 32; j++) {
\r
504 sprintf(buf2 + strlen(buf2), "%s%d",
\r
505 (*buf2 ? "," : ""), cfg->wordness[j]);
\r
507 write_setting_s(sesskey, buf, buf2);
\r
509 write_setting_s(sesskey, "LineCodePage", cfg->line_codepage);
\r
510 write_setting_i(sesskey, "CJKAmbigWide", cfg->cjk_ambig_wide);
\r
511 write_setting_i(sesskey, "UTF8Override", cfg->utf8_override);
\r
512 write_setting_s(sesskey, "Printer", cfg->printer);
\r
513 write_setting_i(sesskey, "CapsLockCyr", cfg->xlat_capslockcyr);
\r
514 write_setting_i(sesskey, "ScrollBar", cfg->scrollbar);
\r
515 write_setting_i(sesskey, "ScrollBarFullScreen", cfg->scrollbar_in_fullscreen);
\r
516 write_setting_i(sesskey, "ScrollOnKey", cfg->scroll_on_key);
\r
517 write_setting_i(sesskey, "ScrollOnDisp", cfg->scroll_on_disp);
\r
518 write_setting_i(sesskey, "EraseToScrollback", cfg->erase_to_scrollback);
\r
519 write_setting_i(sesskey, "LockSize", cfg->resize_action);
\r
520 write_setting_i(sesskey, "BCE", cfg->bce);
\r
521 write_setting_i(sesskey, "BlinkText", cfg->blinktext);
\r
522 write_setting_i(sesskey, "X11Forward", cfg->x11_forward);
\r
523 write_setting_s(sesskey, "X11Display", cfg->x11_display);
\r
524 write_setting_i(sesskey, "X11AuthType", cfg->x11_auth);
\r
525 write_setting_filename(sesskey, "X11AuthFile", cfg->xauthfile);
\r
526 write_setting_i(sesskey, "LocalPortAcceptAll", cfg->lport_acceptall);
\r
527 write_setting_i(sesskey, "RemotePortAcceptAll", cfg->rport_acceptall);
\r
528 wmap(sesskey, "PortForwardings", cfg->portfwd, lenof(cfg->portfwd));
\r
529 write_setting_i(sesskey, "BugIgnore1", 2-cfg->sshbug_ignore1);
\r
530 write_setting_i(sesskey, "BugPlainPW1", 2-cfg->sshbug_plainpw1);
\r
531 write_setting_i(sesskey, "BugRSA1", 2-cfg->sshbug_rsa1);
\r
532 write_setting_i(sesskey, "BugIgnore2", 2-cfg->sshbug_ignore2);
\r
533 write_setting_i(sesskey, "BugHMAC2", 2-cfg->sshbug_hmac2);
\r
534 write_setting_i(sesskey, "BugDeriveKey2", 2-cfg->sshbug_derivekey2);
\r
535 write_setting_i(sesskey, "BugRSAPad2", 2-cfg->sshbug_rsapad2);
\r
536 write_setting_i(sesskey, "BugPKSessID2", 2-cfg->sshbug_pksessid2);
\r
537 write_setting_i(sesskey, "BugRekey2", 2-cfg->sshbug_rekey2);
\r
538 write_setting_i(sesskey, "BugMaxPkt2", 2-cfg->sshbug_maxpkt2);
\r
539 write_setting_i(sesskey, "StampUtmp", cfg->stamp_utmp);
\r
540 write_setting_i(sesskey, "LoginShell", cfg->login_shell);
\r
541 write_setting_i(sesskey, "ScrollbarOnLeft", cfg->scrollbar_on_left);
\r
542 write_setting_fontspec(sesskey, "BoldFont", cfg->boldfont);
\r
543 write_setting_fontspec(sesskey, "WideFont", cfg->widefont);
\r
544 write_setting_fontspec(sesskey, "WideBoldFont", cfg->wideboldfont);
\r
545 write_setting_i(sesskey, "ShadowBold", cfg->shadowbold);
\r
546 write_setting_i(sesskey, "ShadowBoldOffset", cfg->shadowboldoffset);
\r
547 write_setting_s(sesskey, "SerialLine", cfg->serline);
\r
548 write_setting_i(sesskey, "SerialSpeed", cfg->serspeed);
\r
549 write_setting_i(sesskey, "SerialDataBits", cfg->serdatabits);
\r
550 write_setting_i(sesskey, "SerialStopHalfbits", cfg->serstopbits);
\r
551 write_setting_i(sesskey, "SerialParity", cfg->serparity);
\r
552 write_setting_i(sesskey, "SerialFlowControl", cfg->serflow);
\r
553 write_setting_s(sesskey, "WindowClass", cfg->winclass);
\r
556 void load_settings(char *section, Config * cfg)
\r
560 sesskey = open_settings_r(section);
\r
561 load_open_settings(sesskey, cfg);
\r
562 close_settings_r(sesskey);
\r
564 if (cfg_launchable(cfg))
\r
565 add_session_to_jumplist(section);
\r
568 void load_open_settings(void *sesskey, Config *cfg)
\r
573 cfg->ssh_subsys = 0; /* FIXME: load this properly */
\r
574 cfg->remote_cmd_ptr = NULL;
\r
575 cfg->remote_cmd_ptr2 = NULL;
\r
576 cfg->ssh_nc_host[0] = '\0';
\r
578 gpps(sesskey, "HostName", "", cfg->host, sizeof(cfg->host));
\r
579 gppfile(sesskey, "LogFileName", &cfg->logfilename);
\r
580 gppi(sesskey, "LogType", 0, &cfg->logtype);
\r
581 gppi(sesskey, "LogFileClash", LGXF_ASK, &cfg->logxfovr);
\r
582 gppi(sesskey, "LogFlush", 1, &cfg->logflush);
\r
583 gppi(sesskey, "SSHLogOmitPasswords", 1, &cfg->logomitpass);
\r
584 gppi(sesskey, "SSHLogOmitData", 0, &cfg->logomitdata);
\r
586 gpps(sesskey, "Protocol", "default", prot, 10);
\r
587 cfg->protocol = default_protocol;
\r
588 cfg->port = default_port;
\r
590 const Backend *b = backend_from_name(prot);
\r
592 cfg->protocol = b->protocol;
\r
593 gppi(sesskey, "PortNumber", default_port, &cfg->port);
\r
597 /* Address family selection */
\r
598 gppi(sesskey, "AddressFamily", ADDRTYPE_UNSPEC, &cfg->addressfamily);
\r
600 /* The CloseOnExit numbers are arranged in a different order from
\r
601 * the standard FORCE_ON / FORCE_OFF / AUTO. */
\r
602 gppi(sesskey, "CloseOnExit", 1, &i); cfg->close_on_exit = (i+1)%3;
\r
603 gppi(sesskey, "WarnOnClose", 1, &cfg->warn_on_close);
\r
605 /* This is two values for backward compatibility with 0.50/0.51 */
\r
606 int pingmin, pingsec;
\r
607 gppi(sesskey, "PingInterval", 0, &pingmin);
\r
608 gppi(sesskey, "PingIntervalSecs", 0, &pingsec);
\r
609 cfg->ping_interval = pingmin * 60 + pingsec;
\r
611 gppi(sesskey, "TCPNoDelay", 1, &cfg->tcp_nodelay);
\r
612 gppi(sesskey, "TCPKeepalives", 0, &cfg->tcp_keepalives);
\r
613 gpps(sesskey, "TerminalType", "xterm", cfg->termtype,
\r
614 sizeof(cfg->termtype));
\r
615 gpps(sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed,
\r
616 sizeof(cfg->termspeed));
\r
618 /* This hardcodes a big set of defaults in any new saved
\r
619 * sessions. Let's hope we don't change our mind. */
\r
621 char *def = dupstr("");
\r
622 /* Default: all set to "auto" */
\r
623 for (i = 0; ttymodes[i]; i++) {
\r
624 char *def2 = dupprintf("%s%s=A,", def, ttymodes[i]);
\r
628 gppmap(sesskey, "TerminalModes", def,
\r
629 cfg->ttymodes, lenof(cfg->ttymodes));
\r
633 /* proxy settings */
\r
634 gpps(sesskey, "ProxyExcludeList", "", cfg->proxy_exclude_list,
\r
635 sizeof(cfg->proxy_exclude_list));
\r
636 gppi(sesskey, "ProxyDNS", 1, &i); cfg->proxy_dns = (i+1)%3;
\r
637 gppi(sesskey, "ProxyLocalhost", 0, &cfg->even_proxy_localhost);
\r
638 gppi(sesskey, "ProxyMethod", -1, &cfg->proxy_type);
\r
639 if (cfg->proxy_type == -1) {
\r
641 gppi(sesskey, "ProxyType", 0, &i);
\r
643 cfg->proxy_type = PROXY_NONE;
\r
645 cfg->proxy_type = PROXY_HTTP;
\r
647 cfg->proxy_type = PROXY_TELNET;
\r
649 cfg->proxy_type = PROXY_CMD;
\r
651 gppi(sesskey, "ProxySOCKSVersion", 5, &i);
\r
653 cfg->proxy_type = PROXY_SOCKS5;
\r
655 cfg->proxy_type = PROXY_SOCKS4;
\r
658 gpps(sesskey, "ProxyHost", "proxy", cfg->proxy_host,
\r
659 sizeof(cfg->proxy_host));
\r
660 gppi(sesskey, "ProxyPort", 80, &cfg->proxy_port);
\r
661 gpps(sesskey, "ProxyUsername", "", cfg->proxy_username,
\r
662 sizeof(cfg->proxy_username));
\r
663 gpps(sesskey, "ProxyPassword", "", cfg->proxy_password,
\r
664 sizeof(cfg->proxy_password));
\r
665 gpps(sesskey, "ProxyTelnetCommand", "connect %host %port\\n",
\r
666 cfg->proxy_telnet_command, sizeof(cfg->proxy_telnet_command));
\r
667 gppmap(sesskey, "Environment", "", cfg->environmt, lenof(cfg->environmt));
\r
668 gpps(sesskey, "UserName", "", cfg->username, sizeof(cfg->username));
\r
669 gppi(sesskey, "UserNameFromEnvironment", 0, &cfg->username_from_env);
\r
670 gpps(sesskey, "LocalUserName", "", cfg->localusername,
\r
671 sizeof(cfg->localusername));
\r
672 gppi(sesskey, "NoPTY", 0, &cfg->nopty);
\r
673 gppi(sesskey, "Compression", 0, &cfg->compression);
\r
674 gppi(sesskey, "TryAgent", 1, &cfg->tryagent);
\r
675 gppi(sesskey, "AgentFwd", 0, &cfg->agentfwd);
\r
676 gppi(sesskey, "ChangeUsername", 0, &cfg->change_username);
\r
677 gppi(sesskey, "GssapiFwd", 0, &cfg->gssapifwd);
\r
678 gprefs(sesskey, "Cipher", "\0",
\r
679 ciphernames, CIPHER_MAX, cfg->ssh_cipherlist);
\r
681 /* Backward-compatibility: we used to have an option to
\r
682 * disable gex under the "bugs" panel after one report of
\r
683 * a server which offered it then choked, but we never got
\r
684 * a server version string or any other reports. */
\r
685 char *default_kexes;
\r
686 gppi(sesskey, "BugDHGEx2", 0, &i); i = 2-i;
\r
688 default_kexes = "dh-group14-sha1,dh-group1-sha1,rsa,WARN,dh-gex-sha1";
\r
690 default_kexes = "dh-gex-sha1,dh-group14-sha1,dh-group1-sha1,rsa,WARN";
\r
691 gprefs(sesskey, "KEX", default_kexes,
\r
692 kexnames, KEX_MAX, cfg->ssh_kexlist);
\r
694 gppi(sesskey, "RekeyTime", 60, &cfg->ssh_rekey_time);
\r
695 gpps(sesskey, "RekeyBytes", "1G", cfg->ssh_rekey_data,
\r
696 sizeof(cfg->ssh_rekey_data));
\r
697 gppi(sesskey, "SshProt", 2, &cfg->sshprot);
\r
698 gpps(sesskey, "LogHost", "", cfg->loghost, sizeof(cfg->loghost));
\r
699 gppi(sesskey, "SSH2DES", 0, &cfg->ssh2_des_cbc);
\r
700 gppi(sesskey, "SshNoAuth", 0, &cfg->ssh_no_userauth);
\r
701 gppi(sesskey, "SshBanner", 1, &cfg->ssh_show_banner);
\r
702 gppi(sesskey, "AuthTIS", 0, &cfg->try_tis_auth);
\r
703 gppi(sesskey, "AuthKI", 1, &cfg->try_ki_auth);
\r
704 gppi(sesskey, "AuthGSSAPI", 1, &cfg->try_gssapi_auth);
\r
706 gprefs(sesskey, "GSSLibs", "\0",
\r
707 gsslibkeywords, ngsslibs, cfg->ssh_gsslist);
\r
708 gppfile(sesskey, "GSSCustom", &cfg->ssh_gss_custom);
\r
710 gppi(sesskey, "SshNoShell", 0, &cfg->ssh_no_shell);
\r
711 gppfile(sesskey, "PublicKeyFile", &cfg->keyfile);
\r
712 gpps(sesskey, "RemoteCommand", "", cfg->remote_cmd,
\r
713 sizeof(cfg->remote_cmd));
\r
714 gppi(sesskey, "RFCEnviron", 0, &cfg->rfc_environ);
\r
715 gppi(sesskey, "PassiveTelnet", 0, &cfg->passive_telnet);
\r
716 gppi(sesskey, "BackspaceIsDelete", 1, &cfg->bksp_is_delete);
\r
717 gppi(sesskey, "RXVTHomeEnd", 0, &cfg->rxvt_homeend);
\r
718 gppi(sesskey, "LinuxFunctionKeys", 0, &cfg->funky_type);
\r
719 gppi(sesskey, "NoApplicationKeys", 0, &cfg->no_applic_k);
\r
720 gppi(sesskey, "NoApplicationCursors", 0, &cfg->no_applic_c);
\r
721 gppi(sesskey, "NoMouseReporting", 0, &cfg->no_mouse_rep);
\r
722 gppi(sesskey, "NoRemoteResize", 0, &cfg->no_remote_resize);
\r
723 gppi(sesskey, "NoAltScreen", 0, &cfg->no_alt_screen);
\r
724 gppi(sesskey, "NoRemoteWinTitle", 0, &cfg->no_remote_wintitle);
\r
726 /* Backward compatibility */
\r
727 int no_remote_qtitle;
\r
728 gppi(sesskey, "NoRemoteQTitle", 1, &no_remote_qtitle);
\r
729 /* We deliberately interpret the old setting of "no response" as
\r
730 * "empty string". This changes the behaviour, but hopefully for
\r
731 * the better; the user can always recover the old behaviour. */
\r
732 gppi(sesskey, "RemoteQTitleAction",
\r
733 no_remote_qtitle ? TITLE_EMPTY : TITLE_REAL,
\r
734 &cfg->remote_qtitle_action);
\r
736 gppi(sesskey, "NoDBackspace", 0, &cfg->no_dbackspace);
\r
737 gppi(sesskey, "NoRemoteCharset", 0, &cfg->no_remote_charset);
\r
738 gppi(sesskey, "ApplicationCursorKeys", 0, &cfg->app_cursor);
\r
739 gppi(sesskey, "ApplicationKeypad", 0, &cfg->app_keypad);
\r
740 gppi(sesskey, "NetHackKeypad", 0, &cfg->nethack_keypad);
\r
741 gppi(sesskey, "AltF4", 1, &cfg->alt_f4);
\r
742 gppi(sesskey, "AltSpace", 0, &cfg->alt_space);
\r
743 gppi(sesskey, "AltOnly", 0, &cfg->alt_only);
\r
744 gppi(sesskey, "ComposeKey", 0, &cfg->compose_key);
\r
745 gppi(sesskey, "CtrlAltKeys", 1, &cfg->ctrlaltkeys);
\r
746 gppi(sesskey, "TelnetKey", 0, &cfg->telnet_keyboard);
\r
747 gppi(sesskey, "TelnetRet", 1, &cfg->telnet_newline);
\r
748 gppi(sesskey, "LocalEcho", AUTO, &cfg->localecho);
\r
749 gppi(sesskey, "LocalEdit", AUTO, &cfg->localedit);
\r
750 gpps(sesskey, "Answerback", "PuTTY", cfg->answerback,
\r
751 sizeof(cfg->answerback));
\r
752 gppi(sesskey, "AlwaysOnTop", 0, &cfg->alwaysontop);
\r
753 gppi(sesskey, "FullScreenOnAltEnter", 0, &cfg->fullscreenonaltenter);
\r
754 gppi(sesskey, "HideMousePtr", 0, &cfg->hide_mouseptr);
\r
755 gppi(sesskey, "SunkenEdge", 0, &cfg->sunken_edge);
\r
756 gppi(sesskey, "WindowBorder", 1, &cfg->window_border);
\r
757 gppi(sesskey, "CurType", 0, &cfg->cursor_type);
\r
758 gppi(sesskey, "BlinkCur", 0, &cfg->blink_cur);
\r
759 /* pedantic compiler tells me I can't use &cfg->beep as an int * :-) */
\r
760 gppi(sesskey, "Beep", 1, &cfg->beep);
\r
761 gppi(sesskey, "BeepInd", 0, &cfg->beep_ind);
\r
762 gppfile(sesskey, "BellWaveFile", &cfg->bell_wavefile);
\r
763 gppi(sesskey, "BellOverload", 1, &cfg->bellovl);
\r
764 gppi(sesskey, "BellOverloadN", 5, &cfg->bellovl_n);
\r
765 gppi(sesskey, "BellOverloadT", 2*TICKSPERSEC
\r
766 #ifdef PUTTY_UNIX_H
\r
771 #ifdef PUTTY_UNIX_H
\r
775 gppi(sesskey, "BellOverloadS", 5*TICKSPERSEC
\r
776 #ifdef PUTTY_UNIX_H
\r
781 #ifdef PUTTY_UNIX_H
\r
785 gppi(sesskey, "ScrollbackLines", 200, &cfg->savelines);
\r
786 gppi(sesskey, "DECOriginMode", 0, &cfg->dec_om);
\r
787 gppi(sesskey, "AutoWrapMode", 1, &cfg->wrap_mode);
\r
788 gppi(sesskey, "LFImpliesCR", 0, &cfg->lfhascr);
\r
789 gppi(sesskey, "CRImpliesLF", 0, &cfg->crhaslf);
\r
790 gppi(sesskey, "DisableArabicShaping", 0, &cfg->arabicshaping);
\r
791 gppi(sesskey, "DisableBidi", 0, &cfg->bidi);
\r
792 gppi(sesskey, "WinNameAlways", 1, &cfg->win_name_always);
\r
793 gpps(sesskey, "WinTitle", "", cfg->wintitle, sizeof(cfg->wintitle));
\r
794 gppi(sesskey, "TermWidth", 80, &cfg->width);
\r
795 gppi(sesskey, "TermHeight", 24, &cfg->height);
\r
796 gppfont(sesskey, "Font", &cfg->font);
\r
797 gppi(sesskey, "FontQuality", FQ_DEFAULT, &cfg->font_quality);
\r
798 gppi(sesskey, "FontVTMode", VT_UNICODE, (int *) &cfg->vtmode);
\r
799 gppi(sesskey, "UseSystemColours", 0, &cfg->system_colour);
\r
800 gppi(sesskey, "TryPalette", 0, &cfg->try_palette);
\r
801 gppi(sesskey, "ANSIColour", 1, &cfg->ansi_colour);
\r
802 gppi(sesskey, "Xterm256Colour", 1, &cfg->xterm_256_colour);
\r
803 gppi(sesskey, "BoldAsColour", 1, &cfg->bold_colour);
\r
805 for (i = 0; i < 22; i++) {
\r
806 static const char *const defaults[] = {
\r
807 "187,187,187", "255,255,255", "0,0,0", "85,85,85", "0,0,0",
\r
808 "0,255,0", "0,0,0", "85,85,85", "187,0,0", "255,85,85",
\r
809 "0,187,0", "85,255,85", "187,187,0", "255,255,85", "0,0,187",
\r
810 "85,85,255", "187,0,187", "255,85,255", "0,187,187",
\r
811 "85,255,255", "187,187,187", "255,255,255"
\r
813 char buf[20], buf2[30];
\r
815 sprintf(buf, "Colour%d", i);
\r
816 gpps(sesskey, buf, defaults[i], buf2, sizeof(buf2));
\r
817 if (sscanf(buf2, "%d,%d,%d", &c0, &c1, &c2) == 3) {
\r
818 cfg->colours[i][0] = c0;
\r
819 cfg->colours[i][1] = c1;
\r
820 cfg->colours[i][2] = c2;
\r
823 gppi(sesskey, "RawCNP", 0, &cfg->rawcnp);
\r
824 gppi(sesskey, "PasteRTF", 0, &cfg->rtf_paste);
\r
825 gppi(sesskey, "MouseIsXterm", 0, &cfg->mouse_is_xterm);
\r
826 gppi(sesskey, "RectSelect", 0, &cfg->rect_select);
\r
827 gppi(sesskey, "MouseOverride", 1, &cfg->mouse_override);
\r
828 for (i = 0; i < 256; i += 32) {
\r
829 static const char *const defaults[] = {
\r
830 "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
831 "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
832 "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
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,1",
\r
834 "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
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 "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
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
839 char buf[20], buf2[256], *p;
\r
841 sprintf(buf, "Wordness%d", i);
\r
842 gpps(sesskey, buf, defaults[i / 32], buf2, sizeof(buf2));
\r
844 for (j = i; j < i + 32; j++) {
\r
846 while (*p && *p != ',')
\r
850 cfg->wordness[j] = atoi(q);
\r
854 * The empty default for LineCodePage will be converted later
\r
855 * into a plausible default for the locale.
\r
857 gpps(sesskey, "LineCodePage", "", cfg->line_codepage,
\r
858 sizeof(cfg->line_codepage));
\r
859 gppi(sesskey, "CJKAmbigWide", 0, &cfg->cjk_ambig_wide);
\r
860 gppi(sesskey, "UTF8Override", 1, &cfg->utf8_override);
\r
861 gpps(sesskey, "Printer", "", cfg->printer, sizeof(cfg->printer));
\r
862 gppi (sesskey, "CapsLockCyr", 0, &cfg->xlat_capslockcyr);
\r
863 gppi(sesskey, "ScrollBar", 1, &cfg->scrollbar);
\r
864 gppi(sesskey, "ScrollBarFullScreen", 0, &cfg->scrollbar_in_fullscreen);
\r
865 gppi(sesskey, "ScrollOnKey", 0, &cfg->scroll_on_key);
\r
866 gppi(sesskey, "ScrollOnDisp", 1, &cfg->scroll_on_disp);
\r
867 gppi(sesskey, "EraseToScrollback", 1, &cfg->erase_to_scrollback);
\r
868 gppi(sesskey, "LockSize", 0, &cfg->resize_action);
\r
869 gppi(sesskey, "BCE", 1, &cfg->bce);
\r
870 gppi(sesskey, "BlinkText", 0, &cfg->blinktext);
\r
871 gppi(sesskey, "X11Forward", 0, &cfg->x11_forward);
\r
872 gpps(sesskey, "X11Display", "", cfg->x11_display,
\r
873 sizeof(cfg->x11_display));
\r
874 gppi(sesskey, "X11AuthType", X11_MIT, &cfg->x11_auth);
\r
875 gppfile(sesskey, "X11AuthFile", &cfg->xauthfile);
\r
877 gppi(sesskey, "LocalPortAcceptAll", 0, &cfg->lport_acceptall);
\r
878 gppi(sesskey, "RemotePortAcceptAll", 0, &cfg->rport_acceptall);
\r
879 gppmap(sesskey, "PortForwardings", "", cfg->portfwd, lenof(cfg->portfwd));
\r
880 gppi(sesskey, "BugIgnore1", 0, &i); cfg->sshbug_ignore1 = 2-i;
\r
881 gppi(sesskey, "BugPlainPW1", 0, &i); cfg->sshbug_plainpw1 = 2-i;
\r
882 gppi(sesskey, "BugRSA1", 0, &i); cfg->sshbug_rsa1 = 2-i;
\r
883 gppi(sesskey, "BugIgnore2", 0, &i); cfg->sshbug_ignore2 = 2-i;
\r
886 gppi(sesskey, "BugHMAC2", 0, &i); cfg->sshbug_hmac2 = 2-i;
\r
887 if (cfg->sshbug_hmac2 == AUTO) {
\r
888 gppi(sesskey, "BuggyMAC", 0, &i);
\r
890 cfg->sshbug_hmac2 = FORCE_ON;
\r
893 gppi(sesskey, "BugDeriveKey2", 0, &i); cfg->sshbug_derivekey2 = 2-i;
\r
894 gppi(sesskey, "BugRSAPad2", 0, &i); cfg->sshbug_rsapad2 = 2-i;
\r
895 gppi(sesskey, "BugPKSessID2", 0, &i); cfg->sshbug_pksessid2 = 2-i;
\r
896 gppi(sesskey, "BugRekey2", 0, &i); cfg->sshbug_rekey2 = 2-i;
\r
897 gppi(sesskey, "BugMaxPkt2", 0, &i); cfg->sshbug_maxpkt2 = 2-i;
\r
898 cfg->ssh_simple = FALSE;
\r
899 gppi(sesskey, "StampUtmp", 1, &cfg->stamp_utmp);
\r
900 gppi(sesskey, "LoginShell", 1, &cfg->login_shell);
\r
901 gppi(sesskey, "ScrollbarOnLeft", 0, &cfg->scrollbar_on_left);
\r
902 gppi(sesskey, "ShadowBold", 0, &cfg->shadowbold);
\r
903 gppfont(sesskey, "BoldFont", &cfg->boldfont);
\r
904 gppfont(sesskey, "WideFont", &cfg->widefont);
\r
905 gppfont(sesskey, "WideBoldFont", &cfg->wideboldfont);
\r
906 gppi(sesskey, "ShadowBoldOffset", 1, &cfg->shadowboldoffset);
\r
907 gpps(sesskey, "SerialLine", "", cfg->serline, sizeof(cfg->serline));
\r
908 gppi(sesskey, "SerialSpeed", 9600, &cfg->serspeed);
\r
909 gppi(sesskey, "SerialDataBits", 8, &cfg->serdatabits);
\r
910 gppi(sesskey, "SerialStopHalfbits", 2, &cfg->serstopbits);
\r
911 gppi(sesskey, "SerialParity", SER_PAR_NONE, &cfg->serparity);
\r
912 gppi(sesskey, "SerialFlowControl", SER_FLOW_XONXOFF, &cfg->serflow);
\r
913 gpps(sesskey, "WindowClass", "", cfg->winclass, sizeof(cfg->winclass));
\r
916 void do_defaults(char *session, Config * cfg)
\r
918 load_settings(session, cfg);
\r
921 static int sessioncmp(const void *av, const void *bv)
\r
923 const char *a = *(const char *const *) av;
\r
924 const char *b = *(const char *const *) bv;
\r
927 * Alphabetical order, except that "Default Settings" is a
\r
928 * special case and comes first.
\r
930 if (!strcmp(a, "Default Settings"))
\r
931 return -1; /* a comes first */
\r
932 if (!strcmp(b, "Default Settings"))
\r
933 return +1; /* b comes first */
\r
935 * FIXME: perhaps we should ignore the first & in determining
\r
938 return strcmp(a, b); /* otherwise, compare normally */
\r
941 void get_sesslist(struct sesslist *list, int allocate)
\r
943 char otherbuf[2048];
\r
944 int buflen, bufsize, i;
\r
950 buflen = bufsize = 0;
\r
951 list->buffer = NULL;
\r
952 if ((handle = enum_settings_start()) != NULL) {
\r
954 ret = enum_settings_next(handle, otherbuf, sizeof(otherbuf));
\r
956 int len = strlen(otherbuf) + 1;
\r
957 if (bufsize < buflen + len) {
\r
958 bufsize = buflen + len + 2048;
\r
959 list->buffer = sresize(list->buffer, bufsize, char);
\r
961 strcpy(list->buffer + buflen, otherbuf);
\r
962 buflen += strlen(list->buffer + buflen) + 1;
\r
965 enum_settings_finish(handle);
\r
967 list->buffer = sresize(list->buffer, buflen + 1, char);
\r
968 list->buffer[buflen] = '\0';
\r
971 * Now set up the list of sessions. Note that "Default
\r
972 * Settings" must always be claimed to exist, even if it
\r
977 list->nsessions = 1; /* "Default Settings" counts as one */
\r
979 if (strcmp(p, "Default Settings"))
\r
986 list->sessions = snewn(list->nsessions + 1, char *);
\r
987 list->sessions[0] = "Default Settings";
\r
991 if (strcmp(p, "Default Settings"))
\r
992 list->sessions[i++] = p;
\r
998 qsort(list->sessions, i, sizeof(char *), sessioncmp);
\r
1000 sfree(list->buffer);
\r
1001 sfree(list->sessions);
\r
1002 list->buffer = NULL;
\r
1003 list->sessions = NULL;
\r