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