diff --git a/Recipe b/Recipe index 51d2eded..7e7295b7 100644 --- a/Recipe +++ b/Recipe @@ -140,7 +140,7 @@ puttytel : [G] GUITERM NONSSH be_nossh WINMISC win_res.res LIBS1 plink : [C] plink console NONSSH WINSSH be_all logging WINMISC + plink.res LIBS2 pscp : [C] scp console WINSSH be_none SFTP wildcard WINMISC scp.res LIBS1 -psftp : [C] psftp console WINSSH be_none SFTP WINMISC scp.res LIBS1 +psftp : [C] psftp winsftp console WINSSH be_none SFTP WINMISC scp.res LIBS1 pageant : [G] pageant sshrsa sshpubk sshdes sshbn sshmd5 version tree234 + misc sshaes sshsha pageantc sshdss sshsh512 winutils winmisc @@ -159,6 +159,8 @@ puttytel : [X] UXTERM uxmisc misc ldisc settings pty uxsel be_nossh uxstore plink : [U] uxplink uxcons NONSSH UXSSH be_all logging UXMISC signal ux_x11 +# psftp : [U] psftp uxsftp console UXSSH be_none SFTP UXMISC + PuTTY : [M] terminal wcwidth ldiscucs logging be_all mac macdlg macevlog + macterm macucs mac_res.rsrc testback NONSSH MACSSH MACMISC CHARSET + stricmp vsnprint dialog config macctrls diff --git a/psftp.c b/psftp.c index 484d1531..a032c70c 100644 --- a/psftp.c +++ b/psftp.c @@ -2,8 +2,6 @@ * psftp.c: front end for PSFTP. */ -#include - #include #include #include @@ -12,6 +10,7 @@ #define PUTTY_DO_GLOBALS #include "putty.h" +#include "psftp.h" #include "storage.h" #include "ssh.h" #include "sftp.h" @@ -1024,34 +1023,21 @@ static int sftp_cmd_open(struct sftp_command *cmd) static int sftp_cmd_lcd(struct sftp_command *cmd) { - char *currdir; - int len; + char *currdir, *errmsg; if (cmd->nwords < 2) { printf("lcd: expects a local directory name\n"); return 0; } - if (!SetCurrentDirectory(cmd->words[1])) { - LPVOID message; - int i; - FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, GetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&message, 0, NULL); - i = strcspn((char *)message, "\n"); - printf("lcd: unable to change directory: %.*s\n", i, (LPCTSTR)message); - LocalFree(message); + errmsg = psftp_lcd(cmd->words[1]); + if (errmsg) { + printf("lcd: unable to change directory: %s\n", errmsg); + sfree(errmsg); return 0; } - currdir = snewn(256, char); - len = GetCurrentDirectory(256, currdir); - if (len > 256) - currdir = sresize(currdir, len, char); - GetCurrentDirectory(len, currdir); + currdir = psftp_getcwd(); printf("New local directory is %s\n", currdir); sfree(currdir); @@ -1061,13 +1047,8 @@ static int sftp_cmd_lcd(struct sftp_command *cmd) static int sftp_cmd_lpwd(struct sftp_command *cmd) { char *currdir; - int len; - currdir = snewn(256, char); - len = GetCurrentDirectory(256, currdir); - if (len > 256) - currdir = sresize(currdir, len, char); - GetCurrentDirectory(len, currdir); + currdir = psftp_getcwd(); printf("Current local directory is %s\n", currdir); sfree(currdir); @@ -1108,9 +1089,10 @@ static struct sftp_cmd_lookup { * in ASCII order. */ { - "!", TRUE, "run a local Windows command", + "!", TRUE, "run a local command", "\n" - " Runs a local Windows command. For example, \"!del myfile\".\n", + /* FIXME: this example is crap for non-Windows. */ + " Runs a local command. For example, \"!del myfile\".\n", sftp_cmd_pling }, { @@ -1620,20 +1602,6 @@ void ldisc_send(void *handle, char *buf, int len, int interactive) assert(len == 0); } -/* - * Be told what socket we're supposed to be using. - */ -static SOCKET sftp_ssh_socket; -char *do_select(SOCKET skt, int startup) -{ - if (startup) - sftp_ssh_socket = skt; - else - sftp_ssh_socket = INVALID_SOCKET; - return NULL; -} -extern int select_result(WPARAM, LPARAM); - /* * In psftp, all agent requests should be synchronous, so this is a * never-called stub. @@ -1729,13 +1697,8 @@ int sftp_recvdata(char *buf, int len) } while (outlen > 0) { - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(sftp_ssh_socket, &readfds); - if (select(1, &readfds, NULL, NULL, NULL) < 0) + if (ssh_sftp_loop_iteration() < 0) return 0; /* doom */ - select_result((WPARAM) sftp_ssh_socket, (LPARAM) FD_READ); } return 1; @@ -1746,42 +1709,6 @@ int sftp_senddata(char *buf, int len) return 1; } -/* - * Loop through the ssh connection and authentication process. - */ -static void ssh_sftp_init(void) -{ - if (sftp_ssh_socket == INVALID_SOCKET) - return; - while (!back->sendok(backhandle)) { - fd_set readfds; - FD_ZERO(&readfds); - FD_SET(sftp_ssh_socket, &readfds); - if (select(1, &readfds, NULL, NULL, NULL) < 0) - return; /* doom */ - select_result((WPARAM) sftp_ssh_socket, (LPARAM) FD_READ); - } -} - -/* - * Initialize the Win$ock driver. - */ -static void init_winsock(void) -{ - WORD winsock_ver; - WSADATA wsadata; - - winsock_ver = MAKEWORD(1, 1); - if (WSAStartup(winsock_ver, &wsadata)) { - fprintf(stderr, "Unable to initialise WinSock"); - cleanup_exit(1); - } - if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) { - fprintf(stderr, "WinSock version is incompatible with 1.1"); - cleanup_exit(1); - } -} - /* * Short description of parameters. */ @@ -1963,7 +1890,12 @@ static int psftp_connect(char *userhost, char *user, int portnumber) logctx = log_init(NULL, &cfg); back->provide_logctx(backhandle, logctx); console_provide_logctx(logctx); - ssh_sftp_init(); + while (!back->sendok(backhandle)) { + if (ssh_sftp_loop_iteration() < 0) { + fprintf(stderr, "ssh_init: error during SSH connection setup\n"); + return 1; + } + } if (verbose && realhost != NULL) printf("Connected to %s\n", realhost); return 0; @@ -1983,7 +1915,7 @@ void cmdline_error(char *p, ...) /* * Main program. Parse arguments etc. */ -int main(int argc, char *argv[]) +int psftp_main(int argc, char *argv[]) { int i; int portnumber = 0; @@ -1996,7 +1928,6 @@ int main(int argc, char *argv[]) flags = FLAG_STDERR | FLAG_INTERACTIVE | FLAG_SYNCAGENT; cmdline_tooltype = TOOLTYPE_FILETRANSFER; ssh_get_line = &console_get_line; - init_winsock(); sk_init(); userhost = user = NULL; @@ -2064,7 +1995,6 @@ int main(int argc, char *argv[]) back->special(backhandle, TS_EOF); sftp_recvdata(&ch, 1); } - WSACleanup(); random_save_seed(); return 0; diff --git a/psftp.h b/psftp.h new file mode 100644 index 00000000..092d10ac --- /dev/null +++ b/psftp.h @@ -0,0 +1,28 @@ +/* + * psftp.h: interface between psftp.c and each platform-specific + * SFTP module. + */ + +#ifndef PUTTY_PSFTP_H +#define PUTTY_PSFTP_H + +/* + * psftp_getcwd returns the local current directory. The returned + * string must be freed by the caller. + */ +char *psftp_getcwd(void); + +/* + * psftp_lcd changes the local current directory. The return value + * is NULL on success, or else an error message which must be freed + * by the caller. + */ +char *psftp_lcd(char *newdir); + +/* + * One iteration of the PSFTP event loop: wait for network data and + * process it, once. + */ +int ssh_sftp_loop_iteration(void); + +#endif /* PUTTY_PSFTP_H */ diff --git a/winsftp.c b/winsftp.c new file mode 100644 index 00000000..677bf024 --- /dev/null +++ b/winsftp.c @@ -0,0 +1,113 @@ +/* + * winsftp.c: the Windows-specific parts of PSFTP. + */ + +#include + +#include "putty.h" +#include "psftp.h" + +/* + * Be told what socket we're supposed to be using. + */ +static SOCKET sftp_ssh_socket; +char *do_select(SOCKET skt, int startup) +{ + if (startup) + sftp_ssh_socket = skt; + else + sftp_ssh_socket = INVALID_SOCKET; + return NULL; +} +extern int select_result(WPARAM, LPARAM); + +/* + * Initialize the WinSock driver. + */ +static void init_winsock(void) +{ + WORD winsock_ver; + WSADATA wsadata; + + winsock_ver = MAKEWORD(1, 1); + if (WSAStartup(winsock_ver, &wsadata)) { + fprintf(stderr, "Unable to initialise WinSock"); + cleanup_exit(1); + } + if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) { + fprintf(stderr, "WinSock version is incompatible with 1.1"); + cleanup_exit(1); + } +} + +/* + * Set local current directory. Returns NULL on success, or else an + * error message which must be freed after printing. + */ +char *psftp_lcd(char *dir) +{ + char *ret = NULL; + + if (!SetCurrentDirectory(dir)) { + LPVOID message; + int i; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&message, 0, NULL); + i = strcspn((char *)message, "\n"); + ret = dupprintf("%.*s", i, (LPCTSTR)message); + LocalFree(message); + } + + return ret; +} + +/* + * Get local current directory. Returns a string which must be + * freed. + */ +char *psftp_getcwd(void) +{ + char *ret = snewn(256, char); + int len = GetCurrentDirectory(256, ret); + if (len > 256) + ret = sresize(ret, len, char); + GetCurrentDirectory(len, ret); + return ret; +} + +/* + * Wait for some network data and process it. + */ +int ssh_sftp_loop_iteration(void) +{ + fd_set readfds; + + if (sftp_ssh_socket == INVALID_SOCKET) + return -1; /* doom */ + + FD_ZERO(&readfds); + FD_SET(sftp_ssh_socket, &readfds); + if (select(1, &readfds, NULL, NULL, NULL) < 0) + return -1; /* doom */ + + select_result((WPARAM) sftp_ssh_socket, (LPARAM) FD_READ); + return 0; +} + +/* + * Main program. Parse arguments etc. + */ +int main(int argc, char *argv[]) +{ + int ret; + + init_winsock(); + ret = psftp_main(argc, argv); + WSACleanup(); + + return ret; +}