The WinSock library is now loaded at run-time, which means we can
[u/mdw/putty] / window.c
index 96ce4ad..5174b46 100644 (file)
--- a/window.c
+++ b/window.c
@@ -1,23 +1,3 @@
-#include <windows.h>
-#include <imm.h>
-#include <commctrl.h>
-#include <richedit.h>
-#include <mmsystem.h>
-#ifndef AUTO_WINSOCK
-#ifdef WINSOCK_TWO
-#include <winsock2.h>
-#else
-#include <winsock.h>
-#endif
-#endif
-
-#ifndef NO_MULTIMON
-#if WINVER < 0x0500
-#define COMPILE_MULTIMON_STUBS
-#include <multimon.h>
-#endif
-#endif
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <ctype.h>
 #define PUTTY_DO_GLOBALS              /* actually _define_ globals */
 #include "putty.h"
 #include "terminal.h"
 #define PUTTY_DO_GLOBALS              /* actually _define_ globals */
 #include "putty.h"
 #include "terminal.h"
-#include "winstuff.h"
 #include "storage.h"
 #include "win_res.h"
 
 #include "storage.h"
 #include "win_res.h"
 
+#ifndef NO_MULTIMON
+#if WINVER < 0x0500
+#define COMPILE_MULTIMON_STUBS
+#include <multimon.h>
+#endif
+#endif
+
+#include <imm.h>
+#include <commctrl.h>
+#include <richedit.h>
+#include <mmsystem.h>
+
 #define IDM_SHOWLOG   0x0010
 #define IDM_NEWSESS   0x0020
 #define IDM_DUPSESS   0x0030
 #define IDM_SHOWLOG   0x0010
 #define IDM_NEWSESS   0x0020
 #define IDM_DUPSESS   0x0030
@@ -55,6 +46,7 @@
 
 #define WM_IGNORE_CLIP (WM_XUSER + 2)
 #define WM_FULLSCR_ON_MAX (WM_XUSER + 3)
 
 #define WM_IGNORE_CLIP (WM_XUSER + 2)
 #define WM_FULLSCR_ON_MAX (WM_XUSER + 3)
+#define WM_AGENT_CALLBACK (WM_XUSER + 4)
 
 /* Needed for Chinese support and apparently not always defined. */
 #ifndef VK_PROCESSKEY
 
 /* Needed for Chinese support and apparently not always defined. */
 #ifndef VK_PROCESSKEY
@@ -74,6 +66,7 @@ static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
 static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                        unsigned char *output);
 static void cfgtopalette(void);
 static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                        unsigned char *output);
 static void cfgtopalette(void);
+static void systopalette(void);
 static void init_palette(void);
 static void init_fonts(int, int);
 static void another_font(int);
 static void init_palette(void);
 static void init_fonts(int, int);
 static void another_font(int);
@@ -122,6 +115,13 @@ Config cfg;                               /* exported to windlg.c */
 
 extern struct sesslist sesslist;       /* imported from windlg.c */
 
 
 extern struct sesslist sesslist;       /* imported from windlg.c */
 
+struct agent_callback {
+    void (*callback)(void *, void *, int);
+    void *callback_ctx;
+    void *data;
+    int len;
+};
+
 #define FONT_NORMAL 0
 #define FONT_BOLD 1
 #define FONT_UNDERLINE 2
 #define FONT_NORMAL 0
 #define FONT_BOLD 1
 #define FONT_UNDERLINE 2
@@ -169,10 +169,6 @@ static char *window_name, *icon_name;
 
 static int compose_state = 0;
 
 
 static int compose_state = 0;
 
-static int wsa_started = 0;
-
-static OSVERSIONINFO osVersion;
-
 static UINT wm_mousewheel = WM_MOUSEWHEEL;
 
 /* Dummy routine, only required in plink. */
 static UINT wm_mousewheel = WM_MOUSEWHEEL;
 
 /* Dummy routine, only required in plink. */
