Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : /**************************************************************************
30 : : TODO
31 : : **************************************************************************
32 : :
33 : : *************************************************************************/
34 : :
35 : : #include <memory>
36 : : #include <rtl/ustrbuf.hxx>
37 : : #include <com/sun/star/ucb/OpenMode.hpp>
38 : : #include <string.h>
39 : : #include <rtl/uri.hxx>
40 : :
41 : : #include "ftpstrcont.hxx"
42 : : #include "ftpurl.hxx"
43 : : #include "ftphandleprovider.hxx"
44 : : #include "ftpcfunc.hxx"
45 : : #include "ftpcontainer.hxx"
46 : :
47 : : using namespace ftp;
48 : : using namespace com::sun::star::ucb;
49 : : using namespace com::sun::star::uno;
50 : : using namespace com::sun::star::io;
51 : :
52 : : namespace {
53 : :
54 : 0 : rtl::OUString encodePathSegment(rtl::OUString const & decoded) {
55 : : return rtl::Uri::encode(
56 : : decoded, rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes,
57 : 0 : RTL_TEXTENCODING_UTF8);
58 : : }
59 : :
60 : 0 : rtl::OUString decodePathSegment(rtl::OUString const & encoded) {
61 : : return rtl::Uri::decode(
62 : 0 : encoded, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
63 : : }
64 : :
65 : : }
66 : :
67 : 4 : MemoryContainer::MemoryContainer()
68 : : : m_nLen(0),
69 : : m_nWritePos(0),
70 : 4 : m_pBuffer(0)
71 : : {
72 : 4 : }
73 : :
74 : 4 : MemoryContainer::~MemoryContainer()
75 : : {
76 : 4 : rtl_freeMemory(m_pBuffer);
77 : 4 : }
78 : :
79 : :
80 : 0 : int MemoryContainer::append(
81 : : const void* pBuffer,
82 : : size_t size,
83 : : size_t nmemb
84 : : ) throw()
85 : : {
86 : 0 : sal_uInt32 nLen = size*nmemb;
87 : 0 : sal_uInt32 tmp(nLen + m_nWritePos);
88 : :
89 [ # # ]: 0 : if(m_nLen < tmp) { // enlarge in steps of multiples of 1K
90 [ # # ]: 0 : do {
91 : 0 : m_nLen+=1024;
92 : : } while(m_nLen < tmp);
93 : :
94 : 0 : m_pBuffer = rtl_reallocateMemory(m_pBuffer,m_nLen);
95 : : }
96 : :
97 : 0 : rtl_copyMemory(static_cast<sal_Int8*>(m_pBuffer)+m_nWritePos,
98 : 0 : pBuffer,nLen);
99 : 0 : m_nWritePos = tmp;
100 : 0 : return nLen;
101 : : }
102 : :
103 : :
104 : : extern "C" {
105 : :
106 : 0 : int memory_write(void *buffer,size_t size,size_t nmemb,void *stream)
107 : : {
108 : : MemoryContainer *_stream =
109 : 0 : reinterpret_cast<MemoryContainer*>(stream);
110 : :
111 [ # # ]: 0 : if(!_stream)
112 : 0 : return 0;
113 : :
114 : 0 : return _stream->append(buffer,size,nmemb);
115 : : }
116 : :
117 : : }
118 : :
119 : :
120 : 4 : FTPURL::FTPURL(const FTPURL& r)
121 : : : m_mutex(),
122 : : m_pFCP(r.m_pFCP),
123 : : m_aUsername(r.m_aUsername),
124 : : m_bShowPassword(r.m_bShowPassword),
125 : : m_aHost(r.m_aHost),
126 : : m_aPort(r.m_aPort),
127 [ + - ]: 4 : m_aPathSegmentVec(r.m_aPathSegmentVec)
128 : :
129 : : {
130 : 4 : }
131 : :
132 : :
133 : 4 : FTPURL::FTPURL(const rtl::OUString& url,
134 : : FTPHandleProvider* pFCP)
135 : : throw(
136 : : malformed_exception
137 : : )
138 : : : m_pFCP(pFCP),
139 : : m_aUsername("anonymous"),
140 : : m_bShowPassword(false),
141 [ + - ]: 4 : m_aPort("21")
142 : : {
143 [ + - ]: 4 : parse(url); // can reset m_bShowPassword
144 : 4 : }
145 : :
146 : :
147 : 8 : FTPURL::~FTPURL()
148 : : {
149 : 8 : }
150 : :
151 : :
152 : 4 : void FTPURL::parse(const rtl::OUString& url)
153 : : throw(
154 : : malformed_exception
155 : : )
156 : : {
157 : 4 : rtl::OUString aPassword,aAccount;
158 : : rtl::OString aIdent(url.getStr(),
159 : : url.getLength(),
160 [ + - ]: 4 : RTL_TEXTENCODING_UTF8);
161 : :
162 : 4 : rtl::OString lower = aIdent.toAsciiLowerCase();
163 [ - + ]: 8 : if(lower.getLength() < 6 ||
[ + - - + ]
164 : 4 : strncmp("ftp://",lower.getStr(),6))
165 : 0 : throw malformed_exception();
166 : :
167 [ + - ]: 4 : char *buffer = new char[1+aIdent.getLength()];
168 : 4 : const char* p2 = aIdent.getStr();
169 : 4 : p2 += 6;
170 : :
171 : : char ch;
172 : 4 : char *p1 = buffer; // determine "username:password@host:port"
173 [ + + ][ + + ]: 48 : while((ch = *p2++) != '/' && ch)
[ + + ]
174 : 44 : *p1++ = ch;
175 : 4 : *p1 = 0;
176 : :
177 : 4 : rtl::OUString aExpr(rtl::OUString(buffer,strlen(buffer),
178 [ + - ]: 4 : RTL_TEXTENCODING_UTF8));
179 : :
180 : 4 : sal_Int32 l = aExpr.indexOf(sal_Unicode('@'));
181 : 4 : m_aHost = aExpr.copy(1+l);
182 : :
183 [ + + ]: 4 : if(l != -1) {
184 : : // Now username and password.
185 : 2 : aExpr = aExpr.copy(0,l);
186 : 2 : l = aExpr.indexOf(sal_Unicode(':'));
187 [ + - ]: 2 : if(l != -1) {
188 : 2 : aPassword = aExpr.copy(1+l);
189 [ + - ]: 2 : if(!aPassword.isEmpty())
190 : 2 : m_bShowPassword = true;
191 : : }
192 [ + - ]: 2 : if(l > 0)
193 : : // Overwritte only if the username is not empty.
194 : 2 : m_aUsername = aExpr.copy(0,l);
195 [ # # ]: 0 : else if(!aExpr.isEmpty())
196 : 0 : m_aUsername = aExpr;
197 : : }
198 : :
199 : 4 : l = m_aHost.lastIndexOf(sal_Unicode(':'));
200 : 4 : sal_Int32 ipv6Back = m_aHost.lastIndexOf(sal_Unicode(']'));
201 [ + - ][ - + ]: 4 : if((ipv6Back == -1 && l != -1) // not ipv6, but a port
[ # # ][ + - ]
202 : : ||
203 : : (ipv6Back != -1 && 1+ipv6Back == l) // ipv6, and a port
204 : : )
205 : : {
206 [ # # ]: 0 : if(1+l<m_aHost.getLength())
207 : 0 : m_aPort = m_aHost.copy(1+l);
208 : 0 : m_aHost = m_aHost.copy(0,l);
209 : : }
210 : :
211 [ + + ]: 6 : while(ch) { // now determine the pathsegments ...
212 : 2 : p1 = buffer;
213 [ + - ][ + + ]: 24 : while((ch = *p2++) != '/' && ch)
[ + + ]
214 : 22 : *p1++ = ch;
215 : 2 : *p1 = 0;
216 : :
217 [ + - ]: 2 : if(buffer[0]) {
218 [ - + ][ # # ]: 2 : if( strcmp(buffer,"..") == 0 && !m_aPathSegmentVec.empty() && m_aPathSegmentVec.back() != ".." )
[ # # ][ # # ]
[ - + ]
219 [ # # ]: 0 : m_aPathSegmentVec.pop_back();
220 [ + - ]: 2 : else if(strcmp(buffer,".") == 0)
221 : : ; // Ignore
222 : : else
223 : : // This is a legal name.
224 : : m_aPathSegmentVec.push_back(
225 : : rtl::OUString(buffer,
226 : 2 : strlen(buffer),
227 [ + - ][ + - ]: 2 : RTL_TEXTENCODING_UTF8));
228 : : }
229 : : }
230 : :
231 [ + - ]: 4 : delete[] buffer;
232 : :
233 [ + + ]: 4 : if(m_bShowPassword)
234 : : m_pFCP->setHost(m_aHost,
235 : : m_aPort,
236 : : m_aUsername,
237 : : aPassword,
238 [ + - ]: 2 : aAccount);
239 : :
240 : : // now check for something like ";type=i" at end of url
241 [ + + ][ - + ]: 6 : if(m_aPathSegmentVec.size() &&
[ - + ]
242 [ + - ]: 2 : (l = m_aPathSegmentVec.back().indexOf(sal_Unicode(';'))) != -1) {
243 [ # # ]: 0 : m_aType = m_aPathSegmentVec.back().copy(l);
244 [ # # ][ # # ]: 0 : m_aPathSegmentVec.back() = m_aPathSegmentVec.back().copy(0,l);
245 : 4 : }
246 : 4 : }
247 : :
248 : :
249 : 2 : rtl::OUString FTPURL::ident(bool withslash,bool internal) const
250 : : {
251 : : // rebuild the url as one without ellipses,
252 : : // and more important, as one without username and
253 : : // password. ( These are set together with the command. )
254 : :
255 : 2 : rtl::OUStringBuffer bff;
256 [ + - ]: 2 : bff.appendAscii("ftp://");
257 : :
258 [ + - ]: 2 : if( m_aUsername != "anonymous" ) {
259 [ + - ]: 2 : bff.append(m_aUsername);
260 : :
261 : 2 : rtl::OUString aPassword,aAccount;
262 : : m_pFCP->forHost(m_aHost,
263 : : m_aPort,
264 : : m_aUsername,
265 : : aPassword,
266 [ + - ]: 2 : aAccount);
267 : :
268 [ - + ]: 4 : if((m_bShowPassword || internal) &&
[ # # + - ]
[ + - ]
269 : 2 : !aPassword.isEmpty() )
270 [ + - ]: 2 : bff.append(sal_Unicode(':'))
271 [ + - ]: 2 : .append(aPassword);
272 : :
273 [ + - ]: 2 : bff.append(sal_Unicode('@'));
274 : : }
275 [ + - ]: 2 : bff.append(m_aHost);
276 : :
277 [ - + ]: 2 : if( m_aPort != "21" )
278 [ # # ]: 0 : bff.append(sal_Unicode(':'))
279 [ # # ]: 0 : .append(m_aPort)
280 [ # # ]: 0 : .append(sal_Unicode('/'));
281 : : else
282 [ + - ]: 2 : bff.append(sal_Unicode('/'));
283 : :
284 [ - + ]: 2 : for(unsigned i = 0; i < m_aPathSegmentVec.size(); ++i)
285 [ # # ]: 0 : if(i == 0)
286 [ # # ]: 0 : bff.append(m_aPathSegmentVec[i]);
287 : : else
288 [ # # ][ # # ]: 0 : bff.append(sal_Unicode('/')).append(m_aPathSegmentVec[i]);
289 [ + - ]: 2 : if(withslash)
290 [ + - ][ - + ]: 2 : if(bff.getLength() && bff[bff.getLength()-1] != sal_Unicode('/'))
[ - + ]
291 [ # # ]: 0 : bff.append(sal_Unicode('/'));
292 : :
293 [ + - ]: 2 : bff.append(m_aType);
294 [ + - ]: 2 : return bff.makeStringAndClear();
295 : : }
296 : :
297 : :
298 : 0 : rtl::OUString FTPURL::parent(bool internal) const
299 : : {
300 : 0 : rtl::OUStringBuffer bff;
301 : :
302 [ # # ]: 0 : bff.appendAscii("ftp://");
303 : :
304 [ # # ]: 0 : if( m_aUsername != "anonymous" ) {
305 [ # # ]: 0 : bff.append(m_aUsername);
306 : :
307 : 0 : rtl::OUString aPassword,aAccount;
308 : : m_pFCP->forHost(m_aHost,
309 : : m_aPort,
310 : : m_aUsername,
311 : : aPassword,
312 [ # # ]: 0 : aAccount);
313 : :
314 [ # # ][ # # ]: 0 : if((internal || m_bShowPassword) && !aPassword.isEmpty())
[ # # ][ # # ]
315 [ # # ]: 0 : bff.append(sal_Unicode(':'))
316 [ # # ]: 0 : .append(aPassword);
317 : :
318 [ # # ]: 0 : bff.append(sal_Unicode('@'));
319 : : }
320 : :
321 [ # # ]: 0 : bff.append(m_aHost);
322 : :
323 [ # # ]: 0 : if( m_aPort != "21" )
324 [ # # ]: 0 : bff.append(sal_Unicode(':'))
325 [ # # ]: 0 : .append(m_aPort)
326 [ # # ]: 0 : .append(sal_Unicode('/'));
327 : : else
328 [ # # ]: 0 : bff.append(sal_Unicode('/'));
329 : :
330 : 0 : rtl::OUString last;
331 : :
332 [ # # ]: 0 : for(unsigned int i = 0; i < m_aPathSegmentVec.size(); ++i)
333 [ # # ]: 0 : if(1+i == m_aPathSegmentVec.size())
334 : 0 : last = m_aPathSegmentVec[i];
335 [ # # ]: 0 : else if(i == 0)
336 [ # # ]: 0 : bff.append(m_aPathSegmentVec[i]);
337 : : else
338 [ # # ][ # # ]: 0 : bff.append(sal_Unicode('/')).append(m_aPathSegmentVec[i]);
339 : :
340 [ # # ]: 0 : if(last.isEmpty())
341 [ # # ]: 0 : bff.appendAscii("..");
342 [ # # ]: 0 : else if ( last == ".." )
343 [ # # ][ # # ]: 0 : bff.append(last).appendAscii("/..");
344 : :
345 [ # # ]: 0 : bff.append(m_aType);
346 [ # # ]: 0 : return bff.makeStringAndClear();
347 : : }
348 : :
349 : :
350 : 0 : void FTPURL::child(const rtl::OUString& title)
351 : : {
352 [ # # ]: 0 : m_aPathSegmentVec.push_back(encodePathSegment(title));
353 : 0 : }
354 : :
355 : :
356 : 0 : rtl::OUString FTPURL::child() const
357 : : {
358 : : return
359 : 0 : m_aPathSegmentVec.size() ?
360 [ # # ]: 0 : decodePathSegment(m_aPathSegmentVec.back()) : rtl::OUString();
361 : : }
362 : :
363 : :
364 : :
365 : : /** Listing of a directory.
366 : : */
367 : :
368 : : namespace ftp {
369 : :
370 : : enum OS {
371 : : FTP_DOS,FTP_UNIX,FTP_VMS,FTP_UNKNOWN
372 : : };
373 : :
374 : : }
375 : :
376 : :
377 : : #define SET_CONTROL_CONTAINER \
378 : : MemoryContainer control; \
379 : : curl_easy_setopt(curl, \
380 : : CURLOPT_HEADERFUNCTION, \
381 : : memory_write); \
382 : : curl_easy_setopt(curl, \
383 : : CURLOPT_WRITEHEADER, \
384 : : &control)
385 : :
386 : :
387 : : #define SET_DATA_CONTAINER \
388 : : curl_easy_setopt(curl,CURLOPT_NOBODY,false); \
389 : : MemoryContainer data; \
390 : : curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,memory_write); \
391 : : curl_easy_setopt(curl,CURLOPT_WRITEDATA,&data)
392 : :
393 : : #define SET_URL(url) \
394 : : rtl::OString urlParAscii(url.getStr(), \
395 : : url.getLength(), \
396 : : RTL_TEXTENCODING_UTF8); \
397 : : curl_easy_setopt(curl, \
398 : : CURLOPT_URL, \
399 : : urlParAscii.getStr());
400 : :
401 : 0 : FILE* FTPURL::open()
402 : : throw(curl_exception)
403 : : {
404 [ # # ]: 0 : if(m_aPathSegmentVec.empty())
405 : 0 : throw curl_exception(CURLE_FTP_COULDNT_RETR_FILE);
406 : :
407 [ # # ]: 0 : CURL *curl = m_pFCP->handle();
408 : :
409 [ # # ][ # # ]: 0 : SET_CONTROL_CONTAINER;
410 [ # # ]: 0 : rtl::OUString url(ident(false,true));
411 [ # # ][ # # ]: 0 : SET_URL(url);
412 [ # # ]: 0 : FILE *res = tmpfile();
413 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,file_write);
414 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_WRITEDATA,res);
415 : :
416 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
417 [ # # ]: 0 : CURLcode err = curl_easy_perform(curl);
418 : :
419 [ # # ]: 0 : if(err == CURLE_OK)
420 [ # # ]: 0 : rewind(res);
421 : : else {
422 [ # # ]: 0 : fclose(res),res = 0;
423 : 0 : throw curl_exception(err);
424 : : }
425 : :
426 : 0 : return res;
427 : : }
428 : :
429 : :
430 : 2 : std::vector<FTPDirentry> FTPURL::list(
431 : : sal_Int16 nMode
432 : : ) const
433 : : throw(
434 : : curl_exception
435 : : )
436 : : {
437 [ + - ]: 2 : CURL *curl = m_pFCP->handle();
438 : :
439 [ + - ][ + - ]: 2 : SET_CONTROL_CONTAINER;
440 [ + - ][ + - ]: 2 : SET_DATA_CONTAINER;
[ + - ]
441 [ + - ]: 2 : rtl::OUString url(ident(true,true));
442 [ + - ][ + - ]: 2 : SET_URL(url);
443 [ + - ]: 2 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
444 : :
445 [ + - ]: 2 : CURLcode err = curl_easy_perform(curl);
446 [ + - ]: 2 : if(err != CURLE_OK)
447 : 2 : throw curl_exception(err);
448 : :
449 : : // now evaluate the error messages
450 : :
451 : 0 : sal_uInt32 len = data.m_nWritePos;
452 : 0 : char* fwd = (char*) data.m_pBuffer;
453 : 0 : rtl::OString str(fwd,len);
454 : : char *p1, *p2;
455 : 0 : p1 = p2 = fwd;
456 : :
457 : 0 : OS osKind(FTP_UNKNOWN);
458 [ # # ]: 0 : std::vector<FTPDirentry> resvec;
459 : 0 : FTPDirentry aDirEntry;
460 : : // ensure slash at the end
461 [ # # ]: 0 : rtl::OUString viewurl(ident(true,false));
462 : :
463 : 0 : while(true) {
464 [ # # ][ # # ]: 0 : while(p2-fwd < int(len) && *p2 != '\n') ++p2;
[ # # ]
465 [ # # ]: 0 : if(p2-fwd == int(len)) break;
466 : :
467 : 0 : *p2 = 0;
468 [ # # # # ]: 0 : switch(osKind) {
469 : : // While FTP knows the 'system'-command,
470 : : // which returns the operating system type,
471 : : // this is not usable here: There are Windows-server
472 : : // formatting the output like UNIX-ls command.
473 : : case FTP_DOS:
474 [ # # ]: 0 : FTPDirectoryParser::parseDOS(aDirEntry,p1);
475 : 0 : break;
476 : : case FTP_UNIX:
477 [ # # ]: 0 : FTPDirectoryParser::parseUNIX(aDirEntry,p1);
478 : 0 : break;
479 : : case FTP_VMS:
480 [ # # ]: 0 : FTPDirectoryParser::parseVMS(aDirEntry,p1);
481 : 0 : break;
482 : : default:
483 [ # # ][ # # ]: 0 : if(FTPDirectoryParser::parseUNIX(aDirEntry,p1))
484 : 0 : osKind = FTP_UNIX;
485 [ # # ][ # # ]: 0 : else if(FTPDirectoryParser::parseDOS(aDirEntry,p1))
486 : 0 : osKind = FTP_DOS;
487 [ # # ][ # # ]: 0 : else if(FTPDirectoryParser::parseVMS(aDirEntry,p1))
488 : 0 : osKind = FTP_VMS;
489 : : }
490 : 0 : aDirEntry.m_aName = aDirEntry.m_aName.trim();
491 [ # # ][ # # ]: 0 : if( osKind != int(FTP_UNKNOWN) && aDirEntry.m_aName != ".." && aDirEntry.m_aName != "." ) {
[ # # ][ # # ]
492 : 0 : aDirEntry.m_aURL = viewurl + encodePathSegment(aDirEntry.m_aName);
493 : :
494 : : sal_Bool isDir =
495 : 0 : sal_Bool(aDirEntry.m_nMode&INETCOREFTP_FILEMODE_ISDIR);
496 [ # # # ]: 0 : switch(nMode) {
497 : : case OpenMode::DOCUMENTS:
498 [ # # ]: 0 : if(!isDir)
499 [ # # ]: 0 : resvec.push_back(aDirEntry);
500 : 0 : break;
501 : : case OpenMode::FOLDERS:
502 [ # # ]: 0 : if(isDir)
503 [ # # ]: 0 : resvec.push_back(aDirEntry);
504 : 0 : break;
505 : : default:
506 [ # # ]: 0 : resvec.push_back(aDirEntry);
507 : : };
508 : : }
509 : 0 : aDirEntry.clear();
510 : 0 : p1 = p2 + 1;
511 : : }
512 : :
513 : 2 : return resvec;
514 : : }
515 : :
516 : :
517 : 0 : rtl::OUString FTPURL::net_title() const
518 : : throw(curl_exception)
519 : : {
520 [ # # ]: 0 : CURL *curl = m_pFCP->handle();
521 : :
522 [ # # ][ # # ]: 0 : SET_CONTROL_CONTAINER;
523 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer
524 : 0 : struct curl_slist *slist = 0;
525 : : // post request
526 [ # # ]: 0 : slist = curl_slist_append(slist,"PWD");
527 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
528 : :
529 : 0 : bool try_more(true);
530 : : CURLcode err;
531 : 0 : rtl::OUString aNetTitle;
532 : :
533 : 0 : while(true) {
534 [ # # ]: 0 : rtl::OUString url(ident(false,true));
535 : :
536 [ # # # # ]: 0 : if(try_more &&
[ # # ]
537 : 0 : 1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
538 : 0 : url += rtl::OUString("/"); // add end-slash
539 [ # # # # ]: 0 : else if(!try_more &&
[ # # ]
540 : 0 : 1+url.lastIndexOf(sal_Unicode('/')) == url.getLength())
541 : 0 : url = url.copy(0,url.getLength()-1); // remove end-slash
542 : :
543 [ # # ][ # # ]: 0 : SET_URL(url);
544 [ # # ]: 0 : err = curl_easy_perform(curl);
545 : :
546 [ # # ]: 0 : if(err == CURLE_OK) { // get the title from the server
547 : 0 : char* fwd = (char*) control.m_pBuffer;
548 : 0 : sal_uInt32 len = (sal_uInt32) control.m_nWritePos;
549 : :
550 [ # # ]: 0 : aNetTitle = rtl::OUString(fwd,len,RTL_TEXTENCODING_UTF8);
551 : : // the buffer now contains the name of the file;
552 : : // analyze the output:
553 : : // Format of current working directory:
554 : : // 257 "/bla/bla" is current directory
555 : : sal_Int32 index1 = aNetTitle.lastIndexOf(
556 : 0 : rtl::OUString("257"));
557 : 0 : index1 = 1+aNetTitle.indexOf(sal_Unicode('"'),index1);
558 : 0 : sal_Int32 index2 = aNetTitle.indexOf(sal_Unicode('"'),index1);
559 : 0 : aNetTitle = aNetTitle.copy(index1,index2-index1);
560 [ # # ]: 0 : if( aNetTitle != "/" ) {
561 : 0 : index1 = aNetTitle.lastIndexOf(sal_Unicode('/'));
562 : 0 : aNetTitle = aNetTitle.copy(1+index1);
563 : : }
564 : 0 : try_more = false;
565 [ # # ]: 0 : } else if(err == CURLE_BAD_PASSWORD_ENTERED)
566 : : // the client should retry after getting the correct
567 : : // username + password
568 : 0 : throw curl_exception(err);
569 : : #if LIBCURL_VERSION_NUM>=0x070d01 /* 7.13.1 */
570 [ # # ]: 0 : else if(err == CURLE_LOGIN_DENIED)
571 : : // the client should retry after getting the correct
572 : : // username + password
573 : 0 : throw curl_exception(err);
574 : : #endif
575 [ # # ][ # # ]: 0 : else if(try_more && err == CURLE_FTP_ACCESS_DENIED) {
576 : : // We were either denied access when trying to login to
577 : : // an FTP server or when trying to change working directory
578 : : // to the one given in the URL.
579 [ # # ]: 0 : if(!m_aPathSegmentVec.empty())
580 : : // determine title form url
581 [ # # ]: 0 : aNetTitle = decodePathSegment(m_aPathSegmentVec.back());
582 : : else
583 : : // must be root
584 : 0 : aNetTitle = rtl::OUString("/");
585 : 0 : try_more = false;
586 : : }
587 : :
588 [ # # ]: 0 : if(try_more)
589 : 0 : try_more = false;
590 : : else
591 : : break;
592 [ # # ][ # # ]: 0 : }
593 : :
594 [ # # ]: 0 : curl_slist_free_all(slist);
595 : 0 : return aNetTitle;
596 : : }
597 : :
598 : :
599 : 0 : FTPDirentry FTPURL::direntry() const
600 : : throw(curl_exception)
601 : : {
602 [ # # ]: 0 : rtl::OUString nettitle = net_title();
603 : 0 : FTPDirentry aDirentry;
604 : :
605 : 0 : aDirentry.m_aName = nettitle; // init aDirentry
606 [ # # ][ # # ]: 0 : if( nettitle == "/" || nettitle == ".." )
[ # # ]
607 : 0 : aDirentry.m_nMode = INETCOREFTP_FILEMODE_ISDIR;
608 : : else
609 : 0 : aDirentry.m_nMode = INETCOREFTP_FILEMODE_UNKNOWN;
610 : :
611 : 0 : aDirentry.m_nSize = 0;
612 : :
613 [ # # ]: 0 : if( nettitle != "/" ) {
614 : : // try to open the parent directory
615 [ # # ][ # # ]: 0 : FTPURL aURL(parent(),m_pFCP);
616 : :
617 [ # # ]: 0 : std::vector<FTPDirentry> aList = aURL.list(OpenMode::ALL);
618 : :
619 [ # # ]: 0 : for(unsigned i = 0; i < aList.size(); ++i) {
620 [ # # ]: 0 : if(aList[i].m_aName == nettitle) { // the relevant file is found
621 : 0 : aDirentry = aList[i];
622 : 0 : break;
623 : : }
624 [ # # ]: 0 : }
625 : : }
626 : 0 : return aDirentry;
627 : : }
628 : :
629 : :
630 : : extern "C" {
631 : :
632 : 0 : size_t memory_read(void *ptr,size_t size,size_t nmemb,void *stream)
633 : : {
634 : 0 : sal_Int32 nRequested = sal_Int32(size*nmemb);
635 : 0 : CurlInput *curlInput = static_cast<CurlInput*>(stream);
636 [ # # ]: 0 : if(curlInput)
637 : 0 : return size_t(curlInput->read(((sal_Int8*)ptr),nRequested));
638 : : else
639 : 0 : return 0;
640 : : }
641 : :
642 : : }
643 : :
644 : :
645 : 0 : void FTPURL::insert(bool replaceExisting,void* stream) const
646 : : throw(curl_exception)
647 : : {
648 [ # # ]: 0 : if(!replaceExisting) {
649 : : // FTPDirentry aDirentry(direntry());
650 : : // if(aDirentry.m_nMode == INETCOREFTP_FILEMODE_UNKNOWN)
651 : : // throw curl_exception(FILE_EXIST_DURING_INSERT);
652 : 0 : throw curl_exception(FILE_MIGHT_EXIST_DURING_INSERT);
653 : : } // else
654 : : // overwrite is default in libcurl
655 : :
656 [ # # ]: 0 : CURL *curl = m_pFCP->handle();
657 : :
658 [ # # ][ # # ]: 0 : SET_CONTROL_CONTAINER;
659 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,false); // no data => no transfer
660 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
661 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_QUOTE,0);
662 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_READFUNCTION,memory_read);
663 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_READDATA,stream);
664 [ # # ]: 0 : curl_easy_setopt(curl, CURLOPT_UPLOAD,1);
665 : :
666 [ # # ]: 0 : rtl::OUString url(ident(false,true));
667 [ # # ][ # # ]: 0 : SET_URL(url);
668 : :
669 [ # # ]: 0 : CURLcode err = curl_easy_perform(curl);
670 [ # # ]: 0 : curl_easy_setopt(curl, CURLOPT_UPLOAD,false);
671 : :
672 [ # # ]: 0 : if(err != CURLE_OK)
673 : 0 : throw curl_exception(err);
674 : 0 : }
675 : :
676 : :
677 : :
678 : 0 : void FTPURL::mkdir(bool ReplaceExisting) const
679 : : throw(curl_exception)
680 : : {
681 : 0 : rtl::OString title;
682 [ # # ]: 0 : if(!m_aPathSegmentVec.empty()) {
683 [ # # ]: 0 : rtl::OUString titleOU = m_aPathSegmentVec.back();
684 : 0 : titleOU = decodePathSegment(titleOU);
685 : : title = rtl::OString(titleOU.getStr(),
686 : : titleOU.getLength(),
687 [ # # ]: 0 : RTL_TEXTENCODING_UTF8);
688 : : }
689 : : else
690 : : // will give an error
691 : 0 : title = rtl::OString("/");
692 : :
693 : 0 : rtl::OString aDel("del "); aDel += title;
694 : 0 : rtl::OString mkd("mkd "); mkd += title;
695 : :
696 : 0 : struct curl_slist *slist = 0;
697 : :
698 [ # # ]: 0 : FTPDirentry aDirentry(direntry());
699 [ # # ]: 0 : if(!ReplaceExisting) {
700 : : // if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
701 : : // throw curl_exception(FOLDER_EXIST_DURING_INSERT);
702 : 0 : throw curl_exception(FOLDER_MIGHT_EXIST_DURING_INSERT);
703 [ # # ]: 0 : } else if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
704 [ # # ]: 0 : slist = curl_slist_append(slist,aDel.getStr());
705 : :
706 [ # # ]: 0 : slist = curl_slist_append(slist,mkd.getStr());
707 : :
708 [ # # ]: 0 : CURL *curl = m_pFCP->handle();
709 [ # # ][ # # ]: 0 : SET_CONTROL_CONTAINER;
710 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer
711 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_QUOTE,0);
712 : :
713 : : // post request
714 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
715 : :
716 [ # # ]: 0 : rtl::OUString url(parent(true));
717 [ # # ]: 0 : if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
718 : 0 : url += rtl::OUString("/");
719 [ # # ][ # # ]: 0 : SET_URL(url);
720 : :
721 [ # # ]: 0 : CURLcode err = curl_easy_perform(curl);
722 [ # # ]: 0 : curl_slist_free_all(slist);
723 [ # # ]: 0 : if(err != CURLE_OK)
724 : 0 : throw curl_exception(err);
725 : 0 : }
726 : :
727 : :
728 : 0 : rtl::OUString FTPURL::ren(const rtl::OUString& NewTitle)
729 : : throw(curl_exception)
730 : : {
731 [ # # ]: 0 : CURL *curl = m_pFCP->handle();
732 : :
733 : : // post request
734 : 0 : rtl::OString renamefrom("RNFR ");
735 [ # # ]: 0 : rtl::OUString OldTitle = net_title();
736 : : renamefrom +=
737 : : rtl::OString(OldTitle.getStr(),
738 : : OldTitle.getLength(),
739 [ # # ]: 0 : RTL_TEXTENCODING_UTF8);
740 : :
741 : 0 : rtl::OString renameto("RNTO ");
742 : : renameto +=
743 : : rtl::OString(NewTitle.getStr(),
744 : : NewTitle.getLength(),
745 [ # # ]: 0 : RTL_TEXTENCODING_UTF8);
746 : :
747 : 0 : struct curl_slist *slist = 0;
748 [ # # ]: 0 : slist = curl_slist_append(slist,renamefrom.getStr());
749 [ # # ]: 0 : slist = curl_slist_append(slist,renameto.getStr());
750 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
751 : :
752 [ # # ][ # # ]: 0 : SET_CONTROL_CONTAINER;
753 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer
754 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_QUOTE,0);
755 : :
756 [ # # ]: 0 : rtl::OUString url(parent(true));
757 [ # # ]: 0 : if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
758 : 0 : url += rtl::OUString("/");
759 [ # # ][ # # ]: 0 : SET_URL(url);
760 : :
761 [ # # ]: 0 : CURLcode err = curl_easy_perform(curl);
762 [ # # ]: 0 : curl_slist_free_all(slist);
763 [ # # ]: 0 : if(err != CURLE_OK)
764 : 0 : throw curl_exception(err);
765 [ # # ][ # # ]: 0 : else if( m_aPathSegmentVec.size() && m_aPathSegmentVec.back() != ".." )
[ # # ][ # # ]
766 [ # # ]: 0 : m_aPathSegmentVec.back() = encodePathSegment(NewTitle);
767 : 0 : return OldTitle;
768 : : }
769 : :
770 : :
771 : :
772 : 0 : void FTPURL::del() const
773 : : throw(curl_exception)
774 : : {
775 [ # # ]: 0 : FTPDirentry aDirentry(direntry());
776 : :
777 : : rtl::OString dele(aDirentry.m_aName.getStr(),
778 : : aDirentry.m_aName.getLength(),
779 [ # # ]: 0 : RTL_TEXTENCODING_UTF8);
780 : :
781 [ # # ]: 0 : if(aDirentry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) {
782 [ # # ]: 0 : std::vector<FTPDirentry> vec = list(sal_Int16(OpenMode::ALL));
783 [ # # ]: 0 : for( unsigned int i = 0; i < vec.size(); ++i )
784 : : try {
785 [ # # ]: 0 : FTPURL url(vec[i].m_aURL,m_pFCP);
786 [ # # ][ # # ]: 0 : url.del();
[ # # ]
787 : 0 : } catch(const curl_exception&) {
788 : : }
789 : 0 : dele = rtl::OString("RMD ") + dele;
790 : : }
791 [ # # ]: 0 : else if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
792 : 0 : dele = rtl::OString("DELE ") + dele;
793 : : else
794 : 0 : return;
795 : :
796 : : // post request
797 [ # # ]: 0 : CURL *curl = m_pFCP->handle();
798 : 0 : struct curl_slist *slist = 0;
799 [ # # ]: 0 : slist = curl_slist_append(slist,dele.getStr());
800 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
801 : :
802 [ # # ][ # # ]: 0 : SET_CONTROL_CONTAINER;
803 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer
804 [ # # ]: 0 : curl_easy_setopt(curl,CURLOPT_QUOTE,0);
805 : :
806 [ # # ]: 0 : rtl::OUString url(parent(true));
807 [ # # ]: 0 : if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
808 : 0 : url += rtl::OUString("/");
809 [ # # ][ # # ]: 0 : SET_URL(url);
810 : :
811 [ # # ]: 0 : CURLcode err = curl_easy_perform(curl);
812 [ # # ]: 0 : curl_slist_free_all(slist);
813 [ # # ]: 0 : if(err != CURLE_OK)
814 [ # # ][ # # ]: 0 : throw curl_exception(err);
815 : : }
816 : :
817 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|