xref: /trunk/main/ucb/source/ucp/ftp/ftpurl.cxx (revision 421ed02e)
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     throw(
134         malformed_exception
135     )
136     : m_pFCP(pFCP),
137       m_aUsername(rtl::OUString::createFromAscii("anonymous")),
138       m_bShowPassword(false),
139       m_aPort(rtl::OUString::createFromAscii("21"))
140 {
141     parse(url);  // can reset m_bShowPassword
142 }
143 
144 
~FTPURL()145 FTPURL::~FTPURL()
146 {
147 }
148 
149 
parse(const rtl::OUString & url)150 void FTPURL::parse(const rtl::OUString& url)
151     throw(
152         malformed_exception
153     )
154 {
155     rtl::OUString aPassword,aAccount;
156     rtl::OString aIdent(url.getStr(),
157                         url.getLength(),
158                         RTL_TEXTENCODING_UTF8);
159 
160     rtl::OString lower = aIdent.toAsciiLowerCase();
161     if(lower.getLength() < 6 ||
162        strncmp("ftp://",lower.getStr(),6))
163         throw malformed_exception();
164 
165     char *buffer = new char[1+aIdent.getLength()];
166     const char* p2 = aIdent.getStr();
167     p2 += 6;
168 
169     char ch;
170     char *p1 = buffer;      // determine "username:password@host:port"
171     while((ch = *p2++) != '/' && ch)
172         *p1++ = ch;
173     *p1 = 0;
174 
175     rtl::OUString aExpr(rtl::OUString(buffer,strlen(buffer),
176                                       RTL_TEXTENCODING_UTF8));
177 
178     sal_Int32 l = aExpr.indexOf(sal_Unicode('@'));
179     m_aHost = aExpr.copy(1+l);
180 
181     if(l != -1) {
182         // Now username and password.
183         aExpr = aExpr.copy(0,l);
184         l = aExpr.indexOf(sal_Unicode(':'));
185         if(l != -1) {
186             aPassword = aExpr.copy(1+l);
187             if(aPassword.getLength())
188                 m_bShowPassword = true;
189         }
190         if(l > 0)
191             // Overwritte only if the username is not empty.
192             m_aUsername = aExpr.copy(0,l);
193         else if(aExpr.getLength())
194             m_aUsername = aExpr;
195     }
196 
197     l = m_aHost.lastIndexOf(sal_Unicode(':'));
198     sal_Int32 ipv6Back = m_aHost.lastIndexOf(sal_Unicode(']'));
199     if((ipv6Back == -1 && l != -1) // not ipv6, but a port
200        ||
201        (ipv6Back != -1 && 1+ipv6Back == l) // ipv6, and a port
202     )
203     {
204         if(1+l<m_aHost.getLength())
205             m_aPort = m_aHost.copy(1+l);
206         m_aHost = m_aHost.copy(0,l);
207     }
208 
209     while(ch) {  // now determine the pathsegments ...
210         p1 = buffer;
211         while((ch = *p2++) != '/' && ch)
212             *p1++ = ch;
213         *p1 = 0;
214 
215         if(buffer[0]) {
216             if(strcmp(buffer,"..") == 0 &&
217                m_aPathSegmentVec.size() &&
218                ! m_aPathSegmentVec.back().equalsAscii(".."))
219                 m_aPathSegmentVec.pop_back();
220             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                                   strlen(buffer),
227                                   RTL_TEXTENCODING_UTF8));
228         }
229     }
230 
231     delete[] buffer;
232 
233     if(m_bShowPassword)
234         m_pFCP->setHost(m_aHost,
235                         m_aPort,
236                         m_aUsername,
237                         aPassword,
238                         aAccount);
239 
240     // now check for something like ";type=i" at end of url
241     if(m_aPathSegmentVec.size() &&
242        (l = m_aPathSegmentVec.back().indexOf(sal_Unicode(';'))) != -1) {
243         m_aType = m_aPathSegmentVec.back().copy(l);
244         m_aPathSegmentVec.back() = m_aPathSegmentVec.back().copy(0,l);
245     }
246 }
247 
248 
ident(bool withslash,bool internal) const249 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     rtl::OUStringBuffer bff;
256     bff.appendAscii("ftp://");
257 
258     if(!m_aUsername.equalsAscii("anonymous")) {
259         bff.append(m_aUsername);
260 
261         rtl::OUString aPassword,aAccount;
262         m_pFCP->forHost(m_aHost,
263                         m_aPort,
264                         m_aUsername,
265                         aPassword,
266                         aAccount);
267 
268         if((m_bShowPassword || internal) &&
269            aPassword.getLength() )
270             bff.append(sal_Unicode(':'))
271                 .append(aPassword);
272 
273         bff.append(sal_Unicode('@'));
274     }
275     bff.append(m_aHost);
276 
277     if(!m_aPort.equalsAscii("21"))
278         bff.append(sal_Unicode(':'))
279             .append(m_aPort)
280             .append(sal_Unicode('/'));
281     else
282         bff.append(sal_Unicode('/'));
283 
284     for(unsigned i = 0; i < m_aPathSegmentVec.size(); ++i)
285         if(i == 0)
286             bff.append(m_aPathSegmentVec[i]);
287         else
288             bff.append(sal_Unicode('/')).append(m_aPathSegmentVec[i]);
289     if(withslash)
290         if(bff.getLength() && bff[bff.getLength()-1] != sal_Unicode('/'))
291             bff.append(sal_Unicode('/'));
292 
293     bff.append(m_aType);
294     return bff.makeStringAndClear();
295 }
296 
297 
parent(bool internal) const298 rtl::OUString FTPURL::parent(bool internal) const
299 {
300     rtl::OUStringBuffer bff;
301 
302     bff.appendAscii("ftp://");
303 
304     if(!m_aUsername.equalsAscii("anonymous")) {
305         bff.append(m_aUsername);
306 
307         rtl::OUString aPassword,aAccount;
308         m_pFCP->forHost(m_aHost,
309                         m_aPort,
310                         m_aUsername,
311                         aPassword,
312                         aAccount);
313 
314         if((internal || m_bShowPassword) && aPassword.getLength())
315             bff.append(sal_Unicode(':'))
316                 .append(aPassword);
317 
318         bff.append(sal_Unicode('@'));
319     }
320 
321     bff.append(m_aHost);
322 
323     if(!m_aPort.equalsAscii("21"))
324         bff.append(sal_Unicode(':'))
325             .append(m_aPort)
326             .append(sal_Unicode('/'));
327     else
328         bff.append(sal_Unicode('/'));
329 
330     rtl::OUString last;
331 
332     for(unsigned int i = 0; i < m_aPathSegmentVec.size(); ++i)
333         if(1+i == m_aPathSegmentVec.size())
334             last = m_aPathSegmentVec[i];
335         else if(i == 0)
336             bff.append(m_aPathSegmentVec[i]);
337         else
338             bff.append(sal_Unicode('/')).append(m_aPathSegmentVec[i]);
339 
340     if(!last.getLength())
341         bff.appendAscii("..");
342     else if(last.equalsAscii(".."))
343         bff.append(last).appendAscii("/..");
344 
345     bff.append(m_aType);
346     return bff.makeStringAndClear();
347 }
348 
349 
child(const rtl::OUString & title)350 void FTPURL::child(const rtl::OUString& title)
351 {
352     m_aPathSegmentVec.push_back(encodePathSegment(title));
353 }
354 
355 
child() const356 rtl::OUString FTPURL::child() const
357 {
358     return
359         m_aPathSegmentVec.size() ?
360         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         // Setting username:password
402 #define SET_USER_PASSWORD(username,password)                      \
403    rtl::OUString combi(username  +                                \
404                        rtl::OUString::createFromAscii(":") +      \
405                        password);                                 \
406    rtl::OString aUserPsswd(combi.getStr(),                        \
407                            combi.getLength(),                     \
408                            RTL_TEXTENCODING_UTF8);                \
409    curl_easy_setopt(curl,                                         \
410                     CURLOPT_USERPWD,                              \
411                     aUserPsswd.getStr())
412 
413 
414 
open()415 oslFileHandle FTPURL::open()
416     throw(curl_exception)
417 {
418     if(!m_aPathSegmentVec.size())
419         throw curl_exception(CURLE_FTP_COULDNT_RETR_FILE);
420 
421     CURL *curl = m_pFCP->handle();
422 
423     SET_CONTROL_CONTAINER;
424     rtl::OUString url(ident(false,true));
425     SET_URL(url);
426 
427     oslFileHandle res( NULL );
428     if ( osl_createTempFile( NULL, &res, NULL ) == osl_File_E_None )
429     {
430         curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,file_write);
431         curl_easy_setopt(curl,CURLOPT_WRITEDATA,res);
432 
433         curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
434         CURLcode err = curl_easy_perform(curl);
435 
436         if(err == CURLE_OK)
437             osl_setFilePos( res, osl_Pos_Absolut, 0 );
438         else {
439             osl_closeFile(res),res = 0;
440             throw curl_exception(err);
441         }
442     }
443 
444     return res;
445 }
446 
447 
list(sal_Int16 nMode) const448 std::vector<FTPDirentry> FTPURL::list(
449     sal_Int16 nMode
450 ) const
451     throw(
452         curl_exception
453     )
454 {
455     CURL *curl = m_pFCP->handle();
456 
457     SET_CONTROL_CONTAINER;
458     SET_DATA_CONTAINER;
459     rtl::OUString url(ident(true,true));
460     SET_URL(url);
461     curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
462 
463     CURLcode err = curl_easy_perform(curl);
464     if(err != CURLE_OK)
465         throw curl_exception(err);
466 
467     // now evaluate the error messages
468 
469     sal_uInt32 len = data.m_nWritePos;
470     char* fwd = (char*) data.m_pBuffer;
471     rtl::OString str(fwd,len);
472     char *p1, *p2;
473     p1 = p2 = fwd;
474 
475     OS osKind(FTP_UNKNOWN);
476     std::vector<FTPDirentry> resvec;
477     FTPDirentry aDirEntry;
478     // ensure slash at the end
479     rtl::OUString viewurl(ident(true,false));
480 
481     while(true) {
482         while(p2-fwd < int(len) && *p2 != '\n') ++p2;
483         if(p2-fwd == int(len)) break;
484 
485         *p2 = 0;
486         switch(osKind) {
487             // While FTP knows the 'system'-command,
488             // which returns the operating system type,
489             // this is not usable here: There are Windows-server
490             // formatting the output like UNIX-ls command.
491         case FTP_DOS:
492             FTPDirectoryParser::parseDOS(aDirEntry,p1);
493             break;
494         case FTP_UNIX:
495             FTPDirectoryParser::parseUNIX(aDirEntry,p1);
496             break;
497         case FTP_VMS:
498             FTPDirectoryParser::parseVMS(aDirEntry,p1);
499             break;
500         default:
501             if(FTPDirectoryParser::parseUNIX(aDirEntry,p1))
502                 osKind = FTP_UNIX;
503             else if(FTPDirectoryParser::parseDOS(aDirEntry,p1))
504                 osKind = FTP_DOS;
505             else if(FTPDirectoryParser::parseVMS(aDirEntry,p1))
506                 osKind = FTP_VMS;
507         }
508         aDirEntry.m_aName = aDirEntry.m_aName.trim();
509         if(osKind != int(FTP_UNKNOWN) &&
510            !aDirEntry.m_aName.equalsAscii("..") &&
511            !aDirEntry.m_aName.equalsAscii(".")) {
512             aDirEntry.m_aURL = viewurl + encodePathSegment(aDirEntry.m_aName);
513 
514             sal_Bool isDir =
515                 sal_Bool(aDirEntry.m_nMode&INETCOREFTP_FILEMODE_ISDIR);
516             switch(nMode) {
517                 case OpenMode::DOCUMENTS:
518                     if(!isDir)
519                         resvec.push_back(aDirEntry);
520                     break;
521                 case OpenMode::FOLDERS:
522                     if(isDir)
523                         resvec.push_back(aDirEntry);
524                     break;
525                 default:
526                     resvec.push_back(aDirEntry);
527             };
528         }
529         aDirEntry.clear();
530         p1 = p2 + 1;
531     }
532 
533     return resvec;
534 }
535 
536 
net_title() const537 rtl::OUString FTPURL::net_title() const
538     throw(curl_exception)
539 {
540     CURL *curl = m_pFCP->handle();
541 
542     SET_CONTROL_CONTAINER;
543     curl_easy_setopt(curl,CURLOPT_NOBODY,true);       // no data => no transfer
544     struct curl_slist *slist = 0;
545     // post request
546     slist = curl_slist_append(slist,"PWD");
547     curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
548 
549     bool try_more(true);
550     CURLcode err;
551     rtl::OUString aNetTitle;
552 
553     while(true) {
554         rtl::OUString url(ident(false,true));
555 
556         if(try_more &&
557            1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
558             url += rtl::OUString::createFromAscii("/");  // add end-slash
559         else if(!try_more &&
560                 1+url.lastIndexOf(sal_Unicode('/')) == url.getLength())
561             url = url.copy(0,url.getLength()-1);         // remove end-slash
562 
563         SET_URL(url);
564         err = curl_easy_perform(curl);
565 
566         if(err == CURLE_OK) {       // get the title from the server
567             char* fwd = (char*) control.m_pBuffer;
568             sal_uInt32 len = (sal_uInt32) control.m_nWritePos;
569 
570             aNetTitle = rtl::OUString(fwd,len,RTL_TEXTENCODING_UTF8);
571             // the buffer now contains the name of the file;
572             // analyze the output:
573             // Format of current working directory:
574             // 257 "/bla/bla" is current directory
575             sal_Int32 index1 = aNetTitle.lastIndexOf(
576                 rtl::OUString::createFromAscii("257"));
577             index1 = 1+aNetTitle.indexOf(sal_Unicode('"'),index1);
578             sal_Int32 index2 = aNetTitle.indexOf(sal_Unicode('"'),index1);
579             aNetTitle = aNetTitle.copy(index1,index2-index1);
580             if(!aNetTitle.equalsAscii("/")) {
581                 index1 = aNetTitle.lastIndexOf(sal_Unicode('/'));
582                 aNetTitle = aNetTitle.copy(1+index1);
583             }
584             try_more = false;
585         } else if(err == CURLE_BAD_PASSWORD_ENTERED)
586             // the client should retry after getting the correct
587             // username + password
588             throw curl_exception(err);
589 #if LIBCURL_VERSION_NUM>=0x070d01 /* 7.13.1 */
590         else if(err == CURLE_LOGIN_DENIED)
591             // the client should retry after getting the correct
592             // username + password
593             throw curl_exception(err);
594 #endif
595         else if(try_more && err == CURLE_FTP_ACCESS_DENIED) {
596             // We  were  either denied access when trying to login to
597             //  an FTP server or when trying to change working directory
598             //  to the one given in the URL.
599             if(m_aPathSegmentVec.size())
600                 // determine title form url
601                 aNetTitle = decodePathSegment(m_aPathSegmentVec.back());
602             else
603                 // must be root
604                 aNetTitle = rtl::OUString::createFromAscii("/");
605             try_more = false;
606         }
607 
608         if(try_more)
609             try_more = false;
610         else
611             break;
612     }
613 
614     curl_slist_free_all(slist);
615     return aNetTitle;
616 }
617 
618 
direntry() const619 FTPDirentry FTPURL::direntry() const
620     throw(curl_exception)
621 {
622     rtl::OUString nettitle = net_title();
623     FTPDirentry aDirentry;
624 
625     aDirentry.m_aName = nettitle;                 // init aDirentry
626     if(nettitle.equalsAscii("/") ||
627        nettitle.equalsAscii(".."))
628         aDirentry.m_nMode = INETCOREFTP_FILEMODE_ISDIR;
629     else
630         aDirentry.m_nMode = INETCOREFTP_FILEMODE_UNKNOWN;
631 
632     aDirentry.m_nSize = 0;
633 
634     if(!nettitle.equalsAscii("/")) {
635         // try to open the parent directory
636         FTPURL aURL(parent(),m_pFCP);
637 
638         std::vector<FTPDirentry> aList = aURL.list(OpenMode::ALL);
639 
640         for(unsigned i = 0; i < aList.size(); ++i) {
641             if(aList[i].m_aName == nettitle) { // the relevant file is found
642                 aDirentry = aList[i];
643                 break;
644             }
645         }
646     }
647     return aDirentry;
648 }
649 
650 
651 extern "C" {
652 
memory_read(void * ptr,size_t size,size_t nmemb,void * stream)653     size_t memory_read(void *ptr,size_t size,size_t nmemb,void *stream)
654     {
655         sal_Int32 nRequested = sal_Int32(size*nmemb);
656         CurlInput *curlInput = static_cast<CurlInput*>(stream);
657         if(curlInput)
658             return size_t(curlInput->read(((sal_Int8*)ptr),nRequested));
659         else
660             return 0;
661     }
662 
663 }
664 
665 
insert(bool replaceExisting,void * stream) const666 void FTPURL::insert(bool replaceExisting,void* stream) const
667     throw(curl_exception)
668 {
669     if(!replaceExisting) {
670 //          FTPDirentry aDirentry(direntry());
671 //          if(aDirentry.m_nMode == INETCOREFTP_FILEMODE_UNKNOWN)
672         // throw curl_exception(FILE_EXIST_DURING_INSERT);
673         throw curl_exception(FILE_MIGHT_EXIST_DURING_INSERT);
674     } // else
675     // overwrite is default in libcurl
676 
677     CURL *curl = m_pFCP->handle();
678 
679     SET_CONTROL_CONTAINER;
680     curl_easy_setopt(curl,CURLOPT_NOBODY,false);    // no data => no transfer
681     curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
682     curl_easy_setopt(curl,CURLOPT_QUOTE,0);
683     curl_easy_setopt(curl,CURLOPT_READFUNCTION,memory_read);
684     curl_easy_setopt(curl,CURLOPT_READDATA,stream);
685     curl_easy_setopt(curl, CURLOPT_UPLOAD,1);
686 
687     rtl::OUString url(ident(false,true));
688     SET_URL(url);
689 
690     CURLcode err = curl_easy_perform(curl);
691     curl_easy_setopt(curl, CURLOPT_UPLOAD,false);
692 
693     if(err != CURLE_OK)
694         throw curl_exception(err);
695 }
696 
697 
698 
mkdir(bool ReplaceExisting) const699 void FTPURL::mkdir(bool ReplaceExisting) const
700     throw(curl_exception)
701 {
702     rtl::OString title;
703     if(m_aPathSegmentVec.size()) {
704         rtl::OUString titleOU = m_aPathSegmentVec.back();
705         titleOU = decodePathSegment(titleOU);
706         title = rtl::OString(titleOU.getStr(),
707                             titleOU.getLength(),
708                             RTL_TEXTENCODING_UTF8);
709     }
710     else
711         // will give an error
712         title = rtl::OString("/");
713 
714     rtl::OString aDel("del "); aDel += title;
715     rtl::OString mkd("mkd "); mkd += title;
716 
717     struct curl_slist *slist = 0;
718 
719     FTPDirentry aDirentry(direntry());
720     if(!ReplaceExisting) {
721 //          if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
722 //              throw curl_exception(FOLDER_EXIST_DURING_INSERT);
723         throw curl_exception(FOLDER_MIGHT_EXIST_DURING_INSERT);
724     } else if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
725         slist = curl_slist_append(slist,aDel.getStr());
726 
727     slist = curl_slist_append(slist,mkd.getStr());
728 
729     CURL *curl = m_pFCP->handle();
730     SET_CONTROL_CONTAINER;
731     curl_easy_setopt(curl,CURLOPT_NOBODY,true);       // no data => no transfer
732     curl_easy_setopt(curl,CURLOPT_QUOTE,0);
733 
734     // post request
735     curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
736 
737     rtl::OUString url(parent(true));
738     if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
739         url += rtl::OUString::createFromAscii("/");
740     SET_URL(url);
741 
742     CURLcode err = curl_easy_perform(curl);
743     curl_slist_free_all(slist);
744     if(err != CURLE_OK)
745         throw curl_exception(err);
746 }
747 
748 
ren(const rtl::OUString & NewTitle)749 rtl::OUString FTPURL::ren(const rtl::OUString& NewTitle)
750     throw(curl_exception)
751 {
752     CURL *curl = m_pFCP->handle();
753 
754     // post request
755     rtl::OString renamefrom("RNFR ");
756     rtl::OUString OldTitle = net_title();
757     renamefrom +=
758         rtl::OString(OldTitle.getStr(),
759                      OldTitle.getLength(),
760                      RTL_TEXTENCODING_UTF8);
761 
762     rtl::OString renameto("RNTO ");
763     renameto +=
764         rtl::OString(NewTitle.getStr(),
765                      NewTitle.getLength(),
766                      RTL_TEXTENCODING_UTF8);
767 
768     struct curl_slist *slist = 0;
769     slist = curl_slist_append(slist,renamefrom.getStr());
770     slist = curl_slist_append(slist,renameto.getStr());
771     curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
772 
773     SET_CONTROL_CONTAINER;
774     curl_easy_setopt(curl,CURLOPT_NOBODY,true);       // no data => no transfer
775     curl_easy_setopt(curl,CURLOPT_QUOTE,0);
776 
777     rtl::OUString url(parent(true));
778     if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
779         url += rtl::OUString::createFromAscii("/");
780     SET_URL(url);
781 
782     CURLcode err = curl_easy_perform(curl);
783     curl_slist_free_all(slist);
784     if(err != CURLE_OK)
785         throw curl_exception(err);
786     else if(m_aPathSegmentVec.size() &&
787             !m_aPathSegmentVec.back().equalsAscii(".."))
788         m_aPathSegmentVec.back() = encodePathSegment(NewTitle);
789     return OldTitle;
790 }
791 
792 
793 
del() const794 void FTPURL::del() const
795     throw(curl_exception)
796 {
797     FTPDirentry aDirentry(direntry());
798 
799     rtl::OString dele(aDirentry.m_aName.getStr(),
800                       aDirentry.m_aName.getLength(),
801                       RTL_TEXTENCODING_UTF8);
802 
803     if(aDirentry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) {
804         std::vector<FTPDirentry> vec = list(sal_Int16(OpenMode::ALL));
805         for( unsigned int i = 0; i < vec.size(); ++i )
806             try {
807                 FTPURL url(vec[i].m_aURL,m_pFCP);
808                 url.del();
809             } catch(const curl_exception&) {
810             }
811         dele = rtl::OString("RMD ") + dele;
812     }
813     else if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
814         dele = rtl::OString("DELE ") + dele;
815     else
816         return;
817 
818     // post request
819     CURL *curl = m_pFCP->handle();
820     struct curl_slist *slist = 0;
821     slist = curl_slist_append(slist,dele.getStr());
822     curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
823 
824     SET_CONTROL_CONTAINER;
825     curl_easy_setopt(curl,CURLOPT_NOBODY,true);       // no data => no transfer
826     curl_easy_setopt(curl,CURLOPT_QUOTE,0);
827 
828     rtl::OUString url(parent(true));
829     if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
830         url += rtl::OUString::createFromAscii("/");
831     SET_URL(url);
832 
833     CURLcode err = curl_easy_perform(curl);
834     curl_slist_free_all(slist);
835     if(err != CURLE_OK)
836         throw curl_exception(err);
837 }
838 
839