/*
 * config.c - the platform-independent parts of the PuTTY
 * configuration box.
 */

#include <assert.h>
#include <stdlib.h>

#include "putty.h"
#include "dialog.h"
#include "storage.h"

#ifdef SCPORT
#include "pkcs11.h"
#include "sc.h"
void sc_dlg_stdfilesel_handler11(union control *ctrl, void *dlg, void *data, int event) ;
#endif

#define PRINTER_DISABLED_STRING "Печать отключена"

#define HOST_BOX_TITLE "Имя хоста (или IP-адрес)"
#define PORT_BOX_TITLE "Порт"

#ifdef CYGTERMPORT
int cygterm_get_flag( void ) ;
#endif

static void config_host_handler(union control *ctrl, void *dlg,
				void *data, int event)
{
    Config *cfg = (Config *)data;

    /*
     * This function works just like the standard edit box handler,
     * only it has to choose the control's label and text from two
     * different places depending on the protocol.
     */
    if (event == EVENT_REFRESH) {
	if (cfg->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, "Последовательная линия");
	    dlg_editbox_set(ctrl, dlg, cfg->serline);
#ifdef CYGTERMPORT
	} else if (cfg->protocol == PROT_CYGTERM) {
	    dlg_label_change(ctrl, dlg, "Команда ( \"-\" для входа в shell; \"?\" для exe)");
	    dlg_editbox_set(ctrl, dlg, cfg->cygcmd);
#endif
	} else {
	    dlg_label_change(ctrl, dlg, HOST_BOX_TITLE);
	    dlg_editbox_set(ctrl, dlg, cfg->host);
	}
    } else if (event == EVENT_VALCHANGE) {
	if (cfg->protocol == PROT_SERIAL)
	    dlg_editbox_get(ctrl, dlg, cfg->serline, lenof(cfg->serline));
#ifdef CYGTERMPORT
	else if (cfg->protocol == PROT_CYGTERM)
	    dlg_editbox_get(ctrl, dlg, cfg->cygcmd, lenof(cfg->cygcmd));
#endif
	else
	    dlg_editbox_get(ctrl, dlg, cfg->host, lenof(cfg->host));
    }
}

static void config_port_handler(union control *ctrl, void *dlg,
				void *data, int event)
{
    Config *cfg = (Config *)data;
    char buf[80];

    /*
     * This function works similarly to the standard edit box handler,
     * only it has to choose the control's label and text from two
     * different places depending on the protocol.
     */
    if (event == EVENT_REFRESH) {
	if (cfg->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, "Скорость");
	    sprintf(buf, "%d", cfg->serspeed);
#ifdef CYGTERMPORT
	} else if (cfg->protocol == PROT_CYGTERM) {
	    dlg_label_change(ctrl, dlg, "Порт");
	    strcpy(buf, "-");
#endif
	} else {
	    dlg_label_change(ctrl, dlg, PORT_BOX_TITLE);
	    if (cfg->port != 0)
		sprintf(buf, "%d", cfg->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);
#ifdef CYGTERMPORT
	else if (cfg->protocol == PROT_CYGTERM)
	    ;
#endif
	else
	    cfg->port = atoi(buf);
    }
}

struct hostport {
    union control *host, *port;
};

/*
 * We export this function so that platform-specific config
 * routines can use it to conveniently identify the protocol radio
 * buttons in order to add to them.
 */
void config_protocolbuttons_handler(union control *ctrl, void *dlg,
				    void *data, int event)
{
    int button;
    Config *cfg = (Config *)data;
    struct hostport *hp = (struct hostport *)ctrl->radio.context.p;

    /*
     * This function works just like the standard radio-button
     * handler, except that it also has to change the setting of
     * the port box, and refresh both host and port boxes when. We
     * expect the context parameter to point at a hostport
     * structure giving the `union control's for both.
     */
    if (event == EVENT_REFRESH) {
	for (button = 0; button < ctrl->radio.nbuttons; button++)
	    if (cfg->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;
	button = dlg_radiobutton_get(ctrl, dlg);
	assert(button >= 0 && button < ctrl->radio.nbuttons);
	cfg->protocol = ctrl->radio.buttondata[button].i;
	if (oldproto != cfg->protocol) {
	    Backend *ob = backend_from_proto(oldproto);
	    Backend *nb = backend_from_proto(cfg->protocol);
	    assert(ob);
	    assert(nb);
	    /* Iff the user hasn't changed the port from the old protocol's
	     * default, update it with the new protocol's default.
	     * (This includes a "default" of 0, implying that there is no
	     * sensible default for that protocol; in this case it's
	     * displayed as a blank.)
	     * This helps with the common case of tabbing through the
	     * 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;
	}
	dlg_refresh(hp->host, dlg);
	dlg_refresh(hp->port, dlg);
    }
}

static void loggingbuttons_handler(union control *ctrl, void *dlg,
				   void *data, int event)
{
    int button;
    Config *cfg = (Config *)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) {
        for (button = 0; button < ctrl->radio.nbuttons; button++)
            if (cfg->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);
    } 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;
    }
}

static void numeric_keypad_handler(union control *ctrl, void *dlg,
				   void *data, int event)
{
    int button;
    Config *cfg = (Config *)data;
    /*
     * This function works much like the standard radio button
     * handler, but it has to handle two fields in Config.
     */
    if (event == EVENT_REFRESH) {
	if (cfg->nethack_keypad)
	    button = 2;
	else if (cfg->app_keypad)
	    button = 1;
	else
	    button = 0;
	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);
	if (button == 2) {
	    cfg->app_keypad = FALSE;
	    cfg->nethack_keypad = TRUE;
	} else {
	    cfg->app_keypad = (button != 0);
	    cfg->nethack_keypad = FALSE;
	}
    }
}

static void cipherlist_handler(union control *ctrl, void *dlg,
			       void *data, int event)
{
    Config *cfg = (Config *)data;
    if (event == EVENT_REFRESH) {
	int i;

	static const struct { char *s; int c; } ciphers[] = {
	    { "3DES",			CIPHER_3DES },
	    { "Blowfish",		CIPHER_BLOWFISH },
	    { "DES",			CIPHER_DES },
	    { "AES (только SSH-2)",	CIPHER_AES },
	    { "Arcfour (только SSH-2)",	CIPHER_ARCFOUR },
	    { "-- предупреждать о слабом шифре --",	CIPHER_WARN }
	};

	/* Set up the "selected ciphers" box. */
	/* (cipherlist assumed to contain all ciphers) */
	dlg_update_start(ctrl, dlg);
	dlg_listbox_clear(ctrl, dlg);
	for (i = 0; i < CIPHER_MAX; i++) {
	    int c = cfg->ssh_cipherlist[i];
	    int j;
	    char *cstr = NULL;
	    for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
		if (ciphers[j].c == c) {
		    cstr = ciphers[j].s;
		    break;
		}
	    }
	    dlg_listbox_addwithid(ctrl, dlg, cstr, c);
	}
	dlg_update_done(ctrl, dlg);

    } else if (event == EVENT_VALCHANGE) {
	int i;

	/* Update array to match the list box. */
	for (i=0; i < CIPHER_MAX; i++)
	    cfg->ssh_cipherlist[i] = dlg_listbox_getid(ctrl, dlg, i);

    }
}

#ifndef NO_GSSAPI
static void gsslist_handler(union control *ctrl, void *dlg,
			    void *data, int event)
{
    Config *cfg = (Config *)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];
	    assert(id >= 0 && id < ngsslibs);
	    dlg_listbox_addwithid(ctrl, dlg, gsslibnames[id], id);
	}
	dlg_update_done(ctrl, dlg);

    } else if (event == EVENT_VALCHANGE) {
	int i;

	/* Update array to match the list box. */
	for (i=0; i < ngsslibs; i++)
	    cfg->ssh_gsslist[i] = dlg_listbox_getid(ctrl, dlg, i);
    }
}
#endif

static void kexlist_handler(union control *ctrl, void *dlg,
			    void *data, int event)
{
    Config *cfg = (Config *)data;
    if (event == EVENT_REFRESH) {
	int i;

	static const struct { char *s; int k; } kexes[] = {
	    { "Diffie-Hellman group 1",		KEX_DHGROUP1 },
	    { "Diffie-Hellman group 14",	KEX_DHGROUP14 },
	    { "Diffie-Hellman group exchange",	KEX_DHGEX },
	    { "RSA-based key exchange", 	KEX_RSA },
	    { "-- предупреждать о слабом алгоритме --",		KEX_WARN }
	};

	/* Set up the "kex preference" box. */
	/* (kexlist assumed to contain all algorithms) */
	dlg_update_start(ctrl, dlg);
	dlg_listbox_clear(ctrl, dlg);
	for (i = 0; i < KEX_MAX; i++) {
	    int k = cfg->ssh_kexlist[i];
	    int j;
	    char *kstr = NULL;
	    for (j = 0; j < (sizeof kexes) / (sizeof kexes[0]); j++) {
		if (kexes[j].k == k) {
		    kstr = kexes[j].s;
		    break;
		}
	    }
	    dlg_listbox_addwithid(ctrl, dlg, kstr, k);
	}
	dlg_update_done(ctrl, dlg);

    } else if (event == EVENT_VALCHANGE) {
	int i;

	/* Update array to match the list box. */
	for (i=0; i < KEX_MAX; i++)
	    cfg->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;
    if (event == EVENT_REFRESH) {
	int nprinters, i;
	printer_enum *pe;

	dlg_update_start(ctrl, dlg);
	/*
	 * Some backends may wish to disable the drop-down list on
	 * this edit box. Be prepared for this.
	 */
	if (ctrl->editbox.has_list) {
	    dlg_listbox_clear(ctrl, dlg);
	    dlg_listbox_add(ctrl, dlg, PRINTER_DISABLED_STRING);
	    pe = printer_start_enum(&nprinters);
	    for (i = 0; i < nprinters; i++)
		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));
	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';
    }
}

static void codepage_handler(union control *ctrl, void *dlg,
			     void *data, int event)
{
    Config *cfg = (Config *)data;
    if (event == EVENT_REFRESH) {
	int i;
	const char *cp, *thiscp;
	dlg_update_start(ctrl, dlg);
	thiscp = cp_name(decode_codepage(cfg->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);
	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)));
    }
}