@@ -182,9 +178,6 @@ void ldisc_update(void *frontend, int echo, int edit)
 
 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 {
 
 int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
 {
-    static char appname[] = "PuTTY";
-    WORD winsock_ver;
-    WSADATA wsadata;
     WNDCLASS wndclass;
     MSG msg;
     int guess_width, guess_height;
     WNDCLASS wndclass;
     MSG msg;
     int guess_width, guess_height;
@@ -192,20 +185,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
     hinst = inst;
     flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
 
     hinst = inst;
     flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
 
-    winsock_ver = MAKEWORD(1, 1);
-    if (WSAStartup(winsock_ver, &wsadata)) {
-       MessageBox(NULL, "Unable to initialise WinSock", "WinSock Error",
-                  MB_OK | MB_ICONEXCLAMATION);
-       return 1;
-    }
-    if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) {
-       MessageBox(NULL, "WinSock version is incompatible with 1.1",
-                  "WinSock Error", MB_OK | MB_ICONEXCLAMATION);
-       WSACleanup();
-       return 1;
-    }
-    wsa_started = 1;
-    /* WISHLIST: maybe allow config tweaking even if winsock not present? */
     sk_init();
 
     InitCommonControls();
     sk_init();
 
     InitCommonControls();
@@ -214,14 +193,13 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
      * config box. */
     defuse_showwindow();
 
      * config box. */
     defuse_showwindow();
 
+    if (!init_winver())
     {
     {
-       ZeroMemory(&osVersion, sizeof(osVersion));
-       osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
-       if (!GetVersionEx ( (OSVERSIONINFO *) &osVersion)) {
-            MessageBox(NULL, "Windows refuses to report a version",
-                       "PuTTY Fatal Error", MB_OK | MB_ICONEXCLAMATION);
-           return 1;
-        }
+       char *str = dupprintf("%s Fatal Error", appname);
+       MessageBox(NULL, "Windows refuses to report a version",
+                  str, MB_OK | MB_ICONEXCLAMATION);
+       sfree(str);
+       return 1;
     }
 
     /*
     }
 
     /*
@@ -300,8 +278,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
            p[i] = '\0';
            do_defaults(p + 1, &cfg);
            if (!*cfg.host && !do_config()) {
            p[i] = '\0';
            do_defaults(p + 1, &cfg);
            if (!*cfg.host && !do_config()) {
-               WSACleanup();
-               return 0;
+               cleanup_exit(0);
            }
        } else if (*p == '&') {
            /*
            }
        } else if (*p == '&') {
            /*
@@ -319,8 +296,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                UnmapViewOfFile(cp);
                CloseHandle(filemap);
            } else if (!do_config()) {
                UnmapViewOfFile(cp);
                CloseHandle(filemap);
            } else if (!do_config()) {
-               WSACleanup();
-               return 0;
+               cleanup_exit(0);
            }
        } else {
            /*
            }
        } else {
            /*
@@ -350,18 +326,21 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                     * entries associated with PuTTY, and also find
                     * and delete the random seed file.
                     */
                     * entries associated with PuTTY, and also find
                     * and delete the random seed file.
                     */
-                   if (MessageBox(NULL,
-                                  "This procedure will remove ALL Registry\n"
-                                  "entries associated with PuTTY, and will\n"
-                                  "also remove the PuTTY random seed file.\n"
+                   char *s1, *s2;
+                   s1 = dupprintf("This procedure will remove ALL Registry\n"
+                                  "entries associated with %s, and will\n"
+                                  "also remove the random seed file.\n"
                                   "\n"
                                   "THIS PROCESS WILL DESTROY YOUR SAVED\n"
                                   "SESSIONS. Are you really sure you want\n"
                                   "\n"
                                   "THIS PROCESS WILL DESTROY YOUR SAVED\n"
                                   "SESSIONS. Are you really sure you want\n"
-                                  "to continue?",
-                                  "PuTTY Warning",
+                                  "to continue?", appname);
+                   s2 = dupprintf("%s Warning", appname);
+                   if (MessageBox(NULL, s1, s2,
                                   MB_YESNO | MB_ICONWARNING) == IDYES) {
                        cleanup_all();
                    }
                                   MB_YESNO | MB_ICONWARNING) == IDYES) {
                        cleanup_all();
                    }
+                   sfree(s1);
+                   sfree(s2);
                    exit(0);
                } else if (*p != '-') {
                    char *q = p;
                    exit(0);
                } else if (*p != '-') {
                    char *q = p;
@@ -422,8 +401,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        cmdline_run_saved(&cfg);
 
        if (!*cfg.host && !do_config()) {
        cmdline_run_saved(&cfg);
 
        if (!*cfg.host && !do_config()) {
-           WSACleanup();
-           return 0;
+           cleanup_exit(0);
        }
 
        /*
        }
 
        /*
@@ -481,19 +459,21 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
                break;
            }
        if (back == NULL) {
                break;
            }
        if (back == NULL) {
+           char *str = dupprintf("%s Internal Error", appname);
            MessageBox(NULL, "Unsupported protocol number found",
            MessageBox(NULL, "Unsupported protocol number found",
-                      "PuTTY Internal Error", MB_OK | MB_ICONEXCLAMATION);
-           WSACleanup();
-           return 1;
+                      str, MB_OK | MB_ICONEXCLAMATION);
+           sfree(str);
+           cleanup_exit(1);
        }
     }
 
     /* Check for invalid Port number (i.e. zero) */
     if (cfg.port == 0) {
        }
     }
 
     /* Check for invalid Port number (i.e. zero) */
     if (cfg.port == 0) {
+       char *str = dupprintf("%s Internal Error", appname);
        MessageBox(NULL, "Invalid Port Number",
        MessageBox(NULL, "Invalid Port Number",
-                  "PuTTY Internal Error", MB_OK | MB_ICONEXCLAMATION);
-       WSACleanup();
-       return 1;
+                  str, MB_OK | MB_ICONEXCLAMATION);
+       sfree(str);
+       cleanup_exit(1);
     }
 
     if (!prev) {
     }
 
     if (!prev) {
@@ -620,24 +600,26 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
      * Start up the telnet connection.
      */
     {
      * Start up the telnet connection.
      */
     {
-       char *error;
+       const char *error;
        char msg[1024], *title;
        char *realhost;
 
        char msg[1024], *title;
        char *realhost;
 
-       error = back->init((void *)term, &backhandle, &cfg,
+       error = back->init(NULL, &backhandle, &cfg,
                           cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
        back->provide_logctx(backhandle, logctx);
        if (error) {
                           cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
        back->provide_logctx(backhandle, logctx);
        if (error) {
+           char *str = dupprintf("%s Error", appname);
            sprintf(msg, "Unable to open connection to\n"
                    "%.800s\n" "%s", cfg.host, error);
            sprintf(msg, "Unable to open connection to\n"
                    "%.800s\n" "%s", cfg.host, error);
-           MessageBox(NULL, msg, "PuTTY Error", MB_ICONERROR | MB_OK);
+           MessageBox(NULL, msg, str, MB_ICONERROR | MB_OK);
+           sfree(str);
            return 0;
        }
        window_name = icon_name = NULL;
        if (*cfg.wintitle) {
            title = cfg.wintitle;
        } else {
            return 0;
        }
        window_name = icon_name = NULL;
        if (*cfg.wintitle) {
            title = cfg.wintitle;
        } else {
-           sprintf(msg, "%s - PuTTY", realhost);
+           sprintf(msg, "%s - %s", realhost, appname);
            title = msg;
        }
        sfree(realhost);
            title = msg;
        }
        sfree(realhost);
@@ -671,10 +653,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        HMENU m = GetSystemMenu(hwnd, FALSE);
        HMENU s;
        int i;
        HMENU m = GetSystemMenu(hwnd, FALSE);
        HMENU s;
        int i;
+       char *str;
 
        AppendMenu(m, MF_SEPARATOR, 0, 0);
        specials_menu_position = GetMenuItemCount(m);
 
        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...");
        AppendMenu(m, MF_ENABLED, IDM_SHOWLOG, "&Event Log");
        AppendMenu(m, MF_SEPARATOR, 0, 0);
        AppendMenu(m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session...");
@@ -698,7 +680,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        AppendMenu(m, MF_SEPARATOR, 0, 0);
         if (help_path)
             AppendMenu(m, MF_ENABLED, IDM_HELP, "&Help");
        AppendMenu(m, MF_SEPARATOR, 0, 0);
         if (help_path)
             AppendMenu(m, MF_ENABLED, IDM_HELP, "&Help");
-       AppendMenu(m, MF_ENABLED, IDM_ABOUT, "&About PuTTY");
+       str = dupprintf("&About %s", appname);
+       AppendMenu(m, MF_ENABLED, IDM_ABOUT, str);
+       sfree(str);
     }
 
     update_specials_menu(NULL);
     }
 
     update_specials_menu(NULL);
@@ -824,8 +808,6 @@ void cleanup_exit(int code)
     if (pal)
        DeleteObject(pal);
     sk_cleanup();
     if (pal)
        DeleteObject(pal);
     sk_cleanup();
-    if (wsa_started)
-       WSACleanup();
 
     if (cfg.protocol == PROT_SSH) {
        random_save_seed();
 
     if (cfg.protocol == PROT_SSH) {
        random_save_seed();
@@ -852,8 +834,8 @@ char *do_select(SOCKET skt, int startup)
     }
     if (!hwnd)
        return "do_select(): internal error (hwnd==NULL)";
     }
     if (!hwnd)
        return "do_select(): internal error (hwnd==NULL)";
-    if (WSAAsyncSelect(skt, hwnd, msg, events) == SOCKET_ERROR) {
-       switch (WSAGetLastError()) {
+    if (p_WSAAsyncSelect(skt, hwnd, msg, events) == SOCKET_ERROR) {
+       switch (p_WSAGetLastError()) {
          case WSAENETDOWN:
            return "Network is down";
          default:
          case WSAENETDOWN:
            return "Network is down";
          default:
@@ -910,18 +892,22 @@ void set_raw_mouse_mode(void *frontend, int activate)
 void connection_fatal(void *frontend, char *fmt, ...)
 {
     va_list ap;
 void connection_fatal(void *frontend, char *fmt, ...)
 {
     va_list ap;
-    char stuff[200];
+    char *stuff, morestuff[100];
 
     va_start(ap, fmt);
 
     va_start(ap, fmt);
-    vsprintf(stuff, fmt, ap);
+    stuff = dupvprintf(fmt, ap);
     va_end(ap);
     va_end(ap);
-    MessageBox(hwnd, stuff, "PuTTY Fatal Error", MB_ICONERROR | MB_OK);
+    sprintf(morestuff, "%.70s Fatal Error", appname);
+    MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK);
+    sfree(stuff);
+
     if (cfg.close_on_exit == FORCE_ON)
        PostQuitMessage(1);
     else {
        session_closed = TRUE;
     if (cfg.close_on_exit == FORCE_ON)
        PostQuitMessage(1);
     else {
        session_closed = TRUE;
-       set_icon(NULL, "PuTTY (inactive)");
-       set_title(NULL, "PuTTY (inactive)");
+       sprintf(morestuff, "%.70s (inactive)", appname);
+       set_icon(NULL, morestuff);
+       set_title(NULL, morestuff);
     }
 }
 
     }
 }
 
@@ -931,12 +917,14 @@ void connection_fatal(void *frontend, char *fmt, ...)
 void cmdline_error(char *fmt, ...)
 {
     va_list ap;
 void cmdline_error(char *fmt, ...)
 {
     va_list ap;
-    char stuff[200];
+    char *stuff, morestuff[100];
 
     va_start(ap, fmt);
 
     va_start(ap, fmt);
-    vsprintf(stuff, fmt, ap);
+    stuff = dupvprintf(fmt, ap);
     va_end(ap);
     va_end(ap);
-    MessageBox(hwnd, stuff, "PuTTY Command Line Error", MB_ICONERROR | MB_OK);
+    sprintf(morestuff, "%.70s Command Line Error", appname);
+    MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK);
+    sfree(stuff);
     exit(1);
 }
 
     exit(1);
 }
 
@@ -964,11 +952,13 @@ static void enact_pending_netevent(void)
        if (cfg.close_on_exit == FORCE_ON ||
            cfg.close_on_exit == AUTO) PostQuitMessage(0);
        else {
        if (cfg.close_on_exit == FORCE_ON ||
            cfg.close_on_exit == AUTO) PostQuitMessage(0);
        else {
+           char morestuff[100];
            session_closed = TRUE;
            session_closed = TRUE;
-           set_icon(NULL, "PuTTY (inactive)");
-           set_title(NULL, "PuTTY (inactive)");
+           sprintf(morestuff, "%.70s (inactive)", appname);
+           set_icon(NULL, morestuff);
+           set_title(NULL, morestuff);
            MessageBox(hwnd, "Connection closed by remote host",
            MessageBox(hwnd, "Connection closed by remote host",
-                      "PuTTY", MB_OK | MB_ICONINFORMATION);
+                      appname, MB_OK | MB_ICONINFORMATION);
        }
     }
 }
        }
     }
 }
@@ -992,6 +982,38 @@ static void cfgtopalette(void)
        defpal[i].rgbtGreen = cfg.colours[w][1];
        defpal[i].rgbtBlue = cfg.colours[w][2];
     }
        defpal[i].rgbtGreen = cfg.colours[w][1];
        defpal[i].rgbtBlue = cfg.colours[w][2];
     }
+
+    /* Override with system colours if appropriate */
+    if (cfg.system_colour)
+        systopalette();
+}
+
+/*
+ * Override bit of defpal with colours from the system.
+ * (NB that this takes a copy the system colours at the time this is called,
+ * so subsequent colour scheme changes don't take effect. To fix that we'd
+ * probably want to be using GetSysColorBrush() and the like.)
+ */
+static void systopalette(void)
+{
+    int i;
+    static const struct { int nIndex; int norm; int bold; } or[] =
+    {
+       { COLOR_WINDOWTEXT,     16, 17 }, /* Default Foreground */
+       { COLOR_WINDOW,         18, 19 }, /* Default Background */
+       { COLOR_HIGHLIGHTTEXT,  20, 21 }, /* Cursor Text */
+       { COLOR_HIGHLIGHT,      22, 23 }, /* Cursor Colour */
+    };
+
+    for (i = 0; i < (sizeof(or)/sizeof(or[0])); i++) {
+       COLORREF colour = GetSysColor(or[i].nIndex);
+       defpal[or[i].norm].rgbtRed =
+          defpal[or[i].bold].rgbtRed = GetRValue(colour);
+       defpal[or[i].norm].rgbtGreen =
+          defpal[or[i].bold].rgbtGreen = GetGValue(colour);
+       defpal[or[i].norm].rgbtBlue =
+          defpal[or[i].bold].rgbtBlue = GetBValue(colour);
+    }
 }
 
 /*
 }
 
 /*
@@ -1673,13 +1695,17 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
       case WM_CREATE:
        break;
       case WM_CLOSE:
       case WM_CREATE:
        break;
       case WM_CLOSE:
-       show_mouseptr(1);
-       if (!cfg.warn_on_close || session_closed ||
-           MessageBox(hwnd,
-                      "Are you sure you want to close this session?",
-                      "PuTTY Exit Confirmation",
-                      MB_ICONWARNING | MB_OKCANCEL) == IDOK)
-           DestroyWindow(hwnd);
+       {
+           char *str;
+           show_mouseptr(1);
+           str = dupprintf("%s Exit Confirmation", appname);
+           if (!cfg.warn_on_close || session_closed ||
+               MessageBox(hwnd,
+                          "Are you sure you want to close this session?",
+                          str, MB_ICONWARNING | MB_OKCANCEL) == IDOK)
+               DestroyWindow(hwnd);
+           sfree(str);
+       }
        return 0;
       case WM_DESTROY:
        show_mouseptr(1);
        return 0;
       case WM_DESTROY:
        show_mouseptr(1);
@@ -2554,6 +2580,14 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            SetCursor(LoadCursor(NULL, IDC_ARROW));
            return TRUE;
        }
            SetCursor(LoadCursor(NULL, IDC_ARROW));
            return TRUE;
        }
+       break;
+      case WM_AGENT_CALLBACK:
+       {
+           struct agent_callback *c = (struct agent_callback *)lParam;
+           c->callback(c->callback_ctx, c->data, c->len);
+           sfree(c);
+       }
+       return 0;
       default:
        if (message == wm_mousewheel || message == WM_MOUSEWHEEL) {
            int shift_pressed=0, control_pressed=0;
       default:
        if (message == wm_mousewheel || message == WM_MOUSEWHEEL) {
            int shift_pressed=0, control_pressed=0;
@@ -3497,6 +3531,10 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
            *p++ = 0x1C;
            return p - output;
        }
            *p++ = 0x1C;
            return p - output;
        }
+       if (shift_state == 3 && wParam == 0xDE) {
+           *p++ = 0x1E;               /* Ctrl-~ == Ctrl-^ in xterm at least */
+           return p - output;
+       }
        if (shift_state == 0 && wParam == VK_RETURN && term->cr_lf_return) {
            *p++ = '\r';
            *p++ = '\n';
        if (shift_state == 0 && wParam == VK_RETURN && term->cr_lf_return) {
            *p++ = '\r';
            *p++ = '\n';
@@ -3832,9 +3870,10 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam,
                            ldisc_send(ldisc, &ch, 1, 1);
                        }
                        alt_sum = 0;
                            ldisc_send(ldisc, &ch, 1, 1);
                        }
                        alt_sum = 0;
