1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_desktop.hxx"
30 
31 #include "dp_misc.hrc"
32 #include "dp_misc.h"
33 #include "dp_ucb.h"
34 #include "rtl/uri.hxx"
35 #include "rtl/ustrbuf.hxx"
36 #include "ucbhelper/content.hxx"
37 #include "xmlscript/xml_helper.hxx"
38 #include "com/sun/star/io/XInputStream.hpp"
39 #include "com/sun/star/ucb/CommandFailedException.hpp"
40 #include "com/sun/star/ucb/ContentInfo.hpp"
41 #include "com/sun/star/ucb/ContentInfoAttribute.hpp"
42 
43 
44 using namespace ::com::sun::star;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::ucb;
47 using ::rtl::OUString;
48 
49 namespace dp_misc
50 {
51 
52 const OUString StrTitle::operator () ()
53 {
54     return OUSTR("Title");
55 }
56 
57 //==============================================================================
58 bool create_ucb_content(
59     ::ucbhelper::Content * ret_ucbContent, OUString const & url,
60     Reference<XCommandEnvironment> const & xCmdEnv,
61     bool throw_exc )
62 {
63     try {
64         // Existense check...
65         // content ctor/isFolder() will throw exception in case the resource
66         // does not exist.
67 
68         // dilemma: no chance to use the given iahandler here, because it would
69         //          raise no such file dialogs, else no interaction for
70         //          passwords, ...? xxx todo
71         ::ucbhelper::Content ucbContent(
72             url, Reference<XCommandEnvironment>() );
73 
74         ucbContent.isFolder();
75 
76         if (ret_ucbContent != 0)
77         {
78             ucbContent.setCommandEnvironment( xCmdEnv );
79             *ret_ucbContent = ucbContent;
80         }
81         return true;
82     }
83     catch (RuntimeException &) {
84         throw;
85     }
86     catch (Exception &) {
87         if (throw_exc)
88             throw;
89     }
90     return false;
91 }
92 
93 //==============================================================================
94 bool create_folder(
95     ::ucbhelper::Content * ret_ucb_content, OUString const & url_,
96     Reference<XCommandEnvironment> const & xCmdEnv, bool throw_exc )
97 {
98     ::ucbhelper::Content ucb_content;
99     if (create_ucb_content(
100             &ucb_content, url_, xCmdEnv, false /* no throw */ ))
101     {
102         if (ucb_content.isFolder()) {
103             if (ret_ucb_content != 0)
104                 *ret_ucb_content = ucb_content;
105             return true;
106         }
107     }
108 
109     OUString url( url_ );
110     // xxx todo: find parent
111     sal_Int32 slash = url.lastIndexOf( '/' );
112     if (slash < 0) {
113         // fallback:
114         url = expandUnoRcUrl( url );
115         slash = url.lastIndexOf( '/' );
116     }
117     if (slash < 0) {
118         // invalid: has to be at least "auth:/..."
119         if (throw_exc)
120             throw ContentCreationException(
121                 OUSTR("Cannot create folder (invalid path): ") + url,
122                 Reference<XInterface>(), ContentCreationError_UNKNOWN );
123         return false;
124     }
125     ::ucbhelper::Content parentContent;
126     if (! create_folder(
127             &parentContent, url.copy( 0, slash ), xCmdEnv, throw_exc ))
128         return false;
129     const Any title( ::rtl::Uri::decode( url.copy( slash + 1 ),
130                                          rtl_UriDecodeWithCharset,
131                                          RTL_TEXTENCODING_UTF8 ) );
132     const Sequence<ContentInfo> infos(
133         parentContent.queryCreatableContentsInfo() );
134     for ( sal_Int32 pos = 0; pos < infos.getLength(); ++pos )
135     {
136         // look KIND_FOLDER:
137         ContentInfo const & info = infos[ pos ];
138         if ((info.Attributes & ContentInfoAttribute::KIND_FOLDER) != 0)
139         {
140             // make sure the only required bootstrap property is "Title":
141             Sequence<beans::Property> const & rProps = info.Properties;
142             if (rProps.getLength() != 1 ||
143                 !rProps[ 0 ].Name.equalsAsciiL(
144                     RTL_CONSTASCII_STRINGPARAM("Title") ))
145                 continue;
146 
147             try {
148                 if (parentContent.insertNewContent(
149                         info.Type,
150                         Sequence<OUString>( &StrTitle::get(), 1 ),
151                         Sequence<Any>( &title, 1 ),
152                         ucb_content )) {
153                     if (ret_ucb_content != 0)
154                         *ret_ucb_content = ucb_content;
155                     return true;
156                 }
157             }
158             catch (RuntimeException &) {
159                 throw;
160             }
161             catch (CommandFailedException &) {
162                 // Interaction Handler already handled the error
163                 // that has occured...
164             }
165             catch (Exception &) {
166                 if (throw_exc)
167                     throw;
168                 return false;
169             }
170         }
171     }
172     if (throw_exc)
173         throw ContentCreationException(
174             OUSTR("Cannot create folder: ") + url,
175             Reference<XInterface>(), ContentCreationError_UNKNOWN );
176     return false;
177 }
178 
179 //==============================================================================
180 bool erase_path( OUString const & url,
181                  Reference<XCommandEnvironment> const & xCmdEnv,
182                  bool throw_exc )
183 {
184     ::ucbhelper::Content ucb_content;
185     if (create_ucb_content( &ucb_content, url, xCmdEnv, false /* no throw */ ))
186     {
187         try {
188             ucb_content.executeCommand(
189                 OUSTR("delete"), Any( true /* delete physically */ ) );
190         }
191         catch (RuntimeException &) {
192             throw;
193         }
194         catch (Exception &) {
195             if (throw_exc)
196                 throw;
197             return false;
198         }
199     }
200     return true;
201 }
202 
203 //==============================================================================
204 ::rtl::ByteSequence readFile( ::ucbhelper::Content & ucb_content )
205 {
206     ::rtl::ByteSequence bytes;
207     Reference<io::XOutputStream> xStream(
208         ::xmlscript::createOutputStream( &bytes ) );
209     if (! ucb_content.openStream( xStream ))
210         throw RuntimeException(
211             OUSTR(
212                 "::ucbhelper::Content::openStream( XOutputStream ) failed!"),
213             0 );
214     return bytes;
215 }
216 
217 //==============================================================================
218 bool readLine( OUString * res, OUString const & startingWith,
219                ::ucbhelper::Content & ucb_content, rtl_TextEncoding textenc )
220 {
221     // read whole file:
222     ::rtl::ByteSequence bytes( readFile( ucb_content ) );
223     OUString file( reinterpret_cast<sal_Char const *>(bytes.getConstArray()),
224                    bytes.getLength(), textenc );
225     sal_Int32 pos = 0;
226     for (;;)
227     {
228         if (file.match( startingWith, pos ))
229         {
230             ::rtl::OUStringBuffer buf;
231             sal_Int32 start = pos;
232             pos += startingWith.getLength();
233             for (;;)
234             {
235                 pos = file.indexOf( LF, pos );
236                 if (pos < 0) { // EOF
237                     buf.append( file.copy( start ) );
238                 }
239                 else
240                 {
241                     if (pos > 0 && file[ pos - 1 ] == CR)
242                     {
243                         // consume extra CR
244                         buf.append( file.copy( start, pos - start - 1 ) );
245                         ++pos;
246                     }
247                     else
248                         buf.append( file.copy( start, pos - start ) );
249                     ++pos; // consume LF
250                     // check next line:
251                     if (pos < file.getLength() &&
252                         (file[ pos ] == ' ' || file[ pos ] == '\t'))
253                     {
254                         buf.append( static_cast<sal_Unicode>(' ') );
255                         ++pos;
256                         start = pos;
257                         continue;
258                     }
259                 }
260                 break;
261             }
262             *res = buf.makeStringAndClear();
263             return true;
264         }
265         // next line:
266         sal_Int32 next_lf = file.indexOf( LF, pos );
267         if (next_lf < 0) // EOF
268             break;
269         pos = next_lf + 1;
270     }
271     return false;
272 }
273 
274 bool readProperties( ::std::list< ::std::pair< ::rtl::OUString, ::rtl::OUString> > & out_result,
275                      ::ucbhelper::Content & ucb_content )
276 {
277     // read whole file:
278     ::rtl::ByteSequence bytes( readFile( ucb_content ) );
279     OUString file( reinterpret_cast<sal_Char const *>(bytes.getConstArray()),
280                    bytes.getLength(), RTL_TEXTENCODING_UTF8);
281     sal_Int32 pos = 0;
282 
283     for (;;)
284     {
285 
286         ::rtl::OUStringBuffer buf;
287         sal_Int32 start = pos;
288 
289         bool bEOF = false;
290         pos = file.indexOf( LF, pos );
291         if (pos < 0) { // EOF
292             buf.append( file.copy( start ) );
293             bEOF = true;
294         }
295         else
296         {
297             if (pos > 0 && file[ pos - 1 ] == CR)
298                 // consume extra CR
299                 buf.append( file.copy( start, pos - start - 1 ) );
300             else
301                 buf.append( file.copy( start, pos - start ) );
302             pos++;
303         }
304         OUString aLine = buf.makeStringAndClear();
305 
306         sal_Int32 posEqual = aLine.indexOf('=');
307         if (posEqual > 0 && (posEqual + 1) <  aLine.getLength())
308         {
309             OUString name = aLine.copy(0, posEqual);
310             OUString value = aLine.copy(posEqual + 1);
311             out_result.push_back(::std::make_pair(name, value));
312         }
313 
314         if (bEOF)
315             break;
316     }
317     return false;
318 }
319 
320 }
321