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 : rtl::OUString encodePathSegment(rtl::OUString const & decoded) {
46 : return rtl::Uri::encode(
47 : decoded, rtl_UriCharClassPchar, rtl_UriEncodeIgnoreEscapes,
48 0 : RTL_TEXTENCODING_UTF8);
49 : }
50 :
51 0 : rtl::OUString decodePathSegment(rtl::OUString const & encoded) {
52 : return rtl::Uri::decode(
53 0 : encoded, rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8);
54 : }
55 :
56 : }
57 :
58 0 : MemoryContainer::MemoryContainer()
59 : : m_nLen(0),
60 : m_nWritePos(0),
61 0 : m_pBuffer(0)
62 : {
63 0 : }
64 :
65 0 : MemoryContainer::~MemoryContainer()
66 : {
67 0 : rtl_freeMemory(m_pBuffer);
68 0 : }
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 : } 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 0 : 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 0 : m_aPathSegmentVec(r.m_aPathSegmentVec)
119 :
120 : {
121 0 : }
122 :
123 :
124 0 : FTPURL::FTPURL(const rtl::OUString& url,
125 : FTPHandleProvider* pFCP)
126 : throw(
127 : malformed_exception
128 : )
129 : : m_pFCP(pFCP),
130 : m_aUsername("anonymous"),
131 : m_bShowPassword(false),
132 0 : m_aPort("21")
133 : {
134 0 : parse(url); // can reset m_bShowPassword
135 0 : }
136 :
137 :
138 0 : FTPURL::~FTPURL()
139 : {
140 0 : }
141 :
142 :
143 0 : void FTPURL::parse(const rtl::OUString& url)
144 : throw(
145 : malformed_exception
146 : )
147 : {
148 0 : rtl::OUString aPassword,aAccount;
149 : rtl::OString aIdent(url.getStr(),
150 : url.getLength(),
151 0 : RTL_TEXTENCODING_UTF8);
152 :
153 0 : rtl::OString lower = aIdent.toAsciiLowerCase();
154 0 : if(lower.getLength() < 6 ||
155 0 : strncmp("ftp://",lower.getStr(),6))
156 0 : throw malformed_exception();
157 :
158 0 : char *buffer = new char[1+aIdent.getLength()];
159 0 : const char* p2 = aIdent.getStr();
160 0 : p2 += 6;
161 :
162 : char ch;
163 0 : char *p1 = buffer; // determine "username:password@host:port"
164 0 : while((ch = *p2++) != '/' && ch)
165 0 : *p1++ = ch;
166 0 : *p1 = 0;
167 :
168 0 : rtl::OUString aExpr(rtl::OUString(buffer,strlen(buffer),
169 0 : RTL_TEXTENCODING_UTF8));
170 :
171 0 : sal_Int32 l = aExpr.indexOf(sal_Unicode('@'));
172 0 : m_aHost = aExpr.copy(1+l);
173 :
174 0 : if(l != -1) {
175 : // Now username and password.
176 0 : aExpr = aExpr.copy(0,l);
177 0 : l = aExpr.indexOf(sal_Unicode(':'));
178 0 : if(l != -1) {
179 0 : aPassword = aExpr.copy(1+l);
180 0 : if(!aPassword.isEmpty())
181 0 : m_bShowPassword = true;
182 : }
183 0 : if(l > 0)
184 : // Overwritte only if the username is not empty.
185 0 : m_aUsername = aExpr.copy(0,l);
186 0 : else if(!aExpr.isEmpty())
187 0 : m_aUsername = aExpr;
188 : }
189 :
190 0 : l = m_aHost.lastIndexOf(sal_Unicode(':'));
191 0 : sal_Int32 ipv6Back = m_aHost.lastIndexOf(sal_Unicode(']'));
192 0 : if((ipv6Back == -1 && l != -1) // not ipv6, but a port
193 : ||
194 : (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 0 : while(ch) { // now determine the pathsegments ...
203 0 : p1 = buffer;
204 0 : while((ch = *p2++) != '/' && ch)
205 0 : *p1++ = ch;
206 0 : *p1 = 0;
207 :
208 0 : if(buffer[0]) {
209 0 : if( strcmp(buffer,"..") == 0 && !m_aPathSegmentVec.empty() && m_aPathSegmentVec.back() != ".." )
210 0 : m_aPathSegmentVec.pop_back();
211 0 : else if(strcmp(buffer,".") == 0)
212 : ; // Ignore
213 : else
214 : // This is a legal name.
215 : m_aPathSegmentVec.push_back(
216 : rtl::OUString(buffer,
217 0 : strlen(buffer),
218 0 : RTL_TEXTENCODING_UTF8));
219 : }
220 : }
221 :
222 0 : delete[] buffer;
223 :
224 0 : if(m_bShowPassword)
225 : m_pFCP->setHost(m_aHost,
226 : m_aPort,
227 : m_aUsername,
228 : aPassword,
229 0 : aAccount);
230 :
231 : // now check for something like ";type=i" at end of url
232 0 : if(m_aPathSegmentVec.size() &&
233 0 : (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 0 : }
237 0 : }
238 :
239 :
240 0 : rtl::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 0 : rtl::OUStringBuffer bff;
247 0 : bff.appendAscii("ftp://");
248 :
249 0 : if( m_aUsername != "anonymous" ) {
250 0 : bff.append(m_aUsername);
251 :
252 0 : rtl::OUString aPassword,aAccount;
253 : m_pFCP->forHost(m_aHost,
254 : m_aPort,
255 : m_aUsername,
256 : aPassword,
257 0 : aAccount);
258 :
259 0 : if((m_bShowPassword || internal) &&
260 0 : !aPassword.isEmpty() )
261 0 : bff.append(sal_Unicode(':'))
262 0 : .append(aPassword);
263 :
264 0 : bff.append(sal_Unicode('@'));
265 : }
266 0 : bff.append(m_aHost);
267 :
268 0 : if( m_aPort != "21" )
269 0 : bff.append(sal_Unicode(':'))
270 0 : .append(m_aPort)
271 0 : .append(sal_Unicode('/'));
272 : else
273 0 : bff.append(sal_Unicode('/'));
274 :
275 0 : 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 0 : if(withslash)
281 0 : if(bff.getLength() && bff[bff.getLength()-1] != sal_Unicode('/'))
282 0 : bff.append(sal_Unicode('/'));
283 :
284 0 : bff.append(m_aType);
285 0 : return bff.makeStringAndClear();
286 : }
287 :
288 :
289 0 : rtl::OUString FTPURL::parent(bool internal) const
290 : {
291 0 : rtl::OUStringBuffer bff;
292 :
293 0 : bff.appendAscii("ftp://");
294 :
295 0 : if( m_aUsername != "anonymous" ) {
296 0 : bff.append(m_aUsername);
297 :
298 0 : rtl::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 : rtl::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 rtl::OUString& title)
342 : {
343 0 : m_aPathSegmentVec.push_back(encodePathSegment(title));
344 0 : }
345 :
346 :
347 0 : rtl::OUString FTPURL::child() const
348 : {
349 : return
350 0 : m_aPathSegmentVec.size() ?
351 0 : decodePathSegment(m_aPathSegmentVec.back()) : rtl::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 : rtl::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 : FILE* 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 : rtl::OUString url(ident(false,true));
402 0 : SET_URL(url);
403 0 : FILE *res = tmpfile();
404 0 : curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,file_write);
405 0 : curl_easy_setopt(curl,CURLOPT_WRITEDATA,res);
406 :
407 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
408 0 : CURLcode err = curl_easy_perform(curl);
409 :
410 0 : if(err == CURLE_OK)
411 0 : rewind(res);
412 : else {
413 0 : fclose(res),res = 0;
414 0 : throw curl_exception(err);
415 : }
416 :
417 0 : return res;
418 : }
419 :
420 :
421 0 : std::vector<FTPDirentry> FTPURL::list(
422 : sal_Int16 nMode
423 : ) const
424 : throw(
425 : curl_exception
426 : )
427 : {
428 0 : CURL *curl = m_pFCP->handle();
429 :
430 0 : SET_CONTROL_CONTAINER;
431 0 : SET_DATA_CONTAINER;
432 0 : rtl::OUString url(ident(true,true));
433 0 : SET_URL(url);
434 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
435 :
436 0 : CURLcode err = curl_easy_perform(curl);
437 0 : if(err != CURLE_OK)
438 0 : throw curl_exception(err);
439 :
440 : // now evaluate the error messages
441 :
442 0 : sal_uInt32 len = data.m_nWritePos;
443 0 : char* fwd = (char*) data.m_pBuffer;
444 0 : rtl::OString str(fwd,len);
445 : char *p1, *p2;
446 0 : p1 = p2 = fwd;
447 :
448 0 : OS osKind(FTP_UNKNOWN);
449 0 : std::vector<FTPDirentry> resvec;
450 0 : FTPDirentry aDirEntry;
451 : // ensure slash at the end
452 0 : rtl::OUString viewurl(ident(true,false));
453 :
454 0 : while(true) {
455 0 : while(p2-fwd < int(len) && *p2 != '\n') ++p2;
456 0 : if(p2-fwd == int(len)) break;
457 :
458 0 : *p2 = 0;
459 0 : switch(osKind) {
460 : // While FTP knows the 'system'-command,
461 : // which returns the operating system type,
462 : // this is not usable here: There are Windows-server
463 : // formatting the output like UNIX-ls command.
464 : case FTP_DOS:
465 0 : FTPDirectoryParser::parseDOS(aDirEntry,p1);
466 0 : break;
467 : case FTP_UNIX:
468 0 : FTPDirectoryParser::parseUNIX(aDirEntry,p1);
469 0 : break;
470 : case FTP_VMS:
471 0 : FTPDirectoryParser::parseVMS(aDirEntry,p1);
472 0 : break;
473 : default:
474 0 : if(FTPDirectoryParser::parseUNIX(aDirEntry,p1))
475 0 : osKind = FTP_UNIX;
476 0 : else if(FTPDirectoryParser::parseDOS(aDirEntry,p1))
477 0 : osKind = FTP_DOS;
478 0 : else if(FTPDirectoryParser::parseVMS(aDirEntry,p1))
479 0 : osKind = FTP_VMS;
480 : }
481 0 : aDirEntry.m_aName = aDirEntry.m_aName.trim();
482 0 : if( osKind != int(FTP_UNKNOWN) && aDirEntry.m_aName != ".." && aDirEntry.m_aName != "." ) {
483 0 : aDirEntry.m_aURL = viewurl + encodePathSegment(aDirEntry.m_aName);
484 :
485 : sal_Bool isDir =
486 0 : sal_Bool(aDirEntry.m_nMode&INETCOREFTP_FILEMODE_ISDIR);
487 0 : switch(nMode) {
488 : case OpenMode::DOCUMENTS:
489 0 : if(!isDir)
490 0 : resvec.push_back(aDirEntry);
491 0 : break;
492 : case OpenMode::FOLDERS:
493 0 : if(isDir)
494 0 : resvec.push_back(aDirEntry);
495 0 : break;
496 : default:
497 0 : resvec.push_back(aDirEntry);
498 : };
499 : }
500 0 : aDirEntry.clear();
501 0 : p1 = p2 + 1;
502 : }
503 :
504 0 : return resvec;
505 : }
506 :
507 :
508 0 : rtl::OUString FTPURL::net_title() const
509 : throw(curl_exception)
510 : {
511 0 : CURL *curl = m_pFCP->handle();
512 :
513 0 : SET_CONTROL_CONTAINER;
514 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer
515 0 : struct curl_slist *slist = 0;
516 : // post request
517 0 : slist = curl_slist_append(slist,"PWD");
518 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
519 :
520 0 : bool try_more(true);
521 : CURLcode err;
522 0 : rtl::OUString aNetTitle;
523 :
524 0 : while(true) {
525 0 : rtl::OUString url(ident(false,true));
526 :
527 0 : if(try_more &&
528 0 : 1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
529 0 : url += rtl::OUString("/"); // add end-slash
530 0 : else if(!try_more &&
531 0 : 1+url.lastIndexOf(sal_Unicode('/')) == url.getLength())
532 0 : url = url.copy(0,url.getLength()-1); // remove end-slash
533 :
534 0 : SET_URL(url);
535 0 : err = curl_easy_perform(curl);
536 :
537 0 : if(err == CURLE_OK) { // get the title from the server
538 0 : char* fwd = (char*) control.m_pBuffer;
539 0 : sal_uInt32 len = (sal_uInt32) control.m_nWritePos;
540 :
541 0 : aNetTitle = rtl::OUString(fwd,len,RTL_TEXTENCODING_UTF8);
542 : // the buffer now contains the name of the file;
543 : // analyze the output:
544 : // Format of current working directory:
545 : // 257 "/bla/bla" is current directory
546 : sal_Int32 index1 = aNetTitle.lastIndexOf(
547 0 : rtl::OUString("257"));
548 0 : index1 = 1+aNetTitle.indexOf(sal_Unicode('"'),index1);
549 0 : sal_Int32 index2 = aNetTitle.indexOf(sal_Unicode('"'),index1);
550 0 : aNetTitle = aNetTitle.copy(index1,index2-index1);
551 0 : if( aNetTitle != "/" ) {
552 0 : index1 = aNetTitle.lastIndexOf(sal_Unicode('/'));
553 0 : aNetTitle = aNetTitle.copy(1+index1);
554 : }
555 0 : try_more = false;
556 0 : } else if(err == CURLE_BAD_PASSWORD_ENTERED)
557 : // the client should retry after getting the correct
558 : // username + password
559 0 : throw curl_exception(err);
560 : #if LIBCURL_VERSION_NUM>=0x070d01 /* 7.13.1 */
561 0 : else if(err == CURLE_LOGIN_DENIED)
562 : // the client should retry after getting the correct
563 : // username + password
564 0 : throw curl_exception(err);
565 : #endif
566 0 : else if(try_more && err == CURLE_FTP_ACCESS_DENIED) {
567 : // We were either denied access when trying to login to
568 : // an FTP server or when trying to change working directory
569 : // to the one given in the URL.
570 0 : if(!m_aPathSegmentVec.empty())
571 : // determine title form url
572 0 : aNetTitle = decodePathSegment(m_aPathSegmentVec.back());
573 : else
574 : // must be root
575 0 : aNetTitle = rtl::OUString("/");
576 0 : try_more = false;
577 : }
578 :
579 0 : if(try_more)
580 0 : try_more = false;
581 : else
582 : break;
583 0 : }
584 :
585 0 : curl_slist_free_all(slist);
586 0 : return aNetTitle;
587 : }
588 :
589 :
590 0 : FTPDirentry FTPURL::direntry() const
591 : throw(curl_exception)
592 : {
593 0 : rtl::OUString nettitle = net_title();
594 0 : FTPDirentry aDirentry;
595 :
596 0 : aDirentry.m_aName = nettitle; // init aDirentry
597 0 : if( nettitle == "/" || nettitle == ".." )
598 0 : aDirentry.m_nMode = INETCOREFTP_FILEMODE_ISDIR;
599 : else
600 0 : aDirentry.m_nMode = INETCOREFTP_FILEMODE_UNKNOWN;
601 :
602 0 : aDirentry.m_nSize = 0;
603 :
604 0 : if( nettitle != "/" ) {
605 : // try to open the parent directory
606 0 : FTPURL aURL(parent(),m_pFCP);
607 :
608 0 : std::vector<FTPDirentry> aList = aURL.list(OpenMode::ALL);
609 :
610 0 : for(unsigned i = 0; i < aList.size(); ++i) {
611 0 : if(aList[i].m_aName == nettitle) { // the relevant file is found
612 0 : aDirentry = aList[i];
613 0 : break;
614 : }
615 0 : }
616 : }
617 0 : return aDirentry;
618 : }
619 :
620 :
621 : extern "C" {
622 :
623 0 : size_t memory_read(void *ptr,size_t size,size_t nmemb,void *stream)
624 : {
625 0 : sal_Int32 nRequested = sal_Int32(size*nmemb);
626 0 : CurlInput *curlInput = static_cast<CurlInput*>(stream);
627 0 : if(curlInput)
628 0 : return size_t(curlInput->read(((sal_Int8*)ptr),nRequested));
629 : else
630 0 : return 0;
631 : }
632 :
633 : }
634 :
635 :
636 0 : void FTPURL::insert(bool replaceExisting,void* stream) const
637 : throw(curl_exception)
638 : {
639 0 : if(!replaceExisting) {
640 : // FTPDirentry aDirentry(direntry());
641 : // if(aDirentry.m_nMode == INETCOREFTP_FILEMODE_UNKNOWN)
642 : // throw curl_exception(FILE_EXIST_DURING_INSERT);
643 0 : throw curl_exception(FILE_MIGHT_EXIST_DURING_INSERT);
644 : } // else
645 : // overwrite is default in libcurl
646 :
647 0 : CURL *curl = m_pFCP->handle();
648 :
649 0 : SET_CONTROL_CONTAINER;
650 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,false); // no data => no transfer
651 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,0);
652 0 : curl_easy_setopt(curl,CURLOPT_QUOTE,0);
653 0 : curl_easy_setopt(curl,CURLOPT_READFUNCTION,memory_read);
654 0 : curl_easy_setopt(curl,CURLOPT_READDATA,stream);
655 0 : curl_easy_setopt(curl, CURLOPT_UPLOAD,1);
656 :
657 0 : rtl::OUString url(ident(false,true));
658 0 : SET_URL(url);
659 :
660 0 : CURLcode err = curl_easy_perform(curl);
661 0 : curl_easy_setopt(curl, CURLOPT_UPLOAD,false);
662 :
663 0 : if(err != CURLE_OK)
664 0 : throw curl_exception(err);
665 0 : }
666 :
667 :
668 :
669 0 : void FTPURL::mkdir(bool ReplaceExisting) const
670 : throw(curl_exception)
671 : {
672 0 : rtl::OString title;
673 0 : if(!m_aPathSegmentVec.empty()) {
674 0 : rtl::OUString titleOU = m_aPathSegmentVec.back();
675 0 : titleOU = decodePathSegment(titleOU);
676 : title = rtl::OString(titleOU.getStr(),
677 : titleOU.getLength(),
678 0 : RTL_TEXTENCODING_UTF8);
679 : }
680 : else
681 : // will give an error
682 0 : title = rtl::OString("/");
683 :
684 0 : rtl::OString aDel("del "); aDel += title;
685 0 : rtl::OString mkd("mkd "); mkd += title;
686 :
687 0 : struct curl_slist *slist = 0;
688 :
689 0 : FTPDirentry aDirentry(direntry());
690 0 : if(!ReplaceExisting) {
691 : // if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
692 : // throw curl_exception(FOLDER_EXIST_DURING_INSERT);
693 0 : throw curl_exception(FOLDER_MIGHT_EXIST_DURING_INSERT);
694 0 : } else if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
695 0 : slist = curl_slist_append(slist,aDel.getStr());
696 :
697 0 : slist = curl_slist_append(slist,mkd.getStr());
698 :
699 0 : CURL *curl = m_pFCP->handle();
700 0 : SET_CONTROL_CONTAINER;
701 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer
702 0 : curl_easy_setopt(curl,CURLOPT_QUOTE,0);
703 :
704 : // post request
705 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
706 :
707 0 : rtl::OUString url(parent(true));
708 0 : if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
709 0 : url += rtl::OUString("/");
710 0 : SET_URL(url);
711 :
712 0 : CURLcode err = curl_easy_perform(curl);
713 0 : curl_slist_free_all(slist);
714 0 : if(err != CURLE_OK)
715 0 : throw curl_exception(err);
716 0 : }
717 :
718 :
719 0 : rtl::OUString FTPURL::ren(const rtl::OUString& NewTitle)
720 : throw(curl_exception)
721 : {
722 0 : CURL *curl = m_pFCP->handle();
723 :
724 : // post request
725 0 : rtl::OString renamefrom("RNFR ");
726 0 : rtl::OUString OldTitle = net_title();
727 : renamefrom +=
728 : rtl::OString(OldTitle.getStr(),
729 : OldTitle.getLength(),
730 0 : RTL_TEXTENCODING_UTF8);
731 :
732 0 : rtl::OString renameto("RNTO ");
733 : renameto +=
734 : rtl::OString(NewTitle.getStr(),
735 : NewTitle.getLength(),
736 0 : RTL_TEXTENCODING_UTF8);
737 :
738 0 : struct curl_slist *slist = 0;
739 0 : slist = curl_slist_append(slist,renamefrom.getStr());
740 0 : slist = curl_slist_append(slist,renameto.getStr());
741 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
742 :
743 0 : SET_CONTROL_CONTAINER;
744 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer
745 0 : curl_easy_setopt(curl,CURLOPT_QUOTE,0);
746 :
747 0 : rtl::OUString url(parent(true));
748 0 : if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
749 0 : url += rtl::OUString("/");
750 0 : SET_URL(url);
751 :
752 0 : CURLcode err = curl_easy_perform(curl);
753 0 : curl_slist_free_all(slist);
754 0 : if(err != CURLE_OK)
755 0 : throw curl_exception(err);
756 0 : else if( m_aPathSegmentVec.size() && m_aPathSegmentVec.back() != ".." )
757 0 : m_aPathSegmentVec.back() = encodePathSegment(NewTitle);
758 0 : return OldTitle;
759 : }
760 :
761 :
762 :
763 0 : void FTPURL::del() const
764 : throw(curl_exception)
765 : {
766 0 : FTPDirentry aDirentry(direntry());
767 :
768 : rtl::OString dele(aDirentry.m_aName.getStr(),
769 : aDirentry.m_aName.getLength(),
770 0 : RTL_TEXTENCODING_UTF8);
771 :
772 0 : if(aDirentry.m_nMode & INETCOREFTP_FILEMODE_ISDIR) {
773 0 : std::vector<FTPDirentry> vec = list(sal_Int16(OpenMode::ALL));
774 0 : for( unsigned int i = 0; i < vec.size(); ++i )
775 : try {
776 0 : FTPURL url(vec[i].m_aURL,m_pFCP);
777 0 : url.del();
778 0 : } catch(const curl_exception&) {
779 : }
780 0 : dele = rtl::OString("RMD ") + dele;
781 : }
782 0 : else if(aDirentry.m_nMode != INETCOREFTP_FILEMODE_UNKNOWN)
783 0 : dele = rtl::OString("DELE ") + dele;
784 : else
785 0 : return;
786 :
787 : // post request
788 0 : CURL *curl = m_pFCP->handle();
789 0 : struct curl_slist *slist = 0;
790 0 : slist = curl_slist_append(slist,dele.getStr());
791 0 : curl_easy_setopt(curl,CURLOPT_POSTQUOTE,slist);
792 :
793 0 : SET_CONTROL_CONTAINER;
794 0 : curl_easy_setopt(curl,CURLOPT_NOBODY,true); // no data => no transfer
795 0 : curl_easy_setopt(curl,CURLOPT_QUOTE,0);
796 :
797 0 : rtl::OUString url(parent(true));
798 0 : if(1+url.lastIndexOf(sal_Unicode('/')) != url.getLength())
799 0 : url += rtl::OUString("/");
800 0 : SET_URL(url);
801 :
802 0 : CURLcode err = curl_easy_perform(curl);
803 0 : curl_slist_free_all(slist);
804 0 : if(err != CURLE_OK)
805 0 : throw curl_exception(err);
806 : }
807 :
808 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|