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/pathoptions.hxx>
30 #include <unotools/ucbstreamhelper.hxx>
31 #include <unotools/streamwrap.hxx>
32 #include <cppuhelper/implbase.hxx>
33 #include <sfx2/strings.hrc>
34 #include <sfx2/sfxresid.hxx>
35 #include <sfx2/viewfrm.hxx>
36 #include <tools/datetime.hxx>
37 #include <tools/diagnose_ex.h>
38 #include <unotools/datetime.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/settings.hxx>
41 #include <vcl/weld.hxx>
42 #include <svl/fstathelper.hxx>
44 #include <o3tl/string_view.hxx>
45 #include <officecfg/Office/Common.hxx>
47 using namespace com::sun::star
;
52 const OUString
& PROP_BACNAME()
54 static const OUString
sProp("BusinessAuthorizationCategory:Name");
58 const OUString
& PROP_STARTVALIDITY()
60 static const OUString
sProp("Authorization:StartValidity");
64 const OUString
& PROP_NONE()
66 static const OUString
sProp("None");
70 const OUString
& PROP_IMPACTSCALE()
72 static const OUString
sProp("Impact:Scale");
76 const OUString
& PROP_IMPACTLEVEL()
78 static const OUString
sProp("Impact:Level:Confidentiality");
82 const OUString
& PROP_PREFIX_EXPORTCONTROL()
84 static const OUString
sProp("urn:bails:ExportControl:");
88 const OUString
& PROP_PREFIX_NATIONALSECURITY()
90 static const OUString
sProp("urn:bails:NationalSecurity:");
94 /// Represents one category of a classification policy.
95 class SfxClassificationCategory
98 /// PROP_BACNAME() is stored separately for easier lookup.
100 OUString m_aAbbreviatedName
; //< An abbreviation to display instead of m_aName.
101 OUString m_aIdentifier
; //< The Identifier of this entry.
102 size_t m_nConfidentiality
; //< 0 is the lowest (least-sensitive).
103 std::map
<OUString
, OUString
> m_aLabels
;
106 /// Parses a policy XML conforming to the TSCP BAF schema.
107 class SfxClassificationParser
: public cppu::WeakImplHelper
<xml::sax::XDocumentHandler
>
110 std::vector
<SfxClassificationCategory
> m_aCategories
;
111 std::vector
<OUString
> m_aMarkings
;
112 std::vector
<OUString
> m_aIPParts
;
113 std::vector
<OUString
> m_aIPPartNumbers
;
115 OUString m_aPolicyAuthorityName
;
116 bool m_bInPolicyAuthorityName
= false;
117 OUString m_aPolicyName
;
118 bool m_bInPolicyName
= false;
119 OUString m_aProgramID
;
120 bool m_bInProgramID
= false;
122 bool m_bInScale
= false;
123 OUString m_aConfidentalityValue
;
124 bool m_bInConfidentalityValue
= false;
125 OUString m_aIdentifier
;
126 bool m_bInIdentifier
= false;
128 bool m_bInValue
= false;
130 /// Pointer to a value in m_aCategories, the currently parsed category.
131 SfxClassificationCategory
* m_pCategory
= nullptr;
133 SfxClassificationParser();
135 void SAL_CALL
startDocument() override
;
137 void SAL_CALL
endDocument() override
;
139 void SAL_CALL
startElement(const OUString
& rName
, const uno::Reference
<xml::sax::XAttributeList
>& xAttribs
) override
;
141 void SAL_CALL
endElement(const OUString
& rName
) override
;
143 void SAL_CALL
characters(const OUString
& rChars
) override
;
145 void SAL_CALL
ignorableWhitespace(const OUString
& rWhitespaces
) override
;
147 void SAL_CALL
processingInstruction(const OUString
& rTarget
, const OUString
& rData
) override
;
149 void SAL_CALL
setDocumentLocator(const uno::Reference
<xml::sax::XLocator
>& xLocator
) override
;
152 SfxClassificationParser::SfxClassificationParser() = default;
154 void SAL_CALL
SfxClassificationParser::startDocument()
158 void SAL_CALL
SfxClassificationParser::endDocument()
162 void SAL_CALL
SfxClassificationParser::startElement(const OUString
& rName
, const uno::Reference
<xml::sax::XAttributeList
>& xAttribs
)
164 if (rName
== "baf:PolicyAuthorityName")
166 m_aPolicyAuthorityName
.clear();
167 m_bInPolicyAuthorityName
= true;
169 else if (rName
== "baf:PolicyName")
171 m_aPolicyName
.clear();
172 m_bInPolicyName
= true;
174 else if (rName
== "baf:ProgramID")
176 m_aProgramID
.clear();
177 m_bInProgramID
= true;
179 else if (rName
== "baf:BusinessAuthorizationCategory")
181 const OUString aName
= xAttribs
->getValueByName("Name");
182 if (!m_pCategory
&& !aName
.isEmpty())
184 OUString aIdentifier
= xAttribs
->getValueByName("Identifier");
186 // Create a new category and initialize it with the data that's true for all categories.
187 m_aCategories
.emplace_back();
188 SfxClassificationCategory
& rCategory
= m_aCategories
.back();
190 rCategory
.m_aName
= aName
;
191 // Set the abbreviated name, if any, otherwise fallback on the full name.
192 const OUString aAbbreviatedName
= xAttribs
->getValueByName("loextAbbreviatedName");
193 rCategory
.m_aAbbreviatedName
= !aAbbreviatedName
.isEmpty() ? aAbbreviatedName
: aName
;
194 rCategory
.m_aIdentifier
= aIdentifier
;
196 rCategory
.m_aLabels
["PolicyAuthority:Name"] = m_aPolicyAuthorityName
;
197 rCategory
.m_aLabels
["Policy:Name"] = m_aPolicyName
;
198 rCategory
.m_aLabels
["BusinessAuthorization:Identifier"] = m_aProgramID
;
199 rCategory
.m_aLabels
["BusinessAuthorizationCategory:Identifier"] = aIdentifier
;
201 // Also initialize defaults.
202 rCategory
.m_aLabels
["PolicyAuthority:Identifier"] = PROP_NONE();
203 rCategory
.m_aLabels
["PolicyAuthority:Country"] = PROP_NONE();
204 rCategory
.m_aLabels
["Policy:Identifier"] = PROP_NONE();
205 rCategory
.m_aLabels
["BusinessAuthorization:Name"] = PROP_NONE();
206 rCategory
.m_aLabels
["BusinessAuthorization:Locator"] = PROP_NONE();
207 rCategory
.m_aLabels
["BusinessAuthorizationCategory:Identifier:OID"] = PROP_NONE();
208 rCategory
.m_aLabels
["BusinessAuthorizationCategory:Locator"] = PROP_NONE();
209 rCategory
.m_aLabels
["BusinessAuthorization:Locator"] = PROP_NONE();
210 rCategory
.m_aLabels
["MarkingPrecedence"] = PROP_NONE();
211 rCategory
.m_aLabels
["Marking:general-summary"].clear();
212 rCategory
.m_aLabels
["Marking:general-warning-statement"].clear();
213 rCategory
.m_aLabels
["Marking:general-warning-statement:ext:2"].clear();
214 rCategory
.m_aLabels
["Marking:general-warning-statement:ext:3"].clear();
215 rCategory
.m_aLabels
["Marking:general-warning-statement:ext:4"].clear();
216 rCategory
.m_aLabels
["Marking:general-distribution-statement"].clear();
217 rCategory
.m_aLabels
["Marking:general-distribution-statement:ext:2"].clear();
218 rCategory
.m_aLabels
["Marking:general-distribution-statement:ext:3"].clear();
219 rCategory
.m_aLabels
["Marking:general-distribution-statement:ext:4"].clear();
220 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCHEADER()].clear();
221 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCFOOTER()].clear();
222 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCWATERMARK()].clear();
223 rCategory
.m_aLabels
["Marking:email-first-line-of-text"].clear();
224 rCategory
.m_aLabels
["Marking:email-last-line-of-text"].clear();
225 rCategory
.m_aLabels
["Marking:email-subject-prefix"].clear();
226 rCategory
.m_aLabels
["Marking:email-subject-suffix"].clear();
227 rCategory
.m_aLabels
[PROP_STARTVALIDITY()] = PROP_NONE();
228 rCategory
.m_aLabels
["Authorization:StopValidity"] = PROP_NONE();
229 m_pCategory
= &rCategory
;
232 else if (rName
== "loext:Marking")
234 OUString aName
= xAttribs
->getValueByName("Name");
235 m_aMarkings
.push_back(aName
);
237 else if (rName
== "loext:IntellectualPropertyPart")
239 OUString aName
= xAttribs
->getValueByName("Name");
240 m_aIPParts
.push_back(aName
);
242 else if (rName
== "loext:IntellectualPropertyPartNumber")
244 OUString aName
= xAttribs
->getValueByName("Name");
245 m_aIPPartNumbers
.push_back(aName
);
247 else if (rName
== "baf:Scale")
252 else if (rName
== "baf:ConfidentalityValue")
254 m_aConfidentalityValue
.clear();
255 m_bInConfidentalityValue
= true;
257 else if (rName
== "baf:Identifier")
259 m_aIdentifier
.clear();
260 m_bInIdentifier
= true;
262 else if (rName
== "baf:Value")
269 void SAL_CALL
SfxClassificationParser::endElement(const OUString
& rName
)
271 if (rName
== "baf:PolicyAuthorityName")
272 m_bInPolicyAuthorityName
= false;
273 else if (rName
== "baf:PolicyName")
274 m_bInPolicyName
= false;
275 else if (rName
== "baf:ProgramID")
276 m_bInProgramID
= false;
277 else if (rName
== "baf:BusinessAuthorizationCategory")
278 m_pCategory
= nullptr;
279 else if (rName
== "baf:Scale")
283 m_pCategory
->m_aLabels
[PROP_IMPACTSCALE()] = m_aScale
;
285 else if (rName
== "baf:ConfidentalityValue")
287 m_bInConfidentalityValue
= false;
290 std::map
<OUString
, OUString
>& rLabels
= m_pCategory
->m_aLabels
;
291 rLabels
[PROP_IMPACTLEVEL()] = m_aConfidentalityValue
;
292 m_pCategory
->m_nConfidentiality
= m_aConfidentalityValue
.toInt32(); // 0-based class sensitivity; 0 is lowest.
293 // Set the two other type of levels as well, if they're not set
294 // yet: they're optional in BAF, but not in BAILS.
295 rLabels
.try_emplace("Impact:Level:Integrity", m_aConfidentalityValue
);
296 rLabels
.try_emplace("Impact:Level:Availability", m_aConfidentalityValue
);
299 else if (rName
== "baf:Identifier")
300 m_bInIdentifier
= false;
301 else if (rName
== "baf:Value")
305 if (m_aIdentifier
== "Document: Header")
306 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCHEADER()] = m_aValue
;
307 else if (m_aIdentifier
== "Document: Footer")
308 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCFOOTER()] = m_aValue
;
309 else if (m_aIdentifier
== "Document: Watermark")
310 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCWATERMARK()] = m_aValue
;
315 void SAL_CALL
SfxClassificationParser::characters(const OUString
& rChars
)
317 if (m_bInPolicyAuthorityName
)
318 m_aPolicyAuthorityName
+= rChars
;
319 else if (m_bInPolicyName
)
320 m_aPolicyName
+= rChars
;
321 else if (m_bInProgramID
)
322 m_aProgramID
+= rChars
;
325 else if (m_bInConfidentalityValue
)
326 m_aConfidentalityValue
+= rChars
;
327 else if (m_bInIdentifier
)
328 m_aIdentifier
+= rChars
;
333 void SAL_CALL
SfxClassificationParser::ignorableWhitespace(const OUString
& /*rWhitespace*/)
337 void SAL_CALL
SfxClassificationParser::processingInstruction(const OUString
& /*rTarget*/, const OUString
& /*rData*/)
341 void SAL_CALL
SfxClassificationParser::setDocumentLocator(const uno::Reference
<xml::sax::XLocator
>& /*xLocator*/)
345 } // anonymous namespace
347 /// Implementation details of SfxClassificationHelper.
348 class SfxClassificationHelper::Impl
351 /// Selected categories, one category for each policy type.
352 std::map
<SfxClassificationPolicyType
, SfxClassificationCategory
> m_aCategory
;
353 /// Possible categories of a policy to choose from.
354 std::vector
<SfxClassificationCategory
> m_aCategories
;
355 std::vector
<OUString
> m_aMarkings
;
356 std::vector
<OUString
> m_aIPParts
;
357 std::vector
<OUString
> m_aIPPartNumbers
;
359 uno::Reference
<document::XDocumentProperties
> m_xDocumentProperties
;
361 bool m_bUseLocalized
;
363 explicit Impl(uno::Reference
<document::XDocumentProperties
> xDocumentProperties
, bool bUseLocalized
);
365 /// Synchronize m_aLabels back to the document properties.
366 void pushToDocumentProperties();
367 /// Set the classification start date to the system time.
368 void setStartValidity(SfxClassificationPolicyType eType
);
371 SfxClassificationHelper::Impl::Impl(uno::Reference
<document::XDocumentProperties
> xDocumentProperties
, bool bUseLocalized
)
372 : m_xDocumentProperties(std::move(xDocumentProperties
))
373 , m_bUseLocalized(bUseLocalized
)
378 void SfxClassificationHelper::Impl::parsePolicy()
380 uno::Reference
<uno::XComponentContext
> xComponentContext
= comphelper::getProcessComponentContext();
381 SvtPathOptions aOptions
;
382 OUString aPath
= aOptions
.GetClassificationPath();
384 // See if there is a localized variant next to the configured XML.
385 OUString
aExtension(".xml");
386 if (aPath
.endsWith(aExtension
) && m_bUseLocalized
)
388 OUString aBase
= aPath
.copy(0, aPath
.getLength() - aExtension
.getLength());
389 const LanguageTag
& rLanguageTag
= Application::GetSettings().GetLanguageTag();
390 // Expected format is "<original path>_xx-XX.xml".
391 OUString aLocalized
= aBase
+ "_" + rLanguageTag
.getBcp47() + aExtension
;
392 if (FStatHelper::IsDocument(aLocalized
))
396 std::unique_ptr
<SvStream
> pStream
= utl::UcbStreamHelper::CreateStream(aPath
, StreamMode::READ
);
397 uno::Reference
<io::XInputStream
> xInputStream(new utl::OStreamWrapper(std::move(pStream
)));
398 xml::sax::InputSource aParserInput
;
399 aParserInput
.aInputStream
= xInputStream
;
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::makeAny(rLabel
.second
));
463 xPropertyContainer
->addProperty(rLabel
.first
, beans::PropertyAttribute::REMOVABLE
, uno::makeAny(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
== OUStringConcatenation(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("classification", "", 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 const OUString
sProp("Marking:document-header");
923 const OUString
& SfxClassificationHelper::PROP_DOCFOOTER()
925 static const OUString
sProp("Marking:document-footer");
929 const OUString
& SfxClassificationHelper::PROP_DOCWATERMARK()
931 static const OUString
sProp("Marking:document-watermark");
935 const OUString
& SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY()
937 static const OUString
sProp("urn:bails:IntellectualProperty:");
941 SfxClassificationPolicyType
SfxClassificationHelper::getPolicyType()
943 sal_Int32 nPolicyTypeNumber
= officecfg::Office::Common::Classification::Policy::get();
944 auto eType
= static_cast<SfxClassificationPolicyType
>(nPolicyTypeNumber
);
954 OUString
getProperty(uno::Reference
<beans::XPropertyContainer
> const& rxPropertyContainer
,
955 OUString
const& rName
)
959 uno::Reference
<beans::XPropertySet
> xPropertySet(rxPropertyContainer
, uno::UNO_QUERY
);
960 return xPropertySet
->getPropertyValue(rName
).get
<OUString
>();
962 catch (const css::uno::Exception
&)
969 } // end anonymous namespace
971 sfx::ClassificationCreationOrigin
getCreationOriginProperty(uno::Reference
<beans::XPropertyContainer
> const & rxPropertyContainer
,
972 sfx::ClassificationKeyCreator
const & rKeyCreator
)
974 OUString sValue
= getProperty(rxPropertyContainer
, rKeyCreator
.makeCreationOriginKey());
975 if (sValue
.isEmpty())
976 return sfx::ClassificationCreationOrigin::NONE
;
978 return (sValue
== "BAF_POLICY")
979 ? sfx::ClassificationCreationOrigin::BAF_POLICY
980 : sfx::ClassificationCreationOrigin::MANUAL
;
985 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */