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