Jacob's patch for a drag-list to select SSH ciphers. Heavily hacked
[u/mdw/putty] / windlg.c
index 1e5a632..026e35c 100644 (file)
--- a/windlg.c
+++ b/windlg.c
@@ -18,6 +18,8 @@ static int nevents = 0, negsize = 0;
 static int readytogo;
 static int sesslist_has_focus;
 
+static struct prefslist cipherlist;
+
 void force_normal(HWND hwnd)
 {
     static int recurse = 0;
@@ -435,25 +437,31 @@ enum { IDCX_ABOUT =
     IDC_BOX_SSH2,
     IDC_BOX_SSH3,
     IDC_NOPTY,
-    IDC_CIPHERSTATIC,
-    IDC_CIPHER3DES,
-    IDC_CIPHERBLOWF,
-    IDC_CIPHERDES,
-    IDC_CIPHERAES,
+    IDC_BOX_SSHCIPHER,
+    IDC_CIPHERSTATIC2,
+    IDC_CIPHERLIST,
+    IDC_CIPHERUP,
+    IDC_CIPHERDN,
     IDC_BUGGYMAC,
-    IDC_AUTHTIS,
-    IDC_PKSTATIC,
-    IDC_PKEDIT,
-    IDC_PKBUTTON,
     IDC_SSHPROTSTATIC,
     IDC_SSHPROT1,
     IDC_SSHPROT2,
-    IDC_AGENTFWD,
     IDC_CMDSTATIC,
     IDC_CMDEDIT,
     IDC_COMPRESS,
     sshpanelend,
 
+    sshauthpanelstart,
+    IDC_TITLE_SSHAUTH,
+    IDC_BOX_SSHAUTH1,
+    IDC_BOX_SSHAUTH2,
+    IDC_PKSTATIC,
+    IDC_PKEDIT,
+    IDC_PKBUTTON,
+    IDC_AGENTFWD,
+    IDC_AUTHTIS,
+    sshauthpanelend,
+
     selectionpanelstart,
     IDC_TITLE_SELECTION,
     IDC_BOX_SELECTION1,
@@ -503,10 +511,24 @@ enum { IDCX_ABOUT =
 
     tunnelspanelstart,
     IDC_TITLE_TUNNELS,
-    IDC_BOX_TUNNELS,
+    IDC_BOX_TUNNELS1,
+    IDC_BOX_TUNNELS2,
     IDC_X11_FORWARD,
     IDC_X11_DISPSTATIC,
     IDC_X11_DISPLAY,
+    IDC_LPORT_ALL,
+    IDC_PFWDSTATIC,
+    IDC_PFWDSTATIC2,
+    IDC_PFWDREMOVE,
+    IDC_PFWDLIST,
+    IDC_PFWDADD,
+    IDC_SPORTSTATIC,
+    IDC_SPORTEDIT,
+    IDC_DPORTSTATIC,
+    IDC_DPORTEDIT,
+    IDC_PFWDLOCAL,
+    IDC_PFWDREMOTE,
+
     tunnelspanelend,
 
     controlendvalue
@@ -663,11 +685,18 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
                     IDC_LSTATXAPN);
     {
        char *p = cfg.environmt;
+       SendDlgItemMessage(hwnd, IDC_ENVLIST, LB_RESETCONTENT, 0, 0);
        while (*p) {
            SendDlgItemMessage(hwnd, IDC_ENVLIST, LB_ADDSTRING, 0,
                               (LPARAM) p);
            p += strlen(p) + 1;
        }
+       p = cfg.portfwd;
+       while (*p) {
+           SendDlgItemMessage(hwnd, IDC_PFWDLIST, LB_ADDSTRING, 0,
+                              (LPARAM) p);
+           p += strlen(p) + 1;
+       }
     }
     CheckRadioButton(hwnd, IDC_EMBSD, IDC_EMRFC,
                     cfg.rfc_environ ? IDC_EMRFC : IDC_EMBSD);
@@ -680,17 +709,48 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
     CheckDlgButton(hwnd, IDC_COMPRESS, cfg.compression);
     CheckDlgButton(hwnd, IDC_BUGGYMAC, cfg.buggymac);
     CheckDlgButton(hwnd, IDC_AGENTFWD, cfg.agentfwd);
-    CheckRadioButton(hwnd, IDC_CIPHER3DES, IDC_CIPHERAES,
-                    cfg.cipher == CIPHER_BLOWFISH ? IDC_CIPHERBLOWF :
-                    cfg.cipher == CIPHER_DES ? IDC_CIPHERDES :
-                    cfg.cipher == CIPHER_AES ? IDC_CIPHERAES :
-                    IDC_CIPHER3DES);
     CheckRadioButton(hwnd, IDC_SSHPROT1, IDC_SSHPROT2,
                     cfg.sshprot == 1 ? IDC_SSHPROT1 : IDC_SSHPROT2);
     CheckDlgButton(hwnd, IDC_AUTHTIS, cfg.try_tis_auth);
     SetDlgItemText(hwnd, IDC_PKEDIT, cfg.keyfile);
     SetDlgItemText(hwnd, IDC_CMDEDIT, cfg.remote_cmd);
 
+    {
+       int i;
+       static const struct { char *s; int c; } ciphers[] = {
+           { "3DES",                   CIPHER_3DES },
+           { "Blowfish",               CIPHER_BLOWFISH },
+           { "DES (SSH 1 only)",       CIPHER_DES },
+           { "AES (SSH 2 only)",       CIPHER_AES },
+           { "-- warn below here --",  CIPHER_WARN }
+       };
+
+       /* Set up the "selected ciphers" box. */
+       /* (cipherlist assumed to contain all ciphers) */
+       SendDlgItemMessage(hwnd, IDC_CIPHERLIST, LB_RESETCONTENT, 0, 0);
+       for (i = 0; i < CIPHER_MAX; i++) {
+           int c = cfg.ssh_cipherlist[i];
+           int j, pos;
+           char *cstr = NULL;
+           for (j = 0; j < (sizeof ciphers) / (sizeof ciphers[0]); j++) {
+               if (ciphers[j].c == c) {
+                   cstr = ciphers[j].s;
+                   break;
+               }
+           }
+           pos = SendDlgItemMessage(hwnd, IDC_CIPHERLIST, LB_ADDSTRING,
+                                    0, (LPARAM) cstr);
+           SendDlgItemMessage(hwnd, IDC_CIPHERLIST, LB_SETITEMDATA,
+                              pos, (LPARAM) c);
+       }
+       SendDlgItemMessage(hwnd, IDC_CIPHERLIST, LB_ADDSTRING,
+                          0, (LPARAM) "FIXME1");
+       SendDlgItemMessage(hwnd, IDC_CIPHERLIST, LB_ADDSTRING,
+                          0, (LPARAM) "FIXME2");
+
+    }
+
+
     CheckRadioButton(hwnd, IDC_MBWINDOWS, IDC_MBXTERM,
                     cfg.mouse_is_xterm ? IDC_MBXTERM : IDC_MBWINDOWS);
     CheckDlgButton(hwnd, IDC_RAWCNP, cfg.rawcnp);
@@ -725,7 +785,20 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
     SetDlgItemInt(hwnd, IDC_GVALUE, cfg.colours[0][1], FALSE);
     SetDlgItemInt(hwnd, IDC_BVALUE, cfg.colours[0][2], FALSE);
 
-    SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage);
+    {
+       int i;
+       char *cp;
+       int index = 0;
+       SendDlgItemMessage(hwnd, IDC_CODEPAGE, CB_RESETCONTENT, 0, 0);
+       for (i = 0; (cp = cp_enumerate(i)) != NULL; i++) {
+           SendDlgItemMessage(hwnd, IDC_CODEPAGE, CB_ADDSTRING,
+                              0, (LPARAM) cp);
+           if (!strcmp(cp, cfg.line_codepage))
+               index = i;
+       }
+       SendDlgItemMessage(hwnd, IDC_CODEPAGE, CB_SETCURSEL, index, 0);
+    }
+    
     CheckRadioButton(hwnd, IDC_VTXWINDOWS, IDC_VTUNICODE,
                     cfg.vtmode == VT_XWINDOWS ? IDC_VTXWINDOWS :
                     cfg.vtmode == VT_OEMANSI ? IDC_VTOEMANSI :
@@ -735,6 +808,9 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
 
     CheckDlgButton(hwnd, IDC_X11_FORWARD, cfg.x11_forward);
     SetDlgItemText(hwnd, IDC_X11_DISPLAY, cfg.x11_display);
+
+    CheckDlgButton(hwnd, IDC_LPORT_ALL, cfg.lport_acceptall);
+    CheckRadioButton(hwnd, IDC_PFWDLOCAL, IDC_PFWDREMOTE, IDC_PFWDLOCAL);
 }
 
 struct treeview_faff {
@@ -779,10 +855,11 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
        bartitle(&cp, "Basic options for your PuTTY session",
                 IDC_TITLE_SESSION);
        if (dlgtype == 0) {
-           beginbox(&cp, "Specify your connection by host name",
+           beginbox(&cp, "Specify your connection by host name or IP address",
                     IDC_BOX_SESSION1);
            multiedit(&cp,
-                     "Host &Name", IDC_HOSTSTATIC, IDC_HOST, 75,
+                     "Host &Name (or IP address)",
+                     IDC_HOSTSTATIC, IDC_HOST, 75,
                      "&Port", IDC_PORTSTATIC, IDC_PORT, 25, NULL);
            if (backends[3].backend == NULL) {
                /* this is PuTTYtel, so only three protocols available */
@@ -1029,10 +1106,11 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
                 "&Poor man's line drawing (" "+" ", " "-" " and " "|" ")",
                 IDC_VTPOORMAN, "&Unicode mode", IDC_VTUNICODE, NULL);
        endbox(&cp);
-       beginbox(&cp, "Enable character set translation on received data",
+       beginbox(&cp, "Character set translation on received data",
                 IDC_BOX_TRANSLATION2);
-       multiedit(&cp, "Line codepage:", IDC_CODEPAGESTATIC,
-                 IDC_CODEPAGE, 100, NULL);
+       dropdownlist(&cp,
+                    "Received data assumed to be in which character set:",
+                    IDC_CODEPAGESTATIC, IDC_CODEPAGE);
        endbox(&cp);
     }
 
@@ -1158,7 +1236,7 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
     }
 
     if (panel == sshpanelstart) {
-       /* The SSH panel. Accelerators used: [acgo] rmfkw pe123bds i */
+       /* The SSH panel. Accelerators used: [acgo] r pe12i sud */
        struct ctlpos cp;
        ctlposinit(&cp, hwnd, 80, 3, 13);
        if (dlgtype == 0) {
@@ -1169,42 +1247,70 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
                      "&Remote command:", IDC_CMDSTATIC, IDC_CMDEDIT, 100,
                      NULL);
            endbox(&cp);
-           beginbox(&cp, "Authentication options", IDC_BOX_SSH2);
-           checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
-                    IDC_AUTHTIS);
-           checkbox(&cp, "Allow agent &forwarding", IDC_AGENTFWD);
-           editbutton(&cp, "Private &key file for authentication:",
-                      IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...",
-                      IDC_PKBUTTON);
-           endbox(&cp);
-           beginbox(&cp, "Protocol options", IDC_BOX_SSH3);
+           beginbox(&cp, "Protocol options", IDC_BOX_SSH2);
            checkbox(&cp, "Don't allocate a &pseudo-terminal", IDC_NOPTY);
            checkbox(&cp, "Enable compr&ession", IDC_COMPRESS);
            radioline(&cp, "Preferred SSH protocol version:",
                      IDC_SSHPROTSTATIC, 2,
                      "&1", IDC_SSHPROT1, "&2", IDC_SSHPROT2, NULL);
-           radioline(&cp, "Preferred encryption algorithm:",
-                     IDC_CIPHERSTATIC, 4, "&3DES", IDC_CIPHER3DES,
-                     "&Blowfish", IDC_CIPHERBLOWF, "&DES", IDC_CIPHERDES,
-                     "AE&S", IDC_CIPHERAES, NULL);
            checkbox(&cp, "&Imitate SSH 2 MAC bug in commercial <= v2.3.x",
                     IDC_BUGGYMAC);
            endbox(&cp);
+           beginbox(&cp, "Encryption options", IDC_BOX_SSH3);
+           prefslist(&cipherlist, &cp, "Encryption cipher &selection policy:",
+                     IDC_CIPHERSTATIC2, IDC_CIPHERLIST, IDC_CIPHERUP,
+                     IDC_CIPHERDN);
+           endbox(&cp);
+       }
+    }
+
+    if (panel == sshauthpanelstart) {
+       /* The SSH authentication panel. Accelerators used: [acgo] m fkw */
+       struct ctlpos cp;
+       ctlposinit(&cp, hwnd, 80, 3, 13);
+       if (dlgtype == 0) {
+           bartitle(&cp, "Options controlling SSH authentication",
+                    IDC_TITLE_SSHAUTH);
+           beginbox(&cp, "Authentication methods",
+                    IDC_BOX_SSHAUTH1);
+           checkbox(&cp, "Atte&mpt TIS or CryptoCard authentication",
+                    IDC_AUTHTIS);
+           endbox(&cp);
+           beginbox(&cp, "Authentication parameters",
+                    IDC_BOX_SSHAUTH2);
+           checkbox(&cp, "Allow agent &forwarding", IDC_AGENTFWD);
+           editbutton(&cp, "Private &key file for authentication:",
+                      IDC_PKSTATIC, IDC_PKEDIT, "Bro&wse...",
+                      IDC_PKBUTTON);
+           endbox(&cp);
        }
     }
 
     if (panel == tunnelspanelstart) {
-       /* The Tunnels panel. Accelerators used: [acgo] ex */
+       /* The Tunnels panel. Accelerators used: [acgo] deilmrstx */
        struct ctlpos cp;
        ctlposinit(&cp, hwnd, 80, 3, 13);
        if (dlgtype == 0) {
            bartitle(&cp, "Options controlling SSH tunnelling",
                     IDC_TITLE_TUNNELS);
-           beginbox(&cp, "X11 forwarding options", IDC_BOX_TUNNELS);
+           beginbox(&cp, "X11 forwarding", IDC_BOX_TUNNELS1);
            checkbox(&cp, "&Enable X11 forwarding", IDC_X11_FORWARD);
            multiedit(&cp, "&X display location", IDC_X11_DISPSTATIC,
                      IDC_X11_DISPLAY, 50, NULL);
            endbox(&cp);
+           beginbox(&cp, "Port forwarding", IDC_BOX_TUNNELS2);
+           checkbox(&cp, "Local ports accept connections from o&ther hosts", IDC_LPORT_ALL);
+           staticbtn(&cp, "Forwarded ports:", IDC_PFWDSTATIC,
+                     "&Remove", IDC_PFWDREMOVE);
+           fwdsetter(&cp, IDC_PFWDLIST,
+                     "Add new forwarded port:", IDC_PFWDSTATIC2,
+                     "&Source port", IDC_SPORTSTATIC, IDC_SPORTEDIT,
+                     "Dest&ination", IDC_DPORTSTATIC, IDC_DPORTEDIT,
+                     "A&dd", IDC_PFWDADD);
+           bareradioline(&cp, 2,
+                         "&Local", IDC_PFWDLOCAL, "Re&mote", IDC_PFWDREMOTE, NULL);
+           endbox(&cp);
+
        }
     }
 }
