/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2000, 2010 Oracle and/or its affiliates. * * OpenOffice.org - a multi-platform office productivity suite * * This file is part of OpenOffice.org. * * OpenOffice.org is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OpenOffice.org is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OpenOffice.org. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_ucb.hxx" /************************************************************************** TODO ************************************************************************** *************************************************************************/ #include #include "odma_provider.hxx" #include "odma_content.hxx" #include "odma_contentprops.hxx" #include #include #include #include #include using namespace com::sun::star; using namespace odma; //========================================================================= //========================================================================= // // ContentProvider Implementation. // //========================================================================= //========================================================================= ODMHANDLE ContentProvider::m_aOdmHandle = NULL; ContentProvider::ContentProvider( const uno::Reference< lang::XMultiServiceFactory >& rSMgr ) : ::ucbhelper::ContentProviderImplHelper( rSMgr ) { } //========================================================================= // virtual ContentProvider::~ContentProvider() { ContentsMap::iterator aIter = m_aContents.begin(); for (;aIter != m_aContents.end() ;++aIter ) { if(aIter->second->m_bIsOpen) closeDocument(aIter->first); } if(m_aOdmHandle) { NODMUnRegisterApp(m_aOdmHandle); m_aOdmHandle = NULL; } } // ----------------------------------------------------------------------------- inline bool is_current_process_window(HWND hwnd) { DWORD pid; GetWindowThreadProcessId(hwnd, &pid); return (pid == GetCurrentProcessId()); } HWND choose_parent_window() { HWND hwnd_parent = GetForegroundWindow(); if (!is_current_process_window(hwnd_parent)) hwnd_parent = GetDesktopWindow(); return hwnd_parent; } ODMHANDLE ContentProvider::getHandle() { if(!m_aOdmHandle) { ODMSTATUS odm = NODMRegisterApp(&m_aOdmHandle,ODM_API_VERSION,ODMA_ODMA_REGNAME,(DWORD) choose_parent_window( ),NULL); switch(odm) { case ODM_SUCCESS: break; case ODM_E_NODMS: break; case ODM_E_CANTINIT: break; case ODM_E_VERSION: break; default: break; } } return m_aOdmHandle; } // ----------------------------------------------------------------------------- //========================================================================= // // XInterface methods. // //========================================================================= // @@@ Add own interfaces. XINTERFACE_IMPL_3( ContentProvider, lang::XTypeProvider, lang::XServiceInfo, ucb::XContentProvider ); //========================================================================= // // XTypeProvider methods. // //========================================================================= // @@@ Add own interfaces. XTYPEPROVIDER_IMPL_3( ContentProvider, lang::XTypeProvider, lang::XServiceInfo, ucb::XContentProvider ); //========================================================================= // // XServiceInfo methods. // //========================================================================= // @@@ Adjust implementation name. Keep the prefix "com.sun.star.comp."! // @@@ Adjust service name. XSERVICEINFO_IMPL_1( ContentProvider, rtl::OUString::createFromAscii( "com.sun.star.comp.odma.ContentProvider" ), rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_PROVIDER_SERVICE_NAME) ) ); //========================================================================= // // Service factory implementation. // //========================================================================= ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider ); //========================================================================= // // XContentProvider methods. // //========================================================================= // virtual uno::Reference< ucb::XContent > SAL_CALL ContentProvider::queryContent( const uno::Reference< ucb::XContentIdentifier >& Identifier ) throw( ucb::IllegalIdentifierException, uno::RuntimeException ) { // Check URL scheme... if(!getHandle()) throw ucb::IllegalIdentifierException(); rtl::OUString aScheme( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(ODMA_URL_SCHEME) ) ); sal_Int32 nIndex = 0; rtl::OUString sOdma = aScheme.getToken(3,'.',nIndex); rtl::OUString sCanonicURL = Identifier->getContentIdentifier(); // check if url starts with odma if ( !(Identifier->getContentProviderScheme().equalsIgnoreAsciiCase( aScheme ) || Identifier->getContentProviderScheme().equalsIgnoreAsciiCase( sOdma )) ) throw ucb::IllegalIdentifierException(); if(!( sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME_SHORT ODMA_URL_SHORT)) || sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT)))) throw ucb::IllegalIdentifierException(); // @@@ Further id checks may go here... #if 0 if ( id-check-failes ) throw ucb::IllegalIdentifierException(); #endif // @@@ Id normalization may go here... #if 0 // Normalize URL and create new Id. rtl::OUString aCanonicURL = ( Identifier->getContentIdentifier() ); uno::Reference< ucb::XContentIdentifier > xCanonicId = new ::ucb::ContentIdentifier( m_xSMgr, aCanonicURL ); #else uno::Reference< ucb::XContentIdentifier > xCanonicId = Identifier; #endif osl::MutexGuard aGuard( m_aMutex ); // Check, if a content with given id already exists... uno::Reference< ucb::XContent > xContent = queryExistingContent( xCanonicId ).get(); if ( xContent.is() ) return xContent; // @@@ Decision, which content implementation to instanciate may be // made here ( in case you have different content classes ). // Create a new content. sCanonicURL = convertURL(sCanonicURL); ::rtl::Reference aProp; // first check if we got an ODMA ID from outside if( sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_ODMAID))) {// we get an orignal ODMA id so we have to look for the name ::rtl::OString sDocId = ::rtl::OUStringToOString(sCanonicURL,RTL_TEXTENCODING_MS_1252); sal_Char* lpszDocName = new sal_Char[ODM_NAME_MAX]; ODMSTATUS odm = NODMGetDocInfo( getHandle(), const_cast(sDocId.getStr()), ODM_NAME, lpszDocName, ODM_NAME_MAX ); if(odm == ODM_SUCCESS) { aProp = new ContentProperties(); aProp->m_sDocumentName = ::rtl::OStringToOUString(rtl::OString(lpszDocName),RTL_TEXTENCODING_ASCII_US); aProp->m_sDocumentId = sDocId; aProp->m_sContentType = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_TYPE)); append(aProp); } delete [] lpszDocName; } else // we got an already fetched name here so look for it { // we have a valid document name aProp = getContentPropertyWithTitle(sCanonicURL); if(!aProp.is()) aProp = getContentPropertyWithSavedAsName(sCanonicURL); if(!aProp.is()) { if(sCanonicURL.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("/"))) { // found only the scheme aProp = new ContentProperties(); aProp->m_sDocumentId = "/"; aProp->m_sTitle = sCanonicURL; aProp->m_bIsFolder = sal_True; aProp->m_bIsDocument = !aProp->m_bIsFolder; m_aContents.insert(ContentsMap::value_type(aProp->m_sDocumentId,aProp)); } else aProp = queryContentProperty(sCanonicURL); } } if(!aProp.is()) throw ucb::IllegalIdentifierException(); xContent = new Content( m_xSMgr, this, xCanonicId ,aProp); registerNewContent( xContent ); if ( !xContent->getIdentifier().is() ) throw ucb::IllegalIdentifierException(); return xContent; } // ----------------------------------------------------------------------------- void ContentProvider::closeDocument(const ::rtl::OString& _sDocumentId) { ContentsMap::iterator aIter = m_aContents.find(_sDocumentId); if(aIter != m_aContents.end()) { DWORD dwFlags = ODM_SILENT; ODMSTATUS odm = NODMCloseDocEx( ContentProvider::getHandle(), const_cast(_sDocumentId.getStr()), &dwFlags, 0xFFFFFFFF, 0xFFFFFFFF, NULL, 0); OSL_ENSURE(odm == ODM_SUCCESS,"Error while closing a document!"); if(odm == ODM_SUCCESS) aIter->second->m_bIsOpen = sal_False; } } // ----------------------------------------------------------------------------- void ContentProvider::saveDocument(const ::rtl::OString& _sDocumentId) { ContentsMap::iterator aIter = m_aContents.find(_sDocumentId); if(aIter != m_aContents.end()) { sal_Char* lpszDocId = new sal_Char[ODM_DOCID_MAX]; DWORD dwFlags = ODM_SILENT; ODMSTATUS odm = NODMSaveDocEx(getHandle(), const_cast(_sDocumentId.getStr()), lpszDocId, &dwFlags); OSL_ENSURE(odm == ODM_SUCCESS,"Could not save document!"); if(odm != ODM_SUCCESS) { delete [] lpszDocId; throw uno::Exception(); } aIter->second->m_sDocumentId = rtl::OString(lpszDocId); delete [] lpszDocId; } } // ----------------------------------------------------------------------------- util::Date toDate(const ::rtl::OString& _sSQLString) { sal_uInt16 nYear = 0, nMonth = 0, nDay = 0; nYear = (sal_uInt16)_sSQLString.copy(0,4).toInt32(); nMonth = (sal_uInt16)_sSQLString.copy(4,2).toInt32(); nDay = (sal_uInt16)_sSQLString.copy(6,2).toInt32(); return util::Date(nDay,nMonth,nYear); } //----------------------------------------------------------------------------- util::Time toTime(const ::rtl::OString& _sSQLString) { sal_uInt16 nHour = 0, nMinute = 0, nSecond = 0; nHour = (sal_uInt16)_sSQLString.copy(8,2).toInt32(); nMinute = (sal_uInt16)_sSQLString.copy(10,2).toInt32(); nSecond = (sal_uInt16)_sSQLString.copy(12,2).toInt32(); return util::Time(0,nHour,nMinute,nSecond); } //----------------------------------------------------------------------------- util::DateTime toDateTime(const ::rtl::OString& _sSQLString) { util::Date aDate = toDate(_sSQLString); util::Time aTime = toTime(_sSQLString); return util::DateTime(0,aTime.Seconds,aTime.Minutes,aTime.Hours,aDate.Day,aDate.Month,aDate.Year); } // ----------------------------------------------------------------------------- void ContentProvider::fillDocumentProperties(const ::rtl::Reference& _rProp) { // read some properties from the DMS sal_Char* lpszDocInfo = new sal_Char[ODM_DOCID_MAX]; sal_Char* pDocId = const_cast(_rProp->m_sDocumentId.getStr()); // read the create date of the document ODMSTATUS odm = NODMGetDocInfo( getHandle(), pDocId, ODM_CREATEDDATE, lpszDocInfo, ODM_DOCID_MAX); if(odm == ODM_SUCCESS) _rProp->m_aDateCreated = toDateTime(::rtl::OString(lpszDocInfo)); // read the modified date of the document odm = NODMGetDocInfo( getHandle(), pDocId, ODM_MODIFYDATE, lpszDocInfo, ODM_DOCID_MAX); if(odm == ODM_SUCCESS) _rProp->m_aDateModified = toDateTime(::rtl::OString(lpszDocInfo)); // read the title of the document odm = NODMGetDocInfo( getHandle(), pDocId, ODM_TITLETEXT, lpszDocInfo, ODM_DOCID_MAX); if(odm == ODM_SUCCESS) _rProp->m_sTitle = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US); // read the name of the document odm = NODMGetDocInfo( getHandle(), pDocId, ODM_NAME, lpszDocInfo, ODM_DOCID_MAX); if(odm == ODM_SUCCESS) _rProp->m_sDocumentName = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US); // read the author of the document odm = NODMGetDocInfo( getHandle(), pDocId, ODM_AUTHOR, lpszDocInfo, ODM_DOCID_MAX); if(odm == ODM_SUCCESS) _rProp->m_sAuthor = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US); // read the subject of the document odm = NODMGetDocInfo( getHandle(), pDocId, ODM_SUBJECT, lpszDocInfo, ODM_DOCID_MAX); if(odm == ODM_SUCCESS) _rProp->m_sSubject = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US); // read the keywords of the document odm = NODMGetDocInfo( getHandle(), pDocId, ODM_KEYWORDS, lpszDocInfo, ODM_DOCID_MAX); if(odm == ODM_SUCCESS) _rProp->m_sKeywords = ::rtl::OStringToOUString(rtl::OString(lpszDocInfo),RTL_TEXTENCODING_ASCII_US); /* odm = NODMGetDocInfo( getHandle(), const_cast(_rProp->m_sDocumentId.getStr()), ODM_URL, lpszDocInfo, ODM_DOCID_MAX); */ delete [] lpszDocInfo; } // ----------------------------------------------------------------------------- void ContentProvider::append(const ::rtl::Reference& _rProp) { // now fill some more properties fillDocumentProperties(_rProp); // and append them m_aContents.insert(ContentsMap::value_type(_rProp->m_sDocumentId,_rProp)); } // ----------------------------------------------------------------------------- ::rtl::Reference ContentProvider::queryContentProperty(const ::rtl::OUString& _sDocumentName) { ::rtl::Reference aReturn; sal_Char* lpszDMSList = new sal_Char[ODM_DMSID_MAX]; ODMSTATUS odm = NODMGetDMS(ODMA_ODMA_REGNAME, lpszDMSList); if(odm == ODM_SUCCESS) { sal_Char* pQueryId = new sal_Char[ODM_QUERYID_MAX]; lpszDMSList[strlen(lpszDMSList)+1] = '\0'; ::rtl::OString sTitleText(::rtl::OUStringToOString(_sDocumentName,RTL_TEXTENCODING_ASCII_US)); ::rtl::OString sQuery("SELECT ODM_DOCID_LATEST, ODM_NAME WHERE ODM_TITLETEXT = '"); sQuery += sTitleText; sQuery += "'"; DWORD dwFlags = ODM_SPECIFIC; odm = NODMQueryExecute(getHandle(), sQuery,dwFlags, lpszDMSList, pQueryId ); if(odm == ODM_SUCCESS) { sal_uInt16 nCount = 10; sal_uInt16 nMaxCount = 10; sal_Char* lpszDocId = new sal_Char[ODM_DOCID_MAX * nMaxCount]; sal_Char* lpszDocName = new sal_Char[ODM_NAME_MAX * nMaxCount]; sal_Char* lpszDocInfo = new sal_Char[ODM_DOCID_MAX]; ::rtl::OUString sContentType(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_TYPE)); do { if(nCount >= nMaxCount) { // get the result nCount = nMaxCount; odm = NODMQueryGetResults(getHandle(), pQueryId,lpszDocId, lpszDocName, ODM_NAME_MAX, (WORD*)&nCount); } if(odm == ODM_SUCCESS) for(sal_uInt16 i = 0; i < nCount; ++i) { odm = NODMGetDocInfo( getHandle(), &lpszDocId[ODM_DOCID_MAX*i], ODM_TITLETEXT, lpszDocInfo, ODM_DOCID_MAX); if( odm == ODM_SUCCESS && sTitleText == ::rtl::OString(lpszDocInfo)) { aReturn = new ContentProperties(); aReturn->m_sDocumentName = ::rtl::OStringToOUString(rtl::OString(&lpszDocName[ODM_NAME_MAX*i]),RTL_TEXTENCODING_ASCII_US); aReturn->m_sDocumentId = ::rtl::OString(&lpszDocId[ODM_DOCID_MAX*i]); aReturn->m_sContentType = sContentType; append(aReturn); nCount = 0; // break condition from outer loop break; } } } while(nCount > nMaxCount); delete [] lpszDocInfo; delete [] lpszDocId; delete [] lpszDocName; } // now close the query odm = NODMQueryClose(ContentProvider::getHandle(), pQueryId); delete [] pQueryId; } delete [] lpszDMSList; return aReturn; } // ----------------------------------------------------------------------------- ::rtl::Reference ContentProvider::getContentProperty(const ::rtl::OUString& _sName, const ContentPropertiesMemberFunctor& _aFunctor) const { ::rtl::Reference aReturn; ContentsMap::const_iterator aFind = ::std::find_if( m_aContents.begin(), m_aContents.end(), ::std::compose1( ::std::bind2nd(_aFunctor,_sName), ::std::select2nd() ) ); if(aFind != m_aContents.end()) aReturn = aFind->second; return aReturn; } // ----------------------------------------------------------------------------- ::rtl::Reference ContentProvider::getContentPropertyWithSavedAsName(const ::rtl::OUString& _sSaveAsName) const { ContentPropertiesMemberFunctor aFunc(::std::mem_fun(&ContentProperties::getSavedAsName)); return getContentProperty(_sSaveAsName,aFunc); } // ----------------------------------------------------------------------------- ::rtl::Reference ContentProvider::getContentPropertyWithTitle(const ::rtl::OUString& _sTitle) const { ContentPropertiesMemberFunctor aFunc(::std::mem_fun(&ContentProperties::getTitle)); return getContentProperty(_sTitle,aFunc); } // ----------------------------------------------------------------------------- ::rtl::Reference ContentProvider::getContentPropertyWithDocumentId(const ::rtl::OUString& _sDocumentId) const { ContentPropertiesMemberFunctor aFunc(::std::mem_fun(&ContentProperties::getDocumentId)); return getContentProperty(_sDocumentId,aFunc); } // ----------------------------------------------------------------------------- ::rtl::OUString ContentProvider::openDoc(const ::rtl::Reference& _rProp) throw (uno::Exception) { OSL_ENSURE(_rProp.is(),"No valid content properties!"); if(!_rProp->m_bIsOpen) { sal_Char *pFileName = new sal_Char[ODM_FILENAME_MAX]; DWORD dwFlag = ODM_MODIFYMODE | ODM_SILENT; ODMSTATUS odm = NODMOpenDoc(getHandle(), dwFlag, const_cast(_rProp->m_sDocumentId.getStr()), pFileName); switch(odm) { case ODM_E_INUSE: dwFlag = ODM_VIEWMODE; if( NODMOpenDoc(getHandle(), dwFlag, const_cast(_rProp->m_sDocumentId.getStr()), pFileName) != ODM_SUCCESS) break; // else run through case ODM_SUCCESS: ::osl::FileBase::getFileURLFromSystemPath(::rtl::OStringToOUString(rtl::OString(pFileName),RTL_TEXTENCODING_ASCII_US) ,_rProp->m_sFileURL); _rProp->m_bIsOpen = sal_True; break; default: delete [] pFileName; throw uno::Exception(); // TODO give a more precise error message here } delete [] pFileName; } return _rProp->m_sFileURL; } // ----------------------------------------------------------------------------- ::rtl::OUString ContentProvider::convertURL(const ::rtl::OUString& _sCanonicURL) { sal_Int32 nPos = 0; // check if url starts with odma if(_sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME_SHORT ODMA_URL_SHORT))) { // URL starts with odma:// so we have to remove this nPos = ODMA_URL_SHORT_LGTH; } else if(_sCanonicURL.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT))) { // URL starts with vnd.sun.star.odma:/// so we have to remove this nPos = ODMA_URL_LGTH; } ::rtl::OUString sCanonicURL = _sCanonicURL; // now check what formats we allow if(nPos == _sCanonicURL.getLength()) // only ask for root entry sCanonicURL = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")); if(nPos < sCanonicURL.getLength()) { sCanonicURL = sCanonicURL.copy(nPos); sCanonicURL = rtl::Uri::decode(sCanonicURL,rtl_UriDecodeWithCharset,RTL_TEXTENCODING_UTF8); } if(sCanonicURL.getLength() > 1 && sCanonicURL.getStr()[0] == sal_Unicode('/')) { sCanonicURL = sCanonicURL.copy(1); if(sCanonicURL.getLength() == 1 && sCanonicURL.getStr()[0] == sal_Unicode('.')) sCanonicURL = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/")); } return sCanonicURL; } // ----------------------------------------------------------------------------- sal_Bool ContentProvider::deleteDocument(const ::rtl::Reference& _rProp) { closeDocument(_rProp->m_sDocumentId); ODMSTATUS odm = NODMActivate(ContentProvider::getHandle(), ODM_DELETE, const_cast< sal_Char*>(_rProp->m_sDocumentId.getStr())); if(odm == ODM_SUCCESS) m_aContents.erase(_rProp->m_sDocumentId); return odm == ODM_SUCCESS; } // -----------------------------------------------------------------------------