ftpclnt.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:9k
- /*
- * ftpclnt.cxx
- *
- * FTP client class.
- *
- * Portable Windows Library
- *
- * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.0 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Original Code is Portable Windows Library.
- *
- * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
- *
- * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
- * All Rights Reserved.
- *
- * Contributor(s): ______________________________________.
- *
- * $Log: ftpclnt.cxx,v $
- * Revision 1.9 2000/06/21 01:14:23 robertj
- * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
- *
- * Revision 1.8 2000/04/07 06:29:46 rogerh
- * Add a short term workaround for an Internal Compiler Error on MAC OS X when
- * returning certain types of PString. Submitted by Kevin Packard.
- *
- * Revision 1.7 1998/12/23 00:34:55 robertj
- * Fixed normal TCP socket support after adding SOCKS support.
- *
- * Revision 1.6 1998/12/22 10:29:42 robertj
- * Added support for SOCKS based channels.
- *
- * Revision 1.5 1998/12/18 03:48:32 robertj
- * Fixed wanring on PPC linux compile
- *
- * Revision 1.4 1998/11/30 04:50:47 robertj
- * New directory structure
- *
- * Revision 1.3 1998/09/23 06:22:00 robertj
- * Added open source copyright license.
- *
- * Revision 1.2 1997/03/28 13:06:58 robertj
- * made STAT command more robust for getting file info from weird FTP servers.
- *
- * Revision 1.1 1996/09/14 13:02:18 robertj
- * Initial revision
- *
- */
- #include <ptlib.h>
- #include <ptlib/sockets.h>
- #include <ptclib/ftp.h>
- /////////////////////////////////////////////////////////
- // FTP Client
- PFTPClient::PFTPClient()
- {
- }
- PFTPClient::~PFTPClient()
- {
- Close();
- }
- BOOL PFTPClient::Close()
- {
- if (!IsOpen())
- return FALSE;
- BOOL ok = ExecuteCommand(QUIT)/100 == 2;
- return PFTP::Close() && ok;
- }
- BOOL PFTPClient::OnOpen()
- {
- if (!ReadResponse() || lastResponseCode != 220)
- return FALSE;
- // the default data port for a server is the adjacent port
- PIPSocket::Address remoteHost;
- PIPSocket * socket = GetSocket();
- if (socket == NULL)
- return FALSE;
- socket->GetPeerAddress(remoteHost, remotePort);
- remotePort--;
- return TRUE;
- }
- BOOL PFTPClient::LogIn(const PString & username, const PString & password)
- {
- if (ExecuteCommand(USER, username)/100 != 3)
- return FALSE;
- return ExecuteCommand(PASS, password)/100 == 2;
- }
- PString PFTPClient::GetSystemType()
- {
- if (ExecuteCommand(SYST)/100 != 2)
- return PString();
- return lastResponseInfo.Left(lastResponseInfo.Find(' '));
- }
- BOOL PFTPClient::SetType(RepresentationType type)
- {
- static const char * const typeCode[] = { "A", "E", "I" };
- PAssert((PINDEX)type < PARRAYSIZE(typeCode), PInvalidParameter);
- return ExecuteCommand(TYPE, typeCode[type])/100 == 2;
- }
- BOOL PFTPClient::ChangeDirectory(const PString & dirPath)
- {
- return ExecuteCommand(CWD, dirPath)/100 == 2;
- }
- PString PFTPClient::GetCurrentDirectory()
- {
- if (ExecuteCommand(PWD) != 257)
- return PString();
- PINDEX quote1 = lastResponseInfo.Find('"');
- if (quote1 == P_MAX_INDEX)
- return PString();
- PINDEX quote2 = quote1 + 1;
- do {
- quote2 = lastResponseInfo.Find('"', quote2);
- if (quote2 == P_MAX_INDEX)
- return PString();
- while (lastResponseInfo[quote2]=='"' && lastResponseInfo[quote2+1]=='"')
- quote2 += 2;
- } while (lastResponseInfo[quote2] != '"');
- #if defined(P_MACOSX) // make Apple's gnu compiler happy
- PString retval = lastResponseInfo(quote1+1, quote2-1);
- return retval;
- #else
- return lastResponseInfo(quote1+1, quote2-1);
- #endif
- }
- PStringArray PFTPClient::GetDirectoryNames(NameTypes type,
- DataChannelType ctype)
- {
- return GetDirectoryNames(PString(), type, ctype);
- }
- PStringArray PFTPClient::GetDirectoryNames(const PString & path,
- NameTypes type,
- DataChannelType ctype)
- {
- SetType(PFTP::ASCII);
- Commands lcmd = type == DetailedNames ? LIST : NLST;
- PTCPSocket * socket = ctype != Passive ? NormalClientTransfer(lcmd, path)
- : PassiveClientTransfer(lcmd, path);
- if (socket == NULL)
- return PStringArray();
- PString response = lastResponseInfo;
- PString str;
- int count = 0;
- while(socket->Read(str.GetPointer(count+1000)+count, 1000))
- count += socket->GetLastReadCount();
- str.SetSize(count+1);
- delete socket;
- ReadResponse();
- lastResponseInfo = response + 'n' + lastResponseInfo;
- return str.Lines();
- }
- PString PFTPClient::GetFileStatus(const PString & path, DataChannelType ctype)
- {
- if (ExecuteCommand(STATcmd, path)/100 == 2 && lastResponseInfo.Find(path) != P_MAX_INDEX) {
- PINDEX start = lastResponseInfo.Find('n');
- if (start != P_MAX_INDEX) {
- PINDEX end = lastResponseInfo.Find('n', ++start);
- if (end != P_MAX_INDEX)
- return lastResponseInfo(start, end-1);
- }
- }
- PTCPSocket * socket = ctype != Passive ? NormalClientTransfer(LIST, path)
- : PassiveClientTransfer(LIST, path);
- if (socket == NULL)
- return PString();
- PString str;
- socket->Read(str.GetPointer(200), 199);
- str[socket->GetLastReadCount()] = ' ';
- delete socket;
- ReadResponse();
- PINDEX end = str.FindOneOf("rn");
- if (end != P_MAX_INDEX)
- str[end] = ' ';
- return str;
- }
- PTCPSocket * PFTPClient::NormalClientTransfer(Commands cmd,
- const PString & args)
- {
- PIPSocket * socket = GetSocket();
- if (socket == NULL)
- return NULL;
- // setup a socket so we can tell the host where to connect to
- PTCPSocket * listenSocket = (PTCPSocket *)socket->Clone();
- listenSocket->SetPort(0); // Want new random port number
- listenSocket->Listen();
- // The following is just used to automatically delete listenSocket
- PIndirectChannel autoDeleteSocket;
- autoDeleteSocket.Open(listenSocket);
- // get host address and port to send to other end
- WORD localPort = listenSocket->GetPort();
- PIPSocket::Address localAddr;
- socket->GetLocalAddress(localAddr);
- // send PORT command to host
- if (!SendPORT(localAddr, localPort))
- return NULL;
- if (ExecuteCommand(cmd, args)/100 != 1)
- return NULL;
- PTCPSocket * dataSocket = (PTCPSocket *)socket->Clone();
- if (dataSocket->Accept(*listenSocket))
- return dataSocket;
- delete dataSocket;
- return NULL;
- }
- PTCPSocket * PFTPClient::PassiveClientTransfer(Commands cmd,
- const PString & args)
- {
- PIPSocket::Address passiveAddress;
- WORD passivePort;
- if (ExecuteCommand(PASV) != 227)
- return NULL;
- PINDEX start = lastResponseInfo.FindOneOf("0123456789");
- if (start == P_MAX_INDEX)
- return NULL;
- PStringArray bytes = lastResponseInfo(start, P_MAX_INDEX).Tokenise(',');
- if (bytes.GetSize() != 6)
- return NULL;
- passiveAddress = PIPSocket::Address((BYTE)bytes[0].AsInteger(),
- (BYTE)bytes[1].AsInteger(),
- (BYTE)bytes[2].AsInteger(),
- (BYTE)bytes[3].AsInteger());
- passivePort = (WORD)(bytes[4].AsInteger()*256 + bytes[5].AsInteger());
- PTCPSocket * socket = new PTCPSocket(passiveAddress, passivePort);
- if (socket->IsOpen())
- if (ExecuteCommand(cmd, args)/100 == 1)
- return socket;
- delete socket;
- return NULL;
- }
- PTCPSocket * PFTPClient::GetFile(const PString & filename,
- DataChannelType channel)
- {
- return channel != Passive ? NormalClientTransfer(RETR, filename)
- : PassiveClientTransfer(RETR, filename);
- }
- PTCPSocket * PFTPClient::PutFile(const PString & filename,
- DataChannelType channel)
- {
- return channel != Passive ? NormalClientTransfer(STOR, filename)
- : PassiveClientTransfer(STOR, filename);
- }
- // End of File ///////////////////////////////////////////////////////////////