data/ICalendar.h
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <QList> | ||
| 4 | #include <QString> | ||
| 5 | #include <QStringList> | ||
| 6 | |||
| 7 | // RFC 5545 content model: a lossless component tree (Sprint 93 S93.1.1). | ||
| 8 | // | ||
| 9 | // The tree keeps every property, parameter and sub-component it reads. | ||
| 10 | // A property that is never modified is written back with its original | ||
| 11 | // (unfolded) content line, so values MailJD does not understand survive a | ||
| 12 | // parse -> serialize round trip byte for byte (apart from line folding). | ||
| 13 | // Modifying a property through the setters drops that original line and | ||
| 14 | // re-renders it from name/parameters/value. | ||
| 15 | // | ||
| 16 | // Values are kept in their wire form (TEXT escaping included); use | ||
| 17 | // unescapeText()/escapeText() at the call site that interprets them. | ||
| 18 | namespace ICal { | ||
| 19 | |||
| 20 | struct Parameter { | ||
| 21 | QString name; // upper case | ||
| 22 | QString value; // unquoted; multi-values stay comma-separated | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct Property { | ||
| 26 | QString name; // upper case, e.g. "DTSTART", "X-GOOGLE-CONFERENCE" | ||
| 27 | QList<Parameter> parameters; | ||
| 28 | QString value; | ||
| 29 | // Original unfolded content line; empty once the property was modified | ||
| 30 | // or for properties created in code. | ||
| 31 | QString originalLine; | ||
| 32 | |||
| 33 | QString parameter(const QString &name) const; | ||
| 34 | bool hasParameter(const QString &name) const; | ||
| 35 | void setParameter(const QString &name, const QString &value); | ||
| 36 | void removeParameter(const QString &name); | ||
| 37 | void setValue(const QString &newValue); | ||
| 38 | // The unfolded content line (original when untouched). | ||
| 39 | QString contentLine() const; | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct Component { | ||
| 43 | QString name; // upper case, e.g. "VCALENDAR", "VEVENT", "VALARM" | ||
| 44 | QList<Property> properties; | ||
| 45 | QList<Component> components; | ||
| 46 | |||
| 47 | const Property *property(const QString &name) const; | ||
| 48 | Property *property(const QString &name); | ||
| 49 | QList<Property> propertiesNamed(const QString &name) const; | ||
| 50 | QString value(const QString &name) const; | ||
| 51 | bool hasProperty(const QString &name) const; | ||
| 52 | // Replaces the first property of that name (keeping its position) and | ||
| 53 | // removes further ones; appends when absent. | ||
| 54 | void setProperty(const Property &property); | ||
| 55 | void setPropertyValue(const QString &name, const QString &value); | ||
| 56 | int removeProperties(const QString &name); | ||
| 57 | 35887 | void appendProperty(const Property &property) { properties.append(property); } | |
| 58 | QList<Component> componentsNamed(const QString &name) const; | ||
| 59 | int removeComponents(const QString &name); | ||
| 60 | }; | ||
| 61 | |||
| 62 | // Parses a text that contains one or more top-level components (normally a | ||
| 63 | // single VCALENDAR). Lines outside components, malformed lines without a | ||
| 64 | // colon and stray END lines are skipped with a log warning; unbalanced | ||
| 65 | // BEGIN/END fails. Returns false and sets *error on failure. | ||
| 66 | // `skippedLines` (optional) counts the lines that were dropped; writers that | ||
| 67 | // patch a resource refuse to write one whose parse was lossy (Sprint 97). | ||
| 68 | // Components nest at most kMaxComponentDepth deep (S106-124): real calendars | ||
| 69 | // use three levels (VCALENDAR › VEVENT › VALARM); a deeper text fails, so | ||
| 70 | // the recursive serializer and destructor can never run out of stack. | ||
| 71 | constexpr int kMaxComponentDepth = 32; | ||
| 72 | bool parse(const QString &text, QList<Component> *components, QString *error = nullptr, | ||
| 73 | int *skippedLines = nullptr); | ||
| 74 | // Convenience: the first top-level component named `name` (empty on error). | ||
| 75 | Component parseFirst(const QString &text, const QString &name = QStringLiteral("VCALENDAR"), | ||
| 76 | QString *error = nullptr); | ||
| 77 | |||
| 78 | // Serializes with CRLF line ends and folds lines at 75 octets without | ||
| 79 | // splitting UTF-8 sequences (RFC 5545 §3.1). | ||
| 80 | QString serialize(const Component &component); | ||
| 81 | QString foldLine(const QString &line); | ||
| 82 | |||
| 83 | // TEXT value escaping (RFC 5545 §3.3.11): one pass, so "\\n" stays a | ||
| 84 | // backslash followed by "n". | ||
| 85 | QString unescapeText(const QString &value); | ||
| 86 | QString escapeText(const QString &value); | ||
| 87 | |||
| 88 | // Splits a comma-separated multi-value property value (EXDATE, RDATE, | ||
| 89 | // CATEGORIES) while honouring backslash-escaped commas. | ||
| 90 | QStringList splitValues(const QString &value); | ||
| 91 | |||
| 92 | } // namespace ICal | ||
| 93 |