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/document/XDocumentProperties.hpp>
18 #include <com/sun/star/xml/sax/Parser.hpp>
19 #include <com/sun/star/xml/sax/XDocumentHandler.hpp>
20 #include <com/sun/star/xml/sax/SAXParseException.hpp>
21 #include <com/sun/star/beans/PropertyAttribute.hpp>
23 #include <sfx2/infobar.hxx>
24 #include <sfx2/objsh.hxx>
25 #include <o3tl/make_unique.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <unotools/pathoptions.hxx>
28 #include <unotools/ucbstreamhelper.hxx>
29 #include <unotools/streamwrap.hxx>
30 #include <cppuhelper/implbase.hxx>
31 #include <sfx2/strings.hrc>
32 #include <sfx2/sfxresid.hxx>
33 #include <sfx2/viewfrm.hxx>
34 #include <tools/datetime.hxx>
35 #include <unotools/datetime.hxx>
36 #include <vcl/weld.hxx>
37 #include <svl/fstathelper.hxx>
38 #include <config_folders.h>
40 #include <officecfg/Office/Common.hxx>
42 using namespace com::sun::star
;
47 const OUString
& PROP_BACNAME()
49 static OUString
sProp("BusinessAuthorizationCategory:Name");
53 const OUString
& PROP_STARTVALIDITY()
55 static OUString
sProp("Authorization:StartValidity");
59 const OUString
& PROP_NONE()
61 static OUString
sProp("None");
65 const OUString
& PROP_IMPACTSCALE()
67 static OUString
sProp("Impact:Scale");
71 const OUString
& PROP_IMPACTLEVEL()
73 static OUString
sProp("Impact:Level:Confidentiality");
77 const OUString
& PROP_PREFIX_EXPORTCONTROL()
79 static OUString
sProp("urn:bails:ExportControl:");
83 const OUString
& PROP_PREFIX_NATIONALSECURITY()
85 static OUString
sProp("urn:bails:NationalSecurity:");
89 /// Represents one category of a classification policy.
90 class SfxClassificationCategory
93 /// PROP_BACNAME() is stored separately for easier lookup.
95 OUString m_aAbbreviatedName
; //< An abbreviation to display instead of m_aName.
96 OUString m_aIdentifier
; //< The Identifier of this entry.
97 size_t m_nConfidentiality
; //< 0 is the lowest (least-sensitive).
98 std::map
<OUString
, OUString
> m_aLabels
;
101 /// Parses a policy XML conforming to the TSCP BAF schema.
102 class SfxClassificationParser
: public cppu::WeakImplHelper
<xml::sax::XDocumentHandler
>
105 std::vector
<SfxClassificationCategory
> m_aCategories
;
106 std::vector
<OUString
> m_aMarkings
;
107 std::vector
<OUString
> m_aIPParts
;
108 std::vector
<OUString
> m_aIPPartNumbers
;
110 OUString m_aPolicyAuthorityName
;
111 bool m_bInPolicyAuthorityName
= false;
112 OUString m_aPolicyName
;
113 bool m_bInPolicyName
= false;
114 OUString m_aProgramID
;
115 bool m_bInProgramID
= false;
117 bool m_bInScale
= false;
118 OUString m_aConfidentalityValue
;
119 bool m_bInConfidentalityValue
= false;
120 OUString m_aIdentifier
;
121 bool m_bInIdentifier
= false;
123 bool m_bInValue
= false;
125 /// Pointer to a value in m_aCategories, the currently parsed category.
126 SfxClassificationCategory
* m_pCategory
= nullptr;
128 SfxClassificationParser();
130 void SAL_CALL
startDocument() override
;
132 void SAL_CALL
endDocument() override
;
134 void SAL_CALL
startElement(const OUString
& rName
, const uno::Reference
<xml::sax::XAttributeList
>& xAttribs
) override
;
136 void SAL_CALL
endElement(const OUString
& rName
) override
;
138 void SAL_CALL
characters(const OUString
& rChars
) override
;
140 void SAL_CALL
ignorableWhitespace(const OUString
& rWhitespaces
) override
;
142 void SAL_CALL
processingInstruction(const OUString
& rTarget
, const OUString
& rData
) override
;
144 void SAL_CALL
setDocumentLocator(const uno::Reference
<xml::sax::XLocator
>& xLocator
) override
;
147 SfxClassificationParser::SfxClassificationParser() = default;
149 void SAL_CALL
SfxClassificationParser::startDocument()
153 void SAL_CALL
SfxClassificationParser::endDocument()
157 void SAL_CALL
SfxClassificationParser::startElement(const OUString
& rName
, const uno::Reference
<xml::sax::XAttributeList
>& xAttribs
)
159 if (rName
== "baf:PolicyAuthorityName")
161 m_aPolicyAuthorityName
.clear();
162 m_bInPolicyAuthorityName
= true;
164 else if (rName
== "baf:PolicyName")
166 m_aPolicyName
.clear();
167 m_bInPolicyName
= true;
169 else if (rName
== "baf:ProgramID")
171 m_aProgramID
.clear();
172 m_bInProgramID
= true;
174 else if (rName
== "baf:BusinessAuthorizationCategory")
176 const OUString aName
= xAttribs
->getValueByName("Name");
177 if (!m_pCategory
&& !aName
.isEmpty())
179 OUString aIdentifier
= xAttribs
->getValueByName("Identifier");
181 // Create a new category and initialize it with the data that's true for all categories.
182 m_aCategories
.emplace_back(SfxClassificationCategory());
183 SfxClassificationCategory
& rCategory
= m_aCategories
.back();
185 rCategory
.m_aName
= aName
;
186 // Set the abbreviated name, if any, otherwise fallback on the full name.
187 const OUString aAbbreviatedName
= xAttribs
->getValueByName("loextAbbreviatedName");
188 rCategory
.m_aAbbreviatedName
= !aAbbreviatedName
.isEmpty() ? aAbbreviatedName
: aName
;
189 rCategory
.m_aIdentifier
= aIdentifier
;
191 rCategory
.m_aLabels
["PolicyAuthority:Name"] = m_aPolicyAuthorityName
;
192 rCategory
.m_aLabels
["Policy:Name"] = m_aPolicyName
;
193 rCategory
.m_aLabels
["BusinessAuthorization:Identifier"] = m_aProgramID
;
194 rCategory
.m_aLabels
["BusinessAuthorizationCategory:Identifier"] = aIdentifier
;
196 // Also initialize defaults.
197 rCategory
.m_aLabels
["PolicyAuthority:Identifier"] = PROP_NONE();
198 rCategory
.m_aLabels
["PolicyAuthority:Country"] = PROP_NONE();
199 rCategory
.m_aLabels
["Policy:Identifier"] = PROP_NONE();
200 rCategory
.m_aLabels
["BusinessAuthorization:Name"] = PROP_NONE();
201 rCategory
.m_aLabels
["BusinessAuthorization:Locator"] = PROP_NONE();
202 rCategory
.m_aLabels
["BusinessAuthorizationCategory:Identifier:OID"] = PROP_NONE();
203 rCategory
.m_aLabels
["BusinessAuthorizationCategory:Locator"] = PROP_NONE();
204 rCategory
.m_aLabels
["BusinessAuthorization:Locator"] = PROP_NONE();
205 rCategory
.m_aLabels
["MarkingPrecedence"] = PROP_NONE();
206 rCategory
.m_aLabels
["Marking:general-summary"].clear();
207 rCategory
.m_aLabels
["Marking:general-warning-statement"].clear();
208 rCategory
.m_aLabels
["Marking:general-warning-statement:ext:2"].clear();
209 rCategory
.m_aLabels
["Marking:general-warning-statement:ext:3"].clear();
210 rCategory
.m_aLabels
["Marking:general-warning-statement:ext:4"].clear();
211 rCategory
.m_aLabels
["Marking:general-distribution-statement"].clear();
212 rCategory
.m_aLabels
["Marking:general-distribution-statement:ext:2"].clear();
213 rCategory
.m_aLabels
["Marking:general-distribution-statement:ext:3"].clear();
214 rCategory
.m_aLabels
["Marking:general-distribution-statement:ext:4"].clear();
215 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCHEADER()].clear();
216 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCFOOTER()].clear();
217 rCategory
.m_aLabels
[SfxClassificationHelper::PROP_DOCWATERMARK()].clear();
218 rCategory
.m_aLabels
["Marking:email-first-line-of-text"].clear();
219 rCategory
.m_aLabels
["Marking:email-last-line-of-text"].clear();
220 rCategory
.m_aLabels
["Marking:email-subject-prefix"].clear();
221 rCategory
.m_aLabels
["Marking:email-subject-suffix"].clear();
222 rCategory
.m_aLabels
[PROP_STARTVALIDITY()] = PROP_NONE();
223 rCategory
.m_aLabels
["Authorization:StopValidity"] = PROP_NONE();
224 m_pCategory
= &rCategory
;
227 else if (rName
== "loext:Marking")
229 OUString aName
= xAttribs
->getValueByName("Name");
230 m_aMarkings
.push_back(aName
);
232 else if (rName
== "loext:IntellectualPropertyPart")
234 OUString aName
= xAttribs
->getValueByName("Name");
235 m_aIPParts
.push_back(aName
);
237 else if (rName
== "loext:IntellectualPropertyPartNumber")
239 OUString aName
= xAttribs
->getValueByName("Name");
240 m_aIPPartNumbers
.push_back(aName
);
242 else if (rName
== "baf:Scale")
247 else if (rName
== "baf:ConfidentalityValue")
249 m_aConfidentalityValue
.clear();
250 m_bInConfidentalityValue
= true;
252 else if (rName
== "baf:Identifier")
254 m_aIdentifier
.clear();
255 m_bInIdentifier
= true;
257 else if (rName
== "baf:Value")
264 void SAL_CALL
SfxClassificationParser::endElement(const OUString
& rName
)
266 if (rName
== "baf:PolicyAuthorityName")
267 m_bInPolicyAuthorityName
= false;
268 else if (rName
== "baf:PolicyName")
269 m_bInPolicyName
= false;
270 else if (rName
== "baf:ProgramID")
271 m_bInProgramID
= false;
272 else if (rName
== "baf:BusinessAuthorizationCategory")
273 m_pCategory
= nullptr;
274 else if (rName
== "baf:Scale")
278 m_pCategory
->m_aLabels
[PROP_IMPACTSCALE()] = m_aScale
;
280 else if (rName
== "baf:ConfidentalityValue")
282 m_bInConfidentalityValue
= false;
285 std::map
<OUString
, OUString
>& rLabels
= m_pCategory
->m_aLabels
;
286 rLabels
[PROP_IMPACTLEVEL()] = m_aConfidentalityValue
;
287 m_pCategory
->m_nConfidentiality
= m_aConfidentalityValue
.toInt32(); // 0-based class sensitivity; 0 is lowest.
288 // Set the two other type of levels as well, if they're not set
289 // yet: they're optional in BAF, but not in BAILS.
290 if (rLabels
.find("Impact:Level:Integrity") == rLabels
.end())
291 rLabels
["Impact:Level:Integrity"] = m_aConfidentalityValue
;
292 if (rLabels
.find("Impact:Level:Availability") == rLabels
.end())
293 rLabels
["Impact:Level:Availability"] = m_aConfidentalityValue
;
296 else if (rName
== "baf:Identifier")
297 m_bInIdentifier
= false;
298 else if (rName
== "baf:Value")
302 if (m_aIdentifier
== "Document: Header")
303 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCHEADER()] = m_aValue
;
304 else if (m_aIdentifier
== "Document: Footer")
305 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCFOOTER()] = m_aValue
;
306 else if (m_aIdentifier
== "Document: Watermark")
307 m_pCategory
->m_aLabels
[SfxClassificationHelper::PROP_DOCWATERMARK()] = m_aValue
;
312 void SAL_CALL
SfxClassificationParser::characters(const OUString
& rChars
)
314 if (m_bInPolicyAuthorityName
)
315 m_aPolicyAuthorityName
+= rChars
;
316 else if (m_bInPolicyName
)
317 m_aPolicyName
+= rChars
;
318 else if (m_bInProgramID
)
319 m_aProgramID
+= rChars
;
322 else if (m_bInConfidentalityValue
)
323 m_aConfidentalityValue
+= rChars
;
324 else if (m_bInIdentifier
)
325 m_aIdentifier
+= rChars
;
330 void SAL_CALL
SfxClassificationParser::ignorableWhitespace(const OUString
& /*rWhitespace*/)
334 void SAL_CALL
SfxClassificationParser::processingInstruction(const OUString
& /*rTarget*/, const OUString
& /*rData*/)
338 void SAL_CALL
SfxClassificationParser::setDocumentLocator(const uno::Reference
<xml::sax::XLocator
>& /*xLocator*/)
342 } // anonymous namespace
344 /// Implementation details of SfxClassificationHelper.
345 class SfxClassificationHelper::Impl
348 /// Selected categories, one category for each policy type.
349 std::map
<SfxClassificationPolicyType
, SfxClassificationCategory
> m_aCategory
;
350 /// Possible categories of a policy to choose from.
351 std::vector
<SfxClassificationCategory
> m_aCategories
;
352 std::vector
<OUString
> m_aMarkings
;
353 std::vector
<OUString
> m_aIPParts
;
354 std::vector
<OUString
> m_aIPPartNumbers
;
356 uno::Reference
<document::XDocumentProperties
> m_xDocumentProperties
;
358 bool m_bUseLocalized
;
360 explicit Impl(uno::Reference
<document::XDocumentProperties
> xDocumentProperties
, bool bUseLocalized
);
362 /// Synchronize m_aLabels back to the document properties.
363 void pushToDocumentProperties();
364 /// Set the classification start date to the system time.
365 void setStartValidity(SfxClassificationPolicyType eType
);
368 SfxClassificationHelper::Impl::Impl(uno::Reference
<document::XDocumentProperties
> xDocumentProperties
, bool bUseLocalized
)
369 : m_xDocumentProperties(std::move(xDocumentProperties
))
370 , m_bUseLocalized(bUseLocalized
)
375 void SfxClassificationHelper::Impl::parsePolicy()
377 uno::Reference
<uno::XComponentContext
> xComponentContext
= comphelper::getProcessComponentContext();
378 SvtPathOptions aOptions
;
379 OUString aPath
= aOptions
.GetClassificationPath();
381 // See if there is a localized variant next to the configured XML.
382 OUString
aExtension(".xml");
383 if (aPath
.endsWith(aExtension
) && m_bUseLocalized
)
385 OUString aBase
= aPath
.copy(0, aPath
.getLength() - aExtension
.getLength());
386 const LanguageTag
& rLanguageTag
= Application::GetSettings().GetLanguageTag();
387 // Expected format is "<original path>_xx-XX.xml".
388 OUString aLocalized
= aBase
+ "_" + rLanguageTag
.getBcp47() + aExtension
;
389 if (FStatHelper::IsDocument(aLocalized
))
393 SvStream
* pStream
= utl::UcbStreamHelper::CreateStream(aPath
, StreamMode::READ
);
394 uno::Reference
<io::XInputStream
> xInputStream(new utl::OStreamWrapper(*pStream
));
395 xml::sax::InputSource aParserInput
;
396 aParserInput
.aInputStream
= xInputStream
;
398 uno::Reference
<xml::sax::XParser
> xParser
= xml::sax::Parser::create(xComponentContext
);
399 rtl::Reference
<SfxClassificationParser
> xClassificationParser(new SfxClassificationParser());
400 uno::Reference
<xml::sax::XDocumentHandler
> xHandler(xClassificationParser
.get());
401 xParser
->setDocumentHandler(xHandler
);
404 xParser
->parseStream(aParserInput
);
406 catch (const xml::sax::SAXParseException
& rException
)
408 SAL_WARN("sfx.view", "parsePolicy() failed: " << rException
);
410 m_aCategories
= xClassificationParser
->m_aCategories
;
411 m_aMarkings
= xClassificationParser
->m_aMarkings
;
412 m_aIPParts
= xClassificationParser
->m_aIPParts
;
413 m_aIPPartNumbers
= xClassificationParser
->m_aIPPartNumbers
;
416 static bool lcl_containsProperty(const uno::Sequence
<beans::Property
>& rProperties
, const OUString
& rName
)
418 return std::find_if(rProperties
.begin(), rProperties
.end(), [&](const beans::Property
& rProperty
)
420 return rProperty
.Name
== rName
;
421 }) != rProperties
.end();
424 void SfxClassificationHelper::Impl::setStartValidity(SfxClassificationPolicyType eType
)
426 auto itCategory
= m_aCategory
.find(eType
);
427 if (itCategory
== m_aCategory
.end())
430 SfxClassificationCategory
& rCategory
= itCategory
->second
;
431 auto it
= rCategory
.m_aLabels
.find(policyTypeToString(eType
) + PROP_STARTVALIDITY());
432 if (it
!= rCategory
.m_aLabels
.end())
434 if (it
->second
== PROP_NONE())
436 // The policy left the start date unchanged, replace it with the system time.
437 util::DateTime aDateTime
= DateTime(DateTime::SYSTEM
).GetUNODateTime();
438 OUStringBuffer aBuffer
= utl::toISO8601(aDateTime
);
439 it
->second
= aBuffer
.toString();
444 void SfxClassificationHelper::Impl::pushToDocumentProperties()
446 uno::Reference
<beans::XPropertyContainer
> xPropertyContainer
= m_xDocumentProperties
->getUserDefinedProperties();
447 uno::Reference
<beans::XPropertySet
> xPropertySet(xPropertyContainer
, uno::UNO_QUERY
);
448 uno::Sequence
<beans::Property
> aProperties
= xPropertySet
->getPropertySetInfo()->getProperties();
449 for (auto& rPair
: m_aCategory
)
451 SfxClassificationPolicyType eType
= rPair
.first
;
452 SfxClassificationCategory
& rCategory
= rPair
.second
;
453 std::map
<OUString
, OUString
> aLabels
= rCategory
.m_aLabels
;
454 aLabels
[policyTypeToString(eType
) + PROP_BACNAME()] = rCategory
.m_aName
;
455 for (const auto& rLabel
: aLabels
)
459 if (lcl_containsProperty(aProperties
, rLabel
.first
))
460 xPropertySet
->setPropertyValue(rLabel
.first
, uno::makeAny(rLabel
.second
));
462 xPropertyContainer
->addProperty(rLabel
.first
, beans::PropertyAttribute::REMOVABLE
, uno::makeAny(rLabel
.second
));
464 catch (const uno::Exception
& rException
)
466 SAL_WARN("sfx.view", "pushDocumentProperties() failed for property " << rLabel
.first
<< ": " << rException
);
472 bool SfxClassificationHelper::IsClassified(const uno::Reference
<document::XDocumentProperties
>& xDocumentProperties
)
474 uno::Reference
<beans::XPropertyContainer
> xPropertyContainer
= xDocumentProperties
->getUserDefinedProperties();
475 if (!xPropertyContainer
.is())
478 uno::Reference
<beans::XPropertySet
> xPropertySet(xPropertyContainer
, uno::UNO_QUERY
);
479 uno::Sequence
<beans::Property
> aProperties
= xPropertySet
->getPropertySetInfo()->getProperties();
480 for (const beans::Property
& rProperty
: aProperties
)
482 if (rProperty
.Name
.startsWith("urn:bails:"))
489 SfxClassificationCheckPasteResult
SfxClassificationHelper::CheckPaste(const uno::Reference
<document::XDocumentProperties
>& xSource
,
490 const uno::Reference
<document::XDocumentProperties
>& xDestination
)
492 bool bSourceClassified
= SfxClassificationHelper::IsClassified(xSource
);
493 if (!bSourceClassified
)
494 // No classification on the source side. Return early, regardless the
495 // state of the destination side.
496 return SfxClassificationCheckPasteResult::None
;
498 bool bDestinationClassified
= SfxClassificationHelper::IsClassified(xDestination
);
499 if (bSourceClassified
&& !bDestinationClassified
)
501 // Paste from a classified document to a non-classified one -> deny.
502 return SfxClassificationCheckPasteResult::TargetDocNotClassified
;
505 // Remaining case: paste between two classified documents.
506 SfxClassificationHelper
aSource(xSource
);
507 SfxClassificationHelper
aDestination(xDestination
);
508 if (aSource
.GetImpactScale() != aDestination
.GetImpactScale())
509 // It's possible to compare them if they have the same scale.
510 return SfxClassificationCheckPasteResult::None
;
512 if (aSource
.GetImpactLevel() > aDestination
.GetImpactLevel())
513 // Paste from a doc that has higher classification -> deny.
514 return SfxClassificationCheckPasteResult::DocClassificationTooLow
;
516 return SfxClassificationCheckPasteResult::None
;
519 bool SfxClassificationHelper::ShowPasteInfo(SfxClassificationCheckPasteResult eResult
)
523 case SfxClassificationCheckPasteResult::None
:
528 case SfxClassificationCheckPasteResult::TargetDocNotClassified
:
530 if (!Application::IsHeadlessModeEnabled())
532 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(nullptr,
533 VclMessageType::Info
, VclButtonsType::Ok
,
534 SfxResId(STR_TARGET_DOC_NOT_CLASSIFIED
)));
540 case SfxClassificationCheckPasteResult::DocClassificationTooLow
:
542 if (!Application::IsHeadlessModeEnabled())
544 std::unique_ptr
<weld::MessageDialog
> xBox(Application::CreateMessageDialog(nullptr,
545 VclMessageType::Info
, VclButtonsType::Ok
,
546 SfxResId(STR_DOC_CLASSIFICATION_TOO_LOW
)));
557 SfxClassificationHelper::SfxClassificationHelper(const uno::Reference
<document::XDocumentProperties
>& xDocumentProperties
, bool bUseLocalizedPolicy
)
558 : m_pImpl(o3tl::make_unique
<Impl
>(xDocumentProperties
, bUseLocalizedPolicy
))
560 if (!xDocumentProperties
.is())
563 uno::Reference
<beans::XPropertyContainer
> xPropertyContainer
= xDocumentProperties
->getUserDefinedProperties();
564 if (!xPropertyContainer
.is())
567 uno::Reference
<beans::XPropertySet
> xPropertySet(xPropertyContainer
, uno::UNO_QUERY
);
568 uno::Sequence
<beans::Property
> aProperties
= xPropertySet
->getPropertySetInfo()->getProperties();
569 for (const beans::Property
& rProperty
: aProperties
)
571 if (!rProperty
.Name
.startsWith("urn:bails:"))
574 uno::Any aAny
= xPropertySet
->getPropertyValue(rProperty
.Name
);
578 SfxClassificationPolicyType eType
= stringToPolicyType(rProperty
.Name
);
579 OUString aPrefix
= policyTypeToString(eType
);
580 if (!rProperty
.Name
.startsWith(aPrefix
))
581 // It's a prefix we did not recognize, ignore.
584 //TODO: Support abbreviated names(?)
585 if (rProperty
.Name
== (aPrefix
+ PROP_BACNAME()))
586 m_pImpl
->m_aCategory
[eType
].m_aName
= aValue
;
588 m_pImpl
->m_aCategory
[eType
].m_aLabels
[rProperty
.Name
] = aValue
;
593 SfxClassificationHelper::~SfxClassificationHelper() = default;
595 std::vector
<OUString
> const & SfxClassificationHelper::GetMarkings()
597 return m_pImpl
->m_aMarkings
;
600 std::vector
<OUString
> const & SfxClassificationHelper::GetIntellectualPropertyParts()
602 return m_pImpl
->m_aIPParts
;
605 std::vector
<OUString
> const & SfxClassificationHelper::GetIntellectualPropertyPartNumbers()
607 return m_pImpl
->m_aIPPartNumbers
;
610 const OUString
& SfxClassificationHelper::GetBACName(SfxClassificationPolicyType eType
)
612 return m_pImpl
->m_aCategory
[eType
].m_aName
;
615 const OUString
& SfxClassificationHelper::GetAbbreviatedBACName(const OUString
& sFullName
)
617 for (const auto& category
: m_pImpl
->m_aCategories
)
619 if (category
.m_aName
== sFullName
)
620 return category
.m_aAbbreviatedName
;
626 OUString
SfxClassificationHelper::GetBACNameForIdentifier(const OUString
& sIdentifier
)
629 if (sIdentifier
.isEmpty())
632 for (const auto& category
: m_pImpl
->m_aCategories
)
634 if (category
.m_aIdentifier
== sIdentifier
)
635 return category
.m_aName
;
641 OUString
SfxClassificationHelper::GetHigherClass(const OUString
& first
, const OUString
& second
)
643 size_t nFirstConfidentiality
= 0;
644 size_t nSecondConfidentiality
= 0;
645 for (const auto& category
: m_pImpl
->m_aCategories
)
647 if (category
.m_aName
== first
)
648 nFirstConfidentiality
= category
.m_nConfidentiality
;
649 if (category
.m_aName
== second
)
650 nSecondConfidentiality
= category
.m_nConfidentiality
;
653 return nFirstConfidentiality
>= nSecondConfidentiality
? first
: second
;
656 bool SfxClassificationHelper::HasImpactLevel()
658 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
659 if (itCategory
== m_pImpl
->m_aCategory
.end())
662 SfxClassificationCategory
& rCategory
= itCategory
->second
;
663 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
664 if (it
== rCategory
.m_aLabels
.end())
667 it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
668 return it
!= rCategory
.m_aLabels
.end();
671 bool SfxClassificationHelper::HasDocumentHeader()
673 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
674 if (itCategory
== m_pImpl
->m_aCategory
.end())
677 SfxClassificationCategory
& rCategory
= itCategory
->second
;
678 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCHEADER());
679 return it
!= rCategory
.m_aLabels
.end() && !it
->second
.isEmpty();
682 bool SfxClassificationHelper::HasDocumentFooter()
684 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
685 if (itCategory
== m_pImpl
->m_aCategory
.end())
688 SfxClassificationCategory
& rCategory
= itCategory
->second
;
689 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCFOOTER());
690 return it
!= rCategory
.m_aLabels
.end() && !it
->second
.isEmpty();
693 InfoBarType
SfxClassificationHelper::GetImpactLevelType()
697 aRet
= InfoBarType::Warning
;
699 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
700 if (itCategory
== m_pImpl
->m_aCategory
.end())
703 SfxClassificationCategory
& rCategory
= itCategory
->second
;
704 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
705 OUString aScale
= it
->second
;
706 if (it
== rCategory
.m_aLabels
.end())
709 it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
710 OUString aLevel
= it
->second
;
711 if (it
== rCategory
.m_aLabels
.end())
714 // The spec defines two valid scale values: FIPS-199 and UK-Cabinet.
715 if (aScale
== "UK-Cabinet")
718 aRet
= InfoBarType::Success
;
719 else if (aLevel
== "1")
720 aRet
= InfoBarType::Warning
;
721 else if (aLevel
== "2")
722 aRet
= InfoBarType::Warning
;
723 else if (aLevel
== "3")
724 aRet
= InfoBarType::Danger
;
726 else if (aScale
== "FIPS-199")
729 aRet
= InfoBarType::Success
;
730 else if (aLevel
== "Moderate")
731 aRet
= InfoBarType::Warning
;
732 else if (aLevel
== "High")
733 aRet
= InfoBarType::Danger
;
738 sal_Int32
SfxClassificationHelper::GetImpactLevel()
742 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
743 if (itCategory
== m_pImpl
->m_aCategory
.end())
746 SfxClassificationCategory
& rCategory
= itCategory
->second
;
747 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
748 if (it
== rCategory
.m_aLabels
.end())
750 OUString aScale
= it
->second
;
752 it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
753 if (it
== rCategory
.m_aLabels
.end())
755 OUString aLevel
= it
->second
;
757 if (aScale
== "UK-Cabinet")
759 sal_Int32 nValue
= aLevel
.toInt32();
760 if (nValue
< 0 || nValue
> 3)
764 else if (aScale
== "FIPS-199")
766 static std::map
<OUString
, sal_Int32
> aValues
;
770 aValues
["Moderate"] = 1;
773 auto itValues
= aValues
.find(aLevel
);
774 if (itValues
== aValues
.end())
776 nRet
= itValues
->second
;
782 OUString
SfxClassificationHelper::GetImpactScale()
784 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
785 if (itCategory
== m_pImpl
->m_aCategory
.end())
788 SfxClassificationCategory
& rCategory
= itCategory
->second
;
789 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
790 if (it
!= rCategory
.m_aLabels
.end())
796 OUString
SfxClassificationHelper::GetDocumentWatermark()
798 auto itCategory
= m_pImpl
->m_aCategory
.find(SfxClassificationPolicyType::IntellectualProperty
);
799 if (itCategory
== m_pImpl
->m_aCategory
.end())
802 SfxClassificationCategory
& rCategory
= itCategory
->second
;
803 auto it
= rCategory
.m_aLabels
.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCWATERMARK());
804 if (it
!= rCategory
.m_aLabels
.end())
810 std::vector
<OUString
> SfxClassificationHelper::GetBACNames()
812 if (m_pImpl
->m_aCategories
.empty())
813 m_pImpl
->parsePolicy();
815 std::vector
<OUString
> aRet
;
816 std::transform(m_pImpl
->m_aCategories
.begin(), m_pImpl
->m_aCategories
.end(), std::back_inserter(aRet
), [](const SfxClassificationCategory
& rCategory
)
818 return rCategory
.m_aName
;
823 std::vector
<OUString
> SfxClassificationHelper::GetBACIdentifiers()
825 if (m_pImpl
->m_aCategories
.empty())
826 m_pImpl
->parsePolicy();
828 std::vector
<OUString
> aRet
;
829 std::transform(m_pImpl
->m_aCategories
.begin(), m_pImpl
->m_aCategories
.end(), std::back_inserter(aRet
), [](const SfxClassificationCategory
& rCategory
)
831 return rCategory
.m_aIdentifier
;
836 std::vector
<OUString
> SfxClassificationHelper::GetAbbreviatedBACNames()
838 if (m_pImpl
->m_aCategories
.empty())
839 m_pImpl
->parsePolicy();
841 std::vector
<OUString
> aRet
;
842 std::transform(m_pImpl
->m_aCategories
.begin(), m_pImpl
->m_aCategories
.end(), std::back_inserter(aRet
), [](const SfxClassificationCategory
& rCategory
)
844 return rCategory
.m_aAbbreviatedName
;
849 void SfxClassificationHelper::SetBACName(const OUString
& rName
, SfxClassificationPolicyType eType
)
851 if (m_pImpl
->m_aCategories
.empty())
852 m_pImpl
->parsePolicy();
854 auto it
= std::find_if(m_pImpl
->m_aCategories
.begin(), m_pImpl
->m_aCategories
.end(), [&](const SfxClassificationCategory
& rCategory
)
856 return rCategory
.m_aName
== rName
;
858 if (it
== m_pImpl
->m_aCategories
.end())
860 SAL_WARN("sfx.view", "'" << rName
<< "' is not a recognized category name");
864 m_pImpl
->m_aCategory
[eType
].m_aName
= it
->m_aName
;
865 m_pImpl
->m_aCategory
[eType
].m_aAbbreviatedName
= it
->m_aAbbreviatedName
;
866 m_pImpl
->m_aCategory
[eType
].m_nConfidentiality
= it
->m_nConfidentiality
;
867 m_pImpl
->m_aCategory
[eType
].m_aLabels
.clear();
868 const OUString
& rPrefix
= policyTypeToString(eType
);
869 for (const auto& rLabel
: it
->m_aLabels
)
870 m_pImpl
->m_aCategory
[eType
].m_aLabels
[rPrefix
+ rLabel
.first
] = rLabel
.second
;
872 m_pImpl
->setStartValidity(eType
);
873 m_pImpl
->pushToDocumentProperties();
874 SfxViewFrame
* pViewFrame
= SfxViewFrame::Current();
878 UpdateInfobar(*pViewFrame
);
881 void SfxClassificationHelper::UpdateInfobar(SfxViewFrame
& rViewFrame
)
883 OUString aBACName
= GetBACName(SfxClassificationPolicyType::IntellectualProperty
);
884 bool bImpactLevel
= HasImpactLevel();
885 if (!aBACName
.isEmpty() && bImpactLevel
)
887 OUString aMessage
= SfxResId(STR_CLASSIFIED_DOCUMENT
);
888 aMessage
= aMessage
.replaceFirst("%1", aBACName
);
890 rViewFrame
.RemoveInfoBar("classification");
891 rViewFrame
.AppendInfoBar("classification", aMessage
, GetImpactLevelType());
895 SfxClassificationPolicyType
SfxClassificationHelper::stringToPolicyType(const OUString
& rType
)
897 if (rType
.startsWith(PROP_PREFIX_EXPORTCONTROL()))
898 return SfxClassificationPolicyType::ExportControl
;
899 else if (rType
.startsWith(PROP_PREFIX_NATIONALSECURITY()))
900 return SfxClassificationPolicyType::NationalSecurity
;
902 return SfxClassificationPolicyType::IntellectualProperty
;
905 const OUString
& SfxClassificationHelper::policyTypeToString(SfxClassificationPolicyType eType
)
909 case SfxClassificationPolicyType::ExportControl
:
910 return PROP_PREFIX_EXPORTCONTROL();
912 case SfxClassificationPolicyType::NationalSecurity
:
913 return PROP_PREFIX_NATIONALSECURITY();
915 case SfxClassificationPolicyType::IntellectualProperty
:
919 return PROP_PREFIX_INTELLECTUALPROPERTY();
922 const OUString
& SfxClassificationHelper::PROP_DOCHEADER()
924 static OUString
sProp("Marking:document-header");
928 const OUString
& SfxClassificationHelper::PROP_DOCFOOTER()
930 static OUString
sProp("Marking:document-footer");
934 const OUString
& SfxClassificationHelper::PROP_DOCWATERMARK()
936 static OUString
sProp("Marking:document-watermark");
940 const OUString
& SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY()
942 static OUString
sProp("urn:bails:IntellectualProperty:");
946 SfxClassificationPolicyType
SfxClassificationHelper::getPolicyType()
948 sal_Int32 nPolicyTypeNumber
= officecfg::Office::Common::Classification::Policy::get();
949 auto eType
= static_cast<SfxClassificationPolicyType
>(nPolicyTypeNumber
);
959 OUString
getProperty(uno::Reference
<beans::XPropertyContainer
> const& rxPropertyContainer
,
960 OUString
const& rName
)
964 uno::Reference
<beans::XPropertySet
> xPropertySet(rxPropertyContainer
, uno::UNO_QUERY
);
965 return xPropertySet
->getPropertyValue(rName
).get
<OUString
>();
967 catch (const css::uno::Exception
&)
974 } // end anonymous namespace
976 sfx::ClassificationCreationOrigin
getCreationOriginProperty(uno::Reference
<beans::XPropertyContainer
> const & rxPropertyContainer
,
977 sfx::ClassificationKeyCreator
const & rKeyCreator
)
979 OUString sValue
= getProperty(rxPropertyContainer
, rKeyCreator
.makeCreationOriginKey());
980 if (sValue
.isEmpty())
981 return sfx::ClassificationCreationOrigin::NONE
;
983 return (sValue
== "BAF_POLICY")
984 ? sfx::ClassificationCreationOrigin::BAF_POLICY
985 : sfx::ClassificationCreationOrigin::MANUAL
;
990 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */