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 : #include <sal/config.h>
21 :
22 : #include <cassert>
23 : #include <vector>
24 :
25 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
26 : #include <com/sun/star/sdbc/XResultSet.hpp>
27 : #include <com/sun/star/task/XInteractionHandler.hpp>
28 : #include <com/sun/star/ucb/CommandAbortedException.hpp>
29 : #include <com/sun/star/ucb/ContentInfo.hpp>
30 : #include <com/sun/star/ucb/ContentInfoAttribute.hpp>
31 : #include <com/sun/star/ucb/IOErrorCode.hpp>
32 : #include <com/sun/star/ucb/InteractiveIOException.hpp>
33 : #include <com/sun/star/ucb/NameClashException.hpp>
34 : #include <com/sun/star/ucb/UniversalContentBroker.hpp>
35 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
36 : #include <com/sun/star/ucb/XContentAccess.hpp>
37 : #include <com/sun/star/ucb/XContentIdentifier.hpp>
38 : #include <com/sun/star/ucb/XProgressHandler.hpp>
39 : #include <com/sun/star/ucb/XUniversalContentBroker.hpp>
40 : #include <com/sun/star/uno/Any.hxx>
41 : #include <com/sun/star/uno/Exception.hpp>
42 : #include <com/sun/star/uno/Reference.hxx>
43 : #include <com/sun/star/uno/RuntimeException.hpp>
44 : #include <com/sun/star/uno/Sequence.hxx>
45 : #include <com/sun/star/uno/XComponentContext.hpp>
46 : #include <com/sun/star/util/DateTime.hpp>
47 : #include <comphelper/processfactory.hxx>
48 : #include <cppuhelper/exc_hlp.hxx>
49 : #include <osl/file.hxx>
50 : #include <rtl/string.h>
51 : #include <rtl/ustring.h>
52 : #include <rtl/ustring.hxx>
53 : #include <sal/log.hxx>
54 : #include <sal/types.h>
55 : #include <tools/datetime.hxx>
56 : #include <tools/urlobj.hxx>
57 : #include <ucbhelper/commandenvironment.hxx>
58 : #include <ucbhelper/content.hxx>
59 : #include <unotools/localfilehelper.hxx>
60 : #include <unotools/ucbhelper.hxx>
61 :
62 : namespace {
63 :
64 17309 : OUString canonic(OUString const & url) {
65 17309 : INetURLObject o(url);
66 : SAL_WARN_IF(o.HasError(), "unotools.ucbhelper", "Invalid URL \"" << url << '"');
67 17309 : return o.GetMainURL(INetURLObject::NO_DECODE);
68 : }
69 :
70 14781 : ucbhelper::Content content(OUString const & url) {
71 : return ucbhelper::Content(
72 : canonic(url),
73 : css::uno::Reference<css::ucb::XCommandEnvironment>(),
74 14781 : comphelper::getProcessComponentContext());
75 : }
76 :
77 1417 : ucbhelper::Content content(INetURLObject const & url) {
78 : return ucbhelper::Content(
79 : url.GetMainURL(INetURLObject::NO_DECODE),
80 : css::uno::Reference<css::ucb::XCommandEnvironment>(),
81 1417 : comphelper::getProcessComponentContext());
82 : }
83 :
84 0 : std::vector<OUString> getContents(OUString const & url) {
85 : try {
86 0 : std::vector<OUString> cs;
87 0 : ucbhelper::Content c(content(url));
88 0 : css::uno::Sequence<OUString> args(1);
89 0 : args[0] = "Title";
90 : css::uno::Reference<css::sdbc::XResultSet> res(
91 : c.createCursor(args, ucbhelper::INCLUDE_FOLDERS_AND_DOCUMENTS),
92 0 : css::uno::UNO_SET_THROW);
93 : css::uno::Reference<com::sun::star::ucb::XContentAccess> acc(
94 0 : res, css::uno::UNO_QUERY_THROW);
95 0 : while (res->next()) {
96 0 : cs.push_back(acc->queryContentIdentifierString());
97 : }
98 0 : return cs;
99 0 : } catch (css::uno::RuntimeException const &) {
100 0 : throw;
101 0 : } catch (css::ucb::CommandAbortedException const &) {
102 : assert(false && "this cannot happen");
103 0 : throw;
104 0 : } catch (css::uno::Exception const &) {
105 0 : css::uno::Any e(cppu::getCaughtException());
106 : SAL_INFO(
107 : "unotools.ucbhelper",
108 : "getContents(" << url << ") " << e.getValueType().getTypeName()
109 : << " \"" << e.get<css::uno::Exception>().Message << '"');
110 0 : return std::vector<OUString>();
111 : }
112 : }
113 :
114 0 : OUString getCasePreservingUrl(const INetURLObject& url) {
115 : return
116 : content(url).executeCommand(
117 : OUString("getCasePreservingURL"),
118 : css::uno::Any()).
119 0 : get<OUString>();
120 : }
121 :
122 0 : DateTime convert(css::util::DateTime const & dt) {
123 : return DateTime(
124 : Date(dt.Day, dt.Month, dt.Year),
125 0 : tools::Time(dt.Hours, dt.Minutes, dt.Seconds, dt.NanoSeconds));
126 : }
127 :
128 : }
129 :
130 7796 : bool utl::UCBContentHelper::IsDocument(OUString const & url) {
131 : try {
132 7796 : return content(url).isDocument();
133 0 : } catch (css::uno::RuntimeException const &) {
134 0 : throw;
135 0 : } catch (css::ucb::CommandAbortedException const &) {
136 : assert(false && "this cannot happen");
137 0 : throw;
138 3048 : } catch (css::uno::Exception const &) {
139 1524 : css::uno::Any e(cppu::getCaughtException());
140 : SAL_INFO(
141 : "unotools.ucbhelper",
142 : "UCBContentHelper::IsDocument(" << url << ") "
143 : << e.getValueType().getTypeName() << " \""
144 : << e.get<css::uno::Exception>().Message << '"');
145 1524 : return false;
146 : }
147 : }
148 :
149 0 : css::uno::Any utl::UCBContentHelper::GetProperty(
150 : OUString const & url, OUString const & property)
151 : {
152 : try {
153 0 : return content(url).getPropertyValue(property);
154 0 : } catch (css::uno::RuntimeException const &) {
155 0 : throw;
156 0 : } catch (css::ucb::CommandAbortedException const &) {
157 : assert(false && "this cannot happen");
158 0 : throw;
159 0 : } catch (css::uno::Exception const &) {
160 0 : css::uno::Any e(cppu::getCaughtException());
161 : SAL_INFO(
162 : "unotools.ucbhelper",
163 : "UCBContentHelper::GetProperty(" << url << ", " << property << ") "
164 : << e.getValueType().getTypeName() << " \""
165 : << e.get<css::uno::Exception>().Message << '"');
166 0 : return css::uno::Any();
167 : }
168 : }
169 :
170 5596 : bool utl::UCBContentHelper::IsFolder(OUString const & url) {
171 : try {
172 5596 : return content(url).isFolder();
173 0 : } catch (css::uno::RuntimeException const &) {
174 0 : throw;
175 0 : } catch (css::ucb::CommandAbortedException const &) {
176 : assert(false && "this cannot happen");
177 0 : throw;
178 2884 : } catch (css::uno::Exception const &) {
179 1442 : css::uno::Any e(cppu::getCaughtException());
180 : SAL_INFO(
181 : "unotools.ucbhelper",
182 : "UCBContentHelper::IsFolder(" << url << ") "
183 : << e.getValueType().getTypeName() << " \""
184 : << e.get<css::uno::Exception>().Message << '"');
185 1442 : return false;
186 : }
187 : }
188 :
189 0 : bool utl::UCBContentHelper::GetTitle(
190 : OUString const & url, OUString * title)
191 : {
192 : assert(title != 0);
193 : try {
194 0 : return content(url).getPropertyValue("Title") >>= *title;
195 0 : } catch (css::uno::RuntimeException const &) {
196 0 : throw;
197 0 : } catch (css::ucb::CommandAbortedException const &) {
198 : assert(false && "this cannot happen");
199 0 : throw;
200 0 : } catch (css::uno::Exception const &) {
201 0 : css::uno::Any e(cppu::getCaughtException());
202 : SAL_INFO(
203 : "unotools.ucbhelper",
204 : "UCBContentHelper::GetTitle(" << url << ") "
205 : << e.getValueType().getTypeName() << " \""
206 : << e.get<css::uno::Exception>().Message << '"');
207 0 : return false;
208 : }
209 : }
210 :
211 1389 : bool utl::UCBContentHelper::Kill(OUString const & url) {
212 : try {
213 : content(url).executeCommand(
214 : OUString("delete"),
215 1389 : css::uno::makeAny(true));
216 1389 : return true;
217 0 : } catch (css::uno::RuntimeException const &) {
218 0 : throw;
219 0 : } catch (css::ucb::CommandAbortedException const &) {
220 : assert(false && "this cannot happen");
221 0 : throw;
222 0 : } catch (css::uno::Exception const &) {
223 0 : css::uno::Any e(cppu::getCaughtException());
224 : SAL_INFO(
225 : "unotools.ucbhelper",
226 : "UCBContentHelper::Kill(" << url << ") "
227 : << e.getValueType().getTypeName() << " \""
228 : << e.get<css::uno::Exception>().Message << '"');
229 0 : return false;
230 : }
231 : }
232 :
233 1989 : bool utl::UCBContentHelper::MakeFolder(
234 : ucbhelper::Content & parent, OUString const & title,
235 : ucbhelper::Content & result, bool exclusive)
236 : {
237 1989 : bool exists = false;
238 : try {
239 : css::uno::Sequence<css::ucb::ContentInfo> info(
240 1989 : parent.queryCreatableContentsInfo());
241 3962 : for (sal_Int32 i = 0; i < info.getLength(); ++i) {
242 : // Simply look for the first KIND_FOLDER:
243 7924 : if ((info[i].Attributes
244 3962 : & css::ucb::ContentInfoAttribute::KIND_FOLDER)
245 : != 0)
246 : {
247 : // Make sure the only required bootstrap property is "Title":
248 1981 : if ( info[i].Properties.getLength() != 1 || info[i].Properties[0].Name != "Title" )
249 : {
250 0 : continue;
251 : }
252 1981 : css::uno::Sequence<OUString> keys(1);
253 1981 : keys[0] = "Title";
254 3398 : css::uno::Sequence<css::uno::Any> values(1);
255 1981 : values[0] <<= title;
256 1981 : if (parent.insertNewContent(info[i].Type, keys, values, result))
257 : {
258 564 : return true;
259 1417 : }
260 : }
261 1417 : }
262 16 : } catch (css::ucb::InteractiveIOException const & e) {
263 8 : if (e.Code == css::ucb::IOErrorCode_ALREADY_EXISTING) {
264 0 : exists = true;
265 : } else {
266 : SAL_INFO(
267 : "unotools.ucbhelper",
268 : "UCBContentHelper::MakeFolder(" << title
269 : << ") InteractiveIOException \"" << e.Message
270 : << "\", code " << +e.Code);
271 : }
272 2834 : } catch (css::ucb::NameClashException const &) {
273 1417 : exists = true;
274 0 : } catch (css::uno::RuntimeException const &) {
275 0 : throw;
276 0 : } catch (css::ucb::CommandAbortedException const &) {
277 : assert(false && "this cannot happen");
278 0 : throw;
279 0 : } catch (css::uno::Exception const &) {
280 0 : css::uno::Any e(cppu::getCaughtException());
281 : SAL_INFO(
282 : "unotools.ucbhelper",
283 : "UCBContentHelper::MakeFolder(" << title << ") "
284 : << e.getValueType().getTypeName() << " \""
285 0 : << e.get<css::uno::Exception>().Message << '"');
286 : }
287 1425 : if (exists && !exclusive) {
288 1417 : INetURLObject o(parent.getURL());
289 1417 : o.Append(title);
290 1417 : result = content(o);
291 1417 : return true;
292 : } else {
293 8 : return false;
294 : }
295 : }
296 :
297 0 : sal_Int64 utl::UCBContentHelper::GetSize(OUString const & url) {
298 : try {
299 0 : sal_Int64 n = 0;
300 0 : bool ok = (content(url).getPropertyValue("Size") >>= n);
301 : SAL_INFO_IF(
302 : !ok, "unotools.ucbhelper",
303 : "UCBContentHelper::GetSize(" << url
304 : << "): Size cannot be determined");
305 0 : return n;
306 0 : } catch (css::uno::RuntimeException const &) {
307 0 : throw;
308 0 : } catch (css::ucb::CommandAbortedException const &) {
309 : assert(false && "this cannot happen");
310 0 : throw;
311 0 : } catch (css::uno::Exception const &) {
312 0 : css::uno::Any e(cppu::getCaughtException());
313 : SAL_INFO(
314 : "unotools.ucbhelper",
315 : "UCBContentHelper::GetSize(" << url << ") "
316 : << e.getValueType().getTypeName() << " \""
317 : << e.get<css::uno::Exception>().Message << '"');
318 0 : return 0;
319 : }
320 : }
321 :
322 0 : bool utl::UCBContentHelper::IsYounger(
323 : OUString const & younger, OUString const & older)
324 : {
325 : try {
326 : return
327 : convert(
328 : content(younger).getPropertyValue(
329 : OUString("DateModified")).
330 0 : get<css::util::DateTime>())
331 0 : > convert(
332 : content(older).getPropertyValue(
333 : OUString("DateModified")).
334 0 : get<css::util::DateTime>());
335 0 : } catch (css::uno::RuntimeException const &) {
336 0 : throw;
337 0 : } catch (css::ucb::CommandAbortedException const &) {
338 : assert(false && "this cannot happen");
339 0 : throw;
340 0 : } catch (css::uno::Exception const &) {
341 0 : css::uno::Any e(cppu::getCaughtException());
342 : SAL_INFO(
343 : "unotools.ucbhelper",
344 : "UCBContentHelper::IsYounger(" << younger << ", " << older << ") "
345 : << e.getValueType().getTypeName() << " \""
346 : << e.get<css::uno::Exception>().Message << '"');
347 0 : return false;
348 : }
349 : }
350 :
351 522 : bool utl::UCBContentHelper::Exists(OUString const & url) {
352 522 : OUString pathname;
353 522 : if (utl::LocalFileHelper::ConvertURLToPhysicalName(url, pathname)) {
354 : // Try to create a directory entry for the given URL:
355 522 : OUString url2;
356 522 : if (osl::FileBase::getFileURLFromSystemPath(pathname, url2)
357 : == osl::FileBase::E_None)
358 : {
359 : // #106526 osl_getDirectoryItem is an existence check, no further
360 : // osl_getFileStatus call necessary:
361 522 : osl::DirectoryItem item;
362 522 : return osl::DirectoryItem::get(url2, item) == osl::FileBase::E_None;
363 : } else {
364 0 : return false;
365 522 : }
366 : } else {
367 : // Divide URL into folder and name part:
368 0 : INetURLObject o(url);
369 : OUString name(
370 : o.getName(
371 : INetURLObject::LAST_SEGMENT, true,
372 0 : INetURLObject::DECODE_WITH_CHARSET));
373 0 : o.removeSegment();
374 0 : o.removeFinalSlash();
375 : std::vector<OUString> cs(
376 0 : getContents(o.GetMainURL(INetURLObject::NO_DECODE)));
377 0 : for (std::vector<OUString>::iterator i(cs.begin()); i != cs.end();
378 : ++i)
379 : {
380 0 : if (INetURLObject(*i).getName(
381 : INetURLObject::LAST_SEGMENT, true,
382 : INetURLObject::DECODE_WITH_CHARSET).
383 0 : equalsIgnoreAsciiCase(name))
384 : {
385 0 : return true;
386 : }
387 : }
388 0 : return false;
389 522 : }
390 : }
391 :
392 0 : bool utl::UCBContentHelper::IsSubPath(
393 : OUString const & parent, OUString const & child)
394 : {
395 : // The comparison is done in the following way:
396 : // - First, compare case sensitively
397 : // - If names are different, try a fallback comparing case insensitively
398 : // - If the last comparison succeeded, get case preserving normalized names
399 : // for the files and compare them
400 : // (The second step is required because retrieving the normalized names
401 : // might be very expensive in some cases.)
402 0 : INetURLObject candidate(child);
403 0 : INetURLObject folder(parent);
404 0 : if (candidate.GetProtocol() != folder.GetProtocol()) {
405 0 : return false;
406 : }
407 0 : INetURLObject candidateLower(child.toAsciiLowerCase());
408 0 : INetURLObject folderLower(parent.toAsciiLowerCase());
409 : try {
410 0 : INetURLObject tmp;
411 0 : do {
412 0 : if (candidate == folder
413 0 : || (candidate.GetProtocol() == INET_PROT_FILE
414 0 : && candidateLower == folderLower
415 0 : && (getCasePreservingUrl(candidate)
416 0 : == getCasePreservingUrl(folder))))
417 : {
418 0 : return true;
419 : }
420 0 : tmp = candidate;
421 0 : } while (candidate.removeSegment() && candidateLower.removeSegment()
422 0 : && candidate != tmp);
423 : // INetURLObject::removeSegment sometimes returns true without
424 : // modifying the URL, e.g., in case of "file:///"
425 0 : } catch (css::uno::RuntimeException const &) {
426 0 : throw;
427 0 : } catch (css::ucb::CommandAbortedException const &) {
428 : assert(false && "this cannot happen");
429 0 : throw;
430 0 : } catch (css::uno::Exception const &) {
431 0 : css::uno::Any e(cppu::getCaughtException());
432 : SAL_INFO(
433 : "unotools.ucbhelper",
434 : "UCBContentHelper::IsSubPath(" << parent << ", " << child << ") "
435 : << e.getValueType().getTypeName() << " \""
436 0 : << e.get<css::uno::Exception>().Message << '"');
437 : }
438 0 : return false;
439 : }
440 :
441 1306 : bool utl::UCBContentHelper::EqualURLs(
442 : OUString const & url1, OUString const & url2)
443 : {
444 1306 : if (url1.isEmpty() || url2.isEmpty()) {
445 42 : return false;
446 : }
447 : css::uno::Reference< css::ucb::XUniversalContentBroker > ucb(
448 : css::ucb::UniversalContentBroker::create(
449 1264 : comphelper::getProcessComponentContext()));
450 : return
451 1264 : ucb->compareContentIds(
452 2528 : ucb->createContentIdentifier(canonic(url1)),
453 5056 : ucb->createContentIdentifier(canonic(url2)))
454 2528 : == 0;
455 : }
456 :
457 1315 : bool utl::UCBContentHelper::ensureFolder(
458 : css::uno::Reference< css::uno::XComponentContext > xCtx,
459 : css::uno::Reference< css::ucb::XCommandEnvironment > xEnv,
460 : const OUString& rFolder, ucbhelper::Content & result) throw()
461 : {
462 : try
463 : {
464 1315 : INetURLObject aURL( rFolder );
465 1315 : OUString aTitle = aURL.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
466 1315 : aURL.removeSegment();
467 1315 : ::ucbhelper::Content aParent;
468 :
469 2630 : if ( ::ucbhelper::Content::create( aURL.GetMainURL( INetURLObject::NO_DECODE ),
470 2630 : xEnv, xCtx, aParent ) )
471 : {
472 1315 : return ::utl::UCBContentHelper::MakeFolder(aParent, aTitle, result);
473 0 : }
474 : }
475 0 : catch (...)
476 : {
477 : }
478 :
479 0 : return false;
480 : }
481 :
482 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|