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