#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include "sftpfunc.h"
#include "fsplugin.h"
#include "multiserver.h"
#include "resource.h"
#include "utils.h"
#include "CVTUTF.H"
#include "cunicode.h"
#include "ftpdir.h"
#ifdef WIN64
#define myint INT_PTR
#else
#define myint int
#endif
extern tProgressProc ProgressProc;
extern tRequestProc RequestProc;
extern tLogProc LogProc;
extern tCryptProc CryptProc;
extern HINSTANCE hinst;
extern BOOL CryptCheckPass;
extern BOOL UpdatePercentBar(void* serverid,int percent);
extern char pluginname[];
extern int CryptoNumber;
BOOL serverfieldchangedbyuser=false;
char Global_TransferMode='I'; //I=Binary, A=Ansi, X=Auto
WCHAR Global_TextTypes[1024];
char global_detectcrlf=0;
extern void ShowStatus(char* status);
extern void ShowStatusW(WCHAR* status);
// Will be initialized when loading the SSH DLL
BOOL SSH_ScpNeedBlockingMode=true; // Need to use blocking mode for SCP?
BOOL SSH_ScpNeedQuote=true; // Need to use double quotes "" around names with spaces for SCP?
LIBSSH2_CHANNEL* ConnectChannel(LIBSSH2_SESSION *session);
BOOL SendChannelCommand(LIBSSH2_SESSION *session,LIBSSH2_CHANNEL *channel,char* command);
BOOL GetChannelCommandReply(LIBSSH2_SESSION *session,LIBSSH2_CHANNEL *channel,char* command);
void DisconnectShell(LIBSSH2_CHANNEL *channel);
void StripEscapeSequences(char *msgbuf);
BOOL ReadChannelLine(LIBSSH2_CHANNEL *channel,char *line,int linelen,char* msgbuf,int msgbuflen,char* errbuf,int errbuflen);
int CloseRemote(void* serverid,LIBSSH2_SFTP_HANDLE *remotefilesftp,LIBSSH2_CHANNEL *remotefilescp,BOOL timeout,int percent);
//****************** declarations for ipv6: ****************************/
#define AF_INET6 23
typedef struct addrinfo
{
int ai_flags; // AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST
int ai_family; // PF_xxx
int ai_socktype; // SOCK_xxx
int ai_protocol; // 0 or IPPROTO_xxx for IPv4 and IPv6
size_t ai_addrlen; // Length of ai_addr
char * ai_canonname; // Canonical name for nodename
struct sockaddr * ai_addr; // Binary address
struct addrinfo * ai_next; // Next structure in linked list
}
ADDRINFOA, *PADDRINFOA;
typedef struct {
short sin6_family; /* AF_INET6 */
u_short sin6_port; /* Transport level port number */
u_long sin6_flowinfo; /* IPv6 flow information */
u_char sin6_addr[16]; /* IPv6 address */
u_long sin6_scope_id; /* set of interfaces for a scope */
} sockaddr_in6,*psockaddr_in6;
typedef ADDRINFOA ADDRINFO, FAR * LPADDRINFO;
typedef int (WINAPI* tgetaddrinfo)(IN const char FAR * nodename,
IN const char FAR * servname,
IN const struct addrinfo FAR * hints,
OUT struct addrinfo FAR * FAR * res);
typedef int (WINAPI* tfreeaddrinfo)(IN LPADDRINFO pAddrInfo);
typedef int (WINAPI* tWSAAddressToStringA)(
IN LPSOCKADDR lpsaAddress,
IN DWORD dwAddressLength,
IN void* lpProtocolInfo,
IN OUT LPSTR lpszAddressString,
IN OUT LPDWORD lpdwAddressStringLength);
tgetaddrinfo getaddrinfo=NULL;
tfreeaddrinfo freeaddrinfo=NULL;
tWSAAddressToStringA WSAAddressToString=NULL;
typedef struct {
LIBSSH2_CHANNEL *channel;
char msgbuf[2048]; // previously received data
char errbuf[2048];
} SCP_DATA;
BOOL EscapePressed()
{
// Abort with ESCAPE pressed in same program only!
if (GetAsyncKeyState(VK_ESCAPE)<0) {
DWORD procid1;
HWND hwnd=GetActiveWindow();
if (hwnd) {
GetWindowThreadProcessId(hwnd,&procid1);
if (procid1==GetCurrentProcessId())
return true;
}
}
return false;
}
void strlcpyansitoutf8(char* utf8str,const char* ansistr,int maxlen)
{
UTF16 utf16buf[1024];
UTF16* srcstart=utf16buf;
UTF8* trgstart=(unsigned char*)utf8str;
MultiByteToWideChar(CP_ACP,0,ansistr,-1,(WCHAR*)&utf16buf,sizeof(utf16buf)/2);
ConvertUTF16toUTF8(&srcstart,(utf16buf+wcslen((WCHAR*)utf16buf)+2),
&trgstart,trgstart+maxlen-1);
}
void wcslcpytoutf8(char* utf8str,WCHAR* utf16str,int maxlen)
{
UTF16* srcstart=(UTF16*)utf16str;
UTF8* trgstart=(UTF8*)utf8str;
ConvertUTF16toUTF8(&srcstart,srcstart+wcslen((WCHAR*)utf16str)+2,
&trgstart,trgstart+maxlen-1);
}
//#define FUNCDEF(f,p) (*f) p // define the functions as pointers
//#define FUNCDEF(f,p) WINAPI f p
HINSTANCE sshlib=NULL;
BOOL loadOK,loadAgent;
FARPROC GetProcAddress2(HMODULE hModule,LPCSTR lpProcName)
{
FARPROC retval=GetProcAddress(hModule,lpProcName);
if (!retval)
loadOK=false;
return retval;
}
FARPROC GetProcAddressAgent(HMODULE hModule,LPCSTR lpProcName)
{
FARPROC retval=GetProcAddress(hModule,lpProcName);
if (!retval)
loadAgent=false;
return retval;
}
typedef void* LIBSSH2_AGENT;
struct libssh2_agent_publickey {
unsigned int magic; /* magic stored by the library */
void *node; /* handle to the internal representation of key */
unsigned char *blob; /* public key blob */
size_t blob_len; /* length of the public key blob */
char *comment; /* comment in printable format */
};
#undef FUNCDEF
#define FUNCDEF(r,f,p) typedef r (*t##f) p;
#undef FUNCDEF2
#define FUNCDEF2(r,f,p) typedef r (*t##f) p;
#include "sshdynfunctions.h"
#undef FUNCDEF
#define FUNCDEF(r,f,p) t##f f=NULL;
#undef FUNCDEF2
#define FUNCDEF2(r,f,p) t##f f=NULL;
#include "sshdynfunctions.h"
// we need version 1.2.1 or later for SCP mode working in async mode
#define LIBSSH2_VERSION_NUM_ASYNC_SCP 0x010201
// we need version 1.2.1 or later for SCP mode working without quotes "" for files with spaces in name
#define LIBSSH2_VERSION_NUM_QUOTE_SCP 0x010100
BOOL LoadSSHLib()
{
if(!sshlib) {
LogProc(PluginNumber,MSGTYPE_DETAILS,"Loading SSH Library");
int olderrormode=SetErrorMode(0x8001);
char dllname[MAX_PATH];
dllname[0]=0;
// first, try in the program directory.
GetModuleFileName(NULL,dllname,sizeof(dllname)-10);
char* p=strrchr(dllname,'\\');
if (p)
p++;
else
p=dllname;
// Load libeay32.dll first, otherwise it will not be found!
#ifdef WIN64
p[0]=0;
strlcat(dllname,"64\\zlibwapi.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"64\\zlib1.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"64\\libeay32.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"64\\libssh2.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
if (!sshlib) {
p[0]=0;
strlcat(dllname,"x64\\zlibwapi.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"x64\\zlib1.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"x64\\libeay32.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"x64\\libssh2.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
}
#else
sshlib=NULL;
#endif
if (!sshlib) {
p[0]=0;
strlcat(dllname,"zlibwapi.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"libeay32.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"libssh2.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
}
if (!sshlib) {
GetModuleFileName(hinst,dllname,sizeof(dllname)-10);
char* p=strrchr(dllname,'\\');
if (p)
p++;
else
p=dllname;
// Load libeay32.dll first, otherwise it will not be found!
p[0]=0;
#ifdef WIN64
strlcat(dllname,"64\\zlibwapi.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"64\\zlib1.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"64\\libeay32.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"64\\libssh2.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
if (!sshlib) {
p[0]=0;
strlcat(dllname,"x64\\zlibwapi.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"x64\\zlib1.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"x64\\libeay32.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"x64\\libssh2.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
}
#endif
if (!sshlib) {
p[0]=0;
strlcat(dllname,"zlibwapi.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"zlib1.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"libeay32.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
p[0]=0;
strlcat(dllname,"libssh2.dll",sizeof(dllname)-1);
sshlib=(HINSTANCE)LoadLibrary(dllname);
}
}
if (!sshlib) {
// try also in Total Commander dir and the path!
// we don't need to load libeay32.dll then, because
// libssh2.dll would find it in the path anyway!
sshlib=(HINSTANCE)LoadLibrary("libssh2.dll");
}
SetErrorMode(olderrormode);
if (!sshlib) {
#ifdef WIN64
MessageBox(GetActiveWindow(), "Please put libssh2.dll and libeay32.dll either\n- in the same directory as the plugin, or\n- in the Total Commander dir, or\n- in subdir 'x64' of the plugin or TC directory, or\n- somewhere in your PATH!\n\nSee the plugin's readme.txt for download instructions.","Error",MB_ICONSTOP);
#else
MessageBox(GetActiveWindow(), "Please put libssh2.dll and libeay32.dll either\n- in the same directory as the plugin, or\n- in the Total Commander dir, or\n- somewhere in your PATH!\n\nSee the plugin's readme.txt for download instructions.","Error",MB_ICONSTOP);
#endif
return false;
}
loadOK=true;
loadAgent=true;
// the following will load all the functions!
#undef FUNCDEF
#undef FUNCDEF2
#define FUNCDEF(r,f,p) f=(t##f)GetProcAddress2(sshlib, #f)
#define FUNCDEF2(r,f,p) f=(t##f)GetProcAddressAgent(sshlib, #f)
#include "sshdynfunctions.h"
SSH_ScpNeedBlockingMode=(libssh2_version==NULL || !libssh2_version(LIBSSH2_VERSION_NUM_ASYNC_SCP));
SSH_ScpNeedQuote=(libssh2_version==NULL || !libssh2_version(LIBSSH2_VERSION_NUM_QUOTE_SCP));
}
// initialize the Winsock calls too
if (loadOK) {
char ws2libname[MAX_PATH];
WSADATA wsadata;
WSAStartup(MAKEWORD( 2, 2 ), &wsadata);
// also load the getaddrinfo function
if (GetSystemDirectoryA(ws2libname, MAX_PATH)) {
strlcat(ws2libname, "\\ws2_32",sizeof(ws2libname)-1);
HINSTANCE ws2lib = LoadLibraryA(ws2libname);
if (ws2lib) {
getaddrinfo = (tgetaddrinfo)GetProcAddress(ws2lib, "getaddrinfo");
freeaddrinfo = (tfreeaddrinfo)GetProcAddress(ws2lib, "freeaddrinfo");
WSAAddressToString=(tWSAAddressToStringA)GetProcAddress(ws2lib, "WSAAddressToStringA");
if (!getaddrinfo) {
FreeLibrary(ws2lib);
GetSystemDirectoryA(ws2libname, MAX_PATH);
strlcat(ws2libname, "\\wship6",sizeof(ws2libname)-1);
ws2lib = LoadLibraryA(ws2libname);
if (ws2lib) {
getaddrinfo = (tgetaddrinfo)GetProcAddress(ws2lib, "getaddrinfo");
freeaddrinfo = (tfreeaddrinfo)GetProcAddress(ws2lib, "freeaddrinfo");
if (!getaddrinfo) {
FreeLibrary(ws2lib);
}
}
}
}
}
}
return loadOK;
}
static void kbd_callback(const char *name, int name_len,
const char *instruction, int instruction_len, int num_prompts,
const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
void **abstract)
{
for (int i=0;i<num_prompts;i++) {
// Special case: Pass the stored password as the first response to the interactive prompts
// Note: We may get multiple calls to kbd_callback - this is tracked with "InteractivePasswordSent"
pConnectSettings ConnectSettings=(pConnectSettings)*abstract;
if (ConnectSettings && i==0 && ConnectSettings->password[0] && !ConnectSettings->InteractivePasswordSent) {
ConnectSettings->InteractivePasswordSent=true;
responses[0].text = _strdup(ConnectSettings->password);
responses[0].length = (unsigned int)strlen(ConnectSettings->password);
} else {
char buf[1024];
char retbuf[256];
char title[128];
buf[0]=0;
title[0]=0;
if (instruction && instruction_len) {
strlcpy(buf,instruction,min(instruction_len,sizeof(buf)-1));
strlcat(buf,"\n",sizeof(buf)-1);
}
if (prompts[i].length && prompts[i].text) {
strlcpy(retbuf,prompts[i].text,min(prompts[i].length,sizeof(retbuf)-1));
strlcat(buf,retbuf,sizeof(buf)-1);
}
if (buf[0]==0)
strlcat(buf,"Password:",sizeof(buf)-1);
if (name && name_len)
strlcpy(title,name,min(name_len,sizeof(title)-1));
else
strlcpy(title,"SFTP password for",sizeof(title)-1);
if (ConnectSettings) {
strlcat(title," ",sizeof(title)-1);
strlcat(title,ConnectSettings->user,sizeof(title)-1);
strlcat(title,"@",sizeof(title)-1);
strlcat(title,ConnectSettings->server,sizeof(title)-1);
}
retbuf[0]=0;
if (RequestProc(PluginNumber,RT_Password,title,buf,retbuf,sizeof(retbuf)-1)) {
responses[0].text = _strdup(retbuf);
responses[0].length = (unsigned int)strlen(retbuf);
// Remember password for background transfers
if (ConnectSettings && ConnectSettings->password[0]==0)
strlcpy(ConnectSettings->password,retbuf,sizeof(ConnectSettings->password)-1);
} else {
responses[0].text = NULL;
responses[0].length = 0;
}
}
}
} /* kbd_callback */
void *myalloc(size_t count, void **abstract)
{
return malloc(count);
}
void *myrealloc(void *ptr, size_t count, void **abstract)
{
return realloc(ptr,count);
}
void myfree(void *ptr, void **abstract)
{
free(ptr);
}
BOOL ismimechar(char ch)
{
return ((ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || (ch>='0' && ch<='9') ||
ch=='/' || ch=='+' || ch=='=' || ch=='\r' || ch=='\n');
}
BOOL ProgressLoop(char* progresstext,int start,int end,int* loopval,DWORD* lasttime)
{
DWORD time=GetCurrentTime();
if (time-*lasttime>100 || *loopval<start) {
*lasttime=time;
(*loopval)++;
if (*loopval<start || *loopval>end)
*loopval=start;
return ProgressProc(PluginNumber,progresstext,"-",*loopval);
}
return false;
}
void ShowError(char* error)
{
ShowStatus(error); // log it
RequestProc(PluginNumber,RT_MsgOK,"SFTP Error",error,NULL,0);
}
void ShowErrorId(int errorid)
{
char errorstr[256];
LoadStr(errorstr,errorid);
ShowStatus(errorstr); // log it
RequestProc(PluginNumber,RT_MsgOK,"SFTP Error",errorstr,NULL,0);
}
void SetBlockingSocket(SOCKET s,BOOL blocking)
{
u_long arg=blocking ? 0:1;
ioctlsocket(s,FIONBIO,&arg);
}
BOOL IsSocketError(SOCKET s)
{
fd_set fds;
timeval timeout;
timeout.tv_sec=0;
timeout.tv_usec=50000;
FD_ZERO(&fds);
FD_SET(s,&fds);
return 1==select(0,NULL,NULL,&fds,&timeout);
}
BOOL IsSocketWritable(SOCKET s)
{
fd_set fds;
timeval timeout;
timeout.tv_sec=0;
timeout.tv_usec=50000;
FD_ZERO(&fds);
FD_SET(s,&fds);
return 1==select(0,NULL,&fds,NULL,&timeout);
}
BOOL IsSocketReadable(SOCKET s)
{
fd_set fds;
timeval timeout;
timeout.tv_sec=1; // This is absolutely necessary, otherwise wingate local will not work!
timeout.tv_usec=0;
FD_ZERO(&fds);
FD_SET(s,&fds);
int err=select(0,&fds,NULL,NULL,&timeout);
return (err==1);
}
int mysend(SOCKET s,const char *buf,int len,int flags,char* progressmessage,int progressstart,int* ploop,DWORD* plasttime)
{
int err;
int ret=SOCKET_ERROR;
while (true) {
ret=send(s,buf,len,flags);
if (ret!=len)
MessageBeep(0);
if (ret>=0)
return ret;
err=WSAGetLastError();
if (err==WSAEWOULDBLOCK) {
if (ProgressLoop(progressmessage,progressstart,progressstart+10,ploop,plasttime))
break;
}
}
return ret;
}
int myrecv(SOCKET s,char *buf,int len,int flags,char* progressmessage,int progressstart,int* ploop,DWORD* plasttime)
{
int err;
int totallen=len;
int ret=SOCKET_ERROR;
while (true) {
if (!IsSocketReadable(s))
err=WSAEWOULDBLOCK;
else {
ret=recv(s,buf,len,flags);
if (ret==len)
return totallen;
else if (ret<=0)
err=WSAGetLastError();
else { // partial data received!
buf+=ret;
len-=ret;
err=0;
}
}
if (err==WSAEWOULDBLOCK) {
if (ProgressLoop(progressmessage,progressstart,progressstart+10,ploop,plasttime))
break;
Sleep(50);
} else if (err!=0)
break;
}
return ret;
}
pConnectSettings gConnectResults;
char* gDisplayName;
char* gIniFileName;
int g_focusset=0;
void EncryptString(LPCTSTR pszPlain, LPTSTR pszEncrypted, UINT cchEncrypted);
void newpassfunc(LIBSSH2_SESSION *session, char **newpw, int *newpw_len, void **abstract)
{
pConnectSettings PassConnectSettings=(pConnectSettings)*abstract;
char title[128],buf1[128];
char newpass[128];
LoadStr(title,IDS_PASS_TITLE);
LoadStr(buf1,IDS_PASS_CHANGE_REQUEST);
newpass[0]=0;
if (RequestProc(PluginNumber,RT_Password,title,buf1,newpass,sizeof(newpass)-1)) {
int bufsize=(int)strlen(newpass)+1;
*newpw=(char*)malloc(bufsize);
strlcpy(*newpw,newpass,bufsize);
*newpw_len=bufsize;
if (PassConnectSettings) {
strlcpy(PassConnectSettings->password,newpass,sizeof(PassConnectSettings->password)-1);
switch (PassConnectSettings->passSaveMode) {
case 1:
CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_SAVE_PASSWORD,
PassConnectSettings->DisplayName,newpass,0);
break;
case 2:
if (newpass[0]==0) {
WritePrivateProfileString(PassConnectSettings->DisplayName,"password",NULL,gIniFileName);
} else {
char szEncryptedPassword[256];
EncryptString(newpass, szEncryptedPassword, countof(szEncryptedPassword));
WritePrivateProfileString(PassConnectSettings->DisplayName,"password",szEncryptedPassword,gIniFileName);
}
break;
}
}
}
}
int SftpConnect(pConnectSettings ConnectSettings)
{
if (!LoadSSHLib())
return SFTP_FAILED;
if (!loadAgent && ConnectSettings->useagent) {
char buf[128],buf1[128];
LoadStr(buf1,IDS_SSH2_TOO_OLD);
#ifdef sprintf_s
sprintf_s(buf, 128, buf1, LIBSSH2_VERSION);
#else
sprintf(buf, buf1, LIBSSH2_VERSION);
#endif
MessageBox(GetActiveWindow(), buf, "Error", MB_ICONSTOP);
return SFTP_FAILED;
}
char buf[1024];
DWORD len;
char connecttoserver[250];
unsigned long hostaddr;
unsigned short connecttoport;
char* p;
struct sockaddr_in sin;
struct addrinfo hints, *res, *ai;
bool connected = FALSE;
int nsocks; int auth,loop;
DWORD lasttime=GetCurrentTime();
if (!ConnectSettings->session) {
if (ProgressProc(PluginNumber,"Connecting...","-",0))
return -1;
switch (ConnectSettings->proxytype) {
case 0:
strlcpy(connecttoserver,ConnectSettings->server,sizeof(connecttoserver)-1);
connecttoport=ConnectSettings->customport;
break;
case 2: // HTTP connect
if(!ParseAddress(ConnectSettings->proxyserver, &connecttoserver[0], &connecttoport, 8080)) {
MessageBox(GetActiveWindow(),"Invalid proxy server address.","SFTP Error",MB_ICONSTOP);
return -1;
}
break;
case 3: // SOCKS4a
case 4: // SOCKS5
if(!ParseAddress(ConnectSettings->proxyserver, &connecttoserver[0], &connecttoport, 1080)) {
MessageBox(GetActiveWindow(),"Invalid proxy server address.","SFTP Error",MB_ICONSTOP);
return -1;
}
break;
default:
MessageBox(GetActiveWindow(),"Function not supported yet!","SFTP Error",MB_ICONSTOP);
return -1;
}
ShowStatus("========================");
LoadStr(buf,IDS_CONNECT_TO);
strlcat(buf,ConnectSettings->server,sizeof(buf)-1);
ShowStatus(buf);
if (!getaddrinfo) {
hostaddr = inet_addr(connecttoserver);
if (hostaddr==INADDR_NONE) {
hostent* hostinfo;
hostinfo = (struct hostent *) gethostbyname(connecttoserver);
if(hostinfo)
memcpy(&hostaddr,hostinfo->h_addr_list[0],4);
}
ConnectSettings->sock = socket(AF_INET, SOCK_STREAM, 0);
sin.sin_family = AF_INET;
sin.sin_port = htons(connecttoport); //htons(22);
sin.sin_addr.s_addr = hostaddr;
if (ConnectSettings->proxytype) {
LoadStr(buf,IDS_VIA_PROXY);
strlcat(buf,connecttoserver,sizeof(buf)-1);
ShowStatus(buf);
}
SetBlockingSocket(ConnectSettings->sock,false);
connected = connect(ConnectSettings->sock, (struct sockaddr*)(&sin),
sizeof(struct sockaddr_in)) == 0;
if (!connected && WSAGetLastError()==WSAEWOULDBLOCK) {
while (true) {
if (IsSocketWritable(ConnectSettings->sock)) {
connected=true;
break;
}
if (IsSocketError(ConnectSettings->sock))
break;
if (ProgressLoop(buf,0,20,&loop,&lasttime))
break;
}
}
} else {
// IPv6 code added by forum-user "Sob"
memset(&hints, 0, sizeof(hints));
switch (ConnectSettings->protocoltype) {
case 1:
hints.ai_family = AF_INET;
break;
case 2:
hints.ai_family = AF_INET6;
break;
default:
hints.ai_family = AF_UNSPEC;
break;
}
hints.ai_socktype = SOCK_STREAM;
#ifdef sprintf_s
sprintf_s(buf,sizeof(buf), "%d", connecttoport);
#else
sprintf(buf,"%d", connecttoport);
#endif
if (getaddrinfo(connecttoserver, buf, &hints, &res)!=0) {
ShowErrorId(IDS_ERR_GETADDRINFO);
return -1;
}
for (nsocks = 0, ai = res; ai; ai = ai->ai_next, nsocks++) {
if(nsocks>0) closesocket(ConnectSettings->sock);
ConnectSettings->sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (WSAAddressToString) {
len = (DWORD)sizeof(buf)-(DWORD)strlen(buf);
strlcpy(buf,"IP address: ",sizeof(buf)-1);
WSAAddressToString(ai->ai_addr, ai->ai_addrlen, NULL, buf+(DWORD)strlen(buf), (LPDWORD)&len);
ShowStatus(buf);
}
SetBlockingSocket(ConnectSettings->sock,false);
connected=connect(ConnectSettings->sock, ai->ai_addr, (int)ai->ai_addrlen)==0;
if (!connected && WSAGetLastError()==WSAEWOULDBLOCK) {
while (true) {
if (IsSocketWritable(ConnectSettings->sock)) {
connected=true;
break;
}
if (IsSocketError(ConnectSettings->sock))
break;
if (ProgressLoop(buf,0,20,&loop,&lasttime))
break;
}
}
if (connected)
break;
}
if (freeaddrinfo)
freeaddrinfo(res);
}
if (!connected) {
if (ConnectSettings->proxytype)
ShowErrorId(IDS_ERR_PROXYCONNECT);
else
ShowErrorId(IDS_ERR_SERVERCONNECT);
return -1;
}
// **********************************************************
// Proxy?
bool lastcrlfcrlf;
char progressbuf[250];
LoadStr(progressbuf,IDS_PROXY_CONNECT);
int nrbytes;
switch (ConnectSettings->proxytype) {
case 2: // HTTP CONNECT
if (ProgressProc(PluginNumber,progressbuf,"-",20)) {
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
// Send "CONNECT hostname:port HTTP/1.1"<CRLF>"Host: hostname:port"<2xCRLF> to the proxy
if(IsNumericIPv6(ConnectSettings->server))
#ifdef sprintf_s
sprintf_s(buf,sizeof(buf),"CONNECT [%s]:%d HTTP/1.1\r\nHost: [%s]:%d\r\n",ConnectSettings->server,ConnectSettings->customport,ConnectSettings->server,ConnectSettings->customport);
#else
sprintf(buf,"CONNECT [%s]:%d HTTP/1.1\r\nHost: [%s]:%d\r\n",ConnectSettings->server,ConnectSettings->customport,ConnectSettings->server,ConnectSettings->customport);
#endif
else
#ifdef sprintf_s
sprintf_s(buf,sizeof(buf),"CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n",ConnectSettings->server,ConnectSettings->customport,ConnectSettings->server,ConnectSettings->customport);
#else
sprintf(buf,"CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n",ConnectSettings->server,ConnectSettings->customport,ConnectSettings->server,ConnectSettings->customport);
#endif
if (ConnectSettings->proxyuser[0]) {
char buf1[250],buf2[500],title[250];
char passphrase[256];
strlcpy(passphrase,ConnectSettings->proxypassword,sizeof(passphrase)-1);
LoadStr(buf1,IDS_PROXY_PASSWORD_FOR);
strlcpy(title,buf1,sizeof(title)-1);
strlcat(title,ConnectSettings->proxyuser,sizeof(title)-1);
strlcat(title,"@",sizeof(title)-1);
strlcat(title,ConnectSettings->proxyserver,sizeof(title)-1);
LoadStr(buf1,IDS_PROXY_PASSWORD);
if (passphrase[0]==0)
RequestProc(PluginNumber,RT_Password,title,buf1,passphrase,sizeof(passphrase)-1);
strlcpy(buf1,ConnectSettings->proxyuser,sizeof(buf1)-1);
strlcat(buf1,":",sizeof(buf1)-1);
strlcat(buf1,passphrase,sizeof(buf1)-1);
strlcat(buf,"Proxy-Authorization: Basic ",sizeof(buf2)-1);
MimeEncode(buf1,buf2,sizeof(buf2)-1);
strlcat(buf,buf2,sizeof(buf)-1);
strlcat(buf,"\r\n",sizeof(buf)-1);
}
strlcat(buf,"\r\n",sizeof(buf)-1);
mysend(ConnectSettings->sock,buf,(int)strlen(buf),0,progressbuf,20,&loop,&lasttime);
// Response;
// HTTP/1.0 200 Connection established
// Proxy-agent: WinProxy/1.5.3<2xCRLF>
lastcrlfcrlf=false;
nrbytes=myrecv(ConnectSettings->sock,buf,12,0,progressbuf,20,&loop,&lasttime);
if (nrbytes==12 && buf[9]=='2') { // proxy signals success!!
// read data until we get 2xCRLF
bool lastcrlf=false;
bool lastcr=false;
while (1) {
nrbytes=myrecv(ConnectSettings->sock,buf,1,0,progressbuf,20,&loop,&lasttime);
if (nrbytes<=0)
break;
if (buf[0]=='\r')
lastcr=true;
else if (buf[0]=='\n') {
if (lastcr) {
if (lastcrlf) {
lastcrlfcrlf=true;
break;
} else
lastcrlf=true;
} else
lastcrlf=false;
} else {
lastcr=false;
lastcrlf=false;
}
}
}
if (!lastcrlfcrlf) {
ShowErrorId(IDS_VIA_PROXY_CONNECT);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
break;
case 3: // SOCKS4/4A
if (ProgressProc(PluginNumber,progressbuf,"-",20)) {
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
ZeroMemory(buf, sizeof(buf));
buf[0]=4; //version
buf[1]=1; //TCP connect
*((unsigned short *)&buf[2])=htons(ConnectSettings->customport);
// numerical IPv4 given?
hostaddr = inet_addr(ConnectSettings->server);
if (hostaddr==INADDR_NONE)
*((unsigned long *)&buf[4])=htonl(0x00000001);
else
*((unsigned long *)&buf[4])=hostaddr; // it's already in network order!
nrbytes=8;
strlcpy(&buf[nrbytes], ConnectSettings->proxyuser, sizeof(buf)-nrbytes-1);
nrbytes+=(int)strlen(ConnectSettings->proxyuser)+1;
if (hostaddr==INADDR_NONE) { // SOCKS4A
strlcpy(&buf[nrbytes], ConnectSettings->server, sizeof(buf)-nrbytes-1);
nrbytes+=(int)strlen(ConnectSettings->server)+1;
}
//
mysend(ConnectSettings->sock,buf,nrbytes,0,progressbuf,20,&loop,&lasttime);
nrbytes=myrecv(ConnectSettings->sock,buf,8,0,progressbuf,20,&loop,&lasttime);
if (nrbytes!=8 || buf[0]!=0 || buf[1]!=0x5a) {
ShowErrorId(IDS_VIA_PROXY_CONNECT);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
break;
case 4: // SOCKS5
if (ProgressProc(PluginNumber,progressbuf,"-",20)) {
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
ZeroMemory(buf, sizeof(buf));
buf[0]=5; // version
buf[2]=0; // no auth
nrbytes=3;
if (ConnectSettings->proxyuser[0]) {
buf[3]=2; // user/pass auth
nrbytes++;
}
buf[1]=nrbytes-2; // nr. of methods
//
mysend(ConnectSettings->sock,buf,nrbytes,0,progressbuf,20,&loop,&lasttime);
nrbytes=myrecv(ConnectSettings->sock,buf,2,0,progressbuf,20,&loop,&lasttime);
if(!ConnectSettings->proxyuser[0] && buf[1]!=0) {
*((unsigned char *)&buf[1])=0xff;
}
if(nrbytes!=2 || buf[0]!=5 || buf[1]==0xff) {
ShowErrorId(IDS_VIA_PROXY_CONNECT);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
//
if(buf[1]==2) { // user/pass auth
int len;
ZeroMemory(buf, sizeof(buf));
buf[0]=1; // version
len=(int)strlen(ConnectSettings->proxyuser);
buf[1]=len;
strlcpy(&buf[2], ConnectSettings->proxyuser, sizeof(buf)-3);
nrbytes=len+2;
len=(int)strlen(ConnectSettings->proxypassword);
buf[nrbytes]=len;
strlcpy(&buf[nrbytes+1], ConnectSettings->proxypassword, sizeof(buf)-nrbytes-1);
nrbytes+=len+1;
//
mysend(ConnectSettings->sock,buf,nrbytes,0,progressbuf,20,&loop,&lasttime);
nrbytes=myrecv(ConnectSettings->sock,buf,2,0,progressbuf,20,&loop,&lasttime);
if(nrbytes!=2 || buf[1]!=0) {
LoadStr(buf,IDS_SOCKS5PROXYERR);
ShowError(buf);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
}
//
ZeroMemory(buf, sizeof(buf));
buf[0]=5; // version
buf[1]=1; // TCP connect
buf[2]=0; // reserved
hostaddr = inet_addr(ConnectSettings->server);
if (hostaddr!=INADDR_NONE) {
buf[3]=1; // addrtype (IPv4)
*((unsigned long *)&buf[4])=hostaddr; // it's already in network order!
nrbytes=4+4;
} else {
BOOL numipv6=false; // is it an IPv6 numeric address?
if (getaddrinfo && IsNumericIPv6(ConnectSettings->server)) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
#ifdef sprintf_s
sprintf_s(buf,sizeof(buf), "%d", connecttoport);
#else
sprintf(buf,"%d", connecttoport);
#endif
if (getaddrinfo(ConnectSettings->server, buf, &hints, &res)==0 &&
res->ai_addrlen>=sizeof(sockaddr_in6)) {
numipv6=true;
buf[3]=4; // IPv6
memcpy(&buf[4],((psockaddr_in6)(res->ai_addr))->sin6_addr,16);
nrbytes=4+16;
}
}
if (!numipv6) {
buf[3]=3; // addrtype (domainname)
buf[4]=(char)strlen(ConnectSettings->server);
strlcpy(&buf[5], ConnectSettings->server, sizeof(buf)-6);
nrbytes=(unsigned char)buf[4]+5;
}
}
*((unsigned short *)&buf[nrbytes])=htons(ConnectSettings->customport);
nrbytes+=2;
//
mysend(ConnectSettings->sock,buf,nrbytes,0,progressbuf,20,&loop,&lasttime);
nrbytes=myrecv(ConnectSettings->sock,buf,4,0,progressbuf,20,&loop,&lasttime);
if(nrbytes!=4 || buf[0]!=5 || buf[1]!=0) {
//ShowErrorId(IDS_VIA_PROXY_CONNECT);
switch(buf[1]) {
case 1: LoadStr(buf,IDS_GENERALSOCKSFAILURE); break;
case 2: LoadStr(buf,IDS_CONNNOTALLOWED); break;
case 3: LoadStr(buf,IDS_NETUNREACHABLE); break;
case 4: LoadStr(buf,IDS_HOSTUNREACHABLE); break;
case 5: LoadStr(buf,IDS_CONNREFUSED); break;
case 6: LoadStr(buf,IDS_TTLEXPIRED); break;
case 7: LoadStr(buf,IDS_CMDNOTSUPPORTED); break;
case 8: LoadStr(buf,IDS_ADDRTYPENOTSUPPORTED); break;
default:
{
char buf2[MAX_PATH];
LoadStr(buf2,IDS_UNKNOWNSOCKERR);
#ifdef sprintf_s
sprintf_s(buf,sizeof(buf),buf2, buf[1]);
#else
sprintf(buf, buf2, buf[1]);
#endif
}
}
ShowError(buf);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
int needread=0;
switch(buf[3]) {
case 1: needread=6; break; // IPv4+port
case 3:
nrbytes=myrecv(ConnectSettings->sock,buf,1,0,progressbuf,20,&loop,&lasttime);
if (nrbytes==1)
needread=buf[0]+2;
break; // Domain Name+port
case 4: needread=18; break; // IPv6+port
}
nrbytes=myrecv(ConnectSettings->sock,buf,needread,0,progressbuf,20,&loop,&lasttime);
if(nrbytes!=needread) {
ShowErrorId(IDS_VIA_PROXY_CONNECT);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
break;
}
LoadStr(buf,IDS_INITSSH2);
if (ProgressProc(PluginNumber,buf,"-",30)) {
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
ConnectSettings->session = libssh2_session_init_ex(myalloc,myfree,myrealloc,ConnectSettings);
if(!ConnectSettings->session) {
ShowErrorId(IDS_ERR_INIT_SSH2);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
/* Since we have set non-blocking, tell libssh2 we are non-blocking */
libssh2_session_set_blocking(ConnectSettings->session, 0);
// Set ZLIB compression on/off
// Always allow "none" for the case that the server doesn't support compression
loop=30;
LoadStr(buf,IDS_SET_COMPRESSION);
while (libssh2_session_method_pref(ConnectSettings->session,LIBSSH2_METHOD_COMP_CS,ConnectSettings->compressed ? "zlib,none" : "none")== LIBSSH2_ERROR_EAGAIN) {
if (ProgressLoop(buf,30,40,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
while (libssh2_session_method_pref(ConnectSettings->session,LIBSSH2_METHOD_COMP_SC,ConnectSettings->compressed ? "zlib,none" : "none")== LIBSSH2_ERROR_EAGAIN) {
if (ProgressLoop(buf,30,40,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
/* ... start it up. This will trade welcome banners, exchange keys,
* and setup crypto, compression, and MAC layers
*/
LoadStr(buf,IDS_SESSION_STARTUP);
while ((auth = libssh2_session_startup(ConnectSettings->session, (int)ConnectSettings->sock)) == LIBSSH2_ERROR_EAGAIN) {
if (ProgressLoop(buf,40,60,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
if(auth) {
LoadStr(buf,IDS_ERR_SSH_SESSION);
char* errmsg;
int errmsg_len;
libssh2_session_last_error(ConnectSettings->session, &errmsg, &errmsg_len, false);
strlcat(buf,errmsg,sizeof(buf)-1);
ShowError(buf);
libssh2_session_free(ConnectSettings->session);
ConnectSettings->session=NULL;
Sleep(1000);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
LoadStr(buf,IDS_SSH_LOGIN);
if (ProgressProc(PluginNumber,buf,"-",60)) {
libssh2_session_free(ConnectSettings->session);
ConnectSettings->session=NULL;
Sleep(1000);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
const char *fingerprint=libssh2_hostkey_hash(ConnectSettings->session, LIBSSH2_HOSTKEY_HASH_MD5);
LoadStr(buf,IDS_SERVER_FINGERPRINT);
ShowStatus(buf);
buf[0]=0;
for(int i = 0; i < 16; i++) {
char buf1[20];
#ifdef sprintf_s
sprintf_s(buf1,sizeof(buf1),"%02X", (unsigned char)fingerprint[i]);
#else
sprintf(buf1,"%02X", (unsigned char)fingerprint[i]);
#endif
strlcat(buf,buf1,sizeof(buf)-1);
if (i<15)
strlcat(buf," ",sizeof(buf)-1);
}
ShowStatus(buf);
// Verify server
if (ConnectSettings->savedfingerprint[0]==0 || strcmp(ConnectSettings->savedfingerprint,buf)!=0) { // a new server, or changed fingerprint
char buf1[4*MAX_PATH];
char buf2[MAX_PATH];
if (ConnectSettings->savedfingerprint[0]==0)
LoadStr(buf1,IDS_CONNECTION_FIRSTTIME);
else
LoadStr(buf1,IDS_FINGERPRINT_CHANGED);
LoadStr(buf2,IDS_FINGERPRINT);
strlcat(buf1,buf2,sizeof(buf1)-1);
strlcat(buf1,buf,sizeof(buf1)-1);
LoadStr(buf2,IDS_CONNECTING);
if (!RequestProc(PluginNumber,RT_MsgYesNo,buf2,buf1,NULL,0)) {
libssh2_session_free(ConnectSettings->session);
ConnectSettings->session=NULL;
Sleep(1000);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
// Store it, also for quick connections!
WritePrivateProfileString(ConnectSettings->DisplayName,"fingerprint",buf,ConnectSettings->IniFileName);
strlcpy(ConnectSettings->savedfingerprint,buf,sizeof(ConnectSettings->savedfingerprint)-1);
}
// Ask for user name if none was entered
if (ConnectSettings->user[0]==0) {
char title[250];
LoadStr(title,IDS_USERNAME_FOR);
strlcat(title,ConnectSettings->server,sizeof(title)-1);
if (!RequestProc(PluginNumber,RT_UserName,title,NULL,ConnectSettings->user,sizeof(ConnectSettings->user)-1)) {
libssh2_session_free(ConnectSettings->session);
ConnectSettings->session=NULL;
Sleep(1000);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return -1;
}
}
char* userauthlist;
do {
userauthlist = libssh2_userauth_list(ConnectSettings->session,
ConnectSettings->user,(unsigned int)strlen(ConnectSettings->user));
LoadStr(buf,IDS_USER_AUTH_LIST);
if (ProgressLoop(buf,60,70,&loop,&lasttime))
break;
} while (userauthlist==NULL && libssh2_session_last_errno(ConnectSettings->session) ==
LIBSSH2_ERROR_EAGAIN);
int auth_pw=0;
if (userauthlist) {
LoadStr(buf,IDS_SUPPORTED_AUTH_METHODS);
strlcat(buf,userauthlist,sizeof(buf)-1);
ShowStatus(buf);
#ifdef _strlwr_s
_strlwr_s(userauthlist,strlen(userauthlist)+1);
#else
_strlwr(userauthlist);
#endif
if (strstr(userauthlist, "password") != NULL) {
auth_pw |= 1;
}
if (strstr(userauthlist, "keyboard-interactive") != NULL) {
auth_pw |= 2;
}
if (strstr(userauthlist, "publickey") != NULL) {
auth_pw |= 4;
}
} else
auth_pw=5; // assume password+pubkey allowed
auth=0;
if(libssh2_userauth_authenticated(ConnectSettings->session)) {
ShowStatus("User authenticated without password.");
} else if (auth_pw & 4 && ConnectSettings->useagent && loadAgent) {
struct libssh2_agent_publickey *identity, *prev_identity = NULL;
LIBSSH2_AGENT *agent = libssh2_agent_init(ConnectSettings->session);
BOOL connected=true;
if (!agent || libssh2_agent_connect(agent) != 0) {
// Try to launch Pageant!
char linkname[MAX_PATH],dirname[MAX_PATH];
connected=false;
dirname[0]=0;
GetModuleFileName(hinst,dirname,sizeof(dirname)-10);
char* p=strrchr(dirname,'\\');
if (p)
p++;
else
p=dirname;
p[0]=0;
strlcpy(linkname,dirname,MAX_PATH-1);
strlcat(linkname,"pageant.lnk",MAX_PATH-1);
if (GetFileAttributes(linkname)!=0xFFFFFFFF) {
HWND active=GetForegroundWindow();
ShellExecute(active,NULL,linkname,NULL,dirname,SW_SHOW);
Sleep(2000);
DWORD starttime=GetCurrentTime();
while (active!=GetForegroundWindow() && abs(GetCurrentTime()-starttime)<20000) {
Sleep(200);
if (ProgressLoop(buf,65,70,&loop,&lasttime))
break;
}
agent = libssh2_agent_init(ConnectSettings->session);
if (agent && libssh2_agent_connect(agent) == 0)
connected=true;
}
if (!connected) {
LoadStr(buf,IDS_AGENT_CONNECTERROR);
ShowError(buf);
auth = -1;
}
}
if (connected) {
if (libssh2_agent_list_identities(agent)) {
LoadStr(buf,IDS_AGENT_REQUESTIDENTITIES);
ShowError(buf);
auth = -1;
} else {
while (1) {
auth = libssh2_agent_get_identity(agent, &identity, prev_identity);
if (auth == 1) {
LoadStr(buf,IDS_AGENT_AUTHFAILED);
ShowError(buf);
break;
}
if (auth < 0) {
LoadStr(buf,IDS_AGENT_NOIDENTITY);
ShowError(buf);
break;
}
char buf1[128];
LoadStr(buf1,IDS_AGENT_TRYING1);
strlcpy(buf, buf1, sizeof(buf)-1);
strlcat(buf, ConnectSettings->user, sizeof(buf)-1);
LoadStr(buf1,IDS_AGENT_TRYING2);
strlcat(buf, buf1, sizeof(buf)-1);
strlcat(buf, identity->comment, sizeof(buf)-1);
LoadStr(buf1,IDS_AGENT_TRYING3);
strlcat(buf, buf1, sizeof(buf)-1);
ShowStatus(buf);
while ((auth = libssh2_agent_userauth(agent, ConnectSettings->user, identity)) == LIBSSH2_ERROR_EAGAIN);
if (auth) {
LoadStr(buf,IDS_AGENT_AUTHFAILED);
ShowStatus(buf);
} else {
LoadStr(buf,IDS_AGENT_AUTHSUCCEEDED);
ShowStatus(buf);
break;
}
prev_identity = identity;
}
}
}
libssh2_agent_disconnect(agent);
libssh2_agent_free(agent);
} else if (auth_pw & 4 && ConnectSettings->pubkeyfile[0] && ConnectSettings->privkeyfile[0]) {
BOOL pubkeybad=false;
char filebuf[1024];
char passphrase[256];
char pubkeyfile[MAX_PATH],privkeyfile[MAX_PATH];
strlcpy(pubkeyfile,ConnectSettings->pubkeyfile,sizeof(pubkeyfile)-1);
ReplaceSubString(pubkeyfile,"%USER%",ConnectSettings->user,sizeof(pubkeyfile)-1);
ReplaceEnvVars(pubkeyfile,sizeof(pubkeyfile)-1);
strlcpy(privkeyfile,ConnectSettings->privkeyfile,sizeof(privkeyfile)-1);
ReplaceSubString(privkeyfile,"%USER%",ConnectSettings->user,sizeof(privkeyfile)-1);
ReplaceEnvVars(privkeyfile,sizeof(privkeyfile)-1);
passphrase[0]=0;
// verify that we have a valid public key file
HANDLE hf=CreateFile(pubkeyfile,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hf==INVALID_HANDLE_VALUE) {
LoadStr(buf,IDS_ERR_LOAD_PUBKEY);
strlcat(buf,pubkeyfile,sizeof(buf)-1);
ShowError(buf);
auth=LIBSSH2_ERROR_FILE;
pubkeybad=true;
} else {
DWORD dataread=0;
if (ReadFile(hf,&filebuf,10,&dataread,NULL)) {
if (_strnicmp(filebuf,"ssh-",4)!=0) {
LoadStr(buf,IDS_ERR_PUBKEY_WRONG_FORMAT);
ShowError(buf);
auth=LIBSSH2_ERROR_FILE;
pubkeybad=true;
}
}
CloseHandle(hf);
}
if (!pubkeybad) {
// do not ask for the pass phrase if the key isn't encrypted!
HANDLE hf=CreateFile(privkeyfile,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (hf==INVALID_HANDLE_VALUE) {
LoadStr(buf,IDS_ERR_LOAD_PRIVKEY);
strlcat(buf,privkeyfile,sizeof(buf)-1);
ShowError(buf);
auth=LIBSSH2_ERROR_FILE;
} else {
DWORD dataread=0;
BOOL isencrypted=true;
if (ReadFile(hf,&filebuf,sizeof(filebuf)-32,&dataread,NULL)) {
filebuf[dataread]=0;
p=strchr(filebuf,'\n');
if (!p)
p=strchr(filebuf,'\r');
if (p) {
p++;
while (p[0]=='\r' || p[0]=='\n')
p++;
isencrypted=false;
// if there is something else than just MIME-encoded data,
// then the key is encrypted -> we need a pass phrase
for (int i=0;i<32;i++)
if (!ismimechar(p[i]))
isencrypted=true;
}
}
CloseHandle(hf);
if (isencrypted) {
char title[250];
LoadStr(buf,IDS_PASSPHRASE);
strlcpy(title,buf,sizeof(title)-1);
strlcat(title,ConnectSettings->user,sizeof(title)-1);
strlcat(title,"@",sizeof(title)-1);
strlcat(title,ConnectSettings->server,sizeof(title)-1);
LoadStr(buf,IDS_KEYPASSPHRASE);
if (ConnectSettings->password[0]!=0)
strlcpy(passphrase,ConnectSettings->password,sizeof(passphrase)-1);
else
RequestProc(PluginNumber,RT_Password,title,buf,passphrase,sizeof(passphrase)-1);
}
LoadStr(buf,IDS_AUTH_PUBKEY_FOR);
strlcpy(buf,"Auth via public key for user: ",sizeof(buf)-1);
strlcat(buf,ConnectSettings->user,sizeof(buf)-1);
ShowStatus(buf);
LoadStr(buf,IDS_AUTH_PUBKEY);
while ((auth = libssh2_userauth_publickey_fromfile(ConnectSettings->session,
ConnectSettings->user,
pubkeyfile,
privkeyfile,
passphrase)) == LIBSSH2_ERROR_EAGAIN) {
if (ProgressLoop(buf,60,70,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
if (auth)
ShowErrorId(IDS_ERR_AUTH_PUBKEY);
else if (!ConnectSettings->password[0])
strlcpy(ConnectSettings->password,passphrase,sizeof(ConnectSettings->password)-1);
}
}
} else {
if (auth_pw & 1) {
char passphrase[256];
strlcpy(passphrase,ConnectSettings->password,sizeof(passphrase)-1);
if (passphrase[0]==0) {
char title[250];
strlcpy(title,"SFTP password for ",sizeof(title)-1);
strlcat(title,ConnectSettings->user,sizeof(title)-1);
strlcat(title,"@",sizeof(title)-1);
strlcat(title,ConnectSettings->server,sizeof(title)-1);
RequestProc(PluginNumber,RT_Password,title,NULL,passphrase,sizeof(passphrase)-1);
}
LoadStr(buf,IDS_AUTH_PASSWORD_FOR);
strlcat(buf,ConnectSettings->user,sizeof(buf)-1);
ShowStatus(buf);
LoadStr(buf,IDS_AUTH_PASSWORD);
/* We could authenticate via password */
while(1) {
auth=libssh2_userauth_password_ex(ConnectSettings->session,ConnectSettings->user,strlen(ConnectSettings->user),passphrase,strlen(passphrase),&newpassfunc);
if (auth!=LIBSSH2_ERROR_EAGAIN && auth!=LIBSSH2_ERROR_PASSWORD_EXPIRED)
break;
if (ProgressLoop(buf,70,80,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
void* abst=ConnectSettings;
if (auth)
ShowErrorId(IDS_ERR_AUTH_PASSWORD);
else if (!ConnectSettings->password[0])
strlcpy(ConnectSettings->password,passphrase,sizeof(ConnectSettings->password)-1);
} else
auth=LIBSSH2_ERROR_INVAL;
if (auth && auth_pw & 2) { // keyboard-interactive
LoadStr(buf,IDS_AUTH_KEYBDINT_FOR);
strlcat(buf,ConnectSettings->user,sizeof(buf)-1);
ShowStatus(buf);
LoadStr(buf,IDS_AUTH_KEYBDINT);
ConnectSettings->InteractivePasswordSent=false;
while ((auth=libssh2_userauth_keyboard_interactive(ConnectSettings->session,ConnectSettings->user,&kbd_callback))==
LIBSSH2_ERROR_EAGAIN) {
if (ProgressLoop(buf,70,80,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
if (auth)
ShowErrorId(IDS_ERR_AUTH_KEYBDINT);
}
}
if(auth){
libssh2_session_disconnect(ConnectSettings->session, "Shutdown");
libssh2_session_free(ConnectSettings->session);
ConnectSettings->session=NULL;
Sleep(1000);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return SFTP_FAILED;
}
/*char* banner=_ssh_get_issue_banner(ConnectSettings->session);
if(banner){
ShowStatus(banner);
free(banner);
}*/
// try to auto-detect UTF-8 settings
if (ConnectSettings->utf8names==-1) {
ConnectSettings->utf8names=0;
ConnectSettings->codepage=0;
char cmdname[MAX_PATH];
char reply[8192];
strlcpy(cmdname,"echo $LC_ALL $LC_CTYPE $LANG",sizeof(cmdname)-1);
reply[0]=0;
if (SftpQuoteCommand2(ConnectSettings,NULL,cmdname,reply,sizeof(reply)-1)==0) {
#ifdef _strupr_s
_strupr_s(reply,sizeof(reply));
#else
_strupr(reply);
#endif
if (strstr(reply, "UTF-8"))
ConnectSettings->utf8names=1;
else {
strlcpy(cmdname,"locale",sizeof(cmdname)-1);
if (SftpQuoteCommand2(ConnectSettings,NULL,cmdname,reply,sizeof(reply)-1)==0) {
#ifdef _strupr_s
_strupr_s(reply,sizeof(reply));
#else
_strupr(reply);
#endif
if (strstr(reply, "UTF-8"))
ConnectSettings->utf8names=1;
}
}
}
// store the result!
if (strcmp(ConnectSettings->DisplayName,s_quickconnect)!=0)
WritePrivateProfileString(ConnectSettings->DisplayName,"utf8",ConnectSettings->utf8names ? "1" : "0",ConnectSettings->IniFileName);
}
if (ConnectSettings->unixlinebreaks==-1) {
ConnectSettings->unixlinebreaks=0;
char cmdname[MAX_PATH];
char reply[8192];
strlcpy(cmdname,"echo $OSTYPE",sizeof(cmdname)-1);
reply[0]=0;
if (SftpQuoteCommand2(ConnectSettings,NULL,cmdname,reply,sizeof(reply)-1)==0) {
#ifdef _strupr_s
_strupr_s(reply,sizeof(reply));
#else
_strupr(reply);
#endif
if (strstr(reply, "LINUX") || strstr(reply, "UNIX") || strstr(reply, "AIX"))
ConnectSettings->unixlinebreaks=1;
else { // look whether the returned data ends with LF or CRLF!
global_detectcrlf=-1;
strlcpy(cmdname,"ls -l",sizeof(cmdname)-1); // try to get some multi-line reply
if (SftpQuoteCommand2(ConnectSettings,NULL,cmdname,reply,sizeof(reply)-1)==0) {
if (global_detectcrlf==0)
ConnectSettings->unixlinebreaks=1;
}
}
}
// store the result!
if (strcmp(ConnectSettings->DisplayName,s_quickconnect)!=0)
WritePrivateProfileString(ConnectSettings->DisplayName,"unixlinebreaks",ConnectSettings->unixlinebreaks ? "1" : "0",ConnectSettings->IniFileName);
}
ConnectSettings->sftpsession=NULL;
if (!ConnectSettings->scponly) {
do {
ConnectSettings->sftpsession=NULL;
if (ProgressLoop(buf,80,90,&loop,&lasttime))
break;
ConnectSettings->sftpsession=libssh2_sftp_init(ConnectSettings->session);
if ((!ConnectSettings->sftpsession) && (libssh2_session_last_errno(ConnectSettings->session) !=
LIBSSH2_ERROR_EAGAIN)) {
break;
}
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (!ConnectSettings->sftpsession);
if(!ConnectSettings->sftpsession){
LoadStr(buf,IDS_ERR_INIT_SFTP);
char* errmsg;
int errmsg_len,rc;
libssh2_session_last_error(ConnectSettings->session, &errmsg, &errmsg_len, false);
strlcat(buf,errmsg,sizeof(buf)-1);
ShowError(buf);
LoadStr(buf,IDS_DISCONNECTING);
do {
rc=libssh2_session_disconnect(ConnectSettings->session, "Shutdown");
if (ProgressLoop(buf,80,90,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
libssh2_session_free(ConnectSettings->session);
ConnectSettings->session=NULL;
Sleep(1000);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return SFTP_FAILED;
}
// Seems that we need to set it again, so the sftpsession is informed too!
// Otherwise disconnect hangs with CoreFTP mini-sftp-server in libssh2_sftp_shutdown
libssh2_session_set_blocking(ConnectSettings->session,0);
}
LoadStr(buf,IDS_GET_DIRECTORY);
if (ProgressProc(PluginNumber,buf,"-",90)) {
LoadStr(buf,IDS_DISCONNECTING);
int rc;
if (ConnectSettings->sftpsession) {
do {
rc=libssh2_sftp_shutdown(ConnectSettings->sftpsession);
if (ProgressLoop(buf,80,100,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
ConnectSettings->sftpsession=NULL;
}
do {
rc=libssh2_session_disconnect(ConnectSettings->session, "Shutdown");
if (ProgressLoop(buf,80,100,&loop,&lasttime))
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
libssh2_session_free(ConnectSettings->session);
ConnectSettings->session=NULL;
Sleep(1000);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=0;
return SFTP_FAILED;
}
}
if (ConnectSettings->scponly) {
if (!ConnectSettings->session)
return SFTP_FAILED;
else
return SFTP_OK;
} else if (!ConnectSettings->sftpsession) {
return SFTP_FAILED;
} else
return SFTP_OK;
}
LPCTSTR g_pszKey = TEXT("unpzScGeCInX7XcRM2z+svTK+gegRLhz9KXVbYKJl5boSvVCcfym");
void EncryptString(LPCTSTR pszPlain, LPTSTR pszEncrypted, UINT cchEncrypted)
{
int iPlainLength = lstrlen(pszPlain);
int iKeyLength = lstrlen(g_pszKey);
int iPos = lstrlen(pszPlain) % iKeyLength;
pszEncrypted[0] = '\0';
for (int iChar = 0; iChar < iPlainLength; iChar++)
{
#ifdef sprintf_s
sprintf_s(pszEncrypted, cchEncrypted, ("%s%03d"), pszEncrypted, (unsigned char)pszPlain[iChar] ^ (unsigned char)g_pszKey[(iChar + iPos) % iKeyLength]);
#else
sprintf(pszEncrypted, ("%s%03d"), pszEncrypted, (unsigned char)pszPlain[iChar] ^ (unsigned char)g_pszKey[(iChar + iPos) % iKeyLength]);
#endif
}
}
void DecryptString(LPCTSTR pszEncrypted, LPTSTR pszPlain, UINT cchPlain)
{
if (strcmp(pszEncrypted,"!")==0) { // signal password-protected password
if (CryptProc)
strlcpy(pszPlain,"\001",cchPlain-1);
else
pszPlain[0]=0;
return;
}
int iKeyLength = lstrlen(g_pszKey);
int iEncryptedLength = lstrlen(pszEncrypted);
int iPos = (iEncryptedLength/3) % iKeyLength;
int iChar;
pszPlain[0] = ('\0');
for (iChar = 0; iChar < iEncryptedLength / 3 && iChar < (int) (cchPlain - 1); iChar++)
{
int iDigit = pszEncrypted[iChar * 3];
if (iDigit < '0' || iDigit > '9')
{
pszPlain[0] = ('\0');
return;
}
int iNumber = (iDigit - '0') * 100;
iDigit = pszEncrypted[iChar * 3 + 1];
if (iDigit < '0' || iDigit > '9')
{
pszPlain[0] = ('\0');
return;
}
iNumber += (iDigit - '0') * 10;
iDigit = pszEncrypted[iChar * 3 + 2];
if (iDigit < '0' || iDigit > '9')
{
pszPlain[0] = ('\0');
return;
}
iNumber += iDigit - '0';
pszPlain[iChar] = (iNumber ^ g_pszKey[(iChar + iPos) % iKeyLength]);
}
pszPlain[iChar] = ('\0');
}
void SftpGetServerBasePathW(WCHAR* DisplayName,WCHAR* RelativePath,int maxlen,char* inifilename)
{
char DisplayNameA[MAX_PATH],server[MAX_PATH];
walcopy(DisplayNameA,DisplayName,sizeof(DisplayNameA)-1);
GetPrivateProfileString(DisplayNameA,"server","",server,sizeof(server)-1,inifilename);
ReplaceBackslashBySlash(server);
// Remove trailing sftp://
if (_strnicmp(server,"sftp://",7)==0)
memmove(server,server+7,strlen(server)-6);
ReplaceBackslashBySlash(server);
char* p=strchr(server,'/');
if (p)
awlcopy(RelativePath,p,maxlen);
else
wcslcpy(RelativePath,L"/",maxlen);
}
BOOL LoadProxySettingsFromNr(int proxynr,pConnectSettings ConnectResults)
{
if (proxynr>0) {
TCHAR proxyentry[64];
if (proxynr>1)
#ifdef sprintf_s
sprintf_s(proxyentry,sizeof(proxyentry),"proxy%d",proxynr);
#else
sprintf(proxyentry,"proxy%d",proxynr);
#endif
else
strlcpy(proxyentry,"proxy",sizeof(proxyentry)-1);
int type=GetPrivateProfileInt(proxyentry,"proxytype",-1,gIniFileName);
if (type==-1)
ConnectResults->proxytype=0;
else
ConnectResults->proxytype=type;
GetPrivateProfileString(proxyentry,"proxyserver","",ConnectResults->proxyserver,sizeof(ConnectResults->proxyuser)-1,gIniFileName);
GetPrivateProfileString(proxyentry,"proxyuser","",ConnectResults->proxyuser,sizeof(ConnectResults->proxyuser)-1,gIniFileName);
char szPassword[MAX_PATH];
if (GetPrivateProfileString(proxyentry,"proxypassword","", szPassword, countof(szPassword), gIniFileName))
{
DecryptString(szPassword, ConnectResults->proxypassword,countof(ConnectResults->proxypassword));
} else
ConnectResults->proxypassword[0]=0;
return (type!=-1 || proxynr==1); //nr 1 is always valid
} else {
ConnectResults->proxytype=0;
ConnectResults->proxyserver[0]=0;
ConnectResults->proxyuser[0]=0;
ConnectResults->proxypassword[0]=0;
return false;
}
}
BOOL LoadServerSettings(char* DisplayName,pConnectSettings ConnectResults)
{
char szPassword[MAX_PATH],modbuf[6];
strlcpy(ConnectResults->DisplayName,DisplayName,sizeof(ConnectResults->DisplayName)-1);
strlcpy(ConnectResults->IniFileName,gIniFileName,sizeof(ConnectResults->IniFileName)-1);
GetPrivateProfileString(DisplayName,"server","",ConnectResults->server,sizeof(ConnectResults->server)-1,gIniFileName);
ConnectResults->protocoltype=GetPrivateProfileInt(DisplayName,"protocol",0,gIniFileName);
GetPrivateProfileString(DisplayName,"user","",ConnectResults->user,sizeof(ConnectResults->user)-1,gIniFileName);
GetPrivateProfileString(DisplayName,"fingerprint","",ConnectResults->savedfingerprint,sizeof(ConnectResults->savedfingerprint)-1,gIniFileName);
GetPrivateProfileString(DisplayName,"pubkeyfile","",ConnectResults->pubkeyfile,sizeof(ConnectResults->pubkeyfile)-1,gIniFileName);
GetPrivateProfileString(DisplayName,"privkeyfile","",ConnectResults->privkeyfile,sizeof(ConnectResults->privkeyfile)-1,gIniFileName);
ConnectResults->useagent=GetPrivateProfileInt(gDisplayName,"useagent",0,gIniFileName)!=0;
GetPrivateProfileString(DisplayName,"filemod","644",modbuf,sizeof(modbuf)-1,gIniFileName);
ConnectResults->filemod=strtol(modbuf,NULL,8);
GetPrivateProfileString(DisplayName,"dirmod","755",modbuf,sizeof(modbuf)-1,gIniFileName);
ConnectResults->dirmod=strtol(modbuf,NULL,8);
ConnectResults->compressed=GetPrivateProfileInt(gDisplayName,"compression",0,gIniFileName)!=0;
ConnectResults->scpfordata=GetPrivateProfileInt(gDisplayName,"scpfordata",0,gIniFileName)!=0;
ConnectResults->scponly=GetPrivateProfileInt(gDisplayName,"scponly",0,gIniFileName)!=0;
if (ConnectResults->scponly)
ConnectResults->scpfordata=true;
ConnectResults->trycustomlistcommand=2;
ConnectResults->detailedlog=GetPrivateProfileInt(gDisplayName,"detailedlog",0,gIniFileName)!=0;
ConnectResults->utf8names=GetPrivateProfileInt(gDisplayName,"utf8",-1,gIniFileName); // -1 means auto-detect
ConnectResults->codepage=GetPrivateProfileInt(gDisplayName,"codepage",0,gIniFileName); // -1 means local ANSI
ConnectResults->unixlinebreaks=GetPrivateProfileInt(gDisplayName,"unixlinebreaks",-1,gIniFileName); // -1 means auto-detect
ConnectResults->password[0]=0;
// we don't need a password when using Pageant!
if (GetPrivateProfileString(gDisplayName,"password","", szPassword, countof(szPassword), gIniFileName))
{
if (!ConnectResults->useagent)
DecryptString(szPassword, ConnectResults->password, countof(ConnectResults->password));
else if (strcmp(szPassword,"!")==0)
strlcpy(ConnectResults->password,"\001",sizeof(ConnectResults->password)-1);
}
ConnectResults->proxynr=GetPrivateProfileInt(gDisplayName,"proxynr",1,gIniFileName);
LoadProxySettingsFromNr(ConnectResults->proxynr,ConnectResults);
ConnectResults->neednewchannel=false;
return ConnectResults->server[0]!=0;
}
int codepagelist[]={-1,-2,0,1,2,1250,1251,1252,1253,1254,1255,1256,1257,1258,
936,950,932,949,874,437,850,20866,-3,-4};
void EnableControlsPageant(HWND hWnd,BOOL enable)
{
EnableWindow(GetDlgItem(hWnd,IDC_PASSWORD),enable);
EnableWindow(GetDlgItem(hWnd,IDC_EDITPASS),enable);
EnableWindow(GetDlgItem(hWnd,IDC_CRYPTPASS),enable);
EnableWindow(GetDlgItem(hWnd,IDC_CERTFRAME),enable);
EnableWindow(GetDlgItem(hWnd,IDC_STATICPUB),enable);
EnableWindow(GetDlgItem(hWnd,IDC_STATICPEM),enable);
EnableWindow(GetDlgItem(hWnd,IDC_PUBKEY),enable);
EnableWindow(GetDlgItem(hWnd,IDC_PRIVKEY),enable);
EnableWindow(GetDlgItem(hWnd,IDC_LOADPUBKEY),enable);
EnableWindow(GetDlgItem(hWnd,IDC_LOADPRIVKEY),enable);
}
int gProxyNr=0;
myint __stdcall ProxyDlgProc(HWND hWnd,unsigned int Message,WPARAM wParam,LPARAM lParam)
{
RECT rt1,rt2;
int w,h,DlgWidth,DlgHeight,NewPosX,NewPosY;
tConnectSettings ConnectData;
switch (Message) {
case WM_INITDIALOG: {
LoadProxySettingsFromNr(gProxyNr,&ConnectData);
switch (ConnectData.proxytype) {
case 2:g_focusset=IDC_OTHERPROXY;break;
case 3:g_focusset=IDC_SOCKS4APROXY;break;
case 4:g_focusset=IDC_SOCKS5PROXY;break;
default:
g_focusset=IDC_NOPROXY;
}
CheckRadioButton(hWnd,IDC_NOPROXY,IDC_SOCKS5PROXY,g_focusset);
EnableWindow(GetDlgItem(hWnd,IDC_PROXYSERVER),ConnectData.proxytype!=0);
EnableWindow(GetDlgItem(hWnd,IDC_PROXYUSERNAME),ConnectData.proxytype!=0);
EnableWindow(GetDlgItem(hWnd,IDC_PROXYPASSWORD),ConnectData.proxytype!=0);
SetDlgItemText(hWnd,IDC_PROXYSERVER,ConnectData.proxyserver);
SetDlgItemText(hWnd,IDC_PROXYUSERNAME,ConnectData.proxyuser);
if (strcmp(ConnectData.proxypassword,"\001")==0 && CryptProc) {
char proxyentry[64];
if (gProxyNr>1)
#ifdef sprintf_s
sprintf_s(proxyentry,sizeof(proxyentry),"proxy%d",gProxyNr);
#else
sprintf(proxyentry,"proxy%d",gProxyNr);
#endif
else
strlcpy(proxyentry,"proxy",sizeof(proxyentry)-1);
strlcat(proxyentry,"$$pass",sizeof(proxyentry)-1);
if (CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_LOAD_PASSWORD_NO_UI,proxyentry,ConnectData.proxypassword,countof(ConnectData.proxypassword)-1)==FS_FILE_OK) {
SetDlgItemText(hWnd,IDC_PROXYPASSWORD, ConnectData.proxypassword);
CheckDlgButton(hWnd,IDC_CRYPTPASS,BST_CHECKED);
} else {
ShowWindow(GetDlgItem(hWnd,IDC_PROXYPASSWORD),SW_HIDE);
ShowWindow(GetDlgItem(hWnd,IDC_CRYPTPASS),SW_HIDE);
ShowWindow(GetDlgItem(hWnd,IDC_EDITPASS),SW_SHOW);
}
} else {
SetDlgItemText(hWnd,IDC_PROXYPASSWORD, ConnectData.proxypassword);
if (!CryptProc)
EnableWindow(GetDlgItem(hWnd,IDC_CRYPTPASS),false);
else if (ConnectData.proxypassword[0]==0 && CryptCheckPass)
CheckDlgButton(hWnd,IDC_CRYPTPASS,BST_CHECKED);
}
// trying to center the About dialog
if (GetWindowRect(hWnd, &rt1) && GetWindowRect(GetParent(hWnd), &rt2)) {
w=rt2.right-rt2.left;
h=rt2.bottom-rt2.top;
DlgWidth = rt1.right - rt1.left;
DlgHeight = rt1.bottom - rt1.top ;
NewPosX =rt2.left + (w - DlgWidth)/2;
NewPosY =rt2.top + (h - DlgHeight)/2;
SetWindowPos(hWnd, 0, NewPosX, NewPosY,
0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
return 1;
}
case WM_SHOWWINDOW: {
if (g_focusset)
SetFocus(GetDlgItem(hWnd,g_focusset));
break;
}
case WM_COMMAND: {
switch(LOWORD(wParam)) {
case IDOK: {
if (IsDlgButtonChecked(hWnd,IDC_NOPROXY))
ConnectData.proxytype=0;
else if (IsDlgButtonChecked(hWnd,IDC_OTHERPROXY))
ConnectData.proxytype=2;
else if (IsDlgButtonChecked(hWnd,IDC_SOCKS4APROXY))
ConnectData.proxytype=3;
else if (IsDlgButtonChecked(hWnd,IDC_SOCKS5PROXY))
ConnectData.proxytype=4;
else
ConnectData.proxytype=0;
GetDlgItemText(hWnd,IDC_PROXYSERVER,ConnectData.proxyserver,sizeof(ConnectData.proxyserver)-1);
GetDlgItemText(hWnd,IDC_PROXYUSERNAME,ConnectData.proxyuser,sizeof(ConnectData.proxyuser)-1);
GetDlgItemText(hWnd,IDC_PROXYPASSWORD,ConnectData.proxypassword,sizeof(ConnectData.proxypassword)-1);
char proxyentry[64];
if (gProxyNr>1)
#ifdef sprintf_s
sprintf_s(proxyentry,sizeof(proxyentry),"proxy%d",gProxyNr);
#else
sprintf(proxyentry,"proxy%d",gProxyNr);
#endif
else
strlcpy(proxyentry,"proxy",sizeof(proxyentry)-1);
WritePrivateProfileString(proxyentry,"proxyserver",ConnectData.proxyserver,gIniFileName);
WritePrivateProfileString(proxyentry,"proxyuser",ConnectData.proxyuser,gIniFileName);
char buf[64];
_itoa_s(ConnectData.proxytype,buf,sizeof(buf),10);
WritePrivateProfileString(proxyentry,"proxytype",ConnectData.proxytype!=0 ? buf : NULL,gIniFileName);
char szEncryptedPassword[256];
if (!IsWindowVisible(GetDlgItem(hWnd,IDC_EDITPASS))) { //button not visible
if (ConnectData.proxypassword[0]==0) {
WritePrivateProfileString(proxyentry,"proxypassword",NULL,gIniFileName);
} else if (CryptProc && IsDlgButtonChecked(hWnd,IDC_CRYPTPASS)) {
char proxyentry2[64];
strlcpy(proxyentry2,proxyentry,sizeof(proxyentry2)-1);
strlcat(proxyentry2,"$$pass",sizeof(proxyentry2)-1);
BOOL ok=CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_SAVE_PASSWORD,proxyentry2,ConnectData.proxypassword,0)==FS_FILE_OK;
WritePrivateProfileString(proxyentry,"proxypassword",ok? "!" : NULL,gIniFileName);
CryptCheckPass=true;
} else {
EncryptString(ConnectData.proxypassword, szEncryptedPassword, countof(szEncryptedPassword));
WritePrivateProfileString(proxyentry,"proxypassword",szEncryptedPassword,gIniFileName);
}
}
EndDialog(hWnd, IDOK);
return 1;
}
case IDCANCEL:
{
EndDialog(hWnd, IDCANCEL);
return 1;
}
case IDC_OTHERPROXY:
case IDC_SOCKS4APROXY:
case IDC_SOCKS5PROXY:
EnableWindow(GetDlgItem(hWnd,IDC_PROXYSERVER),true);
EnableWindow(GetDlgItem(hWnd,IDC_PROXYUSERNAME),true);
EnableWindow(GetDlgItem(hWnd,IDC_PROXYPASSWORD),true);
SetFocus(GetDlgItem(hWnd, IDC_PROXYSERVER));
break;
case IDC_NOPROXY:
EnableWindow(GetDlgItem(hWnd,IDC_PROXYSERVER),false);
EnableWindow(GetDlgItem(hWnd,IDC_PROXYUSERNAME),false);
EnableWindow(GetDlgItem(hWnd,IDC_PROXYPASSWORD),false);
break;
case IDC_PROXYHELP:
{
TCHAR szCaption[100]; LoadString(hinst, IDS_HELP_CAPTION, szCaption, countof(szCaption));
TCHAR szBuffer[1024]; LoadString(hinst, IDS_HELP_PROXY, szBuffer, countof(szBuffer));
MessageBox(hWnd, szBuffer, szCaption, MB_OK | MB_ICONINFORMATION);
break;
}
case IDC_EDITPASS:
{
BOOL doshow=true;
int err;
TCHAR proxyentry[64];
if (gProxyNr>1)
#ifdef sprintf_s
sprintf_s(proxyentry,sizeof(proxyentry),"proxy%d",gProxyNr);
#else
sprintf(proxyentry,"proxy%d",gProxyNr);
#endif
else
strlcpy(proxyentry,"proxy",sizeof(proxyentry)-1);
strlcat(proxyentry,"$$pass",sizeof(proxyentry)-1);
err=CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_LOAD_PASSWORD,proxyentry,ConnectData.proxypassword,countof(ConnectData.proxypassword)-1);
if (err==FS_FILE_OK) {
SetDlgItemText(hWnd,IDC_PROXYPASSWORD, ConnectData.proxypassword);
} else if (err=FS_FILE_READERROR) { // no password stored!
SetDlgItemText(hWnd,IDC_PROXYPASSWORD, "");
} else {
doshow=false;
}
if (doshow) {
ShowWindow(GetDlgItem(hWnd,IDC_PROXYPASSWORD),SW_SHOW);
ShowWindow(GetDlgItem(hWnd,IDC_CRYPTPASS),SW_SHOW);
ShowWindow(GetDlgItem(hWnd,IDC_EDITPASS),SW_HIDE);
if (gConnectResults->password[0]!=0)
CheckDlgButton(hWnd,IDC_CRYPTPASS,BST_CHECKED);
}
}
}
}
}
return 0;
}
void fillProxyCombobox(HWND hWnd,int defproxynr)
{
SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_RESETCONTENT,0,0);
TCHAR noproxy[100],addproxy[100],httpproxy[100],buf[256];
LoadString(hinst, IDS_NO_PROXY, noproxy, countof(noproxy));
LoadString(hinst, IDS_HTTP_PROXY, httpproxy, countof(httpproxy));
LoadString(hinst, IDS_ADD_PROXY, addproxy, countof(addproxy));
SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_ADDSTRING,0,(LPARAM)&noproxy);
tConnectSettings connectData;
int proxynr=1;
while (true) {
if (LoadProxySettingsFromNr(proxynr,&connectData)) {
#ifdef sprintf_s
sprintf_s(buf,sizeof(buf),TEXT("%d: "),proxynr);
#else
sprintf(buf,TEXT("%d: "),proxynr);
#endif
switch (connectData.proxytype) {
case 0:
strlcat(buf,noproxy,sizeof(buf)-1);
break;
case 2:
strlcat(buf,httpproxy,sizeof(buf)-1);
break;
case 3:
strlcat(buf,"SOCKS4a: ",sizeof(buf)-1);
break;
case 4:
strlcat(buf,"SOCKS5: ",sizeof(buf)-1);
break;
}
if (connectData.proxytype>0)
strlcat(buf,connectData.proxyserver,sizeof(buf)-1);
SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_ADDSTRING,0,(LPARAM)&buf);
} else
break;
proxynr++;
}
SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_ADDSTRING,0,(LPARAM)&addproxy);
if (defproxynr>=0 && defproxynr<=proxynr)
SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_SETCURSEL,defproxynr,0);
}
BOOL DeleteLastProxy(int proxynrtodelete,char* ServerToSkip,char *AppendToList,int maxlen)
{
if (proxynrtodelete<=1)
return false;
BOOL CanDelete=true;
BOOL AlreadyAdded=false;
char name[wdirtypemax];
SERVERHANDLE hdl=FindFirstServer(name,sizeof(name)-1);
while (hdl) {
if (_stricmp(name,ServerToSkip)!=0) {
int proxynr=GetPrivateProfileInt(name,"proxynr",1,gIniFileName);
if (proxynr==proxynrtodelete) {
CanDelete=false;
if (AlreadyAdded)
strlcat(AppendToList,",",maxlen);
strlcat(AppendToList,name,maxlen);
AlreadyAdded=true;
}
}
hdl=FindNextServer(hdl,name,sizeof(name)-1);
}
if (CanDelete) {
char proxyentry[64];
#ifdef sprintf_s
sprintf_s(proxyentry,sizeof(proxyentry),"proxy%d",proxynrtodelete);
#else
sprintf(proxyentry,"proxy%d",proxynrtodelete);
#endif
WritePrivateProfileString(proxyentry,NULL,NULL,gIniFileName);
}
return CanDelete;
}
// SR: 09.07.2005
myint __stdcall ConnectDlgProc(HWND hWnd,unsigned int Message,WPARAM wParam,LPARAM lParam)
{
RECT rt1,rt2;
int i,w,h,DlgWidth,DlgHeight,NewPosX,NewPosY,cp,cbline;
char modbuf[32],strbuf[MAX_PATH];
switch (Message) {
case WM_INITDIALOG: {
SendDlgItemMessage(hWnd,IDC_DEFAULTCOMBO,CB_SETCURSEL,0,0);
serverfieldchangedbyuser=false;
LoadStr(strbuf,IDS_AUTO);
SendDlgItemMessage(hWnd,IDC_UTF8,CB_ADDSTRING,0,(LPARAM)&strbuf);
for (i=IDS_UTF8;i<=IDS_OTHER;i++) {
LoadStr(strbuf,i);
SendDlgItemMessage(hWnd,IDC_UTF8,CB_ADDSTRING,0,(LPARAM)&strbuf);
}
LoadStr(strbuf,IDS_AUTO);
SendDlgItemMessage(hWnd,IDC_SYSTEM,CB_ADDSTRING,0,(LPARAM)&strbuf);
strlcpy(strbuf,"Windows (CR/LF)",sizeof(strbuf)-1);
SendDlgItemMessage(hWnd,IDC_SYSTEM,CB_ADDSTRING,0,(LPARAM)&strbuf);
strlcpy(strbuf,"Unix (LF)",sizeof(strbuf)-1);
SendDlgItemMessage(hWnd,IDC_SYSTEM,CB_ADDSTRING,0,(LPARAM)&strbuf);
if (strcmp(gDisplayName,s_quickconnect)!=0) {
SetDlgItemText(hWnd,IDC_CONNECTTO,gConnectResults->server);
if (gConnectResults->server[0])
serverfieldchangedbyuser=true;
switch (gConnectResults->protocoltype) {
case 1:CheckRadioButton(hWnd,IDC_PROTOAUTO,IDC_PROTOV6,IDC_PROTOV4);break;
case 2:CheckRadioButton(hWnd,IDC_PROTOAUTO,IDC_PROTOV6,IDC_PROTOV6);break;
default:
CheckRadioButton(hWnd,IDC_PROTOAUTO,IDC_PROTOV6,IDC_PROTOAUTO);break;
}
SetDlgItemText(hWnd,IDC_USERNAME,gConnectResults->user);
if (gConnectResults->useagent) {
CheckDlgButton(hWnd,IDC_USEAGENT,BST_CHECKED);
EnableControlsPageant(hWnd,false);
}
if (gConnectResults->detailedlog)
CheckDlgButton(hWnd,IDC_DETAILED_LOG,BST_CHECKED);
if (gConnectResults->compressed)
CheckDlgButton(hWnd,IDC_COMPRESS,BST_CHECKED);
if (gConnectResults->scpfordata)
CheckDlgButton(hWnd,IDC_SCP_DATA,BST_CHECKED);
if (gConnectResults->scponly)
CheckDlgButton(hWnd,IDC_SCP_ALL,BST_CHECKED);
switch (gConnectResults->utf8names) {
case -1:cbline=0; break; // auto-detect
case 1:cbline=1; break;
default:
cbline=0;
cp=gConnectResults->codepage;
for (i=0;i<countof(codepagelist);i++)
if (cp==codepagelist[i]) {
cbline=i;
break;
}
if (cp>0 && cbline==0) {
_itoa_s(cp,strbuf,sizeof(strbuf),10);
SendDlgItemMessage(hWnd,IDC_UTF8,CB_ADDSTRING,0,(LPARAM)&strbuf);
cbline=countof(codepagelist)-1;
}
}
SendDlgItemMessage(hWnd,IDC_UTF8,CB_SETCURSEL,cbline,0);
SendDlgItemMessage(hWnd,IDC_SYSTEM,CB_SETCURSEL,max(0,min(2,gConnectResults->unixlinebreaks+1)),0);
if (strcmp(gConnectResults->password,"\001")==0 && CryptProc) {
if (!gConnectResults->useagent && CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_LOAD_PASSWORD_NO_UI,gDisplayName,gConnectResults->password,countof(gConnectResults->password)-1)==FS_FILE_OK) {
SetDlgItemText(hWnd,IDC_PASSWORD, gConnectResults->password);
CheckDlgButton(hWnd,IDC_CRYPTPASS,BST_CHECKED);
} else {
ShowWindow(GetDlgItem(hWnd,IDC_PASSWORD),SW_HIDE);
ShowWindow(GetDlgItem(hWnd,IDC_CRYPTPASS),SW_HIDE);
ShowWindow(GetDlgItem(hWnd,IDC_EDITPASS),SW_SHOW);
}
} else {
SetDlgItemText(hWnd,IDC_PASSWORD, gConnectResults->password);
if (!CryptProc)
EnableWindow(GetDlgItem(hWnd,IDC_CRYPTPASS),false);
else if (gConnectResults->password[0]==0 && CryptCheckPass)
CheckDlgButton(hWnd,IDC_CRYPTPASS,BST_CHECKED);
}
SetDlgItemText(hWnd,IDC_PUBKEY,gConnectResults->pubkeyfile);
SetDlgItemText(hWnd,IDC_PRIVKEY,gConnectResults->privkeyfile);
_itoa_s(gConnectResults->filemod,modbuf,sizeof(modbuf),8);
SetDlgItemText(hWnd,IDC_FILEMOD,modbuf);
_itoa_s(gConnectResults->dirmod,modbuf,sizeof(modbuf),8);
SetDlgItemText(hWnd,IDC_DIRMOD,modbuf);
fillProxyCombobox(hWnd,gConnectResults->proxynr);
} else {
CheckRadioButton(hWnd,IDC_PROTOAUTO,IDC_PROTOV6,IDC_PROTOAUTO);
SetDlgItemText(hWnd,IDC_FILEMOD,"644");
SetDlgItemText(hWnd,IDC_DIRMOD,"755");
SendDlgItemMessage(hWnd,IDC_UTF8,CB_SETCURSEL,0,0);
SendDlgItemMessage(hWnd,IDC_SYSTEM,CB_SETCURSEL,0,0);
}
if (strcmp(gDisplayName,s_quickconnect)!=0) {
if (gConnectResults->server[0]==0)
g_focusset=IDC_CONNECTTO;
else if (gConnectResults->user[0]==0)
g_focusset=IDC_USERNAME;
else
g_focusset=IDC_PASSWORD;
} else
g_focusset=IDC_CONNECTTO;
// trying to center the About dialog
if (GetWindowRect(hWnd, &rt1) && GetWindowRect(GetParent(hWnd), &rt2)) {
w=rt2.right-rt2.left;
h=rt2.bottom-rt2.top;
DlgWidth = rt1.right - rt1.left;
DlgHeight = rt1.bottom - rt1.top ;
NewPosX =rt2.left + (w - DlgWidth)/2;
NewPosY =rt2.top + (h - DlgHeight)/2;
SetWindowPos(hWnd, 0, NewPosX, NewPosY,
0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
// SR: 11.07.2005
serverfieldchangedbyuser=false;
return 1;
break;
}
case WM_SHOWWINDOW: {
if (g_focusset)
SetFocus(GetDlgItem(hWnd,g_focusset));
break;
}
case WM_COMMAND: {
switch(LOWORD(wParam)) {
case IDOK: {
GetDlgItemText(hWnd,IDC_CONNECTTO,gConnectResults->server,sizeof(gConnectResults->server)-1);
GetDlgItemText(hWnd,IDC_USERNAME,gConnectResults->user,sizeof(gConnectResults->user)-1);
GetDlgItemText(hWnd,IDC_PASSWORD,gConnectResults->password,sizeof(gConnectResults->password)-1);
if (IsDlgButtonChecked(hWnd,IDC_PROTOV4))
gConnectResults->protocoltype=1;
else if (IsDlgButtonChecked(hWnd,IDC_PROTOV6))
gConnectResults->protocoltype=2;
else
gConnectResults->protocoltype=0;
GetDlgItemText(hWnd,IDC_PUBKEY,gConnectResults->pubkeyfile,sizeof(gConnectResults->pubkeyfile)-1);
GetDlgItemText(hWnd,IDC_PRIVKEY,gConnectResults->privkeyfile,sizeof(gConnectResults->privkeyfile)-1);
gConnectResults->useagent=IsDlgButtonChecked(hWnd,IDC_USEAGENT);
gConnectResults->detailedlog=IsDlgButtonChecked(hWnd,IDC_DETAILED_LOG);
gConnectResults->compressed=IsDlgButtonChecked(hWnd,IDC_COMPRESS);
gConnectResults->scpfordata=IsDlgButtonChecked(hWnd,IDC_SCP_DATA);
gConnectResults->scponly=IsDlgButtonChecked(hWnd,IDC_SCP_ALL);
cp=0;
cbline=(char)SendDlgItemMessage(hWnd,IDC_UTF8,CB_GETCURSEL,0,0);
switch (cbline) {
case 0:gConnectResults->utf8names=-1; break; // auto-detect
case 1:gConnectResults->utf8names=1; break;
default:
gConnectResults->utf8names=0;
if (cbline>=0 && cbline<countof(codepagelist)) {
cp=codepagelist[cbline];
if (cp==-3) {
if (RequestProc(PluginNumber,RT_Other,"Code page","Code page (e.g. 28591):",strbuf,sizeof(strbuf)-1)) {
cp=atoi(strbuf);
}
} else if (cp==-4) {
cp=gConnectResults->codepage; // unchanged!
}
}
}
gConnectResults->codepage=cp;
gConnectResults->unixlinebreaks=(char)SendDlgItemMessage(hWnd,IDC_SYSTEM,CB_GETCURSEL,0,0)-1;
GetDlgItemText(hWnd,IDC_FILEMOD,modbuf,sizeof(modbuf)-1);
if (modbuf[0]==0)
gConnectResults->filemod=0644;
else
gConnectResults->filemod=strtol(modbuf,NULL,8);
GetDlgItemText(hWnd,IDC_DIRMOD,modbuf,sizeof(modbuf)-1);
if (modbuf[0]==0)
gConnectResults->dirmod=0755;
else
gConnectResults->dirmod=strtol(modbuf,NULL,8);
gConnectResults->proxynr=(int)SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_GETCURSEL,0,0);
int max=(int)SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_GETCOUNT,0,0)-1;
if (gConnectResults->proxynr>=max) // "add" item!
gConnectResults->proxynr=0;
if (strcmp(gDisplayName,s_quickconnect)!=0) {
char buf[16];
WritePrivateProfileString(gDisplayName,"server",gConnectResults->server,gIniFileName);
WritePrivateProfileString(gDisplayName,"user",gConnectResults->user,gIniFileName);
_itoa_s(gConnectResults->protocoltype,buf,sizeof(buf),10);
WritePrivateProfileString(gDisplayName,"protocol",gConnectResults->protocoltype==0 ? NULL:buf,gIniFileName);
WritePrivateProfileString(gDisplayName,"detailedlog",gConnectResults->detailedlog ? "1" : NULL,gIniFileName);
WritePrivateProfileString(gDisplayName,"utf8",gConnectResults->utf8names==-1 ? NULL : gConnectResults->utf8names==1 ? "1" : "0",gIniFileName);
_itoa_s(gConnectResults->codepage,buf,sizeof(buf),10);
WritePrivateProfileString(gDisplayName,"codepage",buf,gIniFileName);
WritePrivateProfileString(gDisplayName,"unixlinebreaks",gConnectResults->unixlinebreaks==-1 ? NULL : gConnectResults->unixlinebreaks==1 ? "1" : "0",gIniFileName);
WritePrivateProfileString(gDisplayName,"compression",gConnectResults->compressed ? "1" : NULL,gIniFileName);
WritePrivateProfileString(gDisplayName,"scpfordata",gConnectResults->scpfordata ? "1" : NULL,gIniFileName);
WritePrivateProfileString(gDisplayName,"scponly",gConnectResults->scponly ? "1" : NULL,gIniFileName);
WritePrivateProfileString(gDisplayName,"pubkeyfile",gConnectResults->pubkeyfile[0] ?gConnectResults->pubkeyfile:NULL,gIniFileName);
WritePrivateProfileString(gDisplayName,"privkeyfile",gConnectResults->privkeyfile[0] ?gConnectResults->privkeyfile:NULL,gIniFileName);
WritePrivateProfileString(gDisplayName,"useagent",gConnectResults->useagent ? "1" : NULL,gIniFileName);
_itoa_s(gConnectResults->filemod,modbuf,sizeof(modbuf),8);
WritePrivateProfileString(gDisplayName,"filemod",gConnectResults->filemod==0644 ? NULL:modbuf,gIniFileName);
_itoa_s(gConnectResults->dirmod,modbuf,sizeof(modbuf),8);
WritePrivateProfileString(gDisplayName,"dirmod",gConnectResults->dirmod==0755 ? NULL:modbuf,gIniFileName);
_itoa_s(gConnectResults->proxynr,buf,sizeof(buf),10);
WritePrivateProfileString(gDisplayName,TEXT("proxynr"),buf,gIniFileName);
// SR: 09.07.2005
if (!gConnectResults->dialogforconnection)
{
TCHAR szEncryptedPassword[MAX_PATH];
if (!gConnectResults->useagent)
if (!IsWindowVisible(GetDlgItem(hWnd,IDC_EDITPASS))) {
if (gConnectResults->password[0]==0) {
WritePrivateProfileString(gDisplayName,"password",NULL,gIniFileName);
} else if (CryptProc && IsDlgButtonChecked(hWnd,IDC_CRYPTPASS)) {
BOOL ok=CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_SAVE_PASSWORD,gDisplayName,gConnectResults->password,0)==FS_FILE_OK;
WritePrivateProfileString(gDisplayName,"password",ok? "!" : NULL,gIniFileName);
CryptCheckPass=true;
} else {
EncryptString(gConnectResults->password, szEncryptedPassword, countof(szEncryptedPassword));
WritePrivateProfileString(gDisplayName,"password",szEncryptedPassword,gIniFileName);
}
}
}
}
gConnectResults->customport=0; // will be set later
EndDialog(hWnd, IDOK);
return 1;
}
case IDCANCEL:
{
// free serial number structures associated with each client certificate combo item
int iCount = (int)SendDlgItemMessage(hWnd, IDC_CBO_CC, CB_GETCOUNT, (WPARAM) 0, (LPARAM) 0);
EndDialog(hWnd, IDCANCEL);
return 1;
}
case IDC_EDITPASS:
{
BOOL doshow=true;
int err;
err=CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_LOAD_PASSWORD,gDisplayName,gConnectResults->password,countof(gConnectResults->password)-1);
if (err==FS_FILE_OK) {
SetDlgItemText(hWnd,IDC_PASSWORD, gConnectResults->password);
} else if (err=FS_FILE_READERROR) { // no password stored!
SetDlgItemText(hWnd,IDC_PASSWORD, "");
} else {
doshow=false;
}
if (doshow) {
ShowWindow(GetDlgItem(hWnd,IDC_PASSWORD),SW_SHOW);
ShowWindow(GetDlgItem(hWnd,IDC_CRYPTPASS),SW_SHOW);
ShowWindow(GetDlgItem(hWnd,IDC_EDITPASS),SW_HIDE);
if (gConnectResults->password[0]!=0)
CheckDlgButton(hWnd,IDC_CRYPTPASS,BST_CHECKED);
}
}
case IDC_CONNECTTO:
if (HIWORD(wParam)==EN_CHANGE) {
serverfieldchangedbyuser=true;
}
break;
case IDC_CERTHELP:
{
TCHAR szCaption[100]; LoadString(hinst, IDS_HELP_CAPTION, szCaption, countof(szCaption));
TCHAR szBuffer[1024]; LoadString(hinst, IDS_HELP_CERT, szBuffer, countof(szBuffer));
MessageBox(hWnd, szBuffer, szCaption, MB_OK | MB_ICONINFORMATION);
break;
}
case IDC_UTF8HELP:
{
TCHAR szCaption[100]; LoadString(hinst, IDS_HELP_CAPTION, szCaption, countof(szCaption));
TCHAR szBuffer[1024]; LoadString(hinst, IDS_HELP_UTF8 , szBuffer, countof(szBuffer));
MessageBox(hWnd, szBuffer, szCaption, MB_OK | MB_ICONINFORMATION);
break;
}
case IDC_LOADPUBKEY:
case IDC_LOADPRIVKEY:
{
OPENFILENAME ofn ; // structure used by the common file dialog
char szFileName[MAX_PATH] ;
ZeroMemory(&ofn, sizeof(OPENFILENAME)) ;
ofn.lStructSize = sizeof(OPENFILENAME) ;
ofn.hwndOwner = hWnd;
ofn.nFilterIndex = 1 ;
ofn.lpstrFile = szFileName ;
ofn.nMaxFile = sizeof(szFileName) ;
if (LOWORD(wParam)==IDC_LOADPUBKEY) {
lstrcpy(szFileName, TEXT("*.pub")) ;
ofn.lpstrFilter = TEXT("Public key files (*.pub)\0*.pub\0All Files\0*.*\0") ;
ofn.lpstrTitle = TEXT("Select public key file") ;
} else {
lstrcpy(szFileName, TEXT("*.pem")) ;
ofn.lpstrFilter = TEXT("Private key files (*.pub)\0*.pem\0All Files\0*.*\0") ;
ofn.lpstrTitle = TEXT("Select private key file") ;
}
ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY ;
// GetOpenFileName will bring up the common file dialog in open mode
if (GetOpenFileName(&ofn)) // user specified a file
{
SetDlgItemText(hWnd,LOWORD(wParam)==IDC_LOADPUBKEY ? IDC_PUBKEY:IDC_PRIVKEY,szFileName);
}
break;
}
case IDC_USEAGENT:
{
EnableControlsPageant(hWnd,!IsDlgButtonChecked(hWnd,IDC_USEAGENT));
break;
}
case IDC_PROXYCOMBO:
{
int proxynr1=(int)SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_GETCURSEL,0,0);
if (HIWORD(wParam)==CBN_SELCHANGE)
if (proxynr1==(int)SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_GETCOUNT,0,0)-1)
PostMessage(hWnd,WM_COMMAND,IDC_PROXYBUTTON,0);
}
break;
case IDC_PROXYBUTTON:
{
int proxynr=(int)SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_GETCURSEL,0,0);
if (proxynr>0) {
gProxyNr=proxynr;
if (IDOK==DialogBox(hinst,MAKEINTRESOURCE(IDD_PROXY),GetActiveWindow(),ProxyDlgProc))
fillProxyCombobox(hWnd,proxynr);
}
break;
}
case IDC_DELETELAST:
int proxynr=(int)SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_GETCOUNT,0,0)-2;
if (proxynr>=2) { // proxy nr 1 cannot be deleted!
TCHAR errorstr[1024];
LoadString(hinst, IDS_ERROR_INUSE, errorstr, sizeof(errorstr));
strlcat(errorstr,"\n",sizeof(errorstr)-1);
if (DeleteLastProxy(proxynr,gConnectResults->DisplayName,errorstr,sizeof(errorstr)-1)) {
int proxynr=(int)SendDlgItemMessage(hWnd,IDC_PROXYCOMBO,CB_GETCURSEL,0,0);
fillProxyCombobox(hWnd,proxynr);
} else {
MessageBox(hWnd,errorstr,"SFTP",MB_ICONSTOP);
}
} else
MessageBeep(MB_ICONSTOP);
break;
}
}
}
return 0;
}
BOOL ShowConnectDialog(pConnectSettings ConnectSettings,char* DisplayName,char* inifilename)
{
gConnectResults=ConnectSettings;
gDisplayName=DisplayName;
gIniFileName=inifilename;
LoadServerSettings(DisplayName,ConnectSettings);
if (ConnectSettings->dialogforconnection && ConnectSettings->server[0]) {
if ((ConnectSettings->user[0]==0 ||
ConnectSettings->password[0]) && // password saved
(ConnectSettings->proxyuser[0]==0 || // no proxy auth required
ConnectSettings->proxypassword[0])) // or proxy pass saved
return true;
else {
char title[256];
// A proxy user name was given, but no proxy password -> ask for proxy password
if (ConnectSettings->proxyuser[0]!=0 && // no proxy auth required
ConnectSettings->proxypassword[0]==0) {
LoadString(hinst, IDS_PROXY_PASS_TITLE, title, countof(title));
strlcat(title,ConnectSettings->proxyuser,sizeof(title)-1);
if (!RequestProc(PluginNumber,RT_PasswordFirewall,title,title,ConnectSettings->proxypassword,countof(ConnectSettings->proxypassword)-1))
return false;
}
return true;
}
} else
return (IDOK==DialogBox(hinst,MAKEINTRESOURCE(IDD_WEBDAV),GetActiveWindow(),ConnectDlgProc));
}
void* SftpConnectToServer(char* DisplayName,char* inifilename,char* overridepass)
{
tConnectSettings ConnectSettings;
memset(&ConnectSettings,0,sizeof(tConnectSettings));
ConnectSettings.dialogforconnection=true;
// Get connection settings here
if (ShowConnectDialog(&ConnectSettings,DisplayName,inifilename)) {
if (overridepass)
strlcpy(gConnectResults->password,overridepass,sizeof(gConnectResults->password)-1);
if (CryptProc && strcmp(gConnectResults->password,"\001")==0) {
ConnectSettings.passSaveMode=1;
if (CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_LOAD_PASSWORD,gDisplayName,gConnectResults->password,countof(gConnectResults->password)-1)!=FS_FILE_OK) {
MessageBox(GetActiveWindow(),"Failed to load password!","Error",MB_ICONSTOP);
return NULL;
}
} else if (ConnectSettings.useagent || gConnectResults->password[0]==0)
ConnectSettings.passSaveMode=0;
else
ConnectSettings.passSaveMode=2;
if (CryptProc && strcmp(gConnectResults->proxypassword,"\001")==0) {
TCHAR proxyentry[64];
if (gConnectResults->proxynr>1)
#ifdef sprintf_s
sprintf_s(proxyentry,sizeof(proxyentry),"proxy%d",gConnectResults->proxynr);
#else
sprintf(proxyentry,"proxy%d",gConnectResults->proxynr);
#endif
else
strlcpy(proxyentry,"proxy",sizeof(proxyentry)-1);
strlcat(proxyentry,"$$pass",sizeof(proxyentry)-1);
if (CryptProc(PluginNumber,CryptoNumber,FS_CRYPT_LOAD_PASSWORD,proxyentry,gConnectResults->proxypassword,countof(gConnectResults->proxypassword)-1)!=FS_FILE_OK) {
MessageBox(GetActiveWindow(),"Failed to load proxy password!","Error",MB_ICONSTOP);
return NULL;
}
}
// Clear proxy user and pass if proxy type is set to 0!
if (ConnectSettings.proxytype==0) {
ConnectSettings.proxyuser[0]=0;
ConnectSettings.proxypassword[0]=0;
}
// split server name into server/path
ReplaceBackslashBySlash(ConnectSettings.server);
// Remove trailing sftp://
if (_strnicmp(ConnectSettings.server,"sftp://",7)==0)
memmove(ConnectSettings.server,ConnectSettings.server+7,strlen(ConnectSettings.server)-6);
char* p=strchr(ConnectSettings.server,'/');
ConnectSettings.lastactivepath[0]=0;
if (p) {
awlcopy(ConnectSettings.lastactivepath,p,countof(ConnectSettings.lastactivepath)-1);
p[0]=0;
// remove trailing backslash, also in case of root!
}
// look for address and port
p=strchr(ConnectSettings.server,':');
if(!ParseAddress(ConnectSettings.server, &ConnectSettings.server[0], &ConnectSettings.customport, 22)) {
MessageBox(GetActiveWindow(),"Invalid server address.","SFTP Error",MB_ICONSTOP);
return NULL;
}
if (ProgressProc(PluginNumber,DisplayName,"temp",0))
return NULL;
if (SftpConnect(&ConnectSettings)!=SFTP_OK)
return NULL;
{
// This will show ftp toolbar
char connbuf[MAX_PATH];
strlcpy(connbuf,"CONNECT \\",sizeof(connbuf)-1);
strlcat(connbuf,DisplayName,sizeof(connbuf)-1);
LogProc(PluginNumber,MSGTYPE_CONNECT,connbuf);
pConnectSettings psettings=(pConnectSettings)malloc(sizeof(ConnectSettings));
memcpy(psettings,&ConnectSettings,sizeof(ConnectSettings));
return psettings;
}
}
return NULL;
}
BOOL SftpConfigureServer(char* DisplayName,char* inifilename)
{
tConnectSettings ConnectSettings;
memset(&ConnectSettings,0,sizeof(tConnectSettings));
ConnectSettings.dialogforconnection=false;
return ShowConnectDialog(&ConnectSettings,DisplayName,inifilename);
}
int SftpCloseConnection(void* serverid)
{
int rc;
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (ConnectSettings) {
int starttime=(int)GetTickCount();
BOOL doabort=false;
if (ConnectSettings->sftpsession) {
do {
rc=libssh2_sftp_shutdown(ConnectSettings->sftpsession);
if (EscapePressed())
doabort=true;
if (doabort && (int)GetTickCount()-starttime>2000)
break;
if ((int)GetTickCount()-starttime>5000)
break;
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
ConnectSettings->sftpsession=NULL;
}
if (ConnectSettings->session) {
do {
rc=libssh2_session_disconnect(ConnectSettings->session, "Disconnect");
if (EscapePressed())
doabort=true;
if (doabort && (int)GetTickCount()-starttime>2000)
break;
if ((int)GetTickCount()-starttime>5000)
break;
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
libssh2_session_free(ConnectSettings->session);
ConnectSettings->session=NULL;
}
if (ConnectSettings->sock!=INVALID_SOCKET) {
Sleep(1000);
closesocket(ConnectSettings->sock);
ConnectSettings->sock=INVALID_SOCKET;
}
}
return SFTP_FAILED;
}
BOOL ReconnectSFTPChannelIfNeeded(pConnectSettings ConnectSettings)
{
if (ConnectSettings->scponly)
return true; // not needed
if (ConnectSettings->neednewchannel || ConnectSettings->sftpsession==NULL) {
ConnectSettings->neednewchannel=false;
DWORD starttime=(int)GetTickCount();
int rc;
int loop=0;
if (ConnectSettings->sftpsession) {
do {
rc=libssh2_sftp_shutdown(ConnectSettings->sftpsession);
} while (rc==LIBSSH2_ERROR_EAGAIN && (int)GetTickCount()-(int)starttime<2000);
}
if (ConnectSettings->session)
do {
ConnectSettings->sftpsession=NULL;
if (ProgressLoop("Reconnect SFTP channel",0,100,&loop,&starttime))
break;
ConnectSettings->sftpsession=libssh2_sftp_init(ConnectSettings->session);
if ((!ConnectSettings->sftpsession) && (libssh2_session_last_errno(ConnectSettings->session) !=
LIBSSH2_ERROR_EAGAIN)) {
break;
}
} while (!ConnectSettings->sftpsession);
// try to reconnect the entire connection!
if (!ConnectSettings->sftpsession) {
ShowStatus("Connection lost, trying to reconnect!");
SftpCloseConnection(ConnectSettings);
Sleep(1000);
SftpConnect(ConnectSettings);
}
ConnectSettings->neednewchannel=ConnectSettings->sftpsession==NULL;
}
return !ConnectSettings->neednewchannel;
}
int SftpFindFirstFileW(void* serverid,WCHAR* remotedir,void** davdataptr)
{
LIBSSH2_SFTP_HANDLE *dirhandle;
char dirname[wdirtypemax];
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
LoadStr(dirname,IDS_GET_DIR);
walcopy(dirname+strlen(dirname),remotedir,(int)(sizeof(dirname)-strlen(dirname)-1));
ShowStatus(dirname);
if (ConnectSettings->utf8names)
wcslcpytoutf8(dirname,remotedir,sizeof(dirname)-1);
else
walcopyCP(ConnectSettings->codepage,dirname,remotedir,sizeof(dirname)-1);
ReplaceBackslashBySlash(dirname);
if (strlen(dirname)>1) {
char* p=dirname+strlen(dirname)-1;
if (p[0]!='/') // ADD trailing slash!
strlcat(dirname,"/",sizeof(dirname)-1);
}
if (ConnectSettings->scponly) {
LIBSSH2_CHANNEL *channel;
channel=ConnectChannel(ConnectSettings->session);
if (!channel) {
ShowStatus("no channel");
return SFTP_FAILED;
}
char commandbuf[wdirtypemax+100];
int trycustom=ConnectSettings->trycustomlistcommand;
if (trycustom>=1)
strcpy(commandbuf,"LANG= && ");
else
commandbuf[0]=0;
int lencmd0=strlen(commandbuf);
strlcat(commandbuf,"ls -la ",sizeof(commandbuf)-1);
int lencmd1=strlen(commandbuf);
if (trycustom==2)
strlcat(commandbuf,"--time-style=\"+>>%Y%m%d_%H%M%S\" ",sizeof(commandbuf)-1);
int lencmd2=strlen(commandbuf);
BOOL needquotes=strchr(dirname,' ')!=NULL || strchr(dirname,'(')!=NULL || strchr(dirname,')')!=NULL;
if (needquotes)
strlcat(commandbuf,"\"",sizeof(commandbuf)-3);
strlcat(commandbuf,dirname,sizeof(commandbuf)-2);
if (needquotes)
strlcat(commandbuf,"\"",sizeof(commandbuf)-1);
// 3 tries: 2. custom time style, 1. clear LANG, 0. plain ls -l
char errorbuf[1024];
errorbuf[0]=0;
int rcerr=0;
for (int i=trycustom;i>=0;i--) {
if (ConnectSettings->detailedlog)
ShowStatus(commandbuf+(i==1?0:lencmd0));
if (!SendChannelCommand(ConnectSettings->session,channel,
commandbuf+(i==1?0:lencmd0))) {
DisconnectShell(channel);
ShowStatus("send command failed");
return SFTP_FAILED;
}
// check whether the command was understood or not
int rc=0;
rcerr=0;
do {
errorbuf[0]=0;
rc=libssh2_channel_read(channel, errorbuf, 1);
rcerr=libssh2_channel_read_stderr(channel, errorbuf, 1023);
if (rcerr>0) {
errorbuf[rcerr]=0;
if (ConnectSettings->detailedlog)
ShowStatus(errorbuf);
}
} while ((rc==0 || rc==LIBSSH2_ERROR_EAGAIN) &&
(rcerr==0 || rcerr==LIBSSH2_ERROR_EAGAIN));
if (rcerr>0 && i>0) {
DisconnectShell(channel);
channel=ConnectChannel(ConnectSettings->session);
if (!channel) {
ShowStatus("no channel");
return SFTP_FAILED;
}
// remove time style parameter
if (i==2)
memmove(&commandbuf[lencmd1],&commandbuf[lencmd2],strlen(commandbuf+lencmd2)+1);
}
if (rcerr==0 || rcerr==LIBSSH2_ERROR_EAGAIN) { // custom failed, normal OK -> no longer try custom
ConnectSettings->trycustomlistcommand=i;
break;
}
}
SCP_DATA* scpd=(SCP_DATA*)malloc(sizeof(SCP_DATA));
scpd->channel=channel;
scpd->msgbuf[0]=0;
scpd->errbuf[0]=0;
*davdataptr=scpd;
} else {
if (!ReconnectSFTPChannelIfNeeded(ConnectSettings))
return SFTP_FAILED;
/* Request a dir listing via SFTP */
ConnectSettings->findstarttime=(int)GetTickCount();
int aborttime=-1;
int retrycount=3;
do {
dirhandle=libssh2_sftp_opendir(ConnectSettings->sftpsession,dirname);
int err=0;
if (!dirhandle) {
err=libssh2_session_last_errno(ConnectSettings->session);
if (err!=LIBSSH2_ERROR_EAGAIN) {
if (err==LIBSSH2_FX_EOF || err==LIBSSH2_FX_FAILURE || err==LIBSSH2_FX_BAD_MESSAGE ||
err==LIBSSH2_FX_NO_CONNECTION || err==LIBSSH2_FX_CONNECTION_LOST ||
err<0)
retrycount--;
else
retrycount=0;
if (retrycount<=0)
break;
ConnectSettings->neednewchannel=true; // force reconnect
if (!ReconnectSFTPChannelIfNeeded(ConnectSettings))
return SFTP_FAILED;
} else
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
Sleep(50);
int delta=(int)GetTickCount()-ConnectSettings->findstarttime;
if (delta>2000 && aborttime==-1) {
if (ProgressProc(PluginNumber,dirname,"temp",(delta/200)%100))
aborttime=GetTickCount()+2000; // give it 2 seconds to finish properly!
}
delta=(int)GetTickCount()-aborttime;
if (aborttime!=-1 && delta>0) {
ConnectSettings->neednewchannel=true;
break;
}
} while (!dirhandle);
if(!dirhandle) {
char* errmsg;
int errmsg_len;
LoadStr(dirname,IDS_ERR_GET_DIR);
libssh2_session_last_error(ConnectSettings->session, &errmsg, &errmsg_len, false);
strlcat(dirname,errmsg,sizeof(dirname)-1);
ShowStatus(dirname);
return SFTP_FAILED;
}
*davdataptr=dirhandle;
}
wcslcpy(ConnectSettings->lastactivepath,remotedir,countof(ConnectSettings->lastactivepath)-1);
return SFTP_OK;
}
BOOL SftpFindNextFileW(void* serverid,void* davdataptr,WIN32_FIND_DATAW *FindData)
{
char name[512];
WCHAR namew[MAX_PATH];
char completeline[2048];
WCHAR completelinew[2048];
int rc;
LIBSSH2_SFTP_HANDLE *dirhandle;
LIBSSH2_SFTP_ATTRIBUTES file;
FILETIME datetime;
DWORD attr=0;
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
dirhandle=(LIBSSH2_SFTP_HANDLE*)davdataptr;
if (!dirhandle)
return SFTP_FAILED;
completeline[0]=0;
name[0]=0;
namew[0]=0;
int aborttime=-1;
if (ConnectSettings->scponly) {
SCP_DATA* scpd=(SCP_DATA*)davdataptr;
LIBSSH2_CHANNEL *channel = scpd->channel;
if (!channel)
return SFTP_FAILED;
rc=0;
while (ReadChannelLine(channel,completeline,sizeof(completeline)-1,scpd->msgbuf,sizeof(scpd->msgbuf)-1,
scpd->errbuf,sizeof(scpd->errbuf)-1)) {
BOOL longdatetime=false;
StripEscapeSequences(completeline);
if (ConnectSettings->utf8names) {
UTF8* srcstart=(unsigned char*)completeline;
UTF16* trgstart=(UTF16*)completelinew;
ConvertUTF8toUTF16(&srcstart,srcstart+strlen(completeline)+1,
&trgstart,trgstart+countof(completelinew)-1);
} else
awlcopyCP(ConnectSettings->codepage,completelinew,completeline,countof(completelinew)-1);
if (ReadDirLineUNIX(completelinew,namew,countof(namew)-1,(__int64*)&file.filesize,
&datetime,&attr,&file.permissions,longdatetime)) {
file.flags=LIBSSH2_SFTP_ATTR_SIZE | LIBSSH2_SFTP_ATTR_PERMISSIONS;
rc=1;
break;
}
}
} else {
while ((rc = libssh2_sftp_readdir_ex(dirhandle, name, sizeof(name), completeline, sizeof(completeline),
&file)) == LIBSSH2_ERROR_EAGAIN) {
int delta=(int)GetTickCount()-ConnectSettings->findstarttime;
if (delta>2000 && aborttime==-1) {
if (ProgressProc(PluginNumber,"dir","temp",(delta/200)%100))
aborttime=GetTickCount()+2000; // give it 2 seconds to finish properly!
}
delta=(int)GetTickCount()-(int)aborttime;
if (aborttime!=-1 && delta>0) {
ConnectSettings->neednewchannel=true;
break;
}
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
}
if (rc>0) {
if (ConnectSettings->detailedlog)
ShowStatus(completeline);
FindData->dwFileAttributes=0;
if (namew[0]) {
WCHAR* p=wcsstr(namew,L" -> ");
if (p)
p[0]=0;
wcslcpy2(FindData->cFileName,namew,countof(FindData->cFileName)-1);
} else if (ConnectSettings->utf8names) {
UTF8* srcstart=(unsigned char*)name;
UTF16* trgstart=(UTF16*)&(FindData->cFileName);
ConvertUTF8toUTF16(&srcstart,srcstart+strlen(name)+1,
&trgstart,trgstart+countof(FindData->cFileName)-1);
} else {
awlcopyCP(ConnectSettings->codepage,FindData->cFileName,name,countof(FindData->cFileName)-1);
}
if (file.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
if ((file.permissions&S_IFMT)==S_IFDIR ||
(attr & FILE_ATTRIBUTE_DIRECTORY)!=0)
FindData->dwFileAttributes=FILE_ATTRIBUTE_DIRECTORY;
} else if (completeline[0]=='d')
FindData->dwFileAttributes=FILE_ATTRIBUTE_DIRECTORY;
FindData->cAlternateFileName[0]=0;
FindData->ftCreationTime.dwHighDateTime=0;
FindData->ftCreationTime.dwLowDateTime=0;
FindData->ftLastAccessTime.dwHighDateTime=0;
FindData->ftLastAccessTime.dwLowDateTime=0;
if(file.flags & LIBSSH2_SFTP_ATTR_SIZE && FindData->dwFileAttributes==0) {
FindData->nFileSizeHigh=(DWORD)(file.filesize>>32);
FindData->nFileSizeLow=(DWORD)file.filesize;
} else {
FindData->nFileSizeHigh=0;
FindData->nFileSizeLow=0;
}
if (ConnectSettings->scponly) {
FindData->ftLastWriteTime=datetime;
if (attr & FILE_ATTRIBUTE_DIRECTORY!=0)
FindData->dwFileAttributes|=FILE_ATTRIBUTE_DIRECTORY;
} else if(file.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
__int64 tm=0x019DB1DE;
tm<<=32;
tm|=0xD53E8000;
tm+=(__int64)10000000*file.mtime;
FindData->ftLastWriteTime.dwLowDateTime=(DWORD)tm;
FindData->ftLastWriteTime.dwHighDateTime=(DWORD)(tm>>32);
}
if (file.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
FindData->dwFileAttributes|=0x80000000;
FindData->dwReserved0=file.permissions&0xFFFF; //attributes and format mask
}
return SFTP_OK;
}
return SFTP_FAILED;
}
int SftpFindClose(void* serverid,void* davdataptr)
{
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
LIBSSH2_SFTP_HANDLE *dirhandle;
dirhandle=(LIBSSH2_SFTP_HANDLE*)davdataptr;
if (!dirhandle)
return SFTP_FAILED;
int aborttime=-1;
if (ConnectSettings->scponly) {
SCP_DATA* scpd=(SCP_DATA*)davdataptr;
LIBSSH2_CHANNEL *channel = scpd->channel;
CloseRemote(serverid,NULL,channel,true,100);
} else {
while (LIBSSH2_ERROR_EAGAIN==libssh2_sftp_closedir(dirhandle)) {
int delta=(int)GetTickCount()-ConnectSettings->findstarttime;
if (delta>2000 && aborttime==-1) {
if (ProgressProc(PluginNumber,"close dir","temp",(delta/200)%100))
aborttime=GetTickCount()+2000; // give it 2 seconds to finish properly!
}
delta=(int)GetTickCount()-aborttime;
if (aborttime!=-1 && delta>0) {
ConnectSettings->neednewchannel=true;
break;
}
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
}
return SFTP_OK;
}
int SftpCreateDirectoryW(void* serverid,WCHAR* Path)
{
char dirname[wdirtypemax];
WCHAR dirnamedisp[wdirtypemax];
int rc;
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return SFTP_FAILED;
LoadStr(dirname,IDS_MK_DIR);
awlcopy(dirnamedisp,dirname,wdirtypemax-1);
wcslcat(dirnamedisp,Path,countof(dirnamedisp)-1);
ShowStatusW(dirnamedisp);
if (ConnectSettings->utf8names)
wcslcpytoutf8(dirname,Path,sizeof(dirname)-1);
else
walcopyCP(ConnectSettings->codepage,dirname,Path,sizeof(dirname)-1);
ReplaceBackslashBySlash(dirname);
if (ConnectSettings->scponly) {
char commandbuf[wdirtypemax+8];
LIBSSH2_CHANNEL *channel;
channel=ConnectChannel(ConnectSettings->session);
strlcpy(commandbuf,"mkdir ",sizeof(commandbuf)-1);
BOOL needquotes=strchr(dirname,' ')!=NULL || strchr(dirname,'(')!=NULL || strchr(dirname,')')!=NULL;
if (needquotes)
strlcat(commandbuf,"\"",sizeof(commandbuf)-3);
strlcat(commandbuf,dirname,sizeof(commandbuf)-2);
if (needquotes)
strlcat(commandbuf,"\"",sizeof(commandbuf)-1);
BOOL ok=GetChannelCommandReply(ConnectSettings->session,channel,commandbuf);
DisconnectShell(channel);
return ok?SFTP_OK:SFTP_FAILED;
} else {
int starttime=(int)GetTickCount();
int aborttime=-1;
do {
rc=libssh2_sftp_mkdir(ConnectSettings->sftpsession,dirname,ConnectSettings->dirmod);
Sleep(50);
int delta=(int)GetTickCount()-starttime;
if (delta>2000 && aborttime==-1) {
if (EscapePressed()) // ProgressProc not working in this function!
aborttime=GetTickCount()+2000; // give it 2 seconds to finish properly!
}
delta=(int)GetTickCount()-aborttime;
if (aborttime!=-1 && delta>0) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
if (rc==0) {
// Set mod again, because some servers don't seem to set it automatically
if (ConnectSettings->dirmod != 0755) {
LIBSSH2_SFTP_ATTRIBUTES attr;
attr.flags=LIBSSH2_SFTP_ATTR_PERMISSIONS;
attr.permissions=ConnectSettings->dirmod;
do {
rc=libssh2_sftp_setstat(ConnectSettings->sftpsession,dirname,&attr);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
}
return SFTP_OK;
} else {
char* errmsg;
int errmsg_len;
LoadStr(dirname,IDS_ERR_MK_DIR);
libssh2_session_last_error(ConnectSettings->session, &errmsg, &errmsg_len, false);
strlcat(dirname,errmsg,sizeof(dirname)-1);
ShowStatus(dirname);
return SFTP_FAILED;
}
}
}
int SftpRenameMoveFileW(void* serverid,WCHAR* OldName,WCHAR* NewName,BOOL Move, BOOL Overwrite, BOOL isdir)
{
int rc;
char OldName2[wdirtypemax],NewName2[wdirtypemax],abuf[wdirtypemax];
WCHAR buf[wdirtypemax],OldName2W[wdirtypemax],NewName2W[wdirtypemax];
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return SFTP_FAILED;
if (ConnectSettings->utf8names)
wcslcpytoutf8(OldName2,OldName,sizeof(OldName2)-1);
else
walcopyCP(ConnectSettings->codepage,OldName2,OldName,sizeof(OldName2)-1);
ReplaceBackslashBySlash(OldName2);
if (ConnectSettings->utf8names)
wcslcpytoutf8(NewName2,NewName,sizeof(NewName2)-1);
else
walcopyCP(ConnectSettings->codepage,NewName2,NewName,sizeof(NewName2)-1);
ReplaceBackslashBySlash(NewName2);
if (!Overwrite) {
if (ConnectSettings->scponly) {
wcslcpy(NewName2W,NewName,countof(NewName2W)-1);
ReplaceBackslashBySlashW(NewName2W);
WCHAR cmdname[wdirtypemax+8];
wcslcpy(cmdname,L"stat ",countof(cmdname)-1);
BOOL needquotes2=wcschr(NewName2W,' ')!=NULL || wcschr(NewName2W,'(')!=NULL || wcschr(NewName2W,')')!=NULL;
if (needquotes2)
wcslcat(cmdname,L"\"",countof(cmdname)-1);
wcslcat(cmdname,NewName2W,countof(cmdname)-1);
if (needquotes2)
wcslcat(cmdname,L"\"",countof(cmdname)-1);
if (SftpQuoteCommand2W(serverid,NULL,cmdname,NULL,0)==0) { // file found!
int err=libssh2_session_last_errno(ConnectSettings->session);
return SFTP_EXISTS;
}
} else {
LIBSSH2_SFTP_ATTRIBUTES attr;
do {
rc=libssh2_sftp_lstat(ConnectSettings->sftpsession,NewName2,&attr);
if (EscapePressed())
break;
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
if (rc>=0) { // found!
int err=libssh2_session_last_errno(ConnectSettings->session);
return SFTP_EXISTS;
} else if (rc==LIBSSH2_ERROR_EAGAIN) {
ConnectSettings->neednewchannel=true;
return SFTP_FAILED;
}
}
}
LoadStr(abuf,IDS_RENFR);
awlcopy(buf,abuf,countof(buf)-1);
wcslcat(buf,OldName,countof(buf)-1);
ShowStatusW(buf);
LoadStr(abuf,IDS_RENTO);
awlcopy(buf,abuf,countof(buf)-1);
wcslcat(buf,NewName,countof(buf)-1);
ShowStatusW(buf);
if (Move && !ConnectSettings->scponly) {
do {
rc=libssh2_sftp_rename(ConnectSettings->sftpsession,OldName2,NewName2);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
} else {
WCHAR cmdname[2*wdirtypemax];
// note: SftpQuoteCommand2 already converts from Ansi to UTF-8!!!
wcslcpy(OldName2W,OldName,countof(OldName2W)-1);
ReplaceBackslashBySlashW(OldName2W);
wcslcpy(NewName2W,NewName,countof(NewName2W)-1);
ReplaceBackslashBySlashW(NewName2W);
wcslcpy(cmdname,Move?L"mv ":L"cp ",countof(cmdname)-1);
BOOL needquotes1=wcschr(OldName2W,' ')!=NULL || wcschr(OldName2W,'(')!=NULL || wcschr(OldName2W,')')!=NULL;
BOOL needquotes2=wcschr(NewName2W,' ')!=NULL || wcschr(NewName2W,'(')!=NULL || wcschr(NewName2W,')')!=NULL;
if (needquotes1)
wcslcat(cmdname,L"\"",countof(cmdname)-1);
wcslcat(cmdname,OldName2W,countof(cmdname)-1);
if (needquotes1)
wcslcat(cmdname,L"\"",countof(cmdname)-1);
wcslcat(cmdname,L" ",countof(cmdname)-1);
if (needquotes2)
wcslcat(cmdname,L"\"",countof(cmdname)-1);
wcslcat(cmdname,NewName2W,countof(cmdname)-1);
if (needquotes2)
wcslcat(cmdname,L"\"",countof(cmdname)-1);
if (SftpQuoteCommand2W(serverid,NULL,cmdname,NULL,0)==0) {
return SFTP_OK;
} else
return SFTP_FAILED;
}
if (rc==0)
return SFTP_OK;
else {
char* errmsg;
int errmsg_len;
LoadStr(abuf,IDS_ERR_RENAME);
libssh2_session_last_error(ConnectSettings->session, &errmsg, &errmsg_len, false);
strlcat(abuf,errmsg,sizeof(buf)-1);
ShowStatus(abuf);
return SFTP_FAILED;
}
}
int GetPercent(_int64 offset,_int64 filesize)
{
if (!filesize)
return 0;
int percent=(int)(offset*100/filesize);
if (percent<0) percent=0;
if (percent>100) percent=100;
return percent;
}
int CheckInputOrTimeout(void* serverid,BOOL timeout,DWORD starttime,int percent)
{
int retval=SFTP_OK;
if (timeout) {
if (GetTickCount()-starttime>5000 && UpdatePercentBar(serverid,percent)) {
retval=SFTP_ABORT;
}
if (GetTickCount()-starttime>10000) {
retval=SFTP_FAILED;
}
} else if (EscapePressed()) {
retval=SFTP_ABORT;
}
return retval;
}
int CloseRemote(void* serverid,LIBSSH2_SFTP_HANDLE *remotefilesftp,LIBSSH2_CHANNEL *remotefilescp,BOOL timeout,int percent)
{
int retval=SFTP_OK;
DWORD starttime=GetTickCount();
if (remotefilesftp) {
while (LIBSSH2_ERROR_EAGAIN==libssh2_sftp_close(remotefilesftp)) {
retval=CheckInputOrTimeout(serverid,timeout,starttime,percent);
if (retval!=SFTP_OK)
break;
}
remotefilesftp=NULL;
} else {
while (LIBSSH2_ERROR_EAGAIN==libssh2_channel_send_eof(remotefilescp)) {
retval=CheckInputOrTimeout(serverid,timeout,starttime,percent);
if (retval!=SFTP_OK)
break;
}
while (LIBSSH2_ERROR_EAGAIN==libssh2_channel_free(remotefilescp)) {
retval=CheckInputOrTimeout(serverid,timeout,starttime,percent);
if (retval!=SFTP_OK)
break;
}
remotefilescp=NULL;
}
return retval;
}
#define RECV_BLOCK_SIZE 32768
int ConvertCrToCrLf(char* data,int len,BOOL* pLastWasCr)
{
BOOL LastWasCr=*pLastWasCr; // don't convert 0d0a->0d0d0a!
char data2[RECV_BLOCK_SIZE];
int j=0;
for (int i=0;i<len;i++) {
if (data[i]==0x0d)
LastWasCr=true;
else if (data[i]==0x0a && !LastWasCr) {
data2[j]=0x0d;
j++;
LastWasCr=false;
} else
LastWasCr=false;
data2[j++]=data[i];
}
memcpy(data,&data2,j);
*pLastWasCr=LastWasCr; // remember across blocks!
return j;
}
BOOL SftpDetermineTransferModeW(WCHAR* RemoteName) // true if text mode
{
if (Global_TransferMode=='A')
return true;
else if (Global_TransferMode=='I')
return false;
else { // mode 'auto'
WCHAR* p=wcsrchr(RemoteName,'/');
if (!p)
p=wcsrchr(RemoteName,'\\');
if (!p)
p=RemoteName;
else
p++;
return MultiFileMatchW(Global_TextTypes,p);
}
}
int SftpDownloadFileW(void* serverid,WCHAR* RemoteName,WCHAR* LocalName,BOOL alwaysoverwrite,
_int64 filesize,FILETIME *ft,BOOL Resume)
{
LIBSSH2_SFTP_HANDLE *remotefilesftp=NULL;
HANDLE localfile;
char data[RECV_BLOCK_SIZE];
char filename[wdirtypemax];
_int64 sizeloaded=0;
LIBSSH2_CHANNEL *remotefilescp=NULL;
struct stat fileinfoscp;
_off_t scpremain=0;
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return SFTP_FAILED;
BOOL scpdata=ConnectSettings->scpfordata;
if (scpdata && Resume && !ConnectSettings->scponly) // resume not possible with scp!
scpdata=false;
if (scpdata && filesize>(((__int64)1)<<31) && !ConnectSettings->scponly) // scp supports max 2 GB
scpdata=false;
if (ConnectSettings->utf8names)
wcslcpytoutf8(filename,RemoteName,sizeof(filename)-1);
else
walcopyCP(ConnectSettings->codepage,filename,RemoteName,sizeof(filename)-1);
ReplaceBackslashBySlash(filename);
BOOL TextMode;
TextMode=(ConnectSettings->unixlinebreaks==1) && SftpDetermineTransferModeW(RemoteName);
if (TextMode && Resume)
return SFTP_FAILED;
if (!ReconnectSFTPChannelIfNeeded(ConnectSettings))
return SFTP_FAILED;
if (scpdata) {
char filename2[wdirtypemax];
if (SSH_ScpNeedQuote && strchr(filename,' ')!=0) {
filename2[0]='"';
strlcpy(filename2+1,filename,sizeof(filename2)-3);
strlcat(filename2,"\"",sizeof(filename2)-1);
} else
strlcpy(filename2,filename,sizeof(filename2)-1);
do {
remotefilescp=libssh2_scp_recv(ConnectSettings->session,filename2,&fileinfoscp);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
} while (remotefilescp==0 && libssh2_session_last_errno(ConnectSettings->session)==LIBSSH2_ERROR_EAGAIN);
if (!remotefilescp) {
// Note: It seems that scp sometimes fails to get file names with non-English characters!
BOOL hasnonenglish=false;
for (int i=0;i<(int)wcslen(RemoteName);i++) {
if (RemoteName[i]>127) {
hasnonenglish=true;
break;
}
}
if (hasnonenglish)
scpdata=false;
else
return SFTP_READFAILED;
}
scpremain=fileinfoscp.st_size;
}
if (!scpdata) {
do {
remotefilesftp=libssh2_sftp_open(ConnectSettings->sftpsession,filename,LIBSSH2_FXF_READ,0);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (remotefilesftp==0)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (remotefilesftp==0 && libssh2_session_last_errno(ConnectSettings->session)==LIBSSH2_ERROR_EAGAIN);
if(!remotefilesftp)
return SFTP_READFAILED;
}
if (Resume) {
localfile=CreateFileT(LocalName,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (localfile!=INVALID_HANDLE_VALUE) {
DWORD szh;
sizeloaded=GetFileSize(localfile,&szh);
sizeloaded|=((_int64)szh)<<32;
SetFilePointer(localfile,0,NULL,SEEK_END);
if (filesize<=sizeloaded || sizeloaded>=((__int64)1<<31)-1) { // local file is larger!
CloseHandle(localfile);
if (SFTP_OK!=CloseRemote(serverid,remotefilesftp,remotefilescp,false,0)) {
ConnectSettings->neednewchannel=true;
}
return filesize==sizeloaded ? SFTP_OK : SFTP_WRITEFAILED;
}
}
} else {
localfile=CreateFileT(LocalName,GENERIC_WRITE,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,
alwaysoverwrite ? CREATE_ALWAYS : CREATE_NEW,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
}
if (localfile==INVALID_HANDLE_VALUE) {
if (SFTP_OK!=CloseRemote(serverid,remotefilesftp,remotefilescp,false,0)) {
ConnectSettings->neednewchannel=true;
}
int err=GetLastError();
switch (err) {
case ERROR_ACCESS_DENIED:return SFTP_EXISTS;
case ERROR_SHARING_VIOLATION:return SFTP_EXISTS;
default:return SFTP_WRITEFAILED;
}
}
if (Resume && sizeloaded>0) { // seek!
libssh2_sftp_seek(remotefilesftp,(int)sizeloaded);
// Better check whether seek was successful!
if (libssh2_sftp_tell(remotefilesftp)!=(DWORD)sizeloaded) {
if (SFTP_OK!=CloseRemote(serverid,remotefilesftp,remotefilescp,false,0)) {
ConnectSettings->neednewchannel=true;
}
CloseHandle(localfile);
return SFTP_READFAILED;
}
}
BOOL LastWasCr=false;
char abuf[MAX_PATH];
WCHAR msgbuf[wdirtypemax];
WCHAR *pend;
LoadStr(abuf,IDS_DOWNLOAD);
awlcopy(msgbuf,abuf,wdirtypemax-1);
pend=msgbuf+wcslen(msgbuf);
wcslcat(msgbuf,RemoteName,countof(msgbuf)-1);
ReplaceBackslashBySlashW(msgbuf);
ShowStatusW(msgbuf);
ProgressProcT(PluginNumber,pend,LocalName,0);
int len=0;
int maxblocksize=sizeof(data);
if (TextMode)
maxblocksize/=2; // in worst case, we have all line breaks (0A)
int retval=SFTP_OK;
int aborttime=-1;
do {
if (scpdata) {
if (scpremain<=0)
break;
// Note: We must limit the receive buffer so we don't
// read beyond the length of the file, otherwise we will get 1 byte too much!
len=libssh2_channel_read(remotefilescp,data,min(scpremain,maxblocksize));
if (len>0)
scpremain-=len;
} else
len=libssh2_sftp_read(remotefilesftp,data,maxblocksize);
if (len>0) {
DWORD written;
if (TextMode && sizeloaded==0) { // test first block if it's binary
for (int i=0;i<len;i++)
if (data[i]==0) {
TextMode=false;
break;
}
}
sizeloaded+=len; // the unconverted size!
if (TextMode)
len=ConvertCrToCrLf(data,len,&LastWasCr);
if (!WriteFile(localfile,&data,len,&written,NULL) || (int)written!=len){
retval=SFTP_WRITEFAILED;
break;
}
}
// Always, for aborting!
if (UpdatePercentBar(serverid,GetPercent(sizeloaded,filesize))) {
aborttime=(int)GetTickCount()+2000; // give it 2 seconds to finish properly!
retval=SFTP_ABORT;
}
if (len==LIBSSH2_ERROR_EAGAIN) {
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
len=1;
}
else if (aborttime!=-1)
break;
// if there is no data until the abort time is reached, abort anyway
// this can corrupt the sftp channel, so discard it on the next read
int delta=(int)GetTickCount()-aborttime;
if (aborttime!=-1 && delta>0) {
ConnectSettings->neednewchannel=true;
break;
}
} while (len>0);
int retval2=CloseRemote(serverid,remotefilesftp,remotefilescp,true,GetPercent(sizeloaded,filesize));
if (retval2!=SFTP_OK)
ConnectSettings->neednewchannel=true;
if (retval==SFTP_OK)
retval=retval2;
SetFileTime(localfile,NULL,NULL,ft);
CloseHandle(localfile);
if (len<0)
retval=SFTP_READFAILED;
return retval;
}
#define SEND_BLOCK_SIZE 16384
int ConvertCrLfToCr(char* data,int len) // simply remove all <CR> characters!
{
char data2[SEND_BLOCK_SIZE];
int j=0;
for (int i=0;i<len;i++) {
if (data[i]!=0x0d)
data2[j++]=data[i];
}
memcpy(data,&data2,j);
return j;
}
__int64 GetTextModeFileSize(HANDLE localfile,BOOL entirefile)
{
char data[SEND_BLOCK_SIZE];
__int64 filesize=0;
DWORD len;
while (ReadFile(localfile,&data,sizeof(data),&len,NULL) && len>0) {
DWORD numcrs=0;
for (DWORD i=0;i<len;i++)
if (data[i]==0x0d)
numcrs++;
else if (data[i]==0) {
filesize=-1; // binary -> do not convert!
break;
}
if (filesize==-1 || !entirefile) // just check first block for 0 characters
break;
filesize+=len-numcrs;
}
SetFilePointer(localfile,0,NULL,FILE_BEGIN);
return filesize;
}
DWORD GetTextUploadResumePos(HANDLE localfile,DWORD resumepos)
{
char data[SEND_BLOCK_SIZE];
DWORD localfilesize=0;
DWORD convertedfilesize=0;
DWORD len;
while (ReadFile(localfile,&data,sizeof(data),&len,NULL) && len>0) {
DWORD numcrs=0;
for (DWORD i=0;i<len;i++) {
localfilesize++;
if (data[i]!=0x0d)
convertedfilesize++;
if (convertedfilesize>=resumepos) {
if (convertedfilesize>resumepos)
localfilesize=0xFFFFFFFF;
SetFilePointer(localfile,0,NULL,FILE_BEGIN);
return localfilesize;
}
}
}
SetFilePointer(localfile,0,NULL,FILE_BEGIN);
return 0xFFFFFFFF;
}
int SftpUploadFileW(void* serverid,WCHAR* LocalName,WCHAR* RemoteName,BOOL Resume,BOOL setattr)
{
LIBSSH2_SFTP_HANDLE *remotefilesftp=NULL;
LIBSSH2_CHANNEL *remotefilescp=NULL;
HANDLE localfile;
char data[SEND_BLOCK_SIZE]; // 32k does NOT work!
char thename[wdirtypemax]; // remote name in server encoding
int rc;
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return SFTP_FAILED;
if (ConnectSettings->utf8names)
wcslcpytoutf8(thename,RemoteName,sizeof(thename)-1);
else {
walcopyCP(ConnectSettings->codepage,thename,RemoteName,sizeof(thename)-1);
if (strchr(thename,'?')) {
return SFTP_WRITEFAILED; // invalid remote name
}
}
ReplaceBackslashBySlash(thename);
BOOL TextMode;
TextMode=(ConnectSettings->unixlinebreaks==1) && SftpDetermineTransferModeW(LocalName);
BOOL scpdata=ConnectSettings->scpfordata;
if (scpdata && Resume) // resume not possible with scp!
scpdata=false;
if (!ReconnectSFTPChannelIfNeeded(ConnectSettings))
return SFTP_FAILED;
int retval=SFTP_WRITEFAILED;
char abuf[MAX_PATH];
WCHAR msgbuf[wdirtypemax];
LoadStr(abuf,IDS_UPLOAD);
awlcopy(msgbuf,abuf,wdirtypemax-1);
wcslcat(msgbuf,RemoteName,countof(msgbuf)-1);
ReplaceBackslashBySlashW(msgbuf);
ShowStatusW(msgbuf);
localfile=CreateFileT(LocalName,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (localfile!=INVALID_HANDLE_VALUE) {
DWORD sizehigh;
__int64 sizesent=0;
__int64 filesize=GetFileSize(localfile,&sizehigh);
filesize|=(((__int64)sizehigh)<<32);
__int64 sizeloaded=0;
if (scpdata && filesize>(((__int64)1)<<31)) // scp supports max 2 GB
scpdata=false;
if (scpdata) {
char thename2[wdirtypemax];
if (SSH_ScpNeedQuote && strchr(thename,' ')!=0) {
thename2[0]='"';
strlcpy(thename2+1,thename,sizeof(thename2)-3);
strlcat(thename2,"\"",sizeof(thename2)-1);
} else
strlcpy(thename2,thename,sizeof(thename2)-1);
if (TextMode) {
__int64 filesize2=GetTextModeFileSize(localfile,true);
if (filesize2==-1)
TextMode=false;
else
filesize=filesize2;
}
do {
remotefilescp=libssh2_scp_send_ex(ConnectSettings->session,thename2,ConnectSettings->filemod,(int)filesize,0,0);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
} while (remotefilescp==0 && libssh2_session_last_errno(ConnectSettings->session)==LIBSSH2_ERROR_EAGAIN);
if (!remotefilescp)
return SFTP_READFAILED;
} else {
if (TextMode && -1==GetTextModeFileSize(localfile,false))
TextMode=false;
do {
remotefilesftp=libssh2_sftp_open(ConnectSettings->sftpsession,thename,Resume ? LIBSSH2_FXF_WRITE : LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC,
0644); // ConnectSettings->filemod is ignored!!!
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (remotefilesftp==0)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (remotefilesftp==0 && libssh2_session_last_errno(ConnectSettings->session)==LIBSSH2_ERROR_EAGAIN);
}
if (remotefilescp || remotefilesftp) {
if (Resume) { // seek!
DWORD resumepos=0;
LIBSSH2_SFTP_ATTRIBUTES attr;
memset(&attr,0,sizeof(attr));
attr.flags=LIBSSH2_SFTP_ATTR_PERMISSIONS;
do {
rc=libssh2_sftp_fstat(remotefilesftp,&attr);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
if (rc==0) {
resumepos=(DWORD)attr.filesize;
libssh2_sftp_seek(remotefilesftp,resumepos);
// Better check whether seek was successful!
if (libssh2_sftp_tell(remotefilesftp)!=resumepos) {
if (SFTP_OK!=CloseRemote(serverid,remotefilesftp,remotefilescp,false,0)) {
ConnectSettings->neednewchannel=true;
}
CloseHandle(localfile);
return SFTP_WRITEFAILED;
}
if (Resume && TextMode) {
resumepos=GetTextUploadResumePos(localfile,resumepos);
}
if (resumepos==0xFFFFFFFF || resumepos!=SetFilePointer(localfile,resumepos,NULL,SEEK_SET)) {
if (SFTP_OK!=CloseRemote(serverid,remotefilesftp,remotefilescp,false,0)) {
ConnectSettings->neednewchannel=true;
}
CloseHandle(localfile);
return SFTP_WRITEFAILED;
}
sizeloaded=resumepos;
} else
Resume=false;
}
// Switch back to blocking mode, because libssh2_channel_write is faulty in non-blocking mode!!!
BOOL needblockingmode=scpdata && SSH_ScpNeedBlockingMode;
if (needblockingmode) {
SetBlockingSocket(ConnectSettings->sock,true);
libssh2_channel_set_blocking(remotefilescp,1);
libssh2_session_set_blocking(ConnectSettings->session, 1);
}
DWORD starttime;
DWORD len;
retval=SFTP_OK;
while (ReadFile(localfile,&data,sizeof(data),&len,NULL) && len>0) {
int dataread,written;
dataread=len;
char* pdata=data;
if (TextMode)
len=ConvertCrLfToCr(data,len);
do {
if (scpdata)
written=libssh2_channel_write(remotefilescp,pdata,len);
else
written=libssh2_sftp_write(remotefilesftp,pdata,len);
if (written>=0) {
if (written>(int)len) { // libssh2_channel_write sometiomes returns values > len!
retval=SFTP_WRITEFAILED;
// return to non-blocking mode
if (needblockingmode) {
SetBlockingSocket(ConnectSettings->sock,false);
libssh2_channel_set_blocking(remotefilescp,0);
libssh2_session_set_blocking(ConnectSettings->session, 0);
}
written=-1;
break;
}
pdata+=written;
len-=written;
if (len==0)
sizeloaded+=dataread; // not the converted size!
} else if (written!=LIBSSH2_ERROR_EAGAIN) // error?
len=0;
else {
if (!IsSocketWritable(ConnectSettings->sock)) // sleep to avoid 100% CPU!
Sleep(10);
}
if (UpdatePercentBar(serverid,GetPercent(sizeloaded,filesize))) {
// graceful abort if last reply was EAGAIN
starttime=GetTickCount();
while (written==LIBSSH2_ERROR_EAGAIN) {
if (scpdata)
written=libssh2_channel_write(remotefilescp,pdata,len);
else
written=libssh2_sftp_write(remotefilesftp,pdata,len);
if (GetTickCount()-starttime>5000)
break;
IsSocketWritable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
written=-1;
retval=SFTP_ABORT;
break;
}
} while (written==LIBSSH2_ERROR_EAGAIN || len>0);
if(written<0) {
if (retval!=SFTP_ABORT)
retval=SFTP_WRITEFAILED;
break;
}
}
int retval2=CloseRemote(serverid,remotefilesftp,remotefilescp,true,GetPercent(sizeloaded,filesize));
if (retval2!=SFTP_OK)
ConnectSettings->neednewchannel=true;
if (retval==SFTP_OK)
retval=retval2;
if (needblockingmode) {
// return to non-blocking mode
SetBlockingSocket(ConnectSettings->sock,false);
libssh2_session_set_blocking(ConnectSettings->session, 0);
}
if (retval==SFTP_OK) {
LIBSSH2_SFTP_ATTRIBUTES attr;
FILETIME ft;
// set modification time ONLY if target didn't exist yet!!!
memset(&attr,0,sizeof(attr));
attr.flags=LIBSSH2_SFTP_ATTR_ACMODTIME | (setattr ? LIBSSH2_SFTP_ATTR_PERMISSIONS:0);
if (GetFileTime(localfile,NULL,NULL,&ft)) {
__int64 tm2=ft.dwHighDateTime;
tm2<<=32;
tm2|=ft.dwLowDateTime;
__int64 tm=0x019DB1DE;
tm<<=32;
tm|=0xD53E8000;
tm2-=tm;
attr.mtime=(DWORD)(tm2/(__int64)10000000);
attr.atime=attr.mtime;
attr.permissions=ConnectSettings->filemod;
}
while (LIBSSH2_ERROR_EAGAIN==libssh2_sftp_setstat(ConnectSettings->sftpsession,
thename,&attr)) {
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
}
} else
retval=SFTP_WRITEFAILED;
CloseHandle(localfile);
}
return retval;
}
int SftpDeleteFileW(void* serverid,WCHAR* RemoteName,BOOL isdir)
{
char dirname[wdirtypemax],abuf[wdirtypemax];
WCHAR buf[wdirtypemax];
int rc;
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return SFTP_FAILED;
if (ConnectSettings->utf8names)
wcslcpytoutf8(dirname,RemoteName,sizeof(dirname)-1);
else
walcopyCP(ConnectSettings->codepage,dirname,RemoteName,sizeof(dirname)-1);
ReplaceBackslashBySlash(dirname);
if (strcmp(dirname,"/~")==0) // go to home dir special link
return SFTP_FAILED;
LoadStr(abuf,IDS_DELETE);
awlcopy(buf,abuf,countof(buf)-1);
wcslcat(buf,RemoteName,sizeof(buf)-1);
ShowStatusW(buf);
if (ConnectSettings->scponly) {
char commandbuf[wdirtypemax+8];
LIBSSH2_CHANNEL *channel;
channel=ConnectChannel(ConnectSettings->session);
if (isdir)
strlcpy(commandbuf,"rmdir ",sizeof(commandbuf)-1);
else
strlcpy(commandbuf,"rm ",sizeof(commandbuf)-1);
BOOL needquotes=strchr(dirname,' ')!=NULL || strchr(dirname,'(')!=NULL || strchr(dirname,')')!=NULL;
if (needquotes)
strlcat(commandbuf,"\"",sizeof(commandbuf)-3);
strlcat(commandbuf,dirname,sizeof(commandbuf)-2);
if (needquotes)
strlcat(commandbuf,"\"",sizeof(commandbuf)-1);
BOOL ok=GetChannelCommandReply(ConnectSettings->session,channel,commandbuf);
DisconnectShell(channel);
return ok?SFTP_OK:SFTP_FAILED;
} else {
int starttime=(int)GetTickCount();
int aborttime=-1;
do {
if (isdir)
rc=libssh2_sftp_rmdir(ConnectSettings->sftpsession,dirname);
else
rc=libssh2_sftp_unlink(ConnectSettings->sftpsession,dirname);
int delta=(int)GetTickCount()-starttime;
if (delta>2000 && aborttime==-1) {
if (ProgressProcT(PluginNumber,buf,L"delete",(delta/200)%100))
aborttime=GetTickCount()+2000; // give it 2 seconds to finish properly!
}
delta=(int)GetTickCount()-aborttime;
if (aborttime!=-1 && delta>0) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
if (rc==0)
return SFTP_OK;
else {
char* errmsg;
int errmsg_len;
LoadStr(abuf,IDS_ERR_DELETE);
libssh2_session_last_error(ConnectSettings->session, &errmsg, &errmsg_len, false);
awlcopy(buf,abuf,countof(buf)-1);
awlcopy(buf+wcslen(buf),errmsg,countof(buf)-wcslen(buf)-1);
wcslcat(buf,L" ",countof(buf)-1);
wcslcat(buf,RemoteName,countof(buf)-1);
ShowStatusW(buf);
return SFTP_FAILED;
}
}
}
int SftpSetAttr(void* serverid,char* RemoteName,int NewAttr)
{
return SFTP_FAILED;
}
int SftpSetDateTimeW(void* serverid,WCHAR* RemoteName,FILETIME *LastWriteTime)
{
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return SFTP_FAILED;
int rc=0;
WCHAR msgbuf[wdirtypemax];
char filename[wdirtypemax];
if (ConnectSettings->utf8names)
wcslcpytoutf8(filename,RemoteName,sizeof(filename)-1);
else
walcopyCP(ConnectSettings->codepage,filename,RemoteName,sizeof(filename)-1);
ReplaceBackslashBySlash(filename);
wcslcpy(msgbuf,L"Set date/time for: ",countof(msgbuf)-1);
wcslcat(msgbuf,RemoteName,countof(msgbuf)-1);
ReplaceBackslashBySlashW(msgbuf);
ShowStatusW(msgbuf);
// touch -t 201501311530.21 test.py
if (ConnectSettings->scponly) {
SYSTEMTIME tdt={0};
FILETIME lft;
char commandbuf[wdirtypemax+32];
LIBSSH2_CHANNEL *channel;
channel=ConnectChannel(ConnectSettings->session);
FileTimeToLocalFileTime(LastWriteTime,&lft);
FileTimeToSystemTime(&lft,&tdt);
#ifdef sprintf_s
sprintf_s(commandbuf,sizeof(commandbuf),"touch -t %04d%02d%02d%02d%02d.%02d ",tdt.wYear,tdt.wMonth,tdt.wDay,tdt.wHour,tdt.wMinute,tdt.wSecond);
#else
sprintf(commandbuf,"touch -t %04d%02d%02d%02d%02d.%02d ",tdt.wYear,tdt.wMonth,tdt.wDay,tdt.wHour,tdt.wMinute,tdt.wSecond);
#endif
BOOL needquotes=strchr(filename,' ')!=NULL || strchr(filename,'(')!=NULL || strchr(filename,')')!=NULL;
if (needquotes)
strlcat(commandbuf,"\"",sizeof(commandbuf)-3);
strlcat(commandbuf,filename,sizeof(commandbuf)-2);
if (needquotes)
strlcat(commandbuf,"\"",sizeof(commandbuf)-1);
BOOL ok=GetChannelCommandReply(ConnectSettings->session,channel,commandbuf);
DisconnectShell(channel);
return ok?SFTP_OK:SFTP_FAILED;
} else {
LIBSSH2_SFTP_ATTRIBUTES attr;
attr.flags=LIBSSH2_SFTP_ATTR_ACMODTIME;
__int64 tm2=LastWriteTime->dwHighDateTime;
tm2<<=32;
tm2|=LastWriteTime->dwLowDateTime;
__int64 tm=0x019DB1DE;
tm<<=32;
tm|=0xD53E8000;
tm2-=tm;
attr.mtime=(DWORD)(tm2/(__int64)10000000);
attr.atime=attr.mtime;
do {
rc=libssh2_sftp_setstat(ConnectSettings->sftpsession,filename,&attr);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
if (rc)
return SFTP_FAILED;
else
return SFTP_OK;
}
}
BOOL SftpChmodW(void* serverid,WCHAR* RemoteName,WCHAR* chmod)
{
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return SFTP_FAILED;
int rc=0;
WCHAR msgbuf[wdirtypemax];
char filename[wdirtypemax];
if (ConnectSettings->utf8names)
wcslcpytoutf8(filename,RemoteName,sizeof(filename)-1);
else
walcopyCP(ConnectSettings->codepage,filename,RemoteName,sizeof(filename)-1);
ReplaceBackslashBySlash(filename);
wcslcpy(msgbuf,L"Set attributes for: ",countof(msgbuf)-1);
wcslcat(msgbuf,RemoteName,countof(msgbuf)-1);
ReplaceBackslashBySlashW(msgbuf);
ShowStatusW(msgbuf);
LIBSSH2_SFTP_ATTRIBUTES attr;
attr.flags=LIBSSH2_SFTP_ATTR_PERMISSIONS;
attr.permissions=(chmod[0]-'0')*8*8+(chmod[1]-'0')*8+(chmod[2]-'0');
// 4 digits? -> use command line because libssh2_sftp_setstat fails to set extended attributes!
// also when not using SFTP subsystem
if (ConnectSettings->scponly || (chmod[3]>='0' && chmod[3]<='9')) {
char reply[wdirtypemax];
wcslcpy(msgbuf,L"chmod ",countof(msgbuf)-1);
wcslcat(msgbuf,chmod,countof(msgbuf));
wcslcat(msgbuf,L" ",countof(msgbuf));
BOOL needquotes=wcschr(RemoteName,' ')!=NULL || wcschr(RemoteName,'(')!=NULL || wcschr(RemoteName,')')!=NULL;
if (needquotes)
wcslcat(msgbuf,L"\"",countof(msgbuf)-1);
wcslcat(msgbuf,RemoteName,countof(msgbuf)-2);
ReplaceBackslashBySlashW(msgbuf);
if (needquotes)
wcslcat(msgbuf,L"\"",countof(msgbuf)-1);
reply[0]=0;
return SftpQuoteCommand2W(serverid,NULL,msgbuf,reply,sizeof(reply)-1)>=0;
}
do {
rc=libssh2_sftp_setstat(ConnectSettings->sftpsession,filename,&attr);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
if (rc)
return false;
else
return true;
}
BOOL SftpLinkFolderTargetW(void* serverid,WCHAR* RemoteName,int maxlen)
{
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return false;
int rc=0;
WCHAR msgbuf[wdirtypemax];
char filename[wdirtypemax];
if (ConnectSettings->utf8names)
wcslcpytoutf8(filename,RemoteName,sizeof(filename)-1);
else
walcopyCP(ConnectSettings->codepage,filename,RemoteName,sizeof(filename)-1);
ReplaceBackslashBySlash(filename);
wcslcpy(msgbuf,L"Follow link: ",sizeof(msgbuf)-1);
wcslcat(msgbuf,RemoteName,sizeof(msgbuf)-1);
ReplaceBackslashBySlashW(msgbuf);
ShowStatusW(msgbuf);
if (strcmp(filename,"/~")==0 || strcmp(filename,"/home/~")==0) { // go to home dir special link
char ReturnedName[wdirtypemax];
WCHAR cmdname[MAX_PATH];
wcslcpy(cmdname,L"echo $HOME",countof(cmdname)-1);
ReturnedName[0]=0;
if (SftpQuoteCommand2W(ConnectSettings,NULL,cmdname,ReturnedName,wdirtypemax-1)==0 && ReturnedName[0]=='/') {
char* p=strchr(ReturnedName,'\r');
if (p)
p[0]=0;
p=strchr(ReturnedName,'\n');
if (p)
p[0]=0;
ReplaceSlashByBackslash(ReturnedName);
} else {
strlcpy(ReturnedName,"\\home\\",min(maxlen,wdirtypemax));
strlcat(ReturnedName,ConnectSettings->user,min(maxlen,wdirtypemax));
}
if (ConnectSettings->utf8names) {
UTF8* srcstart=(UTF8*)ReturnedName;
UTF16* trgstart=(UTF16*)RemoteName;
ConvertUTF8toUTF16(&srcstart,srcstart+strlen(ReturnedName)+1,
&trgstart,trgstart+maxlen-1);
} else
awlcopyCP(ConnectSettings->codepage,RemoteName,ReturnedName,maxlen);
return true;
} else {
// first check whether the link really points to a directory:
LIBSSH2_SFTP_ATTRIBUTES attr;
rc=-1;
do {
// stat requests the info of the link target
attr.flags=LIBSSH2_SFTP_ATTR_PERMISSIONS;
rc=libssh2_sftp_stat(ConnectSettings->sftpsession,filename,&attr);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
if (rc!=0 || (attr.permissions&S_IFMT)!=S_IFDIR) // not found
return false;
char linktarget[wdirtypemax];
do {
rc=libssh2_sftp_readlink(ConnectSettings->sftpsession,filename,linktarget,sizeof(linktarget)-2);
if (EscapePressed()) {
ConnectSettings->neednewchannel=true;
break;
}
if (rc==LIBSSH2_ERROR_EAGAIN)
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
} while (rc==LIBSSH2_ERROR_EAGAIN);
if (rc<=0) // it returns the length of the link target!
return false;
else {
WCHAR linktargetW[wdirtypemax];
linktarget[rc]=0;
if (ConnectSettings->utf8names) {
UTF8* srcstart=(UTF8*)linktarget;
UTF16* trgstart=(UTF16*)linktargetW;
ConvertUTF8toUTF16(&srcstart,(UTF8*)linktarget+strlen(linktarget)+1,
&trgstart,trgstart+wdirtypemax-1);
} else
awlcopyCP(ConnectSettings->codepage,linktargetW,linktarget,wdirtypemax-1);
// handle the case of relative links!
if (linktargetW[0]!='/') {
ReplaceSlashByBackslashW(RemoteName);
WCHAR* p=wcsrchr(RemoteName,'\\');
if (p) // cut off the name of the link itself!
p[0]=0;
wcslcat(RemoteName,L"\\",maxlen);
wcslcat(RemoteName,linktargetW,maxlen);
} else
wcslcpy(RemoteName,linktargetW,maxlen);
return true;
}
}
}
BOOL isnumeric(char ch)
{
return (ch>='0' && ch<='9');
}
void StripEscapeSequences(char *msgbuf)
{
char* pin=msgbuf;
char* pout=msgbuf;
while (pin[0]) {
if (pin[0]==0x1B) { // escape!
// search for 0 or 'm'
pin++;
while (pin[0] && pin[0]!='m')
pin++;
if (pin[0]==0)
break;
pin++;
} else if (pin[0]=='\\' && isnumeric(pin[1]) && isnumeric(pin[2]) && isnumeric(pin[3])) {
// special characters are encoded in octal: \123
char nrbuf[4];
strlcpy(nrbuf,pin+1,3);
pout++[0]=(char)strtol(nrbuf,NULL,8);
pin+=4;
} else
pout++[0]=pin++[0];
}
pout[0]=0;
}
void DisconnectShell(LIBSSH2_CHANNEL *channel)
{
while (libssh2_channel_free(channel)==LIBSSH2_ERROR_EAGAIN) {
if (EscapePressed())
break;
}
}
LIBSSH2_CHANNEL* ConnectChannel(LIBSSH2_SESSION *session)
{
LIBSSH2_CHANNEL *channel;
if (!session)
return NULL;
do {
channel = libssh2_channel_open_session(session);
if (EscapePressed())
break;
} while (!channel && libssh2_session_last_errno(session)==LIBSSH2_ERROR_EAGAIN);
if (!channel) {
ShowStatus("Unable to open a session");
return NULL;
}
libssh2_channel_set_blocking(channel,0);
return channel;
}
BOOL SendChannelCommand(LIBSSH2_SESSION *session,LIBSSH2_CHANNEL *channel,char* command)
{
int rc=-1;
do {
rc=libssh2_channel_exec(channel, command);
if (rc<0) {
if (rc==-1)
rc=libssh2_session_last_errno(session);
if (rc!=LIBSSH2_ERROR_EAGAIN)
break;
}
if (EscapePressed())
break;
} while (rc<0);
while (libssh2_channel_flush(channel)==LIBSSH2_ERROR_EAGAIN) {
if (EscapePressed())
break;
}
while (libssh2_channel_send_eof(channel)==LIBSSH2_ERROR_EAGAIN) {
if (EscapePressed())
break;
}
return rc>=0;
}
BOOL GetChannelCommandReply(LIBSSH2_SESSION *session,LIBSSH2_CHANNEL *channel,char* command)
{
BOOL hasstderr=false;
if (!SendChannelCommand(session,channel,command))
return false;
while (!libssh2_channel_eof(channel)) {
char buf[1024];
if (0<libssh2_channel_read_stderr(channel, buf, sizeof(buf)-1))
hasstderr=true;
libssh2_channel_read(channel, buf, sizeof(buf)-1);
if (EscapePressed())
break;
}
return 0==libssh2_channel_get_exit_status(channel) && !hasstderr;
}
BOOL onlylinebreaks(char* msgbuf)
{
BOOL onlylinebreaks2=true;
while (msgbuf[0]) {
if (msgbuf[0]!='\r' && msgbuf[0]!='\n') {
onlylinebreaks2=false;
break;
}
msgbuf++;
}
return onlylinebreaks2;
}
BOOL ReadChannelLine(LIBSSH2_CHANNEL *channel,char *line,int linelen,char* msgbuf,int msgbuflen,char* errbuf,int errbuflen)
{
int rc,rcerr;
DWORD startdatatime=GetTickCount();
DWORD lastdatatime=startdatatime;
BOOL endreceived=false;
BOOL detectingcrlf=true;
do {
// we need to read from both, otherwise eof will not become true!
int prevlen=(int)strlen(msgbuf);
int remain=msgbuflen-prevlen;
int remainerr=errbuflen-(int)strlen(errbuf);
char* perr=errbuf+strlen(errbuf); // errbuf contains previously received error data
char* p=msgbuf+strlen(msgbuf); // msgbuf contains previously received data!!!
if (libssh2_channel_eof(channel)) { // end signal AND no more data!
endreceived=true;
}
rcerr=libssh2_channel_read_stderr(channel, perr, remainerr);
rc=libssh2_channel_read(channel, p, remain);
if (EscapePressed())
break;
if (rcerr>0) {
perr[rcerr]=0;
perr+=rcerr;
remainerr-=rcerr;
}
if (rc>=0 || prevlen>0) {
lastdatatime=GetTickCount();
if (rc>=0)
p[rc]=0;
char* p1;
p1=strchr(msgbuf,'\n');
if (p1) {
int l;
p1[0]=0;
p1++;
l=(int)strlen(msgbuf);
if (l && msgbuf[l-1]=='\r') {
if (detectingcrlf && global_detectcrlf==-1)
global_detectcrlf=1;
msgbuf[l-1]=0;
} else if (detectingcrlf && global_detectcrlf==-1)
global_detectcrlf=0;
strlcpy(line,msgbuf,linelen);
StripEscapeSequences(line);
char* p0=msgbuf;
memmove(p0,p1,strlen(p1)+1);
return true;
} else
p1=NULL;
} else if (rc==LIBSSH2_ERROR_EAGAIN) {
Sleep(50);
DWORD thisdatatime=GetTickCount();
if (thisdatatime-lastdatatime<1000 ||
thisdatatime-startdatatime<5000)
rc=1;
}
if (endreceived && rc<=0 && rc!=LIBSSH2_ERROR_EAGAIN) {
if (msgbuf[0] && !onlylinebreaks(msgbuf)) {
if (detectingcrlf) { // only append it once - do not use this appended to detect!
detectingcrlf=false;
strlcat(msgbuf,"\r\n",sizeof(msgbuf)-1);
}
} else {
return false;
}
}
} while (true);
return false;
}
void SftpSetTransferModeW(WCHAR* mode)
{
Global_TransferMode=(char)CharUpperW((LPWSTR)mode[0]);
if (Global_TransferMode=='X')
wcslcpy(Global_TextTypes,mode+1,countof(Global_TextTypes)-1);
}
// returns -1 for error, >=0 is the return value of the called function
int SftpQuoteCommand2(void* serverid,char* remotedir,char* cmd,char* reply,int replylen)
{
LIBSSH2_CHANNEL *channel=NULL;
if (reply && replylen)
reply[0]=0;
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return -1;
int rc=0;
char msgbuf[1024];
char line[1024];
char dirname[wdirtypemax],cmdname[wdirtypemax];
dirname[0]=0;
if (ConnectSettings->utf8names) {
if (remotedir)
strlcpyansitoutf8(dirname,remotedir,sizeof(dirname)-1);
strlcpyansitoutf8(cmdname,cmd,sizeof(cmdname)-1);
} else {
if (remotedir)
strlcpy(dirname,remotedir,sizeof(dirname)-1);
strlcpy(cmdname,cmd,sizeof(cmdname)-1);
}
ReplaceBackslashBySlash(dirname);
strlcpy(msgbuf,"Quote: ",sizeof(msgbuf)-1);
strlcat(msgbuf,cmd,sizeof(msgbuf)-1);
ReplaceBackslashBySlash(msgbuf);
ShowStatus(msgbuf);
channel=ConnectChannel(ConnectSettings->session);
if (!channel)
return -1;
// first set the current directory!
if (remotedir) {
strlcpy(msgbuf,"cd ",sizeof(msgbuf));
BOOL needquotes=strchr(dirname,' ')!=NULL || strchr(dirname,'(')!=NULL || strchr(dirname,')')!=NULL;
if (needquotes)
strlcat(msgbuf,"\"",sizeof(msgbuf)-1);
strlcat(msgbuf,dirname,sizeof(msgbuf)-2);
if (needquotes)
strlcat(msgbuf,"\"",sizeof(msgbuf)-1);
strlcat(msgbuf," && ",sizeof(msgbuf)-2);
} else
msgbuf[0]=0;
// then send the actual command!
strlcat(msgbuf,cmdname,sizeof(msgbuf)-2);
if (!SendChannelCommand(ConnectSettings->session,channel,msgbuf)) {
DisconnectShell(channel);
return -1;
}
char errbuf[2048];
msgbuf[0]=0;
errbuf[0]=0;
while (ReadChannelLine(channel,line,sizeof(line)-1,msgbuf,sizeof(msgbuf)-1,errbuf,sizeof(errbuf)-1)) {
StripEscapeSequences(line);
if (!reply) {
ShowStatus(line);
} else {
if (reply[0])
strlcat(reply,"\r\n",replylen-1);
strlcat(reply,line,replylen-1);
}
}
rc=libssh2_channel_get_exit_status(channel);
if (rc!=0) { // read stderr
#ifdef sprintf_s
sprintf_s(msgbuf,sizeof(msgbuf),"Function return code: %d",rc);
#else
sprintf(msgbuf,"Function return code: %d",rc);
#endif
ShowStatus(msgbuf);
if (errbuf[0]) {
StripEscapeSequences(errbuf);
char* p=errbuf;
if (strncmp(p,"stdin: is not a tty",19)==0) {
p+=19;
while (p[0]=='\r' || p[0]=='\n')
p++;
}
ShowStatus(p);
if (reply) {
if (reply[0])
strlcat(reply,"\r\n",replylen);
strlcat(reply,p,replylen);
}
}
}
while (libssh2_channel_free(channel)==LIBSSH2_ERROR_EAGAIN) {
if (EscapePressed())
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
if (rc<0)
rc=1;
return rc;
}
// returns -1 for error, >=0 is the return value of the called function
int SftpQuoteCommand2W(void* serverid,WCHAR* remotedir,WCHAR* cmd,char* reply,int replylen)
{
LIBSSH2_CHANNEL *channel=NULL;
if (reply && replylen)
reply[0]=0;
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return -1;
int rc=0;
char msgbuf[2*wdirtypemax];
WCHAR msgbufW[wdirtypemax];
char line[2*wdirtypemax];
char dirname[wdirtypemax],cmdname[wdirtypemax];
dirname[0]=0;
if (ConnectSettings->utf8names) {
if (remotedir)
wcslcpytoutf8(dirname,remotedir,sizeof(dirname)-1);
wcslcpytoutf8(cmdname,cmd,sizeof(cmdname)-1);
} else {
if (remotedir)
walcopyCP(ConnectSettings->codepage,dirname,remotedir,sizeof(dirname)-1);
walcopyCP(ConnectSettings->codepage,cmdname,cmd,sizeof(cmdname)-1);
}
ReplaceBackslashBySlash(dirname);
wcslcpy(msgbufW,L"Quote: ",countof(msgbufW)-1);
wcslcat(msgbufW,cmd,countof(msgbufW)-1);
ReplaceBackslashBySlashW(msgbufW);
ShowStatusW(msgbufW);
channel=ConnectChannel(ConnectSettings->session);
if (!channel)
return -1;
// first set the current directory!
if (remotedir) {
strlcpy(msgbuf,"cd ",sizeof(msgbuf)-1);
BOOL needquotes=strchr(dirname,' ')!=NULL || strchr(dirname,'(')!=NULL || strchr(dirname,')')!=NULL;
if (needquotes)
strlcat(msgbuf,"\"",sizeof(msgbuf)-1);
strlcat(msgbuf,dirname,sizeof(msgbuf)-3);
if (needquotes)
strlcat(msgbuf,"\"",sizeof(msgbuf)-1);
strlcat(msgbuf," && ",sizeof(msgbuf)-3);
} else
msgbuf[0]=0;
// then send the actual command!
strlcat(msgbuf,cmdname,sizeof(msgbuf)-3);
if (!SendChannelCommand(ConnectSettings->session,channel,msgbuf)) {
DisconnectShell(channel);
return -1;
}
char errbuf[2048];
msgbuf[0]=0;
errbuf[0]=0;
DWORD starttime=GetCurrentTime();
DWORD lasttime=starttime;
int loop=0;
while (ReadChannelLine(channel,line,sizeof(line)-1,msgbuf,sizeof(msgbuf)-1,errbuf,sizeof(errbuf)-1)) {
StripEscapeSequences(line);
if (!reply) {
ShowStatus(line);
} else {
if (reply[0])
strlcat(reply,"\r\n",replylen);
strlcat(reply,line,replylen);
}
if (GetCurrentTime()-starttime>2000)
if (ProgressLoop("QUOTE",0,100,&loop,&lasttime))
break;
}
rc=libssh2_channel_get_exit_status(channel);
if (rc!=0) { // read stderr
#ifdef sprintf_s
sprintf_s(msgbuf,sizeof(msgbuf),"Function return code: %d",rc);
#else
sprintf(msgbuf,"Function return code: %d",rc);
#endif
ShowStatus(msgbuf);
if (errbuf[0]) {
StripEscapeSequences(errbuf);
char* p=errbuf;
if (strncmp(p,"stdin: is not a tty",19)==0) {
p+=19;
while (p[0]=='\r' || p[0]=='\n')
p++;
}
ShowStatus(p);
if (reply) {
if (reply[0])
strlcat(reply,"\r\n",replylen);
strlcat(reply,p,replylen);
}
}
}
while (libssh2_channel_free(channel)==LIBSSH2_ERROR_EAGAIN) {
if (EscapePressed())
break;
IsSocketReadable(ConnectSettings->sock); // sleep to avoid 100% CPU!
}
if (rc<0)
rc=1;
return rc;
}
BOOL SftpQuoteCommand(void* serverid,char* remotedir,char* cmd)
{
return (SftpQuoteCommand2(serverid,remotedir,cmd,NULL,0)>=0);
}
char* FindStatString(char* searchin,char* searchfor,char* deletedchar)
{
char* p,*p2;
deletedchar[0]=0;
p=strstr(searchin,searchfor);
if (p) {
p+=strlen(searchfor);
while (p[0]==' ') p++;
if (p[0]=='(') {
p++;
p2=p+1;
while (strchr(")\r\n",p2[0])==NULL && p2[0]!=0)
p2++;
} else if (p[0]=='\'' || p[0]=='`' || p[0]=='"') { // Link: `file' -> `target'
p2=p+1;
while (strchr("\"'`\r\n",p2[0])==NULL && p2[0]!=0)
p2++;
p2++;
if (strncmp(p2," -> ",4)==0) {
p2+=5;
while (strchr("\"'`\r\n",p2[0])==NULL && p2[0]!=0)
p2++;
p2++;
}
} else {
p2=p+1;
while (strchr(" \r\n",p2[0])==NULL && p2[0]!=0)
p2++;
}
deletedchar[0]=p2[0];
p2[0]=0;
}
return p;
}
WCHAR* FindStatStringW(WCHAR* searchin,WCHAR* searchfor,WCHAR* deletedchar)
{
WCHAR* p,*p2;
deletedchar[0]=0;
p=wcsstr(searchin,searchfor);
if (p) {
p+=wcslen(searchfor);
while (p[0]==' ') p++;
if (p[0]=='(') {
p++;
p2=p+1;
while (wcschr(L")\r\n",p2[0])==NULL && p2[0]!=0)
p2++;
} else if (p[0]=='\'' || p[0]=='`' || p[0]=='"') { // Link: `file' -> `target'
p2=p+1;
while (wcschr(L"\"'`\r\n",p2[0])==NULL && p2[0]!=0)
p2++;
p2++;
if (wcsncmp(p2,L" -> ",4)==0) {
p2+=5;
while (wcschr(L"\"'`\r\n",p2[0])==NULL && p2[0]!=0)
p2++;
p2++;
}
} else {
p2=p+1;
while (wcschr(L" \r\n",p2[0])==NULL && p2[0]!=0)
p2++;
}
deletedchar[0]=p2[0];
p2[0]=0;
}
return p;
}
WCHAR* g_statreplyW;
WCHAR* g_filenameW;
char* g_statreplyA;
BOOL g_command_ls;
myint __stdcall PropDlgProc(HWND hWnd,unsigned int Message,WPARAM wParam,LPARAM lParam)
{
RECT rt1,rt2;
int w,h,DlgWidth,DlgHeight,NewPosX,NewPosY;
char *p,*p2;
switch (Message) {
case WM_INITDIALOG: {
char ch;
WCHAR chw,*wp;
HDC dc=GetDC(hWnd);
HFONT fixedfont=CreateFont(-MulDiv(8, GetDeviceCaps(dc, LOGPIXELSY), 72),0,0,0,FW_NORMAL,0,0,0,DEFAULT_CHARSET,
OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FIXED_PITCH | FF_DONTCARE,"Courier New");
ReleaseDC(hWnd,dc);
if (fixedfont)
SendDlgItemMessage(hWnd,IDC_PROP_RAWSTAT,WM_SETFONT,(WPARAM)fixedfont,true);
if (usys())
SetDlgItemTextW(hWnd,IDC_PROP_RAWSTAT,g_statreplyW);
else
SetDlgItemText(hWnd,IDC_PROP_RAWSTAT,g_statreplyA);
if (!g_command_ls) {
if (usys()) {
WCHAR *wp;
wp=FindStatStringW(g_statreplyW,L"File:",&chw);
if (wp) {
SetDlgItemTextW(hWnd,IDC_PROP_NAME,wp);
wp[wcslen(wp)]=chw;
}
} else {
p=FindStatString(g_statreplyA,"File:",&ch);
if (p) {
SetDlgItemText(hWnd,IDC_PROP_NAME,p);
p[strlen(p)]=ch;
}
}
p=FindStatString(g_statreplyA,"Size:",&ch);
if (p) {
SetDlgItemText(hWnd,IDC_PROP_SIZE,p);
p[strlen(p)]=ch;
}
p=FindStatString(g_statreplyA,"Access:",&ch);
if (p) {
SetDlgItemText(hWnd,IDC_PROP_PERMISSIONS,p);
p[strlen(p)]=ch;
}
p=FindStatString(g_statreplyA,"Uid:",&ch);
if (p) {
SetDlgItemText(hWnd,IDC_PROP_OWNER,p);
p[strlen(p)]=ch;
}
p=FindStatString(g_statreplyA,"Gid:",&ch);
if (p) {
SetDlgItemText(hWnd,IDC_PROP_GROUP,p);
p[strlen(p)]=ch;
}
p=FindStatString(g_statreplyA,"Modify:",&ch);
if (p) {
int timezone=0;
int tzhours,tzminutes;
SYSTEMTIME tdt={0};
FILETIME ft,lft;
p[strlen(p)]=ch;
char* p2=strchr(p,'\n'); // contains spaces!!!
if (p2)
p2[0]=0;
// is it in ISO format? -> If yes, calculate local time!
// 2008-08-17 12:51:55.000000000 -0400
if (strlen(p)>20 && p[4]=='-' && p[7]=='-' && p[10]==' ' && p[13]==':' && p[16]==':' && p[19]=='.') {
p[4]=' ';
p[7]=' ';
p[10]=' ';
p[13]=' ';
p[16]=' ';
p[19]=' ';
sscanf(p,"%d %d %d %d %d %d %d %d",&tdt.wYear,&tdt.wMonth,&tdt.wDay,&tdt.wHour,&tdt.wMinute,&tdt.wSecond,&tdt.wMilliseconds,&timezone);
SystemTimeToFileTime(&tdt,&ft);
tzhours=abs(timezone)/100;
tzminutes=abs(timezone)-100*tzhours;
__int64 tm=ft.dwHighDateTime;
tm<<=32;
tm+=ft.dwLowDateTime;
if (timezone>0) // it's reversed!
tm-=(__int64)10000000*60*(tzminutes+60*tzhours);
else
tm+=(__int64)10000000*60*(tzminutes+60*tzhours);
ft.dwHighDateTime=(DWORD)(tm>>32);
ft.dwLowDateTime=(DWORD)(tm);
FileTimeToLocalFileTime(&ft,&lft);
FileTimeToSystemTime(&lft,&tdt);
char buf[128];
#ifdef sprintf_s
sprintf_s(buf,sizeof(buf),"%d-%02d-%02d %02d:%02d:%02d (local)",tdt.wYear,tdt.wMonth,tdt.wDay,tdt.wHour,tdt.wMinute,tdt.wSecond);
#else
sprintf(buf,"%d-%02d-%02d %02d:%02d:%02d (local)",tdt.wYear,tdt.wMonth,tdt.wDay,tdt.wHour,tdt.wMinute,tdt.wSecond);
#endif
SetDlgItemText(hWnd,IDC_PROP_MODIFIED,buf);
} else {
SetDlgItemText(hWnd,IDC_PROP_MODIFIED,p);
}
}
} else { // g_command_ls
char abuf[wdirtypemax];
wp=wcsrchr(g_filenameW,'/');
if (wp)
wp++;
else
wp=g_filenameW;
walcopy(abuf,wp,sizeof(abuf)-1);
if (usys()) {
SetDlgItemTextW(hWnd,IDC_PROP_NAME,g_filenameW);
} else {
SetDlgItemText(hWnd,IDC_PROP_NAME,abuf);
}
walcopy(abuf,g_filenameW,sizeof(abuf)-1);
p=strstr(g_statreplyA,abuf);
if (!p) {
walcopy(abuf,wp,sizeof(abuf)-1);
p=strstr(g_statreplyA,abuf);
}
if (p && p>g_statreplyA) {
p[0]=0;
p--;
// now cut off time in form APR 1 2001 or APR 1 13:30
while (p>g_statreplyA && p[0]==' ')
p--;
while (p>g_statreplyA && p[0]!=' ')
p--; //time or year
while (p>g_statreplyA && p[0]==' ')
p--;
while (p>g_statreplyA && p[0]!=' ')
p--; //day
while (p>g_statreplyA && p[0]==' ')
p--;
while (p>g_statreplyA && (p[0]<'0' || p[0]>'9'))
p--; // find size
p2=p+1;
while (p2[0]==' ') p2++;
SetDlgItemText(hWnd,IDC_PROP_MODIFIED,p2);
p[1]=0;
while (p>g_statreplyA && p[0]>='0' && p[0]<='9')
p--; // find size
if (p[0]==' ') p++;
SetDlgItemText(hWnd,IDC_PROP_SIZE,p);
if (p>g_statreplyA) {
p--;
while (p>g_statreplyA && p[0]==' ')
p--;
p[1]=0;
while (p>g_statreplyA && p[0]!=' ')
p--; //group
p2=p;
if (p2[0]==' ') p2++;
SetDlgItemText(hWnd,IDC_PROP_GROUP,p2);
while (p>g_statreplyA && p[0]==' ')
p--;
p[1]=0;
while (p>g_statreplyA && p[0]!=' ')
p--; //group
if (p[0]==' ') p++;
SetDlgItemText(hWnd,IDC_PROP_OWNER,p);
}
// permissions
p=strchr(g_statreplyA,' ');
if (p) {
p[0]=0;
SetDlgItemText(hWnd,IDC_PROP_PERMISSIONS,g_statreplyA);
}
}
}
// trying to center the About dialog
if (GetWindowRect(hWnd, &rt1) && GetWindowRect(GetParent(hWnd), &rt2)) {
w=rt2.right-rt2.left;
h=rt2.bottom-rt2.top;
DlgWidth = rt1.right - rt1.left;
DlgHeight = rt1.bottom - rt1.top ;
NewPosX =rt2.left + (w - DlgWidth)/2;
NewPosY =rt2.top + (h - DlgHeight)/2;
SetWindowPos(hWnd, 0, NewPosX, NewPosY,
0, 0, SWP_NOZORDER | SWP_NOSIZE);
}
return 1;
break;
}
case WM_SHOWWINDOW: {
break;
}
case WM_COMMAND: {
switch(LOWORD(wParam)) {
case IDOK:
case IDCANCEL: {
EndDialog(hWnd, IDOK);
return 1;
}
}
}
}
return 0;
}
void SftpShowPropertiesW(void* serverid,WCHAR* remotename)
{
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (!ConnectSettings)
return;
WCHAR filename[wdirtypemax],cmdname[wdirtypemax],replyW[8192];
char replyA[8192];
// note: SftpQuoteCommand2 already converts from Ansi to UTF-8!!!
wcslcpy(filename,remotename,countof(filename)-1);
ReplaceBackslashBySlashW(filename);
wcslcpy(cmdname,L"stat ",countof(cmdname)-1);
BOOL needquotes=wcschr(filename,' ')!=NULL || wcschr(filename,'(')!=NULL || wcschr(filename,')')!=NULL;
if (needquotes)
wcslcat(cmdname,L"\"",countof(cmdname)-1);
wcslcat(cmdname,filename,countof(cmdname)-1);
if (needquotes)
wcslcat(cmdname,L"\"",countof(cmdname)-1);
replyA[0]=0;
replyW[0]=0;
g_statreplyA=NULL;
g_statreplyW=NULL;
if (SftpQuoteCommand2W(serverid,NULL,cmdname,replyA,sizeof(replyA)-1)>=0) {
if (ConnectSettings->utf8names) {
UTF8* srcstart=(UTF8*)replyA;
UTF16* trgstart=(UTF16*)replyW;
ConvertUTF8toUTF16(&srcstart,srcstart+strlen(replyA)+1,
&trgstart,trgstart+countof(replyW)-1);
} else
awlcopyCP(ConnectSettings->codepage,replyW,replyA,countof(replyW)-1);
walcopy(replyA,replyW,sizeof(replyA)-1);
g_command_ls=false;
g_statreplyA=replyA;
g_statreplyW=replyW;
}
BOOL statworked=g_statreplyW!=NULL;
if (statworked) {
WCHAR chw,*wp;
wp=FindStatStringW(g_statreplyW,L"File:",&chw);
if (wp) {
wp[wcslen(wp)]=chw;
} else
statworked=false;
}
if (!statworked) { // stat failed -> try "ls -la filename"
wcslcpy(replyW,cmdname+5,countof(replyW)-1);
wcslcpy(cmdname,L"ls -la ",countof(cmdname)-1);
wcslcat(cmdname,replyW,wdirtypemax-1);
if (SftpQuoteCommand2W(serverid,NULL,cmdname,replyA,sizeof(replyA)-1)>=0) {
g_command_ls=true;
if (ConnectSettings->utf8names) {
UTF8* srcstart=(UTF8*)replyA;
UTF16* trgstart=(UTF16*)replyW;
ConvertUTF8toUTF16(&srcstart,srcstart+strlen(replyA)+1,
&trgstart,trgstart+countof(replyW)-1);
} else
awlcopyCP(ConnectSettings->codepage,replyW,replyA,countof(replyW)-1);
walcopy(replyA,replyW,sizeof(replyA)-1);
g_statreplyA=replyA;
g_statreplyW=replyW;
}
}
if (g_statreplyA) {
g_filenameW=filename;
if (usys())
DialogBoxW(hinst,MAKEINTRESOURCEW(IDD_PROPERTIES),GetActiveWindow(),PropDlgProc);
else
DialogBox(hinst,MAKEINTRESOURCE(IDD_PROPERTIES),GetActiveWindow(),PropDlgProc);
}
}
void SftpGetLastActivePathW(void* serverid,WCHAR* RelativePath,int maxlen)
{
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (ConnectSettings)
wcslcpy(RelativePath,ConnectSettings->lastactivepath,maxlen);
else
RelativePath[0]=0;
}
BOOL SftpSupportsResume(void* serverid)
{
pConnectSettings ConnectSettings=(pConnectSettings)serverid;
if (ConnectSettings)
return !ConnectSettings->scponly;
else
return false;
}
Detected encoding: UTF-8 | 0
|