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_webdav.hxx"
26 
27 #include <string.h>
28 #include "DAVProperties.hxx"
29 #include <rtl/ustrbuf.hxx>
30 
31 using namespace http_dav_ucp;
32 
33 const ::rtl::OUString DAVProperties::CREATIONDATE =
34                 ::rtl::OUString::createFromAscii( "DAV:creationdate" );
35 const ::rtl::OUString DAVProperties::DISPLAYNAME =
36                 ::rtl::OUString::createFromAscii( "DAV:displayname" );
37 const ::rtl::OUString DAVProperties::GETCONTENTLANGUAGE =
38                 ::rtl::OUString::createFromAscii( "DAV:getcontentlanguage" );
39 const ::rtl::OUString DAVProperties::GETCONTENTLENGTH =
40                 ::rtl::OUString::createFromAscii( "DAV:getcontentlength" );
41 const ::rtl::OUString DAVProperties::GETCONTENTTYPE =
42                 ::rtl::OUString::createFromAscii( "DAV:getcontenttype" );
43 const ::rtl::OUString DAVProperties::GETETAG =
44                 ::rtl::OUString::createFromAscii( "DAV:getetag" );
45 const ::rtl::OUString DAVProperties::GETLASTMODIFIED =
46                 ::rtl::OUString::createFromAscii( "DAV:getlastmodified" );
47 const ::rtl::OUString DAVProperties::LOCKDISCOVERY =
48                 ::rtl::OUString::createFromAscii( "DAV:lockdiscovery" );
49 const ::rtl::OUString DAVProperties::RESOURCETYPE =
50                 ::rtl::OUString::createFromAscii( "DAV:resourcetype" );
51 const ::rtl::OUString DAVProperties::SUPPORTEDLOCK =
52                 ::rtl::OUString::createFromAscii( "DAV:supportedlock" );
53 
54 const ::rtl::OUString DAVProperties::EXECUTABLE =
55                 ::rtl::OUString::createFromAscii(
56                                 "http://apache.org/dav/props/executable" );
57 
58 // -------------------------------------------------------------------
59 // static
60 void DAVProperties::createSerfPropName( const rtl::OUString & rFullName,
61                                         SerfPropName & rName )
62 {
63     if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "DAV:" ) ) == 0 )
64     {
65         rName.nspace = "DAV:";
66         rName.name
67             = strdup( rtl::OUStringToOString(
68                         rFullName.copy( RTL_CONSTASCII_LENGTH( "DAV:" ) ),
69                                         RTL_TEXTENCODING_UTF8 ).getStr() );
70     }
71     else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM(
72                 "http://apache.org/dav/props/" ) ) == 0 )
73     {
74         rName.nspace = "http://apache.org/dav/props/";
75         rName.name
76             = strdup( rtl::OUStringToOString(
77                         rFullName.copy(
78                             RTL_CONSTASCII_LENGTH(
79                                 "http://apache.org/dav/props/" ) ),
80                             RTL_TEXTENCODING_UTF8 ).getStr() );
81     }
82     else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM(
83                 "http://ucb.openoffice.org/dav/props/" ) ) == 0 )
84     {
85         rName.nspace = "http://ucb.openoffice.org/dav/props/";
86         rName.name
87             = strdup( rtl::OUStringToOString(
88                         rFullName.copy(
89                             RTL_CONSTASCII_LENGTH(
90                                 "http://ucb.openoffice.org/dav/props/" ) ),
91                             RTL_TEXTENCODING_UTF8 ).getStr() );
92     }
93     else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM(
94                 "<prop:" ) ) == 0 )
95     {
96         // Support for 3rd party namespaces/props
97 
98         rtl::OString aFullName
99             = rtl::OUStringToOString( rFullName, RTL_TEXTENCODING_UTF8 );
100 
101         // Format: <prop:the_propname xmlns:prop="the_namespace">
102 
103         sal_Int32 nStart = RTL_CONSTASCII_LENGTH( "<prop:" );
104         sal_Int32 nLen = aFullName.indexOf( ' ' ) - nStart;
105         rName.name = strdup( aFullName.copy( nStart, nLen ).getStr() );
106 
107         nStart = aFullName.indexOf( '=', nStart + nLen ) + 2; // after ="
108         nLen = aFullName.getLength() - RTL_CONSTASCII_LENGTH( "\">" ) - nStart;
109         rName.nspace = strdup( aFullName.copy( nStart, nLen ).getStr() );
110     }
111     else
112     {
113         // Add our namespace to our own properties.
114         rName.nspace = "http://ucb.openoffice.org/dav/props/";
115         rName.name
116             = strdup( rtl::OUStringToOString( rFullName,
117                                               RTL_TEXTENCODING_UTF8 ).getStr() );
118     }
119 }
120 
121 // -------------------------------------------------------------------
122 // static
123 void DAVProperties::createUCBPropName( const char * nspace,
124                                        const char * name,
125                                        rtl::OUString & rFullName )
126 {
127     rtl::OUString aNameSpace
128         = rtl::OStringToOUString( nspace, RTL_TEXTENCODING_UTF8 );
129     rtl::OUString aName
130         = rtl::OStringToOUString( name,   RTL_TEXTENCODING_UTF8 );
131 
132     if ( !aNameSpace.getLength() )
133     {
134         // Some servers send XML without proper namespaces. Assume "DAV:"
135         // in this case, if name is a well-known dav property name.
136         // Although this is not 100% correct, it solves many problems.
137 
138         if ( DAVProperties::RESOURCETYPE.matchIgnoreAsciiCase( aName, 4 )  ||
139              DAVProperties::SUPPORTEDLOCK.matchIgnoreAsciiCase( aName, 4 ) ||
140              DAVProperties::LOCKDISCOVERY.matchIgnoreAsciiCase( aName, 4 ) ||
141              DAVProperties::CREATIONDATE.matchIgnoreAsciiCase( aName, 4 ) ||
142              DAVProperties::DISPLAYNAME.matchIgnoreAsciiCase( aName, 4 ) ||
143              DAVProperties::GETCONTENTLANGUAGE.matchIgnoreAsciiCase( aName, 4 ) ||
144              DAVProperties::GETCONTENTLENGTH.matchIgnoreAsciiCase( aName, 4 ) ||
145              DAVProperties::GETCONTENTTYPE.matchIgnoreAsciiCase( aName, 4 ) ||
146              DAVProperties::GETETAG.matchIgnoreAsciiCase( aName, 4 ) ||
147              DAVProperties::GETLASTMODIFIED.matchIgnoreAsciiCase( aName, 4 ) )
148         {
149             aNameSpace = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "DAV:" ) );
150         }
151     }
152 
153     // Note: Concatenating strings BEFORE comparing against known namespaces
154     //       is important. See RFC 2815 ( 23.4.2 Meaning of Qualified Names ).
155     rFullName  = aNameSpace;
156     rFullName += aName;
157 
158     if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM(
159                 "DAV:" ) ) == 0 )
160     {
161         // Okay, Just concat strings.
162     }
163     else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM(
164                 "http://apache.org/dav/props/" ) ) == 0 )
165     {
166         // Okay, Just concat strings.
167     }
168     else if ( rFullName.compareToAscii( RTL_CONSTASCII_STRINGPARAM(
169                 "http://ucb.openoffice.org/dav/props/" ) ) == 0 )
170     {
171         // Remove namespace from our own properties.
172         rFullName = rFullName.copy(
173                         RTL_CONSTASCII_LENGTH(
174                             "http://ucb.openoffice.org/dav/props/" ) );
175     }
176     else
177     {
178         // Create property name that encodes, namespace and name ( XML ).
179         rFullName  = rtl::OUString::createFromAscii( "<prop:" );
180         rFullName += aName;
181         rFullName += rtl::OUString::createFromAscii( " xmlns:prop=\"" );
182         rFullName += aNameSpace;
183         rFullName += rtl::OUString::createFromAscii( "\">" );
184     }
185 }
186 
187 // -------------------------------------------------------------------
188 // static
189 bool DAVProperties::isUCBDeadProperty( const SerfPropName & rName )
190 {
191     return ( rName.nspace &&
192              ( rtl_str_compareIgnoreAsciiCase(
193                  rName.nspace, "http://ucb.openoffice.org/dav/props/" )
194                == 0 ) );
195 }
196 
197 bool DAVProperties::isUCBSpecialProperty(const rtl::OUString& rFullName, rtl::OUString& rParsedName)
198 {
199     sal_Int32 nLen = rFullName.getLength();
200     if ( nLen <= 0 ||
201             !rFullName.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "<prop:" ) ) ||
202             !rFullName.endsWithAsciiL( RTL_CONSTASCII_STRINGPARAM( "\">" ) ) )
203         return false;
204 
205     sal_Int32 nStart = RTL_CONSTASCII_LENGTH( "<prop:" );
206     sal_Int32 nEnd = rFullName.indexOf( sal_Unicode( ' ' ), nStart );
207     if ( nEnd == -1 )
208         return false;
209 
210     rtl::OUString sPropName = rFullName.copy( nStart, nEnd - nStart );
211     if ( !sPropName.getLength() )
212         return false;
213 
214     // TODO skip whitespaces?
215     if ( !rFullName.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "xmlns:prop=\"" ), ++nEnd ) )
216         return false;
217 
218     nStart = nEnd + RTL_CONSTASCII_LENGTH( "xmlns:prop=\"" );
219     nEnd = rFullName.indexOf( sal_Unicode( '"' ), nStart );
220     if ( nEnd != nLen - RTL_CONSTASCII_LENGTH( "\">" ) )
221         return false;
222 
223     rtl::OUString sNamesp = rFullName.copy( nStart, nEnd - nStart );
224     if ( !( nLen = sNamesp.getLength() ) )
225         return false;
226 
227     rtl::OUStringBuffer aBuff( sNamesp );
228     if ( sNamesp[nLen - 1] != '/' )
229         aBuff.append( sal_Unicode( '/' ) );
230     aBuff.append( sPropName );
231     rParsedName = aBuff.makeStringAndClear();
232 
233     return rParsedName.getLength();
234 }
235