static void sshbug_handler(union control *ctrl, void *dlg,
			   void *data, int event)
{
    if (event == EVENT_REFRESH) {
	dlg_update_start(ctrl, dlg);
	dlg_listbox_clear(ctrl, dlg);
	dlg_listbox_addwithid(ctrl, dlg, "Авто", AUTO);
	dlg_listbox_addwithid(ctrl, dlg, "Выкл", FORCE_OFF);
	dlg_listbox_addwithid(ctrl, dlg, "Вкл", FORCE_ON);
	switch (*(int *)ATOFFSET(data, 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;
	}
	dlg_update_done(ctrl, dlg);
    } else if (event == EVENT_SELCHANGE) {
	int i = dlg_listbox_index(ctrl, dlg);
	if (i < 0)
	    i = AUTO;
	else
	    i = dlg_listbox_getid(ctrl, dlg, i);
	*(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
    }
}

#ifdef PERSOPORT
int dlg_listbox_get(union control *ctrl, void *dlg, int index, char * pstr, int maxcount) ;
int dlg_listbox_gettext(union control *ctrl, void *dlg, int index, char * pstr, int maxcount) ;
void InitFolderList( void ) ;
void SaveFolderList( void ) ;
int AddStringList( char **list, char *str ) ;
void DelFolderFromList( char * name ) ;
void UpFolderInList( char * name ) ;
int IsFolderExist( const char * name ) ;
char *  SetSessPath( const char * dec ) ;
void CreateFolderInPath( const char * d ) ;

static void sessionsaver_handler(union control *ctrl, void *dlg, void *data, int event) ;
void GetSessionFolderName( const char * session, char * folder ) ;
void CleanFolderName( char * folder ) ;
int GetSessionField( const char * session_in, const char * folder, const char * field, char * result ) ;
char *stristr (const char *meule_de_foin, const char *aiguille) ;
void RunSession( HWND hwnd, const char * folder_in, char * session_in ) ;

extern int ConfigBoxHeight ;
extern char ** FolderList ;

static char CurrentFolder[1024]="Default" ;
union control * ctrlSessionList = NULL ;
union control * ctrlSessionEdit = NULL ;
union control * ctrlFolderList = NULL ;

int get_param( const char * val ) ;
#ifndef SAVEMODE_DIR
#define SAVEMODE_DIR 2
#endif

void SetInitCurrentFolder( const char * name ) { if( IsFolderExist( name ) ) strcpy( CurrentFolder, name ) ; }

static void folder_handler(union control *ctrl, void *dlg,
			   void *data, int event)
{
	int inc = 1 ;
	int pfold = 0 ;
	char buffer[1024] ;
	
	Config *cfg = (Config *)data ;
	ctrlFolderList = ctrl ;

    if (event == EVENT_REFRESH) {
		dlg_update_start(ctrl, dlg);
		dlg_listbox_clear(ctrl, dlg);
		
		dlg_listbox_addwithid(ctrl, dlg, "Default", 0 ) ;

		while( FolderList[inc] != NULL ) {
			if( !strcmp( CurrentFolder, FolderList[inc] ) ) pfold=inc ;
			if( strlen(FolderList[inc]) > 0 )
				dlg_listbox_addwithid(ctrl, dlg, FolderList[inc], inc ) ;
			inc++;
			}		
		
		if( inc == 1 ) {
			dlg_listbox_select(ctrl, dlg, 0) ;
			}
		else {
			dlg_listbox_select(ctrl, dlg, pfold) ;
			}
		
		dlg_update_done(ctrl, dlg);
    } 
	else if (event == EVENT_SELCHANGE) {
		int i = dlg_listbox_index(ctrl, dlg);
		dlg_listbox_get(ctrl, dlg, i, buffer, 1024) ;
		strcpy( cfg->folder, buffer ) ;
		strcpy( CurrentFolder, buffer ) ;
		
		if (i < 0)
			i = AUTO;
		else
			i = dlg_listbox_getid(ctrl, dlg, i);
		*(int *)ATOFFSET(data, ctrl->listbox.context.i) = i;
		
		dlg_editbox_get( ctrlSessionEdit, dlg, buffer, 1024 ) ;
		if( !strcmp( buffer, "" ) ) 
			sessionsaver_handler( ctrlSessionList, dlg, data, EVENT_REFRESH ) ;
		}
	else if (event == EVENT_VALCHANGE) {
		int i = dlg_listbox_index( ctrl, dlg ) ;
		dlg_listbox_get(ctrl, dlg, i, buffer, 1024) ;
		
		strcpy( cfg->folder, buffer ) ;
		strcpy( CurrentFolder, buffer ) ;
		
/*
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)));
    }
*/
		}	 
	}
#endif

#define SAVEDSESSION_LEN 2048

struct sessionsaver_data {
#ifdef PERSOPORT
    union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton, *createbutton, *delfolderbutton, *arrangebutton ;
	union control *folderlist ;
#else
    union control *editbox, *listbox, *loadbutton, *savebutton, *delbutton;
#endif
	union control *okbutton, *cancelbutton;
    struct sesslist sesslist;
    int midsession;
};

#ifdef SCPORT
void *m_label_dlg = NULL;
void *m_cert_dlg = NULL;
void *sc_get_label_dialog() {
  return m_label_dlg;
}
void *m_label_ctrl = NULL;
void *m_cert_ctrl = NULL;
void *sc_get_label_ctrl() {
  return m_label_ctrl;
}

void sc_cert_handler(union control *ctrl, void *dlg, void *data, int event);
void sc_tokenlabel_handler(union control *ctrl, void *dlg, void *data, int event ) {
  Config *cfg = (Config *)data;
  m_label_dlg = dlg;
  m_label_ctrl = ctrl;
  
  if(event == EVENT_REFRESH) {
    dlg_update_start(ctrl, dlg);
    dlg_listbox_clear(ctrl, dlg);
    if(filename_is_null(cfg->pkcs11_libfile)) {
      strcpy(cfg->pkcs11_token_label, "");
      dlg_listbox_add(ctrl, dlg, "<E: SELECT LIBRARY FIRST!>");
    } else {
      int i;
      CK_RV  rv = 0;
      HINSTANCE hLib = LoadLibrary((char *)&cfg->pkcs11_libfile);
      CK_C_GetFunctionList pGFL = (CK_RV (*)(CK_FUNCTION_LIST_PTR_PTR))GetProcAddress(hLib, "C_GetFunctionList");
      if (pGFL == NULL) {
        strcpy(cfg->pkcs11_token_label, "");
        dlg_listbox_add(ctrl, dlg, "<E: WRONG LIBRARY!>");
      } else {
        CK_FUNCTION_LIST_PTR fl  = 0;
        rv = pGFL(&fl);
        if(rv != CKR_OK) {
          strcpy(cfg->pkcs11_token_label, "");
          dlg_listbox_add(ctrl, dlg, "<E: ACCESS TO LIBARY FAILED!>");
        } else {
          unsigned long slot_count = 16;
          CK_SLOT_ID slots[16];
          if((fl->C_Initialize(0) != CKR_OK) || (fl->C_GetSlotList(TRUE, slots, &slot_count) != CKR_OK)) {
            strcpy(cfg->pkcs11_token_label, "");
            dlg_listbox_add(ctrl, dlg, "<E: ACCESS TO LIBARY FAILED!>");
          } else {
            if(slot_count == 0) {
              strcpy(cfg->pkcs11_token_label, "");
              dlg_listbox_add(ctrl, dlg, "<E: NO TOKEN FOUND!>");
            }
            for(i=0; i<slot_count; i++) {
              CK_TOKEN_INFO token_info;
              CK_SLOT_ID slot = 64;
              slot = slots[i];
              fl->C_GetTokenInfo(slot,&token_info);
              {
                char buf[40];
                memset(buf, 0, 40);
                int j;
                strncpy(buf, token_info.label, 30);
                for(j=29;j>0;j--) {
                  if(buf[j] == ' ') {
                    buf[j] = '\0';
                  } else {
                    break;
                  }
                }
                dlg_listbox_add(ctrl, dlg, buf);
              }
            }
          }
          fl->C_Finalize(0);
        }
      }
      FreeLibrary(hLib);
    }
     dlg_editbox_set(ctrl, dlg, cfg->pkcs11_token_label);
    dlg_update_done(ctrl, dlg);
  } else if (event == EVENT_VALCHANGE) {
    char buf[70];
    dlg_editbox_get(ctrl, dlg, buf,
                    sizeof(buf));
    if(strncmp(buf, "<E: ", 4) != 0){
      strcpy(cfg->pkcs11_token_label, buf);
    }
  }
  if(m_cert_dlg != NULL) {
    sc_cert_handler(m_cert_ctrl, m_cert_dlg, data, EVENT_REFRESH);
  }
}

void sc_cert_handler(union control *ctrl, void *dlg, void *data, int event ) {
  Config *cfg = (Config *)data;
  m_cert_dlg = dlg;
  m_cert_ctrl = ctrl;
    
  if(event == EVENT_REFRESH) {
    dlg_update_start(ctrl, dlg);
    dlg_listbox_clear(ctrl, dlg);
    if(cfg->pkcs11_token_label == NULL ||
       strlen(cfg->pkcs11_token_label) == 0) {
      strcpy(cfg->pkcs11_token_label, "");
      dlg_listbox_add(ctrl, dlg, "<E: SELECT TOKEN FIRST!>");
    } else {
      sc_lib *sclib = calloc(sizeof(sc_lib), 1);
      sc_init_library(NULL, 0, sclib, &cfg->pkcs11_libfile);
      if(sclib->m_fl) {
        CK_SESSION_HANDLE session = sc_get_session(NULL, 0, sclib->m_fl, cfg->pkcs11_token_label);
        if(session) {
          char msg[1024] = "";
          sc_cert_list *pcl;
          sc_cert_list *cl = sc_get_cert_list(sclib, session, msg);
          pcl = cl;
          while(pcl != NULL) {
            char p_buf[pcl->cert_attr[0].ulValueLen+1];
            memset(p_buf, 0, pcl->cert_attr[0].ulValueLen+1);
            strncpy(p_buf, pcl->cert_attr[0].pValue, pcl->cert_attr[0].ulValueLen);
            dlg_listbox_add(ctrl, dlg, p_buf);
            pcl = pcl->next;
          }
          sc_free_cert_list(cl);
          sclib->m_fl->C_CloseSession(session);
        }
        sclib->m_fl->C_Finalize(0);
      }
      free(sclib);
    }
    dlg_editbox_set(ctrl, dlg, cfg->pkcs11_cert_label);
    dlg_update_done(ctrl, dlg);
  } else if (event == EVENT_VALCHANGE) {
    char buf[70];
    dlg_editbox_get(ctrl, dlg, buf, sizeof(buf));
    if(strncmp(buf, "<E: ", 4) != 0) {
      strcpy(cfg->pkcs11_cert_label, buf);
    }
  }
}
#endif

/* 
 * Helper function to load the session selected in the list box, if
 * any, as this is done in more than one place below. Returns 0 for
 * failure.
 */
static int load_selected_session(struct sessionsaver_data *ssd,
				 char *savedsession,
				 void *dlg, Config *cfg, int *maybe_launch)
{
    int i = dlg_listbox_index(ssd->listbox, dlg);
#ifdef PERSOPORT
	{
	char sessionname[1024] ;
	int j;
	dlg_listbox_gettext(ctrlSessionList, dlg, i, sessionname, 1024 ) ;
	for( j=0; j<ssd->sesslist.nsessions; j++ ){
		if( !strcmp( ssd->sesslist.sessions[j], sessionname ) ) i = j ;
		}
	if( (get_param("INIFILE")==2/*SAVEMODE_DIR*/) && get_param("DIRECTORYBROWSE")
		&& (sessionname[0]==' ')&&(sessionname[1]=='[')&&(sessionname[strlen(sessionname)-1]==']') ) {
		sessionname[strlen(sessionname)-1]='\0';

		strcpy( CurrentFolder, SetSessPath( sessionname+2 ) ) ;
		if( strlen(CurrentFolder) == 0 ) strcpy( CurrentFolder, "Default" ) ;
		strcpy( cfg->folder, CurrentFolder ) ;

		savedsession[0]='\0';
		get_sesslist(&ssd->sesslist, FALSE);
		get_sesslist(&ssd->sesslist, TRUE);
		dlg_refresh(ssd->listbox, dlg);
		sessionsaver_handler( ctrlSessionList, dlg, cfg, EVENT_REFRESH ) ;
		return 0 ;
		}
	}
#endif
    int isdef;
    if (i < 0) {
	dlg_beep(dlg);
	return 0;
    }
    isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
    load_settings(ssd->sesslist.sessions[i], cfg);
#ifdef PERSOPORT
	strcpy( CurrentFolder, "Default" ) ;
	if( cfg->folder )
	if( strlen(cfg->folder)>0 ) {
		strcpy( CurrentFolder, cfg->folder ) ;
		AddStringList( FolderList, cfg->folder ) ;
		}
#endif
    if (!isdef) {
	strncpy(savedsession, ssd->sesslist.sessions[i],
		SAVEDSESSION_LEN);
	savedsession[SAVEDSESSION_LEN-1] = '\0';
	if (maybe_launch)
	    *maybe_launch = TRUE;
    } else {
	savedsession[0] = '\0';
	if (maybe_launch)
	    *maybe_launch = FALSE;
    }
    dlg_refresh(NULL, dlg);
    /* Restore the selection, which might have been clobbered by
     * changing the value of the edit box. */
    dlg_listbox_select(ssd->listbox, dlg, i);
    return 1;
}

static void sessionsaver_handler(union control *ctrl, void *dlg,
				 void *data, int event)
{
    Config *cfg = (Config *)data;
    struct sessionsaver_data *ssd =
	(struct sessionsaver_data *)ctrl->generic.context.p;
    char *savedsession;

    /*
     * 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).
     */
    if (!ssd->editbox) {
        savedsession = NULL;
    } else if (!dlg_get_privdata(ssd->editbox, dlg)) {
	savedsession = (char *)
	    dlg_alloc_privdata(ssd->editbox, dlg, SAVEDSESSION_LEN);
	savedsession[0] = '\0';
    } else {
	savedsession = dlg_get_privdata(ssd->editbox, dlg);
    }

    if (event == EVENT_REFRESH) {
	if (ctrl == ssd->editbox) {
#ifdef PERSOPORT
	    ctrlSessionEdit = ctrl ;
	    dlg_editbox_set(ctrl, dlg, savedsession);
#else
	    dlg_editbox_set(ctrl, dlg, savedsession);
#endif
	} else if (ctrl == ssd->listbox) {
	    int i;
	    dlg_update_start(ctrl, dlg);
	    dlg_listbox_clear(ctrl, dlg);
#ifdef PERSOPORT
		ctrlSessionList = ctrl ;
		for (i = 0; i < ssd->sesslist.nsessions; i++) {
			char folder[1024] ;
			char host[1024] ;
			strcpy( folder, "" ) ;
			GetSessionFolderName( ssd->sesslist.sessions[i], folder ) ;
			if( (get_param("INIFILE")==SAVEMODE_DIR) && get_param("DIRECTORYBROWSE") ) CleanFolderName( folder ) ;
			strcpy( host, "" ) ;
			GetSessionField( ssd->sesslist.sessions[i], folder, "HostName", host ) ;
/*
			if(!strcmp( savedsession, "" )) {
				if( (!strcmp( CurrentFolder, "Default" )) || (!strcmp(CurrentFolder,folder)) ) {
					dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]) ;
					}
				}
			else {
				if( ( strlen(savedsession)<=1 )
					|| (stristr(ssd->sesslist.sessions[i],savedsession)!=NULL) )
					dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
				}
*/			if( get_param("PUTTY") )
				dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
			else if( !get_param("SESSIONFILTER") ) 
				dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
			else if( (get_param("INIFILE")==SAVEMODE_DIR) && get_param("DIRECTORYBROWSE") )	{
				/*if( (!strcmp( savedsession, "" )) 
				|| ( strlen(savedsession)<=1 )
				|| (stristr(host,savedsession)!=NULL)
				|| (stristr(ssd->sesslist.sessions[i],savedsession)!=NULL) )*/
//if( strstr(ssd->sesslist.sessions[i],"CMD")) MessageBox(NULL,ssd->sesslist.sessions[i],folder,MB_OK);
				if (!strcmp( savedsession, "" )) {
					if( (!strcmp(CurrentFolder,folder))
						|| (!strcmp("",folder))
						|| ( strstr(ssd->sesslist.sessions[i]," [")==ssd->sesslist.sessions[i] )
						)
						dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
					}
				else {
					if( ( ((!strcmp(CurrentFolder,folder))||(!strcmp("",folder))) && (stristr(ssd->sesslist.sessions[i],savedsession)!=NULL) )
						|| ( strstr(ssd->sesslist.sessions[i]," [")==ssd->sesslist.sessions[i] )
						)
						dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
					}
				}
			else 
			if( (!strcmp( CurrentFolder, "Default" )) || (!strcmp(CurrentFolder,folder)) ) {
				if( (!strcmp( savedsession, "" )) 
				|| ( strlen(savedsession)<=1 )
				|| (stristr(host,savedsession)!=NULL)
				|| (stristr(ssd->sesslist.sessions[i],savedsession)!=NULL) )
					dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]) ;
				}
				
			}
#else 
	    for (i = 0; i < ssd->sesslist.nsessions; i++)
		dlg_listbox_add(ctrl, dlg, ssd->sesslist.sessions[i]);
#endif
	    dlg_update_done(ctrl, dlg);
	}
    } else if (event == EVENT_VALCHANGE) {
        int top, bottom, halfway, i;
	if (ctrl == ssd->editbox) {
	    dlg_editbox_get(ctrl, dlg, savedsession,
			    SAVEDSESSION_LEN);
#ifdef PERSOPORT
	sessionsaver_handler( ctrlSessionList, dlg, data, EVENT_REFRESH ) ;
#endif
	    top = ssd->sesslist.nsessions;
	    bottom = -1;
	    while (top-bottom > 1) {
	        halfway = (top+bottom)/2;
	        i = strcmp(savedsession, ssd->sesslist.sessions[halfway]);
	        if (i <= 0 ) {
		    top = halfway;
	        } else {
		    bottom = halfway;
	        }
	    }
	    if (top == ssd->sesslist.nsessions) {
	        top -= 1;
	    }
	    dlg_listbox_select(ssd->listbox, dlg, top);
	}
    } else if (event == EVENT_ACTION) {
	int mbl = FALSE;
	if (!ssd->midsession &&
	    (ctrl == ssd->listbox ||
	     (ssd->loadbutton && ctrl == ssd->loadbutton))) {
	    /*
	     * The user has double-clicked a session, or hit Load.
	     * We must load the selected session, and then
	     * terminate the configuration dialog _if_ there was a
	     * 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 (defined IMAGEPORT) && (!defined FDJ)
		if( get_param("BACKGROUNDIMAGE")&&(strlen(savedsession)>0)
			&&(cfg->bg_type>0) ) { 	// bug de l'affichage de la background image en PuTTY 0.61
			RunSession( hwnd, CurrentFolder, savedsession ) ;	// On charge avec -load
			dlg_end(dlg, 0) ;
			}
		else
#endif
		dlg_end(dlg, 1);       /* it's all over, and succeeded */
	    }
#ifdef PERSOPORT
		if( get_param("DIRECTORYBROWSE") ) {
			strcpy( CurrentFolder, cfg->folder );
			CleanFolderName( CurrentFolder );
			}
#endif
	} else if (ctrl == ssd->savebutton) {
	    int isdef = !strcmp(savedsession, "Default Settings");
	    if (!savedsession[0]) {
		int i = dlg_listbox_index(ssd->listbox, dlg);
		if (i < 0) {
		    dlg_beep(dlg);
		    return;
		}
		isdef = !strcmp(ssd->sesslist.sessions[i], "Default Settings");
		if (!isdef) {
		    strncpy(savedsession, ssd->sesslist.sessions[i],
			    SAVEDSESSION_LEN);
		    savedsession[SAVEDSESSION_LEN-1] = '\0';
		} else {
		    savedsession[0] = '\0';
		}
	    }
            {
#ifdef PERSOPORT
				if( !get_param("DIRECTORYBROWSE") ) 
					strcpy( cfg->folder, CurrentFolder );
#endif
                char *errmsg = save_settings(savedsession, cfg);
                if (errmsg) {
                    dlg_error_msg(dlg, errmsg);
                    sfree(errmsg);
                }
            }
	    get_sesslist(&ssd->sesslist, FALSE);
	    get_sesslist(&ssd->sesslist, TRUE);
	    dlg_refresh(ssd->editbox, dlg);
	    dlg_refresh(ssd->listbox, dlg);
	} else if (!ssd->midsession &&
		   ssd->delbutton && ctrl == ssd->delbutton) {
	    int i = dlg_listbox_index(ssd->listbox, dlg);
#ifdef PERSOPORT
		{ // Pour recuperer le bon index de la session a supprimer quand il y le filtre des sessions
		char sessionname[1024] ;
		int j;
		dlg_listbox_gettext(ctrlSessionList, dlg, i, sessionname, 1024 ) ;
		for( j=0; j<ssd->sesslist.nsessions; j++ ){
			if( !strcmp( ssd->sesslist.sessions[j], sessionname ) ) i = j ;
			}
		}
#endif
	    if (i <= 0) {
		dlg_beep(dlg);
	    } else {
		del_settings(ssd->sesslist.sessions[i]);
		get_sesslist(&ssd->sesslist, FALSE);
		get_sesslist(&ssd->sesslist, TRUE);
		dlg_refresh(ssd->listbox, dlg);
	    }
	} else if (ctrl == ssd->okbutton) {
            if (ssd->midsession) {
                /* In a mid-session Change Settings, Apply is always OK. */
		dlg_end(dlg, 1);
                return;
            }
	    /*
	     * Annoying special case. If the `Open' button is
	     * pressed while no host name is currently set, _and_
	     * the session list previously had the focus, _and_
	     * there was a session selected in that which had a
	     * valid host name in it, then load it and go.
	     */
	    if (dlg_last_focused(ctrl, dlg) == ssd->listbox &&
		!cfg_launchable(cfg)) {
		Config cfg2;
		int mbl = FALSE;
		if (!load_selected_session(ssd, savedsession, dlg,
					   &cfg2, &mbl)) {
		    dlg_beep(dlg);
		    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;
		    dlg_end(dlg, 1);
		} else
		    dlg_beep(dlg);
                return;
	    }

	    /*
	     * Otherwise, do the normal thing: if we have a valid
	     * session, get going.
	     */
	    if (cfg_launchable(cfg)) {
#if (defined IMAGEPORT) && (!defined FDJ)
		if( get_param("BACKGROUNDIMAGE")&&(strlen(savedsession)>0)
			&&(cfg->bg_type>0) ) { 	// bug de l'affichage de la background image en PuTTY 0.61
			RunSession( hwnd, CurrentFolder, savedsession ) ;	// On charge avec -load
			dlg_end(dlg, 0) ;
			}
		else
#endif
		dlg_end(dlg, 1);
	    } else
		dlg_beep(dlg);
	} else if (ctrl == ssd->cancelbutton) {
	    dlg_end(dlg, 0);
	}
#ifdef PERSOPORT
	else if (!ssd->midsession && // creer un nouveau folder
		   ssd->createbutton && ctrl == ssd->createbutton) {
			if( strlen(savedsession) > 0 ) {
				if( !get_param("DIRECTORYBROWSE") ) {
					InitFolderList() ;
					AddStringList( FolderList, savedsession ) ;
					SaveFolderList();
					folder_handler( ctrlFolderList, dlg, data, EVENT_REFRESH ) ;
					savedsession[0] = '\0';
					dlg_editbox_set( ctrlSessionEdit, dlg, "" ) ;
					}
				else {
					CreateFolderInPath( savedsession ) ;
					savedsession[0] = '\0';
					dlg_editbox_set( ctrlSessionEdit, dlg, "" ) ;
					get_sesslist(&ssd->sesslist, FALSE);
					get_sesslist(&ssd->sesslist, TRUE);
					dlg_refresh(ssd->listbox, dlg);
					//sessionsaver_handler( ctrlSessionList, dlg, cfg, EVENT_REFRESH ) ;
					}
				}
		   }
	else if (!ssd->midsession && // supprimer un folder
		   ssd->delfolderbutton && ctrl == ssd->delfolderbutton) {
		   if( strlen(CurrentFolder) > 0 ) {
				if( !strcmp( CurrentFolder, "Default" ) )
					MessageBox( NULL, "Не допускается удаление корневой папки", "Ошибка при удалении", MB_OK|MB_ICONERROR );
				else {
					DelFolderFromList( CurrentFolder ) ;
					SaveFolderList() ;
					InitFolderList() ;
					strcpy( CurrentFolder,"Default" ) ;
					folder_handler( ctrlFolderList, dlg, data, EVENT_REFRESH ) ;
					savedsession[0] = '\0';
					dlg_editbox_set( ctrlSessionEdit, dlg, "" ) ;
					//sessionsaver_handler( ctrlSessionList, dlg, data, EVENT_REFRESH ) ;
					}
				}
		   }
	else if (!ssd->midsession && // Reordonner les folders
		   ssd->arrangebutton && ctrl == ssd->arrangebutton) {
		   if( strlen(CurrentFolder) > 0 ) 
			if( strcmp( CurrentFolder, "Default" ) ) {
				UpFolderInList( CurrentFolder ) ;
				SaveFolderList() ;
				InitFolderList() ;
				folder_handler( ctrlFolderList, dlg, data, EVENT_REFRESH ) ;
				savedsession[0] = '\0';
				dlg_editbox_set( ctrlSessionEdit, dlg, "" ) ;
				}
		   }
#endif
    }
}

struct charclass_data {
    union control *listbox, *editbox, *button;
};

static void charclass_handler(union control *ctrl, void *dlg,
			      void *data, int event)
{
    Config *cfg = (Config *)data;
    struct charclass_data *ccd =
	(struct charclass_data *)ctrl->generic.context.p;

    if (event == EVENT_REFRESH) {
	if (ctrl == ccd->listbox) {
	    int i;
	    dlg_update_start(ctrl, dlg);
	    dlg_listbox_clear(ctrl, 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]);
		dlg_listbox_add(ctrl, dlg, str);
	    }
	    dlg_update_done(ctrl, dlg);
	}
    } else if (event == EVENT_ACTION) {
	if (ctrl == ccd->button) {
	    char str[100];
	    int i, n;
	    dlg_editbox_get(ccd->editbox, dlg, str, sizeof(str));
	    n = atoi(str);
	    for (i = 0; i < 128; i++) {
		if (dlg_listbox_issel(ccd->listbox, dlg, i))
		    cfg->wordness[i] = n;
	    }
	    dlg_refresh(ccd->listbox, dlg);
	}
    }
}

struct colour_data {
    union control *listbox, *redit, *gedit, *bedit, *button;
};

static const char *const colours[] = {
    "Цвет текста по умолчанию", "Полужирный цвет текста по умолчанию",
    "Цвет фона по умолчанию", "Полужирный цвет фона по умолчанию",
    "Текст курсора", "Цвет курсора",
    "ANSI Чёрный", "ANSI Чёрный полужирный",
    "ANSI Красный", "ANSI Красный полужирный",
    "ANSI Зелёный", "ANSI Зелёный полужирный",
    "ANSI Жёлтый", "ANSI Жёлтый полужирный",
    "ANSI Синий", "ANSI Синий полужирный",
    "ANSI Пурпурный", "ANSI Пурпурный полужирный",
    "ANSI Циан", "ANSI Циан полужирный",
    "ANSI Белый", "ANSI Белый полужирный"
};

static void colour_handler(union control *ctrl, void *dlg,
			    void *data, int event)
{
    Config *cfg = (Config *)data;
    struct colour_data *cd =
	(struct colour_data *)ctrl->generic.context.p;
    int update = FALSE, clear = FALSE, r, g, b;

    if (event == EVENT_REFRESH) {
	if (ctrl == cd->listbox) {
	    int i;
	    dlg_update_start(ctrl, dlg);
	    dlg_listbox_clear(ctrl, dlg);
	    for (i = 0; i < lenof(colours); i++)
		dlg_listbox_add(ctrl, dlg, colours[i]);
	    dlg_update_done(ctrl, dlg);
	    clear = TRUE;
	    update = TRUE;
	}
    } else if (event == EVENT_SELCHANGE) {
	if (ctrl == cd->listbox) {
	    /* The user has selected a colour. Update the RGB text. */
	    int i = dlg_listbox_index(ctrl, dlg);
	    if (i < 0) {
		clear = TRUE;
	    } else {
		clear = FALSE;
		r = cfg->colours[i][0];
		g = cfg->colours[i][1];
		b = cfg->colours[i][2];
	    }
	    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];
	    int i, cval;

	    dlg_editbox_get(ctrl, dlg, buf, lenof(buf));
	    cval = atoi(buf);
	    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;
		else if (ctrl == cd->gedit)
		    cfg->colours[i][1] = cval;
		else if (ctrl == cd->bedit)
		    cfg->colours[i][2] = cval;
	    }
	}
    } else if (event == EVENT_ACTION) {
	if (ctrl == cd->button) {
	    int i = dlg_listbox_index(cd->listbox, dlg);
	    if (i < 0) {
		dlg_beep(dlg);
		return;
	    }
	    /*
	     * Start a colour selector, which will send us an
	     * EVENT_CALLBACK when it's finished and allow us to
	     * pick up the results.
	     */
	    dlg_coloursel_start(ctrl, dlg,
				cfg->colours[i][0],
				cfg->colours[i][1],
				cfg->colours[i][2]);
	}
    } else if (event == EVENT_CALLBACK) {
	if (ctrl == cd->button) {
	    int i = dlg_listbox_index(cd->listbox, dlg);
	    /*
	     * Collect the results of the colour selector. Will
	     * return nonzero on success, or zero if the colour
	     * 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;
		clear = FALSE;
		update = TRUE;
	    }
	}
    }

    if (update) {
	if (clear) {
	    dlg_editbox_set(cd->redit, dlg, "");
	    dlg_editbox_set(cd->gedit, dlg, "");
	    dlg_editbox_set(cd->bedit, dlg, "");
	} else {
	    char buf[40];
	    sprintf(buf, "%d", r); dlg_editbox_set(cd->redit, dlg, buf);
	    sprintf(buf, "%d", g); dlg_editbox_set(cd->gedit, dlg, buf);
	    sprintf(buf, "%d", b); dlg_editbox_set(cd->bedit, dlg, buf);
	}
    }
}

struct ttymodes_data {
    union control *modelist, *valradio, *valbox;
    union control *addbutton, *rembutton, *listbox;
};

static void ttymodes_handler(union control *ctrl, void *dlg,
			     void *data, int event)
{
    Config *cfg = (Config *)data;
    struct ttymodes_data *td =
	(struct ttymodes_data *)ctrl->generic.context.p;

    if (event == EVENT_REFRESH) {
	if (ctrl == td->listbox) {
	    char *p = cfg->ttymodes;
	    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') ? "(авто)" :
				       p+tabpos+2);
		dlg_listbox_add(ctrl, dlg, disp);
		p += strlen(p) + 1;
		sfree(disp);
	    }
	    dlg_update_done(ctrl, dlg);
	} else if (ctrl == td->modelist) {
	    int i;
	    dlg_update_start(ctrl, dlg);
	    dlg_listbox_clear(ctrl, dlg);
	    for (i = 0; ttymodes[i]; i++)
		dlg_listbox_add(ctrl, dlg, ttymodes[i]);
	    dlg_listbox_select(ctrl, dlg, 0); /* *shrug* */
	    dlg_update_done(ctrl, dlg);
	} else if (ctrl == td->valradio) {
	    dlg_radiobutton_set(ctrl, dlg, 0);
	}
    } else if (event == EVENT_ACTION) {
	if (ctrl == td->addbutton) {
	    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)];
		/* 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);
		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;
		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);
			}
		    }
		    memmove(p, p+strlen(p)+1, len - (strlen(p)+1));
		    i++;
		    continue;
		}
		len -= strlen(p) + 1;
		p   += strlen(p) + 1;
		i++;
	    }
	    memset(p, 0, lenof(cfg->ttymodes) - len);
	    dlg_refresh(td->listbox, dlg);
	}
    }
}

struct environ_data {
    union control *varbox, *valbox, *addbutton, *rembutton, *listbox;
};

static void environ_handler(union control *ctrl, void *dlg,
			    void *data, int event)
{
    Config *cfg = (Config *)data;
    struct environ_data *ed =
	(struct environ_data *)ctrl->generic.context.p;

    if (event == EVENT_REFRESH) {
	if (ctrl == ed->listbox) {
	    char *p = cfg->environmt;
	    dlg_update_start(ctrl, dlg);
	    dlg_listbox_clear(ctrl, dlg);
	    while (*p) {
		dlg_listbox_add(ctrl, dlg, p);
		p += strlen(p) + 1;
	    }
	    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) {
		dlg_beep(dlg);
		return;
	    }
	    p = str + strlen(str);
	    *p++ = '\t';
	    dlg_editbox_get(ed->valbox, dlg, p, sizeof(str)-1 - (p - str));
	    if (!*p) {
		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, "Окружение переполнено");
	    }
	} else if (ctrl == ed->rembutton) {
	    int i = dlg_listbox_index(ed->listbox, dlg);
	    if (i < 0) {
		dlg_beep(dlg);
	    } else {
		char *p, *q, *str;

		dlg_listbox_del(ed->listbox, dlg, i);
		p = cfg->environmt;
		while (i > 0) {
		    if (!*p)
			goto disaster;
		    while (*p)
			p++;
		    p++;
		    i--;
		}
		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:;
	    }
	}
    }
}

struct portfwd_data {
    union control *addbutton, *rembutton, *listbox;
    union control *sourcebox, *destbox, *direction;
#ifndef NO_IPV6
    union control *addressfamily;
#endif
};

static void portfwd_handler(union control *ctrl, void *dlg,
			    void *data, int event)
{
    Config *cfg = (Config *)data;
    struct portfwd_data *pfd =
	(struct portfwd_data *)ctrl->generic.context.p;

    if (event == EVENT_REFRESH) {
	if (ctrl == pfd->listbox) {
	    char *p = cfg->portfwd;
	    dlg_update_start(ctrl, dlg);
	    dlg_listbox_clear(ctrl, dlg);
	    while (*p) {
		dlg_listbox_add(ctrl, dlg, p);
		p += strlen(p) + 1;
	    }
	    dlg_update_done(ctrl, dlg);
	} else if (ctrl == pfd->direction) {
	    /*
	     * Default is Local.
	     */
	    dlg_radiobutton_set(ctrl, dlg, 0);
