1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: odma_provider.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_ucb.hxx"
34 /**************************************************************************
36 **************************************************************************
38 *************************************************************************/
39 #include <ucbhelper/contentidentifier.hxx>
40 #include "odma_provider.hxx"
41 #include "odma_content.hxx"
42 #include "odma_contentprops.hxx"
43 #include <com/sun/star/util/Date.hpp>
44 #include <com/sun/star/util/Time.hpp>
45 #include <rtl/uri.hxx>
47 #include <osl/file.hxx>
49 using namespace com::sun::star
;
52 //=========================================================================
53 //=========================================================================
55 // ContentProvider Implementation.
57 //=========================================================================
58 //=========================================================================
59 ODMHANDLE
ContentProvider::m_aOdmHandle
= NULL
;
61 ContentProvider::ContentProvider(
62 const uno::Reference
< lang::XMultiServiceFactory
>& rSMgr
)
63 : ::ucbhelper::ContentProviderImplHelper( rSMgr
)
68 //=========================================================================
70 ContentProvider::~ContentProvider()
72 ContentsMap::iterator aIter
= m_aContents
.begin();
73 for (;aIter
!= m_aContents
.end() ;++aIter
)
75 if(aIter
->second
->m_bIsOpen
)
76 closeDocument(aIter
->first
);
80 NODMUnRegisterApp(m_aOdmHandle
);
84 // -----------------------------------------------------------------------------
85 ODMHANDLE
ContentProvider::getHandle()
89 ODMSTATUS odm
= NODMRegisterApp(&m_aOdmHandle
,ODM_API_VERSION
,ODMA_ODMA_REGNAME
,NULL
,NULL
);
106 // -----------------------------------------------------------------------------
108 //=========================================================================
110 // XInterface methods.
112 //=========================================================================
114 // @@@ Add own interfaces.
115 XINTERFACE_IMPL_3( ContentProvider
,
118 ucb::XContentProvider
);
120 //=========================================================================
122 // XTypeProvider methods.
124 //=========================================================================
126 // @@@ Add own interfaces.
127 XTYPEPROVIDER_IMPL_3( ContentProvider
,
130 ucb::XContentProvider
);
132 //=========================================================================
134 // XServiceInfo methods.
136 //=========================================================================
138 // @@@ Adjust implementation name. Keep the prefix "com.sun.star.comp."!
139 // @@@ Adjust service name.
140 XSERVICEINFO_IMPL_1( ContentProvider
,
141 rtl::OUString::createFromAscii(
142 "com.sun.star.comp.odma.ContentProvider" ),
143 rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_PROVIDER_SERVICE_NAME
) ) );
145 //=========================================================================
147 // Service factory implementation.
149 //=========================================================================
151 ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider
);
153 //=========================================================================
155 // XContentProvider methods.
157 //=========================================================================
160 uno::Reference
< ucb::XContent
> SAL_CALL
ContentProvider::queryContent(
161 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
162 throw( ucb::IllegalIdentifierException
, uno::RuntimeException
)
164 // Check URL scheme...
166 throw ucb::IllegalIdentifierException();
168 rtl::OUString
aScheme( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(ODMA_URL_SCHEME
) ) );
169 sal_Int32 nIndex
= 0;
170 rtl::OUString sOdma
= aScheme
.getToken(3,'.',nIndex
);
171 rtl::OUString sCanonicURL
= Identifier
->getContentIdentifier();
172 // check if url starts with odma
173 if ( !(Identifier
->getContentProviderScheme().equalsIgnoreAsciiCase( aScheme
) ||
174 Identifier
->getContentProviderScheme().equalsIgnoreAsciiCase( sOdma
)) )
175 throw ucb::IllegalIdentifierException();
177 if(!( sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME_SHORT ODMA_URL_SHORT
)) ||
178 sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT
))))
179 throw ucb::IllegalIdentifierException();
181 // @@@ Further id checks may go here...
183 if ( id
-check
-failes
)
184 throw ucb::IllegalIdentifierException();
187 // @@@ Id normalization may go here...
189 // Normalize URL and create new Id.
190 rtl::OUString aCanonicURL
= ( Identifier
->getContentIdentifier() );
191 uno::Reference
< ucb::XContentIdentifier
> xCanonicId
192 = new ::ucb::ContentIdentifier( m_xSMgr
, aCanonicURL
);
194 uno::Reference
< ucb::XContentIdentifier
> xCanonicId
= Identifier
;
197 osl::MutexGuard
aGuard( m_aMutex
);
199 // Check, if a content with given id already exists...
200 uno::Reference
< ucb::XContent
> xContent
201 = queryExistingContent( xCanonicId
).get();
205 // @@@ Decision, which content implementation to instanciate may be
206 // made here ( in case you have different content classes ).
208 // Create a new content.
210 sCanonicURL
= convertURL(sCanonicURL
);
212 ::rtl::Reference
<ContentProperties
> aProp
;
213 // first check if we got an ODMA ID from outside
214 if( sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_ODMAID
)))
215 {// we get an orignal ODMA id so we have to look for the name
216 ::rtl::OString sDocId
= ::rtl::OUStringToOString(sCanonicURL
,RTL_TEXTENCODING_MS_1252
);
217 sal_Char
* lpszDocName
= new sal_Char
[ODM_NAME_MAX
];
219 ODMSTATUS odm
= NODMGetDocInfo( getHandle(),
220 const_cast<sal_Char
*>(sDocId
.getStr()),
225 if(odm
== ODM_SUCCESS
)
227 aProp
= new ContentProperties();
228 aProp
->m_sDocumentName
= ::rtl::OStringToOUString(rtl::OString(lpszDocName
),RTL_TEXTENCODING_ASCII_US
);
229 aProp
->m_sDocumentId
= sDocId
;
230 aProp
->m_sContentType
= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_TYPE
));
235 else // we got an already fetched name here so look for it
237 // we have a valid document name
238 aProp
= getContentPropertyWithTitle(sCanonicURL
);
240 aProp
= getContentPropertyWithSavedAsName(sCanonicURL
);
243 if(sCanonicURL
.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("/")))
244 { // found only the scheme
245 aProp
= new ContentProperties();
246 aProp
->m_sDocumentId
= "/";
247 aProp
->m_sTitle
= sCanonicURL
;
248 aProp
->m_bIsFolder
= sal_True
;
249 aProp
->m_bIsDocument
= !aProp
->m_bIsFolder
;
250 m_aContents
.insert(ContentsMap::value_type(aProp
->m_sDocumentId
,aProp
));
253 aProp
= queryContentProperty(sCanonicURL
);
257 throw ucb::IllegalIdentifierException();
259 xContent
= new Content( m_xSMgr
, this, xCanonicId
,aProp
);
260 registerNewContent( xContent
);
262 if ( !xContent
->getIdentifier().is() )
263 throw ucb::IllegalIdentifierException();
267 // -----------------------------------------------------------------------------
268 void ContentProvider::closeDocument(const ::rtl::OString
& _sDocumentId
)
270 ContentsMap::iterator aIter
= m_aContents
.find(_sDocumentId
);
271 if(aIter
!= m_aContents
.end())
273 DWORD dwFlags
= ODM_SILENT
;
274 ODMSTATUS odm
= NODMCloseDocEx( ContentProvider::getHandle(),
275 const_cast<sal_Char
*>(_sDocumentId
.getStr()),
281 OSL_ENSURE(odm
== ODM_SUCCESS
,"Error while closing a document!");
282 if(odm
== ODM_SUCCESS
)
283 aIter
->second
->m_bIsOpen
= sal_False
;
286 // -----------------------------------------------------------------------------
287 void ContentProvider::saveDocument(const ::rtl::OString
& _sDocumentId
)
289 ContentsMap::iterator aIter
= m_aContents
.find(_sDocumentId
);
290 if(aIter
!= m_aContents
.end())
292 sal_Char
* lpszDocId
= new sal_Char
[ODM_DOCID_MAX
];
293 DWORD dwFlags
= ODM_SILENT
;
294 ODMSTATUS odm
= NODMSaveDocEx(getHandle(),
295 const_cast<sal_Char
*>(_sDocumentId
.getStr()),
298 OSL_ENSURE(odm
== ODM_SUCCESS
,"Could not save document!");
299 if(odm
!= ODM_SUCCESS
)
302 throw uno::Exception();
304 aIter
->second
->m_sDocumentId
= rtl::OString(lpszDocId
);
308 // -----------------------------------------------------------------------------
309 util::Date
toDate(const ::rtl::OString
& _sSQLString
)
311 sal_uInt16 nYear
= 0,
314 nYear
= (sal_uInt16
)_sSQLString
.copy(0,4).toInt32();
315 nMonth
= (sal_uInt16
)_sSQLString
.copy(4,2).toInt32();
316 nDay
= (sal_uInt16
)_sSQLString
.copy(6,2).toInt32();
318 return util::Date(nDay
,nMonth
,nYear
);
320 //-----------------------------------------------------------------------------
321 util::Time
toTime(const ::rtl::OString
& _sSQLString
)
323 sal_uInt16 nHour
= 0,
326 nHour
= (sal_uInt16
)_sSQLString
.copy(8,2).toInt32();
327 nMinute
= (sal_uInt16
)_sSQLString
.copy(10,2).toInt32();
328 nSecond
= (sal_uInt16
)_sSQLString
.copy(12,2).toInt32();
330 return util::Time(0,nHour
,nMinute
,nSecond
);
332 //-----------------------------------------------------------------------------
333 util::DateTime
toDateTime(const ::rtl::OString
& _sSQLString
)
335 util::Date aDate
= toDate(_sSQLString
);
336 util::Time aTime
= toTime(_sSQLString
);
338 return util::DateTime(0,aTime
.Seconds
,aTime
.Minutes
,aTime
.Hours
,aDate
.Day
,aDate
.Month
,aDate
.Year
);
340 // -----------------------------------------------------------------------------
341 void ContentProvider::fillDocumentProperties(const ::rtl::Reference
<ContentProperties
>& _rProp
)
343 // read some properties from the DMS
344 sal_Char
* lpszDocInfo
= new sal_Char
[ODM_DOCID_MAX
];
345 sal_Char
* pDocId
= const_cast<sal_Char
*>(_rProp
->m_sDocumentId
.getStr());
347 // read the create date of the document
348 ODMSTATUS odm
= NODMGetDocInfo( getHandle(),
353 if(odm
== ODM_SUCCESS
)
354 _rProp
->m_aDateCreated
= toDateTime(::rtl::OString(lpszDocInfo
));
356 // read the modified date of the document
357 odm
= NODMGetDocInfo( getHandle(),
362 if(odm
== ODM_SUCCESS
)
363 _rProp
->m_aDateModified
= toDateTime(::rtl::OString(lpszDocInfo
));
365 // read the title of the document
366 odm
= NODMGetDocInfo( getHandle(),
371 if(odm
== ODM_SUCCESS
)
372 _rProp
->m_sTitle
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
374 // read the name of the document
375 odm
= NODMGetDocInfo( getHandle(),
380 if(odm
== ODM_SUCCESS
)
381 _rProp
->m_sDocumentName
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
383 // read the author of the document
384 odm
= NODMGetDocInfo( getHandle(),
389 if(odm
== ODM_SUCCESS
)
390 _rProp
->m_sAuthor
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
392 // read the subject of the document
393 odm
= NODMGetDocInfo( getHandle(),
398 if(odm
== ODM_SUCCESS
)
399 _rProp
->m_sSubject
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
401 // read the keywords of the document
402 odm
= NODMGetDocInfo( getHandle(),
407 if(odm
== ODM_SUCCESS
)
408 _rProp
->m_sKeywords
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
411 odm = NODMGetDocInfo( getHandle(),
412 const_cast<sal_Char*>(_rProp->m_sDocumentId.getStr()),
419 // -----------------------------------------------------------------------------
420 void ContentProvider::append(const ::rtl::Reference
<ContentProperties
>& _rProp
)
422 // now fill some more properties
423 fillDocumentProperties(_rProp
);
425 m_aContents
.insert(ContentsMap::value_type(_rProp
->m_sDocumentId
,_rProp
));
427 // -----------------------------------------------------------------------------
428 ::rtl::Reference
<ContentProperties
> ContentProvider::queryContentProperty(const ::rtl::OUString
& _sDocumentName
)
430 ::rtl::Reference
<ContentProperties
> aReturn
;
431 sal_Char
* lpszDMSList
= new sal_Char
[ODM_DMSID_MAX
];
433 ODMSTATUS odm
= NODMGetDMS(ODMA_ODMA_REGNAME
, lpszDMSList
);
434 if(odm
== ODM_SUCCESS
)
436 sal_Char
* pQueryId
= new sal_Char
[ODM_QUERYID_MAX
];
437 lpszDMSList
[strlen(lpszDMSList
)+1] = '\0';
439 ::rtl::OString
sTitleText(::rtl::OUStringToOString(_sDocumentName
,RTL_TEXTENCODING_ASCII_US
));
440 ::rtl::OString
sQuery("SELECT ODM_DOCID_LATEST, ODM_NAME WHERE ODM_TITLETEXT = '");
441 sQuery
+= sTitleText
;
444 DWORD dwFlags
= ODM_SPECIFIC
;
445 odm
= NODMQueryExecute(getHandle(), sQuery
,dwFlags
, lpszDMSList
, pQueryId
);
446 if(odm
== ODM_SUCCESS
)
448 sal_uInt16 nCount
= 10;
449 sal_uInt16 nMaxCount
= 10;
450 sal_Char
* lpszDocId
= new sal_Char
[ODM_DOCID_MAX
* nMaxCount
];
451 sal_Char
* lpszDocName
= new sal_Char
[ODM_NAME_MAX
* nMaxCount
];
452 sal_Char
* lpszDocInfo
= new sal_Char
[ODM_DOCID_MAX
];
454 ::rtl::OUString
sContentType(RTL_CONSTASCII_USTRINGPARAM(ODMA_CONTENT_TYPE
));
457 if(nCount
>= nMaxCount
)
461 odm
= NODMQueryGetResults(getHandle(), pQueryId
,lpszDocId
, lpszDocName
, ODM_NAME_MAX
, (WORD
*)&nCount
);
463 if(odm
== ODM_SUCCESS
)
464 for(sal_uInt16 i
= 0; i
< nCount
; ++i
)
466 odm
= NODMGetDocInfo( getHandle(),
467 &lpszDocId
[ODM_DOCID_MAX
*i
],
471 if( odm
== ODM_SUCCESS
&& sTitleText
== ::rtl::OString(lpszDocInfo
))
473 aReturn
= new ContentProperties();
474 aReturn
->m_sDocumentName
= ::rtl::OStringToOUString(rtl::OString(&lpszDocName
[ODM_NAME_MAX
*i
]),RTL_TEXTENCODING_ASCII_US
);
475 aReturn
->m_sDocumentId
= ::rtl::OString(&lpszDocId
[ODM_DOCID_MAX
*i
]);
476 aReturn
->m_sContentType
= sContentType
;
478 nCount
= 0; // break condition from outer loop
483 while(nCount
> nMaxCount
);
490 // now close the query
491 odm
= NODMQueryClose(ContentProvider::getHandle(), pQueryId
);
499 // -----------------------------------------------------------------------------
500 ::rtl::Reference
<ContentProperties
> ContentProvider::getContentProperty(const ::rtl::OUString
& _sName
,
501 const ContentPropertiesMemberFunctor
& _aFunctor
) const
503 ::rtl::Reference
<ContentProperties
> aReturn
;
504 ContentsMap::const_iterator aFind
= ::std::find_if( m_aContents
.begin(),
507 ::std::bind2nd(_aFunctor
,_sName
),
508 ::std::select2nd
<ContentsMap::value_type
>()
511 if(aFind
!= m_aContents
.end())
512 aReturn
= aFind
->second
;
515 // -----------------------------------------------------------------------------
516 ::rtl::Reference
<ContentProperties
> ContentProvider::getContentPropertyWithSavedAsName(const ::rtl::OUString
& _sSaveAsName
) const
518 ContentPropertiesMemberFunctor
aFunc(::std::mem_fun(&ContentProperties::getSavedAsName
));
519 return getContentProperty(_sSaveAsName
,aFunc
);
521 // -----------------------------------------------------------------------------
522 ::rtl::Reference
<ContentProperties
> ContentProvider::getContentPropertyWithTitle(const ::rtl::OUString
& _sTitle
) const
524 ContentPropertiesMemberFunctor
aFunc(::std::mem_fun(&ContentProperties::getTitle
));
525 return getContentProperty(_sTitle
,aFunc
);
527 // -----------------------------------------------------------------------------
528 ::rtl::Reference
<ContentProperties
> ContentProvider::getContentPropertyWithDocumentId(const ::rtl::OUString
& _sDocumentId
) const
530 ContentPropertiesMemberFunctor
aFunc(::std::mem_fun(&ContentProperties::getDocumentId
));
531 return getContentProperty(_sDocumentId
,aFunc
);
533 // -----------------------------------------------------------------------------
534 ::rtl::OUString
ContentProvider::openDoc(const ::rtl::Reference
<ContentProperties
>& _rProp
) throw (uno::Exception
)
536 OSL_ENSURE(_rProp
.is(),"No valid content properties!");
537 if(!_rProp
->m_bIsOpen
)
539 sal_Char
*pFileName
= new sal_Char
[ODM_FILENAME_MAX
];
541 DWORD dwFlag
= ODM_MODIFYMODE
| ODM_SILENT
;
542 ODMSTATUS odm
= NODMOpenDoc(getHandle(), dwFlag
, const_cast<sal_Char
*>(_rProp
->m_sDocumentId
.getStr()), pFileName
);
546 dwFlag
= ODM_VIEWMODE
;
547 if( NODMOpenDoc(getHandle(), dwFlag
, const_cast<sal_Char
*>(_rProp
->m_sDocumentId
.getStr()), pFileName
) != ODM_SUCCESS
)
551 ::osl::FileBase::getFileURLFromSystemPath(::rtl::OStringToOUString(rtl::OString(pFileName
),RTL_TEXTENCODING_ASCII_US
)
552 ,_rProp
->m_sFileURL
);
553 _rProp
->m_bIsOpen
= sal_True
;
557 throw uno::Exception(); // TODO give a more precise error message here
562 return _rProp
->m_sFileURL
;
564 // -----------------------------------------------------------------------------
565 ::rtl::OUString
ContentProvider::convertURL(const ::rtl::OUString
& _sCanonicURL
)
568 // check if url starts with odma
569 if(_sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME_SHORT ODMA_URL_SHORT
)))
570 { // URL starts with odma:// so we have to remove this
571 nPos
= ODMA_URL_SHORT_LGTH
;
573 else if(_sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT
)))
574 { // URL starts with vnd.sun.star.odma:/// so we have to remove this
575 nPos
= ODMA_URL_LGTH
;
578 ::rtl::OUString sCanonicURL
= _sCanonicURL
;
579 // now check what formats we allow
580 if(nPos
== _sCanonicURL
.getLength()) // only ask for root entry
581 sCanonicURL
= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));
583 if(nPos
< sCanonicURL
.getLength())
585 sCanonicURL
= sCanonicURL
.copy(nPos
);
586 sCanonicURL
= rtl::Uri::decode(sCanonicURL
,rtl_UriDecodeWithCharset
,RTL_TEXTENCODING_UTF8
);
588 if(sCanonicURL
.getLength() > 1 && sCanonicURL
.getStr()[0] == sal_Unicode('/'))
590 sCanonicURL
= sCanonicURL
.copy(1);
591 if(sCanonicURL
.getLength() == 1 && sCanonicURL
.getStr()[0] == sal_Unicode('.'))
592 sCanonicURL
= ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("/"));
596 // -----------------------------------------------------------------------------
597 sal_Bool
ContentProvider::deleteDocument(const ::rtl::Reference
<ContentProperties
>& _rProp
)
599 closeDocument(_rProp
->m_sDocumentId
);
600 ODMSTATUS odm
= NODMActivate(ContentProvider::getHandle(),
602 const_cast< sal_Char
*>(_rProp
->m_sDocumentId
.getStr()));
603 if(odm
== ODM_SUCCESS
)
604 m_aContents
.erase(_rProp
->m_sDocumentId
);
606 return odm
== ODM_SUCCESS
;
608 // -----------------------------------------------------------------------------