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 
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 
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 
123 		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:
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 
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
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
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
207 SvtInetOptions::Impl::notifyListeners(
208     star::uno::Sequence< rtl::OUString > const & rKeys)
209 {
210 	typedef
211         std::vector< std::pair< star::uno::Reference<
212                                     star::beans::XPropertiesChangeListener >,
213                                 star::uno::Sequence<
214                                     star::beans::PropertyChangeEvent > > >
215     List;
216 	List aNotifications;
217 	{
218 		osl::MutexGuard aGuard(m_aMutex);
219 		aNotifications.reserve(m_aListeners.size());
220 		Map::const_iterator aMapEnd(m_aListeners.end());
221 		for (Map::const_iterator aIt(m_aListeners.begin()); aIt != aMapEnd;
222 			 ++aIt)
223 		{
224 			const Map::mapped_type &rSet = aIt->second;
225 			Map::mapped_type::const_iterator aSetEnd(rSet.end());
226 			star::uno::Sequence< star::beans::PropertyChangeEvent >
227 				aEvents(rKeys.getLength());
228 			sal_Int32 nCount = 0;
229 			for (sal_Int32 i = 0; i < rKeys.getLength(); ++i)
230 			{
231 				rtl::OUString
232 					aTheKey(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(
233 						                      "Inet/")));
234 				aTheKey += rKeys[i];
235 				if (rSet.find(aTheKey) != aSetEnd)
236 				{
237 					aEvents[nCount].PropertyName = aTheKey;
238 					aEvents[nCount].PropertyHandle = -1;
239 					++nCount;
240 				}
241 			}
242 			if (nCount > 0)
243 			{
244 				aEvents.realloc(nCount);
245 				aNotifications.
246 					push_back(std::make_pair< List::value_type::first_type,
247 							                  List::value_type::second_type >(
248 								  aIt->first, aEvents));
249 			}
250 		}
251 	}
252 	for (List::size_type i = 0; i < aNotifications.size(); ++i)
253 		if (aNotifications[i].first.is())
254 			aNotifications[i].first->
255 				propertiesChange(aNotifications[i].second);
256 }
257 
258 //============================================================================
259 SvtInetOptions::Impl::Impl():
260 	ConfigItem(rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("Inet/Settings")))
261 {
262 	m_aEntries[INDEX_NO_PROXY].m_aName
263 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetNoProxy"));
264 	m_aEntries[INDEX_PROXY_TYPE].m_aName
265 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetProxyType"));
266 	m_aEntries[INDEX_FTP_PROXY_NAME].m_aName
267 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetFTPProxyName"));
268 	m_aEntries[INDEX_FTP_PROXY_PORT].m_aName
269 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetFTPProxyPort"));
270 	m_aEntries[INDEX_HTTP_PROXY_NAME].m_aName
271 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetHTTPProxyName"));
272 	m_aEntries[INDEX_HTTP_PROXY_PORT].m_aName
273 		= rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ooInetHTTPProxyPort"));
274 
275 	star::uno::Sequence< rtl::OUString > aKeys(ENTRY_COUNT);
276 	for (sal_Int32 i = 0; i < ENTRY_COUNT; ++i)
277 		aKeys[i] = m_aEntries[i].m_aName;
278 	if (!EnableNotification(aKeys))
279 		OSL_ENSURE(false,
280 				   "SvtInetOptions::Impl::Impl(): Bad EnableNotifications()");
281 }
282 
283 //============================================================================
284 star::uno::Any SvtInetOptions::Impl::getProperty(Index nPropIndex)
285 {
286 	for (int nTryCount = 0; nTryCount < 10; ++nTryCount)
287 	{
288 		{
289 			osl::MutexGuard aGuard(m_aMutex);
290 			if (m_aEntries[nPropIndex].m_eState != Entry::UNKNOWN)
291 				return m_aEntries[nPropIndex].m_aValue;
292 		}
293 		star::uno::Sequence< rtl::OUString > aKeys(ENTRY_COUNT);
294 		int nIndices[ENTRY_COUNT];
295 		sal_Int32 nCount = 0;
296 		{
297 			osl::MutexGuard aGuard(m_aMutex);
298 			for (int i = 0; i < ENTRY_COUNT; ++i)
299 				if (m_aEntries[i].m_eState == Entry::UNKNOWN)
300 				{
301 					aKeys[nCount] = m_aEntries[i].m_aName;
302 					nIndices[nCount] = i;
303 					++nCount;
304 				}
305 		}
306 		if (nCount > 0)
307 		{
308 			aKeys.realloc(nCount);
309 			star::uno::Sequence< star::uno::Any >
310                 aValues(GetProperties(aKeys));
311 			OSL_ENSURE(aValues.getLength() == nCount,
312 					   "SvtInetOptions::Impl::getProperty():"
313 					       " Bad GetProperties() result");
314 			nCount = std::min(nCount, aValues.getLength());
315 			{
316 				osl::MutexGuard aGuard(m_aMutex);
317 				for (sal_Int32 i = 0; i < nCount; ++i)
318 				{
319 					int nIndex = nIndices[i];
320 					if (m_aEntries[nIndex].m_eState == Entry::UNKNOWN)
321 					{
322 						m_aEntries[nIndices[i]].m_aValue = aValues[i];
323 						m_aEntries[nIndices[i]].m_eState = Entry::KNOWN;
324 					}
325 				}
326 			}
327 		}
328 	}
329 	OSL_ENSURE(false,
330 			   "SvtInetOptions::Impl::getProperty(): Possible life lock");
331 	{
332 		osl::MutexGuard aGuard(m_aMutex);
333 		return m_aEntries[nPropIndex].m_aValue;
334 	}
335 }
336 
337 //============================================================================
338 void SvtInetOptions::Impl::setProperty(Index nIndex,
339                                        star::uno::Any const & rValue,
340 									   bool bFlush)
341 {
342 	SetModified();
343 	{
344 		osl::MutexGuard aGuard(m_aMutex);
345 		m_aEntries[nIndex].m_aValue = rValue;
346 		m_aEntries[nIndex].m_eState = bFlush ? Entry::KNOWN : Entry::MODIFIED;
347 	}
348 
349 	star::uno::Sequence< rtl::OUString > aKeys(1);
350 	aKeys[0] = m_aEntries[nIndex].m_aName;
351 	if (bFlush)
352 	{
353 		star::uno::Sequence< star::uno::Any > aValues(1);
354 		aValues[0] = rValue;
355 		PutProperties(aKeys, aValues);
356 	}
357 	else
358 		notifyListeners(aKeys);
359 }
360 
361 //============================================================================
362 void
363 SvtInetOptions::Impl::addPropertiesChangeListener(
364 	star::uno::Sequence< rtl::OUString > const & rPropertyNames,
365 	star::uno::Reference< star::beans::XPropertiesChangeListener > const &
366         rListener)
367 {
368 	osl::MutexGuard aGuard(m_aMutex);
369 	Map::mapped_type & rEntry = m_aListeners[rListener];
370 	for (sal_Int32 i = 0; i < rPropertyNames.getLength(); ++i)
371 		rEntry.insert(rPropertyNames[i]);
372 }
373 
374 //============================================================================
375 void
376 SvtInetOptions::Impl::removePropertiesChangeListener(
377 	star::uno::Sequence< rtl::OUString > const & rPropertyNames,
378 	star::uno::Reference< star::beans::XPropertiesChangeListener > const &
379         rListener)
380 {
381 	osl::MutexGuard aGuard(m_aMutex);
382 	Map::iterator aIt(m_aListeners.find(rListener));
383 	if (aIt != m_aListeners.end())
384 	{
385 		for (sal_Int32 i = 0; i < rPropertyNames.getLength(); ++i)
386 			aIt->second.erase(rPropertyNames[i]);
387 		if (aIt->second.empty())
388 			m_aListeners.erase(aIt);
389 	}
390 }
391 
392 //============================================================================
393 //
394 //  SvtInetOptions
395 //
396 //============================================================================
397 
398 namespace
399 {
400     class LocalSingleton : public rtl::Static< osl::Mutex, LocalSingleton >
401     {
402     };
403 }
404 
405 // static
406 SvtInetOptions::Impl * SvtInetOptions::m_pImpl = 0;
407 
408 //============================================================================
409 SvtInetOptions::SvtInetOptions()
410 {
411     osl::MutexGuard aGuard(LocalSingleton::get());
412 	if (!m_pImpl)
413     {
414         RTL_LOGFILE_CONTEXT(aLog, "unotools ( ??? ) ::SvtInetOptions_Impl::ctor()");
415 		m_pImpl = new Impl;
416 
417         ItemHolder1::holdConfigItem(E_INETOPTIONS);
418     }
419 	m_pImpl->acquire();
420 }
421 
422 //============================================================================
423 SvtInetOptions::~SvtInetOptions()
424 {
425     osl::MutexGuard aGuard(LocalSingleton::get());
426 	if (m_pImpl->release() == 0)
427 		m_pImpl = 0;
428 }
429 
430 //============================================================================
431 rtl::OUString SvtInetOptions::GetProxyNoProxy() const
432 {
433 	return takeAny< rtl::OUString >(m_pImpl->
434 									    getProperty(Impl::INDEX_NO_PROXY));
435 }
436 
437 //============================================================================
438 sal_Int32 SvtInetOptions::GetProxyType() const
439 {
440 	return takeAny< sal_Int32 >(m_pImpl->
441 								    getProperty(Impl::INDEX_PROXY_TYPE));
442 }
443 
444 //============================================================================
445 rtl::OUString SvtInetOptions::GetProxyFtpName() const
446 {
447 	return takeAny< rtl::OUString >(m_pImpl->
448 									    getProperty(
449 											Impl::INDEX_FTP_PROXY_NAME));
450 }
451 
452 //============================================================================
453 sal_Int32 SvtInetOptions::GetProxyFtpPort() const
454 {
455 	return takeAny< sal_Int32 >(m_pImpl->
456 								    getProperty(Impl::INDEX_FTP_PROXY_PORT));
457 }
458 
459 //============================================================================
460 rtl::OUString SvtInetOptions::GetProxyHttpName() const
461 {
462 	return takeAny< rtl::OUString >(m_pImpl->
463 									    getProperty(
464 											Impl::INDEX_HTTP_PROXY_NAME));
465 }
466 
467 //============================================================================
468 sal_Int32 SvtInetOptions::GetProxyHttpPort() const
469 {
470 	return takeAny< sal_Int32 >(m_pImpl->
471 								    getProperty(Impl::INDEX_HTTP_PROXY_PORT));
472 }
473 
474 //============================================================================
475 void SvtInetOptions::SetProxyNoProxy(rtl::OUString const & rValue,
476 									 bool bFlush)
477 {
478 	m_pImpl->setProperty(Impl::INDEX_NO_PROXY,
479 						 star::uno::makeAny(rValue),
480 						 bFlush);
481 }
482 
483 //============================================================================
484 void SvtInetOptions::SetProxyType(ProxyType eValue, bool bFlush)
485 {
486 	m_pImpl->setProperty(Impl::INDEX_PROXY_TYPE,
487 						 star::uno::makeAny(sal_Int32(eValue)),
488 						 bFlush);
489 }
490 
491 //============================================================================
492 void SvtInetOptions::SetProxyFtpName(rtl::OUString const & rValue,
493 									 bool bFlush)
494 {
495 	m_pImpl->setProperty(Impl::INDEX_FTP_PROXY_NAME,
496 						 star::uno::makeAny(rValue),
497 						 bFlush);
498 }
499 
500 //============================================================================
501 void SvtInetOptions::SetProxyFtpPort(sal_Int32 nValue, bool bFlush)
502 {
503 	m_pImpl->setProperty(Impl::INDEX_FTP_PROXY_PORT,
504 						 star::uno::makeAny(nValue),
505 						 bFlush);
506 }
507 
508 //============================================================================
509 void SvtInetOptions::SetProxyHttpName(rtl::OUString const & rValue,
510 									  bool bFlush)
511 {
512 	m_pImpl->setProperty(Impl::INDEX_HTTP_PROXY_NAME,
513 						 star::uno::makeAny(rValue),
514 						 bFlush);
515 }
516 
517 //============================================================================
518 void SvtInetOptions::SetProxyHttpPort(sal_Int32 nValue, bool bFlush)
519 {
520 	m_pImpl->setProperty(Impl::INDEX_HTTP_PROXY_PORT,
521 						 star::uno::makeAny(nValue),
522 						 bFlush);
523 }
524 
525 //============================================================================
526 void SvtInetOptions::flush()
527 {
528 	m_pImpl->flush();
529 }
530 
531 //============================================================================
532 void
533 SvtInetOptions::addPropertiesChangeListener(
534 	star::uno::Sequence< rtl::OUString > const & rPropertyNames,
535 	star::uno::Reference< star::beans::XPropertiesChangeListener > const &
536         rListener)
537 {
538 	m_pImpl->addPropertiesChangeListener(rPropertyNames, rListener);
539 }
540 
541 //============================================================================
542 void
543 SvtInetOptions::removePropertiesChangeListener(
544 	star::uno::Sequence< rtl::OUString > const & rPropertyNames,
545 	star::uno::Reference< star::beans::XPropertiesChangeListener > const &
546         rListener)
547 {
548 	m_pImpl->removePropertiesChangeListener(rPropertyNames, rListener);
549 }
550