Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / sfx2 / source / view / classificationhelper.cxx
bloba642d19b65e809a53a13a130cb7db66a64f4c860
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <sfx2/classificationhelper.hxx>
12 #include <map>
13 #include <algorithm>
14 #include <iterator>
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;
44 namespace
47 const OUString& PROP_BACNAME()
49 static OUString sProp("BusinessAuthorizationCategory:Name");
50 return sProp;
53 const OUString& PROP_STARTVALIDITY()
55 static OUString sProp("Authorization:StartValidity");
56 return sProp;
59 const OUString& PROP_NONE()
61 static OUString sProp("None");
62 return sProp;
65 const OUString& PROP_IMPACTSCALE()
67 static OUString sProp("Impact:Scale");
68 return sProp;
71 const OUString& PROP_IMPACTLEVEL()
73 static OUString sProp("Impact:Level:Confidentiality");
74 return sProp;
77 const OUString& PROP_PREFIX_EXPORTCONTROL()
79 static OUString sProp("urn:bails:ExportControl:");
80 return sProp;
83 const OUString& PROP_PREFIX_NATIONALSECURITY()
85 static OUString sProp("urn:bails:NationalSecurity:");
86 return sProp;
89 /// Represents one category of a classification policy.
90 class SfxClassificationCategory
92 public:
93 /// PROP_BACNAME() is stored separately for easier lookup.
94 OUString m_aName;
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>
104 public:
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;
116 OUString m_aScale;
117 bool m_bInScale = false;
118 OUString m_aConfidentalityValue;
119 bool m_bInConfidentalityValue = false;
120 OUString m_aIdentifier;
121 bool m_bInIdentifier = false;
122 OUString m_aValue;
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")
244 m_aScale.clear();
245 m_bInScale = true;
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")
259 m_aValue.clear();
260 m_bInValue = true;
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")
276 m_bInScale = false;
277 if (m_pCategory)
278 m_pCategory->m_aLabels[PROP_IMPACTSCALE()] = m_aScale;
280 else if (rName == "baf:ConfidentalityValue")
282 m_bInConfidentalityValue = false;
283 if (m_pCategory)
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")
300 if (m_pCategory)
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;
320 else if (m_bInScale)
321 m_aScale += rChars;
322 else if (m_bInConfidentalityValue)
323 m_aConfidentalityValue += rChars;
324 else if (m_bInIdentifier)
325 m_aIdentifier += rChars;
326 else if (m_bInValue)
327 m_aValue += 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
347 public:
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);
361 void parsePolicy();
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)
372 parsePolicy();
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))
390 aPath = 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())
428 return;
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));
461 else
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())
476 return false;
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:"))
483 return true;
486 return false;
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)
521 switch (eResult)
523 case SfxClassificationCheckPasteResult::None:
525 return true;
527 break;
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)));
535 xBox->run();
537 return false;
539 break;
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)));
547 xBox->run();
549 return false;
551 break;
554 return true;
557 SfxClassificationHelper::SfxClassificationHelper(const uno::Reference<document::XDocumentProperties>& xDocumentProperties, bool bUseLocalizedPolicy)
558 : m_pImpl(o3tl::make_unique<Impl>(xDocumentProperties, bUseLocalizedPolicy))
560 if (!xDocumentProperties.is())
561 return;
563 uno::Reference<beans::XPropertyContainer> xPropertyContainer = xDocumentProperties->getUserDefinedProperties();
564 if (!xPropertyContainer.is())
565 return;
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:"))
572 continue;
574 uno::Any aAny = xPropertySet->getPropertyValue(rProperty.Name);
575 OUString aValue;
576 if (aAny >>= aValue)
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.
582 continue;
584 //TODO: Support abbreviated names(?)
585 if (rProperty.Name == (aPrefix + PROP_BACNAME()))
586 m_pImpl->m_aCategory[eType].m_aName = aValue;
587 else
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;
623 return sFullName;
626 OUString SfxClassificationHelper::GetBACNameForIdentifier(const OUString& sIdentifier)
628 OUString aRet;
629 if (sIdentifier.isEmpty())
630 return aRet;
632 for (const auto& category : m_pImpl->m_aCategories)
634 if (category.m_aIdentifier == sIdentifier)
635 return category.m_aName;
638 return aRet;
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())
660 return false;
662 SfxClassificationCategory& rCategory = itCategory->second;
663 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
664 if (it == rCategory.m_aLabels.end())
665 return false;
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())
675 return false;
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())
686 return false;
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()
695 InfoBarType aRet;
697 aRet = InfoBarType::Warning;
699 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
700 if (itCategory == m_pImpl->m_aCategory.end())
701 return aRet;
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())
707 return aRet;
709 it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
710 OUString aLevel = it->second;
711 if (it == rCategory.m_aLabels.end())
712 return aRet;
714 // The spec defines two valid scale values: FIPS-199 and UK-Cabinet.
715 if (aScale == "UK-Cabinet")
717 if (aLevel == "0")
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")
728 if (aLevel == "Low")
729 aRet = InfoBarType::Success;
730 else if (aLevel == "Moderate")
731 aRet = InfoBarType::Warning;
732 else if (aLevel == "High")
733 aRet = InfoBarType::Danger;
735 return aRet;
738 sal_Int32 SfxClassificationHelper::GetImpactLevel()
740 sal_Int32 nRet = -1;
742 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
743 if (itCategory == m_pImpl->m_aCategory.end())
744 return nRet;
746 SfxClassificationCategory& rCategory = itCategory->second;
747 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
748 if (it == rCategory.m_aLabels.end())
749 return nRet;
750 OUString aScale = it->second;
752 it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTLEVEL());
753 if (it == rCategory.m_aLabels.end())
754 return nRet;
755 OUString aLevel = it->second;
757 if (aScale == "UK-Cabinet")
759 sal_Int32 nValue = aLevel.toInt32();
760 if (nValue < 0 || nValue > 3)
761 return nRet;
762 nRet = nValue;
764 else if (aScale == "FIPS-199")
766 static std::map<OUString, sal_Int32> aValues;
767 if (aValues.empty())
769 aValues["Low"] = 0;
770 aValues["Moderate"] = 1;
771 aValues["High"] = 2;
773 auto itValues = aValues.find(aLevel);
774 if (itValues == aValues.end())
775 return nRet;
776 nRet = itValues->second;
779 return nRet;
782 OUString SfxClassificationHelper::GetImpactScale()
784 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
785 if (itCategory == m_pImpl->m_aCategory.end())
786 return OUString();
788 SfxClassificationCategory& rCategory = itCategory->second;
789 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_IMPACTSCALE());
790 if (it != rCategory.m_aLabels.end())
791 return it->second;
793 return OUString();
796 OUString SfxClassificationHelper::GetDocumentWatermark()
798 auto itCategory = m_pImpl->m_aCategory.find(SfxClassificationPolicyType::IntellectualProperty);
799 if (itCategory == m_pImpl->m_aCategory.end())
800 return OUString();
802 SfxClassificationCategory& rCategory = itCategory->second;
803 auto it = rCategory.m_aLabels.find(PROP_PREFIX_INTELLECTUALPROPERTY() + PROP_DOCWATERMARK());
804 if (it != rCategory.m_aLabels.end())
805 return it->second;
807 return OUString();
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;
820 return aRet;
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;
833 return aRet;
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;
846 return aRet;
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");
861 return;
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();
875 if (!pViewFrame)
876 return;
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;
901 else
902 return SfxClassificationPolicyType::IntellectualProperty;
905 const OUString& SfxClassificationHelper::policyTypeToString(SfxClassificationPolicyType eType)
907 switch (eType)
909 case SfxClassificationPolicyType::ExportControl:
910 return PROP_PREFIX_EXPORTCONTROL();
911 break;
912 case SfxClassificationPolicyType::NationalSecurity:
913 return PROP_PREFIX_NATIONALSECURITY();
914 break;
915 case SfxClassificationPolicyType::IntellectualProperty:
916 break;
919 return PROP_PREFIX_INTELLECTUALPROPERTY();
922 const OUString& SfxClassificationHelper::PROP_DOCHEADER()
924 static OUString sProp("Marking:document-header");
925 return sProp;
928 const OUString& SfxClassificationHelper::PROP_DOCFOOTER()
930 static OUString sProp("Marking:document-footer");
931 return sProp;
934 const OUString& SfxClassificationHelper::PROP_DOCWATERMARK()
936 static OUString sProp("Marking:document-watermark");
937 return sProp;
940 const OUString& SfxClassificationHelper::PROP_PREFIX_INTELLECTUALPROPERTY()
942 static OUString sProp("urn:bails:IntellectualProperty:");
943 return sProp;
946 SfxClassificationPolicyType SfxClassificationHelper::getPolicyType()
948 sal_Int32 nPolicyTypeNumber = officecfg::Office::Common::Classification::Policy::get();
949 auto eType = static_cast<SfxClassificationPolicyType>(nPolicyTypeNumber);
950 return eType;
953 namespace sfx
956 namespace
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&)
971 return OUString();
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: */