1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 */ 9 10 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 11 #include <com/sun/star/task/InteractionHandler.hpp> 12 #include <com/sun/star/task/PasswordContainer.hpp> 13 #include <com/sun/star/task/XPasswordContainer2.hpp> 14 #include <com/sun/star/ucb/XCommandEnvironment.hpp> 15 #include <com/sun/star/ucb/XContentAccess.hpp> 16 #include <com/sun/star/sdbc/XResultSet.hpp> 17 #include <com/sun/star/sdbc/XRow.hpp> 18 19 #include <comphelper/processfactory.hxx> 20 #include <officecfg/Office/Common.hxx> 21 #include <rtl/uri.hxx> 22 #include <ucbhelper/content.hxx> 23 #include <ucbhelper/commandenvironment.hxx> 24 #include <toolkit/helper/vclunohelper.hxx> 25 26 #include <svtools/PlaceEditDialog.hxx> 27 #include <svtools/ServerDetailsControls.hxx> 28 29 #include <config_oauth2.h> 30 31 using namespace std; 32 using namespace com::sun::star::lang; 33 using namespace com::sun::star::sdbc; 34 using namespace com::sun::star::task; 35 using namespace com::sun::star::ucb; 36 using namespace com::sun::star::uno; 37 38 DetailsContainer::DetailsContainer(PlaceEditDialog* pDialog) 39 : m_pDialog(pDialog) 40 { 41 m_pDialog->m_xEDPort->connect_output(LINK(this, DetailsContainer, FormatPortHdl)); 42 } 43 44 //format without thousand separator 45 IMPL_STATIC_LINK(DetailsContainer, FormatPortHdl, weld::SpinButton&, rSpinButton, void) 46 { 47 rSpinButton.set_text(OUString::number(rSpinButton.get_value())); 48 } 49 50 DetailsContainer::~DetailsContainer( ) 51 { 52 } 53 54 void DetailsContainer::set_visible( bool ) 55 { 56 m_pDialog->m_xDetailsGrid->set_sensitive(true); 57 58 m_pDialog->m_xEDHost->connect_changed( LINK( this, DetailsContainer, ValueChangeHdl ) ); 59 m_pDialog->m_xEDPort->connect_changed( LINK( this, DetailsContainer, ValueChangeHdl ) ); 60 m_pDialog->m_xEDRoot->connect_changed( LINK( this, DetailsContainer, ValueChangeHdl ) ); 61 } 62 63 INetURLObject DetailsContainer::getUrl( ) 64 { 65 // Don't use that class directly: make it smarter by subclassing it. 66 return INetURLObject( ); 67 } 68 69 bool DetailsContainer::setUrl( const INetURLObject& ) 70 { 71 // That class doesn't contain any logic... it defers the dirty work 72 // to the sub classes. 73 return false; 74 } 75 76 void DetailsContainer::notifyChange( ) 77 { 78 m_aChangeHdl.Call( this ); 79 } 80 81 IMPL_LINK_NOARG( DetailsContainer, ValueChangeHdl, weld::Entry&, void ) 82 { 83 notifyChange( ); 84 } 85 86 HostDetailsContainer::HostDetailsContainer(PlaceEditDialog* pDialog, sal_uInt16 nPort, const OUString& sScheme) : 87 DetailsContainer( pDialog ), 88 m_nDefaultPort( nPort ), 89 m_sScheme( sScheme ) 90 { 91 set_visible( false ); 92 } 93 94 void HostDetailsContainer::set_visible( bool bShow ) 95 { 96 m_pDialog->m_xFTHost->set_visible( bShow ); 97 m_pDialog->m_xHostBox->set_visible( bShow ); 98 m_pDialog->m_xEDRoot->set_visible( bShow ); 99 m_pDialog->m_xFTRoot->set_visible( bShow ); 100 101 DetailsContainer::set_visible( bShow ); 102 103 if ( bShow ) 104 { 105 if (m_pDialog->m_xEDPort->get_value() == 0) 106 m_pDialog->m_xEDPort->set_value( m_nDefaultPort ); 107 m_pDialog->m_xEDHost->set_text( m_sHost ); 108 } 109 else 110 m_pDialog->m_xEDPort->set_value( 0 ); 111 } 112 113 INetURLObject HostDetailsContainer::getUrl( ) 114 { 115 OUString sHost = m_pDialog->m_xEDHost->get_text().trim(); 116 sal_Int64 nPort = m_pDialog->m_xEDPort->get_value(); 117 OUString sPath = m_pDialog->m_xEDRoot->get_text().trim(); 118 119 OUString sUrl; 120 if ( !sHost.isEmpty( ) ) 121 { 122 sUrl = m_sScheme + "://" + sHost; 123 if ( nPort != m_nDefaultPort ) 124 sUrl += ":" + OUString::number( nPort ); 125 if ( !sPath.isEmpty( ) ) 126 if ( sPath.indexOf( '/' ) != 0 ) 127 sUrl += "/"; 128 sUrl += sPath; 129 } 130 131 return INetURLObject( sUrl ); 132 } 133 134 bool HostDetailsContainer::setUrl( const INetURLObject& rUrl ) 135 { 136 bool bSuccess = verifyScheme( INetURLObject::GetScheme( rUrl.GetProtocol( ) ) ); 137 138 if ( bSuccess ) 139 { 140 m_sHost = rUrl.GetHost( ); 141 m_pDialog->m_xEDHost->set_text( rUrl.GetHost( ) ); 142 m_pDialog->m_xEDPort->set_value( rUrl.GetPort( ) ); 143 m_pDialog->m_xEDRoot->set_text( rUrl.GetURLPath() ); 144 } 145 146 return bSuccess; 147 } 148 149 bool HostDetailsContainer::verifyScheme( const OUString& sScheme ) 150 { 151 return sScheme == ( m_sScheme + "://" ); 152 } 153 154 DavDetailsContainer::DavDetailsContainer(PlaceEditDialog* pBuilder) 155 : HostDetailsContainer(pBuilder, 80, "http") 156 { 157 m_pDialog->m_xCBDavs->connect_toggled(LINK(this, DavDetailsContainer, ToggledDavsHdl)); 158 159 set_visible( false ); 160 } 161 162 void DavDetailsContainer::set_visible( bool bShow ) 163 { 164 HostDetailsContainer::set_visible( bShow ); 165 166 if ( !bShow ) 167 m_pDialog->m_xCBDavs->set_active(false); 168 169 m_pDialog->m_xCBDavs->set_visible(bShow); 170 } 171 172 bool DavDetailsContainer::verifyScheme( const OUString& rScheme ) 173 { 174 bool bValid = false; 175 if ( rScheme == "http://" ) 176 { 177 bValid = true; 178 m_pDialog->m_xCBDavs->set_active(false); 179 } 180 else if ( rScheme == "https://" ) 181 { 182 bValid = true; 183 m_pDialog->m_xCBDavs->set_active(true); 184 } 185 return bValid; 186 } 187 188 IMPL_LINK( DavDetailsContainer, ToggledDavsHdl, weld::ToggleButton&, rCheckBox, void ) 189 { 190 // Change default port if needed 191 bool bCheckedDavs = rCheckBox.get_active(); 192 if ( m_pDialog->m_xEDPort->get_value() == 80 && bCheckedDavs ) 193 m_pDialog->m_xEDPort->set_value( 443 ); 194 else if ( m_pDialog->m_xEDPort->get_value() == 443 && !bCheckedDavs ) 195 m_pDialog->m_xEDPort->set_value( 80 ); 196 197 OUString sScheme( "http" ); 198 if ( bCheckedDavs ) 199 sScheme = "https"; 200 setScheme( sScheme ); 201 202 notifyChange( ); 203 } 204 205 SmbDetailsContainer::SmbDetailsContainer(PlaceEditDialog* pDialog) 206 : DetailsContainer(pDialog) 207 { 208 m_pDialog->m_xEDShare->connect_changed( LINK( this, DetailsContainer, ValueChangeHdl ) ); 209 210 set_visible( false ); 211 } 212 213 INetURLObject SmbDetailsContainer::getUrl( ) 214 { 215 OUString sHost = m_pDialog->m_xEDHost->get_text().trim( ); 216 OUString sShare = m_pDialog->m_xEDShare->get_text().trim( ); 217 OUString sPath = m_pDialog->m_xEDRoot->get_text().trim( ); 218 219 OUString sUrl; 220 if ( !sHost.isEmpty( ) ) 221 { 222 sUrl = "smb://" + sHost + "/"; 223 if ( !sShare.isEmpty( ) ) 224 sUrl += sShare; 225 if ( !sPath.isEmpty( ) ) 226 if ( sPath.indexOf( '/' ) != 0 ) 227 sUrl += "/"; 228 sUrl += sPath; 229 } 230 231 return INetURLObject( sUrl ); 232 } 233 234 bool SmbDetailsContainer::setUrl( const INetURLObject& rUrl ) 235 { 236 bool bSuccess = rUrl.GetProtocol() == INetProtocol::Smb; 237 238 if ( bSuccess ) 239 { 240 OUString sShare = rUrl.getName( 0 ); 241 OUString sFullPath = rUrl.GetURLPath( ); 242 OUString sPath; 243 if ( sFullPath.getLength( ) > sShare.getLength( ) ) 244 { 245 sal_Int32 nPos = sShare.getLength( ); 246 if ( nPos != 0 ) 247 ++nPos; 248 sPath = sFullPath.copy( nPos ); 249 } 250 251 m_sHost = rUrl.GetHost( ); 252 m_pDialog->m_xEDHost->set_text( m_sHost ); 253 m_pDialog->m_xEDShare->set_text( sShare ); 254 m_pDialog->m_xEDRoot->set_text( sPath ); 255 } 256 257 return bSuccess; 258 } 259 260 void SmbDetailsContainer::set_visible( bool bShow ) 261 { 262 m_pDialog->m_xEDShare->set_visible( bShow ); 263 m_pDialog->m_xFTShare->set_visible( bShow ); 264 m_pDialog->m_xEDRoot->set_visible( bShow ); 265 m_pDialog->m_xFTRoot->set_visible( bShow ); 266 267 m_pDialog->m_xFTHost->set_visible( bShow ); 268 m_pDialog->m_xHostBox->set_visible( bShow ); 269 m_pDialog->m_xEDPort->set_sensitive( !bShow ); 270 m_pDialog->m_xFTPort->set_sensitive( !bShow ); 271 272 if ( bShow ) 273 m_pDialog->m_xEDHost->set_text( m_sHost ); 274 } 275 276 CmisDetailsContainer::CmisDetailsContainer(PlaceEditDialog* pParentDialog, OUString const & sBinding) : 277 DetailsContainer( pParentDialog ), 278 m_sUsername( ), 279 m_xCmdEnv( ), 280 m_aRepoIds( ), 281 m_sRepoId( ), 282 m_sBinding( sBinding ), 283 m_xParentDialog(pParentDialog->getDialog()->GetXWindow()) 284 { 285 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 286 Reference< XInteractionHandler > xGlobalInteractionHandler( 287 InteractionHandler::createWithParent(xContext, m_xParentDialog), UNO_QUERY); 288 m_xCmdEnv = new ucbhelper::CommandEnvironment( xGlobalInteractionHandler, Reference< XProgressHandler >() ); 289 290 set_visible( false ); 291 } 292 293 void CmisDetailsContainer::set_visible( bool bShow ) 294 { 295 m_pDialog->m_xLBRepository->connect_changed( LINK( this, CmisDetailsContainer, SelectRepoHdl ) ); 296 m_pDialog->m_xBTRepoRefresh->connect_clicked( LINK( this, CmisDetailsContainer, RefreshReposHdl ) ); 297 298 m_pDialog->m_xEDHost->set_text( m_sBinding ); 299 300 if( ( m_sBinding == GDRIVE_BASE_URL ) 301 || m_sBinding.startsWith( ALFRESCO_CLOUD_BASE_URL ) 302 || ( m_sBinding == ONEDRIVE_BASE_URL ) ) 303 { 304 m_pDialog->m_xFTHost->hide(); 305 m_pDialog->m_xHostBox->hide(); 306 m_pDialog->m_xFTRepository->hide(); 307 m_pDialog->m_xRepositoryBox->hide(); 308 m_pDialog->m_xEDRoot->hide(); 309 m_pDialog->m_xFTRoot->hide(); 310 } 311 else 312 { 313 m_pDialog->m_xFTHost->set_visible( bShow ); 314 m_pDialog->m_xHostBox->set_visible( bShow ); 315 m_pDialog->m_xFTRepository->set_visible( bShow ); 316 m_pDialog->m_xRepositoryBox->set_visible( bShow ); 317 m_pDialog->m_xEDRoot->set_visible( bShow ); 318 m_pDialog->m_xFTRoot->set_visible( bShow ); 319 } 320 321 DetailsContainer::set_visible( bShow ); 322 m_pDialog->m_xEDPort->set_sensitive( !bShow ); 323 m_pDialog->m_xFTPort->set_sensitive( !bShow ); 324 } 325 326 INetURLObject CmisDetailsContainer::getUrl( ) 327 { 328 OUString sBindingUrl = m_pDialog->m_xEDHost->get_text().trim(); 329 OUString sPath = m_pDialog->m_xEDRoot->get_text().trim(); 330 331 bool bSkip = true; 332 if( ( m_sBinding == GDRIVE_BASE_URL ) 333 || m_sBinding.startsWith( ALFRESCO_CLOUD_BASE_URL ) 334 || ( m_sBinding == ONEDRIVE_BASE_URL ) ) 335 { 336 bSkip = m_sUsername.isEmpty(); 337 } 338 else 339 { 340 bSkip = m_sRepoId.isEmpty(); 341 } 342 343 OUString sUrl; 344 if ( !sBindingUrl.isEmpty( ) && !bSkip ) 345 { 346 OUString sEncodedBinding = rtl::Uri::encode( 347 sBindingUrl + "#" + m_sRepoId, 348 rtl_UriCharClassRelSegment, 349 rtl_UriEncodeKeepEscapes, 350 RTL_TEXTENCODING_UTF8 ); 351 sUrl = "vnd.libreoffice.cmis://" + sEncodedBinding; 352 } 353 sUrl += sPath; 354 355 return INetURLObject( sUrl ); 356 } 357 358 bool CmisDetailsContainer::setUrl( const INetURLObject& rUrl ) 359 { 360 bool bSuccess = rUrl.GetProtocol() == INetProtocol::Cmis; 361 362 if ( bSuccess ) 363 { 364 OUString sDecodedHost = rUrl.GetHost( INetURLObject::DecodeMechanism::WithCharset ); 365 INetURLObject aHostUrl( sDecodedHost ); 366 m_sBinding = aHostUrl.GetURLNoMark( ); 367 m_sRepoId = aHostUrl.GetMark( ); 368 369 m_pDialog->m_xEDHost->set_text( m_sBinding ); 370 m_pDialog->m_xEDRoot->set_text( rUrl.GetURLPath() ); 371 } 372 return bSuccess; 373 } 374 375 void CmisDetailsContainer::setUsername( const OUString& rUsername ) 376 { 377 m_sUsername = rUsername; 378 } 379 380 void CmisDetailsContainer::setPassword( const OUString& rPass ) 381 { 382 m_sPassword = rPass; 383 } 384 385 void CmisDetailsContainer::selectRepository( ) 386 { 387 // Get the repo ID and call the Change listener 388 const int nPos = m_pDialog->m_xLBRepository->get_active(); 389 if( static_cast<size_t>(nPos) < m_aRepoIds.size() ) 390 { 391 m_sRepoId = m_aRepoIds[nPos]; 392 notifyChange( ); 393 } 394 } 395 396 IMPL_LINK_NOARG( CmisDetailsContainer, RefreshReposHdl, weld::Button&, void ) 397 { 398 Reference< XComponentContext > xContext = ::comphelper::getProcessComponentContext(); 399 Reference< XPasswordContainer2 > xMasterPasswd = PasswordContainer::create( xContext ); 400 401 402 OUString sBindingUrl = m_pDialog->m_xEDHost->get_text().trim( ); 403 404 OUString sEncodedUsername = ""; 405 406 if ( !m_sUsername.isEmpty( ) ) 407 { 408 sEncodedUsername = rtl::Uri::encode(m_sUsername, 409 rtl_UriCharClassUserinfo, 410 rtl_UriEncodeKeepEscapes, 411 RTL_TEXTENCODING_UTF8 ); 412 sEncodedUsername += "@"; 413 } 414 415 // Clean the listbox 416 m_pDialog->m_xLBRepository->clear(); 417 m_aRepoIds.clear(); 418 419 // Compute the URL 420 OUString sUrl; 421 if ( !sBindingUrl.isEmpty( ) ) 422 { 423 OUString sEncodedBinding = rtl::Uri::encode( 424 sBindingUrl, 425 rtl_UriCharClassRelSegment, 426 rtl_UriEncodeKeepEscapes, 427 RTL_TEXTENCODING_UTF8 ); 428 sUrl = "vnd.libreoffice.cmis://" + sEncodedUsername + sEncodedBinding; 429 } 430 431 // temporary remember the password 432 try 433 { 434 if( !sUrl.isEmpty() && !m_sUsername.isEmpty() && !m_sPassword.isEmpty() ) 435 { 436 Reference< XInteractionHandler > xInteractionHandler( 437 InteractionHandler::createWithParent(xContext, m_xParentDialog), 438 UNO_QUERY ); 439 440 Sequence<OUString> aPasswd { m_sPassword }; 441 442 xMasterPasswd->add( 443 sUrl, m_sUsername, aPasswd, xInteractionHandler ); 444 } 445 } 446 catch( const Exception& ) 447 {} 448 449 // Get the Content 450 ::ucbhelper::Content aCnt( sUrl, m_xCmdEnv, comphelper::getProcessComponentContext() ); 451 Sequence<OUString> aProps { "Title" }; 452 453 try 454 { 455 Reference< XResultSet > xResultSet( aCnt.createCursor( aProps ), UNO_QUERY_THROW ); 456 Reference< XContentAccess > xAccess( xResultSet, UNO_QUERY_THROW ); 457 while ( xResultSet->next() ) 458 { 459 OUString sURL = xAccess->queryContentIdentifierString( ); 460 INetURLObject aURL( sURL ); 461 OUString sId = aURL.GetURLPath( INetURLObject::DecodeMechanism::WithCharset ); 462 sId = sId.copy( 1 ); 463 m_aRepoIds.push_back( sId ); 464 465 Reference< XRow > xRow( xResultSet, UNO_QUERY ); 466 OUString sName = xRow->getString( 1 ); 467 m_pDialog->m_xLBRepository->append_text(sName); 468 } 469 } 470 catch ( const Exception& ) 471 { 472 } 473 474 // Auto-select the first one 475 if (m_pDialog->m_xLBRepository->get_count() > 0) 476 { 477 m_pDialog->m_xLBRepository->set_active(0); 478 selectRepository( ); 479 } 480 481 // remove temporary password 482 try 483 { 484 xMasterPasswd->remove( sUrl, m_sUsername ); 485 } 486 catch( const Exception& ) 487 {} 488 } 489 490 IMPL_LINK_NOARG( CmisDetailsContainer, SelectRepoHdl, weld::ComboBox&, void ) 491 { 492 selectRepository( ); 493 } 494 495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 496
