blob: b4759273aafe3c4e98364e3445c016d87c952cb7 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_ucb.hxx"
/**************************************************************************
TODO
**************************************************************************
*************************************************************************/
#include <ucbhelper/contentidentifier.hxx>
#include "odma_provider.hxx"
#include "odma_content.hxx"
#include "odma_contentprops.hxx"
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/Time.hpp>
#include <rtl/uri.hxx>
#include <algorithm>
#include <osl/file.hxx>
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;
}
}
// -----------------------------------------------------------------------------
ODMHANDLE ContentProvider::getHandle()
{
if(!m_aOdmHandle)
{
ODMSTATUS odm = NODMRegisterApp(&m_aOdmHandle,ODM_API_VERSION,ODMA_ODMA_REGNAME,NULL,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<ContentProperties> 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<sal_Char*>(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<sal_Char*>(_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<sal_Char*>(_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<ContentProperties>& _rProp)
{
// read some properties from the DMS
sal_Char* lpszDocInfo = new sal_Char[ODM_DOCID_MAX];
sal_Char* pDocId = const_cast<sal_Char*>(_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<sal_Char*>(_rProp->m_sDocumentId.getStr()),
ODM_URL,
lpszDocInfo,
ODM_DOCID_MAX);
*/
delete [] lpszDocInfo;
}
// -----------------------------------------------------------------------------
void ContentProvider::append(const ::rtl::Reference<ContentProperties>& _rProp)
{
// now fill some more properties
fillDocumentProperties(_rProp);
// and append them
m_aContents.insert(ContentsMap::value_type(_rProp->m_sDocumentId,_rProp));
}
// -----------------------------------------------------------------------------
::rtl::Reference<ContentProperties> ContentProvider::queryContentProperty(const ::rtl::OUString& _sDocumentName)
{
::rtl::Reference<ContentProperties> 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, 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<ContentProperties> ContentProvider::getContentProperty(const ::rtl::OUString& _sName,
const ContentPropertiesMemberFunctor& _aFunctor) const
{
::rtl::Reference<ContentProperties> aReturn;
ContentsMap::const_iterator aFind = ::std::find_if( m_aContents.begin(),
m_aContents.end(),
::std::compose1(
::std::bind2nd(_aFunctor,_sName),
::std::select2nd<ContentsMap::value_type>()
)
);
if(aFind != m_aContents.end())
aReturn = aFind->second;
return aReturn;
}
// -----------------------------------------------------------------------------
::rtl::Reference<ContentProperties> ContentProvider::getContentPropertyWithSavedAsName(const ::rtl::OUString& _sSaveAsName) const
{
ContentPropertiesMemberFunctor aFunc(::std::mem_fun(&ContentProperties::getSavedAsName));
return getContentProperty(_sSaveAsName,aFunc);
}
// -----------------------------------------------------------------------------
::rtl::Reference<ContentProperties> ContentProvider::getContentPropertyWithTitle(const ::rtl::OUString& _sTitle) const
{
ContentPropertiesMemberFunctor aFunc(::std::mem_fun(&ContentProperties::getTitle));
return getContentProperty(_sTitle,aFunc);
}
// -----------------------------------------------------------------------------
::rtl::OUString ContentProvider::openDoc(const ::rtl::Reference<ContentProperties>& _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<sal_Char*>(_rProp->m_sDocumentId.getStr()), pFileName);
switch(odm)
{
case ODM_E_INUSE:
dwFlag = ODM_VIEWMODE;
if( NODMOpenDoc(getHandle(), dwFlag, const_cast<sal_Char*>(_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<ContentProperties>& _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;
}
// -----------------------------------------------------------------------------