📄 filetransfer.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Copyright (C) 2002 Ultr@VNC Team Members. All Rights Reserved.
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// If the source code for the program is not available from the place from
// which you received this file, check
// http://www.teamviewer.com/
//
////////////////////////////////////////////////////////////////////////////
// FileTransfer.cpp: implementation of the FileTransfer class.
// sf@2002 - sf@2003 - sf@2004 - FileTransfer
// This class handles all the FileTransfer messages, events and procs, as well as the
// DialogBox which allows the user to browse Client ans Server disks-directories,
// and select some files to transfer between Client and Server.
//
// The GUI is very basic because I don't want to include MFC Classes in VNC...
// I use only Windows SDK.
//
//
// The GUI is now quite bearable, but following modifs could be done one day or another
// - Add more columns to FileLists (File type, Attributes...)
// - Add the possibility to sort files by colomns (File Size Order, File Ext order...)
// - Total progress should be based on total files' size instead of total number of files
// - Make the History persistent (file) so it's not lost each time the FileTransfer Win is closed
// - Clean-up the code (duplicated parts, arrays and strings dimensions checks...)
// - Display the total files size in the currently displayed directory
// - Remember the current directories - Partially done: the FT window can be minimized...
#include "stdhdrs.h"
#include "vncviewer.h"
#include "FileTransfer.h"
#include "..\winvnc\winvnc\vncservice.h"
// These strings contain all the translated FT messages
extern char sz_H1[64];
extern char sz_H2[64];
extern char sz_H3[128];
extern char sz_H4[64];
extern char sz_H5[64];
extern char sz_H6[64];
extern char sz_H7[64];
extern char sz_H8[64];
extern char sz_H9[64];
extern char sz_H10[64];
extern char sz_H11[64];
extern char sz_H12[64];
extern char sz_H13[64];
extern char sz_H14[64];
extern char sz_H15[64];
extern char sz_H16[64];
extern char sz_H17[64];
extern char sz_H18[64];
extern char sz_H19[64];
extern char sz_H20[64];
extern char sz_H21[64];
extern char sz_H22[64];
extern char sz_H23[64];
extern char sz_H24[64];
extern char sz_H25[64];
extern char sz_H26[64];
extern char sz_H27[64];
extern char sz_H28[64];
extern char sz_H29[64];
extern char sz_H30[64];
extern char sz_H31[64];
extern char sz_H32[64];
extern char sz_H33[64];
extern char sz_H34[64];
extern char sz_H35[64];
extern char sz_H36[64];
extern char sz_H37[64];
extern char sz_H38[128];
extern char sz_H39[64];
extern char sz_H40[64];
extern char sz_H41[64];
extern char sz_H42[64];
extern char sz_H43[128];
extern char sz_H44[64];
extern char sz_H45[64];
extern char sz_H46[128];
extern char sz_H47[64];
extern char sz_H48[64];
extern char sz_H49[64];
extern char sz_H50[64];
extern char sz_H51[64];
extern char sz_H52[64];
extern char sz_H53[64];
extern char sz_H54[64];
extern char sz_H55[64];
extern char sz_H56[64];
extern char sz_H57[64];
// Folder Transfer messages
extern char sz_H58[64];
extern char sz_H59[64];
extern char sz_H60[64];
extern char sz_H61[64];
extern char sz_H62[128];
extern char sz_H63[64];
extern char sz_H64[64];
extern char sz_H65[64];
extern char sz_H66[64];
extern char sz_H67[64];
extern char sz_H68[128];
extern char sz_H69[64];
extern char sz_H70[64];
extern char sz_H71[64];
extern char sz_H72[128];
extern char sz_H73[64];
// File/dir Rename messages
extern char sz_M1[64];
extern char sz_M2[64];
extern char sz_M3[64];
extern char sz_M4[64];
extern char sz_M5[64];
extern char sz_M6[64];
extern char sz_M7[64];
extern char sz_M8[64];
typedef BOOL (WINAPI *PGETDISKFREESPACEEX)(LPCSTR,PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
//
//
//
FileTransfer::FileTransfer(VNCviewerApp *pApp, ClientConnection *pCC)
{
// vnclog.Print(0, VNCLOG(_T("FileTransfer")));
m_pApp = pApp;
m_pCC = pCC;
m_fAbort = false;
m_fAborted = false;
m_FilesList.clear();
m_nFilesToTransfer = 0;
m_nFilesTransfered = 0;
m_fFileCommandPending = false;
m_fFileTransferRunning = false;
m_fFileDownloadRunning = false;
m_fDirectoryReceptionRunning = false;
m_fVisible = true;
m_fFTAllowed = false;
m_timer = 0;
m_lpCSBuffer = NULL;
m_nCSOffset = 0;
m_nCSBufferSize = 0;
m_nDeleteCount = 0;
memset(m_szDeleteButtonLabel, 0, sizeof(m_szDeleteButtonLabel));
memset(m_szNewFolderButtonLabel, 0, sizeof(m_szNewFolderButtonLabel));
memset(m_szRenameButtonLabel, 0, sizeof(m_szRenameButtonLabel));
m_fOldFTProtocole = false;
m_nBlockSize = sz_rfbBlockSize;
m_dwCurrentValue = 0;
m_dwCurrentPercent = 0;
m_fSendFileChunk = false;
m_mmRes = -1;
m_fCreateDirPending = false;
m_fInGetFilesRecursive = false;
m_fGetFilesFirstResponse = false;
hWnd = NULL;
ZeroMemory(&m_szLastRemoteDirVisit,sizeof(m_szLastRemoteDirVisit));
}
//
//
//
FileTransfer::~FileTransfer()
{
// vnclog.Print(0, VNCLOG(_T("nFileTransfer")));
KillDialog();
m_fFileCommandPending = false;
m_FilesList.clear();
}
void FileTransfer::KillDialog()
{
if(!hWnd)
return;
if (m_timer != 0)
KillTimer(hWnd, m_timer);
KillFTTimer();
EndDialog(hWnd, FALSE); // return value==2: ClientConnection terminated
hWnd = NULL;
}
void FileTransfer::InitFTTimer()
{
if (m_mmRes != -1) return;
m_fSendFileChunk = false;
m_mmRes = timeSetEvent( 1, 0, fpTimer, (DWORD)this, TIME_PERIODIC );
}
void FileTransfer::KillFTTimer()
{
timeKillEvent(m_mmRes);
m_mmRes = -1;
}
void CALLBACK FileTransfer::fpTimer(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
{
FileTransfer* ft = (FileTransfer *) dwUser;
if (!ft->m_fFileUploadRunning) return;
if (!ft->m_fSendFileChunk)
{
ft->m_fSendFileChunk = true;
ft->m_dwLastChunkTime = timeGetTime();
SendMessage(ft->m_pCC->m_hwndMain, FileTransferSendPacketMessage, (WPARAM) 0, (LPARAM) 0);
// sf@2005 - FileTransfer Temporization
// - Prevents the windows message stack to be blocked too much when transfering over slow conenction
// - Gives more priority to screen updates during asynchronous filetransfer
if (timeGetTime() - ft->m_dwLastChunkTime > 200)
Sleep(150);
else if (!ft->m_fVisible && !ft->m_fOldFTProtocole && !ft->m_pCC->IsDormant())
Sleep(50);
ft->m_fSendFileChunk = false;
}
}
//
//
//
void FileTransfer::ShowFileTransferWindow(bool fVisible)
{
if(hParent)
ShowWindow(hParent, fVisible ? SW_RESTORE : SW_MINIMIZE);
ShowWindow(hWnd, fVisible ? SW_RESTORE : SW_MINIMIZE);
SetForegroundWindow(hWnd);
}
//
// Simply the classic Windows message processing
//
bool PseudoYield(HWND hWnd)
{
// vnclog.Print(0, VNCLOG(_T("PseudoYield")));
MSG msg;
while (PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_CLOSE) return FALSE;
}
return TRUE;
}
//
// ProcessFileTransferMsg
//
// Here we process all incoming FileTransferMsg stuff
// coming from the server.
// The server only sends FileTransfer data when requested
// by the client. Possible request are:
//
// - Send the list of your drives
// - Send the content of a directory
// - Send a file
// - Accept a file
// - ...
//
// We use the main ClientConnection thread and its
// rfb message reception loop.
// This function is called by the rfb message processing thread.
// Thus it's safe to call the ReadExact and ReadString
// functions in the functions that are called from here:
// PopulateRemoteListBox, ReceiveFile
//
void FileTransfer::ProcessFileTransferMsg(void)
{
// vnclog.Print(0, VNCLOG(_T("ProcessFileTransferMsg")));
rfbFileTransferMsg ft;
m_pCC->ReadExact(((char *) &ft) + m_pCC->m_nTO, sz_rfbFileTransferMsg - m_pCC->m_nTO);
switch (ft.contentType)
{
// Response to a rfbDirContentRequest request:
// some directory data is received from the server
case rfbDirPacket:
switch (ft.contentParam)
{
// Response to a rfbRDrivesList request
case rfbADrivesList:
ListRemoteDrives(hWnd, Swap32IfLE(ft.length));
m_fFileCommandPending = false;
break;
// Response to a rfbRDirContent request
case rfbADirectory:
case rfbAFile:
if (m_fInGetFilesRecursive)
GetFilesRecursiveResponse(Swap32IfLE(ft.length));
else if (!m_fDirectoryReceptionRunning)
PopulateRemoteListBox(hWnd, Swap32IfLE(ft.length));
else
ReceiveDirectoryItem(hWnd, Swap32IfLE(ft.length));
break;
default: // This is bad. Add rfbADirectoryEnd instead...
if (m_fInGetFilesRecursive)
{
m_fInGetFilesRecursive = false;
m_GetFiles.pop_front();
GetFilesRecursive();
}
else
if (m_fDirectoryReceptionRunning)
{
FinishDirectoryReception();
m_fFileCommandPending = false;
}
break;
}
break;
// In response to a rfbFileTransferRequest request
// A file is received from the server.
case rfbFileHeader:
ReceiveFiles(Swap32IfLE(ft.size), Swap32IfLE(ft.length));
break;
// In response to a rfbFileTransferOffer request
// The server can send the checksums of the destination file before sending a ack through
// rfbFileAcceptHeader (only if the destination file already exists and is accessible)
case rfbFileChecksums:
ReceiveDestinationFileChecksums(Swap32IfLE(ft.size), Swap32IfLE(ft.length));
break;
// In response to a rfbFileTransferOffer request
// A ack or nack is received from the server.
case rfbFileAcceptHeader:
SendFiles(Swap32IfLE(ft.size), Swap32IfLE(ft.length));
break;
// Response to a command
case rfbCommandReturn:
switch (ft.contentParam)
{
case rfbADirCreate:
CreateRemoteDirectoryFeedback(Swap32IfLE(ft.size), Swap32IfLE(ft.length));
m_fFileCommandPending = false;
break;
case rfbADirDelete:
case rfbAFileDelete:
DeleteRemoteFileFeedback(Swap32IfLE(ft.size), Swap32IfLE(ft.length));
m_fFileCommandPending = false;
break;
case rfbAFileRename:
RenameRemoteFileOrDirectoryFeedback(Swap32IfLE(ft.size), Swap32IfLE(ft.length));
m_fFileCommandPending = false;
break;
}
break;
// Should never be handled here but in the File Transfer Loop
case rfbFilePacket:
ReceiveFileChunk(Swap32IfLE(ft.length), Swap32IfLE(ft.size));
break;
// Should never be handled here but in the File Transfer Loop
case rfbEndOfFile:
FinishFileReception();
break;
// Abort current file transfer
// For versions <=RC18 we also use it to test if we're allowed to use FileTransfer on the server
case rfbAbortFileTransfer:
// AbortFileDownload();
if (m_fFileDownloadRunning)
{
m_fFileDownloadError = true;
FinishFileReception();
}
else
{
// We want the viewer to be backward compatible with UltraWinVNC running the old FT protocole
m_fOldFTProtocole = true; // Old permission method -> it's a <=RC18 server
m_nBlockSize = 4096; // Old packet size value...
ShowWindow(GetDlgItem(hWnd, IDC_RENAME_B), SW_HIDE);
TestPermission(Swap32IfLE(ft.size), 0);
}
break;
// New FT handshaking/permission method (from RC19)
case rfbFileTransferAccess:
TestPermission(Swap32IfLE(ft.size), ft.contentParam);
break;
default:
return;
break;
}
}
//
// request file transfer permission
//
void FileTransfer::RequestPermission()
{
// vnclog.Print(0, VNCLOG(_T("RequestPermission")));
rfbFileTransferMsg ft;
ft.type = rfbFileTransfer;
// Versions <= RC18 method
ft.contentType = rfbAbortFileTransfer;
// ft.contentParam = 0;
ft.contentParam = rfbFileTransferVersion; // Old viewer will send 0
// New method can't be used yet as we want backward compatibility (new viewer FT must
// work with old UltraWinVNC FT
// ft.contentType = rfbFileTransferAccess;
// ft.contentParam = rfbFileTransferVersion;
ft.length = 0;
ft.size = 0;
m_pCC->WriteExact((char *)&ft, sz_rfbFileTransferMsg, rfbFileTransfer);
return;
}
//
// Test if we are allowed to access filetransfer
//
bool FileTransfer::TestPermission(long lSize, int nVersion)
{
// vnclog.Print(0, VNCLOG(_T("TestPermission")));
if (lSize == -1)
{
m_fFTAllowed = false;
HWND hWndRemoteList = GetDlgItem(hWnd, IDC_REMOTE_FILELIST);
SendDlgItemMessage(hWnd, IDC_REMOTE_DRIVECB, LB_RESETCONTENT, 0, 0L);
ListView_DeleteAllItems(hWndRemoteList);
//saves the last directory the user was browsing
//its used later for redisplaying the remote directory content
//search for IDC_ABORT_B:
GetDlgItemText(hWnd, IDC_CURR_REMOTE, m_szLastRemoteDirVisit, sizeof(m_szLastRemoteDirVisit));
ShowWindow(GetDlgItem(hWnd, IDC_ABORT_B), SW_SHOW);
SetDlgItemText(hWnd, IDC_CURR_REMOTE, sz_H1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -