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_shell.hxx"
26 
27 #include "rtl/ustrbuf.hxx"
28 
29 #include "wininetbackend.hxx"
30 
31 #if defined _MSC_VER
32 #pragma warning(push, 1)
33 #endif
34 #include <windows.h>
35 #include <wininet.h>
36 #include <sal/alloca.h>
37 #if defined _MSC_VER
38 #pragma warning(pop)
39 #endif
40 
41 #define WININET_DLL_NAME "wininet.dll"
42 #define EQUAL_SIGN '='
43 #define COLON      ':'
44 #define SPACE      ' '
45 #define SEMI_COLON ';'
46 
47 namespace {
48 
49 struct Library {
50     HMODULE module;
51 
Library__anone42dcbba0111::Library52     Library(HMODULE theModule): module(theModule) {}
53 
~Library__anone42dcbba0111::Library54     ~Library() { if (module) FreeLibrary(module); }
55 };
56 
57 }
58 
59 typedef struct
60 {
61     rtl::OUString Server;
62     rtl::OUString Port;
63 } ProxyEntry;
64 
65 //------------------------------------------------------------------------
66 // helper functions
67 //------------------------------------------------------------------------
68 
69 namespace // private
70 {
ReadProxyEntry(const rtl::OUString & aProxy,sal_Int32 & i)71     ProxyEntry ReadProxyEntry(const rtl::OUString& aProxy, sal_Int32& i)
72     {
73         ProxyEntry aProxyEntry;
74 
75         aProxyEntry.Server = aProxy.getToken( 0, COLON, i );
76         if ( i > -1 )
77             aProxyEntry.Port = aProxy.getToken( 0, COLON, i );
78 
79         return aProxyEntry;
80     }
81 
FindProxyEntry(const rtl::OUString & aProxyList,const rtl::OUString & aType)82     ProxyEntry FindProxyEntry(const rtl::OUString& aProxyList, const rtl::OUString& aType)
83     {
84         sal_Int32 nIndex = 0;
85 
86         do
87         {
88             // get the next token, e.g. ftp=server:port
89             rtl::OUString nextToken = aProxyList.getToken( 0, SPACE, nIndex );
90 
91             // split the next token again into the parts separated
92             // through '=', e.g. ftp=server:port -> ftp and server:port
93             sal_Int32 i = 0;
94             if( nextToken.indexOf( EQUAL_SIGN ) > -1 )
95             {
96                 if( aType.equals( nextToken.getToken( 0, EQUAL_SIGN, i ) ) )
97                     return ReadProxyEntry(nextToken, i);
98             }
99             else if( aType.getLength() == 0)
100                 return ReadProxyEntry(nextToken, i);
101 
102         } while ( nIndex >= 0 );
103 
104         return ProxyEntry();
105     }
106 
107 } // end private namespace
108 
109 //------------------------------------------------------------------------------
110 
WinInetBackend()111 WinInetBackend::WinInetBackend()
112 {
113     Library hWinInetDll( LoadLibrary( WININET_DLL_NAME ) );
114     if( hWinInetDll.module )
115     {
116         typedef BOOL ( WINAPI *InternetQueryOption_Proc_T )( HINTERNET, DWORD, LPVOID, LPDWORD );
117 
118         InternetQueryOption_Proc_T lpfnInternetQueryOption =
119             reinterpret_cast< InternetQueryOption_Proc_T >(
120                 GetProcAddress( hWinInetDll.module, "InternetQueryOptionA" ) );
121         if (lpfnInternetQueryOption)
122         {
123             LPINTERNET_PROXY_INFO lpi = NULL;
124 
125             // query for the necessary space
126             DWORD dwLength = 0;
127             BOOL bRet = lpfnInternetQueryOption(
128                 NULL,
129                 INTERNET_OPTION_PROXY,
130                 (LPVOID)lpi,
131                 &dwLength );
132 
133             // allocate sufficient space on the heap
134             // insufficient space on the heap results
135             // in a stack overflow exception, we assume
136             // this never happens, because of the relatively
137             // small amount of memory we need
138             // alloca is nice because it is fast and we don't
139             // have to free the allocated memory, it will be
140             // automatically done
141             lpi = reinterpret_cast< LPINTERNET_PROXY_INFO >(
142                 alloca( dwLength ) );
143 
144             bRet = lpfnInternetQueryOption(
145                 NULL,
146                 INTERNET_OPTION_PROXY,
147                 (LPVOID)lpi,
148                 &dwLength );
149 
150             // if a proxy is disabled, InternetQueryOption returns
151             // an empty proxy list, so we don't have to check if
152             // proxy is enabled or not
153 
154             rtl::OUString aProxyList       = rtl::OUString::createFromAscii( lpi->lpszProxy );
155             rtl::OUString aProxyBypassList = rtl::OUString::createFromAscii( lpi->lpszProxyBypass );
156 
157             // override default for ProxyType, which is "0" meaning "No proxies".
158             sal_Int32 nProperties = 1;
159 
160             valueProxyType_.IsPresent = true;
161             valueProxyType_.Value <<= nProperties;
162 
163             // fill proxy bypass list
164             if( aProxyBypassList.getLength() > 0 )
165             {
166                 rtl::OUStringBuffer aReverseList;
167                 sal_Int32 nIndex = 0;
168                 do
169                 {
170                     rtl::OUString aToken = aProxyBypassList.getToken( 0, SPACE, nIndex );
171                     if ( aProxyList.indexOf( aToken ) == -1 )
172                     {
173                         if ( aReverseList.getLength() )
174                         {
175                             aReverseList.insert( 0, sal_Unicode( SEMI_COLON ) );
176                             aReverseList.insert( 0, aToken );
177                         }
178                         else
179                             aReverseList = aToken;
180                     }
181                 }
182                 while ( nIndex >= 0 );
183 
184                 aProxyBypassList = aReverseList.makeStringAndClear();
185 
186                 valueNoProxy_.IsPresent = true;
187                 valueNoProxy_.Value <<= aProxyBypassList.replace( SPACE, SEMI_COLON );
188             }
189 
190             if( aProxyList.getLength() > 0 )
191             {
192                 //-------------------------------------------------
193                 // this implementation follows the algorithm
194                 // of the internet explorer
195                 // if there are type-dependent proxy settings
196                 // and type independent proxy settings in the
197                 // registry the internet explorer chooses the
198                 // type independent proxy for all settings
199                 // e.g. imagine the following registry entry
200                 // ftp=server:port;http=server:port;server:port
201                 // the last token server:port is type independent
202                 // so the ie chooses this proxy server
203 
204                 // if there is no port specified for a type independent
205                 // server the ie uses the port of an http server if
206                 // there is one and it has a port
207                 //-------------------------------------------------
208 
209                 ProxyEntry aTypeIndepProxy = FindProxyEntry( aProxyList, rtl::OUString());
210                 ProxyEntry aHttpProxy = FindProxyEntry( aProxyList, rtl::OUString(
211                     RTL_CONSTASCII_USTRINGPARAM( "http" ) ) );
212                 ProxyEntry aHttpsProxy  = FindProxyEntry( aProxyList, rtl::OUString(
213                     RTL_CONSTASCII_USTRINGPARAM( "https" ) ) );
214 
215                 ProxyEntry aFtpProxy  = FindProxyEntry( aProxyList, rtl::OUString(
216                     RTL_CONSTASCII_USTRINGPARAM( "ftp" ) ) );
217 
218                 if( aTypeIndepProxy.Server.getLength() )
219                 {
220                     aHttpProxy.Server = aTypeIndepProxy.Server;
221                     aHttpsProxy.Server  = aTypeIndepProxy.Server;
222                     aFtpProxy.Server  = aTypeIndepProxy.Server;
223 
224                     if( aTypeIndepProxy.Port.getLength() )
225                     {
226                         aHttpProxy.Port = aTypeIndepProxy.Port;
227                         aHttpsProxy.Port  = aTypeIndepProxy.Port;
228                         aFtpProxy.Port  = aTypeIndepProxy.Port;
229                     }
230                     else
231                     {
232                         aFtpProxy.Port  = aHttpProxy.Port;
233                         aHttpsProxy.Port  = aHttpProxy.Port;
234                     }
235                 }
236 
237                 // http proxy name
238                 if( aHttpProxy.Server.getLength() > 0 )
239                 {
240                     valueHttpProxyName_.IsPresent = true;
241                     valueHttpProxyName_.Value <<= aHttpProxy.Server;
242                 }
243 
244                 // http proxy port
245                 if( aHttpProxy.Port.getLength() > 0 )
246                 {
247                     valueHttpProxyPort_.IsPresent = true;
248                     valueHttpProxyPort_.Value <<= aHttpProxy.Port.toInt32();
249                 }
250 
251                 // https proxy name
252                 if( aHttpsProxy.Server.getLength() > 0 )
253                 {
254                     valueHttpsProxyName_.IsPresent = true;
255                     valueHttpsProxyName_.Value <<= aHttpsProxy.Server;
256                 }
257 
258                 // https proxy port
259                 if( aHttpsProxy.Port.getLength() > 0 )
260                 {
261                     valueHttpsProxyPort_.IsPresent = true;
262                     valueHttpsProxyPort_.Value <<= aHttpsProxy.Port.toInt32();
263                 }
264 
265                 // ftp proxy name
266                 if( aFtpProxy.Server.getLength() > 0 )
267                 {
268                     valueFtpProxyName_.IsPresent = true;
269                     valueFtpProxyName_.Value <<= aFtpProxy.Server;
270                 }
271 
272                 // ftp proxy port
273                 if( aFtpProxy.Port.getLength() > 0 )
274                 {
275                     valueFtpProxyPort_.IsPresent = true;
276                     valueFtpProxyPort_.Value <<= aFtpProxy.Port.toInt32();
277                 }
278             }
279         }
280     }
281 }
282 
283 //------------------------------------------------------------------------------
284 
~WinInetBackend(void)285 WinInetBackend::~WinInetBackend(void)
286 {
287 }
288 
289 //------------------------------------------------------------------------------
290 
createInstance()291 WinInetBackend* WinInetBackend::createInstance()
292 {
293     return new WinInetBackend;
294 }
295 
296 // ---------------------------------------------------------------------------------------
297 
setPropertyValue(rtl::OUString const &,css::uno::Any const &)298 void WinInetBackend::setPropertyValue(
299     rtl::OUString const &, css::uno::Any const &)
300     throw (
301         css::beans::UnknownPropertyException, css::beans::PropertyVetoException,
302         css::lang::IllegalArgumentException, css::lang::WrappedTargetException,
303         css::uno::RuntimeException)
304 {
305     throw css::lang::IllegalArgumentException(
306         rtl::OUString(
307             RTL_CONSTASCII_USTRINGPARAM("setPropertyValue not supported")),
308         static_cast< cppu::OWeakObject * >(this), -1);
309 }
310 
getPropertyValue(rtl::OUString const & PropertyName)311 css::uno::Any WinInetBackend::getPropertyValue(
312     rtl::OUString const & PropertyName)
313     throw (
314         css::beans::UnknownPropertyException, css::lang::WrappedTargetException,
315         css::uno::RuntimeException)
316 {
317     if (PropertyName.equalsAsciiL(
318             RTL_CONSTASCII_STRINGPARAM("ooInetFTPProxyName")))
319     {
320         return css::uno::makeAny(valueFtpProxyName_);
321     } else if (PropertyName.equalsAsciiL(
322                    RTL_CONSTASCII_STRINGPARAM("ooInetFTPProxyPort")))
323     {
324         return css::uno::makeAny(valueFtpProxyPort_);
325     } else if (PropertyName.equalsAsciiL(
326                    RTL_CONSTASCII_STRINGPARAM("ooInetHTTPProxyName")))
327     {
328         return css::uno::makeAny(valueHttpProxyName_);
329     } else if (PropertyName.equalsAsciiL(
330                    RTL_CONSTASCII_STRINGPARAM("ooInetHTTPProxyPort")))
331     {
332         return css::uno::makeAny(valueHttpProxyPort_);
333     } else if (PropertyName.equalsAsciiL(
334                    RTL_CONSTASCII_STRINGPARAM("ooInetHTTPSProxyName")))
335     {
336         return css::uno::makeAny(valueHttpsProxyName_);
337     } else if (PropertyName.equalsAsciiL(
338                    RTL_CONSTASCII_STRINGPARAM("ooInetHTTPSProxyPort")))
339     {
340         return css::uno::makeAny(valueHttpsProxyPort_);
341     } else if (PropertyName.equalsAsciiL(
342                    RTL_CONSTASCII_STRINGPARAM("ooInetNoProxy")))
343     {
344         return css::uno::makeAny(valueNoProxy_);
345     } else if (PropertyName.equalsAsciiL(
346                    RTL_CONSTASCII_STRINGPARAM("ooInetProxyType")))
347     {
348         return css::uno::makeAny(valueProxyType_);
349     } else {
350         throw css::beans::UnknownPropertyException(
351             PropertyName, static_cast< cppu::OWeakObject * >(this));
352     }
353 }
354 
355 //------------------------------------------------------------------------------
356 
getBackendName(void)357 rtl::OUString SAL_CALL WinInetBackend::getBackendName(void) {
358 	return rtl::OUString::createFromAscii("com.sun.star.comp.configuration.backend.WinInetBackend") ;
359 }
360 
361 //------------------------------------------------------------------------------
362 
getImplementationName(void)363 rtl::OUString SAL_CALL WinInetBackend::getImplementationName(void)
364     throw (uno::RuntimeException)
365 {
366     return getBackendName() ;
367 }
368 
369 //------------------------------------------------------------------------------
370 
getBackendServiceNames(void)371 uno::Sequence<rtl::OUString> SAL_CALL WinInetBackend::getBackendServiceNames(void)
372 {
373     uno::Sequence<rtl::OUString> aServiceNameList(1);
374     aServiceNameList[0] = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.configuration.backend.WinInetBackend")) ;
375 
376     return aServiceNameList ;
377 }
378 
379 //------------------------------------------------------------------------------
380 
supportsService(const rtl::OUString & aServiceName)381 sal_Bool SAL_CALL WinInetBackend::supportsService(const rtl::OUString& aServiceName)
382     throw (uno::RuntimeException)
383 {
384     uno::Sequence< rtl::OUString > const svc = getBackendServiceNames();
385 
386     for(sal_Int32 i = 0; i < svc.getLength(); ++i )
387         if(svc[i] == aServiceName)
388             return true;
389 
390     return false;
391 }
392 
393 //------------------------------------------------------------------------------
394 
getSupportedServiceNames(void)395 uno::Sequence<rtl::OUString> SAL_CALL WinInetBackend::getSupportedServiceNames(void)
396     throw (uno::RuntimeException)
397 {
398     return getBackendServiceNames() ;
399 }
400