X-Git-Url: https://asedeno.scripts.mit.edu/gitweb/?a=blobdiff_plain;f=windows%2Fwindow.c;h=004eb4f827eeccaf6ebc3bf1da8bb5f499c94318;hb=510f49e405e71ba5c97875e7a019364e1ef5fac9;hp=a1d99bae98db430dec1e4567ab4f179b7452a1bf;hpb=e350ca2b4e80bfea2fe4915d512000bcb353333b;p=PuTTY.git diff --git a/windows/window.c b/windows/window.c index a1d99bae..004eb4f8 100644 --- a/windows/window.c +++ b/windows/window.c @@ -10,6 +10,10 @@ #include #include +#ifdef __WINE__ +#define NO_MULTIMON /* winelib doesn't have this */ +#endif + #ifndef NO_MULTIMON #define COMPILE_MULTIMON_STUBS #endif @@ -19,6 +23,7 @@ #include "terminal.h" #include "storage.h" #include "win_res.h" +#include "winsecur.h" #ifndef NO_MULTIMON #include @@ -76,6 +81,11 @@ #define WHEEL_DELTA 120 #endif +/* VK_PACKET, used to send Unicode characters in WM_KEYDOWNs */ +#ifndef VK_PACKET +#define VK_PACKET 0xE7 +#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, @@ -88,7 +98,7 @@ static void another_font(int); static void deinit_fonts(void); static void set_input_locale(HKL); static void update_savedsess_menu(void); -static void init_flashwindow(void); +static void init_winfuncs(void); static int is_full_screen(void); static void make_full_screen(void); @@ -104,10 +114,6 @@ static int offset_width, offset_height; static int was_zoomed = 0; static int prev_rows, prev_cols; -static int pending_netevent = 0; -static WPARAM pend_netevent_wParam = 0; -static LPARAM pend_netevent_lParam = 0; -static void enact_pending_netevent(void); static void flash_window(int mode); static void sys_cursor_update(void); static int get_fullscreen_rect(RECT * ss); @@ -121,7 +127,7 @@ static Backend *back; static void *backhandle; static struct unicode_data ucsdata; -static int must_close_session, session_closed; +static int session_closed; static int reconfiguring = FALSE; static const struct telnet_special *specials = NULL; @@ -140,6 +146,12 @@ static struct { enum { SYSMENU, CTXMENU }; static HMENU savedsess_menu; +struct wm_netevent_params { + /* Used to pass data to wm_netevent_callback */ + WPARAM wParam; + LPARAM lParam; +}; + Conf *conf; /* exported to windlg.c */ static void conf_cache_data(void); @@ -168,14 +180,15 @@ struct agent_callback { #define FONT_OEMUND 0x22 #define FONT_OEMBOLDUND 0x23 -#define FONT_MAXNO 0x2F +#define FONT_MAXNO 0x40 #define FONT_SHIFT 5 static HFONT fonts[FONT_MAXNO]; static LOGFONT lfont; static int fontflag[FONT_MAXNO]; static enum { - BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT -} bold_mode; + BOLD_NONE, BOLD_SHADOW, BOLD_FONT +} bold_font_mode; +static int bold_colours; static enum { UND_LINE, UND_FONT } und_mode; @@ -206,9 +219,23 @@ static int compose_state = 0; static UINT wm_mousewheel = WM_MOUSEWHEEL; +#define IS_HIGH_VARSEL(wch1, wch2) \ + ((wch1) == 0xDB40 && ((wch2) >= 0xDD00 && (wch2) <= 0xDDEF)) +#define IS_LOW_VARSEL(wch) \ + (((wch) >= 0x180B && (wch) <= 0x180D) || /* MONGOLIAN FREE VARIATION SELECTOR */ \ + ((wch) >= 0xFE00 && (wch) <= 0xFE0F)) /* VARIATION SELECTOR 1-16 */ + +const int share_can_be_downstream = TRUE; +const int share_can_be_upstream = TRUE; + /* Dummy routine, only required in plink. */ -void ldisc_update(void *frontend, int echo, int edit) +void frontend_echoedit_update(void *frontend, int echo, int edit) +{ +} + +int frontend_is_utf8(void *frontend) { + return ucsdata.line_codepage == CP_UTF8; } char *get_ttymode(void *frontend, const char *mode) @@ -282,11 +309,10 @@ static void start_backend(void) DeleteMenu(popup_menus[i].menu, IDM_RESTART, MF_BYCOMMAND); } - must_close_session = FALSE; session_closed = FALSE; } -static void close_session(void) +static void close_session(void *ignored_context) { char morestuff[100]; int i; @@ -317,24 +343,16 @@ static void close_session(void) InsertMenu(popup_menus[i].menu, IDM_DUPSESS, MF_BYCOMMAND | MF_ENABLED, IDM_RESTART, "&Restart Session"); } - - /* - * Unset the 'must_close_session' flag, or else we'll come - * straight back here the next time we go round the main message - * loop - which, worse still, will be immediately (without - * blocking) because we've just triggered a WM_SETTEXT by the - * window title change above. - */ - must_close_session = FALSE; } int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { - WNDCLASS wndclass; MSG msg; HRESULT hr; int guess_width, guess_height; + dll_hijacking_protection(); + hinst = inst; hwnd = NULL; flags = FLAG_VERBOSE | FLAG_INTERACTIVE; @@ -343,6 +361,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) InitCommonControls(); + /* Set Explicit App User Model Id so that jump lists don't cause + PuTTY to hang on to removable media. */ + + set_explicit_app_user_model_id(); + /* Ensure a Maximize setting in Explorer doesn't maximise the * config box. */ defuse_showwindow(); @@ -368,7 +391,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) init_help(); - init_flashwindow(); + init_winfuncs(); conf = conf_new(); @@ -413,11 +436,20 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) * Process a couple of command-line options which are more * easily dealt with before the line is broken up into words. * These are the old-fashioned but convenient @sessionname and - * the internal-use-only &sharedmemoryhandle, neither of which - * are combined with anything else. + * the internal-use-only &sharedmemoryhandle, plus the &R + * prefix for -restrict-acl, all of which are used by PuTTYs + * auto-launching each other via System-menu options. */ while (*p && isspace(*p)) p++; + if (*p == '&' && p[1] == 'R' && + (!p[2] || p[2] == '@' || p[2] == '&')) { + /* &R restrict-acl prefix */ + restrict_process_acl(); + restricted_acl = TRUE; + p += 2; + } + if (*p == '@') { /* * An initial @ means that the whole of the rest of the @@ -455,7 +487,11 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) cleanup_exit(0); } allow_launch = TRUE; - } else { + } else if (!*p) { + /* Do-nothing case for an empty command line - or rather, + * for a command line that's empty _after_ we strip off + * the &R prefix. */ + } else { /* * Otherwise, break up the command line and deal with * it sensibly. @@ -477,39 +513,22 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) i++; /* skip next argument */ } else if (ret == 1) { continue; /* nothing further needs doing */ - } else if (!strcmp(p, "-cleanup") || - !strcmp(p, "-cleanup-during-uninstall")) { + } else if (!strcmp(p, "-cleanup")) { /* * `putty -cleanup'. Remove all registry * entries associated with PuTTY, and also find * and delete the random seed file. */ char *s1, *s2; - /* Are we being invoked from an uninstaller? */ - if (!strcmp(p, "-cleanup-during-uninstall")) { - s1 = dupprintf("Remove saved sessions and random seed file?\n" - "\n" - "If you hit Yes, ALL Registry entries associated\n" - "with %s will be removed, as well as the\n" - "random seed file. THIS PROCESS WILL\n" - "DESTROY YOUR SAVED SESSIONS.\n" - "(This only affects the currently logged-in user.)\n" - "\n" - "If you hit No, uninstallation will proceed, but\n" - "saved sessions etc will be left on the machine.", - appname); - s2 = dupprintf("%s Uninstallation", appname); - } else { - s1 = dupprintf("This procedure will remove ALL Registry entries\n" - "associated with %s, and will also remove\n" - "the random seed file. (This only affects the\n" - "currently logged-in user.)\n" - "\n" - "THIS PROCESS WILL DESTROY YOUR SAVED SESSIONS.\n" - "Are you really sure you want to continue?", - appname); - s2 = dupprintf("%s Warning", appname); - } + s1 = dupprintf("This procedure will remove ALL Registry entries\n" + "associated with %s, and will also remove\n" + "the random seed file. (This only affects the\n" + "currently logged-in user.)\n" + "\n" + "THIS PROCESS WILL DESTROY YOUR SAVED SESSIONS.\n" + "Are you really sure you want to continue?", + appname); + s2 = dupprintf("%s Warning", appname); if (message_box(s1, s2, MB_YESNO | MB_ICONWARNING | MB_DEFBUTTON2, HELPCTXID(option_cleanup)) == IDYES) { @@ -546,8 +565,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) q += 2; conf_set_int(conf, CONF_protocol, PROT_TELNET); p = q; - while (*p && *p != ':' && *p != '/') - p++; + p += host_strcspn(p, ":/"); c = *p; if (*p) *p++ = '\0'; @@ -610,10 +628,21 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } } - /* - * Trim off a colon suffix if it's there. - */ - host[strcspn(host, ":")] = '\0'; + /* + * Trim a colon suffix off the hostname if it's there. In + * order to protect unbracketed IPv6 address literals + * against this treatment, we do not do this if there's + * _more_ than one colon. + */ + { + char *c = host_strchr(host, ':'); + + if (c) { + char *d = host_strchr(c+1, ':'); + if (!d) + *c = '\0'; + } + } /* * Remove any remaining whitespace. @@ -633,6 +662,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } if (!prev) { + WNDCLASSW wndclass; + wndclass.style = 0; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; @@ -642,9 +673,9 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) wndclass.hCursor = LoadCursor(NULL, IDC_IBEAM); wndclass.hbrBackground = NULL; wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = appname; + wndclass.lpszClassName = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname); - RegisterClass(&wndclass); + RegisterClassW(&wndclass); } memset(&ucsdata, 0, sizeof(ucsdata)); @@ -678,6 +709,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) { int winmode = WS_OVERLAPPEDWINDOW | WS_VSCROLL; int exwinmode = 0; + wchar_t *uappname = dup_mb_to_wc(DEFAULT_CODEPAGE, 0, appname); if (!conf_get_int(conf, CONF_scrollbar)) winmode &= ~(WS_VSCROLL); if (conf_get_int(conf, CONF_resize_action) == RESIZE_DISABLED) @@ -686,12 +718,19 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) exwinmode |= WS_EX_TOPMOST; if (conf_get_int(conf, CONF_sunken_edge)) exwinmode |= WS_EX_CLIENTEDGE; - hwnd = CreateWindowEx(exwinmode, appname, appname, - winmode, CW_USEDEFAULT, CW_USEDEFAULT, - guess_width, guess_height, - NULL, NULL, inst, NULL); + hwnd = CreateWindowExW(exwinmode, uappname, uappname, + winmode, CW_USEDEFAULT, CW_USEDEFAULT, + guess_width, guess_height, + NULL, NULL, inst, NULL); + sfree(uappname); } + /* + * Initialise the fonts, simultaneously correcting the guesses + * for font_{width,height}. + */ + init_fonts(0,0); + /* * Initialise the terminal. (We have to do this _after_ * creating the window, since the terminal is the first thing @@ -705,12 +744,6 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) conf_get_int(conf, CONF_width), conf_get_int(conf, CONF_savelines)); - /* - * Initialise the fonts, simultaneously correcting the guesses - * for font_{width,height}. - */ - init_fonts(0,0); - /* * Correct the guesses for extra_{width,height}. */ @@ -791,7 +824,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) AppendMenu(m, MF_SEPARATOR, 0, 0); AppendMenu(m, MF_ENABLED, IDM_NEWSESS, "Ne&w Session..."); AppendMenu(m, MF_ENABLED, IDM_DUPSESS, "&Duplicate Session"); - AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT) savedsess_menu, + AppendMenu(m, MF_POPUP | MF_ENABLED, (UINT_PTR) savedsess_menu, "Sa&ved Sessions"); AppendMenu(m, MF_ENABLED, IDM_RECONF, "Chan&ge Settings..."); AppendMenu(m, MF_SEPARATOR, 0, 0); @@ -811,6 +844,10 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) } } + if (restricted_acl) { + logevent(NULL, "Running with restricted process ACL"); + } + start_backend(); /* @@ -837,43 +874,76 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) while (1) { HANDLE *handles; int nhandles, n; + DWORD timeout; + + if (toplevel_callback_pending() || + PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) { + /* + * If we have anything we'd like to do immediately, set + * the timeout for MsgWaitForMultipleObjects to zero so + * that we'll only do a quick check of our handles and + * then get on with whatever that was. + * + * One such option is a pending toplevel callback. The + * other is a non-empty Windows message queue, which you'd + * think we could leave to MsgWaitForMultipleObjects to + * check for us along with all the handles, but in fact we + * can't because once PeekMessage in one iteration of this + * loop has removed a message from the queue, the whole + * queue is considered uninteresting by the next + * invocation of MWFMO. So we check ourselves whether the + * message queue is non-empty, and if so, set this timeout + * to zero to ensure MWFMO doesn't block. + */ + timeout = 0; + } else { + timeout = INFINITE; + /* The messages seem unreliable; especially if we're being tricky */ + term_set_focus(term, GetForegroundWindow() == hwnd); + } handles = handle_get_events(&nhandles); - n = MsgWaitForMultipleObjects(nhandles, handles, FALSE, INFINITE, - QS_ALLINPUT); + n = MsgWaitForMultipleObjects(nhandles, handles, FALSE, + timeout, QS_ALLINPUT); if ((unsigned)(n - WAIT_OBJECT_0) < (unsigned)nhandles) { handle_got_event(handles[n - WAIT_OBJECT_0]); sfree(handles); - if (must_close_session) - close_session(); } else sfree(handles); - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { + while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) goto finished; /* two-level break */ if (!(IsWindow(logbox) && IsDialogMessage(logbox, &msg))) - DispatchMessage(&msg); - /* Send the paste buffer if there's anything to send */ - term_paste(term); - /* If there's nothing new in the queue then we can do everything - * we've delayed, reading the socket, writing, and repainting - * the window. - */ - if (must_close_session) - close_session(); - } + DispatchMessageW(&msg); - /* The messages seem unreliable; especially if we're being tricky */ - term_set_focus(term, GetForegroundWindow() == hwnd); - - if (pending_netevent) - enact_pending_netevent(); + /* + * WM_NETEVENT messages seem to jump ahead of others in + * the message queue. I'm not sure why; the docs for + * PeekMessage mention that messages are prioritised in + * some way, but I'm unclear on which priorities go where. + * + * Anyway, in practice I observe that WM_NETEVENT seems to + * jump to the head of the queue, which means that if we + * were to only process one message every time round this + * loop, we'd get nothing but NETEVENTs if the server + * flooded us with data, and stop responding to any other + * kind of window message. So instead, we keep on round + * this loop until we've consumed at least one message + * that _isn't_ a NETEVENT, or run out of messages + * completely (whichever comes first). And we don't go to + * run_toplevel_callbacks (which is where the netevents + * are actually processed, causing fresh NETEVENT messages + * to appear) until we've done this. + */ + if (msg.message != WM_NETEVENT) + break; + } - net_pending_errors(); + run_toplevel_callbacks(); } finished: @@ -985,7 +1055,7 @@ void update_specials_menu(void *frontend) saved_menu = new_menu; /* XXX lame stacking */ new_menu = CreatePopupMenu(); AppendMenu(saved_menu, MF_POPUP | MF_ENABLED, - (UINT) new_menu, specials[i].name); + (UINT_PTR) new_menu, specials[i].name); break; case TS_EXITMENU: nesting--; @@ -1010,13 +1080,14 @@ void update_specials_menu(void *frontend) for (j = 0; j < lenof(popup_menus); j++) { if (specials_menu) { /* XXX does this free up all submenus? */ - DeleteMenu(popup_menus[j].menu, (UINT)specials_menu, MF_BYCOMMAND); + DeleteMenu(popup_menus[j].menu, (UINT_PTR)specials_menu, + MF_BYCOMMAND); DeleteMenu(popup_menus[j].menu, IDM_SPECIALSEP, MF_BYCOMMAND); } if (new_menu) { InsertMenu(popup_menus[j].menu, IDM_SHOWLOG, MF_BYCOMMAND | MF_POPUP | MF_ENABLED, - (UINT) new_menu, "S&pecial Command"); + (UINT_PTR) new_menu, "S&pecial Command"); InsertMenu(popup_menus[j].menu, IDM_SHOWLOG, MF_BYCOMMAND | MF_SEPARATOR, IDM_SPECIALSEP, 0); } @@ -1081,7 +1152,7 @@ void set_raw_mouse_mode(void *frontend, int activate) /* * Print a message box and close the connection. */ -void connection_fatal(void *frontend, char *fmt, ...) +void connection_fatal(void *frontend, const char *fmt, ...) { va_list ap; char *stuff, morestuff[100]; @@ -1096,14 +1167,14 @@ void connection_fatal(void *frontend, char *fmt, ...) if (conf_get_int(conf, CONF_close_on_exit) == FORCE_ON) PostQuitMessage(1); else { - must_close_session = TRUE; + queue_toplevel_callback(close_session, NULL); } } /* * Report an error at the command-line parsing stage. */ -void cmdline_error(char *fmt, ...) +void cmdline_error(const char *fmt, ...) { va_list ap; char *stuff, morestuff[100]; @@ -1120,19 +1191,11 @@ void cmdline_error(char *fmt, ...) /* * Actually do the job requested by a WM_NETEVENT */ -static void enact_pending_netevent(void) +static void wm_netevent_callback(void *vctx) { - static int reentering = 0; - extern int select_result(WPARAM, LPARAM); - - if (reentering) - return; /* don't unpend the pending */ - - pending_netevent = FALSE; - - reentering = 1; - select_result(pend_netevent_wParam, pend_netevent_lParam); - reentering = 0; + struct wm_netevent_params *params = (struct wm_netevent_params *)vctx; + select_result(params->wParam, params->lParam); + sfree(vctx); } /* @@ -1403,8 +1466,9 @@ static void init_fonts(int pick_width, int pick_height) for (i = 0; i < FONT_MAXNO; i++) fonts[i] = NULL; - bold_mode = conf_get_int(conf, CONF_bold_colour) ? - BOLD_COLOURS : BOLD_FONT; + bold_font_mode = conf_get_int(conf, CONF_bold_style) & 1 ? + BOLD_FONT : BOLD_NONE; + bold_colours = conf_get_int(conf, CONF_bold_style) & 2 ? TRUE : FALSE; und_mode = UND_FONT; font = conf_get_fontspec(conf, CONF_font); @@ -1470,7 +1534,8 @@ static void init_fonts(int pick_width, int pick_height) if (cset == OEM_CHARSET) ucsdata.font_codepage = GetOEMCP(); else - if (TranslateCharsetInfo ((DWORD *) cset, &info, TCI_SRCCHARSET)) + if (TranslateCharsetInfo ((DWORD *)(ULONG_PTR)cset, + &info, TCI_SRCCHARSET)) ucsdata.font_codepage = info.ciACP; else ucsdata.font_codepage = -1; @@ -1529,7 +1594,7 @@ static void init_fonts(int pick_width, int pick_height) } } - if (bold_mode == BOLD_FONT) { + if (bold_font_mode == BOLD_FONT) { f(FONT_BOLD, font->charset, fw_bold, FALSE); } #undef f @@ -1556,9 +1621,9 @@ static void init_fonts(int pick_width, int pick_height) fonts[FONT_UNDERLINE] = 0; } - if (bold_mode == BOLD_FONT && + if (bold_font_mode == BOLD_FONT && fontsize[FONT_BOLD] != fontsize[FONT_NORMAL]) { - bold_mode = BOLD_SHADOW; + bold_font_mode = BOLD_SHADOW; DeleteObject(fonts[FONT_BOLD]); fonts[FONT_BOLD] = 0; } @@ -1992,7 +2057,7 @@ void notify_remote_exit(void *fe) (close_on_exit == AUTO && exitcode != INT_MAX)) { PostQuitMessage(0); } else { - must_close_session = TRUE; + queue_toplevel_callback(close_session, NULL); session_closed = TRUE; /* exitcode == INT_MAX indicates that the connection was closed * by a fatal error, so an error box will be coming our way and @@ -2004,10 +2069,14 @@ void notify_remote_exit(void *fe) } } -void timer_change_notify(long next) +void timer_change_notify(unsigned long next) { - long ticks = next - GETTICKCOUNT(); - if (ticks <= 0) ticks = 1; /* just in case */ + unsigned long now = GETTICKCOUNT(); + long ticks; + if (now - next < INT_MAX) + ticks = 0; + else + ticks = next - now; KillTimer(hwnd, TIMING_TIMER_ID); SetTimer(hwnd, TIMING_TIMER_ID, ticks, NULL); timing_next_time = next; @@ -2034,7 +2103,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, switch (message) { case WM_TIMER: if ((UINT_PTR)wParam == TIMING_TIMER_ID) { - long next; + unsigned long next; KillTimer(hwnd, TIMING_TIMER_ID); if (run_timers(timing_next_time, &next)) { @@ -2084,13 +2153,18 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case IDM_SAVEDSESS: { char b[2048]; - char c[30], *cl; - int freecl = FALSE; + char *cl; + const char *argprefix; BOOL inherit_handles; STARTUPINFO si; PROCESS_INFORMATION pi; HANDLE filemap = NULL; + if (restricted_acl) + argprefix = "&R"; + else + argprefix = ""; + if (wParam == IDM_DUPSESS) { /* * Allocate a file-mapping memory chunk for the @@ -2117,20 +2191,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } } inherit_handles = TRUE; - sprintf(c, "putty &%p:%u", filemap, (unsigned)size); - cl = c; + cl = dupprintf("putty %s&%p:%u", argprefix, + filemap, (unsigned)size); } else if (wParam == IDM_SAVEDSESS) { unsigned int sessno = ((lParam - IDM_SAVED_MIN) / MENU_SAVED_STEP) + 1; if (sessno < (unsigned)sesslist.nsessions) { - char *session = sesslist.sessions[sessno]; - cl = dupprintf("putty @%s", session); + const char *session = sesslist.sessions[sessno]; + cl = dupprintf("putty %s@%s", argprefix, session); inherit_handles = FALSE; - freecl = TRUE; } else break; } else /* IDM_NEWSESS */ { - cl = NULL; + cl = dupprintf("putty%s%s", + *argprefix ? " " : "", + argprefix); inherit_handles = FALSE; } @@ -2144,11 +2219,12 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, si.lpReserved2 = NULL; CreateProcess(b, cl, NULL, NULL, inherit_handles, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); if (filemap) CloseHandle(filemap); - if (freecl) - sfree(cl); + sfree(cl); } break; case IDM_RESTART: @@ -2183,8 +2259,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, reconfig_result = do_reconfig(hwnd, back ? back->cfg_info(backhandle) : 0); reconfiguring = FALSE; - if (!reconfig_result) + if (!reconfig_result) { + conf_free(prev_conf); break; + } conf_cache_data(); @@ -2210,9 +2288,10 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * Flush the line discipline's edit buffer in the * case where local editing has just been disabled. */ - ldisc_configure(ldisc, conf); - if (ldisc) - ldisc_send(ldisc, NULL, 0, 0); + if (ldisc) { + ldisc_configure(ldisc, conf); + ldisc_echoedit_update(ldisc); + } if (pal) DeleteObject(pal); logpal = NULL; @@ -2327,8 +2406,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, conf_get_int(prev_conf, CONF_font_quality) || conf_get_int(conf, CONF_vtmode) != conf_get_int(prev_conf, CONF_vtmode) || - conf_get_int(conf, CONF_bold_colour) != - conf_get_int(prev_conf, CONF_bold_colour) || + conf_get_int(conf, CONF_bold_style) != + conf_get_int(prev_conf, CONF_bold_style) || resize_action == RESIZE_DISABLED || resize_action == RESIZE_EITHER || resize_action != conf_get_int(prev_conf, @@ -2338,7 +2417,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, InvalidateRect(hwnd, NULL, TRUE); reset_window(init_lvl); - net_pending_errors(); conf_free(prev_conf); } @@ -2355,7 +2433,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case IDM_RESET: term_pwron(term, TRUE); if (ldisc) - ldisc_send(ldisc, NULL, 0, 0); + ldisc_echoedit_update(ldisc); break; case IDM_ABOUT: showabout(hwnd); @@ -2401,7 +2479,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; if (back) back->special(backhandle, specials[i].code); - net_pending_errors(); } } break; @@ -2681,20 +2758,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } return 0; case WM_NETEVENT: - /* Notice we can get multiple netevents, FD_READ, FD_WRITE etc - * but the only one that's likely to try to overload us is FD_READ. - * This means buffering just one is fine. - */ - if (pending_netevent) - enact_pending_netevent(); - - pending_netevent = TRUE; - pend_netevent_wParam = wParam; - pend_netevent_lParam = lParam; - if (WSAGETSELECTEVENT(lParam) != FD_READ) - enact_pending_netevent(); - - net_pending_errors(); + { + /* + * To protect against re-entrancy when Windows's recv() + * immediately triggers a new WSAAsyncSelect window + * message, we don't call select_result directly from this + * handler but instead wait until we're back out at the + * top level of the message loop. + */ + struct wm_netevent_params *params = + snew(struct wm_netevent_params); + params->wParam = wParam; + params->lParam = lParam; + queue_toplevel_callback(wm_netevent_callback, params); + } return 0; case WM_SETFOCUS: term_set_focus(term, TRUE); @@ -2980,7 +3057,19 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, break; case SB_THUMBPOSITION: case SB_THUMBTRACK: - term_scroll(term, 1, HIWORD(wParam)); + /* + * Use GetScrollInfo instead of HIWORD(wParam) to get + * 32-bit scroll position. + */ + { + SCROLLINFO si; + + si.cbSize = sizeof(si); + si.fMask = SIF_TRACKPOS; + if (GetScrollInfo(hwnd, SB_VERT, &si) == 0) + si.nTrackPos = HIWORD(wParam); + term_scroll(term, 1, si.nTrackPos); + } break; } break; @@ -3026,7 +3115,8 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, unsigned char buf[20]; int len; - if (wParam == VK_PROCESSKEY) { /* IME PROCESS key */ + if (wParam == VK_PROCESSKEY || /* IME PROCESS key */ + wParam == VK_PACKET) { /* 'this key is a Unicode char' */ if (message == WM_KEYDOWN) { MSG m; m.hwnd = hwnd; @@ -3038,17 +3128,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } else { len = TranslateKey(message, wParam, lParam, buf); if (len == -1) - return DefWindowProc(hwnd, message, wParam, lParam); + return DefWindowProcW(hwnd, message, wParam, lParam); if (len != 0) { - /* - * Interrupt an ongoing paste. I'm not sure - * this is sensible, but for the moment it's - * preferable to having to faff about buffering - * things. - */ - term_nopaste(term); - /* * We need not bother about stdin backlogs * here, because in GUI PuTTY we can't do @@ -3059,12 +3141,11 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, */ term_seen_key_event(term); if (ldisc) - ldisc_send(ldisc, buf, len, 1); + ldisc_send(ldisc, (char *)buf, len, 1); show_mouseptr(0); } } } - net_pending_errors(); return 0; case WM_INPUTLANGCHANGE: /* wParam == Font number */ @@ -3105,9 +3186,20 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * instead we luni_send the characters one by one. */ term_seen_key_event(term); - for (i = 0; i < n; i += 2) { - if (ldisc) + /* don't divide SURROGATE PAIR */ + if (ldisc) { + for (i = 0; i < n; i += 2) { + WCHAR hs = *(unsigned short *)(buff+i); + if (IS_HIGH_SURROGATE(hs) && i+2 < n) { + WCHAR ls = *(unsigned short *)(buff+i+2); + if (IS_LOW_SURROGATE(ls)) { + luni_send(ldisc, (unsigned short *)(buff+i), 2, 1); + i += 2; + continue; + } + } luni_send(ldisc, (unsigned short *)(buff+i), 1, 1); + } } free(buff); } @@ -3117,7 +3209,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, case WM_IME_CHAR: if (wParam & 0xFF00) { - unsigned char buf[2]; + char buf[2]; buf[1] = wParam; buf[0] = wParam >> 8; @@ -3140,10 +3232,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * we're ready to cope. */ { - char c = (unsigned char)wParam; - term_seen_key_event(term); - if (ldisc) - lpage_send(ldisc, CP_ACP, &c, 1, 1); + static wchar_t pending_surrogate = 0; + wchar_t c = wParam; + + if (IS_HIGH_SURROGATE(c)) { + pending_surrogate = c; + } else if (IS_SURROGATE_PAIR(pending_surrogate, c)) { + wchar_t pair[2]; + pair[0] = pending_surrogate; + pair[1] = c; + term_seen_key_event(term); + luni_send(ldisc, pair, 2, 1); + } else if (!IS_SURROGATE(c)) { + term_seen_key_event(term); + luni_send(ldisc, &c, 1, 1); + } } return 0; case WM_SYSCOLORCHANGE: @@ -3198,8 +3301,9 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, } else break; - if (send_raw_mouse && shift_pressed && - !(conf_get_int(conf, CONF_mouse_override))) { + if (send_raw_mouse && + !(conf_get_int(conf, CONF_mouse_override) && + shift_pressed)) { /* Mouse wheel position is in screen coordinates for * some reason */ POINT p; @@ -3211,10 +3315,6 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, TO_CHR_X(p.x), TO_CHR_Y(p.y), shift_pressed, control_pressed, is_alt_pressed()); - term_mouse(term, b, translate_button(b), - MA_RELEASE, TO_CHR_X(p.x), - TO_CHR_Y(p.y), shift_pressed, - control_pressed, is_alt_pressed()); } /* else: not sure when this can fail */ } else { /* trigger a scroll */ @@ -3231,7 +3331,7 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, * Any messages we don't process completely above are passed through to * DefWindowProc() for default processing. */ - return DefWindowProc(hwnd, message, wParam, lParam); + return DefWindowProcW(hwnd, message, wParam, lParam); } /* @@ -3306,9 +3406,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, int text_adjust = 0; int xoffset = 0; int maxlen, remaining, opaque; + int is_cursor = FALSE; static int *lpDx = NULL; static int lpDx_len = 0; int *lpDx_maybe; + int len2; /* for SURROGATE PAIR */ lattr &= LATTR_MODE; @@ -3328,11 +3430,9 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if ((attr & TATTR_ACTCURS) && (cursor_type == 0 || term->big_cursor)) { attr &= ~(ATTR_REVERSE|ATTR_BLINK|ATTR_COLOURS); - if (bold_mode == BOLD_COLOURS) - attr &= ~ATTR_BOLD; - /* cursor fg and bg */ attr |= (260 << ATTR_FGSHIFT) | (261 << ATTR_BGSHIFT); + is_cursor = TRUE; } nfont = 0; @@ -3353,6 +3453,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, if (attr & ATTR_NARROW) nfont |= FONT_NARROW; +#ifdef USES_VTLINE_HACK /* Special hack for the VT100 linedraw glyphs. */ if (text[0] >= 0x23BA && text[0] <= 0x23BD) { switch ((unsigned char) (text[0])) { @@ -3377,9 +3478,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, force_manual_underline = 1; } } +#endif /* Anything left as an original character set is unprintable. */ - if (DIRECT_CHAR(text[0])) { + if (DIRECT_CHAR(text[0]) && + (len < 2 || !IS_SURROGATE_PAIR(text[0], text[1]))) { int i; for (i = 0; i < len; i++) text[i] = 0xFFFD; @@ -3391,7 +3494,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, nfg = ((attr & ATTR_FGMASK) >> ATTR_FGSHIFT); nbg = ((attr & ATTR_BGMASK) >> ATTR_BGSHIFT); - if (bold_mode == BOLD_FONT && (attr & ATTR_BOLD)) + if (bold_font_mode == BOLD_FONT && (attr & ATTR_BOLD)) nfont |= FONT_BOLD; if (und_mode == UND_FONT && (attr & ATTR_UNDER)) nfont |= FONT_UNDERLINE; @@ -3411,11 +3514,11 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, nfg = nbg; nbg = t; } - if (bold_mode == BOLD_COLOURS && (attr & ATTR_BOLD)) { + if (bold_colours && (attr & ATTR_BOLD) && !is_cursor) { if (nfg < 16) nfg |= 8; else if (nfg >= 256) nfg |= 1; } - if (bold_mode == BOLD_COLOURS && (attr & ATTR_BLINK)) { + if (bold_colours && (attr & ATTR_BLINK)) { if (nbg < 16) nbg |= 8; else if (nbg >= 256) nbg |= 1; } @@ -3432,6 +3535,24 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, line_box.top = y; line_box.right = x + char_width * len; line_box.bottom = y + font_height; + /* adjust line_box.right for SURROGATE PAIR & VARIATION SELECTOR */ + { + int i; + int rc_width = 0; + for (i = 0; i < len ; i++) { + if (i+1 < len && IS_HIGH_VARSEL(text[i], text[i+1])) { + i++; + } else if (i+1 < len && IS_SURROGATE_PAIR(text[i], text[i+1])) { + rc_width += char_width; + i++; + } else if (IS_LOW_VARSEL(text[i])) { + /* do nothing */ + } else { + rc_width += char_width; + } + } + line_box.right = line_box.left + rc_width; + } /* Only want the left half of double width lines */ if (line_box.right > font_width*term->cols+offset_width) @@ -3462,19 +3583,47 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, opaque = TRUE; /* start by erasing the rectangle */ for (remaining = len; remaining > 0; - text += len, remaining -= len, x += char_width * len) { + text += len, remaining -= len, x += char_width * len2) { len = (maxlen < remaining ? maxlen : remaining); - - if (len > lpDx_len) { - if (len > lpDx_len) { - lpDx_len = len * 9 / 8 + 16; - lpDx = sresize(lpDx, lpDx_len, int); - } + /* don't divide SURROGATE PAIR and VARIATION SELECTOR */ + len2 = len; + if (maxlen == 1) { + if (remaining >= 1 && IS_SURROGATE_PAIR(text[0], text[1])) + len++; + if (remaining-len >= 1 && IS_LOW_VARSEL(text[len])) + len++; + else if (remaining-len >= 2 && + IS_HIGH_VARSEL(text[len], text[len+1])) + len += 2; } + + if (len > lpDx_len) { + lpDx_len = len * 9 / 8 + 16; + lpDx = sresize(lpDx, lpDx_len, int); + + if (lpDx_maybe) lpDx_maybe = lpDx; + } + { int i; - for (i = 0; i < len; i++) + /* only last char has dx width in SURROGATE PAIR and + * VARIATION sequence */ + for (i = 0; i < len; i++) { lpDx[i] = char_width; + if (i+1 < len && IS_HIGH_VARSEL(text[i], text[i+1])) { + if (i > 0) lpDx[i-1] = 0; + lpDx[i] = 0; + i++; + lpDx[i] = char_width; + } else if (i+1 < len && IS_SURROGATE_PAIR(text[i],text[i+1])) { + lpDx[i] = 0; + i++; + lpDx[i] = char_width; + } else if (IS_LOW_VARSEL(text[i])) { + if (i > 0) lpDx[i-1] = 0; + lpDx[i] = char_width; + } + } } /* We're using a private area for direct to font. (512 chars.) */ @@ -3519,7 +3668,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), &line_box, uni_buf, nlen, lpDx_maybe); - if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { + if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { SetBkMode(hdc, TRANSPARENT); ExtTextOutW(hdc, x + xoffset - 1, y - font_height * (lattr == @@ -3544,7 +3693,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, y - font_height * (lattr == LATTR_BOT) + text_adjust, ETO_CLIPPED | (opaque ? ETO_OPAQUE : 0), &line_box, directbuf, len, lpDx_maybe); - if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { + if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { SetBkMode(hdc, TRANSPARENT); /* GRR: This draws the character outside its box and @@ -3583,7 +3732,7 @@ void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len, opaque && !(attr & TATTR_COMBINING)); /* And the shadow bold hack. */ - if (bold_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { + if (bold_font_mode == BOLD_SHADOW && (attr & ATTR_BOLD)) { SetBkMode(hdc, TRANSPARENT); ExtTextOutW(hdc, x + xoffset - 1, y - font_height * (lattr == @@ -3623,9 +3772,35 @@ void do_text(Context ctx, int x, int y, wchar_t *text, int len, { if (attr & TATTR_COMBINING) { unsigned long a = 0; - attr &= ~TATTR_COMBINING; + int len0 = 1; + /* don't divide SURROGATE PAIR and VARIATION SELECTOR */ + if (len >= 2 && IS_SURROGATE_PAIR(text[0], text[1])) + len0 = 2; + if (len-len0 >= 1 && IS_LOW_VARSEL(text[len0])) { + attr &= ~TATTR_COMBINING; + do_text_internal(ctx, x, y, text, len0+1, attr, lattr); + text += len0+1; + len -= len0+1; + a = TATTR_COMBINING; + } else if (len-len0 >= 2 && IS_HIGH_VARSEL(text[len0], text[len0+1])) { + attr &= ~TATTR_COMBINING; + do_text_internal(ctx, x, y, text, len0+2, attr, lattr); + text += len0+2; + len -= len0+2; + a = TATTR_COMBINING; + } else { + attr &= ~TATTR_COMBINING; + } + while (len--) { - do_text_internal(ctx, x, y, text, 1, attr | a, lattr); + if (len >= 1 && IS_SURROGATE_PAIR(text[0], text[1])) { + do_text_internal(ctx, x, y, text, 2, attr | a, lattr); + len--; + text++; + } else { + do_text_internal(ctx, x, y, text, 1, attr | a, lattr); + } + text++; a = TATTR_COMBINING; } @@ -3771,6 +3946,17 @@ int char_width(Context ctx, int uc) { return ibuf; } +DECL_WINDOWS_FUNCTION(static, BOOL, FlashWindowEx, (PFLASHWINFO)); +DECL_WINDOWS_FUNCTION(static, BOOL, ToUnicodeEx, + (UINT, UINT, const BYTE *, LPWSTR, int, UINT, HKL)); + +static void init_winfuncs(void) +{ + HMODULE user32_module = load_system32_dll("user32.dll"); + GET_WINDOWS_FUNCTION(user32_module, FlashWindowEx); + GET_WINDOWS_FUNCTION(user32_module, ToUnicodeEx); +} + /* * Translate a WM_(SYS)?KEY(UP|DOWN) message into a string of ASCII * codes. Returns number of bytes used, zero to drop the message, @@ -3792,8 +3978,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, HKL kbd_layout = GetKeyboardLayout(0); - /* keys is for ToAsciiEx. There's some ick here, see below. */ - static WORD keys[3]; + static wchar_t keys_unicode[3]; static int compose_char = 0; static WPARAM compose_keycode = 0; @@ -3845,12 +4030,12 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, else if (ch) debug((", $%02x", ch)); - if (keys[0]) - debug((", KB0=%02x", keys[0])); - if (keys[1]) - debug((", KB1=%02x", keys[1])); - if (keys[2]) - debug((", KB2=%02x", keys[2])); + if (keys_unicode[0]) + debug((", KB0=%04x", keys_unicode[0])); + if (keys_unicode[1]) + debug((", KB1=%04x", keys_unicode[1])); + if (keys_unicode[2]) + debug((", KB2=%04x", keys_unicode[2])); if ((keystate[VK_SHIFT] & 0x80) != 0) debug((", S")); @@ -4064,7 +4249,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, *p++ = "hH\010\010"[shift_state & 3]; return p - output; case VK_NUMPAD5: - *p++ = shift_state ? '.' : '.'; + *p++ = '.'; return p - output; case VK_NUMPAD6: *p++ = "lL\014\014"[shift_state & 3]; @@ -4429,7 +4614,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, break; } if (xkey) { - p += format_arrow_key(p, term, xkey, shift_state); + p += format_arrow_key((char *)p, term, xkey, shift_state); return p - output; } } @@ -4465,7 +4650,10 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, /* XXX how do we know what the max size of the keys array should * be is? There's indication on MS' website of an Inquire/InquireEx * functioning returning a KBINFO structure which tells us. */ - if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) { + if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT && p_ToUnicodeEx) { + r = p_ToUnicodeEx(wParam, scan, keystate, keys_unicode, + lenof(keys_unicode), 0, kbd_layout); + } else { /* XXX 'keys' parameter is declared in MSDN documentation as * 'LPWORD lpChar'. * The experience of a French user indicates that on @@ -4476,12 +4664,17 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, * Win9x/NT split, but I suspect it's worse than that. * See wishlist item `win-dead-keys' for more horrible detail * and speculations. */ - BYTE keybs[3]; int i; - r = ToAsciiEx(wParam, scan, keystate, (LPWORD)keybs, 0, kbd_layout); - for (i=0; i<3; i++) keys[i] = keybs[i]; - } else { + static WORD keys[3]; + static BYTE keysb[3]; r = ToAsciiEx(wParam, scan, keystate, keys, 0, kbd_layout); + if (r > 0) { + for (i = 0; i < r; i++) { + keysb[i] = (BYTE)keys[i]; + } + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)keysb, r, + keys_unicode, lenof(keys_unicode)); + } } #ifdef SHOW_TOASCII_RESULT if (r == 1 && !key_down) { @@ -4491,13 +4684,13 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, else debug((", LCH(%d)", alt_sum)); } else { - debug((", ACH(%d)", keys[0])); + debug((", ACH(%d)", keys_unicode[0])); } } else if (r > 0) { int r1; debug((", ASC(")); for (r1 = 0; r1 < r; r1++) { - debug(("%s%d", r1 ? "," : "", keys[r1])); + debug(("%s%d", r1 ? "," : "", keys_unicode[r1])); } debug((")")); } @@ -4505,27 +4698,20 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (r > 0) { WCHAR keybuf; - /* - * Interrupt an ongoing paste. I'm not sure this is - * sensible, but for the moment it's preferable to - * having to faff about buffering things. - */ - term_nopaste(term); - p = output; for (i = 0; i < r; i++) { - unsigned char ch = (unsigned char) keys[i]; + wchar_t wch = keys_unicode[i]; - if (compose_state == 2 && (ch & 0x80) == 0 && ch > ' ') { - compose_char = ch; + if (compose_state == 2 && wch >= ' ' && wch < 0x80) { + compose_char = wch; compose_state++; continue; } - if (compose_state == 3 && (ch & 0x80) == 0 && ch > ' ') { + if (compose_state == 3 && wch >= ' ' && wch < 0x80) { int nc; compose_state = 0; - if ((nc = check_compose(compose_char, ch)) == -1) { + if ((nc = check_compose(compose_char, wch)) == -1) { MessageBeep(MB_ICONHAND); return 0; } @@ -4546,7 +4732,7 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, if (ldisc) luni_send(ldisc, &keybuf, 1, 1); } else { - ch = (char) alt_sum; + char ch = (char) alt_sum; /* * We need not bother about stdin * backlogs here, because in GUI PuTTY @@ -4564,40 +4750,39 @@ static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, } else { term_seen_key_event(term); if (ldisc) - lpage_send(ldisc, kbd_codepage, &ch, 1, 1); + luni_send(ldisc, &wch, 1, 1); } } else { - if(capsOn && ch < 0x80) { + if(capsOn && wch < 0x80) { WCHAR cbuf[2]; cbuf[0] = 27; - cbuf[1] = xlat_uskbd2cyrllic(ch); + cbuf[1] = xlat_uskbd2cyrllic(wch); term_seen_key_event(term); if (ldisc) luni_send(ldisc, cbuf+!left_alt, 1+!!left_alt, 1); } else { - char cbuf[2]; + WCHAR cbuf[2]; cbuf[0] = '\033'; - cbuf[1] = ch; + cbuf[1] = wch; term_seen_key_event(term); if (ldisc) - lpage_send(ldisc, kbd_codepage, - cbuf+!left_alt, 1+!!left_alt, 1); + luni_send(ldisc, cbuf +!left_alt, 1+!!left_alt, 1); } } show_mouseptr(0); } /* This is so the ALT-Numpad and dead keys work correctly. */ - keys[0] = 0; + keys_unicode[0] = 0; return p - output; } /* If we're definitly not building up an ALT-54321 then clear it */ if (!left_alt) - keys[0] = 0; + keys_unicode[0] = 0; /* If we will be using alt_sum fix the 256s */ - else if (keys[0] && (in_utf(term) || ucsdata.dbcs_screenfont)) - keys[0] = 10; + else if (keys_unicode[0] && (in_utf(term) || ucsdata.dbcs_screenfont)) + keys_unicode[0] = 10; } /* @@ -4684,7 +4869,7 @@ void palette_set(void *frontend, int n, int r, int g, int b) { if (n >= 16) n += 256 - 16; - if (n > NALLCOLOURS) + if (n >= NALLCOLOURS) return; real_palette_set(n, r, g, b); if (pal) { @@ -4784,10 +4969,17 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des GlobalFree(clipdata2); return; } - if (!(lock = GlobalLock(clipdata))) + if (!(lock = GlobalLock(clipdata))) { + GlobalFree(clipdata); + GlobalFree(clipdata2); return; - if (!(lock2 = GlobalLock(clipdata2))) + } + if (!(lock2 = GlobalLock(clipdata2))) { + GlobalUnlock(clipdata); + GlobalFree(clipdata); + GlobalFree(clipdata2); return; + } memcpy(lock, data, len * sizeof(wchar_t)); WideCharToMultiByte(CP_ACP, 0, data, len, lock2, len2, NULL, NULL); @@ -4837,7 +5029,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des bgcolour = tmpcolour; } - if (bold_mode == BOLD_COLOURS && (attr[i] & ATTR_BOLD)) { + if (bold_colours && (attr[i] & ATTR_BOLD)) { if (fgcolour < 8) /* ANSI colours */ fgcolour += 8; else if (fgcolour >= 256) /* Default colours */ @@ -4928,7 +5120,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des bgcolour = tmpcolour; } - if (bold_mode == BOLD_COLOURS && (attr[tindex] & ATTR_BOLD)) { + if (bold_colours && (attr[tindex] & ATTR_BOLD)) { if (fgcolour < 8) /* ANSI colours */ fgcolour += 8; else if (fgcolour >= 256) /* Default colours */ @@ -4945,7 +5137,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des /* * Collect other attributes */ - if (bold_mode != BOLD_COLOURS) + if (bold_font_mode != BOLD_NONE) attrBold = attr[tindex] & ATTR_BOLD; else attrBold = 0; @@ -4964,7 +5156,7 @@ void write_clip(void *frontend, wchar_t * data, int *attr, int len, int must_des bgcolour = -1; /* No coloring */ if (fgcolour >= 256) { /* Default colour */ - if (bold_mode == BOLD_COLOURS && (fgcolour & 1) && bgcolour == -1) + if (bold_colours && (fgcolour & 1) && bgcolour == -1) attrBold = ATTR_BOLD; /* Emphasize text with bold attribute */ fgcolour = -1; /* No coloring */ @@ -5197,7 +5389,7 @@ void optimised_move(void *frontend, int to, int from, int lines) /* * Print a message box and perform a fatal exit. */ -void fatalbox(char *fmt, ...) +void fatalbox(const char *fmt, ...) { va_list ap; char *stuff, morestuff[100]; @@ -5214,7 +5406,7 @@ void fatalbox(char *fmt, ...) /* * Print a modal (Really Bad) message box and perform a fatal exit. */ -void modalfatalbox(char *fmt, ...) +void modalfatalbox(const char *fmt, ...) { va_list ap; char *stuff, morestuff[100]; @@ -5229,12 +5421,20 @@ void modalfatalbox(char *fmt, ...) cleanup_exit(1); } -DECL_WINDOWS_FUNCTION(static, BOOL, FlashWindowEx, (PFLASHWINFO)); - -static void init_flashwindow(void) +/* + * Print a message box and don't close the connection. + */ +void nonfatal(const char *fmt, ...) { - HMODULE user32_module = load_system32_dll("user32.dll"); - GET_WINDOWS_FUNCTION(user32_module, FlashWindowEx); + va_list ap; + char *stuff, morestuff[100]; + + va_start(ap, fmt); + stuff = dupvprintf(fmt, ap); + va_end(ap); + sprintf(morestuff, "%.70s Error", appname); + MessageBox(hwnd, stuff, morestuff, MB_ICONERROR | MB_OK); + sfree(stuff); } static BOOL flash_window_ex(DWORD dwFlags, UINT uCount, DWORD dwTimeout) @@ -5260,9 +5460,9 @@ static int flashing = 0; * Timer for platforms where we must maintain window flashing manually * (e.g., Win95). */ -static void flash_window_timer(void *ctx, long now) +static void flash_window_timer(void *ctx, unsigned long now) { - if (flashing && now - next_flash >= 0) { + if (flashing && now == next_flash) { flash_window(1); } } @@ -5631,7 +5831,7 @@ int from_backend_eof(void *frontend) return TRUE; /* do respond to incoming EOF with outgoing */ } -int get_userpass_input(prompts_t *p, unsigned char *in, int inlen) +int get_userpass_input(prompts_t *p, const unsigned char *in, int inlen) { int ret; ret = cmdline_get_passwd_input(p, in, inlen);