@@ -1253,6 +1359,7 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
     char portname[32];
     struct servent *service;
     int i;
+    static UINT draglistmsg = WM_NULL;
 
     switch (msg) {
       case WM_INITDIALOG:
@@ -1335,6 +1442,9 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
            treeview_insert(&tvfaff, 1, "Rlogin");
            if (backends[3].backend != NULL) {
                treeview_insert(&tvfaff, 1, "SSH");
+               /* XXX long name is ugly */
+               /* XXX make it closed by default? */
+               treeview_insert(&tvfaff, 2, "Auth");
                treeview_insert(&tvfaff, 2, "Tunnels");
            }
        }
@@ -1410,6 +1520,8 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                create_controls(hwnd, dlgtype, rloginpanelstart);
            if (!strcmp(buffer, "SSH"))
                create_controls(hwnd, dlgtype, sshpanelstart);
+           if (!strcmp(buffer, "Auth"))
+               create_controls(hwnd, dlgtype, sshauthpanelstart);
            if (!strcmp(buffer, "Selection"))
                create_controls(hwnd, dlgtype, selectionpanelstart);
            if (!strcmp(buffer, "Colours"))
@@ -2171,21 +2283,12 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                        cfg.agentfwd =
                        IsDlgButtonChecked(hwnd, IDC_AGENTFWD);
                break;
