File indexing completed on 2024-06-23 05:14:15

0001 /* -*- mode: c++; c-basic-offset:4 -*-
0002     utils/expiration.cpp
0003 
0004     This file is part of Kleopatra, the KDE keymanager
0005     SPDX-FileCopyrightText: 2023 g10 Code GmbH
0006     SPDX-FileContributor: Ingo Klöcker <dev@ingo-kloecker.de>
0007 
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include <config-kleopatra.h>
0012 
0013 #include "expiration.h"
0014 
0015 #include <settings.h>
0016 
0017 #include <KDateComboBox>
0018 #include <KLocalizedString>
0019 
0020 QDate Kleo::maximumAllowedDate()
0021 {
0022     static const QDate maxAllowedDate{2106, 2, 5};
0023     return maxAllowedDate;
0024 }
0025 
0026 QDate Kleo::minimumExpirationDate()
0027 {
0028     return expirationDateRange().minimum;
0029 }
0030 
0031 QDate Kleo::maximumExpirationDate()
0032 {
0033     return expirationDateRange().maximum;
0034 }
0035 
0036 Kleo::DateRange Kleo::expirationDateRange()
0037 {
0038     Kleo::DateRange range;
0039 
0040     const auto settings = Kleo::Settings{};
0041     const auto today = QDate::currentDate();
0042 
0043     const auto minimumExpiry = std::max(1, settings.validityPeriodInDaysMin());
0044     range.minimum = std::min(today.addDays(minimumExpiry), maximumAllowedDate());
0045 
0046     const auto maximumExpiry = settings.validityPeriodInDaysMax();
0047     if (maximumExpiry >= 0) {
0048         range.maximum = std::min(std::max(today.addDays(maximumExpiry), range.minimum), maximumAllowedDate());
0049     }
0050 
0051     return range;
0052 }
0053 
0054 QDate Kleo::defaultExpirationDate(Kleo::ExpirationOnUnlimitedValidity onUnlimitedValidity)
0055 {
0056     QDate expirationDate;
0057 
0058     const auto settings = Kleo::Settings{};
0059     const auto defaultExpirationInDays = settings.validityPeriodInDays();
0060     if (defaultExpirationInDays > 0) {
0061         expirationDate = QDate::currentDate().addDays(defaultExpirationInDays);
0062     } else if (defaultExpirationInDays < 0 || onUnlimitedValidity == ExpirationOnUnlimitedValidity::InternalDefaultExpiration) {
0063         expirationDate = QDate::currentDate().addYears(3);
0064     }
0065 
0066     const auto allowedRange = expirationDateRange();
0067     expirationDate = std::max(expirationDate, allowedRange.minimum);
0068     if (allowedRange.maximum.isValid()) {
0069         expirationDate = std::min(expirationDate, allowedRange.maximum);
0070     }
0071 
0072     return expirationDate;
0073 }
0074 
0075 bool Kleo::isValidExpirationDate(const QDate &date)
0076 {
0077     const auto allowedRange = expirationDateRange();
0078     if (date.isValid()) {
0079         return (date >= allowedRange.minimum //
0080                 && ((allowedRange.maximum.isValid() && date <= allowedRange.maximum) //
0081                     || (!allowedRange.maximum.isValid() && date <= maximumAllowedDate())));
0082     } else {
0083         return !allowedRange.maximum.isValid();
0084     }
0085 }
0086 
0087 static QString dateToString(const QDate &date, QWidget *widget)
0088 {
0089     // workaround for QLocale using "yy" way too often for years
0090     // stolen from KDateComboBox
0091     auto locale = widget ? widget->locale() : QLocale{};
0092     const auto dateFormat = (locale
0093                                  .dateFormat(QLocale::ShortFormat) //
0094                                  .replace(QLatin1StringView{"yy"}, QLatin1String{"yyyy"})
0095                                  .replace(QLatin1StringView{"yyyyyyyy"}, QLatin1String{"yyyy"}));
0096     return locale.toString(date, dateFormat);
0097 }
0098 
0099 static QString validityPeriodHint(const Kleo::DateRange &dateRange, QWidget *widget)
0100 {
0101     // the minimum date is always valid
0102     if (dateRange.maximum.isValid()) {
0103         if (dateRange.maximum == dateRange.minimum) {
0104             return i18nc("@info", "The date cannot be changed.");
0105         } else {
0106             return i18nc("@info ... between <a date> and <another date>.",
0107                          "Enter a date between %1 and %2.",
0108                          dateToString(dateRange.minimum, widget),
0109                          dateToString(dateRange.maximum, widget));
0110         }
0111     } else {
0112         return i18nc("@info ... between <a date> and <another date>.",
0113                      "Enter a date between %1 and %2.",
0114                      dateToString(dateRange.minimum, widget),
0115                      dateToString(Kleo::maximumAllowedDate(), widget));
0116     }
0117 }
0118 
0119 QString Kleo::validityPeriodHint()
0120 {
0121     return ::validityPeriodHint(expirationDateRange(), nullptr);
0122 }
0123 
0124 void Kleo::setUpExpirationDateComboBox(KDateComboBox *dateCB, const Kleo::DateRange &range)
0125 {
0126     const auto dateRange = range.minimum.isValid() ? range : expirationDateRange();
0127     // enable warning on invalid or not allowed dates
0128     dateCB->setOptions(KDateComboBox::EditDate | KDateComboBox::SelectDate | KDateComboBox::DatePicker | KDateComboBox::DateKeywords
0129                        | KDateComboBox::WarnOnInvalid);
0130     const auto hintAndErrorMessage = validityPeriodHint(dateRange, dateCB);
0131     dateCB->setDateRange(dateRange.minimum, dateRange.maximum.isValid() ? dateRange.maximum : maximumAllowedDate(), hintAndErrorMessage, hintAndErrorMessage);
0132     if (dateRange.minimum == dateRange.maximum) {
0133         // only one date is allowed, so that changing it no sense
0134         dateCB->setEnabled(false);
0135     }
0136     dateCB->setToolTip(hintAndErrorMessage);
0137     const QDate today = QDate::currentDate();
0138     dateCB->setDateMap({
0139         {today.addYears(3), i18nc("@item:inlistbox", "Three years from now")},
0140         {today.addYears(2), i18nc("@item:inlistbox", "Two years from now")},
0141         {today.addYears(1), i18nc("@item:inlistbox", "One year from now")},
0142     });
0143 }