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