1//
2// FTPStreamFactory.cpp
3//
4// Library: Net
5// Package: FTP
6// Module: FTPStreamFactory
7//
8// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Net/FTPStreamFactory.h"
16#include "Poco/Net/FTPClientSession.h"
17#include "Poco/Net/NetException.h"
18#include "Poco/URI.h"
19#include "Poco/URIStreamOpener.h"
20#include "Poco/UnbufferedStreamBuf.h"
21#include "Poco/Path.h"
22
23
24using Poco::URIStreamFactory;
25using Poco::URI;
26using Poco::URIStreamOpener;
27using Poco::UnbufferedStreamBuf;
28using Poco::Path;
29
30
31namespace Poco {
32namespace Net {
33
34
35class FTPStreamBuf: public UnbufferedStreamBuf
36{
37public:
38 FTPStreamBuf(std::istream& istr):
39 _istr(istr)
40 {
41 // make sure exceptions from underlying string propagate
42 _istr.exceptions(std::ios::badbit);
43 }
44
45 ~FTPStreamBuf()
46 {
47 }
48
49private:
50 int readFromDevice()
51 {
52 return _istr.get();
53 }
54
55 std::istream& _istr;
56};
57
58
59class FTPIOS: public virtual std::ios
60{
61public:
62 FTPIOS(std::istream& istr):
63 _buf(istr)
64 {
65 poco_ios_init(&_buf);
66 }
67
68 ~FTPIOS()
69 {
70 }
71
72 FTPStreamBuf* rdbuf()
73 {
74 return &_buf;
75 }
76
77protected:
78 FTPStreamBuf _buf;
79};
80
81
82class FTPStream: public FTPIOS, public std::istream
83{
84public:
85 FTPStream(std::istream& istr, FTPClientSession* pSession):
86 FTPIOS(istr),
87 std::istream(&_buf),
88 _pSession(pSession)
89 {
90 }
91
92 ~FTPStream()
93 {
94 delete _pSession;
95 }
96
97private:
98 FTPClientSession* _pSession;
99};
100
101
102FTPPasswordProvider::FTPPasswordProvider()
103{
104}
105
106
107FTPPasswordProvider::~FTPPasswordProvider()
108{
109}
110
111
112std::string FTPStreamFactory::_anonymousPassword("poco@localhost");
113FTPPasswordProvider* FTPStreamFactory::_pPasswordProvider(0);
114
115
116FTPStreamFactory::FTPStreamFactory()
117{
118}
119
120
121FTPStreamFactory::~FTPStreamFactory()
122{
123}
124
125
126std::istream* FTPStreamFactory::open(const URI& uri)
127{
128 poco_assert (uri.getScheme() == "ftp");
129
130 FTPClientSession* pSession = new FTPClientSession(uri.getHost(), uri.getPort());
131 try
132 {
133 std::string username;
134 std::string password;
135 getUserInfo(uri, username, password);
136
137 std::string path;
138 char type;
139 getPathAndType(uri, path, type);
140
141 pSession->login(username, password);
142 if (type == 'a')
143 pSession->setFileType(FTPClientSession::TYPE_TEXT);
144
145 Path p(path, Path::PATH_UNIX);
146 p.makeFile();
147 for (int i = 0; i < p.depth(); ++i)
148 pSession->setWorkingDirectory(p[i]);
149 std::string file(p.getFileName());
150 std::istream& istr = (type == 'd' ? pSession->beginList(file) : pSession->beginDownload(file));
151 return new FTPStream(istr, pSession);
152 }
153 catch (...)
154 {
155 delete pSession;
156 throw;
157 }
158}
159
160
161void FTPStreamFactory::setAnonymousPassword(const std::string& password)
162{
163 _anonymousPassword = password;
164}
165
166
167const std::string& FTPStreamFactory::getAnonymousPassword()
168{
169 return _anonymousPassword;
170}
171
172
173void FTPStreamFactory::setPasswordProvider(FTPPasswordProvider* pProvider)
174{
175 _pPasswordProvider = pProvider;
176}
177
178
179FTPPasswordProvider* FTPStreamFactory::getPasswordProvider()
180{
181 return _pPasswordProvider;
182}
183
184
185void FTPStreamFactory::splitUserInfo(const std::string& userInfo, std::string& username, std::string& password)
186{
187 std::string::size_type pos = userInfo.find(':');
188 if (pos != std::string::npos)
189 {
190 username.assign(userInfo, 0, pos++);
191 password.assign(userInfo, pos, userInfo.size() - pos);
192 }
193 else username = userInfo;
194}
195
196
197void FTPStreamFactory::getUserInfo(const URI& uri, std::string& username, std::string& password)
198{
199 splitUserInfo(uri.getUserInfo(), username, password);
200 if (username.empty())
201 {
202 username = "anonymous";
203 password = _anonymousPassword;
204 }
205 else if (password.empty())
206 {
207 if (_pPasswordProvider)
208 password = _pPasswordProvider->password(username, uri.getHost());
209 else
210 throw FTPException(std::string("Password required for ") + username + "@" + uri.getHost());
211 }
212}
213
214
215void FTPStreamFactory::getPathAndType(const Poco::URI& uri, std::string& path, char& type)
216{
217 path = uri.getPath();
218 type = 'i';
219 std::string::size_type pos = path.rfind(';');
220 if (pos != std::string::npos)
221 {
222 if (path.length() == pos + 7 && path.compare(pos + 1, 5, "type=") == 0)
223 {
224 type = path[pos + 6];
225 path.resize(pos);
226 }
227 }
228}
229
230
231void FTPStreamFactory::registerFactory()
232{
233 URIStreamOpener::defaultOpener().registerStreamFactory("ftp", new FTPStreamFactory);
234}
235
236
237void FTPStreamFactory::unregisterFactory()
238{
239 URIStreamOpener::defaultOpener().unregisterStreamFactory("ftp");
240}
241
242
243} } // namespace Poco::Net
244