#include <windows.h>
#include <commctrl.h>
+#ifndef AUTO_WINSOCK
+#ifdef WINSOCK_TWO
+#include <winsock2.h>
+#else
#include <winsock.h>
+#endif
+#endif
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
#include "putty.h"
+#include "storage.h"
#include "win_res.h"
#define IDM_SHOWLOG 0x0010
#define WM_IGNORE_SIZE (WM_XUSER + 1)
#define WM_IGNORE_CLIP (WM_XUSER + 2)
-#define WM_IGNORE_KEYMENU (WM_XUSER + 3)
static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
static int TranslateKey(UINT message, WPARAM wParam, LPARAM lParam, unsigned char *output);
#define FONT_OEMBOLDUND 6
#define FONT_OEMUND 7
static HFONT fonts[8];
+static int font_needs_hand_underlining;
static enum {
BOLD_COLOURS, BOLD_SHADOW, BOLD_FONT
} bold_mode;
static HWND hwnd;
+static HBITMAP caretbm;
+
static int dbltime, lasttime, lastact;
static Mouse_Button lastbtn;
static char *window_name, *icon_name;
+static Ldisc *real_ldisc;
+
+void begin_session(void) {
+ ldisc = real_ldisc;
+}
+
int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) {
static char appname[] = "PuTTY";
WORD winsock_ver;
int guess_width, guess_height;
putty_inst = inst;
- flags = FLAG_VERBOSE | FLAG_WINDOWED | FLAG_CONNECTION;
+ flags = FLAG_VERBOSE | FLAG_INTERACTIVE;
winsock_ver = MAKEWORD(1, 1);
if (WSAStartup(winsock_ver, &wsadata)) {
tolower(p[1]) == 'o' &&
tolower(p[2]) == 'g') {
logfile = "putty.log";
+ } else if (q == p + 7 &&
+ tolower(p[0]) == 'c' &&
+ tolower(p[1]) == 'l' &&
+ tolower(p[2]) == 'e' &&
+ tolower(p[3]) == 'a' &&
+ tolower(p[4]) == 'n' &&
+ tolower(p[5]) == 'u' &&
+ tolower(p[6]) == 'p') {
+ /*
+ * `putty -cleanup'. Remove all registry 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"
+ "\n"
+ "THIS PROCESS WILL DESTROY YOUR SAVED\n"
+ "SESSIONS. Are you really sure you want\n"
+ "to continue?",
+ "PuTTY Warning",
+ MB_YESNO | MB_ICONWARNING) == IDYES) {
+ cleanup_all();
+ }
+ exit(0);
}
p = q + strspn(q, " \t");
}
return 0;
}
}
+
+ /* See if host is of the form user@host */
+ if (cfg.host[0] != '\0') {
+ char *atsign = strchr(cfg.host, '@');
+ /* Make sure we're not overflowing the user field */
+ if (atsign) {
+ if (atsign-cfg.host < sizeof cfg.username) {
+ strncpy (cfg.username, cfg.host, atsign-cfg.host);
+ cfg.username[atsign-cfg.host] = '\0';
+ }
+ memmove(cfg.host, atsign+1, 1+strlen(atsign+1));
+ }
+ }
}
/*
}
}
- ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple);
+ real_ldisc = (cfg.ldisc_term ? &ldisc_term : &ldisc_simple);
+ /* To start with, we use the simple line discipline, so we can
+ * type passwords etc without fear of them being echoed... */
+ ldisc = &ldisc_simple;
if (!prev) {
wndclass.style = 0;
SWP_NOMOVE | SWP_NOREDRAW | SWP_NOZORDER);
/*
+ * Set up a caret bitmap, with no content.
+ */
+ {
+ char *bits;
+ int size = (font_width+15)/16 * 2 * font_height;
+ bits = calloc(size, 1);
+ caretbm = CreateBitmap(font_width, font_height, 1, 1, bits);
+ free(bits);
+ }
+
+ /*
* Initialise the scroll bar.
*/
{
*/
{
char *error;
- char msg[1024];
+ char msg[1024], *title;
char *realhost;
error = back->init (hwnd, cfg.host, cfg.port, &realhost);
return 0;
}
window_name = icon_name = NULL;
- sprintf(msg, "%s - PuTTY", realhost);
- set_title (msg);
- set_icon (msg);
+ if (*cfg.wintitle) {
+ title = cfg.wintitle;
+ } else {
+ sprintf(msg, "%s - PuTTY", realhost);
+ title = msg;
+ }
+ set_title (title);
+ set_icon (title);
}
session_closed = FALSE;
KillTimer(hwnd, timer_id);
timer_id = 0;
}
+ HideCaret(hwnd);
if (inbuf_head)
term_out();
term_update();
+ ShowCaret(hwnd);
if (!has_focus)
timer_id = SetTimer(hwnd, 1, 2000, NULL);
else if (cfg.blinktext)
}
/*
+ * Print a message box and close the connection.
+ */
+void connection_fatal(char *fmt, ...) {
+ va_list ap;
+ char stuff[200];
+
+ va_start(ap, fmt);
+ vsprintf(stuff, fmt, ap);
+ va_end(ap);
+ MessageBox(hwnd, stuff, "PuTTY Fatal Error", MB_ICONERROR | MB_OK);
+ if (cfg.close_on_exit)
+ PostQuitMessage(1);
+ else {
+ session_closed = TRUE;
+ SetWindowText (hwnd, "PuTTY (inactive)");
+ }
+}
+
+/*
* Actually do the job requested by a WM_NETEVENT
*/
static void enact_pending_netevent(void) {
int i;
+ static int reentering = 0;
+
+ if (reentering)
+ return; /* don't unpend the pending */
+
pending_netevent = FALSE;
+
+ reentering = 1;
i = back->msg (pend_netevent_wParam, pend_netevent_lParam);
+ reentering = 0;
if (i < 0) {
char buf[1024];
sprintf(buf, "Unexpected network error %d", -i);
break;
}
- MessageBox(hwnd, buf, "PuTTY Fatal Error",
- MB_ICONERROR | MB_OK);
- PostQuitMessage(1);
- } else if (i == 0) {
+ connection_fatal(buf);
+ }
+ if (i <= 0) {
if (cfg.close_on_exit)
PostQuitMessage(0);
else {
f(FONT_UNDERLINE, cfg.fontcharset, fw_dontcare, TRUE);
+ /*
+ * Some fonts, e.g. 9-pt Courier, draw their underlines
+ * outside their character cell. We successfully prevent
+ * screen corruption by clipping the text output, but then
+ * we lose the underline completely. Here we try to work
+ * out whether this is such a font, and if it is, we set a
+ * flag that causes underlines to be drawn by hand.
+ *
+ * Having tried other more sophisticated approaches (such
+ * as examining the TEXTMETRIC structure or requesting the
+ * height of a string), I think we'll do this the brute
+ * force way: we create a small bitmap, draw an underlined
+ * space on it, and test to see whether any pixels are
+ * foreground-coloured. (Since we expect the underline to
+ * go all the way across the character cell, we only search
+ * down a single column of the bitmap, half way across.)
+ */
+ {
+ HDC und_dc;
+ HBITMAP und_bm, und_oldbm;
+ int i, gotit;
+ COLORREF c;
+
+ und_dc = CreateCompatibleDC(hdc);
+ und_bm = CreateCompatibleBitmap(hdc, font_width, font_height);
+ und_oldbm = SelectObject(und_dc, und_bm);
+ SelectObject(und_dc, fonts[FONT_UNDERLINE]);
+ SetTextAlign(und_dc, TA_TOP | TA_LEFT | TA_NOUPDATECP);
+ SetTextColor (und_dc, RGB(255,255,255));
+ SetBkColor (und_dc, RGB(0,0,0));
+ SetBkMode (und_dc, OPAQUE);
+ ExtTextOut (und_dc, 0, 0, ETO_OPAQUE, NULL, " ", 1, NULL);
+ gotit = FALSE;
+ for (i = 0; i < font_height; i++) {
+ c = GetPixel(und_dc, font_width/2, i);
+ if (c != RGB(0,0,0))
+ gotit = TRUE;
+ }
+ SelectObject(und_dc, und_oldbm);
+ DeleteObject(und_bm);
+ DeleteDC(und_dc);
+ font_needs_hand_underlining = !gotit;
+ }
+
if (bold_mode == BOLD_FONT) {
f(FONT_BOLD, cfg.fontcharset, fw_bold, FALSE);
f(FONT_BOLDUND, cfg.fontcharset, fw_bold, TRUE);
HDC hdc;
static int ignore_size = FALSE;
static int ignore_clip = FALSE;
- static int ignore_keymenu = TRUE;
static int just_reconfigged = FALSE;
-
- if (message != 275)
- debug(("msg=%d wParam=%08x lParam=%08x\r\n", message, wParam, lParam));
+ static int resizing = FALSE;
switch (message) {
case WM_TIMER:
enact_pending_netevent();
if (inbuf_head)
term_out();
+ HideCaret(hwnd);
term_update();
+ ShowCaret(hwnd);
return 0;
case WM_CREATE:
break;
return 0;
case WM_SYSCOMMAND:
switch (wParam & ~0xF) { /* low 4 bits reserved to Windows */
- case SC_KEYMENU:
- if (ignore_keymenu)
- return 0; /* don't put up system menu on Alt */
- break;
case IDM_SHOWLOG:
showeventlog(hwnd);
break;
case WM_IGNORE_CLIP:
ignore_clip = wParam; /* don't panic on DESTROYCLIPBOARD */
break;
- case WM_IGNORE_KEYMENU:
- ignore_keymenu = wParam; /* do or don't ignore SC_KEYMENU */
- break;
case WM_DESTROYCLIPBOARD:
if (!ignore_clip)
term_deselect();
case WM_PAINT:
{
PAINTSTRUCT p;
+ HideCaret(hwnd);
hdc = BeginPaint (hwnd, &p);
if (pal) {
SelectPalette (hdc, pal, TRUE);
SelectObject (hdc, GetStockObject(SYSTEM_FONT));
SelectObject (hdc, GetStockObject(WHITE_PEN));
EndPaint (hwnd, &p);
+ ShowCaret(hwnd);
}
return 0;
case WM_NETEVENT:
return 0;
case WM_SETFOCUS:
has_focus = TRUE;
+ CreateCaret(hwnd, caretbm, 0, 0);
+ ShowCaret(hwnd);
term_out();
term_update();
break;
case WM_KILLFOCUS:
has_focus = FALSE;
+ DestroyCaret();
term_out();
term_update();
break;
break;
case WM_ENTERSIZEMOVE:
EnableSizeTip(1);
+ resizing = TRUE;
break;
case WM_EXITSIZEMOVE:
EnableSizeTip(0);
+ resizing = FALSE;
+ back->size();
break;
case WM_SIZING:
{
if (w != cols || h != rows || just_reconfigged) {
term_invalidate();
term_size (h, w, cfg.savelines);
- back->size();
+ /*
+ * Don't call back->size in mid-resize. (To prevent
+ * massive numbers of resize events getting sent
+ * down the connection during an NT opaque drag.)
+ */
+ if (!resizing)
+ back->size();
just_reconfigged = FALSE;
}
}
}
/*
+ * Move the system caret. (We maintain one, even though it's
+ * invisible, for the benefit of blind people: apparently some
+ * helper software tracks the system caret, so we should arrange to
+ * have one.)
+ */
+void sys_cursor(int x, int y) {
+ SetCaretPos(x * font_width, y * font_height);
+}
+
+/*
* Draw a line of text in the window, at given character
* coordinates, in given attributes.
*
RECT line_box;
int force_manual_underline = 0;
int fnt_width = font_width*(1+(lattr!=LATTR_NORM));
-static int *IpDx = 0, IpDxLEN = 0;;
+ static int *IpDx = 0, IpDxLEN = 0;;
if (len>IpDxLEN || IpDx[0] != fnt_width) {
int i;
nfont &= ~(FONT_BOLD|FONT_UNDERLINE);
}
+ if (font_needs_hand_underlining && (attr & ATTR_UNDER))
+ force_manual_underline = 1;
if (attr & ATTR_REVERSE) {
t = nfg; nfg = nbg; nbg = t;
}
SendMessage (hwnd, WM_VSCROLL, SB_PAGEDOWN, 0);
return 0;
}
+ if (wParam == VK_INSERT && shift_state == 1) {
+ term_mouse (MB_PASTE, MA_CLICK, 0, 0);
+ term_mouse (MB_PASTE, MA_RELEASE, 0, 0);
+ return 0;
+ }
if (left_alt && wParam == VK_F4 && cfg.alt_f4) {
return -1;
}
if (left_alt && wParam == VK_SPACE && cfg.alt_space) {
- SendMessage (hwnd, WM_IGNORE_KEYMENU, FALSE, 0);
SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
- SendMessage (hwnd, WM_IGNORE_KEYMENU, TRUE, 0);
return -1;
}
if ( cfg.funky_type == 0 ||
( cfg.funky_type == 1 && app_keypad_keys)) switch(wParam) {
- case VK_EXECUTE: xkey = 'P'; break;
+ case VK_EXECUTE: if (app_keypad_keys) xkey = 'P'; break;
case VK_DIVIDE: xkey = 'Q'; break;
case VK_MULTIPLY:xkey = 'R'; break;
case VK_SUBTRACT:xkey = 'S'; break;
}
/* This stops ALT press-release doing a 'COMMAND MENU' function */
-#if 0
if (message == WM_SYSKEYUP && wParam == VK_MENU)
{
keystate[VK_MENU] = 0;
return 0;
}
-#endif
return -1;
}