?? ftpcommandprocessor.cpp
字號:
// FTPCommandProcessor.cpp: implementation of the CFTPCommandProcessor class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "tvnews.h"
#include "FTPCommandProcessor.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
//構造函數,變量初始化
CFTPCommandProcessor::CFTPCommandProcessor()
{
m_pCtrlsokfile=NULL;
m_pCtrlTxarch=NULL;
m_pCtrlRxarch=NULL;
m_Ctrlsok=NULL;
}
CFTPCommandProcessor::~CFTPCommandProcessor()
{
CloseControlChannel();
}
//////////////////////////////////////////////////////////////////////
// Public Functions
//////////////////////////////////////////////////////////////////////
// 登錄到服務器
BOOL CFTPCommandProcessor::LogOnToServer(CString hostname,int hostport,CString username, CString password, CString acct, CString fwhost,CString fwusername, CString fwpassword,int fwport,int logontype)
{
int port,logonpoint=0;
const int LO=-2, ER=-1;
CString buf,temp;
const int NUMLOGIN=9; // 支持9種不同的登錄方式
int logonseq[NUMLOGIN][100] = {
// 下面的數組保存了針對不同防火墻的登錄序列
{0,LO,3, 1,LO,6, 2,LO,ER}, // 沒有防火墻
{3,6,3, 4,6,ER, 5,ER,9, 0,LO,12, 1,LO,15, 2,LO,ER}, // 主機名
{3,6,3, 4,6,ER, 6,LO,9, 1,LO,12, 2,LO,ER}, // USER after logon
{7,3,3, 0,LO,6, 1,LO,9, 2,LO,ER}, //proxy OPEN
{3,6,3, 4,6,ER, 0,LO,9, 1,LO,12, 2,LO,ER}, // Transparent
{6,LO,3, 1,LO,6, 2,LO,ER}, // USER with no logon
{8,6,3, 4,6,ER, 0,LO,9, 1,LO,12, 2,LO,ER}, //USER fireID@remotehost
{9,ER,3, 1,LO,6, 2,LO,ER}, //USER remoteID@remotehost fireID
{10,LO,3, 11,LO,6, 2,LO,ER} // USER remoteID@fireID@remotehost
};
if(logontype<0||logontype>=NUMLOGIN) return FALSE; // illegal connect code
if(!logontype) {
temp=hostname;
port=hostport;
}
else {
temp=fwhost;
port=fwport;
}
if(hostport!=21)
hostname.Format(hostname+":%d",hostport); // 如果端口不是默認端口21,則設定端口
if(!OpenControlChannel(temp,port))
return false;
if(!FTPcommand(""))
return FALSE; // 獲得連接服務器初始化信息
// 獲得登錄類型
while(1) {
switch(logonseq[logontype][logonpoint]) {
case 0:
temp="USER "+username;
break;
case 1:
temp="PASS "+password;
break;
case 2:
temp="ACCT "+acct;
break;
case 3:
temp="USER "+fwusername;
break;
case 4:
temp="PASS "+fwpassword;
break;
case 5:
temp="SITE "+hostname;
break;
case 6:
temp="USER "+username+"@"+hostname;
break;
case 7:
temp="OPEN "+hostname;
break;
case 8:
temp="USER "+fwusername+"@"+hostname;
break;
case 9:
temp="USER "+username+"@"+hostname+" "+fwusername;
break;
case 10:
temp="USER "+username+"@"+fwusername+"@"+hostname;
break;
case 11:
temp="PASS "+password+"@"+fwpassword;
break;
}
// 發出命令,獲得響應
if(!WriteStr(temp)) return FALSE;
if(!ReadStr()) return FALSE;
// 只有這些響應是合法的
if(m_fc!=2&&m_fc!=3) return FALSE;
logonpoint=logonseq[logontype][logonpoint+m_fc-1]; //get next command from array
switch(logonpoint) {
case ER: // 出現錯誤
m_retmsg.LoadString(IDS_FTPMSG1);
return FALSE;
case LO: // L0表示成功登錄
return TRUE;
}
}
}
// 退出服務器
void CFTPCommandProcessor::LogOffServer()
{
WriteStr("QUIT");
CloseControlChannel();
}
// 發送命令到服務器
BOOL CFTPCommandProcessor::FTPcommand(CString command)
{
if(command!=""&&!WriteStr(command)) return FALSE;
if((!ReadStr())||(m_fc!=2)) return FALSE;
return TRUE;
}
// 上載或者下載文件
BOOL CFTPCommandProcessor::MoveFile(CString remotefile, CString localfile,BOOL pasv,BOOL get)
{
CString lhost,temp,rhost;
UINT localsock,serversock,i,j;
CFile datafile;
CSocket sockSrvr;
CAsyncSocket datachannel;
int num,numread,numsent;
const int BUFSIZE=4096;
char cbuf[BUFSIZE];
DWORD lpArgument=0;
// 打開本地文件
if(!datafile.Open(localfile,(get?CFile::modeWrite|CFile::modeCreate:CFile::modeRead))) {
m_retmsg.LoadString(IDS_FTPMSG4);
return FALSE;
}
if(!FTPcommand("TYPE I")) return FALSE; // 請求二進制傳輸
if(pasv) { // 建立被動傳輸方式
if(!FTPcommand("PASV")) return FALSE;
// 分析出服務器傳回的臨時IP地址以及端口號
if((i=m_retmsg.Find("("))==-1||(j=m_retmsg.Find(")"))==-1) return FALSE;
temp=m_retmsg.Mid(i+1,(j-i)-1);
i=temp.ReverseFind(',');
serversock=atol(temp.Right(temp.GetLength()-(i+1))); //get ls byte of server socket
temp=temp.Left(i);
i=temp.ReverseFind(',');
serversock+=256*atol(temp.Right(temp.GetLength()-(i+1))); // add ms byte to server socket
rhost=temp.Left(i);
while(1) { // 將逗號轉化成點
if((i=rhost.Find(","))==-1) break;
rhost.SetAt(i,'.');
}
}
else { // 設置主動的傳輸模式
m_retmsg.LoadString(IDS_FTPMSG6);
//獲取本地的ip地址,發送到服務器
if(!m_Ctrlsok->GetSockName(lhost,localsock)) return FALSE;;
while(1) { // 將IP地址中的點轉化成逗號
if((i=lhost.Find("."))==-1) break;
lhost.SetAt(i,',');
}
// 創建本地偵聽進程
if((!sockSrvr.Create(0,SOCK_STREAM,NULL))||(!sockSrvr.Listen())) return FALSE;
if(!sockSrvr.GetSockName(temp,localsock)) return FALSE;// get the port that MFC chose
// 將端口轉化成2字節,然后加入到本地IP地址中
lhost.Format(lhost+",%d,%d",localsock/256,localsock%256);
if(!FTPcommand("PORT "+lhost)) return FALSE;// 發送端口到服務器
}
// 發送 RETR/STOR 命令到服務器
if(!WriteStr((get?"RETR ":"STOR ")+remotefile)) return FALSE;
if(pasv) {// 如果是PASV模式,則創建socket并初始化外部數據連接,即數據傳輸通道
if(!datachannel.Create()) {
m_retmsg.LoadString(IDS_FTPMSG6);
return FALSE;
}
datachannel.Connect(rhost,serversock); // 試圖異步連接服務器
}
if(!ReadStr()||m_fc!=1) return FALSE; // 獲得服務器響應
if(!pasv&&!sockSrvr.Accept(datachannel)) return FALSE; // 接收從服務器來的內部綁定數據
// 連接成功,然后進行阻塞式數據傳輸
if((!datachannel.AsyncSelect(0))||(!datachannel.IOCtl(FIONBIO,&lpArgument))) {
m_retmsg.LoadString(IDS_FTPMSG6);
return FALSE;
}
while(1) { // 開始傳輸數據
TRY {
if(get) {
if(!(num=datachannel.Receive(cbuf,BUFSIZE,0))||num==SOCKET_ERROR) break; // (EOF||network error)
else datafile.Write(cbuf,num);
}
else {
if(!(numread=datafile.Read(cbuf,BUFSIZE))) break; //EOF
if((numsent=datachannel.Send(cbuf,numread,0))==SOCKET_ERROR) break;
// 如果發送出去的字節少于從文件讀取的字節,則調整發送指針,以使得數據發送正確
if(numread!=numsent) datafile.Seek(numsent-numread,CFile::current);
}
}
CATCH (CException,e) {
m_retmsg.LoadString(IDS_FTPMSG5);
return FALSE;
}
END_CATCH
}
datachannel.Close();
datafile.Close();
if(!FTPcommand("")) return FALSE; // 檢查從服務器發送的傳輸結果信息
return TRUE; // 傳輸成功
}
// 通過控制通道向服務器發送命令
BOOL CFTPCommandProcessor::WriteStr(CString outputstring)
{
m_retmsg.LoadString(IDS_FTPMSG6); // pre-load "network error" msg (in case there is one) #-)
TRY
{
m_pCtrlTxarch->WriteString(outputstring+"\r\n");
m_pCtrlTxarch->Flush();
}
CATCH(CException,e)
{
return FALSE;
}
END_CATCH
return TRUE;
}
// 獲得服務器的響應
BOOL CFTPCommandProcessor::ReadStr()
{
int retcode;
if(!ReadStr2()) return FALSE;
if(m_retmsg.GetLength()<4||m_retmsg.GetAt(3)!='-') return TRUE;
retcode=atol(m_retmsg);
while(1)
{ //處理多行服務器響應
if(m_retmsg.GetLength()>3&&(m_retmsg.GetAt(3)==' '&&atol(m_retmsg)==retcode))
return TRUE;
if(!ReadStr2())
return FALSE;
}
}
//////////////////////////////////////////////////////////////////////
// Private functions
//////////////////////////////////////////////////////////////////////
// 從服務器控制通道獲取一行響應
BOOL CFTPCommandProcessor::ReadStr2()
{
TRY
{
if(!m_pCtrlRxarch->ReadString(m_retmsg))
{
m_retmsg.LoadString(IDS_FTPMSG6);
return FALSE;
}
}
CATCH(CException,e)
{
m_retmsg.LoadString(IDS_FTPMSG6);
return FALSE;
}
END_CATCH
if(m_retmsg.GetLength()>0) m_fc=m_retmsg.GetAt(0)-48; // get 1st digit of the return code (indicates primary result)
return TRUE;
}
// 打開控制通道
BOOL CFTPCommandProcessor::OpenControlChannel(CString serverhost,int serverport)
{
m_retmsg.LoadString(IDS_FTPMSG2);
if(!(m_Ctrlsok=new CSocket))
return FALSE;
WSADATA wsaData;
WORD version=MAKEWORD(2,0);
int ret=WSAStartup(version,&wsaData);
if(ret!=0)
{
AfxMessageBox("網絡初始化失?。?quot;);
return FALSE;
}
if(!(m_Ctrlsok->Create()))
return FALSE;
m_retmsg.LoadString(IDS_FTPMSG3);
if(!(m_Ctrlsok->Connect(serverhost,serverport)))
return FALSE;
m_retmsg.LoadString(IDS_FTPMSG2);
if(!(m_pCtrlsokfile=new CSocketFile(m_Ctrlsok)))
return FALSE;
if(!(m_pCtrlRxarch=new CArchive(m_pCtrlsokfile,CArchive::load)))
return FALSE;
if(!(m_pCtrlTxarch=new CArchive(m_pCtrlsokfile,CArchive::store)))
return FALSE;
return TRUE;
}
// 關閉控制通道
void CFTPCommandProcessor::CloseControlChannel()
{
if(m_pCtrlTxarch) delete m_pCtrlTxarch;
m_pCtrlTxarch=NULL;
if(m_pCtrlRxarch) delete m_pCtrlRxarch;
m_pCtrlRxarch=NULL;
if(m_pCtrlsokfile) delete m_pCtrlsokfile;
m_pCtrlsokfile=NULL;
if(m_Ctrlsok) delete m_Ctrlsok;
m_Ctrlsok=NULL;
return;
}
//列出文件列表
BOOL CFTPCommandProcessor::List()
{
CString lhost,temp,rhost;
UINT localsock,i;
CFile datafile;
CSocket sockSrvr;
CAsyncSocket datachannel;
int num, sum;
const int BUFSIZE = 4096;
DWORD lpArgument=0;
m_buf.RemoveAll();
m_buf.SetSize(BUFSIZE);
if(!FTPcommand("TYPE I"))
return FALSE; // 請求二進制模式
m_retmsg.LoadString(IDS_FTPMSG6);
// 獲取本地IP地址
if(!m_Ctrlsok->GetSockName(lhost,localsock))
return FALSE;;
while(1) {
// 將點轉化成逗號
if((i=lhost.Find("."))==-1) break;
lhost.SetAt(i,',');
}
if((!sockSrvr.Create(0, SOCK_STREAM, NULL))
|| (!sockSrvr.Listen()))
return FALSE;
if(!sockSrvr.GetSockName(temp,localsock))
return FALSE;
lhost.Format(lhost+",%d,%d", localsock / 256, localsock % 256);
if(!FTPcommand("PORT "+lhost))
return FALSE;
if(!WriteStr("LIST") )
return FALSE;
if(!ReadStr())
return FALSE;
if(!sockSrvr.Accept(datachannel))
return FALSE;
if((!datachannel.AsyncSelect(0)) ||
(!datachannel.IOCtl(FIONBIO,&lpArgument))) {
m_retmsg.LoadString(IDS_FTPMSG6);
return FALSE;
}
sum = 0;
while(1) { // 獲得數據
TRY {
if(!(num = datachannel.Receive(m_buf.GetData() + sum, BUFSIZE, 0))
|| num == SOCKET_ERROR)
break;
TRACE("Received :%d\n", num);
Sleep(0);
sum += num;
m_buf.SetSize(sum + BUFSIZE);
}
CATCH (CException,e) {
m_retmsg.LoadString(IDS_FTPMSG5);
return FALSE;
}
END_CATCH
}
datachannel.Close();
}
void CFTPCommandProcessor::ProcessList()
{
}
BOOL CFTPCommandProcessor::GetLine(int& ndx)
{
m_strLine.Empty();
int nBytes = m_buf.GetSize();
BOOL bLine = FALSE;
while ( bLine == FALSE && ndx < nBytes )
{
char ch = (char)(m_buf.GetAt( ndx ));
switch( ch )
{
case '\n': // 行尾
bLine = TRUE;
break;
default: // 其他情況
m_strLine += ch;
break;
}
++ndx;
}
m_strLine = m_strLine.Left(m_strLine.GetLength() - 1);
return bLine;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -