sftpcontrolsocket.cpp

来自「一个支持FTP,SFTP的客户端程序」· C++ 代码 · 共 2,354 行 · 第 1/5 页

CPP
2,354
字号
				pData->pDirectoryListing->server = m_CurrentServer;
				pData->pDirectoryListing->path.SetServer(pData->pDirectoryListing->server);
				if (pData->rawpwd!="")
				{
					if (!pData->pDirectoryListing->path.SetPath(pData->rawpwd))
					{
						delete m_pDirectoryListing;
						m_pDirectoryListing=0;
						ResetOperation(FZ_REPLY_ERROR);
						return;
					}
				}
				else
					pData->pDirectoryListing->path = pData->realpath;
				ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL,0);
				
				//Merge new listing into cache
				CDirectoryCache cache;
				cache.Lock();
				t_directory dir;
				if (!pData->path.IsEmpty() && pData->subdir!="")
				{
					if (cache.Lookup(pData->pDirectoryListing->path, pData->pDirectoryListing->server, dir))
						pData->pDirectoryListing->Merge(dir, pData->ListStartTime);
					cache.Store(*pData->pDirectoryListing,pData->path,pData->subdir);
				}
				else
				{
					if (cache.Lookup(pData->pDirectoryListing->path, pData->pDirectoryListing->server, dir))
						pData->pDirectoryListing->Merge(dir, pData->ListStartTime);
					cache.Store(*pData->pDirectoryListing);
				}
				cache.Unlock();

				SetDirectoryListing(pData->pDirectoryListing);
				ResetOperation(FZ_REPLY_OK);
			}
			return;
		}
	}
	
	if (m_Operation.nOpState==LIST_INIT)
	{ //Initialize some variables
		pData = new CListData(m_CurrentServer);;
		pData->pParser->InitLog(this);
		pData->nListMode=nListMode;
		pData->path=path;
		pData->subdir=subdir;
		m_Operation.pData=pData;
		ShowStatus(IDS_STATUSMSG_RETRIEVINGDIRLIST,0);
		if (m_pDirectoryListing)
		{
			delete m_pDirectoryListing;
			m_pDirectoryListing=0;
		}
		
		CServerPath path=pData->path;
		m_pOwner->GetCurrentPath(pData->realpath);
		CServerPath realpath=pData->realpath;
		if (!pData->realpath.IsEmpty())
		{
			if (!pData->path.IsEmpty() && pData->path!=pData->realpath)
				m_Operation.nOpState=LIST_CWD;
			else if (!pData->path.IsEmpty() && pData->subdir!="")
				m_Operation.nOpState=LIST_CWD2;
			else
			{
				if (pData->nListMode&FZ_LIST_REALCHANGE)
				{
					if (pData->subdir=="")
						m_Operation.nOpState=LIST_CWD;
					else
						m_Operation.nOpState=LIST_CWD2;
				}
				else
				{
					if (pData->nListMode&FZ_LIST_USECACHE)
					{
						t_directory dir;
						CDirectoryCache cache;
						BOOL res=cache.Lookup(pData->realpath,m_CurrentServer,dir);
						if (res)
						{
							BOOL bExact=TRUE;
							if (pData->nListMode & FZ_LIST_EXACT)
								for (int i=0;i<dir.num;i++)
									if (dir.direntry[i].bUnsure || (dir.direntry[i].size==-1 && !dir.direntry[i].dir))
									{
										bExact=FALSE;
										break;
									}
							if (bExact)
							{
								ShowStatus(IDS_STATUSMSG_DIRLISTSUCCESSFUL,0);
								SetDirectoryListing(&dir);
								ResetOperation(FZ_REPLY_OK);
								return;
							}
						}
					}
					m_Operation.nOpState=LIST_LIST;
				}
			}
		}
		else
		{
			if (pData->path.IsEmpty())
				m_Operation.nOpState=LIST_PWD;
			else
				m_Operation.nOpState=LIST_CWD;
		}
	}
	BOOL bSuccessful=FALSE;
	if (m_Operation.nOpState==LIST_PWD)
		bSuccessful=m_pDataChannel->Send(SFTP_DATAID_STC_PWD, 0, 0);
	else if (m_Operation.nOpState==LIST_CWD)
		bSuccessful=m_pDataChannel->Send(SFTP_DATAID_STC_CD, pData->path.GetPath());
	else if (m_Operation.nOpState==LIST_CWD2)
	{
		if (!pData->subdir)
		{
			ResetOperation(FZ_REPLY_ERROR);
			return;
		}
		bSuccessful=m_pDataChannel->Send(SFTP_DATAID_STC_CD, pData->subdir);
	}
	else if (m_Operation.nOpState==LIST_LIST)
	{
		pData->ListStartTime=CTime::GetCurrentTime();
		bSuccessful=m_pDataChannel->Send(SFTP_DATAID_STC_LIST, 0, 0);
	}
	if (!bSuccessful)
		DoClose();
}

void CSFtpControlSocket::FtpCommand(LPCTSTR pCommand)
{
	ASSERT(FALSE);
}

void CSFtpControlSocket::Disconnect()
{
	ASSERT(!m_Operation.nOpMode);
	m_Operation.nOpMode=CSMODE_DISCONNECT;
	DoClose();
}

void CSFtpControlSocket::FileTransfer(t_transferfile *transferfile /*=0*/, BOOL bFinish /*=FALSE*/, int nError /*=0*/)
{
	LogMessage(__FILE__, __LINE__, this,FZ_LOG_DEBUG, _T("FileTransfer(%d, %s, %d)  OpMode=%d OpState=%d"), transferfile,bFinish?_T("TRUE"):_T("FALSE"),nError,m_Operation.nOpMode,m_Operation.nOpState);

	USES_CONVERSION;
	
	#define FILETRANSFER_INIT			-1 //Opt: LIST TYPE
	#define FILETRANSFER_CWD			0 //PWD
	#define FILETRANSFER_MKD			1
	#define FILETRANSFER_CWD2			2
	#define FILETRANSFER_LIST			4
	#define FILETRANSFER_RETRSTOR		13
	
	#define FILETRANSFER_WAIT			15


	//Flowchart of FileTransfer
	//
	//            +----+
	//     /------|Init|--------\
	//     |      +----+        |
	//     |         |          |
	//     |         |          |
	//     |       +---+        |
	//     |       |CWD|--\     |
	//     |       +---+  |     |
	//     |         |    |     |
	//     |         |    |     |
	//     |         |  +---+   |
	//     |         |  |MKD|   |
	//     |         |  +---+   |
	//     |         |    |     |
	//     |         |    |     |
	//     |         |  +----+  |
	//     |         |  |CWD2|  |
	//     |         |  +----+  |
	//     |         |    |     |
	//     |         +----/     |
	//     |         |          |
	//     |         +----------/
	//     |         |
	//     |      +----+
	//     |      |LIST|
	//     |      +----+
    //     |         |
	//     \---------+
	//               |
	//          +--------+
	//          |RETRSTOR|
	//          +--------+
	
	ASSERT(!m_Operation.nOpMode || m_Operation.nOpMode&CSMODE_TRANSFER);
	if (!m_pOwner->IsConnected())
	{
		m_Operation.nOpMode=CSMODE_TRANSFER|(transferfile->get?CSMODE_DOWNLOAD:CSMODE_UPLOAD);
		ResetOperation(FZ_REPLY_ERROR|FZ_REPLY_DISCONNECTED);
	}

	CFileTransferData *pData=static_cast<CFileTransferData *>(m_Operation.pData);

	//////////////////
	//Initialization//
	//////////////////
	int nReplyError=0;
	if (m_Operation.nOpState==FILETRANSFER_INIT)
	{
		ASSERT(transferfile);
		ASSERT(!m_Operation.nOpMode);
		ASSERT(!m_Operation.pData);

		CString str;
		str.Format(transferfile->get?IDS_STATUSMSG_DOWNLOADSTART:IDS_STATUSMSG_UPLOADSTART,transferfile->get?transferfile->remotepath.GetPath()+transferfile->remotefile:transferfile->localfile);
		ShowStatus(str,0);
		
		m_Operation.nOpMode=CSMODE_TRANSFER|(transferfile->get?CSMODE_DOWNLOAD:CSMODE_UPLOAD);

		pData = new CFileTransferData(m_CurrentServer);
		pData->pParser->InitLog(this);
		m_Operation.pData=pData;

		//Replace invalid characters in the local filename
		int pos=transferfile->localfile.ReverseFind('\\');
		for (int i=(pos+1);i<transferfile->localfile.GetLength();i++)
			if (transferfile->localfile[i]==':')
				transferfile->localfile.SetAt(i, '_');
		
		pData->transferfile=*transferfile;
		pData->transferdata.bResume=FALSE;
		pData->transferdata.bType = (pData->transferfile.nType == 1) ? TRUE : FALSE;
		
		CServerPath path;
		VERIFY (m_pOwner->GetCurrentPath(path));
		if (path==pData->transferfile.remotepath)
		{
			if (m_pDirectoryListing)
			{
				m_Operation.nOpState=FILETRANSFER_RETRSTOR;
				CString remotefile=pData->transferfile.remotefile;
				int i;
				for (i=0; i<m_pDirectoryListing->num; i++)
				{
					if (m_pDirectoryListing->direntry[i].name==remotefile &&
						( m_pDirectoryListing->direntry[i].bUnsure || m_pDirectoryListing->direntry[i].size==-1 ))
					{
						delete m_pDirectoryListing;
						m_pDirectoryListing=0;
						m_Operation.nOpState=FILETRANSFER_LIST;
						break;
					}
				}				
				if (m_pDirectoryListing && i==m_pDirectoryListing->num)
				{
					nReplyError=CheckOverwriteFile();
					if (!nReplyError)
					{
						if (pData->transferfile.get)
						{
							CString path=pData->transferfile.localfile;
							if (path.ReverseFind('\\')!=-1)
							{
								path=path.Left(path.ReverseFind('\\')+1);
								CString path2;
								while (path!="")
								{
									path2+=path.Left(path.Find( _T("\\") )+1);
									path=path.Mid(path.Find( _T("\\") )+1);
									int res=CreateDirectory(path2,0);
								}
							}
						}
					}
				}
			}
			else
			{
				CDirectoryCache cache;
				t_server server;
				m_pOwner->GetCurrentServer(server);
				t_directory dir;
				BOOL res=cache.Lookup(pData->transferfile.remotepath,server,dir);
				if (res)
				{
					CString remotefile = pData->transferfile.remotefile;
					int i;
					for (i=0; i<dir.num; i++)
					{
						if (dir.direntry[i].name==remotefile &&
							( dir.direntry[i].bUnsure || dir.direntry[i].size==-1 ))
						{
							m_Operation.nOpState=FILETRANSFER_LIST;
							break;
						}
					}
					if (i==dir.num)
					{
						SetDirectoryListing(&dir);
						m_Operation.nOpState=FILETRANSFER_RETRSTOR;
						nReplyError=CheckOverwriteFile();
						if (!nReplyError)
						{
							if (pData->transferfile.get)
							{
								CString path=pData->transferfile.localfile;
								if (path.ReverseFind('\\')!=-1)
								{
									path=path.Left(path.ReverseFind('\\')+1);
									CString path2;
									while (path!="")
									{
										path2+=path.Left(path.Find( _T("\\") )+1);
										path=path.Mid(path.Find(_T( "\\") )+1);
										int res=CreateDirectory(path2,0);
									}
								}
							}
						}
					}
				}
				else
					m_Operation.nOpState=FILETRANSFER_LIST;
			}
		}
		else
			m_Operation.nOpState=FILETRANSFER_CWD;
	}
	else
	{
		///////////
		//Replies//
		///////////
		switch(m_Operation.nOpState)
		{
		case FILETRANSFER_CWD:
			if (m_bError)
			{
				if (!pData->transferfile.get)
					m_Operation.nOpState = FILETRANSFER_MKD;
				else
				{
					pData->bUseAbsolutePaths = TRUE;
					m_Operation.nOpState = FILETRANSFER_RETRSTOR;
				}
			}
			else
			{
				CServerPath path;
				path.SetServer(m_CurrentServer);
				if (!path.SetPath(A2CT(m_Reply)))
				{
					LogMessage(__FILE__, __LINE__, this,FZ_LOG_WARNING, _T("Can't parse path"));
					nReplyError=FZ_REPLY_ERROR;
				}
				else
				{
					pData->rawpwd=m_Reply;
					m_pOwner->SetCurrentPath(path);
					if (path!=pData->transferfile.remotepath)
						nReplyError=FZ_REPLY_ERROR | FZ_REPLY_CRITICALERROR;
					else
					{
						CDirectoryCache cache;
						t_server server;
						m_pOwner->GetCurrentServer(server);
						t_directory dir;
						BOOL res=cache.Lookup(pData->transferfile.remotepath, server,dir);
						if (res)
						{
							CString remotefile=pData->transferfile.remotefile;
							int i;
							for (i=0; i<dir.num; i++)
							{
								if (dir.direntry[i].name==remotefile &&
									( dir.direntry[i].bUnsure || dir.direntry[i].size==-1 ))
								{
									m_Operation.nOpState=FILETRANSFER_LIST;
									break;
								}
							}
							if (i==dir.num)
							{
								SetDirectoryListing(&dir);
								m_Operation.nOpState=FILETRANSFER_RETRSTOR;
								nReplyError=CheckOverwriteFile();
								if (!nReplyError)
								{
									if (pData->transferfile.get)
									{
										CString path=pData->transferfile.localfile;
										if (path.ReverseFind('\\')!=-1)
										{
											path=path.Left(path.ReverseFind('\\')+1);
											CString path2;
											while (path!="")
											{
												path2+=path.Left(path.Find( _T("\\") )+1);
												path=path.Mid(path.Find( _T("\\") )+1);
												int res=CreateDirectory(path2,0);
											}
										}
									}
								}
							}
						}
						else
							m_Operation.nOpState=FILETRANSFER_LIST;
					}
				}
			}
			break;
		case FILETRANSFER_MKD:
			switch(pData->nMKDOpState)
			{
			case MKD_FINDPARENT:
				if (!m_bError)
				{
					m_pOwner->SetCurrentPath(pData->MKDCurrent);

					if (!m_pDirectoryListing)
					{
						CDirectoryCache cache;
						t_directory dir;
						BOOL res=cache.Lookup(pData->MKDCurrent, m_CurrentServer, dir, TRUE);
						if (res)
							SetDirectoryListing(&dir);
					}
					
					pData->nMKDOpState=MKD_CHANGETOSUBDIR;
					pData->MKDCurrent.AddSubdir(pData->MKDSegments.front());
					CString Segment=pData->MKDSegments.front();
					pData->MKDSegments.pop_front();
					if (!m_pDataChannel->Send(SFTP_DATAID_STC_MKD, Segment))
					{
						DoClose();
						return;
					}
				}
				else
				{
					if (!pData->MKDCurrent.HasParent())
						nReplyError=FZ_REPLY_ERROR|FZ_REPLY_CRITICALERROR;
					else
					{
						pData->MKDSegments.push_front(pData->MKDCurrent.GetLastSegment());
						pData->MKDCurrent=pData->MKDCurrent.GetParent();
						if (!m_pDataChannel->Send(SFTP_DATAID_STC_CD, pData->MKDCurrent.GetPath()))
						{
							DoClose();
							return;	
						}
					}
				}
				break;
			case MKD_MAKESUBDIRS:
				if (!m_bError)
				{ //Create dir entry in parent dir
					ASSERT(!pData->MKDSegments.empty());
					pData->MKDCurrent.AddSubdir(pData->MKDSegments.front());
					CString Segment=pData->MKDSegments.front();
					pData->MKDSegments.pop_front();
					if (m_pDataChannel->Send(SFTP_DATAID_STC_MKD, Segment))
						pData->nMKDOpState=MKD_CHANGETOSUBDIR;
					else
					{
						DoClose();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?