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_svtools.hxx"
26 
27 #ifdef UNX
28 #include <pwd.h>
29 #include <sys/types.h>
30 #endif
31 
32 #include <svtools/inettbc.hxx>
33 #include <com/sun/star/uno/Any.hxx>
34 #include <com/sun/star/uno/Reference.hxx>
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
37 #include <com/sun/star/sdbc/XResultSet.hpp>
38 #include <com/sun/star/sdbc/XRow.hpp>
39 #include <com/sun/star/task/XInteractionHandler.hpp>
40 #include <com/sun/star/ucb/NumberedSortingInfo.hpp>
41 #include <com/sun/star/ucb/XAnyCompareFactory.hpp>
42 #include <com/sun/star/ucb/XProgressHandler.hpp>
43 #include <com/sun/star/ucb/XContentAccess.hpp>
44 #include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp>
45 #include <comphelper/processfactory.hxx>
46 #include <vcl/toolbox.hxx>
47 #include <vos/thread.hxx>
48 #include <vos/mutex.hxx>
49 #include <vcl/svapp.hxx>
50 #include <unotools/historyoptions.hxx>
51 #include <svl/eitem.hxx>
52 #include <svl/stritem.hxx>
53 #include <svl/itemset.hxx>
54 #include "svl/urihelper.hxx"
55 #include <unotools/pathoptions.hxx>
56 
57 #define _SVSTDARR_STRINGSDTOR
58 #include <svl/svstdarr.hxx>
59 #include <ucbhelper/commandenvironment.hxx>
60 #include <ucbhelper/content.hxx>
61 #include <unotools/localfilehelper.hxx>
62 #include <unotools/ucbhelper.hxx>
63 #include "iodlg.hrc"
64 #include <svtools/asynclink.hxx>
65 #include <svl/urlfilter.hxx>
66 
67 #include <vector>
68 #include <algorithm>
69 
70 // -----------------------------------------------------------------------
71 
72 using namespace ::rtl;
73 using namespace ::ucbhelper;
74 using namespace ::utl;
75 using namespace ::com::sun::star;
76 using namespace ::com::sun::star::beans;
77 using namespace ::com::sun::star::lang;
78 using namespace ::com::sun::star::sdbc;
79 using namespace ::com::sun::star::task;
80 using namespace ::com::sun::star::ucb;
81 using namespace ::com::sun::star::uno;
82 
83 // -----------------------------------------------------------------------
84 class SvtURLBox_Impl
85 {
86 public:
87     SvStringsDtor*                  pURLs;
88     SvStringsDtor*                  pCompletions;
89     const IUrlFilter*               pUrlFilter;
90     ::std::vector< WildCard >       m_aFilters;
91 
92     static sal_Bool TildeParsing( String& aText, String& aBaseUrl );
93 
SvtURLBox_Impl()94     inline SvtURLBox_Impl( )
95         :pURLs( NULL )
96         ,pCompletions( NULL )
97         ,pUrlFilter( NULL )
98     {
99         FilterMatch::createWildCardFilterList(String(),m_aFilters);
100     }
101 };
102 
103 // -----------------------------------------------------------------------
104 class SvtMatchContext_Impl : public ::vos::OThread
105 {
106     static ::vos::OMutex*           pDirMutex;
107 
108     SvStringsDtor                   aPickList;
109     SvStringsDtor*                  pCompletions;
110     SvStringsDtor*                  pURLs;
111     svtools::AsynchronLink          aLink;
112     String                          aBaseURL;
113     String                          aText;
114     SvtURLBox*                      pBox;
115     sal_Bool                            bStop;
116     sal_Bool                            bOnlyDirectories;
117     sal_Bool                            bNoSelection;
118 
119     DECL_STATIC_LINK(               SvtMatchContext_Impl, Select_Impl, void* );
120 
121     virtual void SAL_CALL           onTerminated( );
122     virtual void SAL_CALL           run();
123     virtual void SAL_CALL           Cancel();
124     void                            Insert( const String& rCompletion, const String& rURL, sal_Bool bForce = sal_False);
125     void                            ReadFolder( const String& rURL, const String& rMatch, sal_Bool bSmart );
126     void                            FillPicklist( SvStringsDtor& rPickList );
127 
128 public:
129     static ::vos::OMutex*           GetMutex();
130 
131                                     SvtMatchContext_Impl( SvtURLBox* pBoxP, const String& rText );
132                                     ~SvtMatchContext_Impl();
133     void                            Stop();
134 };
135 
136 ::vos::OMutex* SvtMatchContext_Impl::pDirMutex = 0;
137 
GetMutex()138 ::vos::OMutex* SvtMatchContext_Impl::GetMutex()
139 {
140     ::vos::OGuard aGuard( ::vos::OMutex::getGlobalMutex() );
141     if( !pDirMutex )
142         pDirMutex = new ::vos::OMutex;
143     return pDirMutex;
144 }
145 
146 //-------------------------------------------------------------------------
SvtMatchContext_Impl(SvtURLBox * pBoxP,const String & rText)147 SvtMatchContext_Impl::SvtMatchContext_Impl(
148     SvtURLBox* pBoxP, const String& rText )
149     : aLink( STATIC_LINK( this, SvtMatchContext_Impl, Select_Impl ) )
150     , aBaseURL( pBoxP->aBaseURL )
151     , aText( rText )
152     , pBox( pBoxP )
153     , bStop( sal_False )
154     , bOnlyDirectories( pBoxP->bOnlyDirectories )
155     , bNoSelection( pBoxP->bNoSelection )
156 {
157     pURLs = new SvStringsDtor;
158     pCompletions = new SvStringsDtor;
159 
160     aLink.CreateMutex();
161 
162     FillPicklist( aPickList );
163 
164     create();
165 }
166 
167 //-------------------------------------------------------------------------
~SvtMatchContext_Impl()168 SvtMatchContext_Impl::~SvtMatchContext_Impl()
169 {
170     aLink.ClearPendingCall();
171     delete pURLs;
172     delete pCompletions;
173 }
174 
175 //-------------------------------------------------------------------------
FillPicklist(SvStringsDtor & rPickList)176 void SvtMatchContext_Impl::FillPicklist( SvStringsDtor& rPickList )
177 {
178     // Einlesung der Historypickliste
179     Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( eHISTORY );
180     sal_uInt32 nCount = seqPicklist.getLength();
181 
182     for( sal_uInt32 nItem=0; nItem < nCount; nItem++ )
183     {
184         Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
185 
186         OUString sTitle;
187         INetURLObject aURL;
188 
189         sal_uInt32 nPropertyCount = seqPropertySet.getLength();
190 
191         for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ )
192         {
193             if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
194             {
195                 seqPropertySet[nProperty].Value >>= sTitle;
196                 aURL.SetURL( sTitle );
197                 const StringPtr pStr = new String( aURL.GetMainURL( INetURLObject::DECODE_WITH_CHARSET ) );
198                 rPickList.Insert( pStr, (sal_uInt16) nItem );
199                 break;
200             }
201         }
202     }
203 }
204 
205 //-------------------------------------------------------------------------
Cancel()206 void SAL_CALL SvtMatchContext_Impl::Cancel()
207 {
208     // Cancel button pressed
209     terminate();
210 }
211 
212 //-------------------------------------------------------------------------
Stop()213 void SvtMatchContext_Impl::Stop()
214 {
215     bStop = sal_True;
216 
217     if( isRunning() )
218         terminate();
219 }
220 
221 //-------------------------------------------------------------------------
onTerminated()222 void SvtMatchContext_Impl::onTerminated( )
223 {
224     aLink.Call( this );
225 }
226 
227 //-------------------------------------------------------------------------
228 // This method is called via AsynchronLink, so it has the SolarMutex and
229 // calling solar code ( VCL ... ) is safe. It is called when the thread is
230 // terminated ( finished work or stopped ). Cancelling the thread via
231 // Cancellable does not not discard the information gained so far, it
232 // inserts all collected completions into the listbox.
233 
234 IMPL_STATIC_LINK( SvtMatchContext_Impl, Select_Impl, void*, )
235 {
236     // avoid recursion through cancel button
237     if( pThis->bStop )
238     {
239         // completions was stopped, no display
240         delete pThis;
241         return 0;
242     }
243 
244     SvtURLBox* pBox = pThis->pBox;
245     pBox->bAutoCompleteMode = sal_True;
246 
247     // did we filter completions which otherwise would have been valid?
248     // (to be filled below)
249     bool bValidCompletionsFiltered = false;
250 
251     // insert all completed strings into the listbox
252     pBox->Clear();
253 
254     for( sal_uInt16 nPos = 0; nPos<pThis->pCompletions->Count(); nPos++ )
255     {
256         String sCompletion( *(*pThis->pCompletions)[nPos] );
257 
258         // convert the file into an URL
259         String sURL( sCompletion );
260         ::utl::LocalFileHelper::ConvertPhysicalNameToURL( sCompletion, sURL );
261             // note: if this doesn't work, we're not interested in: we're checking the
262             // untouched sCompletion then
263 
264         if ( pBox->pImp->pUrlFilter )
265         {
266             if ( !pBox->pImp->pUrlFilter->isUrlAllowed( sURL ) )
267             {   // this URL is not allowed
268                 bValidCompletionsFiltered = true;
269                 continue;
270             }
271         }
272         if (( sURL.Len() > 0 ) && ( sURL.GetChar(sURL.Len()-1) != '/' ))
273         {
274             String sUpperURL( sURL );
275             sUpperURL.ToUpperAscii();
276 
277             ::std::vector< WildCard >::const_iterator aMatchingFilter =
278                 ::std::find_if(
279                     pBox->pImp->m_aFilters.begin(),
280                     pBox->pImp->m_aFilters.end(),
281                     FilterMatch( sUpperURL )
282                 );
283             if ( aMatchingFilter == pBox->pImp->m_aFilters.end() )
284 
285             {   // this URL is not allowed
286                 bValidCompletionsFiltered = true;
287                 continue;
288             }
289         }
290 
291         pBox->InsertEntry( sCompletion );
292     }
293 
294     if( !pThis->bNoSelection && pThis->pCompletions->Count() && !bValidCompletionsFiltered )
295     {
296         // select the first one
297         String aTmp( pBox->GetEntry(0) );
298         pBox->SetText( aTmp );
299         pBox->SetSelection( Selection( pThis->aText.Len(), aTmp.Len() ) );
300     }
301 
302     // transfer string lists to listbox and forget them
303     delete pBox->pImp->pURLs;
304     delete pBox->pImp->pCompletions;
305     pBox->pImp->pURLs = pThis->pURLs;
306     pBox->pImp->pCompletions = pThis->pCompletions;
307     pThis->pURLs = NULL;
308     pThis->pCompletions = NULL;
309 
310     // force listbox to resize ( it may be open )
311     pBox->Resize();
312 
313     // the box has this control as a member so we have to set that member
314     // to zero before deleting ourself.
315     pBox->pCtx = NULL;
316     delete pThis;
317 
318     return 0;
319 }
320 
321 //-------------------------------------------------------------------------
Insert(const String & rCompletion,const String & rURL,sal_Bool bForce)322 void SvtMatchContext_Impl::Insert( const String& rCompletion,
323                                    const String& rURL,
324                                    sal_Bool bForce )
325 {
326     if( !bForce )
327     {
328         // avoid doubles
329         for( sal_uInt16 nPos = pCompletions->Count(); nPos--; )
330             if( *(*pCompletions)[ nPos ] == rCompletion )
331                 return;
332     }
333 
334     const StringPtr pCompletion = new String( rCompletion );
335     pCompletions->Insert( pCompletion, pCompletions->Count() );
336     const StringPtr pURL = new String( rURL );
337     pURLs->Insert( pURL, pURLs->Count() );
338 }
339 
340 //-------------------------------------------------------------------------
ReadFolder(const String & rURL,const String & rMatch,sal_Bool bSmart)341 void SvtMatchContext_Impl::ReadFolder( const String& rURL,
342                                        const String& rMatch,
343                                        sal_Bool bSmart )
344 {
345     // check folder to scan
346     if( !UCBContentHelper::IsFolder( rURL ) )
347         return;
348 
349     sal_Bool bPureHomePath = sal_False;
350 #ifdef UNX
351     bPureHomePath = aText.Search( '~' ) == 0 && aText.Search( '/' ) == STRING_NOTFOUND;
352 #endif
353 
354     sal_Bool bExectMatch = bPureHomePath
355                 || aText.CompareToAscii( "." ) == COMPARE_EQUAL
356                 || (aText.Len() > 1 && aText.Copy( aText.Len() - 2, 2 ).CompareToAscii( "/." ) == COMPARE_EQUAL)
357                 || (aText.Len() > 2 && aText.Copy( aText.Len() - 3, 3 ).CompareToAscii( "/.." ) == COMPARE_EQUAL);
358 
359     // for pure home pathes ( ~username ) the '.' at the end of rMatch
360     // means that it poits to root catalog
361     // this is done only for file contents since home pathes parsing is usefull only for them
362     if ( bPureHomePath && rMatch.Equals( String::CreateFromAscii( "file:///." ) ) )
363     {
364         // a home that refers to /
365 
366         String aNewText( aText );
367         aNewText += '/';
368         Insert( aNewText, rURL, sal_True );
369 
370         return;
371     }
372 
373     // string to match with
374     INetURLObject aMatchObj( rMatch );
375     String aMatchName;
376 
377     if ( rURL != String(aMatchObj.GetMainURL( INetURLObject::NO_DECODE ) ))
378     {
379         aMatchName = aMatchObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
380 
381         // matching is always done case insensitive, but completion will be case sensitive and case preserving
382         aMatchName.ToLowerAscii();
383 
384         // if the matchstring ends with a slash, we must search for this also
385         if ( rMatch.GetChar(rMatch.Len()-1) == '/' )
386             aMatchName += '/';
387     }
388 
389     xub_StrLen nMatchLen = aMatchName.Len();
390 
391     INetURLObject aFolderObj( rURL );
392     DBG_ASSERT( aFolderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" );
393 
394     try
395     {
396         uno::Reference< XMultiServiceFactory > xFactory = ::comphelper::getProcessServiceFactory();
397 
398         Content aCnt( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ),
399                       new ::ucbhelper::CommandEnvironment( uno::Reference< XInteractionHandler >(),
400                                                      uno::Reference< XProgressHandler >() ) );
401         uno::Reference< XResultSet > xResultSet;
402         Sequence< OUString > aProps(2);
403         OUString* pProps = aProps.getArray();
404         pProps[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
405         pProps[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) );
406 
407         try
408         {
409             uno::Reference< XDynamicResultSet > xDynResultSet;
410             ResultSetInclude eInclude = INCLUDE_FOLDERS_AND_DOCUMENTS;
411             if ( bOnlyDirectories )
412                 eInclude = INCLUDE_FOLDERS_ONLY;
413 
414             xDynResultSet = aCnt.createDynamicCursor( aProps, eInclude );
415 
416             uno::Reference < XAnyCompareFactory > xCompare;
417             uno::Reference < XSortedDynamicResultSetFactory > xSRSFac(
418                 xFactory->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SortedDynamicResultSetFactory") ) ), UNO_QUERY );
419 
420             Sequence< NumberedSortingInfo > aSortInfo( 2 );
421             NumberedSortingInfo* pInfo = aSortInfo.getArray();
422             pInfo[ 0 ].ColumnIndex = 2;
423             pInfo[ 0 ].Ascending   = sal_False;
424             pInfo[ 1 ].ColumnIndex = 1;
425             pInfo[ 1 ].Ascending   = sal_True;
426 
427             uno::Reference< XDynamicResultSet > xDynamicResultSet;
428             xDynamicResultSet =
429                 xSRSFac->createSortedDynamicResultSet( xDynResultSet, aSortInfo, xCompare );
430 
431             if ( xDynamicResultSet.is() )
432             {
433                 xResultSet = xDynamicResultSet->getStaticResultSet();
434             }
435         }
436         catch( ::com::sun::star::uno::Exception& ) {}
437 
438         if ( xResultSet.is() )
439         {
440             uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
441             uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
442 
443             try
444             {
445                 while ( schedule() && xResultSet->next() )
446                 {
447                     String   aURL      = xContentAccess->queryContentIdentifierString();
448                     String   aTitle    = xRow->getString(1);
449                     sal_Bool bIsFolder = xRow->getBoolean(2);
450 
451                     // matching is always done case insensitive, but completion will be case sensitive and case preserving
452                     aTitle.ToLowerAscii();
453 
454                     if (
455                         !nMatchLen ||
456                         (bExectMatch && aMatchName.Equals(aTitle)) ||
457                         (!bExectMatch && aMatchName.CompareTo(aTitle, nMatchLen) == COMPARE_EQUAL)
458                        )
459                     {
460                         // all names fit if matchstring is empty
461                         INetURLObject aObj( aURL );
462                         sal_Unicode aDelimiter = '/';
463                         if ( bSmart )
464                             // when parsing is done "smart", the delimiter must be "guessed"
465                             aObj.getFSysPath( (INetURLObject::FSysStyle)(INetURLObject::FSYS_DETECT & ~INetURLObject::FSYS_VOS), &aDelimiter );
466 
467                         if ( bIsFolder )
468                             aObj.setFinalSlash();
469 
470                         // get the last name of the URL
471                         String aMatch = aObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
472                         String aInput( aText );
473                         if ( nMatchLen )
474                         {
475                             if ((aText.Len() && aText.GetChar(aText.Len() - 1) == '.') || bPureHomePath)
476                             {
477                                 // if a "special folder" URL was typed, don't touch the user input
478                                 aMatch.Erase( 0, nMatchLen );
479                             }
480                             else
481                             {
482                                 // make the user input case preserving
483                                 DBG_ASSERT( aInput.Len() >= nMatchLen, "Suspicious Matching!" );
484                                 aInput.Erase( aInput.Len() - nMatchLen );
485                             }
486                         }
487 
488                         aInput += aMatch;
489 
490                         // folders should get a final slash automatically
491                         if ( bIsFolder )
492                             aInput += aDelimiter;
493 
494                         Insert( aInput, aObj.GetMainURL( INetURLObject::NO_DECODE ), sal_True );
495                     }
496                 }
497             }
498             catch( ::com::sun::star::uno::Exception& )
499             {
500             }
501         }
502     }
503     catch( ::com::sun::star::uno::Exception& )
504     {
505     }
506 }
507 
508 //-------------------------------------------------------------------------
ParseSmart(String aText,String aBaseURL,String aWorkDir)509 String SvtURLBox::ParseSmart( String aText, String aBaseURL, String aWorkDir )
510 {
511     String aMatch;
512 
513     // parse ~ for Unix systems
514     // does nothing for Windows
515     if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) )
516         return String();
517 
518     INetURLObject aURLObject;
519     if( aBaseURL.Len() )
520     {
521         INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
522 
523         // if a base URL is set the string may be parsed relative
524         if( aText.Search( '/' ) == 0 )
525         {
526             // text starting with slashes means absolute file URLs
527             String aTemp = INetURLObject::GetScheme( eBaseProt );
528 
529             // file URL must be correctly encoded!
530             String aTextURL = INetURLObject::encode( aText, INetURLObject::PART_FPATH,
531                                                      '%', INetURLObject::ENCODE_ALL );
532             aTemp += aTextURL;
533 
534             INetURLObject aTmp( aTemp );
535             if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID )
536                 aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE );
537         }
538         else
539         {
540             String aSmart( aText );
541             INetURLObject aObj( aBaseURL );
542 
543             // HRO: I suppose this hack should only be done for Windows !!!???
544 #ifdef WNT
545             // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path
546             //      but in case of "\\\\" INetURLObject is right - this is an absolute path !
547 
548             if( aText.Search( '\\' ) == 0 && (aText.Len() < 2 || aText.GetChar( 1 ) != '\\') )
549             {
550                 // cut to first segment
551                 String aTmp = INetURLObject::GetScheme( eBaseProt );
552                 aTmp += '/';
553                 aTmp += String(aObj.getName( 0, true, INetURLObject::DECODE_WITH_CHARSET ));
554                 aObj.SetURL( aTmp );
555 
556                 aSmart.Erase(0,1);
557             }
558 #endif
559             // base URL must be a directory !
560             aObj.setFinalSlash();
561 
562             // take base URL and append current input
563             bool bWasAbsolute = sal_False;
564 #ifdef UNX
565             // don't support FSYS_MAC under Unix, because here ':' is a valid character for a filename
566             INetURLObject::FSysStyle eStyle = static_cast< INetURLObject::FSysStyle >( INetURLObject::FSYS_VOS | INetURLObject::FSYS_UNX | INetURLObject::FSYS_DOS );
567             // encode file URL correctly
568             aSmart = INetURLObject::encode( aSmart, INetURLObject::PART_FPATH, '%', INetURLObject::ENCODE_ALL );
569             INetURLObject aTmp( aObj.smartRel2Abs(
570                 aSmart, bWasAbsolute, false, INetURLObject::WAS_ENCODED, RTL_TEXTENCODING_UTF8, false, eStyle ) );
571 #else
572             INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) );
573 #endif
574 
575             if ( aText.GetChar( aText.Len() - 1 ) == '.' )
576                 // INetURLObject appends a final slash for the directories "." and "..", this is a bug!
577                 // Remove it as a workaround
578                 aTmp.removeFinalSlash();
579             if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID )
580                 aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE );
581         }
582     }
583     else
584     {
585         ::utl::LocalFileHelper::ConvertSystemPathToURL( aText, aWorkDir, aMatch );
586     }
587 
588     return aMatch;
589 }
590 
591 //-------------------------------------------------------------------------
run()592 void SvtMatchContext_Impl::run()
593 {
594     ::vos::OGuard aGuard( GetMutex() );
595     if( bStop )
596         // have we been stopped while we were waiting for the mutex?
597         return;
598 
599     // Reset match lists
600     pCompletions->Remove( 0, pCompletions->Count() );
601     pURLs->Remove( 0, pURLs->Count() );
602 
603     // check for input
604     sal_uInt16 nTextLen = aText.Len();
605     if ( !nTextLen )
606         return;
607 
608     if( aText.Search( '*' ) != STRING_NOTFOUND || aText.Search( '?' ) != STRING_NOTFOUND )
609         // no autocompletion for wildcards
610         return;
611 
612     String aMatch;
613     String aWorkDir( SvtPathOptions().GetWorkPath() );
614     INetProtocol eProt = INetURLObject::CompareProtocolScheme( aText );
615     INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
616     if ( !aBaseURL.Len() )
617         eBaseProt = INetURLObject::CompareProtocolScheme( aWorkDir );
618     INetProtocol eSmartProt = pBox->GetSmartProtocol();
619 
620     // if the user input is a valid URL, go on with it
621     // otherwise it could be parsed smart with a predefined smart protocol
622     // ( or if this is not set with the protocol of a predefined base URL )
623     if( eProt == INET_PROT_NOT_VALID || eProt == eSmartProt || (eSmartProt == INET_PROT_NOT_VALID && eProt == eBaseProt) )
624     {
625         // not stopped yet ?
626         if( schedule() )
627         {
628             if ( eProt == INET_PROT_NOT_VALID )
629                 aMatch = SvtURLBox::ParseSmart( aText, aBaseURL, aWorkDir );
630             else
631                 aMatch = aText;
632             if ( aMatch.Len() )
633             {
634                 INetURLObject aURLObject( aMatch );
635                 String aMainURL( aURLObject.GetMainURL( INetURLObject::NO_DECODE ) );
636                 if ( aMainURL.Len() )
637                 {
638                     // if text input is a directory, it must be part of the match list! Until then it is scanned
639                     if ( UCBContentHelper::IsFolder( aMainURL ) && aURLObject.hasFinalSlash() )
640                             Insert( aText, aMatch );
641                     else
642                         // otherwise the parent folder will be taken
643                         aURLObject.removeSegment();
644 
645                     // scan directory and insert all matches
646                     ReadFolder( aURLObject.GetMainURL( INetURLObject::NO_DECODE ), aMatch, eProt == INET_PROT_NOT_VALID );
647                 }
648             }
649         }
650     }
651 
652     if ( bOnlyDirectories )
653         // don't scan history picklist if only directories are allowed, picklist contains only files
654         return;
655 
656     sal_Bool bFull = sal_False;
657     int nCount = aPickList.Count();
658 
659     INetURLObject aCurObj;
660     String aEmpty, aCurString, aCurMainURL;
661     INetURLObject aObj;
662     aObj.SetSmartProtocol( eSmartProt == INET_PROT_NOT_VALID ? INET_PROT_HTTP : eSmartProt );
663     for( ;; )
664     {
665         for( sal_uInt16 nPos = 0; schedule() && nPos < nCount; nPos++ )
666         {
667             aCurObj.SetURL( *aPickList.GetObject( nPos ) );
668             aCurObj.SetSmartURL( aCurObj.GetURLNoPass());
669             aCurMainURL = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
670 
671             if( eProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eProt )
672                 continue;
673 
674             if( eSmartProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eSmartProt )
675                 continue;
676 
677             switch( aCurObj.GetProtocol() )
678             {
679                 case INET_PROT_HTTP:
680                 case INET_PROT_HTTPS:
681                 case INET_PROT_FTP:
682                 {
683                     if( eProt == INET_PROT_NOT_VALID && !bFull )
684                     {
685                         aObj.SetSmartURL( aText );
686                         if( aObj.GetURLPath().getLength() > 1 )
687                             continue;
688                     }
689 
690                     aCurString = aCurMainURL;
691                     if( eProt == INET_PROT_NOT_VALID )
692                     {
693                         // try if text matches the scheme
694                         String aScheme( INetURLObject::GetScheme( aCurObj.GetProtocol() ) );
695                         if ( aText.CompareIgnoreCaseToAscii( aScheme, aText.Len() ) == COMPARE_EQUAL && aText.Len() < aScheme.Len() )
696                         {
697                             if( bFull )
698                                 aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
699                             else
700                             {
701                                 aCurObj.SetMark( aEmpty );
702                                 aCurObj.SetParam( aEmpty );
703                                 aCurObj.SetURLPath( aEmpty );
704                                 aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
705                             }
706 
707                             Insert( aMatch, aMatch );
708                         }
709 
710                         // now try smart matching
711                         aCurString.Erase( 0, aScheme.Len() );
712                     }
713 
714                     if( aText.CompareIgnoreCaseToAscii( aCurString, aText.Len() )== COMPARE_EQUAL )
715                     {
716                         if( bFull )
717                             aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
718                         else
719                         {
720                             aCurObj.SetMark( aEmpty );
721                             aCurObj.SetParam( aEmpty );
722                             aCurObj.SetURLPath( aEmpty );
723                             aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
724                         }
725 
726                         String aURL( aMatch );
727                         if( eProt == INET_PROT_NOT_VALID )
728                             aMatch.Erase( 0, sal::static_int_cast< xub_StrLen >(INetURLObject::GetScheme( aCurObj.GetProtocol() ).getLength()) );
729 
730                         if( aText.Len() < aMatch.Len() )
731                             Insert( aMatch, aURL );
732 
733                         continue;
734                     }
735                     break;
736                 }
737                 default:
738                 {
739                     if( bFull )
740                         continue;
741 
742                     if( aText.CompareTo( aCurMainURL, aText.Len() ) == COMPARE_EQUAL )
743                     {
744                         if( aText.Len() < aCurMainURL.Len() )
745                             Insert( aCurMainURL, aCurMainURL );
746 
747                         continue;
748                     }
749                     break;
750                 }
751             }
752         }
753 
754         if( !bFull )
755             bFull = sal_True;
756         else
757             break;
758     }
759 
760     return;
761 }
762 
763 //-------------------------------------------------------------------------
764 //-------------------------------------------------------------------------
765 //-------------------------------------------------------------------------
TryAutoComplete(sal_Bool bForce)766 void SvtURLBox::TryAutoComplete( sal_Bool bForce )
767 {
768     if( Application::AnyInput( INPUT_KEYBOARD ) ) return;
769 
770     String aMatchString;
771     String aCurText = GetText();
772     Selection aSelection( GetSelection() );
773     if( aSelection.Max() != aCurText.Len() && !bForce )
774         return;
775     sal_uInt16 nLen = (sal_uInt16)aSelection.Min();
776     aCurText.Erase( nLen );
777     if( aCurText.Len() && bIsAutoCompleteEnabled )
778     {
779         if ( pCtx )
780         {
781             pCtx->Stop();
782             pCtx = NULL;
783         }
784         pCtx = new SvtMatchContext_Impl( this, aCurText );
785     }
786 }
787 
788 //-------------------------------------------------------------------------
SvtURLBox(Window * pParent,INetProtocol eSmart)789 SvtURLBox::SvtURLBox( Window* pParent, INetProtocol eSmart )
790     :   ComboBox( pParent , WB_DROPDOWN | WB_AUTOSIZE | WB_AUTOHSCROLL ),
791         pCtx( 0 ),
792         eSmartProtocol( eSmart ),
793         bAutoCompleteMode( sal_False ),
794         bOnlyDirectories( sal_False ),
795         bTryAutoComplete( sal_False ),
796         bCtrlClick( sal_False ),
797         bHistoryDisabled( sal_False ),
798         bNoSelection( sal_False ),
799         bIsAutoCompleteEnabled( sal_True )
800 {
801     ImplInit();
802 
803     if ( GetDesktopRectPixel().GetWidth() > 800 )
804         SetSizePixel( Size( 300, 240 ) );
805     else
806         SetSizePixel( Size( 225, 240 ) );
807 }
808 
809 //-------------------------------------------------------------------------
SvtURLBox(Window * pParent,WinBits _nStyle,INetProtocol eSmart)810 SvtURLBox::SvtURLBox( Window* pParent, WinBits _nStyle, INetProtocol eSmart )
811     :   ComboBox( pParent, _nStyle ),
812         pCtx( 0 ),
813         eSmartProtocol( eSmart ),
814         bAutoCompleteMode( sal_False ),
815         bOnlyDirectories( sal_False ),
816         bTryAutoComplete( sal_False ),
817         bCtrlClick( sal_False ),
818         bHistoryDisabled( sal_False ),
819         bNoSelection( sal_False ),
820         bIsAutoCompleteEnabled( sal_True )
821 {
822     ImplInit();
823 }
824 
825 //-------------------------------------------------------------------------
SvtURLBox(Window * pParent,const ResId & _rResId,INetProtocol eSmart)826 SvtURLBox::SvtURLBox( Window* pParent, const ResId& _rResId, INetProtocol eSmart )
827     :   ComboBox( pParent , _rResId ),
828         pCtx( 0 ),
829         eSmartProtocol( eSmart ),
830         bAutoCompleteMode( sal_False ),
831         bOnlyDirectories( sal_False ),
832         bTryAutoComplete( sal_False ),
833         bCtrlClick( sal_False ),
834         bHistoryDisabled( sal_False ),
835         bNoSelection( sal_False ),
836         bIsAutoCompleteEnabled( sal_True )
837 {
838     ImplInit();
839 }
840 
841 //-------------------------------------------------------------------------
ImplInit()842 void SvtURLBox::ImplInit()
843 {
844     pImp = new SvtURLBox_Impl();
845 
846     if ( GetHelpId().getLength() == 0 )
847         SetHelpId( ".uno:OpenURL" );
848     EnableAutocomplete( sal_False );
849 
850     SetText( String() );
851 
852     GetSubEdit()->SetAutocompleteHdl( LINK( this, SvtURLBox, AutoCompleteHdl_Impl ) );
853     UpdatePicklistForSmartProtocol_Impl();
854 }
855 
856 //-------------------------------------------------------------------------
~SvtURLBox()857 SvtURLBox::~SvtURLBox()
858 {
859     if( pCtx )
860     {
861         pCtx->Stop();
862         pCtx = NULL;
863     }
864 
865     delete pImp->pURLs;
866     delete pImp->pCompletions;
867     delete pImp;
868 }
869 
870 //-------------------------------------------------------------------------
UpdatePickList()871 void SvtURLBox::UpdatePickList( )
872 {
873     if( pCtx )
874     {
875         pCtx->Stop();
876         pCtx = NULL;
877     }
878 
879     String sText = GetText();
880     if ( sText.Len() && bIsAutoCompleteEnabled )
881         pCtx = new SvtMatchContext_Impl( this, sText );
882 }
883 
884 //-------------------------------------------------------------------------
SetSmartProtocol(INetProtocol eProt)885 void SvtURLBox::SetSmartProtocol( INetProtocol eProt )
886 {
887     if ( eSmartProtocol != eProt )
888     {
889         eSmartProtocol = eProt;
890         UpdatePicklistForSmartProtocol_Impl();
891     }
892 }
893 
894 //-------------------------------------------------------------------------
UpdatePicklistForSmartProtocol_Impl()895 void SvtURLBox::UpdatePicklistForSmartProtocol_Impl()
896 {
897     Clear();
898     if ( !bHistoryDisabled )
899     {
900         // read history pick list
901         Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( eHISTORY );
902         sal_uInt32 nCount = seqPicklist.getLength();
903         INetURLObject aCurObj;
904 
905         for( sal_uInt32 nItem=0; nItem < nCount; nItem++ )
906         {
907             Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
908 
909             OUString sURL;
910 
911             sal_uInt32 nPropertyCount = seqPropertySet.getLength();
912 
913             for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ )
914             {
915                 if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
916                 {
917                     seqPropertySet[nProperty].Value >>= sURL;
918                     aCurObj.SetURL( sURL );
919 
920                     if ( sURL.getLength() && ( eSmartProtocol != INET_PROT_NOT_VALID ) )
921                     {
922                         if( aCurObj.GetProtocol() != eSmartProtocol )
923                             break;
924                     }
925 
926                     String aURL( aCurObj.GetMainURL( INetURLObject::DECODE_WITH_CHARSET ) );
927 
928                     if ( aURL.Len() && ( !pImp->pUrlFilter || pImp->pUrlFilter->isUrlAllowed( aURL ) ) )
929                     {
930                         sal_Bool bFound = (aURL.GetChar(aURL.Len()-1) == '/' );
931                         if ( !bFound )
932                         {
933                             String aUpperURL( aURL );
934                             aUpperURL.ToUpperAscii();
935 
936                             bFound
937                                 = (::std::find_if(
938                                     pImp->m_aFilters.begin(),
939                                     pImp->m_aFilters.end(),
940                                     FilterMatch( aUpperURL ) )
941                                         != pImp->m_aFilters.end());
942                         }
943                         if ( bFound )
944                         {
945                             String aFile;
946                             if (::utl::LocalFileHelper::ConvertURLToSystemPath(aURL,aFile))
947                                 InsertEntry(aFile);
948                             else
949                                 InsertEntry(aURL);
950                         }
951                     }
952                     break;
953                 }
954             }
955         }
956     }
957 }
958 
959 //-------------------------------------------------------------------------
ProcessKey(const KeyCode & rKey)960 sal_Bool SvtURLBox::ProcessKey( const KeyCode& rKey )
961 {
962     // every key input stops the current matching thread
963     if( pCtx )
964     {
965         pCtx->Stop();
966         pCtx = NULL;
967     }
968 
969     KeyCode aCode( rKey.GetCode() );
970     if ( aCode == KEY_RETURN && GetText().Len() )
971     {
972         // wait for completion of matching thread
973         ::vos::OGuard aGuard( SvtMatchContext_Impl::GetMutex() );
974 
975         if ( bAutoCompleteMode )
976         {
977             // reset picklist
978             bAutoCompleteMode = sal_False;
979             Selection aSelection( GetSelection() );
980             SetSelection( Selection( aSelection.Min(), aSelection.Min() ) );
981             if ( bOnlyDirectories )
982                 Clear();
983             else
984                 UpdatePicklistForSmartProtocol_Impl();
985             Resize();
986         }
987 
988         bCtrlClick = rKey.IsMod1();
989         sal_Bool bHandled = sal_False;
990         if ( GetOpenHdl().IsSet() )
991         {
992             bHandled = sal_True;
993             GetOpenHdl().Call(this);
994         }
995         else if ( GetSelectHdl().IsSet() )
996         {
997             bHandled = sal_True;
998             GetSelectHdl().Call(this);
999         }
1000 
1001         bCtrlClick = sal_False;
1002 
1003         ClearModifyFlag();
1004         return bHandled;
1005     }
1006     else if ( aCode == KEY_RETURN && !GetText().Len() && GetOpenHdl().IsSet() )
1007     {
1008         // for file dialog
1009         bAutoCompleteMode = sal_False;
1010         GetOpenHdl().Call(this);
1011         return sal_True;
1012     }
1013     else if( aCode == KEY_ESCAPE )
1014     {
1015         Selection aSelection( GetSelection() );
1016         if ( bAutoCompleteMode || aSelection.Min() != aSelection.Max() )
1017         {
1018             SetSelection( Selection( aSelection.Min(), aSelection.Min() ) );
1019             if ( bOnlyDirectories )
1020                 Clear();
1021             else
1022                 UpdatePicklistForSmartProtocol_Impl();
1023             Resize();
1024         }
1025         else
1026         {
1027            return sal_False;
1028         }
1029 
1030         bAutoCompleteMode = sal_False;
1031         return sal_True;
1032     }
1033     else
1034     {
1035         return sal_False;
1036     }
1037 }
1038 
1039 //-------------------------------------------------------------------------
Modify()1040 void SvtURLBox::Modify()
1041 {
1042     ComboBox::Modify();
1043 }
1044 
1045 //-------------------------------------------------------------------------
PreNotify(NotifyEvent & rNEvt)1046 long SvtURLBox::PreNotify( NotifyEvent& rNEvt )
1047 {
1048     if( rNEvt.GetWindow() == GetSubEdit() && rNEvt.GetType() == EVENT_KEYINPUT )
1049     {
1050 
1051         const KeyEvent& rEvent = *rNEvt.GetKeyEvent();
1052         const KeyCode& rKey = rEvent.GetKeyCode();
1053         KeyCode aCode( rKey.GetCode() );
1054         if( ProcessKey( rKey ) )
1055         {
1056             return sal_True;
1057         }
1058         else if( ( aCode == KEY_UP || aCode == KEY_DOWN ) && !rKey.IsMod2() )
1059         {
1060             Selection aSelection( GetSelection() );
1061             sal_uInt16 nLen = (sal_uInt16)aSelection.Min();
1062             GetSubEdit()->KeyInput( rEvent );
1063             SetSelection( Selection( nLen, GetText().Len() ) );
1064             return sal_True;
1065         }
1066 
1067         if ( MatchesPlaceHolder( GetText() ) )
1068         {
1069             // set the selection so a key stroke will overwrite
1070             // the placeholder rather than edit it
1071             SetSelection( Selection( 0, GetText().Len() ) );
1072         }
1073     }
1074 
1075     return ComboBox::PreNotify( rNEvt );
1076 }
1077 
1078 //-------------------------------------------------------------------------
IMPL_LINK(SvtURLBox,AutoCompleteHdl_Impl,void *,EMPTYARG)1079 IMPL_LINK( SvtURLBox, AutoCompleteHdl_Impl, void*, EMPTYARG )
1080 {
1081     if ( GetSubEdit()->GetAutocompleteAction() == AUTOCOMPLETE_KEYINPUT )
1082     {
1083         TryAutoComplete( sal_False );
1084         return 1L;
1085     }
1086 
1087     return 0L;
1088 }
1089 
1090 //-------------------------------------------------------------------------
Notify(NotifyEvent & rEvt)1091 long SvtURLBox::Notify( NotifyEvent &rEvt )
1092 {
1093     if ( EVENT_GETFOCUS == rEvt.GetType() )
1094     {
1095 #ifndef UNX
1096         // pb: don't select automatically on unix #93251#
1097         SetSelection( Selection( 0, GetText().Len() ) );
1098 #endif
1099     }
1100     else if ( EVENT_LOSEFOCUS == rEvt.GetType() )
1101     {
1102         if( !GetText().Len() )
1103             ClearModifyFlag();
1104         if ( pCtx )
1105         {
1106             pCtx->Stop();
1107             pCtx = NULL;
1108         }
1109     }
1110 
1111     return ComboBox::Notify( rEvt );
1112 }
1113 
1114 //-------------------------------------------------------------------------
Select()1115 void SvtURLBox::Select()
1116 {
1117     ComboBox::Select();
1118     ClearModifyFlag();
1119 }
1120 
1121 //-------------------------------------------------------------------------
SetOnlyDirectories(sal_Bool bDir)1122 void SvtURLBox::SetOnlyDirectories( sal_Bool bDir )
1123 {
1124     bOnlyDirectories = bDir;
1125     if ( bOnlyDirectories )
1126         Clear();
1127 }
1128 
1129 //-------------------------------------------------------------------------
SetNoURLSelection(sal_Bool bSet)1130 void SvtURLBox::SetNoURLSelection( sal_Bool bSet )
1131 {
1132     bNoSelection = bSet;
1133 }
1134 
1135 //-------------------------------------------------------------------------
GetURL()1136 String SvtURLBox::GetURL()
1137 {
1138     // wait for end of autocompletion
1139     ::vos::OGuard aGuard( SvtMatchContext_Impl::GetMutex() );
1140 
1141     String aText( GetText() );
1142     if ( MatchesPlaceHolder( aText ) )
1143         return aPlaceHolder;
1144     // try to get the right case preserving URL from the list of URLs
1145     if ( pImp->pCompletions && pImp->pURLs )
1146     {
1147         for( sal_uInt16 nPos=0; nPos<pImp->pCompletions->Count(); nPos++ )
1148         {
1149 #ifdef DBG_UTIL
1150             String aTmp( *(*pImp->pCompletions)[ nPos ] );
1151 #endif
1152             if( *(*pImp->pCompletions)[ nPos ] == aText )
1153                 return *(*pImp->pURLs)[nPos];
1154         }
1155     }
1156 
1157 #ifdef WNT
1158     // erase trailing spaces on Windows since thay are invalid on this OS and
1159     // most of the time they are inserted by accident via copy / paste
1160     aText.EraseTrailingChars();
1161     if ( !aText.Len() )
1162         return aText;
1163     // #i9739# - 2002-12-03 - fs@openoffice.org
1164 #endif
1165 
1166     INetURLObject aObj( aText );
1167     if( aText.Search( '*' ) != STRING_NOTFOUND || aText.Search( '?' ) != STRING_NOTFOUND )
1168     {
1169         // no autocompletion for wildcards
1170         INetURLObject aTempObj;
1171         if ( eSmartProtocol != INET_PROT_NOT_VALID )
1172             aTempObj.SetSmartProtocol( eSmartProtocol );
1173         if ( aTempObj.SetSmartURL( aText ) )
1174             return aTempObj.GetMainURL( INetURLObject::NO_DECODE );
1175         else
1176             return aText;
1177     }
1178 
1179     if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
1180     {
1181         String aName = ParseSmart( aText, aBaseURL, SvtPathOptions().GetWorkPath() );
1182         aObj.SetURL( aName );
1183         ::rtl::OUString aURL( aObj.GetMainURL( INetURLObject::NO_DECODE ) );
1184         if ( !aURL.getLength() )
1185             // aText itself is invalid, and even together with aBaseURL, it could not
1186             // made valid -> no chance
1187             return aText;
1188 
1189         bool bSlash = aObj.hasFinalSlash();
1190         {
1191             static const rtl::OUString aPropName(
1192                 rtl::OUString::createFromAscii("CasePreservingURL"));
1193 
1194             rtl::OUString aFileURL;
1195 
1196             Any aAny =
1197                 UCBContentHelper::GetProperty(aURL,aPropName);
1198             sal_Bool success = (aAny >>= aFileURL);
1199             String aTitle;
1200             if(success)
1201                 aTitle = String(
1202                     INetURLObject(aFileURL).getName(
1203                         INetURLObject::LAST_SEGMENT,
1204                         true,
1205                         INetURLObject::DECODE_WITH_CHARSET ));
1206             else
1207                 success =
1208                     UCBContentHelper::GetTitle(aURL,aTitle);
1209 
1210             if( success &&
1211                 ( aTitle.Len() > 1 ||
1212                   (aTitle.CompareToAscii("/") != 0 &&
1213                   aTitle.CompareToAscii(".") != 0) ) )
1214             {
1215                     aObj.SetName( aTitle );
1216                     if ( bSlash )
1217                         aObj.setFinalSlash();
1218             }
1219         }
1220     }
1221 
1222     return aObj.GetMainURL( INetURLObject::NO_DECODE );
1223 }
1224 
1225 //-------------------------------------------------------------------------
DisableHistory()1226 void SvtURLBox::DisableHistory()
1227 {
1228     bHistoryDisabled = sal_True;
1229     UpdatePicklistForSmartProtocol_Impl();
1230 }
1231 
1232 //-------------------------------------------------------------------------
SetBaseURL(const String & rURL)1233 void SvtURLBox::SetBaseURL( const String& rURL )
1234 {
1235     ::vos::OGuard aGuard( SvtMatchContext_Impl::GetMutex() );
1236 
1237     // Reset match lists
1238     if ( pImp->pCompletions )
1239         pImp->pCompletions->Remove( 0, pImp->pCompletions->Count() );
1240 
1241     if ( pImp->pURLs )
1242         pImp->pURLs->Remove( 0, pImp->pURLs->Count() );
1243 
1244     aBaseURL = rURL;
1245 }
1246 
1247 //-------------------------------------------------------------------------
1248 /** Parse leading ~ for Unix systems,
1249     does nothing for Windows
1250  */
TildeParsing(String & aText,String & aBaseURL)1251 sal_Bool SvtURLBox_Impl::TildeParsing(
1252     String&
1253 #ifdef UNX
1254     aText
1255 #endif
1256     , String&
1257 #ifdef UNX
1258     aBaseURL
1259 #endif
1260 )
1261 {
1262 #ifdef UNX
1263     if( aText.Search( '~' ) == 0 )
1264     {
1265         String aParseTilde;
1266         sal_Bool bTrailingSlash = sal_True; // use trailing slash
1267 
1268         if( aText.Len() == 1 || aText.GetChar( 1 ) == '/' )
1269         {
1270             // covers "~" or "~/..." cases
1271             const char* aHomeLocation = getenv( "HOME" );
1272             if( !aHomeLocation )
1273                 aHomeLocation = "";
1274 
1275             aParseTilde = String::CreateFromAscii( aHomeLocation );
1276 
1277             // in case the whole path is just "~" then there should
1278             // be no trailing slash at the end
1279             if( aText.Len() == 1 )
1280                 bTrailingSlash = sal_False;
1281         }
1282         else
1283         {
1284             // covers "~username" and "~username/..." cases
1285             xub_StrLen nNameEnd = aText.Search( '/' );
1286             String aUserName = aText.Copy( 1, ( nNameEnd != STRING_NOTFOUND ) ? nNameEnd : ( aText.Len() - 1 ) );
1287 
1288             struct passwd* pPasswd = NULL;
1289 #ifdef SOLARIS
1290             Sequence< sal_Int8 > sBuf( 1024 );
1291             struct passwd aTmp;
1292             sal_Int32 nRes = getpwnam_r( OUStringToOString( OUString( aUserName ), RTL_TEXTENCODING_ASCII_US ).getStr(),
1293                                   &aTmp,
1294                                   (char*)sBuf.getArray(),
1295                                   1024,
1296                                   &pPasswd );
1297             if( !nRes && pPasswd )
1298                 aParseTilde = String::CreateFromAscii( pPasswd->pw_dir );
1299             else
1300                 return sal_False; // no such user
1301 #else
1302             pPasswd = getpwnam( OUStringToOString( OUString( aUserName ), RTL_TEXTENCODING_ASCII_US ).getStr() );
1303             if( pPasswd )
1304                 aParseTilde = String::CreateFromAscii( pPasswd->pw_dir );
1305             else
1306                 return sal_False; // no such user
1307 #endif
1308 
1309             // in case the path is "~username" then there should
1310             // be no trailing slash at the end
1311             if( nNameEnd == STRING_NOTFOUND )
1312                 bTrailingSlash = sal_False;
1313         }
1314 
1315         if( !bTrailingSlash )
1316         {
1317             if( !aParseTilde.Len() || aParseTilde.EqualsAscii( "/" ) )
1318             {
1319                 // "/" path should be converted to "/."
1320                 aParseTilde = String::CreateFromAscii( "/." );
1321             }
1322             else
1323             {
1324                 // "blabla/" path should be converted to "blabla"
1325                 aParseTilde.EraseTrailingChars( '/' );
1326             }
1327         }
1328         else
1329         {
1330             if( aParseTilde.GetChar( aParseTilde.Len() - 1 ) != '/' )
1331                 aParseTilde += '/';
1332             if( aText.Len() > 2 )
1333                 aParseTilde += aText.Copy( 2 );
1334         }
1335 
1336         aText = aParseTilde;
1337         aBaseURL = String(); // tilde provide absolute path
1338     }
1339 #endif
1340 
1341     return sal_True;
1342 }
1343 
1344 //-------------------------------------------------------------------------
SetUrlFilter(const IUrlFilter * _pFilter)1345 void SvtURLBox::SetUrlFilter( const IUrlFilter* _pFilter )
1346 {
1347     pImp->pUrlFilter = _pFilter;
1348 }
1349 
1350 //-------------------------------------------------------------------------
GetUrlFilter() const1351 const IUrlFilter* SvtURLBox::GetUrlFilter( ) const
1352 {
1353     return pImp->pUrlFilter;
1354 }
1355 // -----------------------------------------------------------------------------
SetFilter(const String & _sFilter)1356 void SvtURLBox::SetFilter(const String& _sFilter)
1357 {
1358     pImp->m_aFilters.clear();
1359     FilterMatch::createWildCardFilterList(_sFilter,pImp->m_aFilters);
1360 }
1361 
1362