1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <sfx2/classificationhelper.hxx>
16 #include <com/sun/star/beans/XPropertyContainer.hpp>
17 #include <com/sun/star/beans/Property.hpp>
18 #include <com/sun/star/beans/XPropertySet.hpp>
19 #include <com/sun/star/document/XDocumentProperties.hpp>
20 #include <com/sun/star/xml/sax/Parser.hpp>
21 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
22 #include <com/sun/star/xml/sax/SAXParseException.hpp>
23 #include <com/sun/star/beans/PropertyAttribute.hpp>
25 #include <sal/log.hxx>
26 #include <i18nlangtag/languagetag.hxx>
27 #include <sfx2/infobar.hxx>
28 #include <comphelper/processfactory.hxx>
29 #include <unotools/configmgr.hxx>
30 #include <unotools/pathoptions.hxx>
31 #include <unotools/ucbstreamhelper.hxx>
32 #include <unotools/streamwrap.hxx>
33 #include <cppuhelper/implbase.hxx>
34 #include <sfx2/strings.hrc>
35 #include <sfx2/sfxresid.hxx>
36 #include <sfx2/viewfrm.hxx>
37 #include <tools/datetime.hxx>
38 #include <comphelper/diagnose_ex.hxx>
39 #include <unotools/datetime.hxx>
40 #include <vcl/svapp.hxx>
41 #include <vcl/settings.hxx>
42 #include <vcl/weld.hxx>
43 #include <svl/fstathelper.hxx>
45 #include <o3tl/string_view.hxx>
46 #include <officecfg/Office/Common.hxx>
48 using namespace com::sun::star
;
53 const OUString
& PROP_BACNAME()
55 static constexpr OUString
sProp(u
"BusinessAuthorizationCategory:Name"_ustr
);
59 const OUString
& PROP_STARTVALIDITY()
61 static constexpr OUString
sProp(u
"Authorization:StartValidity"_ustr
);
65 const OUString
& PROP_NONE()
67 static constexpr OUString
sProp(u
"None"_ustr
);
71 const OUString
& PROP_IMPACTSCALE()
73 static constexpr OUString
sProp(u
"Impact:Scale"_ustr
);
77 const OUString
& PROP_IMPACTLEVEL()
79 static constexpr OUString
sProp(u
"Impact:Level:Confidentiality"_ustr
);
83 const OUString
& PROP_PREFIX_EXPORTCONTROL()
85 static constexpr OUString
sProp(u
"urn:bails:ExportControl:"_ustr
);
89 const OUString
& PROP_PREFIX_NATIONALSECURITY()
91 static constexpr OUString
sProp(u
"urn:bails:NationalSecurity:"_ustr
);
95 /// Represents one category of a classification policy.
96 class SfxClassificationCategory
99 /// PROP_BACNAME() is stored separately for easier lookup.
101 OUString m_aAbbreviatedName
; //< An abbreviation to display instead of m_aName.
102 OUString m_aIdentifier
; //< The Identifier of this entry.
103 size_t m_nConfidentiality
; //< 0 is the lowest (least-sensitive).
104 std::map
<OUString
, OUString
> m_aLabels
;
107 /// Parses a policy XML conforming to the TSCP BAF schema.
108 class SfxClassificationParser
: public cppu::WeakImplHelper
<xml::sax::XDocumentHandler
>
111 std::vector
<SfxClassificationCategory
> m_aCategories
;
112 std::vector
<OUString
> m_aMarkings
;
113 std::vector
<OUString
> m_aIPParts
;
114 std::vector
<OUString
> m_aIPPartNumbers
;
116 OUString m_aPolicyAuthorityName
;
117 bool m_bInPolicyAuthorityName
= false;
118 OUString m_aPolicyName
;
119 bool m_bInPolicyName
= false;
120 OUString m_aProgramID
;
121 bool m_bInProgramID
= false;
123 bool m_bInScale
= false;
124 OUString m_aConfidentalityValue
;
125 bool m_bInConfidentalityValue
= false;
126 OUString m_aIdentifier
;
127 bool m_bInIdentifier
= false;
129 bool m_bInValue
= false;
131 /// Pointer to a value in m_aCategories, the currently parsed category.
132 SfxClassificationCategory
* m_pCategory
= nullptr;
134 SfxClassificationParser();
136 void SAL_CALL
startDocument() override
;
138 void SAL_CALL
endDocument() override
;
140 void SAL_CALL
startElement(const OUString
& rName
, const uno::Reference
<xml::sax::XAttributeList
>& xAttribs
) override
;
142 void SAL_CALL
endElement(const OUString
& rName
) override
;
144 void SAL_CALL
characters(const OUString
& rChars
) override
;
146 void SAL_CALL
ignorableWhitespace(const OUString
& rWhitespaces
) override
;
148 void SAL_CALL
processingInstruction(const OUString
& rTarget
, const OUString
& rData
) override
;
150 void SAL_CALL
setDocumentLocator(const uno::Reference
<xml::sax::XLocator
>& xLocator
) override
;
153 SfxClassificationParser::SfxClassificationParser() = default;
155 void SAL_CALL
SfxClassificationParser::startDocument()
159 void SAL_CALL
SfxClassificationParser::endDocument()
163 void SAL_CALL
SfxClassificationParser::startElement(const OUString
& rName
, const uno::Reference
<xml::sax::XAttributeList
>& xAttribs
)
165 if (rName
== "baf:PolicyAuthorityName")
167 m_aPolicyAuthorityName
.clear();
168 m_bInPolicyAuthorityName
= true;
170 else if (rName
== "baf:PolicyName")
172 m_aPolicyName
.clear();
173 m_bInPolicyName
= true;
175 else if (rName
== "baf:ProgramID")
177 m_aProgramID
.clear();
178 m_bInProgramID
= true;
180 else if (rName
== "baf:BusinessAuthorizationCategory")
182 const OUString aName
= xAttribs
->getValueByName(u
"Name"_ustr
);
183 if (!m_pCategory
&& !aName
.isEmpty())
185 OUString aIdentifier
= xAttribs
->getValueByName(u
"Identifier"_ustr
);
187 // Create a new category and initialize it with the data that's true for all categories.
188 m_aCategories
.emplace_back();
189 SfxClassificationCategory
& rCategory
= m_aCategories
.back();
191 rCategory
.m_aName
= aName
;
192 // Set the abbreviated name, if any, otherwise fallback on the full name.
193 const OUString aAbbreviatedName
= xAttribs
->getValueByName(u
"loextAbbreviatedName"_ustr
);
194 rCategory
.m_aAbbreviatedName
= !aAbbreviatedName
.isEmpty() ? aAbbreviatedName
: aName
;
195 rCategory
.m_aIdentifier
= aIdentifier
;
197 rCategory
.m_aLabels
[u
"PolicyAuthority:Name"_ustr
] = m_aPolicyAuthorityName
;
198 rCategory
.m_aLabels
[u
"Policy:Name"_ustr
] = m_aPolicyName
;
199 rCategory
.m_aLabels
[u
"BusinessAuthorization:Identifier"_ustr
] = m_aProgramID
;
200 rCategory
.m_aLabels
[u
"BusinessAuthorizationCategory:Identifier"_ustr
] = aIdentifier
;
202 // Also initialize defaults.
203 rCategory
.m_aLabels
[u
"PolicyAuthority:Identifier"_ustr
] = PROP_NONE();
204 rCategory
.m_aLabels
[u
"PolicyAuthority:Country"_ustr
] = PROP_NONE();
205 rCategory
.m_aLabels
[u
"Policy:Identifier"_ustr
] = PROP_NONE();
206 rCategory
.m_aLabels
[u
"BusinessAuthorization:Name"_ustr
] = PROP_NONE();
207 rCategory
.m_aLabels
[u
"BusinessAuthorization:Locator"_ustr
] = PROP_NONE();
208 rCategory
.m_aLabels
[u
"BusinessAuthorizationCategory:Identifier:OID"_ustr
] = PROP_NONE();
209 rCategory
.m_aLabels
[u
"BusinessAuthorizationCategory:Locator"_ustr
] = PROP_NONE();
210 rCategory
.m_aLabels
[u
"BusinessAuthorization:Locator"_ustr
] = PROP_NONE();
211 rCategory
.m_aLabels
[u
"MarkingPrecedence"_ustr
] = PROP_NONE();
212 rCategory
.m_aLabels
[u
"Marking:general-summary"_ustr
].clear();
213 rCategory
.m_aLabels
[u
"Marking:general-warning-statement"_ustr
].clear();
214 rCategory
.m_aLabels
[u
"Marking:general-warning-statement:ext:2"_ustr
].clear();
215 rCategory
.m_aLabels
[u
"Marking:general-warning-statement:ext:3"_ustr
].clear();
216 rCategory
.m_aLabels
[u
"Marking:general-warning-statement:ext:4"_ustr
].clear();
217 rCategory
.m_aLabels
[u
"Marking:general-distribution-statement"_ustr
].clear();
218 rCategory
.m_aLabels
[u
"Marking:general-distribution-statement:ext:2"_ustr
].clear();
219 rCategory
.m_aLabels
[u
"Marking:general-distribution-statement:ext:3"_ustr
].clear();
220 rCategory
.m_aLabels
[u
"Marking:general-distribution-statement:ext:4"_ustr
].clear();
221 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCHEADER()].clear();
222 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCFOOTER()].clear();
223 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCWATERMARK()].clear();
224 rCategory
.m_aLabels
[u
"Marking:email-first-line-of-text"_ustr
].clear();
225 rCategory
.m_aLabels
[u
"Marking:email-last-line-of-text"_ustr
].clear();
226 rCategory
.m_aLabels
[u
"Marking:email-subject-prefix"_ustr
].clear();
227 rCategory
.m_aLabels
[u
"Marking:email-subject-suffix"_ustr
].clear();
228 rCategory
.m_aLabels
[PROP_STARTVALIDITY()] = PROP_NONE();
229 rCategory
.m_aLabels
[u
"Authorization:StopValidity"_ustr
] = PROP_NONE();
230 m_pCategory
= &rCategory
;
233 else if (rName
== "loext:Marking")
235 OUString aName
= xAttribs
->getValueByName(u
"Name"_ustr
);
236 m_aMarkings
.push_back(aName
);
238 else if (rName
== "loext:IntellectualPropertyPart")
240 OUString aName
= xAttribs
->getValueByName(u
"Name"_ustr
);
241 m_aIPParts
.push_back(aName
);
243 else if (rName
== "loext:IntellectualPropertyPartNumber")
245 OUString aName
= xAttribs
->getValueByName(u
"Name"_ustr
);
246 m_aIPPartNumbers
.push_back(aName
);
248 else if (rName
== "baf:Scale")
253 else if (rName
== "baf:ConfidentalityValue")
255 m_aConfidentalityValue
.clear();
256 m_bInConfidentalityValue
= true;
258 else if (rName
== "baf:Identifier")
260 m_aIdentifier
.clear();
261 m_bInIdentifier
= true;
263 else if (rName
== "baf:Value")
270 void SAL_CALL
SfxClassificationParser::endElement(const OUString
& rName
)
272 if (rName
== "baf:PolicyAuthorityName")
273 m_bInPolicyAuthorityName
= false;
274 else if (rName
== "baf:PolicyName")
275 m_bInPolicyName
= false;
276 else if (rName
== "baf:ProgramID")
277 m_bInProgramID
= false;
278 else if (rName
== "baf:BusinessAuthorizationCategory")
279 m_pCategory
= nullptr;
280 else if (rName
== "baf:Scale")
284 m_pCategory
->m_aLabels
[PROP_IMPACTSCALE()] = m_aScale
;
286 else if (rName
== "baf:ConfidentalityValue")
288 m_bInConfidentalityValue
= false;
291 std::map
<OUString
, OUString
>& rLabels
= m_pCategory
->m_aLabels
;
292 rLabels
[PROP_IMPACTLEVEL()] = m_aConfidentalityValue
;
293 m_pCategory
->m_nConfidentiality
= m_aConfidentalityValue
.toInt32(); // 0-based class sensitivity; 0 is lowest.
294 // Set the two other type of levels as well, if they're not set
295 // yet: they're optional in BAF, but not in BAILS.
296 rLabels
.try_emplace(u
"Impact:Level:Integrity"_ustr
, m_aConfidentalityValue
);
297 rLabels
.try_emplace(u
"Impact:Level:Availability"_ustr
, m_aConfidentalityValue
);
300 else if (rName
== "baf:Identifier")
301 m_bInIdentifier
= false;
302 else if (rName
== "baf:Value")
306 if (m_aIdentifier
== "Document: Header")
307 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCHEADER()] = m_aValue
;
308 else if (m_aIdentifier
== "Document: Footer")
309 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCFOOTER()] = m_aValue
;
310 else if (m_aIdentifier
== "Document: Watermark")
311 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCWATERMARK()] = m_aValue
;
316 void SAL_CALL
SfxClassificationParser::characters(const OUString
& rChars
)
318 if (m_bInPolicyAuthorityName
)
319 m_aPolicyAuthorityName
+= rChars
;
320 else if (m_bInPolicyName
)
321 m_aPolicyName
+= rChars
;
322 else if (m_bInProgramID
)
323 m_aProgramID
+= rChars
;
326 else if (m_bInConfidentalityValue
)
327 m_aConfidentalityValue
+= rChars
;
328 else if (m_bInIdentifier
)
329 m_aIdentifier
+= rChars
;
334 void SAL_CALL
SfxClassificationParser::ignorableWhitespace(const OUString
& /*rWhitespace*/)
338 void SAL_CALL
SfxClassificationParser::processingInstruction(const OUString
& /*rTarget*/, const OUString
& /*rData*/)
342 void SAL_CALL
SfxClassificationParser::setDocumentLocator(const uno::Reference
<xml::sax::XLocator
>& /*xLocator*/)
346 } // anonymous namespace
348 /// Implementation details of SfxClassificationHelper.
349 class SfxClassificationHelper::Impl
352 /// Selected categories, one category for each policy type.
353 std::map
<SfxClassificationPolicyType
, SfxClassificationCategory
> m_aCategory
;
354 /// Possible categories of a policy to choose from.
355 std::vector
<SfxClassificationCategory
> m_aCategories
;
356 std::vector
<OUString
> m_aMarkings
;
357 std::vector
<OUString
> m_aIPParts
;
358 std::vector
<OUString
> m_aIPPartNumbers
;
360 uno::Reference
<document::XDocumentProperties
> m_xDocumentProperties
;
362 bool m_bUseLocalized
;
364 explicit Impl(uno::Reference
<document::XDocumentProperties
> xDocumentProperties
, bool bUseLocalized
);
366 /// Synchronize m_aLabels back to the document properties.
367 void pushToDocumentProperties();
368 /// Set the classification start date to the system time.
369 void setStartValidity(SfxClassificationPolicyType eType
);
372 SfxClassificationHelper::Impl::Impl(uno::Reference
<document::XDocumentProperties
> xDocumentProperties
, bool bUseLocalized
)
373 : m_xDocumentProperties(std::move(xDocumentProperties
))
374 , m_bUseLocalized(bUseLocalized
)
379 void SfxClassificationHelper::Impl::parsePolicy()
381 const uno::Reference
<uno::XComponentContext
>& xComponentContext
= comphelper::getProcessComponentContext();
382 SvtPathOptions aOptions
;
383 OUString aPath
= aOptions
.GetClassificationPath();
385 // See if there is a localized variant next to the configured XML.
386 OUString
aExtension(u
".xml"_ustr
);
387 if (aPath
.endsWith(aExtension
) && m_bUseLocalized
)
389 std::u16string_view aBase
= aPath
.subView(0, aPath
.getLength() - aExtension
.getLength());
390 const LanguageTag
& rLanguageTag
= Application::GetSettings().GetLanguageTag();
391 // Expected format is "<original path>_xx-XX.xml".
392 OUString aLocalized
= OUString::Concat(aBase
) + "_" + rLanguageTag
.getBcp47() + aExtension
;
393 if (FStatHelper::IsDocument(aLocalized
))
397 xml::sax::InputSource aParserInput
;
398 std::unique_ptr
<SvStream
> pStream
= utl::UcbStreamHelper::CreateStream(aPath
, StreamMode::READ
);
399 aParserInput
.aInputStream
.set(new utl::OStreamWrapper(std::move(pStream
)));
401 uno::Reference
<xml::sax::XParser
> xParser
= xml::sax::Parser::create(xComponentContext
);
402 rtl::Reference
<SfxClassificationParser
> xClassificationParser(new SfxClassificationParser());
403 xParser
->setDocumentHandler(xClassificationParser
);
406 xParser
->parseStream(aParserInput
);
408 catch (const xml::sax::SAXParseException
&)
410 TOOLS_WARN_EXCEPTION("sfx.view", "parsePolicy() failed");
412 m_aCategories
= xClassificationParser
->m_aCategories
;
413 m_aMarkings
= xClassificationParser
->m_aMarkings
;
414 m_aIPParts
= xClassificationParser
->m_aIPParts
;
415 m_aIPPartNumbers
= xClassificationParser
->m_aIPPartNumbers
;
418 static bool lcl_containsProperty(const uno::Sequence
<beans::Property
>& rProperties
, std::u16string_view rName
)
420 return std::any_of(rProperties
.begin(), rProperties
.end(), [&](const beans::Property
& rProperty
)
422 return rProperty
.Name
== rName
;
426 void SfxClassificationHelper::Impl::setStartValidity(SfxClassificationPolicyType eType
)
428 auto itCategory
= m_aCategory
.find(eType
);
429 if (itCategory
== m_aCategory
.end())
432 SfxClassificationCategory
& rCategory
= itCategory
->second
;
433 auto it
= rCategory
.m_aLabels
.find(policyTypeToString(eType
) + PROP_STARTVALIDITY());
434 if (it
!= rCategory
.m_aLabels
.end())
436 if (it
->second
== PROP_NONE())
438 // The policy left the start date unchanged, replace it with the system time.
439 util::DateTime aDateTime
= DateTime(DateTime::SYSTEM
).GetUNODateTime();
440 it
->second
= utl::toISO8601(aDateTime
);
445 void SfxClassificationHelper::Impl::pushToDocumentProperties()
447 uno::Reference
<beans::XPropertyContainer
> xPropertyContainer
= m_xDocumentProperties
->getUserDefinedProperties();
448 uno::Reference
<beans::XPropertySet
> xPropertySet(xPropertyContainer
, uno::UNO_QUERY
);
449 uno::Sequence
<beans::Property
> aProperties
= xPropertySet
->getPropertySetInfo()->getProperties();
450 for (auto& rPair
: m_aCategory
)
452 SfxClassificationPolicyType eType
= rPair
.first
;
453 SfxClassificationCategory
& rCategory
= rPair
.second
;
454 std::map
<OUString
, OUString
> aLabels
= rCategory
.m_aLabels
;
455 aLabels
[policyTypeToString(eType
) + PROP_BACNAME()] = rCategory
.m_aName
;
456 for (const auto& rLabel
: aLabels
)
460 if (lcl_containsProperty(aProperties
, rLabel
.first
))
461 xPropertySet
->setPropertyValue(rLabel
.first
, uno::Any(rLabel
.second
));
463 xPropertyContainer
->addProperty(rLabel
.first
, beans::PropertyAttribute::REMOVABLE
, uno::Any(rLabel
.second
));
465 catch (const uno::Exception
&)
467 TOOLS_WARN_EXCEPTION("sfx.view", "pushDocumentProperties() failed for property " << rLabel
.first
);
473 bool SfxClassificationHelper::IsClassified(const uno::Reference
<document::XDocumentProperties
>& xDocumentProperties
)
475 uno::Reference
<beans::XPropertyContainer
> xPropertyContainer
= xDocumentProperties
->getUserDefinedProperties();
476 if (!xPropertyContainer
.is())
479 uno::Reference
<beans::XPropertySet
> xPropertySet(xPropertyContainer
, uno::UNO_QUERY
);
480 const uno::Sequence
<beans::Property
> aProperties
= xPropertySet
->getPropertySetInfo()->getProperties();
481 for (const beans::Property
& rProperty
: aProperties
)
483 if (rProperty
.Name
.startsWith("urn:bails:"))
490 SfxClassificationCheckPasteResult
SfxClassificationHelper::CheckPaste(const uno::Reference
<document::XDocumentProperties
>& xSource
,
491 const uno::Reference
<document::XDocumentProperties
>& xDestination
)
493 if (!SfxClassificationHelper::IsClassified(xSource
))
494 // No classification on the source side. Return early, regardless the
495 // state of the destination side.
496 return SfxClassificationCheckPasteResult::None
;
498 if (!SfxClassificationHelper::IsClassified(xDestination
))
500 // Paste from a classified document to a non-classified one -> deny.
501 return SfxClassificationCheckPasteResult::TargetDocNotClassified
;
504 // Remaining case: paste between two classified documents.
505 SfxClassificationHelper
aSource(xSource
);
506 SfxClassificationHelper
aDestination(xDestination
);
507 if (aSource
.GetImpactScale() != aDestination
.GetImpactScale())
508 // It's possible to compare them if they have the same scale.
509 return SfxClassificationCheckPasteResult::None
;
511 if (aSource
.GetImpactLevel() > aDestination
.GetImpactLevel())
512 // Paste from a doc that has higher classification -> deny.
513 return SfxClassificationCheckPasteResult::DocClassificationTooLow
;
515 return SfxClassificationCheckPasteResult::None
;
518 bool SfxClassificationHelper::ShowPasteInfo(SfxClassificationCheckPasteResult eResult
)
522 case SfxClassificationCheckPasteResult::None
:
527 case SfxClassificationCheckPasteResult::TargetDocNotClassified
:
529 if (!Application::IsHeadlessModeEnabled())
531 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(nullptr,
532 VclMessageType::Info
, VclButtonsType::Ok
,
533 SfxResId(STR_TARGET_DOC_NOT_CLASSIFIED
)));
539 case SfxClassificationCheckPasteResult::DocClassificationTooLow
:
541 if (!Application::IsHeadlessModeEnabled())
543 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(nullptr,
544 VclMessageType::Info
, VclButtonsType::Ok
,
545 SfxResId(STR_DOC_CLASSIFICATION_TOO_LOW
)));
556 SfxClassificationHelper::SfxClassificationHelper(const uno::Reference
<document::XDocumentProperties
>& xDocumentProperties
, bool bUseLocalizedPolicy
)
557 : m_pImpl(std::make_unique
<Impl
>(xDocumentProperties
, bUseLocalizedPolicy
))
559 if (!xDocumentProperties
.is())
562 uno::Reference
<beans::XPropertyContainer
> xPropertyContainer
= xDocumentProperties
->getUserDefinedProperties();
563 if (!xPropertyContainer
.is())
566 uno::Reference
<beans::XPropertySet
> xPropertySet(xPropertyContainer
, uno::UNO_QUERY
);
567 const uno::Sequence
<beans::Property
> aProperties
= xPropertySet
->getPropertySetInfo()->getProperties();
568 for (const beans::Property
& rProperty
: aProperties
)
570 if (!rProperty
.Name
.startsWith("urn:bails:"))
573 uno::Any aAny
= xPropertySet
->getPropertyValue(rProperty
.Name
);
577 SfxClassificationPolicyType eType
= stringToPolicyType(rProperty
.Name
);
578 OUString aPrefix
= policyTypeToString(eType
);
579 if (!rProperty
.Name
.startsWith(aPrefix
))
580 // It's a prefix we did not recognize, ignore.
583 //TODO: Support abbreviated names(?)
584 if (rProperty
.Name
== Concat2View(aPrefix
+ PROP_BACNAME()))
585 m_pImpl
->m_aCategory
[eType
].m_aName
= aValue
;
587 m_pImpl
->m_aCategory
[eType
].m_aLabels
[rProperty
.Name
] = aValue
;
592 SfxClassificationHelper::~SfxClassificationHelper() = default;
594 std::vector
<OUString
> const & SfxClassificationHelper::GetMarkings() const
596 return m_pImpl
->m_aMarkings
;
599 std::vector
<OUString
> const & SfxClassificationHelper::GetIntellectualPropertyParts() const
601 return m_pImpl
->m_aIPParts
;
604 std::vector
<OUString
> const & SfxClassificationHelper::GetIntellectualPropertyPartNumbers() const
606 return m_pImpl
->m_aIPPartNumbers
;
609 const OUString
& SfxClassificationHelper::GetBACName(SfxClassificationPolicyType eType
) const
611 return m_pImpl
->m_aCategory
[eType
].m_aName
;
614 const OUString
& SfxClassificationHelper::GetAbbreviatedBACName(const OUString
& sFullName
)
616 for (const auto& category
: m_pImpl
->m_aCategories
)
618 if (category
.m_aName
== sFullName
)
619 return category
.m_aAbbreviatedName
;
625 OUString
SfxClassificationHelper::GetBACNameForIdentifier(std::u16string_view sIdentifier
)
627 if (sIdentifier
.empty())
630 for (const auto& category
: m_pImpl
->m_aCategories
)
632 if (category
.m_aIdentifier
== sIdentifier
)
633 return category
.m_aName
;
639 OUString
SfxClassificationHelper::GetHigherClass(const OUString
& first
, const OUString
& second
)
641 size_t nFirstConfidentiality
= 0;
642 size_t nSecondConfidentiality
= 0;
643 for (const auto& category
: m_pImpl
->m_aCategories
)
645 if (category
.m_aName
== first
)
646 nFirstConfidentiality
= category
.m_nConfidentiality
;
647 if (category
.m_aName
== second
)
648 nSecondConfidentiality
= category
.m_nConfidentiality
;
651 return nFirstConfidentiality
>= nSecondConfidentiality
? first
: second
;
654 bool SfxClassificationHelper::HasImpactLevel()
656 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
657 if (itCategory
== m_pImpl
->m_aCategory
.end())
660 SfxClassificationCategory
& rCategory
= itCategory
->second
;
661 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
662 if (it
== rCategory
.m_aLabels
.end())
665 it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
666 return it
!= rCategory
.m_aLabels
.end();
669 bool SfxClassificationHelper::HasDocumentHeader()
671 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
672 if (itCategory
== m_pImpl
->m_aCategory
.end())
675 SfxClassificationCategory
& rCategory
= itCategory
->second
;
676 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCHEADER());
677 return it
!= rCategory
.m_aLabels
.end() && !it
->second
.isEmpty();
680 bool SfxClassificationHelper::HasDocumentFooter()
682 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
683 if (itCategory
== m_pImpl
->m_aCategory
.end())
686 SfxClassificationCategory
& rCategory
= itCategory
->second
;
687 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCFOOTER());
688 return it
!= rCategory
.m_aLabels
.end() && !it
->second
.isEmpty();
691 InfobarType
SfxClassificationHelper::GetImpactLevelType()
695 aRet
= InfobarType::WARNING
;
697 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
698 if (itCategory
== m_pImpl
->m_aCategory
.end())
701 SfxClassificationCategory
& rCategory
= itCategory
->second
;
702 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
703 if (it
== rCategory
.m_aLabels
.end())
705 OUString aScale
= it
->second
;
707 it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
708 if (it
== rCategory
.m_aLabels
.end())
710 OUString aLevel
= it
->second
;
712 // The spec defines two valid scale values: FIPS-199 and UK-Cabinet.
713 if (aScale
== "UK-Cabinet")
716 aRet
= InfobarType::SUCCESS
;
717 else if (aLevel
== "1")
718 aRet
= InfobarType::WARNING
;
719 else if (aLevel
== "2")
720 aRet
= InfobarType::WARNING
;
721 else if (aLevel
== "3")
722 aRet
= InfobarType::DANGER
;
724 else if (aScale
== "FIPS-199")
727 aRet
= InfobarType::SUCCESS
;
728 else if (aLevel
== "Moderate")
729 aRet
= InfobarType::WARNING
;
730 else if (aLevel
== "High")
731 aRet
= InfobarType::DANGER
;
736 sal_Int32
SfxClassificationHelper::GetImpactLevel()
740 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
741 if (itCategory
== m_pImpl
->m_aCategory
.end())
744 SfxClassificationCategory
& rCategory
= itCategory
->second
;
745 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
746 if (it
== rCategory
.m_aLabels
.end())
748 OUString aScale
= it
->second
;
750 it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
751 if (it
== rCategory
.m_aLabels
.end())
753 OUString aLevel
= it
->second
;
755 if (aScale
== "UK-Cabinet")
757 sal_Int32 nValue
= aLevel
.toInt32();
758 if (nValue
< 0 || nValue
> 3)
762 else if (aScale
== "FIPS-199")
764 static std::map
<OUString
, sal_Int32
> const aValues
770 auto itValues
= aValues
.find(aLevel
);
771 if (itValues
== aValues
.end())
773 nRet
= itValues
->second
;
779 OUString
SfxClassificationHelper::GetImpactScale()
781 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
782 if (itCategory
== m_pImpl
->m_aCategory
.end())
785 SfxClassificationCategory
& rCategory
= itCategory
->second
;
786 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
787 if (it
!= rCategory
.m_aLabels
.end())
793 OUString
SfxClassificationHelper::GetDocumentWatermark()
795 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
796 if (itCategory
== m_pImpl
->m_aCategory
.end())
799 SfxClassificationCategory
& rCategory
= itCategory
->second
;
800 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCWATERMARK());
801 if (it
!= rCategory
.m_aLabels
.end())
807 std::vector
<OUString
> SfxClassificationHelper::GetBACNames()
809 if (m_pImpl
->m_aCategories
.empty())
810 m_pImpl
->parsePolicy();
812 std::vector
<OUString
> aRet
;
813 std::transform(m_pImpl
->m_aCategories
.begin(), m_pImpl
->m_aCategories
.end(), std::back_inserter(aRet
), [](const SfxClassificationCategory
& rCategory
)
815 return rCategory
.m_aName
;
820 std::vector
<OUString
> SfxClassificationHelper::GetBACIdentifiers()
822 if (m_pImpl
->m_aCategories
.empty())
823 m_pImpl
->parsePolicy();
825 std::vector
<OUString
> aRet
;
826 std::transform(m_pImpl
->m_aCategories
.begin(), m_pImpl
->m_aCategories
.end(), std::back_inserter(aRet
), [](const SfxClassificationCategory
& rCategory
)
828 return rCategory
.m_aIdentifier
;
833 std::vector
<OUString
> SfxClassificationHelper::GetAbbreviatedBACNames()
835 if (m_pImpl
->m_aCategories
.empty())
836 m_pImpl
->parsePolicy();
838 std::vector
<OUString
> aRet
;
839 std::transform(m_pImpl
->m_aCategories
.begin(), m_pImpl
->m_aCategories
.end(), std::back_inserter(aRet
), [](const SfxClassificationCategory
& rCategory
)
841 return rCategory
.m_aAbbreviatedName
;
846 void SfxClassificationHelper::SetBACName(const OUString
& rName
, SfxClassificationPolicyType eType
)
848 if (m_pImpl
->m_aCategories
.empty())
849 m_pImpl
->parsePolicy();
851 auto it
= std::find_if(m_pImpl
->m_aCategories
.begin(), m_pImpl
->m_aCategories
.end(), [&](const SfxClassificationCategory
& rCategory
)
853 return rCategory
.m_aName
== rName
;
855 if (it
== m_pImpl
->m_aCategories
.end())
857 SAL_WARN("sfx.view", "'" << rName
<< "' is not a recognized category name");
861 m_pImpl
->m_aCategory
[eType
].m_aName
= it
->m_aName
;
862 m_pImpl
->m_aCategory
[eType
].m_aAbbreviatedName
= it
->m_aAbbreviatedName
;
863 m_pImpl
->m_aCategory
[eType
].m_nConfidentiality
= it
->m_nConfidentiality
;
864 m_pImpl
->m_aCategory
[eType
].m_aLabels
.clear();
865 const OUString
& rPrefix
= policyTypeToString(eType
);
866 for (const auto& rLabel
: it
->m_aLabels
)
867 m_pImpl
->m_aCategory
[eType
].m_aLabels
[rPrefix
+ rLabel
.first
] = rLabel
.second
;
869 m_pImpl
->setStartValidity(eType
);
870 m_pImpl
->pushToDocumentProperties();
871 SfxViewFrame
* pViewFrame
= SfxViewFrame::Current();
875 UpdateInfobar(*pViewFrame
);
878 void SfxClassificationHelper::UpdateInfobar(SfxViewFrame
& rViewFrame
)
880 OUString aBACName
= GetBACName(SfxClassificationPolicyType::IntellectualProperty
);
881 bool bImpactLevel
= HasImpactLevel();
882 if (!aBACName
.isEmpty() && bImpactLevel
)
884 OUString aMessage
= SfxResId(STR_CLASSIFIED_DOCUMENT
);
885 aMessage
= aMessage
.replaceFirst("%1", aBACName
);
887 rViewFrame
.RemoveInfoBar(u
"classification");
888 rViewFrame
.AppendInfoBar(u
"classification"_ustr
, u
""_ustr
, aMessage
, GetImpactLevelType());
892 SfxClassificationPolicyType
SfxClassificationHelper::stringToPolicyType(std::u16string_view rType
)
894 if (o3tl::starts_with(rType
, PROP_PREFIX_EXPORTCONTROL()))
895 return SfxClassificationPolicyType::ExportControl
;
896 else if (o3tl::starts_with(rType
, PROP_PREFIX_NATIONALSECURITY()))
897 return SfxClassificationPolicyType::NationalSecurity
;
899 return SfxClassificationPolicyType::IntellectualProperty
;
902 const OUString
& SfxClassificationHelper::policyTypeToString(SfxClassificationPolicyType eType
)
906 case SfxClassificationPolicyType::ExportControl
:
907 return PROP_PREFIX_EXPORTCONTROL();
908 case SfxClassificationPolicyType::NationalSecurity
:
909 return PROP_PREFIX_NATIONALSECURITY();
910 case SfxClassificationPolicyType::IntellectualProperty
:
914 return PROP_PREFIX_INTELLECTUALPROPERTY();
917 const OUString
& SfxClassificationHelper::PROP_DOCHEADER()
919 static constexpr OUString
sProp(u
"Marking:document-header"_ustr
);
923 const OUString
& SfxClassificationHelper::PROP_DOCFOOTER()
925 static constexpr OUString
sProp(u
"Marking:document-footer"_ustr
);
929 const OUString
& SfxClassificationHelper::PROP_DOCWATERMARK()
931 static constexpr OUString
sProp(u
"Marking:document-watermark"_ustr
);
935 const OUString
& SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY()
937 static constexpr OUString
sProp(u
"urn:bails:IntellectualProperty:"_ustr
);
941 SfxClassificationPolicyType
SfxClassificationHelper::getPolicyType()
943 if (comphelper::IsFuzzing())
944 return SfxClassificationPolicyType::IntellectualProperty
;
945 sal_Int32 nPolicyTypeNumber
= officecfg::Office::Common::Classification::Policy::get();
946 auto eType
= static_cast<SfxClassificationPolicyType
>(nPolicyTypeNumber
);
956 OUString
getProperty(uno::Reference
<beans::XPropertyContainer
> const& rxPropertyContainer
,
957 OUString
const& rName
)
961 uno::Reference
<beans::XPropertySet
> xPropertySet(rxPropertyContainer
, uno::UNO_QUERY
);
962 return xPropertySet
->getPropertyValue(rName
).get
<OUString
>();
964 catch (const css::uno::Exception
&)
971 } // end anonymous namespace
973 sfx::ClassificationCreationOrigin
getCreationOriginProperty(uno::Reference
<beans::XPropertyContainer
> const & rxPropertyContainer
,
974 sfx::ClassificationKeyCreator
const & rKeyCreator
)
976 OUString sValue
= getProperty(rxPropertyContainer
, rKeyCreator
.makeCreationOriginKey());
977 if (sValue
.isEmpty())
978 return sfx::ClassificationCreationOrigin::NONE
;
980 return (sValue
== "BAF_POLICY")
981 ? sfx::ClassificationCreationOrigin::BAF_POLICY
982 : sfx::ClassificationCreationOrigin::MANUAL
;
987 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */