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_unotools.hxx"
30 #include <unotools/inetoptions.hxx>
31 #include "rtl/instance.hxx"
32 #include <tools/urlobj.hxx>
33 #ifndef _WILDCARD_HXX
34 #include <tools/wldcrd.hxx>
35 #endif
36 
37 #include <algorithm>
38 #include <map>
39 #include <set>
40 #include <vector>
41 #include <utility>
42 #include <com/sun/star/beans/PropertyChangeEvent.hpp>
43 #include <com/sun/star/beans/XPropertiesChangeListener.hpp>
44 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
45 #include <com/sun/star/system/XProxySettings.hpp>
46 #include <com/sun/star/uno/Any.hxx>
47 #include <com/sun/star/uno/Exception.hpp>
48 #include <com/sun/star/uno/Reference.hxx>
49 #include <com/sun/star/uno/RuntimeException.hpp>
50 #include <osl/mutex.hxx>
51 #include <rtl/ustring.h>
52 #include <rtl/ustring.hxx>
53 #include <sal/types.h>
54 #include <unotools/configitem.hxx>
55 #include <unotools/processfactory.hxx>
56 #include <osl/diagnose.h>
57 #include <salhelper/refobj.hxx>
58 #include <rtl/logfile.hxx>
59 #include "itemholder1.hxx"
60 
61 using namespace com::sun;
62 
63 //============================================================================
64 //
65 //  takeAny
66 //
67 //============================================================================
68 
69 namespace {
70 
71 template< typename T > inline T takeAny(star::uno::Any const & rAny)
72 {
73 	T aValue = T();
74 	rAny >>= aValue;
75 	return aValue;
76 }
77 
78 }
79 
80 //============================================================================
81 //
82 //  SvtInetOptions::Impl
83 //
84 //============================================================================
85 
86 class SvtInetOptions::Impl: public salhelper::ReferenceObject,
87                             public utl::ConfigItem
88 {
89 public:
90 	enum Index
91 	{
92 		INDEX_NO_PROXY,
93 		INDEX_PROXY_TYPE,
94 		INDEX_FTP_PROXY_NAME,
95 		INDEX_FTP_PROXY_PORT,
96 		INDEX_HTTP_PROXY_NAME,
97 		INDEX_HTTP_PROXY_PORT
98 	};
99 
100 	Impl();
101 
102 	star::uno::Any getProperty(Index nIndex);
103 
104 	void
105     setProperty(Index nIndex, star::uno::Any const & rValue, bool bFlush);
106 
107 	inline void flush() { Commit(); }
108 
109 	void
110 	addPropertiesChangeListener(
111 		star::uno::Sequence< rtl::OUString > const & rPropertyNames,
112 		star::uno::Reference< star::beans::XPropertiesChangeListener > const &
113             rListener);
114 
115 	void
116 	removePropertiesChangeListener(
117 		star::uno::Sequence< rtl::OUString > const & rPropertyNames,
118 		star::uno::Reference< star::beans::XPropertiesChangeListener > const &
119             rListener);
120 
121 private:
122 	enum { ENTRY_COUNT = INDEX_HTTP_PROXY_PORT + 1 };
123 
124 	struct Entry
125 	{
126 		enum State { UNKNOWN, KNOWN, MODIFIED };
127 
128 		inline Entry(): m_eState(UNKNOWN) {}
129 
130 		rtl::OUString m_aName;
131 		star::uno::Any m_aValue;
132 		State m_eState;
133 	};
134 
135 	// MSVC has problems with the below Map type when
136 	// star::uno::Reference< star::beans::XPropertiesChangeListener > is not
137     // wrapped in class Listener:
138 	class Listener:
139         public star::uno::Reference< star::beans::XPropertiesChangeListener >
140 	{
141 	public:
142 		Listener(star::uno::Reference<
143                          star::beans::XPropertiesChangeListener > const &
144 				     rListener):
145 			star::uno::Reference< star::beans::XPropertiesChangeListener >(
146                 rListener)
147         {}
148 	};
149 
150 	typedef std::map< Listener, std::set< rtl::OUString > > Map;
151 
152 	osl::Mutex m_aMutex;
153 	Entry m_aEntries[ENTRY_COUNT];
154 	Map m_aListeners;
155 
156 	virtual inline ~Impl() { Commit(); }
157 
158 	virtual void Notify(star::uno::Sequence< rtl::OUString > const & rKeys);
159 
160 	virtual void Commit();
161 
162 	void notifyListeners(star::uno::Sequence< rtl::OUString > const & rKeys);
163 };
164 
165 //============================================================================
166 // virtual
167 void
168 SvtInetOptions::Impl::Notify(star::uno::Sequence< rtl::OUString > const &
169                                  rKeys)
170 {
171 	{
172 		osl::MutexGuard aGuard(m_aMutex);
173 		for (sal_Int32 i = 0; i < rKeys.getLength(); ++i)
174 			for (sal_Int32 j = 0; j < ENTRY_COUNT; ++j)
175 				if (rKeys[i] == m_aEntries[j].m_aName)
176 				{
177 					m_aEntries[j].m_eState = Entry::UNKNOWN;
178 					break;
179 				}
180 	}
181 	notifyListeners(rKeys);
182 }
183 
184 //============================================================================
185 // virtual
186 void SvtInetOptions::Impl::Commit()
187 {
188 	star::uno::Sequence< rtl::OUString > aKeys(ENTRY_COUNT);
189 	star::uno::Sequence< star::uno::Any > aValues(ENTRY_COUNT);
190 	sal_Int32 nCount = 0;
191 	{
192 		osl::MutexGuard aGuard(m_aMutex);
193 		for (sal_Int32 i = 0; i < ENTRY_COUNT; ++i)
194 			if (m_aEntries[i].m_eState == Entry::MODIFIED)
195 			{
196 				aKeys[nCount] = m_aEntries[i].m_aName;
197 				aValues[nCount] = m_aEntries[i].m_aValue;
198 				++nCount;
199 				m_aEntries[i].m_eState = Entry::KNOWN;
200 			}
201 	}
202 	if (nCount > 0)
203 	{
204 		aKeys.realloc(nCount);
205 		aValues.realloc(nCount);
206 		PutProperties(aKeys, aValues);
207 	}
208 }
209 
210 //============================================================================
211 void
212 SvtInetOptions::Impl::notifyListeners(
213     star::uno::Sequence< rtl::OUString > const & rKeys)
214 {
215 	typedef
216         std::vector< std::pair< star::uno::Reference<
217                                     star::beans::XPropertiesChangeListener >,
218                                 star::uno::Sequence<
219                                     star::beans::PropertyChangeEvent > > >
220     List;
221 	List aNotifications;
222 	{
223 		osl::MutexGuard aGuard(m_aMutex);
224 		aNotifications.reserve(m_aListeners.size());
225 		Map::const_iterator aMapEnd(m_aListeners.end());
226 		for (Map::const_iterator aIt(m_aListeners.begin()); aIt != aMapEnd;
227 			 ++aIt)
228 		{
229 			const Map::mapped_type &rSet = aIt->second;
230 			Map::mapped_type::const_iterator aSetEnd(rSet.end());
231 			star::uno::Sequence< star::beans::PropertyChangeEvent >
232 				aEvents(rKeys.getLength());
233 			sal_Int32 nCount = 0;
234 			for (sal_Int32 i = 0; i < rKeys.getLength(); ++i)
235 			{
236 				rtl::OUString
237 					aTheKey(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
238 						                      "Inet/")));
239 				aTheKey += rKeys[i];
240 				if (rSet.find(aTheKey) != aSetEnd)
241 				{
242 					aEvents[nCount].PropertyName = aTheKey;
243 					aEvents[nCount].PropertyHandle = -1;
244 					++nCount;
245 				}
246 			}
247 			if (nCount > 0)
248 			{
249 				aEvents.realloc(nCount);
250 				aNotifications.
251 					push_back(std::make_pair< List::value_type::first_type,
252 							                  List::value_type::second_type >(
253 								  aIt->first, aEvents));
254 			}
255 		}
256 	}
257 	for (List::size_type i = 0; i < aNotifications.size(); ++i)
258 		if (aNotifications[i].first.is())
259 			aNotifications[i].first->
260 				propertiesChange(aNotifications[i].second);
261 }
262 
263 //============================================================================
264 SvtInetOptions::Impl::Impl():
265 	ConfigItem(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Inet/Settings")))
266 {
267 	m_aEntries[INDEX_NO_PROXY].m_aName
268 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetNoProxy"));
269 	m_aEntries[INDEX_PROXY_TYPE].m_aName
270 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetProxyType"));
271 	m_aEntries[INDEX_FTP_PROXY_NAME].m_aName
272 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetFTPProxyName"));
273 	m_aEntries[INDEX_FTP_PROXY_PORT].m_aName
274 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetFTPProxyPort"));
275 	m_aEntries[INDEX_HTTP_PROXY_NAME].m_aName
276 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetHTTPProxyName"));
277 	m_aEntries[INDEX_HTTP_PROXY_PORT].m_aName
278 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetHTTPProxyPort"));
279 
280 	star::uno::Sequence< rtl::OUString > aKeys(ENTRY_COUNT);
281 	for (sal_Int32 i = 0; i < ENTRY_COUNT; ++i)
282 		aKeys[i] = m_aEntries[i].m_aName;
283 	if (!EnableNotification(aKeys))
284 		OSL_ENSURE(false,
285 				   "SvtInetOptions::Impl::Impl(): Bad EnableNotifications()");
286 }
287 
288 //============================================================================
289 star::uno::Any SvtInetOptions::Impl::getProperty(Index nPropIndex)
290 {
291 	for (int nTryCount = 0; nTryCount < 10; ++nTryCount)
292 	{
293 		{
294 			osl::MutexGuard aGuard(m_aMutex);
295 			if (m_aEntries[nPropIndex].m_eState != Entry::UNKNOWN)
296 				return m_aEntries[nPropIndex].m_aValue;
297 		}
298 		star::uno::Sequence< rtl::OUString > aKeys(ENTRY_COUNT);
299 		int nIndices[ENTRY_COUNT];
300 		sal_Int32 nCount = 0;
301 		{
302 			osl::MutexGuard aGuard(m_aMutex);
303 			for (int i = 0; i < ENTRY_COUNT; ++i)
304 				if (m_aEntries[i].m_eState == Entry::UNKNOWN)
305 				{
306 					aKeys[nCount] = m_aEntries[i].m_aName;
307 					nIndices[nCount] = i;
308 					++nCount;
309 				}
310 		}
311 		if (nCount > 0)
312 		{
313 			aKeys.realloc(nCount);
314 			star::uno::Sequence< star::uno::Any >
315                 aValues(GetProperties(aKeys));
316 			OSL_ENSURE(aValues.getLength() == nCount,
317 					   "SvtInetOptions::Impl::getProperty():"
318 					       " Bad GetProperties() result");
319 			nCount = std::min(nCount, aValues.getLength());
320 			{
321 				osl::MutexGuard aGuard(m_aMutex);
322 				for (sal_Int32 i = 0; i < nCount; ++i)
323 				{
324 					int nIndex = nIndices[i];
325 					if (m_aEntries[nIndex].m_eState == Entry::UNKNOWN)
326 					{
327 						m_aEntries[nIndices[i]].m_aValue = aValues[i];
328 						m_aEntries[nIndices[i]].m_eState = Entry::KNOWN;
329 					}
330 				}
331 			}
332 		}
333 	}
334 	OSL_ENSURE(false,
335 			   "SvtInetOptions::Impl::getProperty(): Possible life lock");
336 	{
337 		osl::MutexGuard aGuard(m_aMutex);
338 		return m_aEntries[nPropIndex].m_aValue;
339 	}
340 }
341 
342 //============================================================================
343 void SvtInetOptions::Impl::setProperty(Index nIndex,
344                                        star::uno::Any const & rValue,
345 									   bool bFlush)
346 {
347 	SetModified();
348 	{
349 		osl::MutexGuard aGuard(m_aMutex);
350 		m_aEntries[nIndex].m_aValue = rValue;
351 		m_aEntries[nIndex].m_eState = bFlush ? Entry::KNOWN : Entry::MODIFIED;
352 	}
353 
354 	star::uno::Sequence< rtl::OUString > aKeys(1);
355 	aKeys[0] = m_aEntries[nIndex].m_aName;
356 	if (bFlush)
357 	{
358 		star::uno::Sequence< star::uno::Any > aValues(1);
359 		aValues[0] = rValue;
360 		PutProperties(aKeys, aValues);
361 	}
362 	else
363 		notifyListeners(aKeys);
364 }
365 
366 //============================================================================
367 void
368 SvtInetOptions::Impl::addPropertiesChangeListener(
369 	star::uno::Sequence< rtl::OUString > const & rPropertyNames,
370 	star::uno::Reference< star::beans::XPropertiesChangeListener > const &
371         rListener)
372 {
373 	osl::MutexGuard aGuard(m_aMutex);
374 	Map::mapped_type & rEntry = m_aListeners[rListener];
375 	for (sal_Int32 i = 0; i < rPropertyNames.getLength(); ++i)
376 		rEntry.insert(rPropertyNames[i]);
377 }
378 
379 //============================================================================
380 void
381 SvtInetOptions::Impl::removePropertiesChangeListener(
382 	star::uno::Sequence< rtl::OUString > const & rPropertyNames,
383 	star::uno::Reference< star::beans::XPropertiesChangeListener > const &
384         rListener)
385 {
386 	osl::MutexGuard aGuard(m_aMutex);
387 	Map::iterator aIt(m_aListeners.find(rListener));
388 	if (aIt != m_aListeners.end())
389 	{
390 		for (sal_Int32 i = 0; i < rPropertyNames.getLength(); ++i)
391 			aIt->second.erase(rPropertyNames[i]);
392 		if (aIt->second.empty())
393 			m_aListeners.erase(aIt);
394 	}
395 }
396 
397 //============================================================================
398 //
399 //  SvtInetOptions
400 //
401 //============================================================================
402 
403 namespace
404 {
405     class LocalSingleton : public rtl::Static< osl::Mutex, LocalSingleton >
406     {
407     };
408 }
409 
410 // static
411 SvtInetOptions::Impl * SvtInetOptions::m_pImpl = 0;
412 
413 //============================================================================
414 SvtInetOptions::SvtInetOptions()
415 {
416     osl::MutexGuard aGuard(LocalSingleton::get());
417 	if (!m_pImpl)
418     {
419         RTL_LOGFILE_CONTEXT(aLog, "unotools ( ??? ) ::SvtInetOptions_Impl::ctor()");
420 		m_pImpl = new Impl;
421 
422         ItemHolder1::holdConfigItem(E_INETOPTIONS);
423     }
424 	m_pImpl->acquire();
425 }
426 
427 //============================================================================
428 SvtInetOptions::~SvtInetOptions()
429 {
430     osl::MutexGuard aGuard(LocalSingleton::get());
431 	if (m_pImpl->release() == 0)
432 		m_pImpl = 0;
433 }
434 
435 //============================================================================
436 rtl::OUString SvtInetOptions::GetProxyNoProxy() const
437 {
438 	return takeAny< rtl::OUString >(m_pImpl->
439 									    getProperty(Impl::INDEX_NO_PROXY));
440 }
441 
442 //============================================================================
443 sal_Int32 SvtInetOptions::GetProxyType() const
444 {
445 	return takeAny< sal_Int32 >(m_pImpl->
446 								    getProperty(Impl::INDEX_PROXY_TYPE));
447 }
448 
449 //============================================================================
450 rtl::OUString SvtInetOptions::GetProxyFtpName() const
451 {
452 	return takeAny< rtl::OUString >(m_pImpl->
453 									    getProperty(
454 											Impl::INDEX_FTP_PROXY_NAME));
455 }
456 
457 //============================================================================
458 sal_Int32 SvtInetOptions::GetProxyFtpPort() const
459 {
460 	return takeAny< sal_Int32 >(m_pImpl->
461 								    getProperty(Impl::INDEX_FTP_PROXY_PORT));
462 }
463 
464 //============================================================================
465 rtl::OUString SvtInetOptions::GetProxyHttpName() const
466 {
467 	return takeAny< rtl::OUString >(m_pImpl->
468 									    getProperty(
469 											Impl::INDEX_HTTP_PROXY_NAME));
470 }
471 
472 //============================================================================
473 sal_Int32 SvtInetOptions::GetProxyHttpPort() const
474 {
475 	return takeAny< sal_Int32 >(m_pImpl->
476 								    getProperty(Impl::INDEX_HTTP_PROXY_PORT));
477 }
478 
479 //============================================================================
480 void SvtInetOptions::SetProxyNoProxy(rtl::OUString const & rValue,
481 									 bool bFlush)
482 {
483 	m_pImpl->setProperty(Impl::INDEX_NO_PROXY,
484 						 star::uno::makeAny(rValue),
485 						 bFlush);
486 }
487 
488 //============================================================================
489 void SvtInetOptions::SetProxyType(ProxyType eValue, bool bFlush)
490 {
491 	m_pImpl->setProperty(Impl::INDEX_PROXY_TYPE,
492 						 star::uno::makeAny(sal_Int32(eValue)),
493 						 bFlush);
494 }
495 
496 //============================================================================
497 void SvtInetOptions::SetProxyFtpName(rtl::OUString const & rValue,
498 									 bool bFlush)
499 {
500 	m_pImpl->setProperty(Impl::INDEX_FTP_PROXY_NAME,
501 						 star::uno::makeAny(rValue),
502 						 bFlush);
503 }
504 
505 //============================================================================
506 void SvtInetOptions::SetProxyFtpPort(sal_Int32 nValue, bool bFlush)
507 {
508 	m_pImpl->setProperty(Impl::INDEX_FTP_PROXY_PORT,
509 						 star::uno::makeAny(nValue),
510 						 bFlush);
511 }
512 
513 //============================================================================
514 void SvtInetOptions::SetProxyHttpName(rtl::OUString const & rValue,
515 									  bool bFlush)
516 {
517 	m_pImpl->setProperty(Impl::INDEX_HTTP_PROXY_NAME,
518 						 star::uno::makeAny(rValue),
519 						 bFlush);
520 }
521 
522 //============================================================================
523 void SvtInetOptions::SetProxyHttpPort(sal_Int32 nValue, bool bFlush)
524 {
525 	m_pImpl->setProperty(Impl::INDEX_HTTP_PROXY_PORT,
526 						 star::uno::makeAny(nValue),
527 						 bFlush);
528 }
529 
530 //============================================================================
531 void SvtInetOptions::flush()
532 {
533 	m_pImpl->flush();
534 }
535 
536 //============================================================================
537 void
538 SvtInetOptions::addPropertiesChangeListener(
539 	star::uno::Sequence< rtl::OUString > const & rPropertyNames,
540 	star::uno::Reference< star::beans::XPropertiesChangeListener > const &
541         rListener)
542 {
543 	m_pImpl->addPropertiesChangeListener(rPropertyNames, rListener);
544 }
545 
546 //============================================================================
547 void
548 SvtInetOptions::removePropertiesChangeListener(
549 	star::uno::Sequence< rtl::OUString > const & rPropertyNames,
550 	star::uno::Reference< star::beans::XPropertiesChangeListener > const &
551         rListener)
552 {
553 	m_pImpl->removePropertiesChangeListener(rPropertyNames, rListener);
554 }
555