-             case IDC_CIPHER3DES:
-             case IDC_CIPHERBLOWF:
-             case IDC_CIPHERDES:
-             case IDC_CIPHERAES:
-               if (HIWORD(wParam) == BN_CLICKED ||
-                   HIWORD(wParam) == BN_DOUBLECLICKED) {
-                   if (IsDlgButtonChecked(hwnd, IDC_CIPHER3DES))
-                       cfg.cipher = CIPHER_3DES;
-                   else if (IsDlgButtonChecked(hwnd, IDC_CIPHERBLOWF))
-                       cfg.cipher = CIPHER_BLOWFISH;
-                   else if (IsDlgButtonChecked(hwnd, IDC_CIPHERDES))
-                       cfg.cipher = CIPHER_DES;
-                   else if (IsDlgButtonChecked(hwnd, IDC_CIPHERAES))
-                       cfg.cipher = CIPHER_AES;
-               }
+             case IDC_CIPHERLIST:
+             case IDC_CIPHERUP:
+             case IDC_CIPHERDN:
+               handle_prefslist(&cipherlist,
+                                cfg.ssh_cipherlist, CIPHER_MAX,
+                                0, hwnd, wParam, lParam);
                break;
              case IDC_SSHPROT1:
              case IDC_SSHPROT2:
@@ -2354,28 +2457,11 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                }
                break;
              case IDC_CODEPAGE:
-               if (HIWORD(wParam) == EN_CHANGE)
-                   GetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage,
-                                  sizeof(cfg.line_codepage) - 1);
-               if (HIWORD(wParam) == EN_KILLFOCUS) {
-                   int cp = decode_codepage(cfg.line_codepage);
-                   char buf[256];
-                   if (cp < -1) {
-                       if (cp == -2)
-                           sprintf(buf,
-                                   "Unable to identify character set '%s', "
-                                   "translation disabled.",
-                                   cfg.line_codepage);
-                       if (cp == -3)
-                           sprintf(buf,
-                                   "Character set '%s' is a DBCS, "
-                                   "translation is not available.",
-                                   cfg.line_codepage);
-                       MessageBox(hwnd, buf, "PuTTY Error",
-                                  MB_ICONERROR | MB_OK);
-                   }
-                   strcpy(cfg.line_codepage, cp_name(cp));
-                   SetDlgItemText(hwnd, IDC_CODEPAGE, cfg.line_codepage);
+               if (HIWORD(wParam) == CBN_SELCHANGE) {
+                   int index = SendDlgItemMessage(hwnd, IDC_CODEPAGE,
+                                                  CB_GETCURSEL, 0, 0);
+                   SendDlgItemMessage(hwnd, IDC_CODEPAGE, CB_GETLBTEXT,
+                                      index, (LPARAM)cfg.line_codepage);
                }
                break;
              case IDC_VTXWINDOWS:
@@ -2399,11 +2485,101 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
                        cfg.x11_forward =
                        IsDlgButtonChecked(hwnd, IDC_X11_FORWARD);
                break;
+             case IDC_LPORT_ALL:
+               if (HIWORD(wParam) == BN_CLICKED ||
+                   HIWORD(wParam) == BN_DOUBLECLICKED)
+                       cfg.lport_acceptall =
+                       IsDlgButtonChecked(hwnd, IDC_LPORT_ALL);
+               break;
              case IDC_X11_DISPLAY:
                if (HIWORD(wParam) == EN_CHANGE)
                    GetDlgItemText(hwnd, IDC_X11_DISPLAY, cfg.x11_display,
                                   sizeof(cfg.x11_display) - 1);
                break;
+             case IDC_PFWDADD:
+               if (HIWORD(wParam) == BN_CLICKED ||
+                   HIWORD(wParam) == BN_DOUBLECLICKED) {
+                   char str[sizeof(cfg.portfwd)];
+                   char *p;
+                   if (IsDlgButtonChecked(hwnd, IDC_PFWDLOCAL))
+                       str[0] = 'L';
+                   else
+                       str[0] = 'R';
+                   GetDlgItemText(hwnd, IDC_SPORTEDIT, str+1,
+                                  sizeof(str) - 2);
+                   if (!str[1]) {
+                       MessageBox(hwnd,
+                                  "You need to specify a source port number",
+                                  "PuTTY Error", MB_OK | MB_ICONERROR);
+                       break;
+                   }
+                   p = str + strlen(str);
+                   *p++ = '\t';
+                   GetDlgItemText(hwnd, IDC_DPORTEDIT, p,
+                                  sizeof(str) - 1 - (p - str));
+                   if (!*p || !strchr(p, ':')) {
+                       MessageBox(hwnd,
+                                  "You need to specify a destination address\n"
+                                  "in the form \"host.name:port\"",
+                                  "PuTTY Error", MB_OK | MB_ICONERROR);
+                       break;
+                   }
+                   p = cfg.portfwd;
+                   while (*p) {
+                       while (*p)
+                           p++;
+                       p++;
+                   }
+                   if ((p - cfg.portfwd) + strlen(str) + 2 <
+                       sizeof(cfg.portfwd)) {
+                       strcpy(p, str);
+                       p[strlen(str) + 1] = '\0';
+                       SendDlgItemMessage(hwnd, IDC_PFWDLIST, LB_ADDSTRING,
+                                          0, (LPARAM) str);
+                       SetDlgItemText(hwnd, IDC_SPORTEDIT, "");
+                       SetDlgItemText(hwnd, IDC_DPORTEDIT, "");
+                   } else {
+                       MessageBox(hwnd, "Too many forwardings",
+                                  "PuTTY Error", MB_OK | MB_ICONERROR);
+                   }
+               }
+               break;
+             case IDC_PFWDREMOVE:
+               if (HIWORD(wParam) != BN_CLICKED &&
+                   HIWORD(wParam) != BN_DOUBLECLICKED) break;
+               i = SendDlgItemMessage(hwnd, IDC_PFWDLIST,
+                                      LB_GETCURSEL, 0, 0);
+               if (i == LB_ERR)
+                   MessageBeep(0);
+               else {
+                   char *p, *q;
+
+                   SendDlgItemMessage(hwnd, IDC_PFWDLIST, LB_DELETESTRING,
+                                      i, 0);
+                   p = cfg.portfwd;
+                   while (i > 0) {
+                       if (!*p)
+                           goto disaster2;
+                       while (*p)
+                           p++;
+                       p++;
+                       i--;
+                   }
+                   q = p;
+                   if (!*p)
+                       goto disaster2;
+                   while (*p)
+                       p++;
+                   p++;
+                   while (*p) {
+                       while (*p)
+                           *q++ = *p++;
+                       *q++ = *p++;
+                   }
+                   *q = '\0';
+                 disaster2:;
+               }
+               break;
            }
        return 0;
       case WM_CLOSE:
@@ -2415,6 +2591,26 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
        if (wParam == SIZE_MAXIMIZED)
            force_normal(hwnd);
        return 0;
+
+      default:
+       /*
+        * Handle application-defined messages eg. DragListBox
+        */
+       /* First find out what the number is (once). */
+       if (draglistmsg == WM_NULL)
+           draglistmsg = RegisterWindowMessage (DRAGLISTMSGSTRING);
+
+       if (msg == draglistmsg) {
+           /* Only process once dialog is fully formed. */
+           if (GetWindowLong(hwnd, GWL_USERDATA) == 1) switch (LOWORD(wParam)) {
+             case IDC_CIPHERLIST:
+               return handle_prefslist(&cipherlist,
+                                       cfg.ssh_cipherlist, CIPHER_MAX,
+                                       1, hwnd, wParam, lParam);
+           }
+       }
+       return 0;
+
     }
     return 0;
 }
@@ -2426,8 +2622,7 @@ static int CALLBACK MainDlgProc(HWND hwnd, UINT msg,
     }
     if (msg == WM_COMMAND && LOWORD(wParam) == IDCX_ABOUT) {
        EnableWindow(hwnd, 0);
-       DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
-                 GetParent(hwnd), AboutProc);
+       DialogBox(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd, AboutProc);
        EnableWindow(hwnd, 1);
        SetActiveWindow(hwnd);
     }
@@ -2452,6 +2647,7 @@ void defuse_showwindow(void)
        hwnd = CreateDialog(hinst, MAKEINTRESOURCE(IDD_ABOUTBOX),
                            NULL, NullDlgProc);
        ShowWindow(hwnd, SW_HIDE);
+       SetActiveWindow(hwnd);
        DestroyWindow(hwnd);
     }
 }
@@ -2597,6 +2793,36 @@ void verify_ssh_host_key(char *host, int port, char *keytype,
 }
 
 /*
+ * Ask whether the selected cipher is acceptable (since it was
+ * below the configured 'warn' threshold).
+ * cs: 0 = both ways, 1 = client->server, 2 = server->client
+ */
+void askcipher(char *ciphername, int cs)
+{
+    static const char mbtitle[] = "PuTTY Security Alert";
+    static const char msg[] =
+       "The first %.35scipher supported by the server\n"
+       "is %.64s, which is below the configured\n"
+       "warning threshold.\n"
+       "Do you want to continue with this connection?\n";
+    /* guessed cipher name + type max length */
+    char message[100 + sizeof(msg)];
+    int mbret;
+
+    sprintf(message, msg,
+           (cs == 0) ? "" :
+           (cs == 1) ? "client-to-server " :
+                       "server-to-client ",
+           ciphername);
+    mbret = MessageBox(NULL, message, mbtitle,
+                      MB_ICONWARNING | MB_YESNO);
+    if (mbret == IDYES)
+       return;
+    else
+       exit(0);
+}
+
+/*
  * Ask whether to wipe a session log file before writing to it.
  * Returns 2 for wipe, 1 for append, 0 for cancel (don't log).
  */