123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529 |
- /*/////////////////////////////////////////////////////////////////////
- FTPSend.cpp (c) GDI 1999
- V1.0.0 (10/4/99)
- Phil Anderson. philip@gd-ind.com
- Simple FTP client functionality. If you have any problems with it,
- please tell me about them (or better still e-mail me the fixed
- code). Please feel free to use this code however you wish, although
- if you make changes please put your name in the source & comment what
- you did.
- Nothing awesome going on here at all (all sockets are used in
- synchronous blocking mode), but it does the following
- things WinInet doesn't seem to:
- * Supports loads of different firewalls (I think, I don't
- have access to all types so they haven't all been fully
- tested yet)
- * Allows you to execute any command on the FTP server
- * Adds 10K to your app install rather than 1Mb #;-)
- Functions return TRUE if everything went OK, FALSE if there was an,
- error. A message describing the outcome (normally the one returned
- from the server) will be in m_retmsg on return from the function.
- There are a few error msgs in the app's string table that you'll
- need to paste into your app, along with this file & FTPSend.h
- If you created your app without checking the "Use Windows Sockets"
- checkbox in AppWizard, you'll need to add the following bit of code
- to you app's InitInstance()
- if(!AfxSocketInit())
- {
- AfxMessageBox("Could not initialize Windows Sockets!");
- return FALSE;
- }
- To use:
- 1/ Create an object of CFTPSend.
- 2/ Use LogOnToServer() to connect to the server. Any arguments
- not used (e.g. if you're not using a firewall), pass an empty
- string or zero for numeric args. You must pass a server port
- number, use the FTP default of 21 if you don't know what it is.
- 3/ Use MoveFile() to upload/download a file, 1st arg is local file
- path, 2nd arg is remote file path, 3rd arg is TRUE for a PASV
- connection (required by some firewalls), FALSE otherwise, 4th arg
- is TRUE to upload, FALSE to download file. MoveFile only works in
- synchronous mode (ie the function will not return 'till the transfer
- is finished). File transfers are always of type BINARY.
- 4/ You can use FTPcommand() to execute FTP commands (eg
- FTPcommand("CWD /home/mydir") to change directory on the server),
- note that this function will return FALSE unless the server response
- is a 200 series code. This should work fine for most FTP commands,
- otherwise you can use WriteStr() and ReadStr() to send commands &
- interpret the response yourself. Use LogOffServer() to disconnect
- when done.
- /////////////////////////////////////////////////////////////////////*/
- #include "stdafx.h"
- #include "FTPSend.h"
- #include "AutoRun.h"
- #ifdef _DEBUG
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #define new DEBUG_NEW
- #endif
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- CFTPSend::CFTPSend()
- {
- m_pCtrlsokfile = NULL;
- m_pCtrlTxarch = NULL;
- m_pCtrlRxarch = NULL;
- m_Ctrlsok = NULL;
- }
- CFTPSend::~CFTPSend()
- {
- CloseControlChannel();
- }
- //////////////////////////////////////////////////////////////////////
- // Public Functions
- //////////////////////////////////////////////////////////////////////
- // function to connect & log on to FTP server
- //BOOL CFTPSend2::LogOnToServer(CString hostname,int hostport,CString username, CString password)
- BOOL CFTPSend::LogOnToServer(CString hostname, int hostport, CString username, CString password)
- {
- CString acct = "";
- CString fwhost = "";
- CString fwusername = "";
- CString fwpassword = "";
- int fwport = 21;
- int logontype = 0;
- int port, logonpoint = 0;
- const int LO = -2, ER = -1;
- CString buf, temp;
- //登陆方式数目
- const int NUMLOGIN = 9;
- //登陆方式数组
- int logonseq[NUMLOGIN][100] =
- {
- { 0, LO, 3, 1, LO, 6, 2, LO, ER }, // no firewall
- { 3, 6, 3, 4, 6, ER, 5, ER, 9, 0, LO, 12, 1, LO, 15, 2, LO, ER }, // SITE hostname
- { 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;
- //确定直接连接还是通过防火墙连接
- if (!logontype)
- {
- temp = hostname;
- port = hostport;
- }
- else
- {
- temp = fwhost;
- port = fwport;
- }
- if (hostport != 21)
- hostname.Format("%s:%d", hostname, hostport);
- //打开控制连接
- 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];
- switch (logonpoint)
- {
- //登陆错误
- case ER:
- // m_retmsg.LoadString(IDS_FTPMSG1);
- return FALSE;
- //完全登陆
- case LO:
- return TRUE;
- }
- }
- }
- // function to log off & close connection to FTP server
- void CFTPSend::LogOffServer() {
- WriteStr("QUIT");
- CloseControlChannel();
- }
- // function to execute commands on the FTP server
- BOOL CFTPSend::FTPcommand(CString command) {
- if (command != ""&&!WriteStr(command)) return FALSE;
- if ((!ReadStr()) || (m_fc != 2)) return FALSE;
- return TRUE;
- }
- int CFTPSend::MoveFile(CString remotefile, CString localfile, BOOL get)
- {
- BOOL pasv = 1;
- 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;
- DWORD fileleng = 0;
- DWORD sended = 0;
- DWORD tick = ::GetTickCount();
- // 打开本地文件
- if (!datafile.Open(localfile, (get ? CFile::modeWrite | CFile::modeCreate : CFile::modeRead)))
- {
- return FALSE;
- }
- fileleng = datafile.GetLength();
- //二进制传输模式
- 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)));
- 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
- {
- //获取本地控制连接IP
- if (!m_Ctrlsok->GetSockName(lhost, localsock))
- return FALSE;
- while (1)
- {
- //转换.
- if ((i = lhost.Find(".")) == -1) break;
- lhost.SetAt(i, ',');
- }
- //创建侦听Socket
- if ((!sockSrvr.Create(0, SOCK_STREAM, NULL)) || (!sockSrvr.Listen()))
- return FALSE;
- if (!sockSrvr.GetSockName(temp, localsock))
- return FALSE;
- lhost.Format("%s,%d,%d", lhost, localsock / 256, localsock % 256);
- //发送Port命令
- if (!FTPcommand("PORT " + lhost)) return FALSE;
- }
- /////////////////////////////////
- if (!FTPcommand("CWD \\"))
- {
- datafile.Close();
- return FALSE;
- }
- int pos = remotefile.Find("\\");
- while (pos != -1)
- {
- CString dir = remotefile.Left(pos);
- if (FTPcommand("CWD " + dir) == 0)
- {
- FTPcommand("MKD " + dir);
- if (FTPcommand("CWD " + dir) == 0)
- {
- datafile.Close();
- return 0;
- }
- }
- remotefile = remotefile.Right(remotefile.GetLength() - pos - 1);
- pos = remotefile.Find("\\");
- }
- ////////////////////////////////
- if (!WriteStr((get ? "RETR " : "STOR ") + remotefile))
- {
- datafile.Close();
- return FALSE;
- }
- if (pasv)
- {
- if (!datachannel.Create()) {
- datafile.Close();
- return FALSE;
- }
- //数据通道连接
- datachannel.Connect(rhost, serversock);
- }
- //获取响应
- if (!ReadStr() || m_fc != 1)
- {
- datafile.Close();
- return FALSE;
- }
- //通道建立
- if (!pasv&&!sockSrvr.Accept(datachannel))
- {
- datafile.Close();
- return FALSE;
- }
- if ((!datachannel.AsyncSelect(0)) || (!datachannel.IOCtl(FIONBIO, &lpArgument)))
- {
- datafile.Close();
- return FALSE;
- }
- //开始数据传输
- while (1)
- {
- TRY
- {
- //获取数据
- if (get)
- {
- //传输完毕
- if (!(num = datachannel.Receive(cbuf, BUFSIZE, 0)) || num == SOCKET_ERROR)
- break;
- else
- datafile.Write(cbuf, num);
- }
- //上传数据
- else
- {
- //传输完毕
- if (!(numread = datafile.Read(cbuf, BUFSIZE)))
- break;
- if ((numsent = datachannel.Send(cbuf, numread, 0)) == SOCKET_ERROR)
- break;
- //发送的数据少于实际文件,重新定位文件指针
- if (numread != numsent)
- datafile.Seek(numsent - numread, CFile::current);
- sended += numsent;
- }
- }
- CATCH(CException, e) {
- return FALSE;
- }
- END_CATCH
- }
- //数据通道关闭
- datachannel.Close();
- datafile.Close();
- //获取响应
- if (!FTPcommand("NOOP"))
- return FALSE;
- return TRUE;
- }
- // function to send a command string on the server control channel
- BOOL CFTPSend::WriteStr(CString outputstring)
- {
- //载入错误信息,便于后面显示
- // m_retmsg.LoadString(IDS_FTPMSG6);
- //发送信息
- TRY{
- m_pCtrlTxarch->WriteString(outputstring + "\r\n");
- m_pCtrlTxarch->Flush();
- }
- //捕获异常
- CATCH(CException, e) {
- return FALSE;
- }
- END_CATCH
- return TRUE;
- }
- // this function gets the server response line
- BOOL CFTPSend::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
- //////////////////////////////////////////////////////////////////////
- // read a single response line from the server control channel
- BOOL CFTPSend::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;
- return TRUE;
- }
- // open the control channel to the FTP server
- BOOL CFTPSend::OpenControlChannel(CString serverhost, int serverport) {
- // m_retmsg.LoadString(IDS_FTPMSG2);
- if (!(m_Ctrlsok = new CSocket))
- return FALSE;
- if (!(m_Ctrlsok->Create()))
- return FALSE;
- // m_retmsg.LoadString(IDS_FTPMSG3);
- //控制通道Socket连接服务器
- 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;
- }
- // close the control channel to the FTP server
- void CFTPSend::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;
- }
|