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