1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
33 #include <ucbhelper/contentidentifier.hxx>
34 #include "odma_provider.hxx"
35 #include "odma_content.hxx"
36 #include "odma_contentprops.hxx"
37 #include <com/sun/star/util/Date.hpp>
38 #include <com/sun/star/util/Time.hpp>
39 #include <rtl/uri.hxx>
41 #include <osl/file.hxx>
43 #include <o3tl/compat_functional.hxx>
45 using namespace com::sun::star
;
48 //=========================================================================
49 //=========================================================================
51 // ContentProvider Implementation.
53 //=========================================================================
54 //=========================================================================
55 ODMHANDLE
ContentProvider::m_aOdmHandle
= NULL
;
57 ContentProvider::ContentProvider(
58 const uno::Reference
< lang::XMultiServiceFactory
>& rSMgr
)
59 : ::ucbhelper::ContentProviderImplHelper( rSMgr
)
64 //=========================================================================
66 ContentProvider::~ContentProvider()
68 ContentsMap::iterator aIter
= m_aContents
.begin();
69 for (;aIter
!= m_aContents
.end() ;++aIter
)
71 if(aIter
->second
->m_bIsOpen
)
72 closeDocument(aIter
->first
);
76 NODMUnRegisterApp(m_aOdmHandle
);
80 // -----------------------------------------------------------------------------
81 inline bool is_current_process_window(HWND hwnd
)
84 GetWindowThreadProcessId(hwnd
, &pid
);
85 return (pid
== GetCurrentProcessId());
88 HWND
choose_parent_window()
90 HWND hwnd_parent
= GetForegroundWindow();
91 if (!is_current_process_window(hwnd_parent
))
92 hwnd_parent
= GetDesktopWindow();
96 ODMHANDLE
ContentProvider::getHandle()
100 ODMSTATUS odm
= NODMRegisterApp(&m_aOdmHandle
,ODM_API_VERSION
,const_cast<char*>(ODMA_ODMA_REGNAME
),(DWORD
) choose_parent_window( ),NULL
);
117 // -----------------------------------------------------------------------------
119 //=========================================================================
121 // XInterface methods.
123 //=========================================================================
125 // @@@ Add own interfaces.
126 XINTERFACE_IMPL_3( ContentProvider
,
129 ucb::XContentProvider
);
131 //=========================================================================
133 // XTypeProvider methods.
135 //=========================================================================
137 // @@@ Add own interfaces.
138 XTYPEPROVIDER_IMPL_3( ContentProvider
,
141 ucb::XContentProvider
);
143 //=========================================================================
145 // XServiceInfo methods.
147 //=========================================================================
149 // @@@ Adjust implementation name. Keep the prefix "com.sun.star.comp."!
150 // @@@ Adjust service name.
151 XSERVICEINFO_IMPL_1( ContentProvider
,
152 rtl::OUString( "com.sun.star.comp.odma.ContentProvider" ),
153 rtl::OUString(ODMA_CONTENT_PROVIDER_SERVICE_NAME
) );
155 //=========================================================================
157 // Service factory implementation.
159 //=========================================================================
161 ONE_INSTANCE_SERVICE_FACTORY_IMPL( ContentProvider
);
163 //=========================================================================
165 // XContentProvider methods.
167 //=========================================================================
170 uno::Reference
< ucb::XContent
> SAL_CALL
ContentProvider::queryContent(
171 const uno::Reference
< ucb::XContentIdentifier
>& Identifier
)
172 throw( ucb::IllegalIdentifierException
, uno::RuntimeException
)
174 // Check URL scheme...
176 throw ucb::IllegalIdentifierException();
178 rtl::OUString
aScheme( rtl::OUString( ODMA_URL_SCHEME
) );
179 sal_Int32 nIndex
= 0;
180 rtl::OUString sOdma
= aScheme
.getToken(3,'.',nIndex
);
181 rtl::OUString sCanonicURL
= Identifier
->getContentIdentifier();
182 // check if url starts with odma
183 if ( !(Identifier
->getContentProviderScheme().equalsIgnoreAsciiCase( aScheme
) ||
184 Identifier
->getContentProviderScheme().equalsIgnoreAsciiCase( sOdma
)) )
185 throw ucb::IllegalIdentifierException();
187 if(!( sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME_SHORT ODMA_URL_SHORT
)) ||
188 sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT
))))
189 throw ucb::IllegalIdentifierException();
192 // @@@ Id normalization may go here...
194 uno::Reference
< ucb::XContentIdentifier
> xCanonicId
= Identifier
;
196 osl::MutexGuard
aGuard( m_aMutex
);
198 // Check, if a content with given id already exists...
199 uno::Reference
< ucb::XContent
> xContent
200 = queryExistingContent( xCanonicId
).get();
204 // @@@ Decision, which content implementation to instanciate may be
205 // made here ( in case you have different content classes ).
207 // Create a new content.
209 sCanonicURL
= convertURL(sCanonicURL
);
211 ::rtl::Reference
<ContentProperties
> aProp
;
212 // first check if we got an ODMA ID from outside
213 if( sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_ODMAID
)))
214 {// we get an orignal ODMA id so we have to look for the name
215 ::rtl::OString sDocId
= ::rtl::OUStringToOString(sCanonicURL
,RTL_TEXTENCODING_MS_1252
);
216 sal_Char
* lpszDocName
= new sal_Char
[ODM_NAME_MAX
];
218 ODMSTATUS odm
= NODMGetDocInfo( getHandle(),
219 const_cast<sal_Char
*>(sDocId
.getStr()),
224 if(odm
== ODM_SUCCESS
)
226 aProp
= new ContentProperties();
227 aProp
->m_sDocumentName
= ::rtl::OStringToOUString(rtl::OString(lpszDocName
),RTL_TEXTENCODING_ASCII_US
);
228 aProp
->m_sDocumentId
= sDocId
;
229 aProp
->m_sContentType
= ::rtl::OUString(ODMA_CONTENT_TYPE
);
232 delete [] lpszDocName
;
234 else // we got an already fetched name here so look for it
236 // we have a valid document name
237 aProp
= getContentPropertyWithTitle(sCanonicURL
);
239 aProp
= getContentPropertyWithSavedAsName(sCanonicURL
);
242 if(sCanonicURL
.equalsIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM("/")))
243 { // found only the scheme
244 aProp
= new ContentProperties();
245 aProp
->m_sDocumentId
= "/";
246 aProp
->m_sTitle
= sCanonicURL
;
247 aProp
->m_bIsFolder
= sal_True
;
248 aProp
->m_bIsDocument
= !aProp
->m_bIsFolder
;
249 m_aContents
.insert(ContentsMap::value_type(aProp
->m_sDocumentId
,aProp
));
252 aProp
= queryContentProperty(sCanonicURL
);
256 throw ucb::IllegalIdentifierException();
258 xContent
= new Content( m_xSMgr
, this, xCanonicId
,aProp
);
259 registerNewContent( xContent
);
261 if ( !xContent
->getIdentifier().is() )
262 throw ucb::IllegalIdentifierException();
266 // -----------------------------------------------------------------------------
267 void ContentProvider::closeDocument(const ::rtl::OString
& _sDocumentId
)
269 ContentsMap::iterator aIter
= m_aContents
.find(_sDocumentId
);
270 if(aIter
!= m_aContents
.end())
272 DWORD dwFlags
= ODM_SILENT
;
273 ODMSTATUS odm
= NODMCloseDocEx( ContentProvider::getHandle(),
274 const_cast<sal_Char
*>(_sDocumentId
.getStr()),
280 OSL_ENSURE(odm
== ODM_SUCCESS
,"Error while closing a document!");
281 if(odm
== ODM_SUCCESS
)
282 aIter
->second
->m_bIsOpen
= sal_False
;
285 // -----------------------------------------------------------------------------
286 void ContentProvider::saveDocument(const ::rtl::OString
& _sDocumentId
)
288 ContentsMap::iterator aIter
= m_aContents
.find(_sDocumentId
);
289 if(aIter
!= m_aContents
.end())
291 sal_Char
* lpszDocId
= new sal_Char
[ODM_DOCID_MAX
];
292 DWORD dwFlags
= ODM_SILENT
;
293 ODMSTATUS odm
= NODMSaveDocEx(getHandle(),
294 const_cast<sal_Char
*>(_sDocumentId
.getStr()),
297 OSL_ENSURE(odm
== ODM_SUCCESS
,"Could not save document!");
298 if(odm
!= ODM_SUCCESS
)
301 throw uno::Exception();
303 aIter
->second
->m_sDocumentId
= rtl::OString(lpszDocId
);
307 // -----------------------------------------------------------------------------
308 util::Date
toDate(const ::rtl::OString
& _sSQLString
)
310 sal_uInt16 nYear
= 0,
313 nYear
= (sal_uInt16
)_sSQLString
.copy(0,4).toInt32();
314 nMonth
= (sal_uInt16
)_sSQLString
.copy(4,2).toInt32();
315 nDay
= (sal_uInt16
)_sSQLString
.copy(6,2).toInt32();
317 return util::Date(nDay
,nMonth
,nYear
);
319 //-----------------------------------------------------------------------------
320 util::Time
toTime(const ::rtl::OString
& _sSQLString
)
322 sal_uInt16 nHour
= 0,
325 nHour
= (sal_uInt16
)_sSQLString
.copy(8,2).toInt32();
326 nMinute
= (sal_uInt16
)_sSQLString
.copy(10,2).toInt32();
327 nSecond
= (sal_uInt16
)_sSQLString
.copy(12,2).toInt32();
329 return util::Time(0,nHour
,nMinute
,nSecond
);
331 //-----------------------------------------------------------------------------
332 util::DateTime
toDateTime(const ::rtl::OString
& _sSQLString
)
334 util::Date aDate
= toDate(_sSQLString
);
335 util::Time aTime
= toTime(_sSQLString
);
337 return util::DateTime(0,aTime
.Seconds
,aTime
.Minutes
,aTime
.Hours
,aDate
.Day
,aDate
.Month
,aDate
.Year
);
339 // -----------------------------------------------------------------------------
340 void ContentProvider::fillDocumentProperties(const ::rtl::Reference
<ContentProperties
>& _rProp
)
342 // read some properties from the DMS
343 sal_Char
* lpszDocInfo
= new sal_Char
[ODM_DOCID_MAX
];
344 sal_Char
* pDocId
= const_cast<sal_Char
*>(_rProp
->m_sDocumentId
.getStr());
346 // read the create date of the document
347 ODMSTATUS odm
= NODMGetDocInfo( getHandle(),
352 if(odm
== ODM_SUCCESS
)
353 _rProp
->m_aDateCreated
= toDateTime(::rtl::OString(lpszDocInfo
));
355 // read the modified date of the document
356 odm
= NODMGetDocInfo( getHandle(),
361 if(odm
== ODM_SUCCESS
)
362 _rProp
->m_aDateModified
= toDateTime(::rtl::OString(lpszDocInfo
));
364 // read the title of the document
365 odm
= NODMGetDocInfo( getHandle(),
370 if(odm
== ODM_SUCCESS
)
371 _rProp
->m_sTitle
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
373 // read the name of the document
374 odm
= NODMGetDocInfo( getHandle(),
379 if(odm
== ODM_SUCCESS
)
380 _rProp
->m_sDocumentName
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
382 // read the author of the document
383 odm
= NODMGetDocInfo( getHandle(),
388 if(odm
== ODM_SUCCESS
)
389 _rProp
->m_sAuthor
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
391 // read the subject of the document
392 odm
= NODMGetDocInfo( getHandle(),
397 if(odm
== ODM_SUCCESS
)
398 _rProp
->m_sSubject
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
400 // read the keywords of the document
401 odm
= NODMGetDocInfo( getHandle(),
406 if(odm
== ODM_SUCCESS
)
407 _rProp
->m_sKeywords
= ::rtl::OStringToOUString(rtl::OString(lpszDocInfo
),RTL_TEXTENCODING_ASCII_US
);
410 odm = NODMGetDocInfo( getHandle(),
411 const_cast<sal_Char*>(_rProp->m_sDocumentId.getStr()),
416 delete [] lpszDocInfo
;
418 // -----------------------------------------------------------------------------
419 void ContentProvider::append(const ::rtl::Reference
<ContentProperties
>& _rProp
)
421 // now fill some more properties
422 fillDocumentProperties(_rProp
);
424 m_aContents
.insert(ContentsMap::value_type(_rProp
->m_sDocumentId
,_rProp
));
426 // -----------------------------------------------------------------------------
427 ::rtl::Reference
<ContentProperties
> ContentProvider::queryContentProperty(const ::rtl::OUString
& _sDocumentName
)
429 ::rtl::Reference
<ContentProperties
> aReturn
;
430 sal_Char
* lpszDMSList
= new sal_Char
[ODM_DMSID_MAX
];
432 ODMSTATUS odm
= NODMGetDMS(ODMA_ODMA_REGNAME
, lpszDMSList
);
433 if(odm
== ODM_SUCCESS
)
435 sal_Char
* pQueryId
= new sal_Char
[ODM_QUERYID_MAX
];
436 lpszDMSList
[strlen(lpszDMSList
)+1] = '\0';
438 ::rtl::OString
sTitleText(::rtl::OUStringToOString(_sDocumentName
,RTL_TEXTENCODING_ASCII_US
));
439 ::rtl::OString
sQuery("SELECT ODM_DOCID_LATEST, ODM_NAME WHERE ODM_TITLETEXT = '");
440 sQuery
+= sTitleText
;
443 DWORD dwFlags
= ODM_SPECIFIC
;
444 odm
= NODMQueryExecute(getHandle(), sQuery
.getStr(), dwFlags
, lpszDMSList
, pQueryId
);
445 if(odm
== ODM_SUCCESS
)
447 sal_uInt16 nCount
= 10;
448 sal_uInt16 nMaxCount
= 10;
449 sal_Char
* lpszDocId
= new sal_Char
[ODM_DOCID_MAX
* nMaxCount
];
450 sal_Char
* lpszDocName
= new sal_Char
[ODM_NAME_MAX
* nMaxCount
];
451 sal_Char
* lpszDocInfo
= new sal_Char
[ODM_DOCID_MAX
];
453 ::rtl::OUString
sContentType(ODMA_CONTENT_TYPE
);
456 if(nCount
>= nMaxCount
)
460 odm
= NODMQueryGetResults(getHandle(), pQueryId
,lpszDocId
, lpszDocName
, ODM_NAME_MAX
, (WORD
*)&nCount
);
462 if(odm
== ODM_SUCCESS
)
463 for(sal_uInt16 i
= 0; i
< nCount
; ++i
)
465 odm
= NODMGetDocInfo( getHandle(),
466 &lpszDocId
[ODM_DOCID_MAX
*i
],
470 if( odm
== ODM_SUCCESS
&& sTitleText
== ::rtl::OString(lpszDocInfo
))
472 aReturn
= new ContentProperties();
473 aReturn
->m_sDocumentName
= ::rtl::OStringToOUString(rtl::OString(&lpszDocName
[ODM_NAME_MAX
*i
]),RTL_TEXTENCODING_ASCII_US
);
474 aReturn
->m_sDocumentId
= ::rtl::OString(&lpszDocId
[ODM_DOCID_MAX
*i
]);
475 aReturn
->m_sContentType
= sContentType
;
477 nCount
= 0; // break condition from outer loop
482 while(nCount
> nMaxCount
);
484 delete [] lpszDocInfo
;
486 delete [] lpszDocName
;
489 // now close the query
490 odm
= NODMQueryClose(ContentProvider::getHandle(), pQueryId
);
493 delete [] lpszDMSList
;
498 // -----------------------------------------------------------------------------
499 ::rtl::Reference
<ContentProperties
> ContentProvider::getContentProperty(const ::rtl::OUString
& _sName
,
500 const ContentPropertiesMemberFunctor
& _aFunctor
) const
502 ::rtl::Reference
<ContentProperties
> aReturn
;
503 ContentsMap::const_iterator aFind
= ::std::find_if( m_aContents
.begin(),
506 ::std::bind2nd(_aFunctor
,_sName
),
507 ::o3tl::select2nd
<ContentsMap::value_type
>()
510 if(aFind
!= m_aContents
.end())
511 aReturn
= aFind
->second
;
514 // -----------------------------------------------------------------------------
515 ::rtl::Reference
<ContentProperties
> ContentProvider::getContentPropertyWithSavedAsName(const ::rtl::OUString
& _sSaveAsName
) const
517 ContentPropertiesMemberFunctor
aFunc(::std::mem_fun(&ContentProperties::getSavedAsName
));
518 return getContentProperty(_sSaveAsName
,aFunc
);
520 // -----------------------------------------------------------------------------
521 ::rtl::Reference
<ContentProperties
> ContentProvider::getContentPropertyWithTitle(const ::rtl::OUString
& _sTitle
) const
523 ContentPropertiesMemberFunctor
aFunc(::std::mem_fun(&ContentProperties::getTitle
));
524 return getContentProperty(_sTitle
,aFunc
);
526 // -----------------------------------------------------------------------------
527 ::rtl::Reference
<ContentProperties
> ContentProvider::getContentPropertyWithDocumentId(const ::rtl::OUString
& _sDocumentId
) const
529 ContentPropertiesMemberFunctor
aFunc(::std::mem_fun(&ContentProperties::getDocumentId
));
530 return getContentProperty(_sDocumentId
,aFunc
);
532 // -----------------------------------------------------------------------------
533 ::rtl::OUString
ContentProvider::openDoc(const ::rtl::Reference
<ContentProperties
>& _rProp
) throw (uno::Exception
)
535 OSL_ENSURE(_rProp
.is(),"No valid content properties!");
536 if(!_rProp
->m_bIsOpen
)
538 sal_Char
*pFileName
= new sal_Char
[ODM_FILENAME_MAX
];
540 DWORD dwFlag
= ODM_MODIFYMODE
| ODM_SILENT
;
541 ODMSTATUS odm
= NODMOpenDoc(getHandle(), dwFlag
, const_cast<sal_Char
*>(_rProp
->m_sDocumentId
.getStr()), pFileName
);
545 dwFlag
= ODM_VIEWMODE
;
546 if( NODMOpenDoc(getHandle(), dwFlag
, const_cast<sal_Char
*>(_rProp
->m_sDocumentId
.getStr()), pFileName
) != ODM_SUCCESS
)
550 ::osl::FileBase::getFileURLFromSystemPath(::rtl::OStringToOUString(rtl::OString(pFileName
),RTL_TEXTENCODING_ASCII_US
)
551 ,_rProp
->m_sFileURL
);
552 _rProp
->m_bIsOpen
= sal_True
;
556 throw uno::Exception(); // TODO give a more precise error message here
561 return _rProp
->m_sFileURL
;
563 // -----------------------------------------------------------------------------
564 ::rtl::OUString
ContentProvider::convertURL(const ::rtl::OUString
& _sCanonicURL
)
567 // check if url starts with odma
568 if(_sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME_SHORT ODMA_URL_SHORT
)))
569 { // URL starts with odma:// so we have to remove this
570 nPos
= ODMA_URL_SHORT_LGTH
;
572 else if(_sCanonicURL
.matchIgnoreAsciiCaseAsciiL(RTL_CONSTASCII_STRINGPARAM(ODMA_URL_SCHEME ODMA_URL_SHORT
)))
573 { // URL starts with vnd.sun.star.odma:/// so we have to remove this
574 nPos
= ODMA_URL_LGTH
;
577 ::rtl::OUString sCanonicURL
= _sCanonicURL
;
578 // now check what formats we allow
579 if(nPos
== _sCanonicURL
.getLength()) // only ask for root entry
580 sCanonicURL
= ::rtl::OUString("/");
582 if(nPos
< sCanonicURL
.getLength())
584 sCanonicURL
= sCanonicURL
.copy(nPos
);
585 sCanonicURL
= rtl::Uri::decode(sCanonicURL
,rtl_UriDecodeWithCharset
,RTL_TEXTENCODING_UTF8
);
587 if(sCanonicURL
.getLength() > 1 && sCanonicURL
.getStr()[0] == sal_Unicode('/'))
589 sCanonicURL
= sCanonicURL
.copy(1);
590 if(sCanonicURL
.getLength() == 1 && sCanonicURL
.getStr()[0] == sal_Unicode('.'))
591 sCanonicURL
= ::rtl::OUString("/");
595 // -----------------------------------------------------------------------------
596 sal_Bool
ContentProvider::deleteDocument(const ::rtl::Reference
<ContentProperties
>& _rProp
)
598 closeDocument(_rProp
->m_sDocumentId
);
599 ODMSTATUS odm
= NODMActivate(ContentProvider::getHandle(),
601 const_cast< sal_Char
*>(_rProp
->m_sDocumentId
.getStr()));
602 if(odm
== ODM_SUCCESS
)
603 m_aContents
.erase(_rProp
->m_sDocumentId
);
605 return odm
== ODM_SUCCESS
;
607 // -----------------------------------------------------------------------------
609 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */