diff --git a/0.76_My_PuTTY/settings.c b/0.76_My_PuTTY/settings.c index 826ac5b..8a964c1 100644 --- a/0.76_My_PuTTY/settings.c +++ b/0.76_My_PuTTY/settings.c @@ -1295,8 +1295,8 @@ void load_open_settings(settings_r *sesskey, Conf *conf) gppb(sesskey, "HideMousePtr", false, conf, CONF_hide_mouseptr); gppb(sesskey, "SunkenEdge", false, conf, CONF_sunken_edge); gppi(sesskey, "WindowBorder", 1, conf, CONF_window_border); - gppi(sesskey, "CurType", 0, conf, CONF_cursor_type); - gppb(sesskey, "BlinkCur", false, conf, CONF_blink_cur); + gppi(sesskey, "CurType", 1, conf, CONF_cursor_type); + gppb(sesskey, "BlinkCur", true, conf, CONF_blink_cur); /* pedantic compiler tells me I can't use conf, CONF_beep as an int * :-) */ gppi(sesskey, "Beep", 1, conf, CONF_beep); gppi(sesskey, "BeepInd", 0, conf, CONF_beep_ind); diff --git a/0.76_My_PuTTY/terminal.c b/0.76_My_PuTTY/terminal.c index 06c91ca..043894b 100644 --- a/0.76_My_PuTTY/terminal.c +++ b/0.76_My_PuTTY/terminal.c @@ -13,6 +13,10 @@ #include "putty.h" #include "terminal.h" +/* base64 library - needed for far2l extensions support */ +#include +#include + #ifdef MOD_PERSO #include "charset.h" int get_param( const char * val ) ; @@ -2000,6 +2004,10 @@ Terminal *term_init(Conf *myconf, struct unicode_data *ucsdata, TermWin *win) * that need it. */ term = snew(Terminal); + /* far2l */ + term->far2l_ext = 0; // far2l extensions mode is enabled? + term->is_apc = 0; // currently processing incoming APC sequence? + term->clip_allowed = -1; // remote clipboard access is enabled? term->win = win; term->ucsdata = ucsdata; term->conf = conf_copy(myconf); @@ -3204,6 +3212,577 @@ static void toggle_mode(Terminal *term, int mode, int query, bool state) */ static void do_osc(Terminal *term) { + /* far2l extensions support */ + if (term->is_apc) { + + #ifndef _WINDOWS + #define DWORD unsigned int + #define WORD unsigned short + #endif + + if (strncmp(term->osc_string, "far2l", 5) == 0) { + + // okay, this is far2l terminal extensions APC sequence + + // for more info about far2l terminal extensions please see: + // https://github.com/cyd01/KiTTY/issues/74 + // https://github.com/elfmz/far2l/blob/master/WinPort/FarTTY.h + + if (strncmp(term->osc_string+5, "1", 1) == 0) { + + // extensions mode on + + term->far2l_ext = 1; + + char *reply_buf = dupprintf( + "\x1b_far2lok\x07"); + ldisc_send(term->ldisc, reply_buf, strlen(reply_buf), + false); + sfree(reply_buf); + + // reset clipboard state; todo: do it on session init! + term->clip_allowed = -1; + + } else if (strncmp(term->osc_string+5, "0", 1) == 0) { + + // extensions mode off + + term->far2l_ext = 0; + + // reset clipboard state; todo: do it on session init! + term->clip_allowed = -1; + + } else if (strncmp(term->osc_string+5, ":", 1) == 0) { + + // processing actual payload + + // base64-decode payload + base64_decodestate _d_state; + base64_init_decodestate(&_d_state); + char* d_out = malloc(term->osc_strlen); + int d_count = base64_decode_block( + term->osc_string+6, term->osc_strlen-6, d_out, &_d_state); + + // last byte is id + BYTE id = d_out[d_count-1]; + char* reply = 0; + int reply_size = 0; + + if (term->osc_strlen == OSC_STR_MAX) { + + // it's possibly too large clipboard + + // we can't deal with it + // until implementing dynamic osc_string allocation + + #ifdef _WINDOWS + MessageBox(wgs.term_hwnd, "Too large clipboard :(", "Error", MB_OK); + #endif + + // correct request id is lost forever + // so we can not prevent far2l from hanging + // so sad + + // fixme: good idea is to free all allocated memory here, though + exit(100); + } + + DWORD len; + + // next from the end byte is command + switch (d_out[d_count-2]) { + + case 'f':; // FARTTY_INTERRACT_SET_FKEY_TITLES + + reply_size = 5; + reply = malloc(reply_size); + + // fixme: unimplemented + DWORD zero = 0; + + memcpy(reply, &zero, sizeof(DWORD)); + + break; + + case 'n':; // FARTTY_INTERRACT_DESKTOP_NOTIFICATION + + /* // not ready yet + + // todo: generate some reply + // todo: show notification only if window is out of focus + // todo: remove icon after notification timeout or by mouse click + + // title length, source, utf8, no zero-terminate, bytes + DWORD len1; + memcpy(&len1, d_out+d_count-6, sizeof(len1)); + + // text length, source, utf8, no zero-terminate, bytes + DWORD len2; + memcpy(&len2, d_out+d_count-6-4-len1, sizeof(len2)); + + // destination (wide char) + LPWSTR text_wc, title_wc; + int textsz_wc, titlesz_wc; + + // notification may contain file names in non-latin + // or may have localized title + // so we can not assume ascii here and should do + // full utf8->multibyte conversion + + titlesz_wc = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)(d_out+len2+4), len1, 0, 0); + textsz_wc = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len2, 0, 0); + + if (titlesz_wc && textsz_wc) { + title_wc = malloc((titlesz_wc+1)*sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, (LPCCH)(d_out+len2+4), len1, title_wc, titlesz_wc); + text_wc = malloc((textsz_wc+1)*sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len2, text_wc, textsz_wc); + + title_wc[titlesz_wc] = 0; + text_wc[textsz_wc] = 0; + + NOTIFYICONDATAW pnid; + + // todo: do this on window focus also + pnid.cbSize = sizeof(pnid); + pnid.hWnd = wgs.term_hwnd; + pnid.hIcon = LoadIcon(0, IDI_APPLICATION); + pnid.uID = 200; + Shell_NotifyIconW(NIM_DELETE, &pnid); + + // todo: use putty icon + pnid.cbSize = sizeof(pnid); + pnid.hWnd = wgs.term_hwnd; + pnid.hIcon = LoadIcon(0, IDI_APPLICATION); + pnid.uID = 200; + pnid.uFlags = NIF_ICON | NIF_INFO | NIF_MESSAGE; + pnid.uCallbackMessage = (WM_USER + 200); + pnid.dwInfoFlags = NIIF_INFO | NIIF_NOSOUND; + memcpy(pnid.szInfoTitle, title_wc, (titlesz_wc+1)*sizeof(wchar_t)); + memcpy(pnid.szInfo, text_wc, (textsz_wc+1)*sizeof(wchar_t)); + Shell_NotifyIconW(NIM_ADD, &pnid); + + free(text_wc); + free(title_wc); + } + + */ + + break; + + case 'w': // FARTTY_INTERRACT_GET_WINDOW_MAXSIZE + + // get largest console window size + + reply_size = 5; + reply = malloc(reply_size); + + // fixme: unimplemented + // here should be short x and short y + DWORD none = 0; + + memcpy(reply, &none, sizeof(DWORD)); + + break; + + case 'c': // FARTTY_INTERRACT_CLIPBOARD + + // clipboard interaction + // next from the end byte is subcommand + + switch (d_out[d_count-3]) { + + case 'r':; // FARTTY_INTERRACT_CLIP_REGISTER_FORMAT + + // register format + + memcpy(&len, d_out + d_count - 3 - 4, sizeof(DWORD)); + d_out[len] = 0; // zero-terminate format name + + #ifdef _WINDOWS + // far2l sends format name as (utf8?) string, + // which actually containing ascii only + // so we can just call ascii function + uint32_t status = RegisterClipboardFormatA(d_out); + #endif + + reply_size = 5; + reply = malloc(reply_size); + + #ifdef _WINDOWS + memcpy(reply, &status, sizeof(uint32_t)); + #else + bzero(reply, sizeof(uint32_t)); + #endif + + break; + + case 'e':; // FARTTY_INTERRACT_CLIP_EMPTY + + #ifdef _WINDOWS + char ec_status = 0; + if (term->clip_allowed == 1) { + OpenClipboard(wgs.term_hwnd); + ec_status = EmptyClipboard() ? 1 : 0; + CloseClipboard(); + } + #endif + + reply_size = 2; + reply = malloc(reply_size); + + #ifdef _WINDOWS + reply[0] = ec_status; + #else + reply[0] = 0; + #endif + + break; + + case 'a':; // FARTTY_INTERRACT_CLIP_ISAVAIL + + uint32_t a_fmt; + memcpy(&a_fmt, d_out + d_count - 3 - 4, sizeof(uint32_t)); + + #ifdef _WINDOWS + char out = IsClipboardFormatAvailable(a_fmt) ? 1 : 0; + #endif + + reply_size = 2; + reply = malloc(reply_size); + + #ifdef _WINDOWS + reply[0] = out; + #else + reply[0] = 0; + #endif + + break; + + case 'o':; // FARTTY_INTERRACT_CLIP_OPEN + + // open + // next from the end 4 bytes is client_id length + memcpy(&len, d_out + d_count - 3 - 4, sizeof(DWORD)); + d_out[len] = 0; // all remaining string is client id, make it zero terminated + + // todo: check/store client id, all that stuff + + reply_size = 2; + reply = malloc(reply_size); + + #ifdef _WINDOWS + if (term->clip_allowed == -1) { + int status = MessageBox(wgs.term_hwnd, + "Allow far2l clipboard sync?", "PyTTY", MB_OKCANCEL); + if (status == IDOK) { + term->clip_allowed = 1; + } else { + // IDCANCEL + term->clip_allowed = 0; + } + } + + // status is first response byte + if (term->clip_allowed == 1) { + reply[0] = 1; + } else { + reply[0] = -1; + } + #else + reply[0] = -1; + #endif + + break; + + case 's':; // FARTTY_INTERRACT_CLIP_SETDATA + + // set data + + if (term->clip_allowed == 1 && d_count >= 4 + 4 + 3) { + + #ifdef _WINDOWS + + uint32_t fmt; + char* buffer = NULL; + int BufferSize = 0; + memcpy(&fmt, d_out + d_count - 3 - 4, sizeof(uint32_t)); + + // id, 'c', 's', 4-byte fmt, next goes 4-byte len + memcpy(&len, d_out + d_count - 3 - 4 - 4, sizeof(DWORD)); + if (len > d_count - 3 - 4 - 4) + len = d_count - 3 - 4 - 4; + + if (fmt == CF_TEXT) { + int cnt = MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len, NULL, 0); + if (cnt > 0) { + buffer = calloc(cnt + 1, sizeof(wchar_t)); + MultiByteToWideChar(CP_UTF8, 0, (LPCCH)d_out, len, (PWCHAR)buffer, cnt); + } + fmt = CF_UNICODETEXT; + BufferSize = (wcslen((PWCHAR)buffer) + 1) * sizeof(WCHAR); + + } else if (fmt == CF_UNICODETEXT) { + // very stupid utf32->utf16 'conversion' + buffer = calloc((len / sizeof(uint32_t)) + 1, sizeof(wchar_t)); + for (int i=0; i < len / sizeof(uint32_t); ++i) { + memcpy( + &buffer[i * sizeof(wchar_t)], + &d_out[i * sizeof(uint32_t)], + sizeof(wchar_t) + ); + } + BufferSize = (wcslen((PWCHAR)buffer) + 1) * sizeof(WCHAR); + + } else if (fmt >= 0xC000) { + // no transcoding - copy it as is + buffer = malloc(len); + memcpy(buffer, &d_out[0], len); + BufferSize = len; + } + + // clipboard stuff itself + + HGLOBAL hData; + void *GData; + + bool set_successful = 0; + + if (buffer && (hData=GlobalAlloc(GMEM_MOVEABLE,BufferSize))) { + + if ((GData=GlobalLock(hData))) { + + memcpy(GData,buffer,BufferSize); + GlobalUnlock(hData); + + if (OpenClipboard(wgs.term_hwnd)) { + + if (!SetClipboardData(fmt, (HANDLE)hData)) { + GlobalFree(hData); + } else { + set_successful = 1; + } + + CloseClipboard(); + + } else { + GlobalFree(hData); + } + + } else { + GlobalFree(hData); + } + } + + free(buffer); + + #endif + + // prepare reply + reply_size = 2; + reply = malloc(reply_size); + + // first reply byte is status + #ifdef _WINDOWS + reply[0] = set_successful; + #else + reply[0] = 0; + #endif + + } else { + + reply_size = 2; + reply = malloc(reply_size); + + reply[0] = 0; + } + + break; + + case 'g':; // FARTTY_INTERRACT_CLIP_GETDATA + + if (term->clip_allowed == 1) { + + #ifdef _WINDOWS + + uint32_t gfmt; + memcpy(&gfmt, d_out + d_count - 3 - 4, sizeof(uint32_t)); + + // clipboard stuff itself + + void *ClipText = NULL; + int32_t ClipTextSize = 0; + + if ((gfmt == CF_TEXT || gfmt == CF_UNICODETEXT || gfmt >= 0xC000) && + OpenClipboard(wgs.term_hwnd)) + { + HANDLE hClipData = GetClipboardData((gfmt == CF_TEXT) ? CF_UNICODETEXT : gfmt); + + if (hClipData) + { + void *pClipData=GlobalLock(hClipData); + + if (pClipData) + { + size_t n = GlobalSize(hClipData); + + if (gfmt == CF_TEXT) { + + ClipTextSize = WideCharToMultiByte( + CP_UTF8, + 0, + (wchar_t *)pClipData, + n, + NULL, + 0, + NULL, + NULL + ) + 1; + + if (ClipTextSize >= 0) { + n = wcsnlen((wchar_t *)pClipData, n / sizeof(wchar_t)); + ClipText = calloc(ClipTextSize + 1, 1); + if (ClipText) { + WideCharToMultiByte( + CP_UTF8, + 0, + (wchar_t *)pClipData, + n, + (char *)ClipText, + ClipTextSize, + NULL, + NULL + ); + ClipTextSize = strlen((char *)ClipText) + 1; + } + } + + } else if (gfmt == CF_UNICODETEXT) { + n = wcsnlen((wchar_t *)pClipData, n / sizeof(wchar_t)); + ClipText = calloc((n + 1), sizeof(uint32_t)); + if (ClipText) { + for (size_t i = 0; i < n; ++i) { + ((uint32_t *)ClipText)[i] = ((uint16_t *)pClipData)[i]; + } + ClipTextSize = (n + 1) * sizeof(uint32_t); + } + + } else { + ClipText = malloc(n); + if (ClipText) { + memcpy(ClipText, pClipData, n); + ClipTextSize = n; + } + } + + GlobalUnlock(hClipData); + } + + } else { + // todo: process errors + } + CloseClipboard(); + } + + + if (!ClipText || ClipTextSize <= 0) { + + // clipboard is empty + reply_size = 5; // 4 bytes for size and one for id + reply = calloc(1, reply_size); + + } else { + + // + length (4 bytes) + id (1 byte) + reply_size = ClipTextSize + 5; + reply = calloc(1, reply_size); + memcpy(reply, ClipText, ClipTextSize); + + // set size + memcpy(reply + ClipTextSize, &ClipTextSize, sizeof(ClipTextSize)); + } + + free(ClipText); + + #else + reply_size = 5; + reply = calloc(1, reply_size); + #endif + + } else { + + // we should never reach here + // anyway, mimic empty clipboard + + reply_size = 5; + reply = calloc(1, reply_size); + } + + break; + } + + break; + } + + free(d_out); + + if (reply_size > 0) { + // request is correct and we should send reply + + // last byte is always id + reply[reply_size-1] = id; + + // ok, let us try to answer something + + // base64-encode + // result in null-terminated char* out + base64_encodestate _state; + base64_init_encodestate(&_state); + + char* out = malloc(reply_size*2); + int count = base64_encode_block((char*)reply, reply_size, out, &_state); + // finishing '=' characters + char* next_char = out + count; + switch (_state.step) + { + case step_B: + *next_char++ = base64_encode_value(_state.result); + *next_char++ = '='; + *next_char++ = '='; + break; + case step_C: + *next_char++ = base64_encode_value(_state.result); + *next_char++ = '='; + break; + case step_A: + break; + } + count = next_char - out; + out[count] = 0; + + // send escape seq + + char* str = "\x1b_far2l"; + backend_send(term->backend, str, strlen(str)); + + backend_send(term->backend, out, count); + + char* str2 = "\x07"; + backend_send(term->backend, str2, strlen(str2)); + + // don't forget to free memory :) + free(reply); + free(out); + + } + } + } + + term->osc_strlen = 0; + term->is_apc = 0; + + } else + if (term->osc_w) { while (term->osc_strlen--) term->wordness[(unsigned char) @@ -4119,7 +4698,15 @@ static void term_out(Terminal *term) term->esc_args[0] = ARG_DEFAULT; term->esc_query = 0; break; - case ']': /* OSC: xterm escape sequences */ + case '_': /* far2l: processing APC is almost the same as processing OSC */ + term->is_apc = 1; + //break; + //case SEEN_APC: + /* todo */ + // if (!WriteStr2TC(fdout, enable ? "\x1b_far2l1\x1b\\\x1b[5n" : "\x1b_far2l0\x07\x1b[5n")) + // if (!WriteStr2TC(fdout, enable ? "\x1b_far2l1\x1b\\\x1b[5n" : "\x1b_far2l0\x07\x1b[5n")) + //break; + case ']': /* OSC: xterm escape sequences */ /* Compatibility is nasty here, xterm, linux, decterm yuk! */ compatibility(OTHER); term->termstate = SEEN_OSC; @@ -5340,6 +5927,10 @@ static void term_out(Terminal *term) } else { term->termstate = OSC_STRING; term->osc_strlen = 0; + /* far2l */ + if (term->is_apc) { + term->osc_string[term->osc_strlen++] = (char)c; + } } } break; diff --git a/0.76_My_PuTTY/terminal.h b/0.76_My_PuTTY/terminal.h index bd4c5dd..44109a7 100644 --- a/0.76_My_PuTTY/terminal.h +++ b/0.76_My_PuTTY/terminal.h @@ -6,6 +6,9 @@ * but for the moment, this will do. */ +#include +extern WinGuiSeat wgs; + #ifndef PUTTY_TERMINAL_H #define PUTTY_TERMINAL_H @@ -185,11 +188,20 @@ struct terminal_tag { #define ANSI(x,y) ((x)+((y)*256)) #define ANSI_QUE(x) ANSI(x,1) -#define OSC_STR_MAX 2048 +/* far2l extensions support */ +//#define OSC_STR_MAX 2048 +// todo: allocate osc_string dynamically +#define OSC_STR_MAX 1048576 + int osc_strlen; char osc_string[OSC_STR_MAX + 1]; bool osc_w; + /* far2l */ + int far2l_ext; // extensions mode on + bool is_apc; // currently processing APC sequence + int clip_allowed; // remote clipboard access is allowed + char id_string[1024]; unsigned char *tabs; @@ -205,7 +217,8 @@ struct terminal_tag { SEEN_OSC_P, OSC_STRING, OSC_MAYBE_ST, - VT52_ESC, + /* far2l extensions support */ SEEN_APC, + VT52_ESC, VT52_Y1, VT52_Y2, VT52_FG, diff --git a/0.76_My_PuTTY/windows/MAKEFILE.MINGW b/0.76_My_PuTTY/windows/MAKEFILE.MINGW index 6af2e87..6dcfd48 100644 --- a/0.76_My_PuTTY/windows/MAKEFILE.MINGW +++ b/0.76_My_PuTTY/windows/MAKEFILE.MINGW @@ -418,6 +418,7 @@ putty.exe: agentf.o aqsync.o be_all_s.o be_misc.o callback.o cmdline.o \ winnps.o winpgntc.o winprint.o winproxy.o winsecur.o \ winselgui.o winser.o winshare.o winstore.o wintime.o \ winucs.o winutils.o winx11.o x11fwd.o \ + cencode.o cdecode.o \ adb.o \ kitty.o kitty_commun.o kitty_crypt.o kitty_image.o kitty_proxy.o kitty_registry.o kitty_ssh.o \ kitty_store.o kitty_tools.o kitty_win.o \ @@ -447,6 +448,7 @@ putty.exe: agentf.o aqsync.o be_all_s.o be_misc.o callback.o cmdline.o \ winnps.o winpgntc.o winprint.o winproxy.o winsecur.o \ winselgui.o winser.o winshare.o winstore.o wintime.o \ winucs.o winutils.o winx11.o x11fwd.o \ + cencode.o cdecode.o \ adb.o \ kitty.o kitty_commun.o kitty_crypt.o kitty_image.o kitty_proxy.o kitty_registry.o kitty_ssh.o \ kitty_store.o kitty_tools.o kitty_win.o \ @@ -528,6 +530,11 @@ testcrypt.exe: ecc.o marshal.o memory.o millerrabin.o mpint.o mpunsafe.o \ sshpubk.o sshrsa.o sshrsag.o sshsh256.o sshsh512.o sshsha.o \ sshsha3.o testcrypt.o tree234.o utils.o winmiscs.o +cencode.o: ../windows/cencode.c + $(CC) $(COMPAT) $(CFLAGS) $(XFLAGS) -c ../windows/cencode.c + +cdecode.o: ../windows/cencode.c + $(CC) $(COMPAT) $(CFLAGS) $(XFLAGS) -c ../windows/cdecode.c agentf.o: ../agentf.c ../putty.h ../ssh.h ../pageant.h ../sshchan.h \ ../defs.h ../puttyps.h ../network.h ../misc.h ../marshal.h \ diff --git a/0.76_My_PuTTY/windows/cdecode.c b/0.76_My_PuTTY/windows/cdecode.c new file mode 100644 index 0000000..7b2aad0 --- /dev/null +++ b/0.76_My_PuTTY/windows/cdecode.c @@ -0,0 +1,88 @@ +/* +cdecoder.c - c source to a base64 decoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include + +int base64_decode_value(char value_in) +{ + static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51}; + static const char decoding_size = sizeof(decoding); + value_in -= 43; + if (value_in < 0 || value_in > decoding_size) return -1; + return decoding[(int)value_in]; +} + +void base64_init_decodestate(base64_decodestate* state_in) +{ + state_in->step = step_a; + state_in->plainchar = 0; +} + +int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in) +{ + const char* codechar = code_in; + char* plainchar = plaintext_out; + char fragment; + + *plainchar = state_in->plainchar; + + switch (state_in->step) + { + while (1) + { + case step_a: + do { + if (codechar == code_in+length_in) + { + state_in->step = step_a; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (char)base64_decode_value(*codechar++); + } while (fragment < 0); + *plainchar = (fragment & 0x03f) << 2; + case step_b: + do { + if (codechar == code_in+length_in) + { + state_in->step = step_b; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (char)base64_decode_value(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x030) >> 4; + *plainchar = (fragment & 0x00f) << 4; + case step_c: + do { + if (codechar == code_in+length_in) + { + state_in->step = step_c; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (char)base64_decode_value(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x03c) >> 2; + *plainchar = (fragment & 0x003) << 6; + case step_d: + do { + if (codechar == code_in+length_in) + { + state_in->step = step_d; + state_in->plainchar = *plainchar; + return plainchar - plaintext_out; + } + fragment = (char)base64_decode_value(*codechar++); + } while (fragment < 0); + *plainchar++ |= (fragment & 0x03f); + } + } + /* control should not reach here */ + return plainchar - plaintext_out; +} + diff --git a/0.76_My_PuTTY/windows/cdecode.h b/0.76_My_PuTTY/windows/cdecode.h new file mode 100644 index 0000000..d0d7f48 --- /dev/null +++ b/0.76_My_PuTTY/windows/cdecode.h @@ -0,0 +1,28 @@ +/* +cdecode.h - c header for a base64 decoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CDECODE_H +#define BASE64_CDECODE_H + +typedef enum +{ + step_a, step_b, step_c, step_d +} base64_decodestep; + +typedef struct +{ + base64_decodestep step; + char plainchar; +} base64_decodestate; + +void base64_init_decodestate(base64_decodestate* state_in); + +int base64_decode_value(char value_in); + +int base64_decode_block(const char* code_in, const int length_in, char* plaintext_out, base64_decodestate* state_in); + +#endif /* BASE64_CDECODE_H */ diff --git a/0.76_My_PuTTY/windows/cencode.c b/0.76_My_PuTTY/windows/cencode.c new file mode 100644 index 0000000..872856d --- /dev/null +++ b/0.76_My_PuTTY/windows/cencode.c @@ -0,0 +1,109 @@ +/* +cencoder.c - c source to a base64 encoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include + +const int CHARS_PER_LINE = 72; + +void base64_init_encodestate(base64_encodestate* state_in) +{ + state_in->step = step_A; + state_in->result = 0; + state_in->stepcount = 0; +} + +char base64_encode_value(char value_in) +{ + static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if (value_in > 63) return '='; + return encoding[(int)value_in]; +} + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) +{ + const char* plainchar = plaintext_in; + const char* const plaintextend = plaintext_in + length_in; + char* codechar = code_out; + char result; + char fragment; + + result = state_in->result; + + switch (state_in->step) + { + while (1) + { + case step_A: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_A; + return codechar - code_out; + } + fragment = *plainchar++; + result = (fragment & 0x0fc) >> 2; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x003) << 4; + case step_B: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_B; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0f0) >> 4; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x00f) << 2; + case step_C: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_C; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0c0) >> 6; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x03f) >> 0; + *codechar++ = base64_encode_value(result); + + ++(state_in->stepcount); + if (state_in->stepcount == CHARS_PER_LINE/4) + { + //*codechar++ = '\n'; + state_in->stepcount = 0; + } + } + } + /* control should not reach here */ + return codechar - code_out; +} + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in) +{ + char* codechar = code_out; + + switch (state_in->step) + { + case step_B: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + *codechar++ = '='; + break; + case step_C: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + break; + case step_A: + break; + } + //*codechar++ = '\n'; + + return codechar - code_out; +} + diff --git a/0.76_My_PuTTY/windows/cencode.h b/0.76_My_PuTTY/windows/cencode.h new file mode 100644 index 0000000..c1e3464 --- /dev/null +++ b/0.76_My_PuTTY/windows/cencode.h @@ -0,0 +1,31 @@ +/* +cencode.h - c header for a base64 encoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CENCODE_H +#define BASE64_CENCODE_H + +typedef enum +{ + step_A, step_B, step_C +} base64_encodestep; + +typedef struct +{ + base64_encodestep step; + char result; + int stepcount; +} base64_encodestate; + +void base64_init_encodestate(base64_encodestate* state_in); + +char base64_encode_value(char value_in); + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in); + +#endif /* BASE64_CENCODE_H */ diff --git a/0.76_My_PuTTY/windows/window.c b/0.76_My_PuTTY/windows/window.c index 15a9780..010b3ec 100644 --- a/0.76_My_PuTTY/windows/window.c +++ b/0.76_My_PuTTY/windows/window.c @@ -10,6 +10,10 @@ #include #include +/* far2l extensions support - base64 encode/decode libs */ +#include +#include + #ifdef __WINE__ #define NO_MULTIMON /* winelib doesn't have this */ #endif @@ -436,7 +440,7 @@ int WINAPI Agent_WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show #endif #ifdef MOD_WTS -typedef enum _WTS_VIRTUAL_CLASS { WTSVirtualClientData, WTSVirtualFileHandle } WTS_VIRTUAL_CLASS; // WTS_VIRTUAL_CLASS n'est pas défini dans le fichier wtsapi32.h !!! +//typedef enum _WTS_VIRTUAL_CLASS { WTSVirtualClientData, WTSVirtualFileHandle } WTS_VIRTUAL_CLASS; // WTS_VIRTUAL_CLASS n'est pas défini dans le fichier wtsapi32.h !!! #include #endif #if (defined MOD_BACKGROUNDIMAGE) && (!defined FLJ) @@ -612,7 +616,9 @@ static const SeatVtable win_seat_vt = { .interactive = nullseat_interactive_yes, .get_cursor_position = win_seat_get_cursor_position, }; -static WinGuiSeat wgs = { .seat.vt = &win_seat_vt, +// "static" removed by far2l extensions support patch +// we need to access wgs from terminal.c to open dialog boxes, etc +WinGuiSeat wgs = { .seat.vt = &win_seat_vt, .logpolicy.vt = &win_gui_logpolicy_vt }; #ifdef MOD_PERSO @@ -4827,10 +4833,17 @@ free(cmd); ignore_clip = wParam; /* don't panic on DESTROYCLIPBOARD */ break; case WM_DESTROYCLIPBOARD: - if (!ignore_clip) - term_lost_clipboard_ownership(term, CLIP_SYSTEM); - ignore_clip = false; - return 0; + /* far2l extensions support */ + + // In far2l extensions mode we should not do anything here, + // clipboard is handled by far2l extensions. + if (!(term->far2l_ext == 1) || (!term->clip_allowed)) { + if (!ignore_clip) + term_lost_clipboard_ownership(term, CLIP_SYSTEM); + ignore_clip = false; + } + + return 0; case WM_PAINT: { PAINTSTRUCT p; #if (defined MOD_BACKGROUNDIMAGE) && (!defined FLJ) @@ -5591,13 +5604,130 @@ if( (GetKeyState(VK_MENU)&0x8000) && (wParam==VK_SPACE) ) { */ noise_ultralight(NOISE_SOURCE_KEY, lParam); - /* - * We don't do TranslateMessage since it disassociates the - * resulting CHAR message from the KEYDOWN that sparked it, - * which we occasionally don't want. Instead, we process - * KEYDOWN, and call the Win32 translator functions so that - * we get the translations under _our_ control. - */ + /* far2l extensions support */ + if (term->far2l_ext) { + + // extensions mode enabled + + // far2l_ext keyboard input event structure + WORD repeat; // 2 bytes + WORD vkc; // 2 bytes + WORD vsc; // 2 bytes + DWORD ctrl; // 4 bytes + DWORD uchar; // 4 bytes + CHAR type; // 1 byte + + // set repeat, virtual keycode, virtual scancode + repeat = LOWORD(lParam); + vsc = HIWORD(lParam) & 0xFF; + vkc = LOWORD(wParam); + + // this fixes far2l's "editor autocomplete" plugin behavior + if ((vkc == VK_TAB) || (vkc == VK_BACK) || (vkc == VK_ESCAPE) || (vkc == VK_DELETE)) { + vsc = 0; + } + + // fixes strange alt+arrows behavior + if ((vkc == VK_LEFT) || (vkc == VK_RIGHT) || (vkc == VK_UP) || (vkc == VK_DOWN)) { + vsc = 0; + } + + // set control keys state + ctrl = 0; + if (GetAsyncKeyState(VK_LCONTROL)) { ctrl |= LEFT_CTRL_PRESSED; } + if (GetAsyncKeyState(VK_RCONTROL)) { ctrl |= RIGHT_CTRL_PRESSED; } + if (GetAsyncKeyState(VK_LMENU)) { ctrl |= LEFT_ALT_PRESSED; } + if (GetAsyncKeyState(VK_RMENU)) { ctrl |= RIGHT_ALT_PRESSED; } + if (GetAsyncKeyState(VK_SHIFT)) { ctrl |= SHIFT_PRESSED; } + // begin: reserved for future usage + // Console WinAPI does not allow us to distinguish between left and right + // shift keys. But PuTTY is not a console app, so why not to send + // all information about control keys state that we actually have here? + // Using bits not used by any other status for backward compatibility. + #define RIGHT_SHIFT_PRESSED 0x1000 + #define LEFT_SHIFT_PRESSED 0x2000 + if (GetAsyncKeyState(VK_LSHIFT)) { ctrl |= RIGHT_SHIFT_PRESSED; } + if (GetAsyncKeyState(VK_RSHIFT)) { ctrl |= LEFT_SHIFT_PRESSED; } + // end + if ((lParam & ( 1 << 24 )) >> 24) { ctrl |= ENHANCED_KEY; } + if ((((u_short)GetKeyState(VK_NUMLOCK)) & 0xffff) != 0) { ctrl |= NUMLOCK_ON; } + if ((((u_short)GetKeyState(VK_SCROLL)) & 0xffff) != 0) { ctrl |= SCROLLLOCK_ON; } + if ((((u_short)GetKeyState(VK_CAPITAL)) & 0xffff) != 0) { ctrl |= CAPSLOCK_ON; } + + // set unicode character + BYTE kb[256]; + GetKeyboardState(kb); + WCHAR uc[5] = {}; + ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0); + // todo: check result + //int result = ToUnicode(wParam, MapVirtualKey(wParam, MAPVK_VK_TO_VSC), kb, uc, 4, 0); + uchar = uc[0]; + + // set event type + if ((message == WM_KEYDOWN) || (message == WM_SYSKEYDOWN)) { + type = 'K'; + } else { + type = 'k'; + } + + char* kev = malloc(15); // keyboard event structure length + memcpy(kev, &repeat, sizeof(repeat)); + memcpy(kev + 2, &vkc, sizeof(vkc)); + memcpy(kev + 4, &vsc, sizeof(vsc)); + memcpy(kev + 6, &ctrl, sizeof(ctrl)); + memcpy(kev + 10, &uchar, sizeof(uchar)); + memcpy(kev + 14, &type, sizeof(type)); + + // base64-encode kev + // result in null-terminated char* out + base64_encodestate _state; + base64_init_encodestate(&_state); + char* out = malloc(15*2); + int count = base64_encode_block(kev, 15, out, &_state); + // finishing '=' characters + char* next_char = out + count; + switch (_state.step) + { + case step_B: + *next_char++ = base64_encode_value(_state.result); + *next_char++ = '='; + *next_char++ = '='; + break; + case step_C: + *next_char++ = base64_encode_value(_state.result); + *next_char++ = '='; + break; + case step_A: + break; + } + count = next_char - out; + out[count] = 0; + + // send escape seq + + char* str = "\x1b_f2l"; + backend_send(backend, str, strlen(str)); + + backend_send(backend, out, count); + + char* str2 = "\x07"; + backend_send(backend, str2, strlen(str2)); + + // don't forget to free memory :) + free(out); + + // we should not do any other key processing in this mode + return 0; + } + + +/* + * We don't do TranslateMessage since it disassociates the + * resulting CHAR message from the KEYDOWN that sparked it, + * which we occasionally don't want. Instead, we process + * KEYDOWN, and call the Win32 translator functions so that + * we get the translations under _our_ control. + */ { unsigned char buf[20]; int len; diff --git a/0.76_My_PuTTY/windows/winseat.h b/0.76_My_PuTTY/windows/winseat.h index b888343..7434f4f 100644 --- a/0.76_My_PuTTY/windows/winseat.h +++ b/0.76_My_PuTTY/windows/winseat.h @@ -3,6 +3,8 @@ * and windlg.c. */ +#pragma once + typedef struct WinGuiSeat WinGuiSeat; struct WinGuiSeat {