ftpclnt.cxx
上传用户:hzhsqp
上传日期:2007-01-06
资源大小:1600k
文件大小:9k
源码类别:

IP电话/视频会议

开发平台:

Visual C++

  1. /*
  2.  * ftpclnt.cxx
  3.  *
  4.  * FTP client class.
  5.  *
  6.  * Portable Windows Library
  7.  *
  8.  * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
  9.  *
  10.  * The contents of this file are subject to the Mozilla Public License
  11.  * Version 1.0 (the "License"); you may not use this file except in
  12.  * compliance with the License. You may obtain a copy of the License at
  13.  * http://www.mozilla.org/MPL/
  14.  *
  15.  * Software distributed under the License is distributed on an "AS IS"
  16.  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  17.  * the License for the specific language governing rights and limitations
  18.  * under the License.
  19.  *
  20.  * The Original Code is Portable Windows Library.
  21.  *
  22.  * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
  23.  *
  24.  * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
  25.  * All Rights Reserved.
  26.  *
  27.  * Contributor(s): ______________________________________.
  28.  *
  29.  * $Log: ftpclnt.cxx,v $
  30.  * Revision 1.9  2000/06/21 01:14:23  robertj
  31.  * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
  32.  *
  33.  * Revision 1.8  2000/04/07 06:29:46  rogerh
  34.  * Add a short term workaround for an Internal Compiler Error on MAC OS X when
  35.  * returning certain types of PString. Submitted by Kevin Packard.
  36.  *
  37.  * Revision 1.7  1998/12/23 00:34:55  robertj
  38.  * Fixed normal TCP socket support after adding SOCKS support.
  39.  *
  40.  * Revision 1.6  1998/12/22 10:29:42  robertj
  41.  * Added support for SOCKS based channels.
  42.  *
  43.  * Revision 1.5  1998/12/18 03:48:32  robertj
  44.  * Fixed wanring on PPC linux compile
  45.  *
  46.  * Revision 1.4  1998/11/30 04:50:47  robertj
  47.  * New directory structure
  48.  *
  49.  * Revision 1.3  1998/09/23 06:22:00  robertj
  50.  * Added open source copyright license.
  51.  *
  52.  * Revision 1.2  1997/03/28 13:06:58  robertj
  53.  * made STAT command more robust for getting file info from weird FTP servers.
  54.  *
  55.  * Revision 1.1  1996/09/14 13:02:18  robertj
  56.  * Initial revision
  57.  *
  58.  */
  59. #include <ptlib.h>
  60. #include <ptlib/sockets.h>
  61. #include <ptclib/ftp.h>
  62. /////////////////////////////////////////////////////////
  63. //  FTP Client
  64. PFTPClient::PFTPClient()
  65. {
  66. }
  67. PFTPClient::~PFTPClient()
  68. {
  69.   Close();
  70. }
  71. BOOL PFTPClient::Close()
  72. {
  73.   if (!IsOpen())
  74.     return FALSE;
  75.   BOOL ok = ExecuteCommand(QUIT)/100 == 2;
  76.   return PFTP::Close() && ok;
  77. }
  78. BOOL PFTPClient::OnOpen()
  79. {
  80.   if (!ReadResponse() || lastResponseCode != 220)
  81.     return FALSE;
  82.   // the default data port for a server is the adjacent port
  83.   PIPSocket::Address remoteHost;
  84.   PIPSocket * socket = GetSocket();
  85.   if (socket == NULL)
  86.     return FALSE;
  87.   socket->GetPeerAddress(remoteHost, remotePort);
  88.   remotePort--;
  89.   return TRUE;
  90. }
  91. BOOL PFTPClient::LogIn(const PString & username, const PString & password)
  92. {
  93.   if (ExecuteCommand(USER, username)/100 != 3)
  94.     return FALSE;
  95.   return ExecuteCommand(PASS, password)/100 == 2;
  96. }
  97. PString PFTPClient::GetSystemType()
  98. {
  99.   if (ExecuteCommand(SYST)/100 != 2)
  100.     return PString();
  101.   return lastResponseInfo.Left(lastResponseInfo.Find(' '));
  102. }
  103. BOOL PFTPClient::SetType(RepresentationType type)
  104. {
  105.   static const char * const typeCode[] = { "A", "E", "I" };
  106.   PAssert((PINDEX)type < PARRAYSIZE(typeCode), PInvalidParameter);
  107.   return ExecuteCommand(TYPE, typeCode[type])/100 == 2;
  108. }
  109. BOOL PFTPClient::ChangeDirectory(const PString & dirPath)
  110. {
  111.   return ExecuteCommand(CWD, dirPath)/100 == 2;
  112. }
  113. PString PFTPClient::GetCurrentDirectory()
  114. {
  115.   if (ExecuteCommand(PWD) != 257)
  116.     return PString();
  117.   PINDEX quote1 = lastResponseInfo.Find('"');
  118.   if (quote1 == P_MAX_INDEX)
  119.     return PString();
  120.   PINDEX quote2 = quote1 + 1;
  121.   do {
  122.     quote2 = lastResponseInfo.Find('"', quote2);
  123.     if (quote2 == P_MAX_INDEX)
  124.       return PString();
  125.     while (lastResponseInfo[quote2]=='"' && lastResponseInfo[quote2+1]=='"')
  126.       quote2 += 2;
  127.   } while (lastResponseInfo[quote2] != '"');
  128. #if defined(P_MACOSX) // make Apple's gnu compiler happy
  129.   PString retval = lastResponseInfo(quote1+1, quote2-1);
  130.   return retval;
  131. #else
  132.   return lastResponseInfo(quote1+1, quote2-1);
  133. #endif
  134. }
  135. PStringArray PFTPClient::GetDirectoryNames(NameTypes type,
  136.                                            DataChannelType ctype)
  137. {
  138.   return GetDirectoryNames(PString(), type, ctype);
  139. }
  140. PStringArray PFTPClient::GetDirectoryNames(const PString & path,
  141.                                           NameTypes type,
  142.                                           DataChannelType ctype)
  143. {
  144.   SetType(PFTP::ASCII);
  145.   Commands lcmd = type == DetailedNames ? LIST : NLST;
  146.   PTCPSocket * socket = ctype != Passive ? NormalClientTransfer(lcmd, path)
  147.                                          : PassiveClientTransfer(lcmd, path);
  148.   if (socket == NULL)
  149.     return PStringArray();
  150.   PString response = lastResponseInfo;
  151.   PString str;
  152.   int count = 0;
  153.   while(socket->Read(str.GetPointer(count+1000)+count, 1000))
  154.     count += socket->GetLastReadCount();
  155.   str.SetSize(count+1);
  156.   delete socket;
  157.   ReadResponse();
  158.   lastResponseInfo = response + 'n' + lastResponseInfo;
  159.   return str.Lines();
  160. }
  161. PString PFTPClient::GetFileStatus(const PString & path, DataChannelType ctype)
  162. {
  163.   if (ExecuteCommand(STATcmd, path)/100 == 2 && lastResponseInfo.Find(path) != P_MAX_INDEX) {
  164.     PINDEX start = lastResponseInfo.Find('n');
  165.     if (start != P_MAX_INDEX) {
  166.       PINDEX end = lastResponseInfo.Find('n', ++start);
  167.       if (end != P_MAX_INDEX)
  168.         return lastResponseInfo(start, end-1);
  169.     }
  170.   }
  171.   PTCPSocket * socket = ctype != Passive ? NormalClientTransfer(LIST, path)
  172.                                          : PassiveClientTransfer(LIST, path);
  173.   if (socket == NULL)
  174.     return PString();
  175.   PString str;
  176.   socket->Read(str.GetPointer(200), 199);
  177.   str[socket->GetLastReadCount()] = '';
  178.   delete socket;
  179.   ReadResponse();
  180.   PINDEX end = str.FindOneOf("rn");
  181.   if (end != P_MAX_INDEX)
  182.     str[end] = '';
  183.   return str;
  184. }
  185. PTCPSocket * PFTPClient::NormalClientTransfer(Commands cmd,
  186.                                               const PString & args)
  187. {
  188.   PIPSocket * socket = GetSocket();
  189.   if (socket == NULL)
  190.     return NULL;
  191.   // setup a socket so we can tell the host where to connect to
  192.   PTCPSocket * listenSocket = (PTCPSocket *)socket->Clone();
  193.   listenSocket->SetPort(0);  // Want new random port number
  194.   listenSocket->Listen();
  195.   // The following is just used to automatically delete listenSocket
  196.   PIndirectChannel autoDeleteSocket;
  197.   autoDeleteSocket.Open(listenSocket);
  198.   // get host address and port to send to other end
  199.   WORD localPort = listenSocket->GetPort();
  200.   PIPSocket::Address localAddr;
  201.   socket->GetLocalAddress(localAddr);
  202.   // send PORT command to host
  203.   if (!SendPORT(localAddr, localPort))
  204.     return NULL;
  205.   if (ExecuteCommand(cmd, args)/100 != 1)
  206.     return NULL;
  207.   PTCPSocket * dataSocket = (PTCPSocket *)socket->Clone();
  208.   if (dataSocket->Accept(*listenSocket))
  209.     return dataSocket;
  210.   delete dataSocket;
  211.   return NULL;
  212. }
  213. PTCPSocket * PFTPClient::PassiveClientTransfer(Commands cmd,
  214.                                                const PString & args)
  215. {
  216.   PIPSocket::Address passiveAddress;
  217.   WORD passivePort;
  218.   if (ExecuteCommand(PASV) != 227)
  219.     return NULL;
  220.   PINDEX start = lastResponseInfo.FindOneOf("0123456789");
  221.   if (start == P_MAX_INDEX)
  222.     return NULL;
  223.   PStringArray bytes = lastResponseInfo(start, P_MAX_INDEX).Tokenise(',');
  224.   if (bytes.GetSize() != 6)
  225.     return NULL;
  226.   passiveAddress = PIPSocket::Address((BYTE)bytes[0].AsInteger(),
  227.                                       (BYTE)bytes[1].AsInteger(),
  228.                                       (BYTE)bytes[2].AsInteger(),
  229.                                       (BYTE)bytes[3].AsInteger());
  230.   passivePort = (WORD)(bytes[4].AsInteger()*256 + bytes[5].AsInteger());
  231.   PTCPSocket * socket = new PTCPSocket(passiveAddress, passivePort);
  232.   if (socket->IsOpen())
  233.     if (ExecuteCommand(cmd, args)/100 == 1)
  234.       return socket;
  235.   delete socket;
  236.   return NULL;
  237. }
  238. PTCPSocket * PFTPClient::GetFile(const PString & filename,
  239.                                  DataChannelType channel)
  240. {
  241.   return channel != Passive ? NormalClientTransfer(RETR, filename)
  242.                             : PassiveClientTransfer(RETR, filename);
  243. }
  244. PTCPSocket * PFTPClient::PutFile(const PString & filename,
  245.                                  DataChannelType channel)
  246. {
  247.   return channel != Passive ? NormalClientTransfer(STOR, filename)
  248.                             : PassiveClientTransfer(STOR, filename);
  249. }
  250. // End of File ///////////////////////////////////////////////////////////////