| 47 |
#include "crypt.h" |
#include "crypt.h" |
| 48 |
#include "fwd.h" |
#include "fwd.h" |
| 49 |
|
|
| 50 |
|
#include <sys/types.h> |
| 51 |
|
#include <sys/stat.h> |
| 52 |
|
#include <assert.h> |
| 53 |
|
|
| 54 |
// SSH2 macro |
// SSH2 macro |
| 55 |
#ifdef _DEBUG |
#ifdef _DEBUG |
| 56 |
#define SSH2_DEBUG |
#define SSH2_DEBUG |
| 68 |
#define CHANNEL_MAX 100 |
#define CHANNEL_MAX 100 |
| 69 |
|
|
| 70 |
enum channel_type { |
enum channel_type { |
| 71 |
TYPE_SHELL, TYPE_PORTFWD, |
TYPE_SHELL, TYPE_PORTFWD, TYPE_SCP, |
| 72 |
|
}; |
| 73 |
|
|
| 74 |
|
enum scp_state { |
| 75 |
|
SCP_INIT, SCP_TIMESTAMP, SCP_FILEINFO, SCP_DATA, SCP_CLOSING, |
| 76 |
}; |
}; |
| 77 |
|
|
| 78 |
typedef struct bufchain { |
typedef struct bufchain { |
| 80 |
struct bufchain *next; |
struct bufchain *next; |
| 81 |
} bufchain_t; |
} bufchain_t; |
| 82 |
|
|
| 83 |
|
typedef struct scp { |
| 84 |
|
enum scp_state state; // SCP state |
| 85 |
|
char sendfile[MAX_PATH]; // sending filename |
| 86 |
|
char sendfilefull[MAX_PATH]; // sending filename fullpath |
| 87 |
|
FILE *sendfp; // file pointer |
| 88 |
|
struct _stat filestat; // file status information |
| 89 |
|
HANDLE thread; // sending thread handle |
| 90 |
|
} scp_t; |
| 91 |
|
|
| 92 |
typedef struct channel { |
typedef struct channel { |
| 93 |
int used; |
int used; |
| 94 |
int self_id; |
int self_id; |
| 102 |
enum channel_type type; |
enum channel_type type; |
| 103 |
int local_num; |
int local_num; |
| 104 |
bufchain_t *bufchain; |
bufchain_t *bufchain; |
| 105 |
|
scp_t scp; |
| 106 |
} Channel_t; |
} Channel_t; |
| 107 |
|
|
| 108 |
static Channel_t channels[CHANNEL_MAX]; |
static Channel_t channels[CHANNEL_MAX]; |
| 179 |
c->type = type; |
c->type = type; |
| 180 |
c->local_num = local_num; // alloc_channel()の返値を保存しておく |
c->local_num = local_num; // alloc_channel()の返値を保存しておく |
| 181 |
c->bufchain = NULL; |
c->bufchain = NULL; |
| 182 |
|
if (type == TYPE_SCP) { |
| 183 |
|
c->scp.state = SCP_INIT; |
| 184 |
|
c->scp.thread = (HANDLE)-1L; |
| 185 |
|
} |
| 186 |
|
|
| 187 |
return (c); |
return (c); |
| 188 |
} |
} |
| 253 |
free(ptr); |
free(ptr); |
| 254 |
} |
} |
| 255 |
|
|
| 256 |
|
if (c->type == TYPE_SCP) { |
| 257 |
|
c->scp.state = SCP_CLOSING; |
| 258 |
|
// SCPスレッドが動いていたら終わるまで待つ |
| 259 |
|
if (c->scp.thread != (HANDLE)-1L) { |
| 260 |
|
WaitForSingleObject(c->scp.thread, INFINITE); |
| 261 |
|
CloseHandle(c->scp.thread); |
| 262 |
|
c->scp.thread = (HANDLE)-1L; |
| 263 |
|
} |
| 264 |
|
} |
| 265 |
|
|
| 266 |
memset(c, 0, sizeof(Channel_t)); |
memset(c, 0, sizeof(Channel_t)); |
| 267 |
c->used = 0; |
c->used = 0; |
| 268 |
} |
} |
| 315 |
// |
// |
| 316 |
// SSH heartbeat mutex |
// SSH heartbeat mutex |
| 317 |
// |
// |
| 318 |
static CRITICAL_SECTION g_ssh_heartbeat_lock; /* ロック用変数 */ |
static CRITICAL_SECTION g_ssh_heartbeat_lock; /* 送受信用ロック */ |
| 319 |
|
static CRITICAL_SECTION g_ssh_blocking_send_lock; /* send_packet_blocking()用ロック */ |
| 320 |
|
|
| 321 |
void ssh_heartbeat_lock_initialize(void) |
void ssh_heartbeat_lock_initialize(void) |
| 322 |
{ |
{ |
| 323 |
InitializeCriticalSection(&g_ssh_heartbeat_lock); |
InitializeCriticalSection(&g_ssh_heartbeat_lock); |
| 324 |
|
InitializeCriticalSection(&g_ssh_blocking_send_lock); |
| 325 |
} |
} |
| 326 |
|
|
| 327 |
void ssh_heartbeat_lock_finalize(void) |
void ssh_heartbeat_lock_finalize(void) |
| 328 |
{ |
{ |
| 329 |
DeleteCriticalSection(&g_ssh_heartbeat_lock); |
DeleteCriticalSection(&g_ssh_heartbeat_lock); |
| 330 |
|
DeleteCriticalSection(&g_ssh_blocking_send_lock); |
| 331 |
} |
} |
| 332 |
|
|
| 333 |
void ssh_heartbeat_lock(void) |
void ssh_heartbeat_lock(void) |
| 340 |
LeaveCriticalSection(&g_ssh_heartbeat_lock); |
LeaveCriticalSection(&g_ssh_heartbeat_lock); |
| 341 |
} |
} |
| 342 |
|
|
| 343 |
|
static void ssh_blocking_send_lock(void) |
| 344 |
|
{ |
| 345 |
|
EnterCriticalSection(&g_ssh_blocking_send_lock); |
| 346 |
|
} |
| 347 |
|
|
| 348 |
|
static void ssh_blocking_send_unlock(void) |
| 349 |
|
{ |
| 350 |
|
LeaveCriticalSection(&g_ssh_blocking_send_lock); |
| 351 |
|
} |
| 352 |
|
|
| 353 |
|
|
| 354 |
// |
// |
| 355 |
// SSH memory dump (for debug) |
// SSH memory dump (for debug) |
| 875 |
// パケット送信後にバッファを使いまわすため、ブロッキングで送信してしまう必要がある。 |
// パケット送信後にバッファを使いまわすため、ブロッキングで送信してしまう必要がある。 |
| 876 |
// ノンブロッキングで送信してWSAEWOULDBLOCKが返ってきた場合、そのバッファは送信完了する |
// ノンブロッキングで送信してWSAEWOULDBLOCKが返ってきた場合、そのバッファは送信完了する |
| 877 |
// まで保持しておかなくてはならない。(2007.10.30 yutaka) |
// まで保持しておかなくてはならない。(2007.10.30 yutaka) |
| 878 |
|
// 以下の処理は thread-safe ではないため、失敗することがある。ゆえに、全体をロックする |
| 879 |
|
// 必要がある。(2007.12.24 yutaka) |
| 880 |
u_long do_block = 0; |
u_long do_block = 0; |
| 881 |
int code = 0; |
int code = 0; |
| 882 |
char *kind = NULL, buf[256]; |
char *kind = NULL, buf[256]; |
| 899 |
return TRUE; |
return TRUE; |
| 900 |
} |
} |
| 901 |
#else |
#else |
| 902 |
|
ssh_blocking_send_lock(); |
| 903 |
|
|
| 904 |
if ((pvar->PWSAAsyncSelect) (pvar->socket, pvar->NotificationWindow, |
if ((pvar->PWSAAsyncSelect) (pvar->socket, pvar->NotificationWindow, |
| 905 |
0, 0) == SOCKET_ERROR) { |
0, 0) == SOCKET_ERROR) { |
| 906 |
code = WSAGetLastError(); |
code = WSAGetLastError(); |
| 925 |
kind = "WSAAsyncSelect2"; |
kind = "WSAAsyncSelect2"; |
| 926 |
goto error; |
goto error; |
| 927 |
} |
} |
| 928 |
|
ssh_blocking_send_unlock(); |
| 929 |
|
|
| 930 |
return TRUE; |
return TRUE; |
| 931 |
|
|
| 932 |
error: |
error: |
| 933 |
|
ssh_blocking_send_unlock(); |
| 934 |
|
|
| 935 |
UTIL_get_lang_msg("MSG_SSH_SEND_PKT_ERROR", pvar, |
UTIL_get_lang_msg("MSG_SSH_SEND_PKT_ERROR", pvar, |
| 936 |
"A communications error occurred while sending an SSH packet.\n" |
"A communications error occurred while sending an SSH packet.\n" |
| 937 |
"The connection will close. (%s:%d)"); |
"The connection will close. (%s:%d)"); |
| 3362 |
} |
} |
| 3363 |
|
|
| 3364 |
|
|
| 3365 |
|
// |
| 3366 |
|
// SCP support |
| 3367 |
|
// |
| 3368 |
|
// (2007.12.21 yutaka) |
| 3369 |
|
// |
| 3370 |
|
int SSH_start_scp(PTInstVar pvar, char *sendfile) |
| 3371 |
|
{ |
| 3372 |
|
buffer_t *msg; |
| 3373 |
|
char *s; |
| 3374 |
|
unsigned char *outmsg; |
| 3375 |
|
int len; |
| 3376 |
|
Channel_t *c = NULL; |
| 3377 |
|
FILE *fp = NULL; |
| 3378 |
|
struct _stat st; |
| 3379 |
|
|
| 3380 |
|
// ソケットがクローズされている場合は何もしない。 |
| 3381 |
|
if (pvar->socket == INVALID_SOCKET) |
| 3382 |
|
goto error; |
| 3383 |
|
|
| 3384 |
|
if (SSHv1(pvar)) // SSH1サポートはTBD |
| 3385 |
|
goto error; |
| 3386 |
|
|
| 3387 |
|
fp = fopen(sendfile, "rb"); |
| 3388 |
|
if (fp == NULL) |
| 3389 |
|
goto error; |
| 3390 |
|
|
| 3391 |
|
// チャネル設定 |
| 3392 |
|
c = ssh2_channel_new(CHAN_SES_WINDOW_DEFAULT, CHAN_SES_PACKET_DEFAULT, TYPE_SCP, -1); |
| 3393 |
|
if (c == NULL) { |
| 3394 |
|
UTIL_get_lang_msg("MSG_SSH_NO_FREE_CHANNEL", pvar, |
| 3395 |
|
"Could not open new channel. TTSSH is already opening too many channels."); |
| 3396 |
|
notify_fatal_error(pvar, pvar->ts->UIMsg); |
| 3397 |
|
goto error; |
| 3398 |
|
} |
| 3399 |
|
// setup SCP data |
| 3400 |
|
c->scp.state = SCP_INIT; |
| 3401 |
|
strncpy_s(c->scp.sendfilefull, sizeof(c->scp.sendfilefull), sendfile, _TRUNCATE); // full path |
| 3402 |
|
ExtractFileName(sendfile, c->scp.sendfile, sizeof(c->scp.sendfile)); // file name only |
| 3403 |
|
c->scp.sendfp = fp; // file pointer |
| 3404 |
|
if (_stat(c->scp.sendfilefull, &st) == 0) { |
| 3405 |
|
c->scp.filestat = st; |
| 3406 |
|
} else { |
| 3407 |
|
goto error; |
| 3408 |
|
} |
| 3409 |
|
|
| 3410 |
|
// session open |
| 3411 |
|
msg = buffer_init(); |
| 3412 |
|
if (msg == NULL) { |
| 3413 |
|
goto error; |
| 3414 |
|
} |
| 3415 |
|
s = "session"; |
| 3416 |
|
buffer_put_string(msg, s, strlen(s)); // ctype |
| 3417 |
|
buffer_put_int(msg, c->self_id); // self(channel number) |
| 3418 |
|
buffer_put_int(msg, c->local_window); // local_window |
| 3419 |
|
buffer_put_int(msg, c->local_maxpacket); // local_maxpacket |
| 3420 |
|
len = buffer_len(msg); |
| 3421 |
|
outmsg = begin_send_packet(pvar, SSH2_MSG_CHANNEL_OPEN, len); |
| 3422 |
|
memcpy(outmsg, buffer_ptr (msg), len); |
| 3423 |
|
finish_send_packet(pvar); |
| 3424 |
|
buffer_free(msg); |
| 3425 |
|
|
| 3426 |
|
return TRUE; |
| 3427 |
|
|
| 3428 |
|
error: |
| 3429 |
|
if (c != NULL) |
| 3430 |
|
ssh2_channel_delete(c); |
| 3431 |
|
if (fp != NULL) |
| 3432 |
|
fclose(fp); |
| 3433 |
|
|
| 3434 |
|
return FALSE; |
| 3435 |
|
} |
| 3436 |
|
|
| 3437 |
|
|
| 3438 |
///////////////////////////////////////////////////////////////////////////// |
///////////////////////////////////////////////////////////////////////////// |
| 3439 |
// |
// |
| 3440 |
// SSH2 protocol procedure in the following code: |
// SSH2 protocol procedure in the following code: |
| 6752 |
return TRUE; |
return TRUE; |
| 6753 |
} |
} |
| 6754 |
|
|
| 6755 |
// ポートフォワーディングの準備 (2005.2.26, 2005.6.21 yutaka) |
if (c->type == TYPE_SHELL) { |
| 6756 |
// シェルオープンしたあとに X11 の要求を出さなくてはならない。(2005.7.3 yutaka) |
// ポートフォワーディングの準備 (2005.2.26, 2005.6.21 yutaka) |
| 6757 |
FWD_prep_forwarding(pvar); |
// シェルオープンしたあとに X11 の要求を出さなくてはならない。(2005.7.3 yutaka) |
| 6758 |
FWD_enter_interactive_mode(pvar); |
FWD_prep_forwarding(pvar); |
| 6759 |
|
FWD_enter_interactive_mode(pvar); |
| 6760 |
|
} |
| 6761 |
|
|
| 6762 |
//debug_print(100, data, len); |
//debug_print(100, data, len); |
| 6763 |
|
|
| 6775 |
} |
} |
| 6776 |
|
|
| 6777 |
buffer_put_int(msg, remote_id); |
buffer_put_int(msg, remote_id); |
| 6778 |
s = "pty-req"; // pseudo terminalのリクエスト |
if (c->type == TYPE_SCP) { |
| 6779 |
|
s = "exec"; |
| 6780 |
|
} else { |
| 6781 |
|
s = "pty-req"; // pseudo terminalのリクエスト |
| 6782 |
|
} |
| 6783 |
buffer_put_string(msg, s, strlen(s)); |
buffer_put_string(msg, s, strlen(s)); |
| 6784 |
buffer_put_char(msg, wantconfirm); // wantconfirm (disableに変更 2005/3/28 yutaka) |
buffer_put_char(msg, wantconfirm); // wantconfirm (disableに変更 2005/3/28 yutaka) |
| 6785 |
|
|
| 6786 |
|
if (c->type == TYPE_SCP) { |
| 6787 |
|
char sbuf[MAX_PATH + 30]; |
| 6788 |
|
_snprintf_s(sbuf, sizeof(sbuf), _TRUNCATE, "scp -t %s", c->scp.sendfile); |
| 6789 |
|
buffer_put_string(msg, sbuf, strlen(sbuf)); |
| 6790 |
|
goto done; |
| 6791 |
|
} |
| 6792 |
|
|
| 6793 |
s = pvar->ts->TermType; // TERM |
s = pvar->ts->TermType; // TERM |
| 6794 |
buffer_put_string(msg, s, strlen(s)); |
buffer_put_string(msg, s, strlen(s)); |
| 6795 |
buffer_put_int(msg, pvar->ssh_state.win_cols); // columns |
buffer_put_int(msg, pvar->ssh_state.win_cols); // columns |
| 6820 |
buffer_put_string(msg, buffer_ptr(ttymsg), buffer_len(ttymsg)); |
buffer_put_string(msg, buffer_ptr(ttymsg), buffer_len(ttymsg)); |
| 6821 |
#endif |
#endif |
| 6822 |
|
|
| 6823 |
|
done: |
| 6824 |
len = buffer_len(msg); |
len = buffer_len(msg); |
| 6825 |
outmsg = begin_send_packet(pvar, SSH2_MSG_CHANNEL_REQUEST, len); |
outmsg = begin_send_packet(pvar, SSH2_MSG_CHANNEL_REQUEST, len); |
| 6826 |
memcpy(outmsg, buffer_ptr(msg), len); |
memcpy(outmsg, buffer_ptr(msg), len); |
| 7017 |
|
|
| 7018 |
} |
} |
| 7019 |
|
|
| 7020 |
|
|
| 7021 |
|
typedef struct scp_thread_parm { |
| 7022 |
|
PTInstVar pvar; |
| 7023 |
|
Channel_t *c; |
| 7024 |
|
} scp_thread_parm_t; |
| 7025 |
|
|
| 7026 |
|
static unsigned __stdcall ssh_scp_thread(void FAR * p) |
| 7027 |
|
{ |
| 7028 |
|
scp_thread_parm_t *parm = (scp_thread_parm_t *)p; |
| 7029 |
|
PTInstVar pvar = parm->pvar; |
| 7030 |
|
Channel_t *c = parm->c; |
| 7031 |
|
char buf[8192]; |
| 7032 |
|
size_t ret; |
| 7033 |
|
long long total_size = 0; |
| 7034 |
|
|
| 7035 |
|
do { |
| 7036 |
|
// ファイルから読み込んだデータはかならずサーバへ送信する。 |
| 7037 |
|
ret = fread(buf, 1, sizeof(buf), c->scp.sendfp); |
| 7038 |
|
if (ret == 0) |
| 7039 |
|
break; |
| 7040 |
|
|
| 7041 |
|
do { |
| 7042 |
|
// socket or channelがクローズされたらスレッドを終わる |
| 7043 |
|
if (pvar->socket == INVALID_SOCKET || c->scp.state == SCP_CLOSING || c->used == 0) |
| 7044 |
|
goto done; |
| 7045 |
|
|
| 7046 |
|
// サーバのウィンドウに余裕がない場合は、送信しない。SSH2_send_channel_data()で遅延送信処理が |
| 7047 |
|
// あるが、SCPスレッドとメインスレッドは別コンテキストであるため、SCPスレッドから遅延送信処理を |
| 7048 |
|
// 行おうとしてもうまく動かない。 |
| 7049 |
|
if (ret > c->remote_window) { |
| 7050 |
|
Sleep(100); // yield |
| 7051 |
|
} |
| 7052 |
|
} while (ret > c->remote_window); |
| 7053 |
|
|
| 7054 |
|
// 別コンテキストで、SSHのシーケンスへ割り込まないようにロックを取る。 |
| 7055 |
|
ssh_heartbeat_lock(); |
| 7056 |
|
SSH2_send_channel_data(pvar, c, buf, ret); |
| 7057 |
|
ssh_heartbeat_unlock(); |
| 7058 |
|
|
| 7059 |
|
total_size += ret; |
| 7060 |
|
|
| 7061 |
|
} while (ret >= sizeof(buf)); |
| 7062 |
|
|
| 7063 |
|
// EOF |
| 7064 |
|
SSH2_send_channel_data(pvar, c, "\0", 1); |
| 7065 |
|
c->scp.state = SCP_DATA; |
| 7066 |
|
|
| 7067 |
|
assert(total_size == c->scp.filestat.st_size); |
| 7068 |
|
|
| 7069 |
|
done: |
| 7070 |
|
free(p); |
| 7071 |
|
|
| 7072 |
|
return 0; |
| 7073 |
|
} |
| 7074 |
|
|
| 7075 |
|
|
| 7076 |
static BOOL handle_SSH2_channel_data(PTInstVar pvar) |
static BOOL handle_SSH2_channel_data(PTInstVar pvar) |
| 7077 |
{ |
{ |
| 7078 |
int len; |
int len; |
| 7079 |
char *data; |
char *data; |
| 7080 |
int id; |
int id; |
| 7081 |
unsigned int strlen; |
unsigned int str_len; |
| 7082 |
Channel_t *c; |
Channel_t *c; |
| 7083 |
|
|
| 7084 |
// 6byte(サイズ+パディング+タイプ)を取り除いた以降のペイロード |
// 6byte(サイズ+パディング+タイプ)を取り除いた以降のペイロード |
| 7099 |
} |
} |
| 7100 |
|
|
| 7101 |
// string length |
// string length |
| 7102 |
strlen = get_uint32_MSBfirst(data); |
str_len = get_uint32_MSBfirst(data); |
| 7103 |
data += 4; |
data += 4; |
| 7104 |
|
|
| 7105 |
// バッファサイズのチェック |
// バッファサイズのチェック |
| 7106 |
if (strlen > c->local_maxpacket) { |
if (str_len > c->local_maxpacket) { |
| 7107 |
// TODO: logging |
// TODO: logging |
| 7108 |
} |
} |
| 7109 |
if (strlen > c->local_window) { |
if (str_len > c->local_window) { |
| 7110 |
// TODO: logging |
// TODO: logging |
| 7111 |
// local window sizeより大きなパケットは捨てる |
// local window sizeより大きなパケットは捨てる |
| 7112 |
return FALSE; |
return FALSE; |
| 7114 |
|
|
| 7115 |
// ペイロードとしてクライアント(TeraTerm)へ渡す |
// ペイロードとしてクライアント(TeraTerm)へ渡す |
| 7116 |
if (c->type == TYPE_SHELL) { |
if (c->type == TYPE_SHELL) { |
| 7117 |
pvar->ssh_state.payload_datalen = strlen; |
pvar->ssh_state.payload_datalen = str_len; |
| 7118 |
pvar->ssh_state.payload_datastart = 8; // id + strlen |
pvar->ssh_state.payload_datastart = 8; // id + strlen |
| 7119 |
|
|
| 7120 |
} else { |
} else if (c->type == TYPE_PORTFWD) { |
| 7121 |
//debug_print(0, data, strlen); |
//debug_print(0, data, strlen); |
| 7122 |
FWD_received_data(pvar, c->local_num, data, strlen); |
FWD_received_data(pvar, c->local_num, data, str_len); |
| 7123 |
|
|
| 7124 |
|
} else if (c->type == TYPE_SCP) { // SCP |
| 7125 |
|
if (str_len == 1 && data[0] == '\0') { // OK |
| 7126 |
|
|
| 7127 |
|
if (c->scp.state == SCP_INIT) { |
| 7128 |
|
char buf[128]; |
| 7129 |
|
|
| 7130 |
|
_snprintf_s(buf, sizeof(buf), _TRUNCATE, "T%lu 0 %lu 0\n", |
| 7131 |
|
(unsigned long)c->scp.filestat.st_mtime, (unsigned long)c->scp.filestat.st_atime); |
| 7132 |
|
|
| 7133 |
|
c->scp.state = SCP_TIMESTAMP; |
| 7134 |
|
SSH2_send_channel_data(pvar, c, buf, strlen(buf)); |
| 7135 |
|
|
| 7136 |
|
} else if (c->scp.state == SCP_TIMESTAMP) { |
| 7137 |
|
char buf[128]; |
| 7138 |
|
|
| 7139 |
|
_snprintf_s(buf, sizeof(buf), _TRUNCATE, "C0644 %lld %s\n", |
| 7140 |
|
(long long)c->scp.filestat.st_size, c->scp.sendfile); |
| 7141 |
|
|
| 7142 |
|
c->scp.state = SCP_FILEINFO; |
| 7143 |
|
SSH2_send_channel_data(pvar, c, buf, strlen(buf)); |
| 7144 |
|
|
| 7145 |
|
} else if (c->scp.state == SCP_FILEINFO) { |
| 7146 |
|
HANDLE thread; |
| 7147 |
|
unsigned tid; |
| 7148 |
|
scp_thread_parm_t *parm = malloc(sizeof(scp_thread_parm_t)); |
| 7149 |
|
|
| 7150 |
|
if (parm == NULL) { |
| 7151 |
|
// TODO: |
| 7152 |
|
} |
| 7153 |
|
parm->pvar = pvar; |
| 7154 |
|
parm->c = c; |
| 7155 |
|
|
| 7156 |
|
thread = (HANDLE)_beginthreadex(NULL, 0, ssh_scp_thread, parm, 0, &tid); |
| 7157 |
|
if (thread == (HANDLE)-1) { |
| 7158 |
|
// TODO: |
| 7159 |
|
} |
| 7160 |
|
c->scp.thread = thread; |
| 7161 |
|
|
| 7162 |
|
} else if (c->scp.state == SCP_DATA) { |
| 7163 |
|
// 送信完了 |
| 7164 |
|
ssh2_channel_delete(c); // free channel |
| 7165 |
|
|
| 7166 |
|
MessageBox(NULL, "SCP sending done.", "TTSSH", MB_OK); |
| 7167 |
|
} |
| 7168 |
|
|
| 7169 |
|
} else { // error |
| 7170 |
|
char msg[2048]; |
| 7171 |
|
unsigned int i; |
| 7172 |
|
|
| 7173 |
|
for (i = 0 ; i < str_len ; i++) { |
| 7174 |
|
msg[i] = data[i]; |
| 7175 |
|
} |
| 7176 |
|
msg[i] = '\0'; |
| 7177 |
|
|
| 7178 |
|
ssh2_channel_delete(c); // free channel |
| 7179 |
|
|
| 7180 |
|
MessageBox(NULL, msg, "TTSSH: SCP error", MB_OK | MB_ICONEXCLAMATION); |
| 7181 |
|
} |
| 7182 |
} |
} |
| 7183 |
|
|
| 7184 |
//debug_print(200, data, strlen); |
//debug_print(200, data, strlen); |
| 7185 |
|
|
| 7186 |
// ウィンドウサイズの調整 |
// ウィンドウサイズの調整 |
| 7187 |
c->local_window -= strlen; |
c->local_window -= str_len; |
| 7188 |
|
|
| 7189 |
do_SSH2_adjust_window_size(pvar, c); |
do_SSH2_adjust_window_size(pvar, c); |
| 7190 |
|
|