MailJD nbsp;·nbsp; Test Dashboard nbsp;·nbsp; Coverage
LCOV - code coverage report
Current view: top level - data - SettingsSyncModels.h (source / functions) Coverage Total Hit
Test: MailJD Coverage (Unit + E2E) Lines: 98.5 % 199 196
Test Date: 2026-06-21 21:10:19 Functions: 100.0 % 5 5
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 54.6 % 614 335

             Branch data     Line data    Source code
       1                 :             : #pragma once
       2                 :             : 
       3                 :             : #include <QByteArray>
       4                 :             : #include <QDateTime>
       5                 :             : #include <QJsonArray>
       6                 :             : #include <QJsonDocument>
       7                 :             : #include <QJsonObject>
       8                 :             : #include <QList>
       9                 :             : #include <QMap>
      10                 :             : #include <QString>
      11                 :             : #include <QStringList>
      12                 :             : 
      13                 :             : // T-311: Settings synchronisation data model.
      14                 :             : // Represents the complete set of syncable settings as a JSON payload
      15                 :             : // stored inside a virtual IMAP mail message.
      16                 :             : //
      17                 :             : // The mail has:
      18                 :             : //   Subject:      X-MailJD-Settings-Sync
      19                 :             : //   Content-Type: application/json; charset=utf-8
      20                 :             : //   Body:         JSON serialisation of this struct
      21                 :             : 
      22                 :             : struct SyncPayload {
      23                 :             :   static constexpr qsizetype MaxRfcMessageBytes = 1024 * 1024;
      24                 :             : 
      25                 :             :   int version = 1;
      26                 :             :   QDateTime lastModified;
      27                 :             :   QString clientId; // UUID identifying this installation
      28                 :             : 
      29                 :             :   // --- Syncable categories ---
      30                 :             : 
      31                 :             :   QMap<QString, QString> folderIcons;  // folderPath → MDI icon name
      32                 :             :   QMap<QString, QString> folderColors; // folderPath → #hex color
      33                 :             :   QMap<QString, QString> calendarColors; // calendarPath → #hex color
      34                 :             : 
      35                 :             :   QStringList hiddenFolders;
      36                 :             : 
      37                 :             :   struct WhitelistItem {
      38                 :             :     QString type;  // "sender" or "domain"
      39                 :             :     QString value; // e.g. "user@example.com" or "example.com"
      40                 :             :   };
      41                 :             :   QList<WhitelistItem> externalContentWhitelist;
      42                 :             : 
      43                 :             :   struct CardDavAccount {
      44                 :             :     QString id;        // UUID
      45                 :             :     QString serverUrl; // e.g. "https://cloud.example.com"
      46                 :             :     QString username;
      47                 :             :     // NOTE: password is intentionally NOT synced (security)
      48                 :             :     QStringList selectedBooks; // DAV paths
      49                 :             :   };
      50                 :             :   QList<CardDavAccount> carddavAccounts;
      51                 :             : 
      52                 :             :   // T-334: CalDAV calendar sync config (Sprint 32)
      53                 :             :   // Credentials are shared with CardDAV — referenced by account ID.
      54                 :             :   struct CalDavSyncConfig {
      55                 :             :     QString carddavAccountId;     // References CardDavAccount.id
      56                 :             :     QStringList selectedCalendars; // DAV paths of selected calendars
      57                 :             :     QStringList readOnlyCalendars; // Subset marked read-only
      58                 :             :     // Sprint 73: per-config interval is LEGACY/deferred metadata only. The
      59                 :             :     // active CalDAV scheduler is the single global 'caldav/syncIntervalMin'
      60                 :             :     // key (one timer for all DAV accounts). This field is still round-
      61                 :             :     // tripped by settings sync for backward compatibility, but the current
      62                 :             :     // scheduler does NOT read it. Do not wire UI controls to it unless a
      63                 :             :     // per-account scheduler is implemented.
      64                 :             :     int syncIntervalMinutes = 15;
      65                 :             :   };
      66                 :             :   QList<CalDavSyncConfig> caldavConfigs;
      67                 :             : 
      68                 :             :   struct GeneralSettings {
      69                 :             :     QString defaultView = QStringLiteral("text");
      70                 :             :     QString externalContent = QStringLiteral("block");
      71                 :             :     QString language = QStringLiteral("auto");
      72                 :             :     int carddavSyncInterval = 0; // minutes, 0 = off
      73                 :             :     int caldavSyncInterval = 15; // T-334: default minutes, 0 = off
      74                 :             :   };
      75                 :             :   GeneralSettings general;
      76                 :             : 
      77                 :             :   // Which categories are enabled for sync
      78                 :             :   QStringList enabledCategories;
      79                 :             : 
      80                 :             :   // --- Serialisation ---
      81                 :             : 
      82                 :          39 :   QJsonObject toJson() const {
      83         [ +  - ]:          39 :     QJsonObject root;
      84   [ +  -  +  -  :          78 :     root[QStringLiteral("version")] = version;
                   +  - ]
      85         [ +  - ]:          78 :     root[QStringLiteral("lastModified")] =
      86   [ +  -  +  -  :         117 :         lastModified.toUTC().toString(Qt::ISODate);
             +  -  +  - ]
      87   [ +  -  +  -  :          78 :     root[QStringLiteral("clientId")] = clientId;
                   +  - ]
      88                 :             : 
      89         [ +  - ]:          39 :     QJsonObject settings;
      90                 :             : 
      91                 :             :     // folderIcons
      92         [ +  - ]:          39 :     QJsonObject icons;
      93   [ +  -  +  -  :          63 :     for (auto it = folderIcons.constBegin(); it != folderIcons.constEnd(); ++it)
                   +  + ]
      94   [ +  -  +  -  :          24 :       icons[it.key()] = it.value();
                   +  - ]
      95   [ +  -  +  -  :          78 :     settings[QStringLiteral("folderIcons")] = icons;
                   +  - ]
      96                 :             : 
      97                 :             :     // folderColors
      98         [ +  - ]:          39 :     QJsonObject colors;
      99   [ +  -  +  -  :          57 :     for (auto it = folderColors.constBegin(); it != folderColors.constEnd();
                   +  + ]
     100                 :          18 :          ++it)
     101   [ +  -  +  -  :          18 :       colors[it.key()] = it.value();
                   +  - ]
     102   [ +  -  +  -  :          78 :     settings[QStringLiteral("folderColors")] = colors;
                   +  - ]
     103                 :             : 
     104                 :             :     // calendarColors
     105         [ +  - ]:          39 :     QJsonObject calColors;
     106   [ +  -  +  -  :          49 :     for (auto it = calendarColors.constBegin(); it != calendarColors.constEnd();
                   +  + ]
     107                 :          10 :          ++it)
     108   [ +  -  +  -  :          10 :       calColors[it.key()] = it.value();
                   +  - ]
     109   [ +  -  +  -  :          78 :     settings[QStringLiteral("calendarColors")] = calColors;
                   +  - ]
     110                 :             : 
     111                 :             :     // hiddenFolders
     112         [ +  - ]:          39 :     QJsonArray hidden;
     113         [ +  + ]:          62 :     for (const auto &f : hiddenFolders)
     114   [ +  -  +  - ]:          23 :       hidden.append(f);
     115   [ +  -  +  -  :          78 :     settings[QStringLiteral("hiddenFolders")] = hidden;
                   +  - ]
     116                 :             : 
     117                 :             :     // externalContentWhitelist
     118         [ +  - ]:          39 :     QJsonArray wl;
     119         [ +  + ]:          53 :     for (const auto &item : externalContentWhitelist) {
     120         [ +  - ]:          14 :       QJsonObject obj;
     121   [ +  -  +  -  :          28 :       obj[QStringLiteral("type")] = item.type;
                   +  - ]
     122   [ +  -  +  -  :          28 :       obj[QStringLiteral("value")] = item.value;
                   +  - ]
     123   [ +  -  +  - ]:          14 :       wl.append(obj);
     124                 :          14 :     }
     125   [ +  -  +  -  :          78 :     settings[QStringLiteral("externalContentWhitelist")] = wl;
                   +  - ]
     126                 :             : 
     127                 :             :     // carddavAccounts (NO passwords!)
     128         [ +  - ]:          39 :     QJsonArray cdArr;
     129         [ +  + ]:          50 :     for (const auto &acc : carddavAccounts) {
     130         [ +  - ]:          11 :       QJsonObject obj;
     131   [ +  -  +  -  :          22 :       obj[QStringLiteral("id")] = acc.id;
                   +  - ]
     132   [ +  -  +  -  :          22 :       obj[QStringLiteral("serverUrl")] = acc.serverUrl;
                   +  - ]
     133   [ +  -  +  -  :          22 :       obj[QStringLiteral("username")] = acc.username;
                   +  - ]
     134         [ +  - ]:          11 :       QJsonArray books;
     135         [ +  + ]:          25 :       for (const auto &b : acc.selectedBooks)
     136   [ +  -  +  - ]:          14 :         books.append(b);
     137   [ +  -  +  -  :          22 :       obj[QStringLiteral("selectedBooks")] = books;
                   +  - ]
     138   [ +  -  +  - ]:          11 :       cdArr.append(obj);
     139                 :          11 :     }
     140   [ +  -  +  -  :          78 :     settings[QStringLiteral("carddavAccounts")] = cdArr;
                   +  - ]
     141                 :             : 
     142                 :             :     // T-334: caldavConfigs (calendar sync tied to CardDAV accounts)
     143         [ +  - ]:          39 :     QJsonArray caArr;
     144         [ +  + ]:          49 :     for (const auto &cfg : caldavConfigs) {
     145         [ +  - ]:          10 :       QJsonObject obj;
     146   [ +  -  +  -  :          20 :       obj[QStringLiteral("carddavAccountId")] = cfg.carddavAccountId;
                   +  - ]
     147         [ +  - ]:          10 :       QJsonArray cals;
     148         [ +  + ]:          23 :       for (const auto &c : cfg.selectedCalendars)
     149   [ +  -  +  - ]:          13 :         cals.append(c);
     150   [ +  -  +  -  :          20 :       obj[QStringLiteral("selectedCalendars")] = cals;
                   +  - ]
     151         [ +  - ]:          10 :       QJsonArray roCals;
     152         [ +  + ]:          16 :       for (const auto &r : cfg.readOnlyCalendars)
     153   [ +  -  +  - ]:           6 :         roCals.append(r);
     154   [ +  -  +  -  :          20 :       obj[QStringLiteral("readOnlyCalendars")] = roCals;
                   +  - ]
     155   [ +  -  +  -  :          20 :       obj[QStringLiteral("syncIntervalMinutes")] = cfg.syncIntervalMinutes;
                   +  - ]
     156   [ +  -  +  - ]:          10 :       caArr.append(obj);
     157                 :          10 :     }
     158   [ +  -  +  -  :          78 :     settings[QStringLiteral("caldavConfigs")] = caArr;
                   +  - ]
     159                 :             : 
     160                 :             :     // general
     161         [ +  - ]:          39 :     QJsonObject gen;
     162   [ +  -  +  -  :          78 :     gen[QStringLiteral("defaultView")] = general.defaultView;
                   +  - ]
     163   [ +  -  +  -  :          78 :     gen[QStringLiteral("externalContent")] = general.externalContent;
                   +  - ]
     164   [ +  -  +  -  :          78 :     gen[QStringLiteral("language")] = general.language;
                   +  - ]
     165   [ +  -  +  -  :          78 :     gen[QStringLiteral("carddavSyncInterval")] = general.carddavSyncInterval;
                   +  - ]
     166   [ +  -  +  -  :          78 :     gen[QStringLiteral("caldavSyncInterval")] = general.caldavSyncInterval;
                   +  - ]
     167   [ +  -  +  -  :          78 :     settings[QStringLiteral("general")] = gen;
                   +  - ]
     168                 :             : 
     169   [ +  -  +  -  :          78 :     root[QStringLiteral("settings")] = settings;
                   +  - ]
     170                 :             : 
     171                 :             :     // enabledCategories
     172         [ +  - ]:          39 :     QJsonArray cats;
     173         [ +  + ]:          98 :     for (const auto &c : enabledCategories)
     174   [ +  -  +  - ]:          59 :       cats.append(c);
     175   [ +  -  +  -  :          78 :     root[QStringLiteral("enabledCategories")] = cats;
                   +  - ]
     176                 :             : 
     177                 :          39 :     return root;
     178                 :          39 :   }
     179                 :             : 
     180                 :          47 :   static SyncPayload fromJson(const QJsonObject &root) {
     181         [ +  - ]:          47 :     SyncPayload p;
     182   [ +  -  +  - ]:          47 :     p.version = root.value(QStringLiteral("version")).toInt(1);
     183         [ +  - ]:          94 :     p.lastModified = QDateTime::fromString(
     184   [ +  -  +  - ]:         141 :         root.value(QStringLiteral("lastModified")).toString(), Qt::ISODate);
     185   [ +  -  +  - ]:          47 :     p.clientId = root.value(QStringLiteral("clientId")).toString();
     186                 :             : 
     187   [ +  -  +  - ]:          47 :     auto settings = root.value(QStringLiteral("settings")).toObject();
     188                 :             : 
     189                 :             :     // folderIcons
     190   [ +  -  +  - ]:          47 :     auto icons = settings.value(QStringLiteral("folderIcons")).toObject();
     191   [ +  -  +  + ]:          66 :     for (auto it = icons.constBegin(); it != icons.constEnd(); ++it)
     192   [ +  -  +  -  :          19 :       p.folderIcons[it.key()] = it.value().toString();
                   +  - ]
     193                 :             : 
     194                 :             :     // folderColors
     195   [ +  -  +  - ]:          47 :     auto colors = settings.value(QStringLiteral("folderColors")).toObject();
     196   [ +  -  +  + ]:          63 :     for (auto it = colors.constBegin(); it != colors.constEnd(); ++it)
     197   [ +  -  +  -  :          16 :       p.folderColors[it.key()] = it.value().toString();
                   +  - ]
     198                 :             : 
     199                 :             :     // calendarColors (backward-compatible: absent = empty)
     200                 :             :     auto calColors =
     201   [ +  -  +  - ]:          47 :         settings.value(QStringLiteral("calendarColors")).toObject();
     202   [ +  -  +  + ]:          55 :     for (auto it = calColors.constBegin(); it != calColors.constEnd(); ++it)
     203   [ +  -  +  -  :           8 :       p.calendarColors[it.key()] = it.value().toString();
                   +  - ]
     204                 :             : 
     205                 :             :     // hiddenFolders
     206   [ +  -  +  - ]:          47 :     auto hidden = settings.value(QStringLiteral("hiddenFolders")).toArray();
     207   [ +  -  +  -  :          67 :     for (const auto &v : hidden)
                   +  + ]
     208   [ +  -  +  - ]:          20 :       p.hiddenFolders.append(v.toString());
     209                 :             : 
     210                 :             :     // externalContentWhitelist
     211                 :             :     auto wl =
     212   [ +  -  +  - ]:          47 :         settings.value(QStringLiteral("externalContentWhitelist")).toArray();
     213   [ +  -  +  -  :          59 :     for (const auto &v : wl) {
                   +  + ]
     214         [ +  - ]:          12 :       auto obj = v.toObject();
     215                 :          12 :       WhitelistItem item;
     216   [ +  -  +  - ]:          12 :       item.type = obj.value(QStringLiteral("type")).toString();
     217   [ +  -  +  - ]:          12 :       item.value = obj.value(QStringLiteral("value")).toString();
     218         [ +  - ]:          12 :       p.externalContentWhitelist.append(item);
     219                 :          12 :     }
     220                 :             : 
     221                 :             :     // carddavAccounts
     222                 :             :     auto cdArr =
     223   [ +  -  +  - ]:          47 :         settings.value(QStringLiteral("carddavAccounts")).toArray();
     224   [ +  -  +  -  :          55 :     for (const auto &v : cdArr) {
                   +  + ]
     225         [ +  - ]:           8 :       auto obj = v.toObject();
     226                 :           8 :       CardDavAccount acc;
     227   [ +  -  +  - ]:           8 :       acc.id = obj.value(QStringLiteral("id")).toString();
     228   [ +  -  +  - ]:           8 :       acc.serverUrl = obj.value(QStringLiteral("serverUrl")).toString();
     229   [ +  -  +  - ]:           8 :       acc.username = obj.value(QStringLiteral("username")).toString();
     230   [ +  -  +  - ]:           8 :       auto books = obj.value(QStringLiteral("selectedBooks")).toArray();
     231   [ +  -  +  -  :          19 :       for (const auto &b : books)
                   +  + ]
     232   [ +  -  +  - ]:          11 :         acc.selectedBooks.append(b.toString());
     233         [ +  - ]:           8 :       p.carddavAccounts.append(acc);
     234                 :           8 :     }
     235                 :             : 
     236                 :             :     // T-334: caldavConfigs (backward-compatible: absent = empty list)
     237                 :             :     auto caArr =
     238   [ +  -  +  - ]:          47 :         settings.value(QStringLiteral("caldavConfigs")).toArray();
     239   [ +  -  +  -  :          57 :     for (const auto &v : caArr) {
                   +  + ]
     240         [ +  - ]:          10 :       auto obj = v.toObject();
     241                 :          10 :       CalDavSyncConfig cfg;
     242                 :             :       cfg.carddavAccountId =
     243   [ +  -  +  - ]:          10 :           obj.value(QStringLiteral("carddavAccountId")).toString();
     244   [ +  -  +  - ]:          10 :       auto cals = obj.value(QStringLiteral("selectedCalendars")).toArray();
     245   [ +  -  +  -  :          21 :       for (const auto &c : cals)
                   +  + ]
     246   [ +  -  +  - ]:          11 :         cfg.selectedCalendars.append(c.toString());
     247   [ +  -  +  - ]:          10 :       auto roCals = obj.value(QStringLiteral("readOnlyCalendars")).toArray();
     248   [ +  -  +  -  :          15 :       for (const auto &r : roCals)
                   +  + ]
     249   [ +  -  +  - ]:           5 :         cfg.readOnlyCalendars.append(r.toString());
     250                 :          10 :       cfg.syncIntervalMinutes =
     251   [ +  -  +  - ]:          10 :           obj.value(QStringLiteral("syncIntervalMinutes")).toInt(15);
     252         [ +  - ]:          10 :       p.caldavConfigs.append(cfg);
     253                 :          10 :     }
     254                 :             : 
     255                 :             :     // general
     256   [ +  -  +  - ]:          47 :     auto gen = settings.value(QStringLiteral("general")).toObject();
     257   [ +  -  +  + ]:          47 :     if (!gen.isEmpty()) {
     258                 :             :       p.general.defaultView =
     259   [ +  -  +  - ]:          62 :           gen.value(QStringLiteral("defaultView")).toString(QStringLiteral("text"));
     260                 :             :       p.general.externalContent =
     261   [ +  -  +  - ]:          62 :           gen.value(QStringLiteral("externalContent")).toString(QStringLiteral("block"));
     262                 :             :       p.general.language =
     263   [ +  -  +  - ]:          62 :           gen.value(QStringLiteral("language")).toString(QStringLiteral("auto"));
     264                 :          31 :       p.general.carddavSyncInterval =
     265   [ +  -  +  - ]:          31 :           gen.value(QStringLiteral("carddavSyncInterval")).toInt(0);
     266                 :          31 :       p.general.caldavSyncInterval =
     267   [ +  -  +  - ]:          31 :           gen.value(QStringLiteral("caldavSyncInterval")).toInt(15);
     268                 :             :     }
     269                 :             : 
     270                 :             :     // enabledCategories
     271   [ +  -  +  - ]:          47 :     auto cats = root.value(QStringLiteral("enabledCategories")).toArray();
     272   [ +  -  +  -  :          91 :     for (const auto &v : cats)
                   +  + ]
     273   [ +  -  +  - ]:          44 :       p.enabledCategories.append(v.toString());
     274                 :             : 
     275                 :          47 :     return p;
     276                 :          47 :   }
     277                 :             : 
     278                 :             :   // --- RFC-2822 message serialisation ---
     279                 :             : 
     280                 :             :   // Build a minimal RFC-2822 message wrapping the JSON payload.
     281                 :             :   // This message is stored via IMAP APPEND in the sync folder.
     282                 :          15 :   QByteArray toRfcMessage() const {
     283                 :          15 :     QByteArray msg;
     284         [ +  - ]:          15 :     msg += "From: mailjd-settings-sync@localhost\r\n";
     285         [ +  - ]:          15 :     msg += "Subject: X-MailJD-Settings-Sync\r\n";
     286                 :          15 :     msg += "Date: " +
     287   [ +  -  +  -  :          30 :            lastModified.toUTC().toString(Qt::RFC2822Date).toUtf8() + "\r\n";
          +  -  +  -  +  
                -  +  - ]
     288         [ +  - ]:          15 :     msg += "MIME-Version: 1.0\r\n";
     289         [ +  - ]:          15 :     msg += "Content-Type: application/json; charset=utf-8\r\n";
     290         [ +  - ]:          15 :     msg += "Content-Transfer-Encoding: 8bit\r\n";
     291   [ +  -  +  -  :          15 :     msg += "X-MailJD-ClientId: " + clientId.toUtf8() + "\r\n";
             +  -  +  - ]
     292         [ +  - ]:          15 :     msg += "\r\n"; // Header/body separator
     293                 :             : 
     294   [ +  -  +  - ]:          15 :     QJsonDocument doc(toJson());
     295   [ +  -  +  - ]:          15 :     msg += doc.toJson(QJsonDocument::Indented);
     296                 :             : 
     297                 :          15 :     return msg;
     298                 :          15 :   }
     299                 :             : 
     300                 :             :   // Parse a SyncPayload from a raw RFC-2822 message (as fetched via IMAP).
     301                 :          18 :   static SyncPayload fromRfcMessage(const QByteArray &raw) {
     302         [ +  + ]:          18 :     if (raw.size() > MaxRfcMessageBytes)
     303                 :           1 :       return {};
     304                 :             : 
     305                 :             :     // Find header/body separator (blank line = \r\n\r\n or \n\n)
     306                 :          17 :     int bodyStart = raw.indexOf("\r\n\r\n");
     307         [ +  + ]:          17 :     if (bodyStart >= 0) {
     308                 :          13 :       bodyStart += 4;
     309                 :             :     } else {
     310                 :           4 :       bodyStart = raw.indexOf("\n\n");
     311         [ +  + ]:           4 :       if (bodyStart >= 0)
     312                 :           2 :         bodyStart += 2;
     313                 :             :       else
     314                 :           2 :         bodyStart = 0; // Fallback: treat entire content as body
     315                 :             :     }
     316                 :             : 
     317         [ +  - ]:          17 :     QByteArray body = raw.mid(bodyStart);
     318                 :             : 
     319         [ +  - ]:          17 :     auto doc = QJsonDocument::fromJson(body);
     320   [ +  -  +  +  :          17 :     if (doc.isNull() || !doc.isObject())
          +  -  +  +  +  
                      + ]
     321                 :           2 :       return {};
     322                 :             : 
     323   [ +  -  +  - ]:          15 :     SyncPayload p = fromJson(doc.object());
     324                 :             : 
     325                 :             :     // Also extract clientId from header if missing from JSON
     326         [ +  + ]:          15 :     if (p.clientId.isEmpty()) {
     327                 :             :       // Parse X-MailJD-ClientId header
     328         [ +  - ]:           5 :       QByteArray header = raw.left(bodyStart);
     329                 :           5 :       int idx = header.indexOf("X-MailJD-ClientId:");
     330         [ +  + ]:           5 :       if (idx >= 0) {
     331                 :           3 :         int lineEnd = header.indexOf('\n', idx);
     332         [ -  + ]:           3 :         if (lineEnd < 0)
     333                 :           0 :           lineEnd = header.size();
     334                 :             :         QByteArray val =
     335   [ +  -  +  - ]:           3 :             header.mid(idx + 18, lineEnd - idx - 18).trimmed();
     336                 :             :         // Remove trailing \r if present
     337   [ +  -  -  + ]:           3 :         if (val.endsWith('\r'))
     338         [ #  # ]:           0 :           val.chop(1);
     339         [ +  - ]:           3 :         p.clientId = QString::fromUtf8(val);
     340                 :           3 :       }
     341                 :           5 :     }
     342                 :             : 
     343                 :          15 :     return p;
     344                 :          29 :   }
     345                 :             : 
     346                 :             :   // --- Default categories ---
     347                 :             : 
     348                 :         105 :   static QStringList allCategories() {
     349                 :             :     return {
     350                 :           0 :         QStringLiteral("folderIcons"),
     351                 :         105 :         QStringLiteral("folderColors"),
     352                 :         105 :         QStringLiteral("calendarColors"),
     353                 :         105 :         QStringLiteral("hiddenFolders"),
     354                 :         105 :         QStringLiteral("externalContentWhitelist"),
     355                 :         105 :         QStringLiteral("davAccounts"),
     356                 :         105 :         QStringLiteral("general"),
     357   [ +  +  -  - ]:         945 :     };
     358   [ +  -  -  -  :         840 :   }
                   -  - ]
     359                 :             : };
        

Generated by: LCOV version 2.0-1