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