#ifndef NO_IPV6
	} else if (ctrl == pfd->addressfamily) {
	    dlg_radiobutton_set(ctrl, dlg, 0);
#endif
	}
    } else if (event == EVENT_ACTION) {
	if (ctrl == pfd->addbutton) {
	    char str[sizeof(cfg->portfwd)];
	    char *p;
	    int i, type;
	    int whichbutton;

	    i = 0;
#ifndef NO_IPV6
	    whichbutton = dlg_radiobutton_get(pfd->addressfamily, dlg);
	    if (whichbutton == 1)
		str[i++] = '4';
	    else if (whichbutton == 2)
		str[i++] = '6';
#endif

	    whichbutton = dlg_radiobutton_get(pfd->direction, dlg);
	    if (whichbutton == 0)
		type = 'L';
	    else if (whichbutton == 1)
		type = 'R';
	    else
		type = 'D';
	    str[i++] = type;

	    dlg_editbox_get(pfd->sourcebox, dlg, str+i, sizeof(str) - i);
	    if (!str[i]) {
		dlg_error_msg(dlg, "Укажите номер порта отправителя");
		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, ':')) {
		    dlg_error_msg(dlg,
				  "Укажите адрес назначения\n"
				  "в формате \"имя.хоста:порт\"");
		    return;
		}
	    } else
		*p = '\0';
	    p = cfg->portfwd;
	    while (*p) {
		if (strcmp(p,str) == 0) {
		    dlg_error_msg(dlg, "Указанная переадресация уже определена");
		    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, "Слишком много переадресаций");
		}
	    }
	} else if (ctrl == pfd->rembutton) {
	    int i = dlg_listbox_index(pfd->listbox, dlg);
	    if (i < 0)
		dlg_beep(dlg);
	    else {
		char *p, *q, *src, *dst;
		char dir;

		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. */
		{
		    static const char *const afs = "A46";
		    char *afp = strchr(afs, *p);
#ifndef NO_IPV6
		    int 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;
		    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 = "";
		}
		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:;
	    }
	}
    }
}

void setup_config_box(struct controlbox *b, int midsession,
		      int protocol, int protcfginfo)
{
    struct controlset *s;
    struct sessionsaver_data *ssd;
    struct charclass_data *ccd;
    struct colour_data *cd;
    struct ttymodes_data *td;
    struct environ_data *ed;
    struct portfwd_data *pfd;
    union control *c;
    char *str;

    ssd = (struct sessionsaver_data *)
	ctrl_alloc(b, sizeof(struct sessionsaver_data));
    memset(ssd, 0, sizeof(*ssd));
    ssd->midsession = midsession;

    /*
     * The standard panel that appears at the bottom of all panels:
     * Open, Cancel, Apply etc.
     */
    s = ctrl_getset(b, "", "", "");
    ctrl_columns(s, 5, 20, 20, 20, 20, 20);
    ssd->okbutton = ctrl_pushbutton(s,
				    (midsession ? "Применить" : "Соединение"),
				    (char)(midsession ? 'a' : 'o'),
				    HELPCTX(no_help),
				    sessionsaver_handler, P(ssd));
    ssd->okbutton->button.isdefault = TRUE;
//#ifdef PERSOPORT @@@@@
//    if( ConfigBoxHeight>7 ) ssd->okbutton->generic.column = 0 ; else 
//#endif
    ssd->okbutton->generic.column = 3;
    ssd->cancelbutton = ctrl_pushbutton(s, "Отмена", 'c', HELPCTX(no_help),
					sessionsaver_handler, P(ssd));
    ssd->cancelbutton->button.iscancel = TRUE;
//#ifdef PERSOPORT @@@@@
//    if( ConfigBoxHeight>7 ) ssd->cancelbutton->generic.column = 0 ; else
//#endif
    ssd->cancelbutton->generic.column = 4;
    /* We carefully don't close the 5-column part, so that platform-
     * specific add-ons can put extra buttons alongside Open and Cancel. */

    /*
     * The Session panel.
     */
    str = dupprintf("Основные настройки сеанса %s", appname);
    ctrl_settitle(b, "Сеанс", str);
    sfree(str);

    if (!midsession) {
	struct hostport *hp = (struct hostport *)
	    ctrl_alloc(b, sizeof(struct hostport));

	s = ctrl_getset(b, "Сеанс", "hostport",
			"Укажите адрес, к которому хотите подключиться");
	ctrl_columns(s, 2, 75, 25);
	c = ctrl_editbox(s, HOST_BOX_TITLE, 'n', 100,
			 HELPCTX(session_hostname),
			 config_host_handler, I(0), I(0));
	c->generic.column = 0;
	hp->host = c;
	c = ctrl_editbox(s, PORT_BOX_TITLE, 'p', 100,
			 HELPCTX(session_hostname),
			 config_port_handler, I(0), I(0));
	c->generic.column = 1;
	hp->port = c;
	ctrl_columns(s, 1, 100);

	if (!backend_from_proto(PROT_SSH)) {
	    ctrl_radiobuttons(s, "Тип соединения:", NO_SHORTCUT, 5,
			      HELPCTX(session_hostname),
			      config_protocolbuttons_handler, P(hp),
			      "Telnet", 't', I(PROT_TELNET),
			      "Raw", 'w', I(PROT_RAW),
			      "Rlogin", 'i', I(PROT_RLOGIN),
			      NULL);
	} else {
	    ctrl_radiobuttons(s, "Тип соединения:", NO_SHORTCUT, 5,
			      HELPCTX(session_hostname),
			      config_protocolbuttons_handler, P(hp),
			      "Telnet", 't', I(PROT_TELNET),
			      "SSH", 's', I(PROT_SSH),
			      "Raw", 'w', I(PROT_RAW),
			      "Rlogin", 'i', I(PROT_RLOGIN),
			      NULL);
	}
    }

    /*
     * The Load/Save panel is available even in mid-session.
     */
    s = ctrl_getset(b, "Сеанс", "savedsessions",
		    midsession ? "Сохранить настройки текущего сеанса" :
		    "Управление сеансами");
    ctrl_columns(s, 2, 75, 25);
    get_sesslist(&ssd->sesslist, TRUE);
    ssd->editbox = ctrl_editbox(s, "Сохранённые сеансы:", 'e', 100,
				HELPCTX(session_saved),
				sessionsaver_handler, P(ssd), P(NULL));
    ssd->editbox->generic.column = 0;
    /* Reset columns so that the buttons are alongside the list, rather
     * than alongside that edit box. */
    ctrl_columns(s, 1, 100);
    ctrl_columns(s, 2, 75, 25);
    ssd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
				HELPCTX(session_saved),
				sessionsaver_handler, P(ssd));
    ssd->listbox->generic.column = 0;
#ifdef PERSOPORT
	ssd->listbox->listbox.height = 13; // = ConfigBoxHeight ;
#else
    ssd->listbox->listbox.height = 7;
#endif
#ifdef CYGTERMPORT
	if( cygterm_get_flag() ) ssd->listbox->listbox.height-- ;
#endif

    if (!midsession) {
	ssd->loadbutton = ctrl_pushbutton(s, "Загрузить", 'l',
					  HELPCTX(session_saved),
					  sessionsaver_handler, P(ssd));
	ssd->loadbutton->generic.column = 1;
    } else {
	/* We can't offer the Load button mid-session, as it would allow the
	 * user to load and subsequently save settings they can't see. (And
	 * also change otherwise immutable settings underfoot; that probably
	 * shouldn't be a problem, but.) */
	ssd->loadbutton = NULL;
    }
    /* "Save" button is permitted mid-session. */
#ifdef PERSOPORT
    if( get_param("INIFILE") == 1 )
	ssd->savebutton = ctrl_pushbutton(s, "Сохранить (f)", 'v', HELPCTX(session_saved), sessionsaver_handler, P(ssd));
    else if( get_param("INIFILE") == 2 )
	ssd->savebutton = ctrl_pushbutton(s, "Сохранить (d)", 'v', HELPCTX(session_saved), sessionsaver_handler, P(ssd));
    else
#endif
    ssd->savebutton = ctrl_pushbutton(s, "Сохранить", 'v',
				      HELPCTX(session_saved),
				      sessionsaver_handler, P(ssd));
    ssd->savebutton->generic.column = 1;
    if (!midsession) {
	ssd->delbutton = ctrl_pushbutton(s, "Удалить", 'd',
					 HELPCTX(session_saved),
					 sessionsaver_handler, P(ssd));
	ssd->delbutton->generic.column = 1;
    } else {
	/* Disable the Delete button mid-session too, for UI consistency. */
	ssd->delbutton = NULL;
    }
#ifdef PERSOPORT
	if( ConfigBoxHeight>7 ) { // On n'affiche les boutons KiTTY que si la taille de la config box le permet
	    
	if (!midsession) { // Bouton de creation d'un folder
	ssd->createbutton = ctrl_pushbutton(s, "Новая папка", '§',
					  HELPCTX(session_saved),
					  sessionsaver_handler, P(ssd));
	ssd->createbutton->generic.column = 1;
	}
	else {
	ssd->createbutton = NULL ;
	}
	
	if( !get_param("DIRECTORYBROWSE" ) ) {
		if (!midsession) { // Bouton de suppression d'un folder
		ssd->delfolderbutton = ctrl_pushbutton(s, "Удалить папку", ']',
					  HELPCTX(session_saved),
					  sessionsaver_handler, P(ssd));
		ssd->delfolderbutton->generic.column = 1;	
		}
		else {
		ssd->delfolderbutton = NULL ;
		}
	}
	
	if( !get_param("DIRECTORYBROWSE" ) ) {
		if ( !midsession ) { // Bouton d'arrange de l'ordre de la liste des folders
		ssd->arrangebutton = ctrl_pushbutton(s, "Уровень выше", '[',
					  HELPCTX(session_saved),
					  sessionsaver_handler, P(ssd));
		ssd->arrangebutton->generic.column = 1;	
		}
		else {
		ssd->arrangebutton = NULL ;
		}
	}
	
	if( !get_param("DIRECTORYBROWSE" ) )
	ctrl_droplist(s, "Папка", 'F', 80,
			  HELPCTX(session_folder),
			  folder_handler, I(offsetof(Config,folder)));
	}
#endif
    ctrl_columns(s, 1, 100);

    s = ctrl_getset(b, "Сеанс", "otheropts", NULL);
    c = ctrl_radiobuttons(s, "Закрывать окно при выходе:", 'x', 4,
			  HELPCTX(session_coe),
			  dlg_stdradiobutton_handler,
			  I(offsetof(Config, close_on_exit)),
			  "Всегда", I(FORCE_ON),
			  "Никогда", I(FORCE_OFF),
			  "Только вручную", I(AUTO), NULL);

    /*
     * The Session/Logging panel.
     */
    ctrl_settitle(b, "Сеанс/Журнал", "Настройки журналирования");

    s = ctrl_getset(b, "Сеанс/Журнал", "main", NULL);
    /*
     * The logging buttons change depending on whether SSH packet
     * logging can sensibly be available.
     */
    {
	char *sshlogname, *sshrawlogname;
	if ((midsession && protocol == PROT_SSH) ||
	    (!midsession && backend_from_proto(PROT_SSH))) {
	    sshlogname = "SSH пакеты";
	    sshrawlogname = "SSH пакеты и raw data";
        } else {
	    sshlogname = NULL;	       /* this will disable both buttons */
	    sshrawlogname = NULL;      /* this will just placate optimisers */
        }
	ctrl_radiobuttons(s, "Журналирование сеанса:", NO_SHORTCUT, 2,
			  HELPCTX(logging_main),
			  loggingbuttons_handler,
			  I(offsetof(Config, logtype)),
			  "Отключено", 't', I(LGTYP_NONE),
			  "Печатаемый вывод", 'p', I(LGTYP_ASCII),
			  "Весь вывод", 'l', I(LGTYP_DEBUG),
			  sshlogname, 's', I(LGTYP_PACKETS),
			  sshrawlogname, 'r', I(LGTYP_SSHRAW),
			  NULL);
    }
    ctrl_filesel(s, "Имя файла журнала:", 'f',
		 NULL, TRUE, "Выберите файл для сохранения журнала сеанса",
		 HELPCTX(logging_filename),
		 dlg_stdfilesel_handler, I(offsetof(Config, logfilename)));
    ctrl_text(s, "(Имя файла может содержать &Y, &M, &D для обозначения текущей даты,"
	      " &T для времени, и &H для имени хоста)",
	      HELPCTX(logging_filename));
#ifdef PERSOPORT
    ctrl_editbox(s, "Метка времени:", '}', 100,
		 HELPCTX(logging_logtimestamp),
		 dlg_stdeditbox_handler, I(offsetof(Config,logtimestamp)),
		 I(sizeof(((Config *)0)->logtimestamp)));
