Turned the old `Telnet Command' System-submenu into a more general
[u/mdw/putty] / window.c
index 4bfec69..96ce4ad 100644 (file)
--- a/window.c
+++ b/window.c
 #define IDM_RECONF    0x0040
 #define IDM_CLRSB     0x0050
 #define IDM_RESET     0x0060
-#define IDM_TEL_AYT   0x0070
-#define IDM_TEL_BRK   0x0080
-#define IDM_TEL_SYNCH 0x0090
-#define IDM_TEL_EC    0x00a0
-#define IDM_TEL_EL    0x00b0
-#define IDM_TEL_GA    0x00c0
-#define IDM_TEL_NOP   0x00d0
-#define IDM_TEL_ABORT 0x00e0
-#define IDM_TEL_AO    0x00f0
-#define IDM_TEL_IP    0x0100
-#define IDM_TEL_SUSP  0x0110
-#define IDM_TEL_EOR   0x0120
-#define IDM_TEL_EOF   0x0130
 #define IDM_HELP      0x0140
 #define IDM_ABOUT     0x0150
 #define IDM_SAVEDSESS 0x0160
 #define IDM_SESSLGP   0x0250          /* log type printable */
 #define IDM_SESSLGA   0x0260          /* log type all chars */
 #define IDM_SESSLGE   0x0270          /* log end */
+
+#define IDM_SPECIAL_MIN 0x0400
+#define IDM_SPECIAL_MAX 0x0800
+
 #define IDM_SAVED_MIN 0x1000
 #define IDM_SAVED_MAX 0x2000
 
@@ -78,6 +69,7 @@
 #define WHEEL_DELTA 120
 #endif
 
+static Mouse_Button translate_button(Mouse_Button button);
 static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                        unsigned char *output);
@@ -87,7 +79,6 @@ static void init_fonts(int, int);
 static void another_font(int);
 static void deinit_fonts(void);
 static void set_input_locale(HKL);
-static int do_mouse_wheel_msg(UINT message, WPARAM wParam, LPARAM lParam);
 
 static int is_full_screen(void);
 static void make_full_screen(void);
@@ -121,8 +112,14 @@ static void *ldisc;
 static Backend *back;
 static void *backhandle;
 
+static struct unicode_data ucsdata;
 static int session_closed;
 
+static const struct telnet_special *specials;
+static int specials_menu_position;
+
+Config cfg;                           /* exported to windlg.c */
+
 extern struct sesslist sesslist;       /* imported from windlg.c */
 
 #define FONT_NORMAL 0
@@ -270,8 +267,17 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        char *p;
        int got_host = 0;
 
-       default_protocol = DEFAULT_PROTOCOL;
-       default_port = DEFAULT_PORT;
+       default_protocol = be_default_protocol;
+       /* Find the appropriate default port. */
+       {
+           int i;
+           default_port = 0; /* illegal */
+           for (i = 0; backends[i].backend != NULL; i++)
+               if (backends[i].protocol == default_protocol) {
+                   default_port = backends[i].backend->default_port;
+                   break;
+               }
+       }
        cfg.logtype = LGTYP_NONE;
 
        do_defaults(NULL, &cfg);
@@ -330,7 +336,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                char *p = argv[i];
                int ret;
 
-               ret = cmdline_process_param(p, i+1<argc?argv[i+1]:NULL, 1);
+               ret = cmdline_process_param(p, i+1<argc?argv[i+1]:NULL,
+                                           1, &cfg);
                if (ret == -2) {
                    cmdline_error("option \"%s\" requires an argument", p);
                } else if (ret == 2) {
@@ -366,7 +373,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                         * argument, so that it will be deferred
                         * until it's a good moment to run it.
                         */
-                       int ret = cmdline_process_param("-P", p, 1);
+                       int ret = cmdline_process_param("-P", p, 1, &cfg);
                        assert(ret == 2);
                    } else if (!strncmp(q, "telnet:", 7)) {
                        /*
@@ -412,7 +419,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
            }
        }
 
-       cmdline_run_saved();
+       cmdline_run_saved(&cfg);
 
        if (!*cfg.host && !do_config()) {
            WSACleanup();
@@ -506,8 +513,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 
     hwnd = NULL;
 
-    term = term_init(&cfg, NULL);
-    logctx = log_init(NULL);
+    memset(&ucsdata, 0, sizeof(ucsdata));
+
+    term = term_init(&cfg, &ucsdata, NULL);
+    logctx = log_init(NULL, &cfg);
     term_provide_logctx(term, logctx);
 
     cfgtopalette();
@@ -585,7 +594,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     {
        char *bits;
        int size = (font_width + 15) / 16 * 2 * font_height;
-       bits = smalloc(size);
+       bits = snewn(size, char);
        memset(bits, 0, size);
        caretbm = CreateBitmap(font_width, font_height, 1, 1, bits);
        sfree(bits);
@@ -615,7 +624,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        char msg[1024], *title;
        char *realhost;
 
-       error = back->init((void *)term, &backhandle,
+       error = back->init((void *)term, &backhandle, &cfg,
                           cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
        back->provide_logctx(backhandle, logctx);
        if (error) {
@@ -644,7 +653,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     /*
      * Set up a line discipline.
      */
-    ldisc = ldisc_create(term, back, backhandle, NULL);
+    ldisc = ldisc_create(&cfg, term, back, backhandle, NULL);
 
     session_closed = FALSE;
 
@@ -660,32 +669,12 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
      */
     {
        HMENU m = GetSystemMenu(hwnd, FALSE);
-       HMENU p, s;
+       HMENU s;
        int i;
 
        AppendMenu(m, MF_SEPARATOR, 0, 0);
-       if (cfg.protocol == PROT_TELNET) {
-           p = CreateMenu();
-           AppendMenu(p, MF_ENABLED, IDM_TEL_AYT, "Are You There");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_BRK, "Break");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_SYNCH, "Synch");
-           AppendMenu(p, MF_SEPARATOR, 0, 0);
-           AppendMenu(p, MF_ENABLED, IDM_TEL_EC, "Erase Character");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_EL, "Erase Line");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_GA, "Go Ahead");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_NOP, "No Operation");
-           AppendMenu(p, MF_SEPARATOR, 0, 0);
-           AppendMenu(p, MF_ENABLED, IDM_TEL_ABORT, "Abort Process");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_AO, "Abort Output");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_IP, "Interrupt Process");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_SUSP, "Suspend Process");
-           AppendMenu(p, MF_SEPARATOR, 0, 0);
-           AppendMenu(p, MF_ENABLED, IDM_TEL_EOR, "End Of Record");
-           AppendMenu(p, MF_ENABLED, IDM_TEL_EOF, "End Of File");
-           AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) p,
-                      "Telnet Command");
-           AppendMenu(m, MF_SEPARATOR, 0, 0);
-       }
+       specials_menu_position = GetMenuItemCount(m);
+       debug(("specials_menu_position = %d\n", specials_menu_position));
        AppendMenu(m, MF_ENABLED, IDM_SHOWLOG, "&Event Log");
        AppendMenu(m, MF_SEPARATOR, 0, 0);
        AppendMenu(m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session...");
@@ -712,6 +701,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        AppendMenu(m, MF_ENABLED, IDM_ABOUT, "&About PuTTY");
     }
 
+    update_specials_menu(NULL);
+
     /*
      * Set up the initial input locale.
      */
@@ -773,9 +764,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
            if (pending_netevent) {
                enact_pending_netevent();
 
-               /* Force the cursor blink on */
-               term_blink(term, 1);
-
                if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                    continue;
            }
@@ -876,6 +864,37 @@ char *do_select(SOCKET skt, int startup)
 }
 
 /*
+ * Update the Special Commands submenu.
+ */
+void update_specials_menu(void *frontend)
+{
+    HMENU m = GetSystemMenu(hwnd, FALSE);
+    int menu_already_exists = (specials != NULL);
+    int i;
+
+    specials = back->get_specials(backhandle);
+    if (specials) {
+       HMENU p = CreateMenu();
+       for (i = 0; specials[i].name; i++) {
+           assert(IDM_SPECIAL_MIN + 0x10 * i < IDM_SPECIAL_MAX);
+           if (*specials[i].name)
+               AppendMenu(p, MF_ENABLED, IDM_SPECIAL_MIN + 0x10 * i,
+                          specials[i].name);
+           else
+               AppendMenu(p, MF_SEPARATOR, 0, 0);
+       }
+       if (menu_already_exists)
+           DeleteMenu(m, specials_menu_position, MF_BYPOSITION);
+       else
+           InsertMenu(m, specials_menu_position,
+                      MF_BYPOSITION | MF_SEPARATOR, 0, 0);
+       InsertMenu(m, specials_menu_position,
+                  MF_BYPOSITION | MF_POPUP | MF_ENABLED,
+                  (UINT) p, "Special Command");
+    }
+}
+
+/*
  * set or clear the "raw mouse message" mode
  */
 void set_raw_mouse_mode(void *frontend, int activate)
@@ -897,11 +916,12 @@ void connection_fatal(void *frontend, char *fmt, ...)
     vsprintf(stuff, fmt, ap);
     va_end(ap);
     MessageBox(hwnd, stuff, "PuTTY Fatal Error", MB_ICONERROR | MB_OK);
-    if (cfg.close_on_exit == COE_ALWAYS)
+    if (cfg.close_on_exit == FORCE_ON)
        PostQuitMessage(1);
     else {
        session_closed = TRUE;
-       SetWindowText(hwnd, "PuTTY (inactive)");
+       set_icon(NULL, "PuTTY (inactive)");
+       set_title(NULL, "PuTTY (inactive)");
     }
 }
 
@@ -941,11 +961,12 @@ static void enact_pending_netevent(void)
     if (ret == 0 && !session_closed) {
        /* Abnormal exits will already have set session_closed and taken
         * appropriate action. */
-       if (cfg.close_on_exit == COE_ALWAYS ||
-           cfg.close_on_exit == COE_NORMAL) PostQuitMessage(0);
+       if (cfg.close_on_exit == FORCE_ON ||
+           cfg.close_on_exit == AUTO) PostQuitMessage(0);
        else {
            session_closed = TRUE;
-           SetWindowText(hwnd, "PuTTY (inactive)");
+           set_icon(NULL, "PuTTY (inactive)");
+           set_title(NULL, "PuTTY (inactive)");
            MessageBox(hwnd, "Connection closed by remote host",
                       "PuTTY", MB_OK | MB_ICONINFORMATION);
        }
@@ -982,6 +1003,10 @@ static void init_palette(void)
     HDC hdc = GetDC(hwnd);
     if (hdc) {
        if (cfg.try_palette && GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) {
+           /*
+            * This is a genuine case where we must use smalloc
+            * because the snew macros can't cope.
+            */
            logpal = smalloc(sizeof(*logpal)
                             - sizeof(logpal->palPalEntry)
                             + NCOLOURS * sizeof(PALETTEENTRY));
@@ -1045,7 +1070,7 @@ static void init_fonts(int pick_width, int pick_height)
     bold_mode = cfg.bold_colour ? BOLD_COLOURS : BOLD_FONT;
     und_mode = UND_FONT;
 
-    if (cfg.fontisbold) {
+    if (cfg.font.isbold) {
        fw_dontcare = FW_BOLD;
        fw_bold = FW_HEAVY;
     } else {
@@ -1058,7 +1083,7 @@ static void init_fonts(int pick_width, int pick_height)
     if (pick_height)
        font_height = pick_height;
     else {
-       font_height = cfg.fontheight;
+       font_height = cfg.font.height;
        if (font_height > 0) {
            font_height =
                -MulDiv(font_height, GetDeviceCaps(hdc, LOGPIXELSY), 72);
@@ -1070,9 +1095,9 @@ static void init_fonts(int pick_width, int pick_height)
     fonts[i] = CreateFont (font_height, font_width, 0, 0, w, FALSE, u, FALSE, \
                           c, OUT_DEFAULT_PRECIS, \
                           CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, \
-                          FIXED_PITCH | FF_DONTCARE, cfg.font)
+                          FIXED_PITCH | FF_DONTCARE, cfg.font.name)
 
-    f(FONT_NORMAL, cfg.fontcharset, fw_dontcare, FALSE);
+    f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE);
 
     lfont.lfHeight = font_height;
     lfont.lfWidth = font_width;
@@ -1082,12 +1107,12 @@ static void init_fonts(int pick_width, int pick_height)
     lfont.lfItalic = FALSE;
     lfont.lfUnderline = FALSE;
     lfont.lfStrikeOut = FALSE;
-    lfont.lfCharSet = cfg.fontcharset;
+    lfont.lfCharSet = cfg.font.charset;
     lfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
     lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
     lfont.lfQuality = DEFAULT_QUALITY;
     lfont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
-    strncpy(lfont.lfFaceName, cfg.font, LF_FACESIZE);
+    strncpy(lfont.lfFaceName, cfg.font.name, LF_FACESIZE);
 
     SelectObject(hdc, fonts[FONT_NORMAL]);
     GetTextMetrics(hdc, &tm);
@@ -1110,19 +1135,18 @@ static void init_fonts(int pick_width, int pick_height)
 
        /* !!! Yes the next line is right */
        if (cset == OEM_CHARSET)
-           font_codepage = GetOEMCP();
+           ucsdata.font_codepage = GetOEMCP();
        else
-           if (TranslateCharsetInfo
-               ((DWORD *) cset, &info, TCI_SRCCHARSET)) font_codepage =
-               info.ciACP;
+           if (TranslateCharsetInfo ((DWORD *) cset, &info, TCI_SRCCHARSET))
+               ucsdata.font_codepage = info.ciACP;
        else
-           font_codepage = -1;
+           ucsdata.font_codepage = -1;
 
-       GetCPInfo(font_codepage, &cpinfo);
-       dbcs_screenfont = (cpinfo.MaxCharSize > 1);
+       GetCPInfo(ucsdata.font_codepage, &cpinfo);
+       ucsdata.dbcs_screenfont = (cpinfo.MaxCharSize > 1);
     }
 
-    f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE);
+    f(FONT_UNDERLINE, cfg.font.charset, fw_dontcare, TRUE);
 
     /*
      * Some fonts, e.g. 9-pt Courier, draw their underlines
@@ -1173,7 +1197,7 @@ static void init_fonts(int pick_width, int pick_height)
     }
 
     if (bold_mode == BOLD_FONT) {
-       f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE);
+       f(FONT_BOLD, cfg.font.charset, fw_bold, FALSE);
     }
 #undef f
 
@@ -1207,7 +1231,7 @@ static void init_fonts(int pick_width, int pick_height)
     }
     fontflag[0] = fontflag[1] = fontflag[2] = 1;
 
-    init_ucs();
+    init_ucs(&cfg, &ucsdata);
 }
 
 static void another_font(int fontno)
@@ -1224,7 +1248,7 @@ static void another_font(int fontno)
     if (basefont != fontno && !fontflag[basefont])
        another_font(basefont);
 
-    if (cfg.fontisbold) {
+    if (cfg.font.isbold) {
        fw_dontcare = FW_BOLD;
        fw_bold = FW_HEAVY;
     } else {
@@ -1232,10 +1256,10 @@ static void another_font(int fontno)
        fw_bold = FW_BOLD;
     }
 
-    c = cfg.fontcharset;
+    c = cfg.font.charset;
     w = fw_dontcare;
     u = FALSE;
-    s = cfg.font;
+    s = cfg.font.name;
     x = font_width;
 
     if (fontno & FONT_WIDE)
@@ -1545,7 +1569,8 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt)
 
     if (send_raw_mouse && !(cfg.mouse_override && shift)) {
        lastbtn = MBT_NOTHING;
-       term_mouse(term, b, MA_CLICK, x, y, shift, ctrl, alt);
+       term_mouse(term, b, translate_button(b), MA_CLICK,
+                  x, y, shift, ctrl, alt);
        return;
     }
 
@@ -1558,7 +1583,8 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt)
        lastact = MA_CLICK;
     }
     if (lastact != MA_NOTHING)
-       term_mouse(term, b, lastact, x, y, shift, ctrl, alt);
+       term_mouse(term, b, translate_button(b), lastact,
+                  x, y, shift, ctrl, alt);
     lasttime = thistime;
 }
 
@@ -1566,7 +1592,7 @@ static void click(Mouse_Button b, int x, int y, int shift, int ctrl, int alt)
  * Translate a raw mouse button designation (LEFT, MIDDLE, RIGHT)
  * into a cooked one (SELECT, EXTEND, PASTE).
  */
-Mouse_Button translate_button(void *frontend, Mouse_Button button)
+static Mouse_Button translate_button(Mouse_Button button)
 {
     if (button == MBT_LEFT)
        return MBT_SELECT;
@@ -1705,7 +1731,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                    if ((lParam - IDM_SAVED_MIN) / 16 < sesslist.nsessions) {
                        char *session =
                            sesslist.sessions[(lParam - IDM_SAVED_MIN) / 16];
-                       cl = smalloc(16 + strlen(session));
+                       cl = snewn(16 + strlen(session), char);
                                       /* 8, but play safe */
                        if (!cl)
                            cl = NULL;    
@@ -1760,11 +1786,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                    }
                }
 
-               if (strcmp(prev_cfg.logfilename, cfg.logfilename) ||
-                   prev_cfg.logtype != cfg.logtype) {
-                   logfclose(logctx); /* reset logging */
-                   logfopen(logctx);
-               }
+               /* Pass new config data to the logging module */
+               log_reconfig(logctx, &cfg);
 
                sfree(logpal);
                /*
@@ -1779,8 +1802,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                cfgtopalette();
                init_palette();
 
-               /* Give terminal a heads-up on miscellaneous stuff */
-               term_reconfig(term);
+               /* Pass new config data to the terminal */
+               term_reconfig(term, &cfg);
+
+               /* Pass new config data to the back end */
+               back->reconfig(backhandle, &cfg);
 
                /* Screen size changed ? */
                if (cfg.height != prev_cfg.height ||
@@ -1860,11 +1886,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                                  icon_name);
                }
 
-               if (strcmp(cfg.font, prev_cfg.font) != 0 ||
+               if (strcmp(cfg.font.name, prev_cfg.font.name) != 0 ||
                    strcmp(cfg.line_codepage, prev_cfg.line_codepage) != 0 ||
-                   cfg.fontisbold != prev_cfg.fontisbold ||
-                   cfg.fontheight != prev_cfg.fontheight ||
-                   cfg.fontcharset != prev_cfg.fontcharset ||
+                   cfg.font.isbold != prev_cfg.font.isbold ||
+                   cfg.font.height != prev_cfg.font.height ||
+                   cfg.font.charset != prev_cfg.font.charset ||
                    cfg.vtmode != prev_cfg.vtmode ||
                    cfg.bold_colour != prev_cfg.bold_colour ||
                    cfg.resize_action == RESIZE_DISABLED ||
@@ -1887,58 +1913,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            term_pwron(term);
            ldisc_send(ldisc, NULL, 0, 0);
            break;
-         case IDM_TEL_AYT:
-           back->special(backhandle, TS_AYT);
-           net_pending_errors();
-           break;
-         case IDM_TEL_BRK:
-           back->special(backhandle, TS_BRK);
-           net_pending_errors();
-           break;
-         case IDM_TEL_SYNCH:
-           back->special(backhandle, TS_SYNCH);
-           net_pending_errors();
-           break;
-         case IDM_TEL_EC:
-           back->special(backhandle, TS_EC);
-           net_pending_errors();
-           break;
-         case IDM_TEL_EL:
-           back->special(backhandle, TS_EL);
-           net_pending_errors();
-           break;
-         case IDM_TEL_GA:
-           back->special(backhandle, TS_GA);
-           net_pending_errors();
-           break;
-         case IDM_TEL_NOP:
-           back->special(backhandle, TS_NOP);
-           net_pending_errors();
-           break;
-         case IDM_TEL_ABORT:
-           back->special(backhandle, TS_ABORT);
-           net_pending_errors();
-           break;
-         case IDM_TEL_AO:
-           back->special(backhandle, TS_AO);
-           net_pending_errors();
-           break;
-         case IDM_TEL_IP:
-           back->special(backhandle, TS_IP);
-           net_pending_errors();
-           break;
-         case IDM_TEL_SUSP:
-           back->special(backhandle, TS_SUSP);
-           net_pending_errors();
-           break;
-         case IDM_TEL_EOR:
-           back->special(backhandle, TS_EOR);
-           net_pending_errors();
-           break;
-         case IDM_TEL_EOF:
-           back->special(backhandle, TS_EOF);
-           net_pending_errors();
-           break;
          case IDM_ABOUT:
            showabout(hwnd);
            break;
@@ -1973,6 +1947,22 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            if (wParam >= IDM_SAVED_MIN && wParam <= IDM_SAVED_MAX) {
                SendMessage(hwnd, WM_SYSCOMMAND, IDM_SAVEDSESS, wParam);
            }
+           if (wParam >= IDM_SPECIAL_MIN && wParam <= IDM_SPECIAL_MAX) {
+               int i = (wParam - IDM_SPECIAL_MIN) / 0x10;
+               int j;
+               /*
+                * Ensure we haven't been sent a bogus SYSCOMMAND
+                * which would cause us to reference invalid memory
+                * and crash. Perhaps I'm just too paranoid here.
+                */
+               for (j = 0; j < i; j++)
+                   if (!specials || !specials[j].name)
+                       break;
+               if (j == i) {
+                   back->special(backhandle, specials[i].code);
+                   net_pending_errors();
+               }
+           }
        }
        break;
 
@@ -2037,7 +2027,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                      is_alt_pressed());
                SetCapture(hwnd);
            } else {
-               term_mouse(term, button, MA_RELEASE,
+               term_mouse(term, button, translate_button(button), MA_RELEASE,
                           TO_CHR_X(X_POS(lParam)),
                           TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
                           wParam & MK_CONTROL, is_alt_pressed());
@@ -2062,7 +2052,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                b = MBT_MIDDLE;
            else
                b = MBT_RIGHT;
-           term_mouse(term, b, MA_DRAG, TO_CHR_X(X_POS(lParam)),
+           term_mouse(term, b, translate_button(b), MA_DRAG,
+                      TO_CHR_X(X_POS(lParam)),
                       TO_CHR_Y(Y_POS(lParam)), wParam & MK_SHIFT,
                       wParam & MK_CONTROL, is_alt_pressed());
        }
@@ -2512,7 +2503,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
 
            if (n > 0) {
                int i;
-               buff = (char*) smalloc(n);
+               buff = snewn(n, char);
                ImmGetCompositionStringW(hIMC, GCS_RESULTSTR, buff, n);
                /*
                 * Jaeyoun Chung reports that Korean character
@@ -2597,12 +2588,13 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
                if (send_raw_mouse &&
                    !(cfg.mouse_override && shift_pressed)) {
                    /* send a mouse-down followed by a mouse up */
-                   term_mouse(term, b,
+                   term_mouse(term, b, translate_button(b),
                               MA_CLICK,
                               TO_CHR_X(X_POS(lParam)),
                               TO_CHR_Y(Y_POS(lParam)), shift_pressed,
                               control_pressed, is_alt_pressed());
-                   term_mouse(term, b, MA_RELEASE, TO_CHR_X(X_POS(lParam)),
+                   term_mouse(term, b, translate_button(b),
+                              MA_RELEASE, TO_CHR_X(X_POS(lParam)),
                               TO_CHR_Y(Y_POS(lParam)), shift_pressed,
                               control_pressed, is_alt_pressed());
                } else {
@@ -2699,7 +2691,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        int i;
        if (len > IpDxLEN) {
            sfree(IpDx);
-           IpDx = smalloc((len + 16) * sizeof(int));
+           IpDx = snewn(len + 16, int);
            IpDxLEN = (len + 16);
        }
        for (i = 0; i < IpDxLEN; i++)
@@ -2758,8 +2750,8 @@ void do_text(Context ctx, int x, int y, char *text, int len,
            if (lattr == LATTR_TOP || lattr == LATTR_BOT)
                text_adjust *= 2;
            attr &= ~CSET_MASK;
-           text[0] = (char) (unitab_xterm['q'] & CHAR_MASK);
-           attr |= (unitab_xterm['q'] & CSET_MASK);
+           text[0] = (char) (ucsdata.unitab_xterm['q'] & CHAR_MASK);
+           attr |= (ucsdata.unitab_xterm['q'] & CSET_MASK);
            if (attr & ATTR_UNDER) {
                attr &= ~ATTR_UNDER;
                force_manual_underline = 1;
@@ -2778,8 +2770,10 @@ void do_text(Context ctx, int x, int y, char *text, int len,
     if ((attr & CSET_MASK) == ATTR_OEMCP)
        nfont |= FONT_OEM;
 
-    nfg = 2 * ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
-    nbg = 2 * ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
+    nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT);
+    nfg = 2 * (nfg & 0xF) + (nfg & 0x10 ? 1 : 0);
+    nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT);
+    nbg = 2 * (nbg & 0xF) + (nbg & 0x10 ? 1 : 0);
     if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD))
        nfont |= FONT_BOLD;
     if (und_mode == UND_FONT && (attr & ATTR_UNDER))
@@ -2801,9 +2795,9 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        nbg = t;
     }
     if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD))
-       nfg++;
+       nfg |= 1;
     if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK))
-       nbg++;
+       nbg |= 1;
     fg = colours[nfg];
     bg = colours[nbg];
     SelectObject(hdc, fonts[nfont]);
@@ -2820,7 +2814,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        line_box.right = font_width*term->cols+offset_width;
 
     /* We're using a private area for direct to font. (512 chars.) */
-    if (dbcs_screenfont && (attr & CSET_MASK) == ATTR_ACP) {
+    if (ucsdata.dbcs_screenfont && (attr & CSET_MASK) == ATTR_ACP) {
        /* Ho Hum, dbcs fonts are a PITA! */
        /* To display on W9x I have to convert to UCS */
        static wchar_t *uni_buf = 0;
@@ -2828,20 +2822,21 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        int nlen, mptr;
        if (len > uni_len) {
            sfree(uni_buf);
-           uni_buf = smalloc((uni_len = len) * sizeof(wchar_t));
+           uni_len = len;
+           uni_buf = snewn(uni_len, wchar_t);
        }
 
        for(nlen = mptr = 0; mptr<len; mptr++) {
            uni_buf[nlen] = 0xFFFD;
-           if (IsDBCSLeadByteEx(font_codepage, (BYTE) text[mptr])) {
+           if (IsDBCSLeadByteEx(ucsdata.font_codepage, (BYTE) text[mptr])) {
                IpDx[nlen] += char_width;
-               MultiByteToWideChar(font_codepage, MB_USEGLYPHCHARS,
+               MultiByteToWideChar(ucsdata.font_codepage, MB_USEGLYPHCHARS,
                                   text+mptr, 2, uni_buf+nlen, 1);
                mptr++;
            }
            else
            {
-               MultiByteToWideChar(font_codepage, MB_USEGLYPHCHARS,
+               MultiByteToWideChar(ucsdata.font_codepage, MB_USEGLYPHCHARS,
                                   text+mptr, 1, uni_buf+nlen, 1);
            }
            nlen++;
@@ -2888,7 +2883,7 @@ void do_text(Context ctx, int x, int y, char *text, int len,
        if (wlen < len) {
            sfree(wbuf);
            wlen = len;
-           wbuf = smalloc(wlen * sizeof(WCHAR));
+           wbuf = snewn(wlen, WCHAR);
        }
        for (i = 0; i < len; i++)
            wbuf[i] = (WCHAR) ((attr & CSET_MASK) + (text[i] & CHAR_MASK));
@@ -3010,17 +3005,17 @@ int char_width(Context ctx, int uc) {
 
     switch (uc & CSET_MASK) {
       case ATTR_ASCII:
-       uc = unitab_line[uc & 0xFF];
+       uc = ucsdata.unitab_line[uc & 0xFF];
        break;
       case ATTR_LINEDRW:
-       uc = unitab_xterm[uc & 0xFF];
+       uc = ucsdata.unitab_xterm[uc & 0xFF];
        break;
       case ATTR_SCOACS:
-       uc = unitab_scoacs[uc & 0xFF];
+       uc = ucsdata.unitab_scoacs[uc & 0xFF];
        break;
     }
     if (DIRECT_FONT(uc)) {
-       if (dbcs_screenfont) return 1;
+       if (ucsdata.dbcs_screenfont) return 1;
 
        /* Speedup, I know of no font where ascii is the wrong width */
        if ((uc&CHAR_MASK) >= ' ' && (uc&CHAR_MASK)<= '~') 
@@ -3288,10 +3283,18 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            SendMessage(hwnd, WM_VSCROLL, SB_PAGEUP, 0);
            return 0;
        }
+       if (wParam == VK_PRIOR && shift_state == 2) {
+           SendMessage(hwnd, WM_VSCROLL, SB_LINEUP, 0);
+           return 0;
+       }
        if (wParam == VK_NEXT && shift_state == 1) {
            SendMessage(hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
            return 0;
        }
+       if (wParam == VK_NEXT && shift_state == 2) {
+           SendMessage(hwnd, WM_VSCROLL, SB_LINEDOWN, 0);
+           return 0;
+       }
        if (wParam == VK_INSERT && shift_state == 1) {
            term_do_paste(term);
            return 0;
@@ -3486,7 +3489,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            *p++ = "\000\033\034\035\036\037\177"[wParam - '2'];
            return p - output;
        }
-       if (shift_state == 2 && wParam == 0xBD) {
+       if (shift_state == 2 && (wParam == 0xBD || wParam == 0xBF)) {
            *p++ = 0x1F;
            return p - output;
        }
@@ -3757,7 +3760,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 #ifdef SHOW_TOASCII_RESULT
        if (r == 1 && !key_down) {
            if (alt_sum) {
-               if (in_utf(term) || dbcs_screenfont)
+               if (in_utf(term) || ucsdata.dbcs_screenfont)
                    debug((", (U+%04x)", alt_sum));
                else
                    debug((", LCH(%d)", alt_sum));
@@ -3810,7 +3813,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
 
                if (!key_down) {
                    if (alt_sum) {
-                       if (in_utf(term) || dbcs_screenfont) {
+                       if (in_utf(term) || ucsdata.dbcs_screenfont) {
                            keybuf = alt_sum;
                            term_seen_key_event(term);
                            luni_send(ldisc, &keybuf, 1, 1);
@@ -3860,7 +3863,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
        if (!left_alt)
            keys[0] = 0;
        /* If we will be using alt_sum fix the 256s */
-       else if (keys[0] && (in_utf(term) || dbcs_screenfont))
+       else if (keys[0] && (in_utf(term) || ucsdata.dbcs_screenfont))
            keys[0] = 10;
     }
 
@@ -3890,7 +3893,7 @@ void request_paste(void *frontend)
 void set_title(void *frontend, char *title)
 {
     sfree(window_name);
-    window_name = smalloc(1 + strlen(title));
+    window_name = snewn(1 + strlen(title), char);
     strcpy(window_name, title);
     if (cfg.win_name_always || !IsIconic(hwnd))
        SetWindowText(hwnd, title);
@@ -3899,7 +3902,7 @@ void set_title(void *frontend, char *title)
 void set_icon(void *frontend, char *title)
 {
     sfree(icon_name);
-    icon_name = smalloc(1 + strlen(title));
+    icon_name = snewn(1 + strlen(title), char);
     strcpy(icon_name, title);
     if (!cfg.win_name_always && IsIconic(hwnd))
        SetWindowText(hwnd, title);
@@ -4069,10 +4072,10 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
 
        get_unitab(CP_ACP, unitab, 0);
 
-       rtfsize = 100 + strlen(cfg.font);
-       rtf = smalloc(rtfsize);
+       rtfsize = 100 + strlen(cfg.font.name);
+       rtf = snewn(rtfsize, char);
        sprintf(rtf, "{\\rtf1\\ansi%d{\\fonttbl\\f0\\fmodern %s;}\\f0",
-               GetACP(), cfg.font);
+               GetACP(), cfg.font.name);
        rtflen = strlen(rtf);
 
        /*
@@ -4135,7 +4138,7 @@ void write_clip(void *frontend, wchar_t * data, int len, int must_deselect)
 
            if (rtfsize < rtflen + totallen + 3) {
                rtfsize = rtflen + totallen + 512;
-               rtf = srealloc(rtf, rtfsize);
+               rtf = sresize(rtf, rtfsize, char);
            }
 
            strcpy(rtf + rtflen, before); rtflen += blen;
@@ -4223,7 +4226,7 @@ void get_clip(void *frontend, wchar_t ** p, int *len)
            CloseClipboard();
            s = GlobalLock(clipdata);
            i = MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1, 0, 0);
-           *p = converted = smalloc(i * sizeof(wchar_t));
+           *p = converted = snewn(i, wchar_t);
            MultiByteToWideChar(CP_ACP, 0, s, strlen(s) + 1, converted, i);
            *len = i - 1;
            return;
@@ -4348,7 +4351,8 @@ void beep(void *frontend, int mode)
         */
        lastbeep = GetTickCount();
     } else if (mode == BELL_WAVEFILE) {
-       if (!PlaySound(cfg.bell_wavefile, NULL, SND_ASYNC | SND_FILENAME)) {
+       if (!PlaySound(cfg.bell_wavefile.path, NULL,
+                      SND_ASYNC | SND_FILENAME)) {
            char buf[sizeof(cfg.bell_wavefile) + 80];
            sprintf(buf, "Unable to play sound file\n%s\n"
                    "Using default sound instead", cfg.bell_wavefile);