data/IcsFile.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "IcsFile.h" | ||
| 2 | |||
| 3 | #include "ICalEventCodec.h" | ||
| 4 | #include "ICalTime.h" | ||
| 5 | #include "ICalendar.h" | ||
| 6 | |||
| 7 | #include <QHash> | ||
| 8 | #include <QLoggingCategory> | ||
| 9 | #include <QSet> | ||
| 10 | |||
| 11 |
4/7✓ Branch 2 → 3 taken 6 times.
✓ Branch 2 → 8 taken 24 times.
✓ Branch 4 → 5 taken 6 times.
✗ Branch 4 → 8 not taken.
✓ Branch 5 → 6 taken 6 times.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 12 not taken.
|
30 | Q_LOGGING_CATEGORY(lcIcsFile, "mailjd.calendar.ics") |
| 12 | |||
| 13 | namespace IcsFile { | ||
| 14 | |||
| 15 | namespace { | ||
| 16 | |||
| 17 | // S106-126: MaxBytes is enforced here, for every caller (the subscription | ||
| 18 | // download is capped at the network layer only above it). | ||
| 19 | 29 | bool withinSize(const QString &text, QString *error) { | |
| 20 |
8/11✓ Branch 3 → 4 taken 2 times.
✓ Branch 3 → 7 taken 27 times.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 2 times.
✓ Branch 9 → 10 taken 2 times.
✓ Branch 9 → 11 taken 27 times.
✓ Branch 11 → 12 taken 27 times.
✓ Branch 11 → 13 taken 2 times.
✗ Branch 38 → 39 not taken.
✗ Branch 38 → 40 not taken.
|
29 | if (text.size() <= MaxBytes / 3 || text.toUtf8().size() <= MaxBytes) |
| 21 | 27 | return true; | |
| 22 |
7/7✓ Branch 13 → 14 taken 2 times.
✓ Branch 17 → 18 taken 2 times.
✓ Branch 18 → 19 taken 2 times.
✓ Branch 19 → 20 taken 2 times.
✓ Branch 20 → 21 taken 2 times.
✓ Branch 24 → 15 taken 2 times.
✓ Branch 24 → 25 taken 2 times.
|
4 | qCWarning(lcIcsFile) << "Calendar file refused: larger than" << MaxBytes << "bytes"; |
| 23 |
2/3✓ Branch 25 → 26 taken 2 times.
✗ Branch 25 → 36 not taken.
✓ Branch 30 → 31 taken 2 times.
|
6 | if (error) *error = QStringLiteral("The calendar file is larger than %1 MB").arg(MaxBytes / (1024 * 1024)); |
| 24 | 2 | return false; | |
| 25 | } | ||
| 26 | |||
| 27 | // The TZIDs the components use (properties of the components and of their | ||
| 28 | // sub-components such as VALARM). | ||
| 29 | 196 | void collectZones(const ICal::Component &component, QSet<QString> *zones) { | |
| 30 |
2/2✓ Branch 18 → 4 taken 808 times.
✓ Branch 18 → 19 taken 196 times.
|
1004 | for (const ICal::Property &property : component.properties) { |
| 31 |
1/1✓ Branch 8 → 9 taken 808 times.
|
808 | const QString tzid = property.parameter(QStringLiteral("TZID")); |
| 32 |
3/3✓ Branch 12 → 13 taken 16 times.
✓ Branch 12 → 15 taken 792 times.
✓ Branch 13 → 14 taken 16 times.
|
808 | if (!tzid.isEmpty()) zones->insert(tzid); |
| 33 | 808 | } | |
| 34 |
1/3✗ Branch 22 → 23 not taken.
✗ Branch 25 → 21 not taken.
✓ Branch 25 → 26 taken 196 times.
|
196 | for (const ICal::Component &child : component.components) collectZones(child, zones); |
| 35 | 196 | } | |
| 36 | |||
| 37 | // S106-127: each entry carries only the VTIMEZONEs its own components use | ||
| 38 | // (every zone of the file in every entry amplified a 0.4 MB file to | ||
| 39 | // 380 MB), and all entries together stay within kMaximumResourceBytes. | ||
| 40 | constexpr qint64 kMaximumResourceBytes = 4 * MaxBytes; | ||
| 41 | |||
| 42 | 188 | ICal::Component entryBase(const ICal::Component &base, const QList<ICal::Component> &own) { | |
| 43 | 188 | QSet<QString> zones; | |
| 44 |
3/3✓ Branch 6 → 7 taken 196 times.
✓ Branch 9 → 5 taken 196 times.
✓ Branch 9 → 10 taken 188 times.
|
384 | for (const ICal::Component &component : own) collectZones(component, &zones); |
| 45 | 188 | ICal::Component result = base; | |
| 46 |
1/1✓ Branch 11 → 12 taken 188 times.
|
188 | result.components.removeIf([&zones](const ICal::Component &child) { |
| 47 |
2/2✓ Branch 4 → 5 taken 11 times.
✓ Branch 4 → 14 taken 4 times.
|
26 | return child.name == QLatin1String("VTIMEZONE") && |
| 48 |
15/25✓ Branch 8 → 9 taken 11 times.
✓ Branch 9 → 10 taken 11 times.
✓ Branch 10 → 11 taken 11 times.
✓ Branch 12 → 13 taken 7 times.
✓ Branch 12 → 14 taken 4 times.
✓ Branch 15 → 16 taken 11 times.
✓ Branch 15 → 17 taken 4 times.
✓ Branch 17 → 18 taken 11 times.
✓ Branch 17 → 19 taken 4 times.
✓ Branch 19 → 20 taken 11 times.
✓ Branch 19 → 21 taken 4 times.
✓ Branch 21 → 22 taken 11 times.
✓ Branch 21 → 23 taken 4 times.
✓ Branch 23 → 24 taken 11 times.
✓ Branch 23 → 25 taken 4 times.
✗ Branch 27 → 28 not taken.
✗ Branch 27 → 29 not taken.
✗ Branch 31 → 32 not taken.
✗ Branch 31 → 33 not taken.
✗ Branch 35 → 36 not taken.
✗ Branch 35 → 37 not taken.
✗ Branch 39 → 40 not taken.
✗ Branch 39 → 41 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 45 not taken.
|
37 | !zones.contains(ICal::unescapeText(child.value(QStringLiteral("TZID"))).trimmed()); |
| 49 | }); | ||
| 50 | 188 | return result; | |
| 51 | 188 | } | |
| 52 | |||
| 53 | 188 | bool withinBudget(qint64 *used, const QString &resourceText, QString *error) { | |
| 54 | 188 | *used += resourceText.size(); | |
| 55 |
2/2✓ Branch 3 → 4 taken 187 times.
✓ Branch 3 → 5 taken 1 time.
|
188 | if (*used <= kMaximumResourceBytes) |
| 56 | 187 | return true; | |
| 57 |
5/5✓ Branch 5 → 6 taken 1 time.
✓ Branch 9 → 10 taken 1 time.
✓ Branch 10 → 11 taken 1 time.
✓ Branch 16 → 7 taken 1 time.
✓ Branch 16 → 17 taken 1 time.
|
2 | qCWarning(lcIcsFile) << "Calendar file refused: its entries would take more than" |
| 58 |
2/2✓ Branch 11 → 12 taken 1 time.
✓ Branch 12 → 13 taken 1 time.
|
1 | << kMaximumResourceBytes << "characters"; |
| 59 |
1/2✓ Branch 17 → 18 taken 1 time.
✗ Branch 17 → 25 not taken.
|
2 | if (error) *error = QStringLiteral("The calendar file is too complex to import"); |
| 60 | 1 | return false; | |
| 61 | } | ||
| 62 | |||
| 63 | } // namespace | ||
| 64 | |||
| 65 | 18 | QList<Entry> read(const QString &text, QString *error) { | |
| 66 | 18 | QList<Entry> entries; | |
| 67 |
3/3✓ Branch 2 → 3 taken 18 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 6 taken 17 times.
|
18 | if (!withinSize(text, error)) return entries; |
| 68 |
1/1✓ Branch 9 → 10 taken 17 times.
|
17 | const ICal::Component calendar = ICal::parseFirst(text, QStringLiteral("VCALENDAR"), error); |
| 69 |
2/2✓ Branch 13 → 14 taken 1 time.
✓ Branch 13 → 16 taken 16 times.
|
17 | if (calendar.name.isEmpty()) return entries; |
| 70 | 16 | ICal::Component base; | |
| 71 | 16 | base.name = calendar.name; | |
| 72 | 16 | base.properties = calendar.properties; | |
| 73 |
1/1✓ Branch 21 → 22 taken 16 times.
|
16 | base.removeProperties(QStringLiteral("METHOD")); |
| 74 |
2/2✓ Branch 33 → 26 taken 4047 times.
✓ Branch 33 → 34 taken 16 times.
|
4063 | for (const ICal::Component &component : calendar.components) |
| 75 |
3/3✓ Branch 29 → 30 taken 7 times.
✓ Branch 29 → 31 taken 4040 times.
✓ Branch 30 → 31 taken 7 times.
|
4047 | if (component.name != QLatin1String("VEVENT")) base.components.append(component); |
| 76 | // VEVENTs grouped by UID in file order. | ||
| 77 | 16 | QStringList order; | |
| 78 | 16 | QHash<QString, QList<ICal::Component>> byUid; | |
| 79 |
2/2✓ Branch 93 → 36 taken 4047 times.
✓ Branch 93 → 94 taken 16 times.
|
4063 | for (const ICal::Component &component : calendar.components) { |
| 80 |
2/2✓ Branch 39 → 40 taken 7 times.
✓ Branch 39 → 41 taken 4040 times.
|
4049 | if (component.name != QLatin1String("VEVENT")) continue; |
| 81 |
3/3✓ Branch 44 → 45 taken 4040 times.
✓ Branch 45 → 46 taken 4040 times.
✓ Branch 46 → 47 taken 4040 times.
|
4040 | const QString uid = ICal::unescapeText(component.value(QStringLiteral("UID"))).trimmed(); |
| 82 |
2/2✓ Branch 52 → 53 taken 2 times.
✓ Branch 52 → 64 taken 4038 times.
|
4040 | if (uid.isEmpty()) { |
| 83 |
5/5✓ Branch 53 → 54 taken 2 times.
✓ Branch 57 → 58 taken 2 times.
✓ Branch 58 → 59 taken 2 times.
✓ Branch 62 → 55 taken 2 times.
✓ Branch 62 → 63 taken 2 times.
|
4 | qCWarning(lcIcsFile) << "Skipping VEVENT without UID"; |
| 84 | 2 | continue; | |
| 85 | 2 | } | |
| 86 |
2/2✓ Branch 65 → 66 taken 4030 times.
✓ Branch 65 → 82 taken 8 times.
|
4038 | if (!byUid.contains(uid)) { |
| 87 |
1/2✗ Branch 67 → 68 not taken.
✓ Branch 67 → 81 taken 4030 times.
|
4030 | if (order.size() == MaxEntries) { |
| 88 | ✗ | qCWarning(lcIcsFile) << "Calendar file has more than" << MaxEntries << "appointments; the rest is skipped"; | |
| 89 | ✗ | break; | |
| 90 | } | ||
| 91 |
1/1✓ Branch 81 → 82 taken 4030 times.
|
4030 | order.append(uid); |
| 92 | } | ||
| 93 |
2/2✓ Branch 82 → 83 taken 4038 times.
✓ Branch 83 → 84 taken 4038 times.
|
4038 | byUid[uid].append(component); |
| 94 | 4040 | } | |
| 95 | 16 | qint64 used = 0; | |
| 96 |
4/4✓ Branch 94 → 95 taken 16 times.
✓ Branch 95 → 96 taken 16 times.
✓ Branch 160 → 97 taken 184 times.
✓ Branch 160 → 161 taken 15 times.
|
199 | for (const QString &uid : order) { |
| 97 |
1/1✓ Branch 99 → 100 taken 184 times.
|
184 | ICal::Component resource = entryBase(base, byUid.value(uid)); |
| 98 | // A VTODO or VJOURNAL of the file belongs to no appointment. | ||
| 99 |
1/1✓ Branch 104 → 105 taken 184 times.
|
184 | resource.removeComponents(QStringLiteral("VTODO")); |
| 100 |
1/1✓ Branch 110 → 111 taken 184 times.
|
184 | resource.removeComponents(QStringLiteral("VJOURNAL")); |
| 101 |
5/5✓ Branch 114 → 115 taken 184 times.
✓ Branch 115 → 116 taken 184 times.
✓ Branch 118 → 119 taken 192 times.
✓ Branch 121 → 117 taken 192 times.
✓ Branch 121 → 122 taken 184 times.
|
376 | for (const ICal::Component &vevent : byUid.value(uid)) resource.components.append(vevent); |
| 102 |
1/1✓ Branch 123 → 124 taken 184 times.
|
184 | const QString resourceText = ICal::serialize(resource); |
| 103 |
3/3✓ Branch 124 → 125 taken 184 times.
✓ Branch 125 → 126 taken 1 time.
✓ Branch 125 → 128 taken 183 times.
|
184 | if (!withinBudget(&used, resourceText, error)) return {}; |
| 104 |
1/1✓ Branch 128 → 129 taken 183 times.
|
183 | const ICalTime::ZoneResolver resolver(resource); |
| 105 | 183 | Entry entry; | |
| 106 | 183 | entry.uid = uid; | |
| 107 |
4/4✓ Branch 131 → 132 taken 183 times.
✓ Branch 132 → 133 taken 183 times.
✓ Branch 144 → 134 taken 191 times.
✓ Branch 144 → 145 taken 183 times.
|
374 | for (const ICal::Component &vevent : byUid.value(uid)) { |
| 108 |
1/1✓ Branch 135 → 136 taken 191 times.
|
191 | CalendarEvent row = ICalEventCodec::eventFromComponent(vevent, resolver); |
| 109 | 191 | row.resourceIcal = resourceText; | |
| 110 | // The master leads the series. | ||
| 111 |
4/4✓ Branch 137 → 138 taken 191 times.
✓ Branch 138 → 139 taken 183 times.
✓ Branch 138 → 140 taken 8 times.
✓ Branch 139 → 141 taken 183 times.
|
191 | if (!row.recurrenceId.isValid()) entry.rows.prepend(row); |
| 112 |
1/1✓ Branch 140 → 141 taken 8 times.
|
8 | else entry.rows.append(row); |
| 113 | 374 | } | |
| 114 |
1/1✓ Branch 146 → 147 taken 183 times.
|
183 | entries.append(entry); |
| 115 | 185 | } | |
| 116 |
7/7✓ Branch 161 → 162 taken 15 times.
✓ Branch 165 → 166 taken 15 times.
✓ Branch 166 → 167 taken 15 times.
✓ Branch 168 → 169 taken 15 times.
✓ Branch 169 → 170 taken 15 times.
✓ Branch 173 → 163 taken 15 times.
✓ Branch 173 → 174 taken 15 times.
|
30 | qCInfo(lcIcsFile) << "Read" << entries.size() << "appointments from a calendar file"; |
| 117 | 15 | return entries; | |
| 118 | 18 | } | |
| 119 | |||
| 120 | 9 | QByteArray write(const QList<QList<CalendarEvent>> &series) { | |
| 121 | 9 | ICal::Component calendar; | |
| 122 | 9 | calendar.name = QStringLiteral("VCALENDAR"); | |
| 123 | 9 | ICal::Property version; | |
| 124 | 9 | version.name = QStringLiteral("VERSION"); | |
| 125 | 9 | version.value = QStringLiteral("2.0"); | |
| 126 | 9 | ICal::Property prodid; | |
| 127 | 9 | prodid.name = QStringLiteral("PRODID"); | |
| 128 | 9 | prodid.value = QStringLiteral("-//MailJD//MailJD Calendar//EN"); | |
| 129 |
1/1✓ Branch 32 → 33 taken 9 times.
|
9 | calendar.appendProperty(version); |
| 130 |
1/1✓ Branch 33 → 34 taken 9 times.
|
9 | calendar.appendProperty(prodid); |
| 131 | 9 | QSet<QString> zones; | |
| 132 | 9 | QList<ICal::Component> events; | |
| 133 |
2/2✓ Branch 104 → 37 taken 14 times.
✓ Branch 104 → 105 taken 9 times.
|
23 | for (const QList<CalendarEvent> &rows : series) { |
| 134 |
1/2✗ Branch 39 → 40 not taken.
✓ Branch 39 → 41 taken 14 times.
|
14 | if (rows.isEmpty()) continue; |
| 135 | 14 | CalendarEvent master = rows.first(); | |
| 136 | 14 | QList<CalendarEvent> exceptions; | |
| 137 |
2/2✓ Branch 52 → 45 taken 22 times.
✓ Branch 52 → 53 taken 14 times.
|
36 | for (const CalendarEvent &row : rows) { |
| 138 |
3/3✓ Branch 46 → 47 taken 22 times.
✓ Branch 47 → 48 taken 14 times.
✓ Branch 47 → 49 taken 8 times.
|
22 | if (!row.recurrenceId.isValid()) master = row; |
| 139 |
1/1✓ Branch 49 → 50 taken 8 times.
|
8 | else exceptions.append(row); |
| 140 | } | ||
| 141 | const ICal::Component resource = | ||
| 142 |
3/3✓ Branch 56 → 57 taken 14 times.
✓ Branch 57 → 58 taken 14 times.
✓ Branch 58 → 59 taken 14 times.
|
14 | ICal::parseFirst(QString::fromUtf8(ICalEventCodec::buildResource(master, exceptions, master.resourceIcal))); |
| 143 |
2/2✓ Branch 96 → 65 taken 23 times.
✓ Branch 96 → 97 taken 14 times.
|
37 | for (const ICal::Component &component : resource.components) { |
| 144 |
2/2✓ Branch 68 → 69 taken 1 time.
✓ Branch 68 → 90 taken 22 times.
|
23 | if (component.name == QLatin1String("VTIMEZONE")) { |
| 145 |
3/3✓ Branch 72 → 73 taken 1 time.
✓ Branch 73 → 74 taken 1 time.
✓ Branch 74 → 75 taken 1 time.
|
1 | const QString tzid = ICal::unescapeText(component.value(QStringLiteral("TZID"))).trimmed(); |
| 146 |
1/2✗ Branch 80 → 81 not taken.
✓ Branch 80 → 82 taken 1 time.
|
1 | if (zones.contains(tzid)) continue; |
| 147 |
1/1✓ Branch 82 → 83 taken 1 time.
|
1 | zones.insert(tzid); |
| 148 |
1/1✓ Branch 83 → 84 taken 1 time.
|
1 | calendar.components.append(component); |
| 149 |
2/4✓ Branch 86 → 87 taken 1 time.
✗ Branch 86 → 89 not taken.
✓ Branch 92 → 93 taken 22 times.
✗ Branch 92 → 94 not taken.
|
23 | } else if (component.name == QLatin1String("VEVENT")) { |
| 150 |
1/1✓ Branch 93 → 94 taken 22 times.
|
22 | events.append(component); |
| 151 | } | ||
| 152 | } | ||
| 153 | 14 | } | |
| 154 |
1/1✓ Branch 105 → 106 taken 9 times.
|
9 | calendar.components.append(events); |
| 155 |
2/2✓ Branch 106 → 107 taken 9 times.
✓ Branch 107 → 108 taken 9 times.
|
18 | return ICal::serialize(calendar).toUtf8(); |
| 156 | 9 | } | |
| 157 | |||
| 158 | 11 | QList<TodoEntry> readTodos(const QString &text, QString *error) { | |
| 159 | 11 | QList<TodoEntry> entries; | |
| 160 |
3/3✓ Branch 2 → 3 taken 11 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 6 taken 10 times.
|
11 | if (!withinSize(text, error)) return entries; |
| 161 |
1/1✓ Branch 9 → 10 taken 10 times.
|
10 | const ICal::Component calendar = ICal::parseFirst(text, QStringLiteral("VCALENDAR"), error); |
| 162 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 16 taken 10 times.
|
10 | if (calendar.name.isEmpty()) return entries; |
| 163 | 10 | ICal::Component base; | |
| 164 | 10 | base.name = calendar.name; | |
| 165 | 10 | base.properties = calendar.properties; | |
| 166 |
1/1✓ Branch 21 → 22 taken 10 times.
|
10 | base.removeProperties(QStringLiteral("METHOD")); |
| 167 |
2/2✓ Branch 33 → 26 taken 32 times.
✓ Branch 33 → 34 taken 10 times.
|
42 | for (const ICal::Component &component : calendar.components) |
| 168 |
3/3✓ Branch 29 → 30 taken 2 times.
✓ Branch 29 → 31 taken 30 times.
✓ Branch 30 → 31 taken 2 times.
|
32 | if (component.name == QLatin1String("VTIMEZONE")) base.components.append(component); |
| 169 | 10 | QStringList order; | |
| 170 | 10 | QHash<QString, QList<ICal::Component>> byUid; | |
| 171 |
2/2✓ Branch 93 → 36 taken 32 times.
✓ Branch 93 → 94 taken 10 times.
|
42 | for (const ICal::Component &component : calendar.components) { |
| 172 |
2/2✓ Branch 39 → 40 taken 28 times.
✓ Branch 39 → 41 taken 4 times.
|
32 | if (component.name != QLatin1String("VTODO")) continue; |
| 173 |
3/3✓ Branch 44 → 45 taken 4 times.
✓ Branch 45 → 46 taken 4 times.
✓ Branch 46 → 47 taken 4 times.
|
4 | const QString uid = ICal::unescapeText(component.value(QStringLiteral("UID"))).trimmed(); |
| 174 |
1/2✗ Branch 52 → 53 not taken.
✓ Branch 52 → 64 taken 4 times.
|
4 | if (uid.isEmpty()) { |
| 175 | ✗ | qCWarning(lcIcsFile) << "Skipping VTODO without UID"; | |
| 176 | ✗ | continue; | |
| 177 | ✗ | } | |
| 178 |
1/2✓ Branch 65 → 66 taken 4 times.
✗ Branch 65 → 82 not taken.
|
4 | if (!byUid.contains(uid)) { |
| 179 |
1/2✗ Branch 67 → 68 not taken.
✓ Branch 67 → 81 taken 4 times.
|
4 | if (order.size() == MaxEntries) { |
| 180 | ✗ | qCWarning(lcIcsFile) << "Calendar file has more than" << MaxEntries << "tasks; the rest is skipped"; | |
| 181 | ✗ | break; | |
| 182 | } | ||
| 183 |
1/1✓ Branch 81 → 82 taken 4 times.
|
4 | order.append(uid); |
| 184 | } | ||
| 185 |
2/2✓ Branch 82 → 83 taken 4 times.
✓ Branch 83 → 84 taken 4 times.
|
4 | byUid[uid].append(component); |
| 186 | 4 | } | |
| 187 | 10 | qint64 used = 0; | |
| 188 |
4/4✓ Branch 94 → 95 taken 10 times.
✓ Branch 95 → 96 taken 10 times.
✓ Branch 131 → 97 taken 4 times.
✓ Branch 131 → 132 taken 10 times.
|
14 | for (const QString &uid : order) { |
| 189 |
1/1✓ Branch 99 → 100 taken 4 times.
|
4 | ICal::Component resource = entryBase(base, byUid.value(uid)); |
| 190 |
5/5✓ Branch 102 → 103 taken 4 times.
✓ Branch 103 → 104 taken 4 times.
✓ Branch 106 → 107 taken 4 times.
✓ Branch 109 → 105 taken 4 times.
✓ Branch 109 → 110 taken 4 times.
|
8 | for (const ICal::Component &vtodo : byUid.value(uid)) resource.components.append(vtodo); |
| 191 |
1/1✓ Branch 111 → 112 taken 4 times.
|
4 | const QString resourceText = ICal::serialize(resource); |
| 192 |
2/3✓ Branch 112 → 113 taken 4 times.
✗ Branch 113 → 114 not taken.
✓ Branch 113 → 116 taken 4 times.
|
4 | if (!withinBudget(&used, resourceText, error)) return {}; |
| 193 | 4 | entries.append({uid, resourceText}); | |
| 194 | 4 | } | |
| 195 |
7/7✓ Branch 132 → 133 taken 10 times.
✓ Branch 136 → 137 taken 10 times.
✓ Branch 137 → 138 taken 10 times.
✓ Branch 139 → 140 taken 10 times.
✓ Branch 140 → 141 taken 10 times.
✓ Branch 144 → 134 taken 10 times.
✓ Branch 144 → 145 taken 10 times.
|
20 | qCInfo(lcIcsFile) << "Read" << entries.size() << "tasks from a calendar file"; |
| 196 | 10 | return entries; | |
| 197 | 15 | } | |
| 198 | |||
| 199 | 1 | QByteArray writeTodos(const QStringList &resources) { | |
| 200 | 1 | ICal::Component calendar; | |
| 201 | 1 | calendar.name = QStringLiteral("VCALENDAR"); | |
| 202 | 1 | ICal::Property version; | |
| 203 | 1 | version.name = QStringLiteral("VERSION"); | |
| 204 | 1 | version.value = QStringLiteral("2.0"); | |
| 205 | 1 | ICal::Property prodid; | |
| 206 | 1 | prodid.name = QStringLiteral("PRODID"); | |
| 207 | 1 | prodid.value = QStringLiteral("-//MailJD//MailJD Tasks//EN"); | |
| 208 |
1/1✓ Branch 32 → 33 taken 1 time.
|
1 | calendar.appendProperty(version); |
| 209 |
1/1✓ Branch 33 → 34 taken 1 time.
|
1 | calendar.appendProperty(prodid); |
| 210 | 1 | QSet<QString> zones; | |
| 211 | 1 | QList<ICal::Component> todos; | |
| 212 |
2/2✓ Branch 81 → 37 taken 2 times.
✓ Branch 81 → 82 taken 1 time.
|
3 | for (const QString &text : resources) { |
| 213 |
1/1✓ Branch 41 → 42 taken 2 times.
|
2 | const ICal::Component resource = ICal::parseFirst(text, QStringLiteral("VCALENDAR")); |
| 214 |
2/2✓ Branch 77 → 46 taken 3 times.
✓ Branch 77 → 78 taken 2 times.
|
5 | for (const ICal::Component &component : resource.components) { |
| 215 |
2/2✓ Branch 49 → 50 taken 1 time.
✓ Branch 49 → 71 taken 2 times.
|
3 | if (component.name == QLatin1String("VTIMEZONE")) { |
| 216 |
3/3✓ Branch 53 → 54 taken 1 time.
✓ Branch 54 → 55 taken 1 time.
✓ Branch 55 → 56 taken 1 time.
|
1 | const QString tzid = ICal::unescapeText(component.value(QStringLiteral("TZID"))).trimmed(); |
| 217 |
1/2✗ Branch 61 → 62 not taken.
✓ Branch 61 → 63 taken 1 time.
|
1 | if (zones.contains(tzid)) continue; |
| 218 |
1/1✓ Branch 63 → 64 taken 1 time.
|
1 | zones.insert(tzid); |
| 219 |
1/1✓ Branch 64 → 65 taken 1 time.
|
1 | calendar.components.append(component); |
| 220 |
2/4✓ Branch 67 → 68 taken 1 time.
✗ Branch 67 → 70 not taken.
✓ Branch 73 → 74 taken 2 times.
✗ Branch 73 → 75 not taken.
|
3 | } else if (component.name == QLatin1String("VTODO")) { |
| 221 |
1/1✓ Branch 74 → 75 taken 2 times.
|
2 | todos.append(component); |
| 222 | } | ||
| 223 | } | ||
| 224 | 2 | } | |
| 225 |
1/1✓ Branch 82 → 83 taken 1 time.
|
1 | calendar.components.append(todos); |
| 226 |
2/2✓ Branch 83 → 84 taken 1 time.
✓ Branch 84 → 85 taken 1 time.
|
2 | return ICal::serialize(calendar).toUtf8(); |
| 227 | 1 | } | |
| 228 | |||
| 229 | 12 | QString fileName(const QString &title) { | |
| 230 | 12 | QString name; | |
| 231 |
6/6✓ Branch 2 → 3 taken 12 times.
✓ Branch 3 → 4 taken 12 times.
✓ Branch 5 → 6 taken 12 times.
✓ Branch 6 → 7 taken 12 times.
✓ Branch 25 → 8 taken 83 times.
✓ Branch 25 → 26 taken 12 times.
|
95 | for (const QChar c : title.trimmed().left(80)) { |
| 232 |
8/15✓ Branch 9 → 10 taken 83 times.
✗ Branch 9 → 15 not taken.
✓ Branch 13 → 14 taken 83 times.
✓ Branch 14 → 15 taken 4 times.
✓ Branch 14 → 16 taken 79 times.
✓ Branch 17 → 18 taken 83 times.
✗ Branch 17 → 19 not taken.
✓ Branch 19 → 20 taken 83 times.
✗ Branch 19 → 21 not taken.
✓ Branch 21 → 22 taken 4 times.
✓ Branch 21 → 23 taken 79 times.
✗ Branch 65 → 66 not taken.
✗ Branch 65 → 67 not taken.
✗ Branch 69 → 70 not taken.
✗ Branch 69 → 71 not taken.
|
166 | if (c.category() == QChar::Other_Control || QStringLiteral("/\\:*?\"<>|").contains(c)) continue; |
| 233 |
1/1✓ Branch 23 → 24 taken 79 times.
|
79 | name += c; |
| 234 | 12 | } | |
| 235 | // No hidden files and no "..": leading dots go. | ||
| 236 |
8/9✓ Branch 28 → 29 taken 5 times.
✓ Branch 31 → 32 taken 17 times.
✓ Branch 32 → 33 taken 12 times.
✓ Branch 32 → 37 taken 5 times.
✓ Branch 35 → 36 taken 12 times.
✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 12 times.
✓ Branch 39 → 28 taken 5 times.
✓ Branch 39 → 40 taken 12 times.
|
17 | while (name.startsWith(QLatin1Char('.')) || name.startsWith(QLatin1Char(' '))) name.remove(0, 1); |
| 237 |
1/1✓ Branch 40 → 41 taken 12 times.
|
12 | name = name.trimmed(); |
| 238 |
5/7✓ Branch 47 → 48 taken 2 times.
✓ Branch 47 → 51 taken 10 times.
✓ Branch 52 → 53 taken 12 times.
✓ Branch 55 → 56 taken 2 times.
✓ Branch 55 → 57 taken 10 times.
✗ Branch 83 → 84 not taken.
✗ Branch 83 → 85 not taken.
|
26 | return (name.isEmpty() ? QStringLiteral("appointment") : name) + QStringLiteral(".ics"); |
| 239 | 12 | } | |
| 240 | |||
| 241 | } // namespace IcsFile | ||
| 242 |