-                   } else
+                   } else {
                        term_seen_key_event(term);
                        lpage_send(ldisc, kbd_codepage, &ch, 1, 1);
                        term_seen_key_event(term);
                        lpage_send(ldisc, kbd_codepage, &ch, 1, 1);
+                   }
                } else {
                    if(capsOn && ch < 0x80) {
                        WCHAR cbuf[2];
                } else {
                    if(capsOn && ch < 0x80) {
                        WCHAR cbuf[2];
@@ -4265,12 +4304,14 @@ void optimised_move(void *frontend, int to, int from, int lines)
 void fatalbox(char *fmt, ...)
 {
     va_list ap;
 void fatalbox(char *fmt, ...)
 {
     va_list ap;
-    char stuff[200];
+    char *stuff, morestuff[100];
 
     va_start(ap, fmt);
 
     va_start(ap, fmt);
-    vsprintf(stuff, fmt, ap);
+    stuff = dupvprintf(fmt, ap);
     va_end(ap);
     va_end(ap);
-    MessageBox(hwnd, stuff, "PuTTY Fatal Error", MB_ICONERROR | MB_OK);
+    sprintf(morestuff, "%.70s Fatal Error", appname);
+    MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK);
+    sfree(stuff);
     cleanup_exit(1);
 }
 
     cleanup_exit(1);
 }
 
@@ -4280,13 +4321,15 @@ void fatalbox(char *fmt, ...)
 void modalfatalbox(char *fmt, ...)
 {
     va_list ap;
 void modalfatalbox(char *fmt, ...)
 {
     va_list ap;
-    char stuff[200];
+    char *stuff, morestuff[100];
 
     va_start(ap, fmt);
 
     va_start(ap, fmt);
-    vsprintf(stuff, fmt, ap);
+    stuff = dupvprintf(fmt, ap);
     va_end(ap);
     va_end(ap);
-    MessageBox(hwnd, stuff, "PuTTY Fatal Error",
+    sprintf(morestuff, "%.70s Fatal Error", appname);
+    MessageBox(hwnd, stuff, morestuff,
               MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
               MB_SYSTEMMODAL | MB_ICONERROR | MB_OK);
+    sfree(stuff);
     cleanup_exit(1);
 }
 
     cleanup_exit(1);
 }
 
@@ -4354,12 +4397,31 @@ void beep(void *frontend, int mode)
        if (!PlaySound(cfg.bell_wavefile.path, NULL,
                       SND_ASYNC | SND_FILENAME)) {
            char buf[sizeof(cfg.bell_wavefile) + 80];
        if (!PlaySound(cfg.bell_wavefile.path, NULL,
                       SND_ASYNC | SND_FILENAME)) {
            char buf[sizeof(cfg.bell_wavefile) + 80];
+           char otherbuf[100];
            sprintf(buf, "Unable to play sound file\n%s\n"
                    "Using default sound instead", cfg.bell_wavefile);
            sprintf(buf, "Unable to play sound file\n%s\n"
                    "Using default sound instead", cfg.bell_wavefile);
-           MessageBox(hwnd, buf, "PuTTY Sound Error",
+           sprintf(otherbuf, "%.70s Sound Error", appname);
+           MessageBox(hwnd, buf, otherbuf,
                       MB_OK | MB_ICONEXCLAMATION);
            cfg.beep = BELL_DEFAULT;
        }
                       MB_OK | MB_ICONEXCLAMATION);
            cfg.beep = BELL_DEFAULT;
        }
+    } else if (mode == BELL_PCSPEAKER) {
+       static long lastbeep = 0;
+       long beepdiff;
+
+       beepdiff = GetTickCount() - lastbeep;
+       if (beepdiff >= 0 && beepdiff < 50)
+           return;
+
+       /*
+        * We must beep in different ways depending on whether this
+        * is a 95-series or NT-series OS.
+        */
+       if(osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
+           Beep(800, 100);
+       else
+           MessageBeep(-1);
+       lastbeep = GetTickCount();
     }
     /* Otherwise, either visual bell or disabled; do nothing here */
     if (!term->has_focus) {
     }
     /* Otherwise, either visual bell or disabled; do nothing here */
     if (!term->has_focus) {
@@ -4596,3 +4658,19 @@ void frontend_keypress(void *handle)
      */
     return;
 }
      */
     return;
 }
+
+int from_backend(void *frontend, int is_stderr, const char *data, int len)
+{
+    return term_data(term, is_stderr, data, len);
+}
+
+void agent_schedule_callback(void (*callback)(void *, void *, int),
+                            void *callback_ctx, void *data, int len)
+{
+    struct agent_callback *c = snew(struct agent_callback);
+    c->callback = callback;
+    c->callback_ctx = callback_ctx;
+    c->data = data;
+    c->len = len;
+    PostMessage(hwnd, WM_AGENT_CALLBACK, 0, (LPARAM)c);
+}