6 * Portable Windows Library
8 * Copyright (c) 1993-2002 Equivalence Pty. Ltd.
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/
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
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Contributor(s): ______________________________________.
27 * Revision 1.11 2002/11/06 22:47:24 robertj
28 * Fixed header comment (copyright etc)
30 * Revision 1.10 2002/10/10 04:43:44 robertj
31 * VxWorks port, thanks Martijn Roest
33 * Revision 1.9 2000/06/21 01:14:23 robertj
34 * AIX port, thanks Wolfgang Platzer (wolfgang.platzer@infonova.at).
36 * Revision 1.8 2000/04/07 06:29:46 rogerh
37 * Add a short term workaround for an Internal Compiler Error on MAC OS X when
38 * returning certain types of PString. Submitted by Kevin Packard.
40 * Revision 1.7 1998/12/23 00:34:55 robertj
41 * Fixed normal TCP socket support after adding SOCKS support.
43 * Revision 1.6 1998/12/22 10:29:42 robertj
44 * Added support for SOCKS based channels.
46 * Revision 1.5 1998/12/18 03:48:32 robertj
47 * Fixed wanring on PPC linux compile
49 * Revision 1.4 1998/11/30 04:50:47 robertj
50 * New directory structure
52 * Revision 1.3 1998/09/23 06:22:00 robertj
53 * Added open source copyright license.
55 * Revision 1.2 1997/03/28 13:06:58 robertj
56 * made STAT command more robust for getting file info from weird FTP servers.
58 * Revision 1.1 1996/09/14 13:02:18 robertj
64 #include <ptlib/sockets.h>
65 #include <ptclib/ftp.h>
68 /////////////////////////////////////////////////////////
71 PFTPClient::PFTPClient()
76 PFTPClient::~PFTPClient()
82 BOOL
PFTPClient::Close()
86 BOOL ok
= ExecuteCommand(QUIT
)/100 == 2;
87 return PFTP::Close() && ok
;
90 BOOL
PFTPClient::OnOpen()
92 if (!ReadResponse() || lastResponseCode
!= 220)
95 // the default data port for a server is the adjacent port
96 PIPSocket::Address remoteHost
;
97 PIPSocket
* socket
= GetSocket();
101 socket
->GetPeerAddress(remoteHost
, remotePort
);
107 BOOL
PFTPClient::LogIn(const PString
& username
, const PString
& password
)
109 if (ExecuteCommand(USER
, username
)/100 != 3)
111 return ExecuteCommand(PASS
, password
)/100 == 2;
115 PString
PFTPClient::GetSystemType()
117 if (ExecuteCommand(SYST
)/100 != 2)
120 return lastResponseInfo
.Left(lastResponseInfo
.Find(' '));
124 BOOL
PFTPClient::SetType(RepresentationType type
)
126 static const char * const typeCode
[] = { "A", "E", "I" };
127 PAssert((PINDEX
)type
< PARRAYSIZE(typeCode
), PInvalidParameter
);
128 return ExecuteCommand(TYPE
, typeCode
[type
])/100 == 2;
132 BOOL
PFTPClient::ChangeDirectory(const PString
& dirPath
)
134 return ExecuteCommand(CWD
, dirPath
)/100 == 2;
138 PString
PFTPClient::GetCurrentDirectory()
140 if (ExecuteCommand(PWD
) != 257)
143 PINDEX quote1
= lastResponseInfo
.Find('"');
144 if (quote1
== P_MAX_INDEX
)
147 PINDEX quote2
= quote1
+ 1;
149 quote2
= lastResponseInfo
.Find('"', quote2
);
150 if (quote2
== P_MAX_INDEX
)
153 while (lastResponseInfo
[quote2
]=='"' && lastResponseInfo
[quote2
+1]=='"')
156 } while (lastResponseInfo
[quote2
] != '"');
158 // make Apple's and Tornado's gnu compiler happy
159 PString retval
= lastResponseInfo(quote1
+1, quote2
-1);
164 PStringArray
PFTPClient::GetDirectoryNames(NameTypes type
,
165 DataChannelType ctype
)
167 return GetDirectoryNames(PString(), type
, ctype
);
171 PStringArray
PFTPClient::GetDirectoryNames(const PString
& path
,
173 DataChannelType ctype
)
175 SetType(PFTP::ASCII
);
177 Commands lcmd
= type
== DetailedNames
? LIST
: NLST
;
178 PTCPSocket
* socket
= ctype
!= Passive
? NormalClientTransfer(lcmd
, path
)
179 : PassiveClientTransfer(lcmd
, path
);
181 return PStringArray();
183 PString response
= lastResponseInfo
;
186 while(socket
->Read(str
.GetPointer(count
+1000)+count
, 1000))
187 count
+= socket
->GetLastReadCount();
188 str
.SetSize(count
+1);
192 lastResponseInfo
= response
+ '\n' + lastResponseInfo
;
197 PString
PFTPClient::GetFileStatus(const PString
& path
, DataChannelType ctype
)
199 if (ExecuteCommand(STATcmd
, path
)/100 == 2 && lastResponseInfo
.Find(path
) != P_MAX_INDEX
) {
200 PINDEX start
= lastResponseInfo
.Find('\n');
201 if (start
!= P_MAX_INDEX
) {
202 PINDEX end
= lastResponseInfo
.Find('\n', ++start
);
203 if (end
!= P_MAX_INDEX
)
204 return lastResponseInfo(start
, end
-1);
208 PTCPSocket
* socket
= ctype
!= Passive
? NormalClientTransfer(LIST
, path
)
209 : PassiveClientTransfer(LIST
, path
);
214 socket
->Read(str
.GetPointer(200), 199);
215 str
[socket
->GetLastReadCount()] = '\0';
219 PINDEX end
= str
.FindOneOf("\r\n");
220 if (end
!= P_MAX_INDEX
)
226 PTCPSocket
* PFTPClient::NormalClientTransfer(Commands cmd
,
227 const PString
& args
)
229 PIPSocket
* socket
= GetSocket();
233 // setup a socket so we can tell the host where to connect to
234 PTCPSocket
* listenSocket
= (PTCPSocket
*)socket
->Clone();
235 listenSocket
->SetPort(0); // Want new random port number
236 listenSocket
->Listen();
238 // The following is just used to automatically delete listenSocket
239 PIndirectChannel autoDeleteSocket
;
240 autoDeleteSocket
.Open(listenSocket
);
242 // get host address and port to send to other end
243 WORD localPort
= listenSocket
->GetPort();
244 PIPSocket::Address localAddr
;
245 socket
->GetLocalAddress(localAddr
);
247 // send PORT command to host
248 if (!SendPORT(localAddr
, localPort
))
251 if (ExecuteCommand(cmd
, args
)/100 != 1)
254 PTCPSocket
* dataSocket
= (PTCPSocket
*)socket
->Clone();
255 if (dataSocket
->Accept(*listenSocket
))
263 PTCPSocket
* PFTPClient::PassiveClientTransfer(Commands cmd
,
264 const PString
& args
)
266 PIPSocket::Address passiveAddress
;
269 if (ExecuteCommand(PASV
) != 227)
272 PINDEX start
= lastResponseInfo
.FindOneOf("0123456789");
273 if (start
== P_MAX_INDEX
)
276 PStringArray bytes
= lastResponseInfo(start
, P_MAX_INDEX
).Tokenise(',');
277 if (bytes
.GetSize() != 6)
280 passiveAddress
= PIPSocket::Address((BYTE
)bytes
[0].AsInteger(),
281 (BYTE
)bytes
[1].AsInteger(),
282 (BYTE
)bytes
[2].AsInteger(),
283 (BYTE
)bytes
[3].AsInteger());
284 passivePort
= (WORD
)(bytes
[4].AsInteger()*256 + bytes
[5].AsInteger());
286 PTCPSocket
* socket
= new PTCPSocket(passiveAddress
, passivePort
);
287 if (socket
->IsOpen())
288 if (ExecuteCommand(cmd
, args
)/100 == 1)
296 PTCPSocket
* PFTPClient::GetFile(const PString
& filename
,
297 DataChannelType channel
)
299 return channel
!= Passive
? NormalClientTransfer(RETR
, filename
)
300 : PassiveClientTransfer(RETR
, filename
);
304 PTCPSocket
* PFTPClient::PutFile(const PString
& filename
,
305 DataChannelType channel
)
307 return channel
!= Passive
? NormalClientTransfer(STOR
, filename
)
308 : PassiveClientTransfer(STOR
, filename
);
313 // End of File ///////////////////////////////////////////////////////////////