File indexing completed on 2024-09-22 04:50:04

0001 /*
0002   SPDX-FileCopyrightText: 2003 Andreas Gungl <a.gungl@gmx.de>
0003 
0004   SPDX-License-Identifier: GPL-2.0-only
0005 */
0006 
0007 #include "filterlog.h"
0008 
0009 #include "mailcommon_debug.h"
0010 
0011 #include <QFile>
0012 #include <QTime>
0013 
0014 #include <sys/stat.h>
0015 
0016 using namespace MailCommon;
0017 
0018 class Q_DECL_HIDDEN FilterLog::FilterLogPrivate
0019 {
0020 public:
0021     FilterLogPrivate(FilterLog *qq)
0022         : q(qq)
0023         , mMaxLogSize(512 * 1024)
0024         , mAllowedTypes(FilterLog::Meta | FilterLog::PatternDescription | FilterLog::RuleResult | FilterLog::PatternResult | FilterLog::AppliedAction)
0025     {
0026     }
0027 
0028     static FilterLog *mSelf;
0029 
0030     FilterLog *const q;
0031     QStringList mLogEntries;
0032     long mMaxLogSize;
0033     long mCurrentLogSize = 0;
0034     int mAllowedTypes;
0035     bool mLogging = false;
0036 
0037     void checkLogSize();
0038 };
0039 
0040 void FilterLog::FilterLogPrivate::checkLogSize()
0041 {
0042     if (mCurrentLogSize > mMaxLogSize && mMaxLogSize > -1) {
0043         qCDebug(MAILCOMMON_LOG) << "Filter log: memory limit reached, starting to discard old items, size =" << QString::number(mCurrentLogSize);
0044 
0045         // avoid some kind of hysteresis, shrink the log to 90% of its maximum
0046         while (mCurrentLogSize > (mMaxLogSize * 0.9)) {
0047             QStringList::Iterator it = mLogEntries.begin();
0048             if (it != mLogEntries.end()) {
0049                 mCurrentLogSize -= (*it).length();
0050                 mLogEntries.erase(it);
0051                 qCDebug(MAILCOMMON_LOG) << "Filter log: new size =" << QString::number(mCurrentLogSize);
0052             } else {
0053                 qCDebug(MAILCOMMON_LOG) << "Filter log: size reduction disaster!";
0054                 q->clear();
0055             }
0056         }
0057 
0058         Q_EMIT q->logShrinked();
0059     }
0060 }
0061 
0062 FilterLog *FilterLog::FilterLogPrivate::mSelf = nullptr;
0063 
0064 FilterLog::FilterLog()
0065     : d(new FilterLogPrivate(this))
0066 {
0067 }
0068 
0069 FilterLog::~FilterLog() = default;
0070 
0071 FilterLog *FilterLog::instance()
0072 {
0073     if (!FilterLog::FilterLogPrivate::mSelf) {
0074         FilterLog::FilterLogPrivate::mSelf = new FilterLog();
0075     }
0076 
0077     return FilterLog::FilterLogPrivate::mSelf;
0078 }
0079 
0080 bool FilterLog::isLogging() const
0081 {
0082     return d->mLogging;
0083 }
0084 
0085 void FilterLog::setLogging(bool active)
0086 {
0087     d->mLogging = active;
0088     Q_EMIT logStateChanged();
0089 }
0090 
0091 void FilterLog::setMaxLogSize(long size)
0092 {
0093     if (size < -1) {
0094         size = -1;
0095     }
0096 
0097     // do not allow less than 1 KByte except unlimited (-1)
0098     if (size >= 0 && size < 1024) {
0099         size = 1024;
0100     }
0101 
0102     d->mMaxLogSize = size;
0103     Q_EMIT logStateChanged();
0104     d->checkLogSize();
0105 }
0106 
0107 long FilterLog::maxLogSize() const
0108 {
0109     return d->mMaxLogSize;
0110 }
0111 
0112 void FilterLog::setContentTypeEnabled(ContentType contentType, bool enable)
0113 {
0114     if (enable) {
0115         d->mAllowedTypes |= contentType;
0116     } else {
0117         d->mAllowedTypes &= ~contentType;
0118     }
0119 
0120     Q_EMIT logStateChanged();
0121 }
0122 
0123 bool FilterLog::isContentTypeEnabled(ContentType contentType) const
0124 {
0125     return d->mAllowedTypes & contentType;
0126 }
0127 
0128 void FilterLog::add(const QString &logEntry, ContentType contentType)
0129 {
0130     if (isLogging() && (d->mAllowedTypes & contentType)) {
0131         QString timedLog;
0132         if (contentType & ~Meta) {
0133             timedLog = QLatin1Char('[') + QTime::currentTime().toString() + QLatin1StringView("] ") + logEntry;
0134         } else {
0135             timedLog = logEntry;
0136         }
0137 
0138         d->mLogEntries.append(timedLog);
0139         Q_EMIT logEntryAdded(timedLog);
0140         d->mCurrentLogSize += timedLog.length();
0141         d->checkLogSize();
0142     }
0143 }
0144 
0145 void FilterLog::addSeparator()
0146 {
0147     add(QStringLiteral("------------------------------"), Meta);
0148 }
0149 
0150 void FilterLog::clear()
0151 {
0152     d->mLogEntries.clear();
0153     d->mCurrentLogSize = 0;
0154 }
0155 
0156 QStringList FilterLog::logEntries() const
0157 {
0158     return d->mLogEntries;
0159 }
0160 
0161 void FilterLog::dump()
0162 {
0163     qCDebug(MAILCOMMON_LOG) << "----- starting filter log -----";
0164     for (const QString &entry : std::as_const(d->mLogEntries)) {
0165         qCDebug(MAILCOMMON_LOG) << entry;
0166     }
0167     qCDebug(MAILCOMMON_LOG) << "------ end of filter log ------";
0168 }
0169 
0170 bool FilterLog::saveToFile(const QString &fileName) const
0171 {
0172     QFile file(fileName);
0173     if (!file.open(QIODevice::WriteOnly)) {
0174         return false;
0175     }
0176 
0177     file.write("<html>\n<body>\n");
0178     file.write("<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\">\n");
0179     for (const QString &entry : std::as_const(d->mLogEntries)) {
0180         const QString line = QLatin1StringView("<p>") + entry + QLatin1StringView("</p>") + QLatin1Char('\n');
0181         file.write(line.toLocal8Bit());
0182     }
0183     file.write("</body>\n</html>\n");
0184     file.close();
0185     return true;
0186 }
0187 
0188 QString FilterLog::recode(const QString &plain)
0189 {
0190     return plain.toHtmlEscaped();
0191 }
0192 
0193 #include "moc_filterlog.cpp"