#endif
    ctrl_radiobuttons(s, "Что делать если файл журнала уже существует:", 'e', 1,
		      HELPCTX(logging_exists),
		      dlg_stdradiobutton_handler, I(offsetof(Config,logxfovr)),
		      "Перезаписать", I(LGXF_OVR),
		      "Дописывать новые данные в конец файла", I(LGXF_APN),
		      "Спросить действие пользователя", I(LGXF_ASK), NULL);
    ctrl_checkbox(s, "Время от времени сбрасывать файл журнала", 'u',
		 HELPCTX(logging_flush),
		 dlg_stdcheckbox_handler, I(offsetof(Config,logflush)));

    if ((midsession && protocol == PROT_SSH) ||
	(!midsession && backend_from_proto(PROT_SSH))) {
	s = ctrl_getset(b, "Сеанс/Журнал", "ssh",
			"Настройки журналирования SSH пакетов");
	ctrl_checkbox(s, "Пропускать поля ввода пароля", 'k',
		      HELPCTX(logging_ssh_omit_password),
		      dlg_stdcheckbox_handler, I(offsetof(Config,logomitpass)));
	ctrl_checkbox(s, "Пропускать данные сеанса", 'd',
		      HELPCTX(logging_ssh_omit_data),
		      dlg_stdcheckbox_handler, I(offsetof(Config,logomitdata)));
    }

    /*
     * The Terminal panel.
     */
    ctrl_settitle(b, "Терминал", "Настройки эмулятора терминала");

    s = ctrl_getset(b, "Терминал", "general", "Установка различных опций терминала");
    ctrl_checkbox(s, "Перенос строк по умолчанию", 'w',
		  HELPCTX(terminal_autowrap),
		  dlg_stdcheckbox_handler, I(offsetof(Config,wrap_mode)));
    ctrl_checkbox(s, "DEC Origin Mode по умолчанию", 'd',
		  HELPCTX(terminal_decom),
		  dlg_stdcheckbox_handler, I(offsetof(Config,dec_om)));
    ctrl_checkbox(s, "Неявный CR каждому LF", 'r',
		  HELPCTX(terminal_lfhascr),
		  dlg_stdcheckbox_handler, I(offsetof(Config,lfhascr)));
    ctrl_checkbox(s, "Неявный LF каждому CR", 'f',
		  HELPCTX(terminal_crhaslf),
		  dlg_stdcheckbox_handler, I(offsetof(Config,crhaslf)));
    ctrl_checkbox(s, "Использовать цвет фона для очистки экрана", 'e',
		  HELPCTX(terminal_bce),
		  dlg_stdcheckbox_handler, I(offsetof(Config,bce)));
    ctrl_checkbox(s, "Разрешить мигающий текст", 'n',
		  HELPCTX(terminal_blink),
		  dlg_stdcheckbox_handler, I(offsetof(Config,blinktext)));
    ctrl_editbox(s, "Обратный ответ на ^E:", 's', 100,
		 HELPCTX(terminal_answerback),
		 dlg_stdeditbox_handler, I(offsetof(Config,answerback)),
		 I(sizeof(((Config *)0)->answerback)));

    s = ctrl_getset(b, "Терминал", "ldisc", "Line discipline options");
    ctrl_radiobuttons(s, "Локальное эхо:", 'l', 3,
		      HELPCTX(terminal_localecho),
		      dlg_stdradiobutton_handler,I(offsetof(Config,localecho)),
		      "Авто", I(AUTO),
		      "Вкл", I(FORCE_ON),
		      "Выкл", I(FORCE_OFF), NULL);
    ctrl_radiobuttons(s, "Локальное редактирование строки:", 't', 3,
		      HELPCTX(terminal_localedit),
		      dlg_stdradiobutton_handler,I(offsetof(Config,localedit)),
		      "Авто", I(AUTO),
		      "Вкл", I(FORCE_ON),
		      "Выкл", I(FORCE_OFF), NULL);

    s = ctrl_getset(b, "Терминал", "printing", "Удалённое управление печатью");
    ctrl_combobox(s, "Выберите принтер:", 'p', 100,
		  HELPCTX(terminal_printing),
		  printerbox_handler, P(NULL), P(NULL));

    /*
     * The Terminal/Keyboard panel.
     */
    ctrl_settitle(b, "Терминал/Клавиатура",
		  "Настройки эффектов клавиатуры");

    s = ctrl_getset(b, "Терминал/Клавиатура", "mappings",
		    "Отправляемые последовательности:");
    ctrl_radiobuttons(s, "Клавиша «Backspace» генерирует", 'b', 2,
		      HELPCTX(keyboard_backspace),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config, bksp_is_delete)),
		      "Control-H", I(0), "Control-? (127)", I(1), NULL);
    ctrl_radiobuttons(s, "Клавиши «Home» и «End» генерируют", 'e', 2,
		      HELPCTX(keyboard_homeend),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config, rxvt_homeend)),
		      "Standard", I(0), "rxvt", I(1), NULL);
    ctrl_radiobuttons(s, "Функциональные клавиши и цифровая клавиатура", 'f', 3,
		      HELPCTX(keyboard_funkeys),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config, funky_type)),
		      "ESC[n~", I(0), "Linux", I(1), "Xterm R6", I(2),
		      "VT400", I(3), "VT100+", I(4), "SCO", I(5), NULL);

    s = ctrl_getset(b, "Терминал/Клавиатура", "appkeypad",
		    "Цифровая клавиатура в приложениях:");
    ctrl_radiobuttons(s, "Исходное состояние клавиш управления курсором:", 'r', 3,
		      HELPCTX(keyboard_appcursor),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config, app_cursor)),
		      "Нормальное", I(0), "Приложение", I(1), NULL);
    ctrl_radiobuttons(s, "Исходное состояние цифровой клавиатуры:", 'n', 3,
		      HELPCTX(keyboard_appkeypad),
		      numeric_keypad_handler, P(NULL),
		      "Нормальное", I(0), "Приложение", I(1), "NetHack", I(2),
		      NULL);

    /*
     * The Terminal/Bell panel.
     */
    ctrl_settitle(b, "Терминал/Уведомления",
		  "Настройки терминального сигнала");

    s = ctrl_getset(b, "Терминал/Уведомления", "style", "Стиль сигнала");
    ctrl_radiobuttons(s, "Действие при срабатывании сигнала:", 'b', 1,
		      HELPCTX(bell_style),
		      dlg_stdradiobutton_handler, I(offsetof(Config, beep)),
		      "Сигнал отключён", I(BELL_DISABLED),
		      "Звук оповещения по умолчанию в системе", I(BELL_DEFAULT),
		      "Визуальное оповещение (мигающее окно)", I(BELL_VISUAL), NULL);

    s = ctrl_getset(b, "Терминал/Уведомления", "overload",
		    "Управление поведением сигнала при перегрузке");
    ctrl_checkbox(s, "Временно отключать сигнал при частом вызове", 'd',
		  HELPCTX(bell_overload),
		  dlg_stdcheckbox_handler, I(offsetof(Config,bellovl)));
    ctrl_editbox(s, "Частое использование означает кол-во вызовов...", 'm', 20,
		 HELPCTX(bell_overload),
		 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_n)), I(-1));
    ctrl_editbox(s, "... за столько-то секунд ...", 't', 20,
		 HELPCTX(bell_overload),
		 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_t)),
		 I(-TICKSPERSEC));
    ctrl_text(s, "Возобновить действие сигнала после отключения",
	      HELPCTX(bell_overload));
    ctrl_editbox(s, "Через столько секунд тишины", 's', 20,
		 HELPCTX(bell_overload),
		 dlg_stdeditbox_handler, I(offsetof(Config,bellovl_s)),
		 I(-TICKSPERSEC));

    /*
     * The Terminal/Features panel.
     */
    ctrl_settitle(b, "Терминал/Особенности",
		  "Управление расшренными свойствами терминала");

    s = ctrl_getset(b, "Терминал/Особенности", "main", NULL);
    ctrl_checkbox(s, "Запретить режим клавиши курсора в приложениях", 'u',
		  HELPCTX(features_application),
		  dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_c)));
    ctrl_checkbox(s, "Запретить режим цифровой клавиатуры в приложениях", 'k',
		  HELPCTX(features_application),
		  dlg_stdcheckbox_handler, I(offsetof(Config,no_applic_k)));
    ctrl_checkbox(s, "Запретить xterm-style mouse reporting", 'x',
		  HELPCTX(features_mouse),
		  dlg_stdcheckbox_handler, I(offsetof(Config,no_mouse_rep)));
    ctrl_checkbox(s, "Запретить удалённое изменение размеров окна", 's',
		  HELPCTX(features_resize),
		  dlg_stdcheckbox_handler,
		  I(offsetof(Config,no_remote_resize)));
    ctrl_checkbox(s, "Запретить переключение на дополнительный экран терминала", 'w',
		  HELPCTX(features_altscreen),
		  dlg_stdcheckbox_handler, I(offsetof(Config,no_alt_screen)));
    ctrl_checkbox(s, "Запретить удалённое изменение заголовка окна", 't',
		  HELPCTX(features_retitle),
		  dlg_stdcheckbox_handler,
		  I(offsetof(Config,no_remote_wintitle)));
    ctrl_radiobuttons(s, "Удалённый запрос заголовка окна (SECURITY):", 'q', 3,
		      HELPCTX(features_qtitle),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config,remote_qtitle_action)),
		      "Не отвечать", I(TITLE_NONE),
		      "Пустая строка", I(TITLE_EMPTY),
		      "Заголовок окна", I(TITLE_REAL), NULL);
    ctrl_checkbox(s, "Запретить destructive backspace при отправке на сервер ^?",'b',
		  HELPCTX(features_dbackspace),
		  dlg_stdcheckbox_handler, I(offsetof(Config,no_dbackspace)));
    ctrl_checkbox(s, "Запретить удалённое управление настройками кодировки",
		  'r', HELPCTX(features_charset), dlg_stdcheckbox_handler,
		  I(offsetof(Config,no_remote_charset)));
    ctrl_checkbox(s, "Запретить форматирование арабского текста",
		  'l', HELPCTX(features_arabicshaping), dlg_stdcheckbox_handler,
		  I(offsetof(Config, arabicshaping)));
    ctrl_checkbox(s, "Запретить отображение двунаправленного текста",
		  'd', HELPCTX(features_bidi), dlg_stdcheckbox_handler,
		  I(offsetof(Config, bidi)));

    /*
     * The Window panel.
     */
    str = dupprintf("Настройки окна %s", appname);
    ctrl_settitle(b, "Окно", str);
    sfree(str);

    s = ctrl_getset(b, "Окно", "size", "Размер окна");
    ctrl_columns(s, 2, 50, 50);
    c = ctrl_editbox(s, "Ширина", 'm', 100,
		     HELPCTX(window_size),
		     dlg_stdeditbox_handler, I(offsetof(Config,width)), I(-1));
    c->generic.column = 0;
    c = ctrl_editbox(s, "Высота", 'r', 100,
		     HELPCTX(window_size),
		     dlg_stdeditbox_handler, I(offsetof(Config,height)),I(-1));
    c->generic.column = 1;
    ctrl_columns(s, 1, 100);

    s = ctrl_getset(b, "Окно", "scrollback",
		    "Настройка буфера экрана");
    ctrl_editbox(s, "Обратная прокрутка (строк)", 's', 50,
		 HELPCTX(window_scrollback),
		 dlg_stdeditbox_handler, I(offsetof(Config,savelines)), I(-1));
    ctrl_checkbox(s, "Отображать полосу прокрутки", 'd',
		  HELPCTX(window_scrollback),
		  dlg_stdcheckbox_handler, I(offsetof(Config,scrollbar)));
    ctrl_checkbox(s, "Сбрасывать буфер при нажатии на клавишу", 'k',
		  HELPCTX(window_scrollback),
		  dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_key)));
    ctrl_checkbox(s, "Сбрасывать буфер при активности экрана", 'p',
		  HELPCTX(window_scrollback),
		  dlg_stdcheckbox_handler, I(offsetof(Config,scroll_on_disp)));
    ctrl_checkbox(s, "Передвинуть очищенный текст под полосу прокрутки", 'e',
		  HELPCTX(window_erased),
		  dlg_stdcheckbox_handler,
		  I(offsetof(Config,erase_to_scrollback)));

    /*
     * The Window/Appearance panel.
     */
    str = dupprintf("Настройки внешнего вида %s", appname);
    ctrl_settitle(b, "Окно/Внешний вид", str);
    sfree(str);

    s = ctrl_getset(b, "Окно/Внешний вид", "cursor",
		    "Курсор");
    ctrl_radiobuttons(s, "Форма курсора:", NO_SHORTCUT, 4,
		      HELPCTX(appearance_cursor),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config, cursor_type)),
		      "Блок", 'l', I(0),
		      "Черта снизу", 'u', I(1),
		      "Вертикальная черта", 'v', I(2), NULL);
    ctrl_checkbox(s, "Мигающий курсор", 'b',
		  HELPCTX(appearance_cursor),
		  dlg_stdcheckbox_handler, I(offsetof(Config,blink_cur)));

    s = ctrl_getset(b, "Окно/Внешний вид", "font",
		    "Шрифты");
    ctrl_fontsel(s, "Шрифт, используемый в окне терминала:", 'n',
		 HELPCTX(appearance_font),
		 dlg_stdfontsel_handler, I(offsetof(Config, font)));

    s = ctrl_getset(b, "Окно/Внешний вид", "mouse",
		    "Указатель мыши");
    ctrl_checkbox(s, "Скрыть указатель мыши при наборе текста", 'p',
		  HELPCTX(appearance_hidemouse),
		  dlg_stdcheckbox_handler, I(offsetof(Config,hide_mouseptr)));

    s = ctrl_getset(b, "Окно/Внешний вид", "border",
		    "Границы окон");
    ctrl_editbox(s, "Расстояние между текстом и краем окна:", 'e', 20,
		 HELPCTX(appearance_border),
		 dlg_stdeditbox_handler,
		 I(offsetof(Config,window_border)), I(-1));
#ifdef PERSOPORT
	if( !get_param("PUTTY") ) {
	/*
     * Brad's The Window/Position & Icon panel.
     */
	/* BKG */
    //s = ctrl_getset(b, "Окно/Внешний вид", "position",
	//	    "Позиция окон");
    /**/
    ctrl_checkbox(s, "Запоминать позиции окон", '+',
		  HELPCTX(appearance_hidemouse),
		  dlg_stdcheckbox_handler, I(offsetof(Config,save_windowpos)));
    ctrl_editbox(s, "Верхняя позиция:", NO_SHORTCUT, 20,
		 HELPCTX(appearance_border),
		 dlg_stdeditbox_handler,
		 I(offsetof(Config,ypos)), I(-1));
    ctrl_editbox(s, "Левая позиция:", NO_SHORTCUT, 20,
		 HELPCTX(appearance_border),
		 dlg_stdeditbox_handler,
		 I(offsetof(Config,xpos)), I(-1));
	}
    if( !get_param("PUTTY") && (get_param("ICON")>0) ) {
    s = ctrl_getset(b, "Окно/Внешний вид", "icon",
		    "Define the window icon");
    c = ctrl_editbox(s, "Icon (from internal resources)", '_', 40,
			 HELPCTX(appearance_icone),
			 dlg_stdeditbox_handler,
			 I(offsetof(Config,icone)), I(-1));
    ctrl_filesel(s, "External icon file:", '{',
		     FILTER_ICON_FILES, FALSE, "Select icon file",
		     HELPCTX(appearance_iconefile),
		     dlg_stdfilesel_handler, I(offsetof(Config, iconefile)));
    }
#endif
#if (defined IMAGEPORT) && (!defined FDJ)
	if( !get_param("PUTTY") && get_param("BACKGROUNDIMAGE") ) {
    /*
     * The Window/Background panel.
     * (This would really belong in Appearance but we overflowed -- to much
     * stuff on one page otherwise).
     */
    str = dupprintf("Настройки фона окна %s", appname);
    ctrl_settitle(b, "Окно/Фон", str);
    sfree(str);

    s = ctrl_getset(b, "Окно/Фон", "bg_style",
            "Стиль фона");
    ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 1,
              HELPCTX(appearance_background),
              dlg_stdradiobutton_handler,
              I(offsetof(Config, bg_type)),
              "Сплошной цвет", NO_SHORTCUT, I(0),  // TODO: Define shortcuts for these.
              "Рабочий стол", NO_SHORTCUT, I(1),
              "Фоновый рисунок", NO_SHORTCUT, I(2),
              NULL);

    s = ctrl_getset(b, "Окно/Фон", "bg_wp_img_settings",
            "Desktop and image settings");
    ctrl_editbox(s, "Прозрачность:", NO_SHORTCUT, 20,
		 HELPCTX(appearance_background),
		 dlg_stdeditbox_handler,
		 I(offsetof(Config,bg_opacity)), I(-1));
    ctrl_editbox(s, "Слайд-шоу:", NO_SHORTCUT, 20,
		 HELPCTX(appearance_background),
		 dlg_stdeditbox_handler,
		 I(offsetof(Config,bg_slideshow)), I(-1));

    s = ctrl_getset(b, "Окно/Фон", "bg_img_settings",
            "Настройки фонового изображения");
    ctrl_filesel(s, "Файл:", 'k',
		     FILTER_IMAGE_FILES, FALSE, "Выберите файл фонового изображения",
		     HELPCTX(appearance_background),
		     dlg_stdfilesel_handler, I(offsetof(Config, bg_image_filename)));
    ctrl_radiobuttons(s, "Стиль:", NO_SHORTCUT, 3,
              HELPCTX(appearance_background),
              dlg_stdradiobutton_handler,
              I(offsetof(Config, bg_image_style)),
              "Черепицей", NO_SHORTCUT, I(0),  // TODO: Define shortcuts for these.
              "По центру", NO_SHORTCUT, I(1),
              "Растянуть", NO_SHORTCUT, I(2),
              "Абсолют (X,Y)", NO_SHORTCUT, I(3),
	      "Пустой фон", NO_SHORTCUT, I(4),
	      "Растянуть+", NO_SHORTCUT, I(5),
              NULL);
    ctrl_editbox(s, "Абсолютное значение по оси X:", NO_SHORTCUT, 20,
		 HELPCTX(appearance_background),
		 dlg_stdeditbox_handler,
		 I(offsetof(Config,bg_image_abs_x)), I(-1));
    ctrl_editbox(s, "Абсолютное значение по оси Y:", NO_SHORTCUT, 20,
		 HELPCTX(appearance_background),
		 dlg_stdeditbox_handler,
		 I(offsetof(Config,bg_image_abs_y)), I(-1));
    ctrl_radiobuttons(s, "Размещать изображение относительно:", NO_SHORTCUT, 2,
              HELPCTX(appearance_background),
              dlg_stdradiobutton_handler,
              I(offsetof(Config, bg_image_abs_fixed)),
              "Рабочего стола", NO_SHORTCUT, I(0),  // TODO: Define shortcuts for these.
              "Окна терминала", NO_SHORTCUT, I(1),
              NULL);
      }
#endif 

    /*
     * The Window/Behaviour panel.
     */
    str = dupprintf("Настройки поведения окна %s", appname);
    ctrl_settitle(b, "Окно/Поведение", str);
    sfree(str);

    s = ctrl_getset(b, "Окно/Поведение", "title",
		    "Управление поведением заголовка окна");
    ctrl_editbox(s, "Заголовок окна:", 't', 100,
		 HELPCTX(appearance_title),
		 dlg_stdeditbox_handler, I(offsetof(Config,wintitle)),
		 I(sizeof(((Config *)0)->wintitle)));
#ifdef PERSOPORT
      ctrl_text(s, "     %%f: имя папки", HELPCTX(appearance_title));
      ctrl_text(s, "     %%h: имя хоста", HELPCTX(appearance_title));
      ctrl_text(s, "     %%p: номер порта", HELPCTX(appearance_title));
      ctrl_text(s, "     %%P: имя протокола", HELPCTX(appearance_title));
      ctrl_text(s, "     %%s: имя сеанса", HELPCTX(appearance_title));
      ctrl_text(s, "     %%u: имя пользователя", HELPCTX(appearance_title));
#endif
    ctrl_checkbox(s, "Separate window and icon titles", 'i',
		  HELPCTX(appearance_title),
		  dlg_stdcheckbox_handler,
		  I(CHECKBOX_INVERT | offsetof(Config,win_name_always)));

    s = ctrl_getset(b, "Окно/Поведение", "main", NULL);
    ctrl_checkbox(s, "Предупреждать перед закрытием окна", 'w',
		  HELPCTX(behaviour_closewarn),
		  dlg_stdcheckbox_handler, I(offsetof(Config,warn_on_close)));

    /*
     * The Window/Translation panel.
     */
    ctrl_settitle(b, "Окно/Кодировка",
		  "Настройки преобразования набора символов");

    s = ctrl_getset(b, "Окно/Кодировка", "trans",
		    "Кодировка");
    ctrl_combobox(s, NULL,
		  'r', 100, HELPCTX(translation_codepage),
		  codepage_handler, P(NULL), P(NULL));

    s = ctrl_getset(b, "Окно/Кодировка", "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)));

    str = dupprintf("Обработка символов рисования линий", appname);
    s = ctrl_getset(b, "Окно/Кодировка", "linedraw", str);
    sfree(str);
    ctrl_radiobuttons(s, NULL, NO_SHORTCUT,1,
		      HELPCTX(translation_linedraw),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config, vtmode)),
		      "Использовать коды прорисовки линий Unicode",'u',I(VT_UNICODE),
		      "Использовать псевдо-линии (символы +, - и |)",'p',I(VT_POORMAN),
		      NULL);
    ctrl_checkbox(s, "Заменять символы рисования линий на lqqqk",'d',
		  HELPCTX(selection_linedraw),
		  dlg_stdcheckbox_handler, I(offsetof(Config,rawcnp)));

    /*
     * The Window/Selection panel.
     */
    ctrl_settitle(b, "Окно/Выделение", "Настройка копирования/вставки");
	
    s = ctrl_getset(b, "Окно/Выделение", "mouse",
		    "Использование управления мышью");
    ctrl_checkbox(s, "Shift переопределяет использование мыши приложением", 'p',
		  HELPCTX(selection_shiftdrag),
		  dlg_stdcheckbox_handler, I(offsetof(Config,mouse_override)));
#ifdef URLPORT
    ctrl_checkbox(s, "Detect URLs on selection and launch in browser", 'и',
		  HELPCTX(selection_shiftdrag),
		  dlg_stdcheckbox_handler, I(offsetof(Config,copy_clipbd_url_reg)));
#endif
    ctrl_radiobuttons(s,
		      "Режим выделения по умолчанию (Alt+перетащить делает другое):",
		      NO_SHORTCUT, 2,
		      HELPCTX(selection_rect),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config, rect_select)),
		      "Обычный", 'n', I(0),
		      "Прямоугольный блок", 'r', I(1), NULL);

    s = ctrl_getset(b, "Окно/Выделение", "charclass",
		    "Управление режимом «выбирать одно слово за раз»");
    ccd = (struct charclass_data *)
	ctrl_alloc(b, sizeof(struct charclass_data));
    ccd->listbox = ctrl_listbox(s, "Классы символов:", 'e',
				HELPCTX(selection_charclasses),
				charclass_handler, P(ccd));
    ccd->listbox->listbox.multisel = 1;
    ccd->listbox->listbox.ncols = 4;
    ccd->listbox->listbox.percentages = snewn(4, int);
    ccd->listbox->listbox.percentages[0] = 15;
    ccd->listbox->listbox.percentages[1] = 25;
    ccd->listbox->listbox.percentages[2] = 20;
    ccd->listbox->listbox.percentages[3] = 40;
    ctrl_columns(s, 2, 67, 33);
    ccd->editbox = ctrl_editbox(s, "Set to class", 't', 50,
				HELPCTX(selection_charclasses),
				charclass_handler, P(ccd), P(NULL));
    ccd->editbox->generic.column = 0;
    ccd->button = ctrl_pushbutton(s, "Установить", 's',
				  HELPCTX(selection_charclasses),
				  charclass_handler, P(ccd));
    ccd->button->generic.column = 1;
    ctrl_columns(s, 1, 100);

    /*
     * The Window/Colours panel.
     */
    ctrl_settitle(b, "Окно/Цветовая схема", "Настройки цветовой схемы");

    s = ctrl_getset(b, "Окно/Цветовая схема", "general",
		    "Основные настройки использования цвета");
    ctrl_checkbox(s, "Разрешить терминалу определять ANSI цвета", 'i',
		  HELPCTX(colours_ansi),
		  dlg_stdcheckbox_handler, I(offsetof(Config,ansi_colour)));
    ctrl_checkbox(s, "Разрешить терминалу использовать 256-цветный xterm режим", '2',
		  HELPCTX(colours_xterm256), dlg_stdcheckbox_handler,
		  I(offsetof(Config,xterm_256_colour)));
#ifdef PERSOPORT
	if( !get_param("PUTTY" ) ) {
	ctrl_radiobuttons(s,
		      "Отображение полужирного текста",
		      'b', 1,
		      HELPCTX(colours_bold),
		      dlg_stdradiobutton_handler,
		      I(offsetof(Config, bold_colour)),
		      "Только полужирный шрифт", I(0),
		      "Только полужирная расцветка", I(1),
		      "И полужирный шрифт и полужирные цвета", I(2),
                      NULL);
		}
	else
#endif
    ctrl_checkbox(s, "Bolded text is a different colour", 'b',
		  HELPCTX(colours_bold),
		  dlg_stdcheckbox_handler, I(offsetof(Config,bold_colour)));

    str = dupprintf("Тонкая настройка рацветки дисплея", appname);
    s = ctrl_getset(b, "Окно/Цветовая схема", "adjust", str);
    sfree(str);
    //ctrl_text(s, "Выберите расцветку из списка,"
	//      " и затем нажмите кнопку «Изменить».",
	//      HELPCTX(colours_config));
    ctrl_columns(s, 2, 67, 33);
    cd = (struct colour_data *)ctrl_alloc(b, sizeof(struct colour_data));
    cd->listbox = ctrl_listbox(s, "Выберите расцветку:", 'u',
			       HELPCTX(colours_config), colour_handler, P(cd));
    cd->listbox->generic.column = 0;
    cd->listbox->listbox.height = 7;
    c = ctrl_text(s, "Значение RGB:", HELPCTX(colours_config));
    c->generic.column = 1;
    cd->redit = ctrl_editbox(s, "Красный", 'r', 50, HELPCTX(colours_config),
			     colour_handler, P(cd), P(NULL));
    cd->redit->generic.column = 1;
    cd->gedit = ctrl_editbox(s, "Зелёный", 'n', 50, HELPCTX(colours_config),
			     colour_handler, P(cd), P(NULL));
    cd->gedit->generic.column = 1;
    cd->bedit = ctrl_editbox(s, "Синий", 'e', 50, HELPCTX(colours_config),
			     colour_handler, P(cd), P(NULL));
    cd->bedit->generic.column = 1;
    cd->button = ctrl_pushbutton(s, "Изменить...", 'm', HELPCTX(colours_config),
				 colour_handler, P(cd));
    cd->button->generic.column = 1;
    ctrl_columns(s, 1, 100);

    /*
     * The Connection panel. This doesn't show up if we're in a
     * non-network utility such as pterm. We tell this by being
     * passed a protocol < 0.
     */
    if (protocol >= 0) {
	ctrl_settitle(b, "Соединение", "Настройки соединения");

	s = ctrl_getset(b, "Соединение", "keepalive",
			"Отправка пустых пакетов для сохранения активности сеанса");
	ctrl_editbox(s, "Интервал в секундах между отправкой (0 - отключено)", 'k', 20,
		     HELPCTX(connection_keepalive),
		     dlg_stdeditbox_handler, I(offsetof(Config,ping_interval)),
		     I(-1));
#ifdef PERSOPORT
    	ctrl_editbox(s, "Посылать строку вместо null", '&', 50,
		HELPCTX(connection_antiidle),
		dlg_stdeditbox_handler, I(offsetof(Config,antiidle)),
		I(sizeof(((Config *)0)->antiidle)));
#endif

	if (!midsession) {
	    s = ctrl_getset(b, "Соединение", "tcp",
			    "Низкоуровневые настройки TCP");
	    ctrl_checkbox(s, "Отключить Nagle's algorithm (опция TCP_NODELAY)",
			  'n', HELPCTX(connection_nodelay),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,tcp_nodelay)));
	    ctrl_checkbox(s, "Включить TCP keepalives (опция SO_KEEPALIVE)",
			  'p', HELPCTX(connection_tcpkeepalive),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,tcp_keepalives)));
#ifndef NO_IPV6
	    s = ctrl_getset(b, "Соединение", "ipversion",
			  "Версия Internet Protocol");
	    ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
			  HELPCTX(connection_ipversion),
			  dlg_stdradiobutton_handler,
			  I(offsetof(Config, addressfamily)),
			  "Авто", 'u', I(ADDRTYPE_UNSPEC),
			  "IPv4", '4', I(ADDRTYPE_IPV4),
			  "IPv6", '6', I(ADDRTYPE_IPV6),
			  NULL);
#endif

#ifdef RECONNECTPORT
	if( !get_param("PUTTY" ) ) {
		s = ctrl_getset(b, "Соединение", "reconnect", "Настройки переподключения");
		ctrl_checkbox(s, "Пробовать переподключиться после выхода из режима сна", 'w', HELPCTX(no_help), dlg_stdcheckbox_handler, I(offsetof(Config,wakeup_reconnect)));
		ctrl_checkbox(s, "Пробовать переподключиться после разрыва соединения", 'v', HELPCTX(no_help), dlg_stdcheckbox_handler, I(offsetof(Config,failure_reconnect)));
	}
#endif

	    {
		char *label = backend_from_proto(PROT_SSH) ?
		    "Логическое имя удалённого хоста (например, для поиска SSH-ключа):" :
		    "Логическое имя удалённого хоста:";
		s = ctrl_getset(b, "Соединение", "identity",
				"Логическое имя удалённого хоста");
		ctrl_editbox(s, label, 'm', 100,
			     HELPCTX(connection_loghost),
			     dlg_stdeditbox_handler, I(offsetof(Config,loghost)),
			     I(sizeof(((Config *)0)->loghost)));
	    }
	}

	/*
	 * A sub-panel Connection/Data, containing options that
	 * decide on data to send to the server.
	 */
	if (!midsession) {
	    ctrl_settitle(b, "Соединение/Данные", "Данные для отправки на сервер");

	    s = ctrl_getset(b, "Соединение/Данные", "login",
			    "Данные для входа в систему");
	    ctrl_editbox(s, "Имя пользователя для автовхода", 'u', 50,
			 HELPCTX(connection_username),
			 dlg_stdeditbox_handler, I(offsetof(Config,username)),
			 I(sizeof(((Config *)0)->username)));
	    {
		/* We assume the local username is sufficiently stable
		 * to include on the dialog box. */
		char *user = get_username();
		char *userlabel = dupprintf("Использовать системное (%s)",
					    user ? user : "");
		sfree(user);
		ctrl_radiobuttons(s, "Если имя пользователя не указано:", 'n', 4,
				  HELPCTX(connection_username_from_env),
				  dlg_stdradiobutton_handler,
				  I(offsetof(Config, username_from_env)),
				  "Спрашивать", I(FALSE),
				  userlabel, I(TRUE),
				  NULL);
		sfree(userlabel);
	    }
#ifdef PERSOPORT
	if( !get_param("PUTTY" ) ) {
	//s = ctrl_getset(b, "Соединение", "automatic", "Auto-connect");
	c = ctrl_editbox(s, "Пароль для автовхода", 'y', 50,
		     HELPCTX(connection_password),
		     dlg_stdeditbox_handler, I(offsetof(Config,password)),
		     I(sizeof(((Config *)0)->password)));
	c->editbox.password = 1;
	ctrl_editbox(s, "Посылать команду", 'z', 74,
		     HELPCTX(connection_autocommand),
		     dlg_stdeditbox_handler, I(offsetof(Config,autocommand)),
		     I(sizeof(((Config *)0)->autocommand)));
	ctrl_filesel(s, "Файл сценария входа в систему:", 'k',
			"Файлы Src (*.scr, *.txt)\0*.scr;*.txt\0Все файлы (*.*)\0*\0\0\0"
			 ,FALSE, "Выберите файл сценария входа в систему",
			 HELPCTX(scriptfile),
			 dlg_stdfilesel_handler, I(offsetof(Config, scriptfile)));
	}
#endif

	    s = ctrl_getset(b, "Соединение/Данные", "term",
			    "Детали терминала");
	    ctrl_editbox(s, "Строка типа терминала", 't', 50,
			 HELPCTX(connection_termtype),
			 dlg_stdeditbox_handler, I(offsetof(Config,termtype)),
			 I(sizeof(((Config *)0)->termtype)));
	    ctrl_editbox(s, "Скорости терминала", 's', 50,
			 HELPCTX(connection_termspeed),
			 dlg_stdeditbox_handler, I(offsetof(Config,termspeed)),
			 I(sizeof(((Config *)0)->termspeed)));

	    s = ctrl_getset(b, "Соединение/Данные", "env",
			    "Переменные окружения");
	    ctrl_columns(s, 2, 80, 20);
	    ed = (struct environ_data *)
		ctrl_alloc(b, sizeof(struct environ_data));
	    ed->varbox = ctrl_editbox(s, "Переменная", 'v', 60,
				      HELPCTX(telnet_environ),
				      environ_handler, P(ed), P(NULL));
	    ed->varbox->generic.column = 0;
	    ed->valbox = ctrl_editbox(s, "Значение", 'l', 60,
				      HELPCTX(telnet_environ),
				      environ_handler, P(ed), P(NULL));
	    ed->valbox->generic.column = 0;
	    ed->addbutton = ctrl_pushbutton(s, "Добавить", 'd',
					    HELPCTX(telnet_environ),
					    environ_handler, P(ed));
	    ed->addbutton->generic.column = 1;
	    ed->rembutton = ctrl_pushbutton(s, "Удалить", 'r',
					    HELPCTX(telnet_environ),
					    environ_handler, P(ed));
	    ed->rembutton->generic.column = 1;
	    ctrl_columns(s, 1, 100);
	    ed->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
				       HELPCTX(telnet_environ),
				       environ_handler, P(ed));
	    ed->listbox->listbox.height = 3;
	    ed->listbox->listbox.ncols = 2;
	    ed->listbox->listbox.percentages = snewn(2, int);
	    ed->listbox->listbox.percentages[0] = 30;
	    ed->listbox->listbox.percentages[1] = 70;
	}

    }

    if (!midsession) {
	/*
	 * The Connection/Proxy panel.
	 */
	ctrl_settitle(b, "Соединение/Прокси",
		      "Настройки соединения с прокси-сервером");

	s = ctrl_getset(b, "Соединение/Прокси", "basics", NULL);
	ctrl_radiobuttons(s, "Тип прокси:", 't', 3,
			  HELPCTX(proxy_type),
			  dlg_stdradiobutton_handler,
			  I(offsetof(Config, proxy_type)),
			  "Без прокси", I(PROXY_NONE),
			  "SOCKS 4", I(PROXY_SOCKS4),
			  "SOCKS 5", I(PROXY_SOCKS5),
			  "HTTP", I(PROXY_HTTP),
			  "Telnet", I(PROXY_TELNET),
			  NULL);
	ctrl_columns(s, 2, 80, 20);
	c = ctrl_editbox(s, "Адрес прокси-сервера", 'y', 100,
			 HELPCTX(proxy_main),
			 dlg_stdeditbox_handler,
			 I(offsetof(Config,proxy_host)),
			 I(sizeof(((Config *)0)->proxy_host)));
	c->generic.column = 0;
	c = ctrl_editbox(s, "Порт", 'p', 100,
			 HELPCTX(proxy_main),
			 dlg_stdeditbox_handler,
			 I(offsetof(Config,proxy_port)),
			 I(-1));
	c->generic.column = 1;
	ctrl_columns(s, 1, 100);
	ctrl_editbox(s, "Не использовать прокси для", 'e', 100,
		     HELPCTX(proxy_exclude),
		     dlg_stdeditbox_handler,
		     I(offsetof(Config,proxy_exclude_list)),
		     I(sizeof(((Config *)0)->proxy_exclude_list)));
	ctrl_checkbox(s, "Использовать прокси-сервер для локальных адресов", 'x',
		      HELPCTX(proxy_exclude),
		      dlg_stdcheckbox_handler,
		      I(offsetof(Config,even_proxy_localhost)));
	ctrl_radiobuttons(s, "Выполнять DNS запросы через прокси-сервер:", 'd', 3,
			  HELPCTX(proxy_dns),
			  dlg_stdradiobutton_handler,
			  I(offsetof(Config, proxy_dns)),
			  "Нет", I(FORCE_OFF),
			  "Авто", I(AUTO),
			  "Да", I(FORCE_ON), NULL);
	ctrl_editbox(s, "Имя пользователя", 'u', 60,
		     HELPCTX(proxy_auth),
		     dlg_stdeditbox_handler,
		     I(offsetof(Config,proxy_username)),
		     I(sizeof(((Config *)0)->proxy_username)));
	c = ctrl_editbox(s, "Пароль", 'w', 60,
			 HELPCTX(proxy_auth),
			 dlg_stdeditbox_handler,
			 I(offsetof(Config,proxy_password)),
			 I(sizeof(((Config *)0)->proxy_password)));
	c->editbox.password = 1;
	ctrl_editbox(s, "Команда Telnet", 'm', 100,
		     HELPCTX(proxy_command),
		     dlg_stdeditbox_handler,
		     I(offsetof(Config,proxy_telnet_command)),
		     I(sizeof(((Config *)0)->proxy_telnet_command)));
    }

    /*
     * The Telnet panel exists in the base config box, and in a
     * mid-session reconfig box _if_ we're using Telnet.
     */
    if (!midsession || protocol == PROT_TELNET) {
	/*
	 * The Connection/Telnet panel.
	 */
	ctrl_settitle(b, "Соединение/Telnet",
		      "Настройки Telnet соединения");

	s = ctrl_getset(b, "Соединение/Telnet", "protocol",
			"Особенности протокола Telnet");

	if (!midsession) {
	    ctrl_radiobuttons(s, "Обработка неоднозначностей OLD_ENVIRON:",
			      NO_SHORTCUT, 2,
			      HELPCTX(telnet_oldenviron),
			      dlg_stdradiobutton_handler,
			      I(offsetof(Config, rfc_environ)),
			      "BSD (типично)", 'b', I(0),
			      "RFC 1408 (необычно)", 'f', I(1), NULL);
	    ctrl_radiobuttons(s, "Режим согласования Telnet:", 't', 2,
			      HELPCTX(telnet_passive),
			      dlg_stdradiobutton_handler,
			      I(offsetof(Config, passive_telnet)),
			      "Пассивный", I(1), "Активный", I(0), NULL);
	}
	ctrl_checkbox(s, "Keyboard sends Telnet special commands", 'k',
		      HELPCTX(telnet_specialkeys),
		      dlg_stdcheckbox_handler,
		      I(offsetof(Config,telnet_keyboard)));
	ctrl_checkbox(s, "Клавиша Return/Enter отправляет символ новой строки вместо ^M",
		      'm', HELPCTX(telnet_newline),
		      dlg_stdcheckbox_handler,
		      I(offsetof(Config,telnet_newline)));
    }

    if (!midsession) {

	/*
	 * The Connection/Rlogin panel.
	 */
	ctrl_settitle(b, "Соединение/Rlogin",
		      "Настройки Rlogin соединения");

	s = ctrl_getset(b, "Соединение/Rlogin", "data",
			"Данные для отправки на сервер");
	ctrl_editbox(s, "Локальное имя пользователя:", 'l', 50,
		     HELPCTX(rlogin_localuser),
		     dlg_stdeditbox_handler, I(offsetof(Config,localusername)),
		     I(sizeof(((Config *)0)->localusername)));

    }

    /*
     * All the SSH stuff is omitted in PuTTYtel, or in a reconfig
     * when we're not doing SSH.
     */

    if (backend_from_proto(PROT_SSH) && (!midsession || protocol == PROT_SSH)) {

	/*
	 * The Connection/SSH panel.
	 */
	ctrl_settitle(b, "Соединение/SSH",
		      "Настройки SSH соединения");

	if (midsession && protcfginfo == 1) {
	    s = ctrl_getset(b, "Соединение/SSH", "disclaimer", NULL);
	    ctrl_text(s, "Nothing on this panel may be reconfigured in mid-"
		      "session; it is only here so that sub-panels of it can "
		      "exist without looking strange.", HELPCTX(no_help));
	}

	if (!midsession) {

	    s = ctrl_getset(b, "Соединение/SSH", "data",
			    "Данные для отправки на сервер");
	    ctrl_editbox(s, "Выполнение удалённой команды:", 'r', 100,
			 HELPCTX(ssh_command),
			 dlg_stdeditbox_handler, I(offsetof(Config,remote_cmd)),
			 I(sizeof(((Config *)0)->remote_cmd)));

	    s = ctrl_getset(b, "Соединение/SSH", "protocol", "Настройка протокола");
	    ctrl_checkbox(s, "Не запускать shell и не выполнять никаких команд", 'n',
			  HELPCTX(ssh_noshell),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,ssh_no_shell)));
	}

	if (!midsession || protcfginfo != 1) {
	    s = ctrl_getset(b, "Соединение/SSH", "protocol", "Параметры протокола");

	    ctrl_checkbox(s, "Разрешить сжатие", 'e',
			  HELPCTX(ssh_compress),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,compression)));
	}

	if (!midsession) {
	    s = ctrl_getset(b, "Соединение/SSH", "protocol", "Настройка протокола");

	    ctrl_radiobuttons(s, "Предпочтительная версия SSH:", NO_SHORTCUT, 4,
			      HELPCTX(ssh_protocol),
			      dlg_stdradiobutton_handler,
			      I(offsetof(Config, sshprot)),
			      "Только 1", 'l', I(0),
			      "1", '1', I(1),
			      "2", '2', I(2),
			      "Только 2", 'y', I(3), NULL);
	}

	if (!midsession || protcfginfo != 1) {
	    s = ctrl_getset(b, "Соединение/SSH", "encryption", "Параметры шифрования");
	    c = ctrl_draglist(s, "Политика выбора шифра:", 's',
			      HELPCTX(ssh_ciphers),
			      cipherlist_handler, P(NULL));
	    c->listbox.height = 6;

	    ctrl_checkbox(s, "Разрешить использование устаревшего single-DES для SSH-2", 'i',
			  HELPCTX(ssh_ciphers),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,ssh2_des_cbc)));
	}

	/*
	 * The Connection/SSH/Kex panel. (Owing to repeat key
	 * exchange, this is all meaningful in mid-session _if_
	 * we're using SSH-2 or haven't decided yet.)
	 */
	if (protcfginfo != 1) {
	    ctrl_settitle(b, "Соединение/SSH/Обмен ключами",
			  "Параметры управления обменом SSH ключами");

	    s = ctrl_getset(b, "Соединение/SSH/Обмен ключами", "main",
			    "Алгоритмы обмена ключами");
	    c = ctrl_draglist(s, "Политика выбора алгоритма:", 's',
			      HELPCTX(ssh_kexlist),
			      kexlist_handler, P(NULL));
	    c->listbox.height = 5;

	    s = ctrl_getset(b, "Соединение/SSH/Обмен ключами", "repeat",
			    "Параметры перевыбора ключей");

	    ctrl_editbox(s, "Макс. минут до повторного обмена (0 - без лимита)", 't', 20,
			 HELPCTX(ssh_kex_repeat),
			 dlg_stdeditbox_handler,
			 I(offsetof(Config,ssh_rekey_time)),
			 I(-1));
	    ctrl_editbox(s, "Макс. данных до повторного обмена (0 - без лимита)", 'x', 20,
			 HELPCTX(ssh_kex_repeat),
			 dlg_stdeditbox_handler,
			 I(offsetof(Config,ssh_rekey_data)),
			 I(16));
	    ctrl_text(s, "(Используйте 1M для 1 мегабайта, 1G для гигабайта, и т.д.)",
		      HELPCTX(ssh_kex_repeat));
	}

	if (!midsession) {

	    /*
	     * The Connection/SSH/Auth panel.
	     */
	    ctrl_settitle(b, "Соединение/SSH/Аутентификация",
			  "Параметры управления SSH аутентификацией");

	    s = ctrl_getset(b, "Соединение/SSH/Аутентификация", "main", NULL);
	    ctrl_checkbox(s, "Обход аутентификации полностью (только для SSH-2)", 'b',
			  HELPCTX(ssh_auth_bypass),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,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)));

	    s = ctrl_getset(b, "Соединение/SSH/Аутентификация", "methods",
			    "Методы аутентификации");
	    ctrl_checkbox(s, "Пробовать аутентификацию с использованием Pageant", 'p',
			  HELPCTX(ssh_auth_pageant),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,tryagent)));
	    ctrl_checkbox(s, "Пробовать аутентификацию TIS или CryptoCard (SSH-1)", 'm',
			  HELPCTX(ssh_auth_tis),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,try_tis_auth)));
	    ctrl_checkbox(s, "Пробовать аутентификацию с \"интерактивной клавиатуры\" (SSH-2)",
			  'i', HELPCTX(ssh_auth_ki),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,try_ki_auth)));

	    s = ctrl_getset(b, "Соединение/SSH/Аутентификация", "params",
			    "Параметры аутентификации");
	    ctrl_checkbox(s, "Разрешить переадресацию агента", 'f',
			  HELPCTX(ssh_auth_agentfwd),
			  dlg_stdcheckbox_handler, I(offsetof(Config,agentfwd)));
	    ctrl_checkbox(s, "Разрешить попытку смены имени пользователя (SSH-2)", NO_SHORTCUT,
			  HELPCTX(ssh_auth_changeuser),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,change_username)));
	    ctrl_filesel(s, "Файл с секретным ключом для аутентификации:", 'k',
			 FILTER_KEY_FILES, FALSE, "Выберите файл, содержажий секретный ключ сервера",
			 HELPCTX(ssh_auth_privkey),
			 dlg_stdfilesel_handler, I(offsetof(Config, keyfile)));

#ifndef NO_GSSAPI
	    /*
	     * Connection/SSH/Auth/GSSAPI, which sadly won't fit on
	     * the main Auth panel.
	     */
	    ctrl_settitle(b, "Соединение/SSH/Аутентификация/GSSAPI",
			  "Options controlling GSSAPI authentication");
	    s = ctrl_getset(b, "Соединение/SSH/Аутентификация/GSSAPI", "gssapi", NULL);

	    ctrl_checkbox(s, "Пробовать аутентификацию GSSAPI (SSH-2)",
			  't', HELPCTX(ssh_gssapi),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,try_gssapi_auth)));

	    ctrl_checkbox(s, "Разрешить GSSAPI credential delegation", 'l',
			  HELPCTX(ssh_gssapi_delegation),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,gssapifwd)));

	    /*
	     * GSSAPI library selection.
	     */
	    if (ngsslibs > 1) {
		c = ctrl_draglist(s, "Предпочтительный порядок выбора библиотеки GSSAPI:",
				  'p', HELPCTX(ssh_gssapi_libraries),
				  gsslist_handler, P(NULL));
		c->listbox.height = ngsslibs;

		/*
		 * I currently assume that if more than one GSS
		 * library option is available, then one of them is
		 * 'user-supplied' and so we should present the
		 * following file selector. This is at least half-
		 * reasonable, because if we're using statically
		 * linked GSSAPI then there will only be one option
		 * and no way to load from a user-supplied library,
		 * whereas if we're using dynamic libraries then
		 * there will almost certainly be some default
		 * option in addition to a user-supplied path. If
		 * anyone ever ports PuTTY to a system on which
		 * dynamic-library GSSAPI is available but there is
		 * absolutely no consensus on where to keep the
		 * libraries, there'll need to be a flag alongside
		 * ngsslibs to control whether the file selector is
		 * displayed. 
		 */

		ctrl_filesel(s, "Указать собственный путь к библиотеке GSSAPI:", 's',
			     FILTER_DYNLIB_FILES, FALSE, "Выберите файл библиотеки",
			     HELPCTX(ssh_gssapi_libraries),
			     dlg_stdfilesel_handler,
			     I(offsetof(Config, ssh_gss_custom)));
	    }
