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_ucbhelper.hxx"
30 
31 /**************************************************************************
32                                 TODO
33  **************************************************************************
34 
35  *************************************************************************/
36 
37 #include <utility>
38 #include <vector>
39 #include <list>
40 #include <osl/mutex.hxx>
41 #include <rtl/ref.hxx>
42 #include <osl/socket.hxx>
43 #include <rtl/ustrbuf.hxx>
44 #include <com/sun/star/container/XNameAccess.hpp>
45 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
46 #include <com/sun/star/util/XChangesListener.hpp>
47 #include <com/sun/star/util/XChangesNotifier.hpp>
48 #include <cppuhelper/implbase1.hxx>
49 #include "ucbhelper/proxydecider.hxx"
50 
51 using namespace com::sun::star;
52 using namespace ucbhelper;
53 
54 #define CONFIG_ROOT_KEY      "org.openoffice.Inet/Settings"
55 #define PROXY_TYPE_KEY       "ooInetProxyType"
56 #define NO_PROXY_LIST_KEY    "ooInetNoProxy"
57 #define HTTP_PROXY_NAME_KEY  "ooInetHTTPProxyName"
58 #define HTTP_PROXY_PORT_KEY  "ooInetHTTPProxyPort"
59 #define HTTPS_PROXY_NAME_KEY "ooInetHTTPSProxyName"
60 #define HTTPS_PROXY_PORT_KEY "ooInetHTTPSProxyPort"
61 #define FTP_PROXY_NAME_KEY   "ooInetFTPProxyName"
62 #define FTP_PROXY_PORT_KEY   "ooInetFTPProxyPort"
63 
64 //=========================================================================
65 namespace ucbhelper
66 {
67 
68 //=========================================================================
69 namespace proxydecider_impl
70 {
71 
72 // A simple case ignoring wildcard matcher.
73 class WildCard
74 {
75 private:
76     rtl::OString m_aWildString;
77 
78 public:
79     WildCard( const rtl::OUString& rWildCard )
80     : m_aWildString(
81         rtl::OUStringToOString(
82             rWildCard, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase() ) {}
83 
84     bool Matches( const rtl::OUString & rStr ) const;
85 };
86 
87 //=========================================================================
88 typedef std::pair< WildCard, WildCard > NoProxyListEntry;
89 
90 //=========================================================================
91 
92 class HostnameCache
93 {
94     typedef std::pair< rtl::OUString, rtl::OUString > HostListEntry;
95 
96     std::list< HostListEntry >     m_aHostList;
97     sal_uInt32                     m_nCapacity;
98 
99 public:
100     explicit HostnameCache( sal_uInt32 nCapacity )
101         : m_nCapacity( nCapacity ) {}
102 
103     bool get( const rtl::OUString & rKey, rtl::OUString & rValue ) const
104     {
105         std::list< HostListEntry >::const_iterator it
106             = m_aHostList.begin();
107         const std::list< HostListEntry >::const_iterator end
108             = m_aHostList.end();
109 
110         while ( it != end )
111         {
112             if ( (*it).first == rKey )
113             {
114                 rValue = (*it).second;
115                 return true;
116             }
117             it++;
118         }
119         return false;
120     }
121 
122     void put( const rtl::OUString & rKey, const rtl::OUString & rValue )
123     {
124         if ( m_aHostList.size() == m_nCapacity )
125             m_aHostList.resize( m_nCapacity / 2 );
126 
127         m_aHostList.push_front( HostListEntry( rKey, rValue ) );
128     }
129 };
130 
131 //=========================================================================
132 class InternetProxyDecider_Impl :
133     public cppu::WeakImplHelper1< util::XChangesListener >
134 {
135     mutable osl::Mutex                       m_aMutex;
136     InternetProxyServer                      m_aHttpProxy;
137     InternetProxyServer                      m_aHttpsProxy;
138     InternetProxyServer                      m_aFtpProxy;
139     const InternetProxyServer                m_aEmptyProxy;
140     sal_Int32                                m_nProxyType;
141     uno::Reference< util::XChangesNotifier > m_xNotifier;
142     std::vector< NoProxyListEntry >          m_aNoProxyList;
143     mutable HostnameCache                    m_aHostnames;
144 
145 private:
146     bool shouldUseProxy( const rtl::OUString & rHost,
147                          sal_Int32 nPort,
148                          bool bUseFullyQualified ) const;
149 public:
150     InternetProxyDecider_Impl(
151         const uno::Reference< lang::XMultiServiceFactory >& rxSMgr );
152     virtual ~InternetProxyDecider_Impl();
153 
154     static rtl::Reference< InternetProxyDecider_Impl > createInstance(
155         const uno::Reference< lang::XMultiServiceFactory >& rxSMgr );
156 
157     void dispose();
158 
159     const InternetProxyServer & getProxy( const rtl::OUString & rProtocol,
160                                           const rtl::OUString & rHost,
161                                           sal_Int32 nPort ) const;
162 
163     // XChangesListener
164     virtual void SAL_CALL changesOccurred( const util::ChangesEvent& Event )
165         throw( uno::RuntimeException );
166 
167     // XEventListener ( base of XChangesLisetenr )
168     virtual void SAL_CALL disposing( const lang::EventObject& Source )
169         throw( uno::RuntimeException );
170 
171 private:
172     void setNoProxyList( const rtl::OUString & rNoProxyList );
173 };
174 
175 //=========================================================================
176 //=========================================================================
177 //
178 // WildCard Implementation.
179 //
180 //=========================================================================
181 //=========================================================================
182 
183 bool WildCard::Matches( const rtl::OUString& rString ) const
184 {
185     rtl::OString aString
186         = rtl::OUStringToOString(
187                     rString, RTL_TEXTENCODING_UTF8 ).toAsciiLowerCase();
188     const char * pStr  = aString.getStr();
189     const char * pWild = m_aWildString.getStr();
190 
191     int pos  = 0;
192     int flag = 0;
193 
194     while ( *pWild || flag )
195     {
196         switch ( *pWild )
197         {
198             case '?':
199                 if ( *pStr == '\0' )
200                     return 0;
201                 break;
202 
203             default:
204                 if ( ( *pWild == '\\' ) && ( ( *( pWild + 1 ) == '?' )
205                                              || ( *( pWild + 1 ) == '*') ) )
206                     pWild++;
207                 if ( *pWild != *pStr )
208                     if ( !pos )
209                         return 0;
210                     else
211                         pWild += pos;
212                 else
213                     break;
214 
215                 // Note: fall-thru's are intended!
216 
217             case '*':
218                 while ( *pWild == '*' )
219                     pWild++;
220                 if ( *pWild == '\0' )
221                     return 1;
222                 flag = 1;
223                 pos  = 0;
224                 if ( *pStr == '\0' )
225                     return ( *pWild == '\0' );
226                 while ( *pStr && *pStr != *pWild )
227                 {
228                     if ( *pWild == '?' ) {
229                         pWild++;
230                         while ( *pWild == '*' )
231                             pWild++;
232                     }
233                     pStr++;
234                     if ( *pStr == '\0' )
235                         return ( *pWild == '\0' );
236                 }
237                 break;
238         }
239         if ( *pWild != '\0' )
240             pWild++;
241         if ( *pStr != '\0' )
242             pStr++;
243         else
244             flag = 0;
245         if ( flag )
246             pos--;
247     }
248     return ( *pStr == '\0' ) && ( *pWild == '\0' );
249 }
250 
251 //=========================================================================
252 bool getConfigStringValue(
253     const uno::Reference< container::XNameAccess > & xNameAccess,
254     const char * key,
255     rtl::OUString & value )
256 {
257     try
258     {
259         if ( !( xNameAccess->getByName( rtl::OUString::createFromAscii( key ) )
260                 >>= value ) )
261         {
262             OSL_ENSURE( sal_False,
263                         "InternetProxyDecider - "
264                         "Error getting config item value!" );
265             return false;
266         }
267     }
268     catch ( lang::WrappedTargetException const & )
269     {
270         return false;
271     }
272     catch ( container::NoSuchElementException const & )
273     {
274         return false;
275     }
276     return true;
277 }
278 
279 //=========================================================================
280 bool getConfigInt32Value(
281     const uno::Reference< container::XNameAccess > & xNameAccess,
282     const char * key,
283     sal_Int32 & value )
284 {
285     try
286     {
287         uno::Any aValue = xNameAccess->getByName(
288             rtl::OUString::createFromAscii( key ) );
289         if ( aValue.hasValue() && !( aValue >>= value ) )
290         {
291             OSL_ENSURE( sal_False,
292                         "InternetProxyDecider - "
293                         "Error getting config item value!" );
294             return false;
295         }
296     }
297     catch ( lang::WrappedTargetException const & )
298     {
299         return false;
300     }
301     catch ( container::NoSuchElementException const & )
302     {
303         return false;
304     }
305     return true;
306 }
307 
308 //=========================================================================
309 //=========================================================================
310 //
311 // InternetProxyDecider_Impl Implementation.
312 //
313 //=========================================================================
314 //=========================================================================
315 
316 InternetProxyDecider_Impl::InternetProxyDecider_Impl(
317     const uno::Reference< lang::XMultiServiceFactory >& rxSMgr )
318     : m_nProxyType( 0 ),
319       m_aHostnames( 256 ) // cache size
320 {
321     try
322     {
323         //////////////////////////////////////////////////////////////
324         // Read proxy configuration from config db.
325         //////////////////////////////////////////////////////////////
326 
327         uno::Reference< lang::XMultiServiceFactory > xConfigProv(
328                 rxSMgr->createInstance(
329                     rtl::OUString::createFromAscii(
330                         "com.sun.star.configuration.ConfigurationProvider" ) ),
331                 uno::UNO_QUERY );
332 
333         uno::Sequence< uno::Any > aArguments( 1 );
334         aArguments[ 0 ] <<= rtl::OUString::createFromAscii( CONFIG_ROOT_KEY );
335 
336         uno::Reference< uno::XInterface > xInterface(
337                     xConfigProv->createInstanceWithArguments(
338                         rtl::OUString::createFromAscii(
339                             "com.sun.star.configuration.ConfigurationAccess" ),
340                     aArguments ) );
341 
342         OSL_ENSURE( xInterface.is(),
343                     "InternetProxyDecider - No config access!" );
344 
345         if ( xInterface.is() )
346         {
347             uno::Reference< container::XNameAccess > xNameAccess(
348                                             xInterface, uno::UNO_QUERY );
349             OSL_ENSURE( xNameAccess.is(),
350                         "InternetProxyDecider - No name access!" );
351 
352             if ( xNameAccess.is() )
353             {
354                 // *** Proxy type ***
355                 getConfigInt32Value(
356                     xNameAccess, PROXY_TYPE_KEY, m_nProxyType );
357 
358                 // *** No proxy list ***
359                 rtl::OUString aNoProxyList;
360                 getConfigStringValue(
361                     xNameAccess, NO_PROXY_LIST_KEY, aNoProxyList );
362                 setNoProxyList( aNoProxyList );
363 
364                 // *** HTTP ***
365                 getConfigStringValue(
366                     xNameAccess, HTTP_PROXY_NAME_KEY, m_aHttpProxy.aName );
367 
368                 m_aHttpProxy.nPort = -1;
369                 getConfigInt32Value(
370                     xNameAccess, HTTP_PROXY_PORT_KEY, m_aHttpProxy.nPort );
371                 if ( m_aHttpProxy.nPort == -1 )
372                     m_aHttpProxy.nPort = 80; // standard HTTP port.
373 
374                 // *** HTTPS ***
375                 getConfigStringValue(
376                     xNameAccess, HTTPS_PROXY_NAME_KEY, m_aHttpsProxy.aName );
377 
378                 m_aHttpsProxy.nPort = -1;
379                 getConfigInt32Value(
380                     xNameAccess, HTTPS_PROXY_PORT_KEY, m_aHttpsProxy.nPort );
381                 if ( m_aHttpsProxy.nPort == -1 )
382                     m_aHttpsProxy.nPort = 443; // standard HTTPS port.
383 
384                 // *** FTP ***
385                 getConfigStringValue(
386                     xNameAccess, FTP_PROXY_NAME_KEY, m_aFtpProxy.aName );
387 
388                 m_aFtpProxy.nPort = -1;
389                 getConfigInt32Value(
390                     xNameAccess, FTP_PROXY_PORT_KEY, m_aFtpProxy.nPort );
391             }
392 
393             // Register as listener for config changes.
394 
395             m_xNotifier = uno::Reference< util::XChangesNotifier >(
396                                                 xInterface, uno::UNO_QUERY );
397 
398             OSL_ENSURE( m_xNotifier.is(),
399                         "InternetProxyDecider - No notifier!" );
400 
401             if ( m_xNotifier.is() )
402                 m_xNotifier->addChangesListener( this );
403         }
404     }
405     catch ( uno::Exception const & )
406     {
407         // createInstance, createInstanceWithArguments
408         OSL_ENSURE( sal_False, "InternetProxyDecider - Exception!" );
409     }
410 }
411 
412 //=========================================================================
413 // virtual
414 InternetProxyDecider_Impl::~InternetProxyDecider_Impl()
415 {
416 }
417 
418 //=========================================================================
419 void InternetProxyDecider_Impl::dispose()
420 {
421     uno::Reference< util::XChangesNotifier > xNotifier;
422 
423     if ( m_xNotifier.is() )
424     {
425         osl::Guard< osl::Mutex > aGuard( m_aMutex );
426 
427         if ( m_xNotifier.is() )
428         {
429             xNotifier = m_xNotifier;
430             m_xNotifier.clear();
431         }
432     }
433 
434     // Do this unguarded!
435     if ( xNotifier.is() )
436         xNotifier->removeChangesListener( this );
437 }
438 
439 //=========================================================================
440 bool InternetProxyDecider_Impl::shouldUseProxy( const rtl::OUString & rHost,
441                                                 sal_Int32 nPort,
442                                                 bool bUseFullyQualified ) const
443 {
444     rtl::OUStringBuffer aBuffer;
445 
446     if ( ( rHost.indexOf( ':' ) != -1 ) &&
447          ( rHost[ 0 ] != sal_Unicode( '[' ) ) )
448     {
449         // host is given as numeric IPv6 address
450         aBuffer.appendAscii( "[" );
451         aBuffer.append( rHost );
452         aBuffer.appendAscii( "]" );
453     }
454     else
455     {
456         // host is given either as numeric IPv4 address or non-numeric hostname
457         aBuffer.append( rHost );
458     }
459 
460     aBuffer.append( sal_Unicode( ':' ) );
461     aBuffer.append( rtl::OUString::valueOf( nPort ) );
462     const rtl::OUString aHostAndPort( aBuffer.makeStringAndClear() );
463 
464     std::vector< NoProxyListEntry >::const_iterator it
465         = m_aNoProxyList.begin();
466     const std::vector< NoProxyListEntry >::const_iterator end
467         = m_aNoProxyList.end();
468 
469     while ( it != end )
470     {
471         if ( bUseFullyQualified )
472         {
473             if ( (*it).second.Matches( aHostAndPort ) )
474                 return false;
475         }
476         else
477         {
478             if ( (*it).first.Matches( aHostAndPort ) )
479                 return false;
480         }
481         it++;
482     }
483 
484     return true;
485 }
486 
487 //=========================================================================
488 const InternetProxyServer & InternetProxyDecider_Impl::getProxy(
489                                             const rtl::OUString & rProtocol,
490                                             const rtl::OUString & rHost,
491                                             sal_Int32 nPort ) const
492 {
493     osl::Guard< osl::Mutex > aGuard( m_aMutex );
494 
495     if ( m_nProxyType == 0 )
496     {
497         // Never use proxy.
498         return m_aEmptyProxy;
499     }
500 
501     if ( rHost.getLength() && m_aNoProxyList.size() )
502     {
503         //////////////////////////////////////////////////////////////////
504         // First, try direct hostname match - #110515#
505         //////////////////////////////////////////////////////////////////
506 
507         if ( !shouldUseProxy( rHost, nPort, false ) )
508             return m_aEmptyProxy;
509 
510         //////////////////////////////////////////////////////////////////
511         // Second, try match against full qualified hostname - #104401#
512         //////////////////////////////////////////////////////////////////
513 
514         rtl::OUString aHost;
515 
516         if ( ( rHost[ 0 ] == sal_Unicode( '[' ) ) &&
517              ( rHost.getLength() > 1 ) )
518         {
519             // host is given as numeric IPv6 address. name resolution
520             // functions need hostname without square brackets.
521             aHost = rHost.copy( 1, rHost.getLength() - 2 );
522         }
523         else
524         {
525             aHost = rHost;
526         }
527 
528         rtl::OUString aFullyQualifiedHost;
529         if ( !m_aHostnames.get( aHost, aFullyQualifiedHost ) )
530         {
531             // This might be quite expensive (DNS lookup).
532             const osl::SocketAddr aAddr( aHost, nPort );
533             aFullyQualifiedHost = aAddr.getHostname().toAsciiLowerCase();
534             m_aHostnames.put( aHost, aFullyQualifiedHost );
535         }
536 
537         // Error resolving name? -> fallback.
538         if ( !aFullyQualifiedHost.getLength() )
539             aFullyQualifiedHost = aHost;
540 
541         if ( aFullyQualifiedHost != aHost )
542         {
543             if ( !shouldUseProxy( aFullyQualifiedHost, nPort, false ) )
544                 return m_aEmptyProxy;
545         }
546 
547         //////////////////////////////////////////////////////////////////
548         // Third, try match of fully qualified entries in no-proxy list
549         // against full qualified hostname
550         //
551         // Example:
552         // list: staroffice-doc -> full: xyz.germany.sun.com
553         // in:   staroffice-doc.germany.sun.com -> full: xyz.germany.sun.com
554         //
555         //////////////////////////////////////////////////////////////////
556 
557         if ( !shouldUseProxy( aFullyQualifiedHost, nPort, true ) )
558             return m_aEmptyProxy;
559     }
560 
561     if ( rProtocol.toAsciiLowerCase()
562             .equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ftp" ) ) )
563     {
564         if ( m_aFtpProxy.aName.getLength() > 0 && m_aFtpProxy.nPort >= 0 )
565             return m_aFtpProxy;
566     }
567     else if ( rProtocol.toAsciiLowerCase()
568                   .equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "https" ) ) )
569     {
570         if ( m_aHttpsProxy.aName.getLength() )
571             return m_aHttpsProxy;
572     }
573     else if ( m_aHttpProxy.aName.getLength() )
574     {
575         // All other protocols use the HTTP proxy.
576         return m_aHttpProxy;
577     }
578     return m_aEmptyProxy;
579 }
580 
581 //=========================================================================
582 // virtual
583 void SAL_CALL InternetProxyDecider_Impl::changesOccurred(
584                                         const util::ChangesEvent& Event )
585     throw( uno::RuntimeException )
586 {
587     osl::Guard< osl::Mutex > aGuard( m_aMutex );
588 
589     sal_Int32 nCount = Event.Changes.getLength();
590     if ( nCount )
591     {
592         const util::ElementChange* pElementChanges
593             = Event.Changes.getConstArray();
594         for ( sal_Int32 n = 0; n < nCount; ++n )
595         {
596             const util::ElementChange& rElem = pElementChanges[ n ];
597             rtl::OUString aKey;
598             if ( ( rElem.Accessor >>= aKey ) && aKey.getLength() )
599             {
600                 if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
601                                                     PROXY_TYPE_KEY ) ) )
602                 {
603                     if ( !( rElem.Element >>= m_nProxyType ) )
604                     {
605                         OSL_ENSURE( sal_False,
606                                     "InternetProxyDecider - changesOccurred - "
607                                     "Error getting config item value!" );
608                     }
609                 }
610                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
611                                                     NO_PROXY_LIST_KEY ) ) )
612                 {
613                     rtl::OUString aNoProxyList;
614                     if ( !( rElem.Element >>= aNoProxyList ) )
615                     {
616                         OSL_ENSURE( sal_False,
617                                     "InternetProxyDecider - changesOccurred - "
618                                     "Error getting config item value!" );
619                     }
620 
621                     setNoProxyList( aNoProxyList );
622                 }
623                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
624                                                     HTTP_PROXY_NAME_KEY ) ) )
625                 {
626                     if ( !( rElem.Element >>= m_aHttpProxy.aName ) )
627                     {
628                         OSL_ENSURE( sal_False,
629                                     "InternetProxyDecider - changesOccurred - "
630                                     "Error getting config item value!" );
631                     }
632                 }
633                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
634                                                     HTTP_PROXY_PORT_KEY ) ) )
635                 {
636                     if ( !( rElem.Element >>= m_aHttpProxy.nPort ) )
637                     {
638                         OSL_ENSURE( sal_False,
639                                     "InternetProxyDecider - changesOccurred - "
640                                     "Error getting config item value!" );
641                     }
642 
643                     if ( m_aHttpProxy.nPort == -1 )
644                         m_aHttpProxy.nPort = 80; // standard HTTP port.
645                 }
646                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
647                                                     HTTPS_PROXY_NAME_KEY ) ) )
648                 {
649                     if ( !( rElem.Element >>= m_aHttpsProxy.aName ) )
650                     {
651                         OSL_ENSURE( sal_False,
652                                     "InternetProxyDecider - changesOccurred - "
653                                     "Error getting config item value!" );
654                     }
655                 }
656                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
657                                                     HTTPS_PROXY_PORT_KEY ) ) )
658                 {
659                     if ( !( rElem.Element >>= m_aHttpsProxy.nPort ) )
660                     {
661                         OSL_ENSURE( sal_False,
662                                     "InternetProxyDecider - changesOccurred - "
663                                     "Error getting config item value!" );
664                     }
665 
666                     if ( m_aHttpsProxy.nPort == -1 )
667                         m_aHttpsProxy.nPort = 443; // standard HTTPS port.
668                 }
669                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
670                                                     FTP_PROXY_NAME_KEY ) ) )
671                 {
672                     if ( !( rElem.Element >>= m_aFtpProxy.aName ) )
673                     {
674                         OSL_ENSURE( sal_False,
675                                     "InternetProxyDecider - changesOccurred - "
676                                     "Error getting config item value!" );
677                     }
678                 }
679                 else if ( aKey.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
680                                                     FTP_PROXY_PORT_KEY ) ) )
681                 {
682                     if ( !( rElem.Element >>= m_aFtpProxy.nPort ) )
683                     {
684                         OSL_ENSURE( sal_False,
685                                     "InternetProxyDecider - changesOccurred - "
686                                     "Error getting config item value!" );
687                     }
688                 }
689             }
690         }
691     }
692 }
693 
694 //=========================================================================
695 // virtual
696 void SAL_CALL InternetProxyDecider_Impl::disposing(const lang::EventObject&)
697     throw( uno::RuntimeException )
698 {
699     if ( m_xNotifier.is() )
700     {
701         osl::Guard< osl::Mutex > aGuard( m_aMutex );
702 
703         if ( m_xNotifier.is() )
704             m_xNotifier.clear();
705     }
706 }
707 
708 //=========================================================================
709 void InternetProxyDecider_Impl::setNoProxyList(
710                                         const rtl::OUString & rNoProxyList )
711 {
712     osl::Guard< osl::Mutex > aGuard( m_aMutex );
713 
714     m_aNoProxyList.clear();
715 
716     if ( rNoProxyList.getLength() )
717     {
718         // List of connection endpoints hostname[:port],
719         // separated by semicolon. Wilcards allowed.
720 
721         sal_Int32 nPos = 0;
722         sal_Int32 nEnd = rNoProxyList.indexOf( ';' );
723         sal_Int32 nLen = rNoProxyList.getLength();
724 
725         do
726         {
727             if ( nEnd == -1 )
728                 nEnd = nLen;
729 
730             rtl::OUString aToken = rNoProxyList.copy( nPos, nEnd - nPos );
731 
732             if ( aToken.getLength() )
733             {
734                 rtl::OUString aServer;
735                 rtl::OUString aPort;
736 
737                 // numerical IPv6 address?
738                 bool bIPv6Address = false;
739                 sal_Int32 nClosedBracketPos = aToken.indexOf( ']' );
740                 if ( nClosedBracketPos == -1 )
741                     nClosedBracketPos = 0;
742                 else
743                     bIPv6Address = true;
744 
745                 sal_Int32 nColonPos = aToken.indexOf( ':', nClosedBracketPos );
746                 if ( nColonPos == -1 )
747                 {
748                     // No port given, server pattern equals current token
749                     aPort = rtl::OUString::createFromAscii( "*" );
750                     if ( aToken.indexOf( '*' ) == -1 )
751                     {
752                         // pattern describes exactly one server
753                         aServer = aToken;
754                     }
755 
756                     aToken += rtl::OUString::createFromAscii( ":*" );
757                 }
758                 else
759                 {
760                     // Port given, extract server pattern
761                     sal_Int32 nAsterixPos = aToken.indexOf( '*' );
762                     aPort = aToken.copy( nColonPos + 1 );
763                     if ( nAsterixPos < nColonPos )
764                     {
765                         // pattern describes exactly one server
766                         aServer = aToken.copy( 0, nColonPos );
767                     }
768                 }
769 
770                 rtl::OUStringBuffer aFullyQualifiedHost;
771                 if ( aServer.getLength() )
772                 {
773                     // Remember fully qualified server name if current list
774                     // entry specifies exactly one non-fully qualified server
775                     // name.
776 
777                     // remove square brackets from host name in case it's
778                     // a numerical IPv6 address.
779                     if ( bIPv6Address )
780                         aServer = aServer.copy( 1, aServer.getLength() - 2 );
781 
782                     // This might be quite expensive (DNS lookup).
783                     const osl::SocketAddr aAddr( aServer, 0 );
784                     rtl::OUString aTmp = aAddr.getHostname().toAsciiLowerCase();
785                     if ( aTmp != aServer.toAsciiLowerCase() )
786                     {
787                         if ( bIPv6Address )
788                         {
789                             aFullyQualifiedHost.appendAscii( "[" );
790                             aFullyQualifiedHost.append( aTmp );
791                             aFullyQualifiedHost.appendAscii( "]" );
792                         }
793                         else
794                         {
795                             aFullyQualifiedHost.append( aTmp );
796                         }
797                         aFullyQualifiedHost.appendAscii( ":" );
798                         aFullyQualifiedHost.append( aPort );
799                     }
800                 }
801 
802                 m_aNoProxyList.push_back(
803                     NoProxyListEntry( WildCard( aToken ),
804                                       WildCard(
805                                         aFullyQualifiedHost
806                                             .makeStringAndClear() ) ) );
807             }
808 
809             if ( nEnd != nLen )
810             {
811                 nPos = nEnd + 1;
812                 nEnd = rNoProxyList.indexOf( ';', nPos );
813             }
814         }
815         while ( nEnd != nLen );
816     }
817 }
818 
819 } // namespace proxydecider_impl
820 
821 //=========================================================================
822 //=========================================================================
823 //
824 // InternetProxyDecider Implementation.
825 //
826 //=========================================================================
827 //=========================================================================
828 
829 InternetProxyDecider::InternetProxyDecider(
830     const uno::Reference< lang::XMultiServiceFactory >& rxSMgr )
831 : m_pImpl( new proxydecider_impl::InternetProxyDecider_Impl( rxSMgr ) )
832 {
833     m_pImpl->acquire();
834 }
835 
836 //=========================================================================
837 InternetProxyDecider::~InternetProxyDecider()
838 {
839     // Break circular reference between config listener and notifier.
840     m_pImpl->dispose();
841 
842     // Let him go...
843     m_pImpl->release();
844 }
845 
846 //=========================================================================
847 bool InternetProxyDecider::shouldUseProxy( const rtl::OUString & rProtocol,
848                                            const rtl::OUString & rHost,
849                                            sal_Int32 nPort ) const
850 {
851     const InternetProxyServer & rData = m_pImpl->getProxy( rProtocol,
852                                                            rHost,
853                                                            nPort );
854     return ( rData.aName.getLength() > 0 );
855 }
856 
857 //=========================================================================
858 const InternetProxyServer & InternetProxyDecider::getProxy(
859                                             const rtl::OUString & rProtocol,
860                                             const rtl::OUString & rHost,
861                                             sal_Int32 nPort ) const
862 {
863     return m_pImpl->getProxy( rProtocol, rHost, nPort );
864 }
865 
866 } // namespace ucbhelper
867