#endif
	}

	if (!midsession) {
#ifdef SCPORT
          /*
           * The Connection/SSH/Pkcs11 panel.
           */
	   if( !get_param("PUTTY") ) {
          ctrl_settitle(b, "Соединение/SSH/Pkcs11",
                        "Настройка SSH аутентификации по стандарту PKCS#11");
          
          s = ctrl_getset(b, "Соединение/SSH/Pkcs11", "methods",
                          "Методы аутентификации");
          ctrl_checkbox(s, "Использовать журнала событий Windows", NO_SHORTCUT,
                        HELPCTX(ssh_write_syslog),
                        dlg_stdcheckbox_handler,
                        I(offsetof(Config,try_write_syslog)));
          ctrl_checkbox(s, "Пробовать аутентификацию \"PKCS#11 smartcard\" (SSH-2)", NO_SHORTCUT,
                        HELPCTX(ssh_auth_pkcs11),
                        dlg_stdcheckbox_handler,
                        I(offsetof(Config,try_pkcs11_auth)));
          
          s = ctrl_getset(b, "Соединение/SSH/Pkcs11", "params",
                          "Параметры аутентификации");
          ctrl_filesel(s, "Библиотека PKCS#11 для аутентификации:", NO_SHORTCUT,
                       FALSE , FALSE, "Выберите файл библиотеки PKCS#11",
                       HELPCTX(ssh_auth_pkcs11_libfile),
                       sc_dlg_stdfilesel_handler11, I(offsetof(Config, pkcs11_libfile)));
          ctrl_combobox(s, "Token label:",
                        NO_SHORTCUT, 70, HELPCTX(ssh_auth_pkcs11_token_label),
                        sc_tokenlabel_handler, P(NULL), P(NULL));
          ctrl_combobox(s, "Certificate label:",
                        NO_SHORTCUT, 70, HELPCTX(ssh_auth_pkcs11_cert_label),
                        sc_cert_handler, P(NULL), P(NULL));
		}
#endif
	    /*
	     * The Connection/SSH/TTY panel.
	     */
	    ctrl_settitle(b, "Соединение/SSH/TTY", "Параметры удалённого терминала");

	    s = ctrl_getset(b, "Соединение/SSH/TTY", "sshtty", NULL);
	    ctrl_checkbox(s, "Не выделять псевдо-терминал", 'p',
			  HELPCTX(ssh_nopty),
			  dlg_stdcheckbox_handler,
			  I(offsetof(Config,nopty)));

	    s = ctrl_getset(b, "Соединение/SSH/TTY", "ttymodes",
			    "Режимы терминала");
	    td = (struct ttymodes_data *)
		ctrl_alloc(b, sizeof(struct ttymodes_data));
	    ctrl_columns(s, 2, 75, 25);
	    c = ctrl_text(s, "Режимы терминала для передачи:", HELPCTX(ssh_ttymodes));
	    c->generic.column = 0;
	    td->rembutton = ctrl_pushbutton(s, "Удалить", 'r',
					    HELPCTX(ssh_ttymodes),
					    ttymodes_handler, P(td));
	    td->rembutton->generic.column = 1;
	    td->rembutton->generic.tabdelay = 1;
	    ctrl_columns(s, 1, 100);
	    td->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
				       HELPCTX(ssh_ttymodes),
				       ttymodes_handler, P(td));
	    td->listbox->listbox.multisel = 1;
	    td->listbox->listbox.height = 4;
	    td->listbox->listbox.ncols = 2;
	    td->listbox->listbox.percentages = snewn(2, int);
	    td->listbox->listbox.percentages[0] = 40;
	    td->listbox->listbox.percentages[1] = 60;
	    ctrl_tabdelay(s, td->rembutton);
	    ctrl_columns(s, 2, 75, 25);
	    td->modelist = ctrl_droplist(s, "Режим:", 'm', 67,
					 HELPCTX(ssh_ttymodes),
					 ttymodes_handler, P(td));
	    td->modelist->generic.column = 0;
	    td->addbutton = ctrl_pushbutton(s, "Добавить", 'd',
					    HELPCTX(ssh_ttymodes),
					    ttymodes_handler, P(td));
	    td->addbutton->generic.column = 1;
	    td->addbutton->generic.tabdelay = 1;
	    ctrl_columns(s, 1, 100);	    /* column break */
	    /* Bit of a hack to get the value radio buttons and
	     * edit-box on the same row. */
	    ctrl_columns(s, 3, 25, 50, 25);
	    c = ctrl_text(s, "Значение:", HELPCTX(ssh_ttymodes));
	    c->generic.column = 0;
	    td->valradio = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 2,
					     HELPCTX(ssh_ttymodes),
					     ttymodes_handler, P(td),
					     "Авто", NO_SHORTCUT, P(NULL),
					     "Данное:", NO_SHORTCUT, P(NULL),
					     NULL);
	    td->valradio->generic.column = 1;
	    td->valbox = ctrl_editbox(s, NULL, NO_SHORTCUT, 100,
				      HELPCTX(ssh_ttymodes),
				      ttymodes_handler, P(td), P(NULL));
	    td->valbox->generic.column = 2;
	    ctrl_tabdelay(s, td->addbutton);

	}

	if (!midsession) {
	    /*
	     * The Connection/SSH/X11 panel.
	     */
	    ctrl_settitle(b, "Соединение/SSH/X11",
			  "Настройка переадресации SSH X11");

	    s = ctrl_getset(b, "Соединение/SSH/X11", "x11", "Переадресация X11");
	    ctrl_checkbox(s, "Включить переадресацию X11", 'e',
			  HELPCTX(ssh_tunnels_x11),
			  dlg_stdcheckbox_handler,I(offsetof(Config,x11_forward)));
	    ctrl_editbox(s, "Отображение дисплея X", 'x', 50,
			 HELPCTX(ssh_tunnels_x11),
			 dlg_stdeditbox_handler, I(offsetof(Config,x11_display)),
			 I(sizeof(((Config *)0)->x11_display)));
	    ctrl_radiobuttons(s, "Протокол X11 аутентификации", 'u', 2,
			      HELPCTX(ssh_tunnels_x11auth),
			      dlg_stdradiobutton_handler,
			      I(offsetof(Config, x11_auth)),
			      "MIT-Magic-Cookie-1", I(X11_MIT),
			      "XDM-Authorization-1", I(X11_XDM), NULL);
	}

	/*
	 * The Tunnels panel _is_ still available in mid-session.
	 */
	ctrl_settitle(b, "Соединение/SSH/Туннели",
		      "Настройка переадресации SSH портов");

	s = ctrl_getset(b, "Соединение/SSH/Туннели", "portfwd",
			"Переадресации портов");
	ctrl_checkbox(s, "Разрешать локальным портам принимать соединения извне",'t',
		      HELPCTX(ssh_tunnels_portfwd_localhost),
		      dlg_stdcheckbox_handler,
		      I(offsetof(Config,lport_acceptall)));
	ctrl_checkbox(s, "Удаленные порты делают то же самое (SSH-2 only)", 'p',
		      HELPCTX(ssh_tunnels_portfwd_localhost),
		      dlg_stdcheckbox_handler,
		      I(offsetof(Config,rport_acceptall)));

	ctrl_columns(s, 3, 55, 20, 25);
	c = ctrl_text(s, "Проброшенные порты:", HELPCTX(ssh_tunnels_portfwd));
	c->generic.column = COLUMN_FIELD(0,2);
	/* You want to select from the list, _then_ hit Remove. So tab order
	 * should be that way round. */
	pfd = (struct portfwd_data *)ctrl_alloc(b,sizeof(struct portfwd_data));
	pfd->rembutton = ctrl_pushbutton(s, "Удалить", 'r',
					 HELPCTX(ssh_tunnels_portfwd),
					 portfwd_handler, P(pfd));
	pfd->rembutton->generic.column = 2;
	pfd->rembutton->generic.tabdelay = 1;
	pfd->listbox = ctrl_listbox(s, NULL, NO_SHORTCUT,
				    HELPCTX(ssh_tunnels_portfwd),
				    portfwd_handler, P(pfd));
	pfd->listbox->listbox.height = 3;
	pfd->listbox->listbox.ncols = 2;
	pfd->listbox->listbox.percentages = snewn(2, int);
	pfd->listbox->listbox.percentages[0] = 20;
	pfd->listbox->listbox.percentages[1] = 80;
	ctrl_tabdelay(s, pfd->rembutton);
	ctrl_text(s, "Добавить новый проброс порта:", HELPCTX(ssh_tunnels_portfwd));
	/* You want to enter source, destination and type, _then_ hit Add.
	 * Again, we adjust the tab order to reflect this. */
	pfd->addbutton = ctrl_pushbutton(s, "Добавить", 'd',
					 HELPCTX(ssh_tunnels_portfwd),
					 portfwd_handler, P(pfd));
	pfd->addbutton->generic.column = 2;
	pfd->addbutton->generic.tabdelay = 1;
	pfd->sourcebox = ctrl_editbox(s, "Порт отправителя", 's', 40,
				      HELPCTX(ssh_tunnels_portfwd),
				      portfwd_handler, P(pfd), P(NULL));
	pfd->sourcebox->generic.column = 0;
	pfd->destbox = ctrl_editbox(s, "Назначение", 'i', 67,
				    HELPCTX(ssh_tunnels_portfwd),
				    portfwd_handler, P(pfd), P(NULL));
	pfd->direction = ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
					   HELPCTX(ssh_tunnels_portfwd),
					   portfwd_handler, P(pfd),
					   "Локальный", 'l', P(NULL),
					   "Удалённый", 'm', P(NULL),
					   "Динамический", 'y', P(NULL),
					   NULL);
#ifndef NO_IPV6
	pfd->addressfamily =
	    ctrl_radiobuttons(s, NULL, NO_SHORTCUT, 3,
			      HELPCTX(ssh_tunnels_portfwd_ipversion),
			      portfwd_handler, P(pfd),
			      "Авто", 'u', I(ADDRTYPE_UNSPEC),
			      "IPv4", '4', I(ADDRTYPE_IPV4),
			      "IPv6", '6', I(ADDRTYPE_IPV6),
			      NULL);
#endif
	ctrl_tabdelay(s, pfd->addbutton);
	ctrl_columns(s, 1, 100);

	if (!midsession) {
	    /*
	     * The Connection/SSH/Bugs panel.
	     */
	    ctrl_settitle(b, "Соединение/SSH/Заплатки",
			  "Методы обхода ошибок популярных SSH-серверов");

	    s = ctrl_getset(b, "Соединение/SSH/Заплатки", "main",
			    "Детектирование известных багов в SSH серверах");
	    ctrl_droplist(s, "Chokes on SSH-1 ignore messages", 'i', 20,
			  HELPCTX(ssh_bugs_ignore1),
			  sshbug_handler, I(offsetof(Config,sshbug_ignore1)));
	    ctrl_droplist(s, "Refuses all SSH-1 password camouflage", 's', 20,
			  HELPCTX(ssh_bugs_plainpw1),
			  sshbug_handler, I(offsetof(Config,sshbug_plainpw1)));
	    ctrl_droplist(s, "Chokes on SSH-1 RSA authentication", 'r', 20,
			  HELPCTX(ssh_bugs_rsa1),
			  sshbug_handler, I(offsetof(Config,sshbug_rsa1)));
	    ctrl_droplist(s, "Chokes on SSH-2 ignore messages", '2', 20,
			  HELPCTX(ssh_bugs_ignore2),
			  sshbug_handler, I(offsetof(Config,sshbug_ignore2)));
	    ctrl_droplist(s, "Miscomputes SSH-2 HMAC keys", 'm', 20,
			  HELPCTX(ssh_bugs_hmac2),
			  sshbug_handler, I(offsetof(Config,sshbug_hmac2)));
	    ctrl_droplist(s, "Miscomputes SSH-2 encryption keys", 'e', 20,
			  HELPCTX(ssh_bugs_derivekey2),
			  sshbug_handler, I(offsetof(Config,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)));
	    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)));
	    ctrl_droplist(s, "Handles SSH-2 key re-exchange badly", 'k', 20,
			  HELPCTX(ssh_bugs_rekey2),
			  sshbug_handler, I(offsetof(Config,sshbug_rekey2)));
	    ctrl_droplist(s, "Ignores SSH-2 maximum packet size", 'x', 20,
			  HELPCTX(ssh_bugs_maxpkt2),
			  sshbug_handler, I(offsetof(Config,sshbug_maxpkt2)));
	}
    }
#ifdef ZMODEMPORT
    // z-modem panel
     if( (!get_param("PUTTY"))&&get_param("ZMODEM") ) {
    ctrl_settitle(b, "Соединение/ZModem",
		      "Настройка передачи данных по протоколу Z Modem");

    s = ctrl_getset(b, "Соединение/ZModem", "receive",
			"Получение команд");

    ctrl_filesel(s, "Команда:", NO_SHORTCUT,
		 FILTER_EXE_FILES, FALSE, "Выберите команду для получения данных по zmodem",
		 HELPCTX(zmodem_rzcommand),
		 dlg_stdfilesel_handler, I(offsetof(Config, rzcommand)));

    ctrl_editbox(s, "Параметры", NO_SHORTCUT, 
		     50,
		     HELPCTX(zmodem_rzoptions),
		     dlg_stdeditbox_handler, I(offsetof(Config,rzoptions)),
		     I(sizeof(((Config *)0)->rzoptions)));

    s = ctrl_getset(b, "Соединение/ZModem", "send",
			"Отправка команд");

    ctrl_filesel(s, "Команда:", NO_SHORTCUT,
		 FILTER_EXE_FILES, FALSE, "Выберите команду для отправки по даннх по zmodem",
		 HELPCTX(zmodem_szcommand),
		 dlg_stdfilesel_handler, I(offsetof(Config, szcommand)));
    ctrl_editbox(s, "Параметры", NO_SHORTCUT, 
		     50,
		     HELPCTX(zmodem_szoptions),
		     dlg_stdeditbox_handler, I(offsetof(Config,szoptions)),
		     I(sizeof(((Config *)0)->szoptions)));

   s = ctrl_getset(b, "Соединение/ZModem", "download",
			"Путь для сохранения файлов folder");

    ctrl_directorysel(s, "Расположение:", NO_SHORTCUT,
		 "Выберите папку для загрузок",
		 HELPCTX(zmodem_zdownloaddir),
		 dlg_stddirectorysel_handler, I(offsetof(Config, zdownloaddir)));

	}
#endif
}
