diff --git a/README.md b/README.md index f81b10c..efec110 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ A PDF of the working specification for Outlook rules files (.rwz) files can be f ```swift let data = Data(contentsOfFile: ".rwz")! -let file = try OutlookRulesFile(data: data) +let file = try OutlookRules(data: data) print(file.rules.count) print(file.rules[0].name) print(file.rules[0].enabled) diff --git a/Sources/OutlookRulesReader/OutlookRulesFile.swift b/Sources/OutlookRulesReader/OutlookRules.swift similarity index 73% rename from Sources/OutlookRulesReader/OutlookRulesFile.swift rename to Sources/OutlookRulesReader/OutlookRules.swift index 949ff55..43e9e24 100644 --- a/Sources/OutlookRulesReader/OutlookRulesFile.swift +++ b/Sources/OutlookRulesReader/OutlookRules.swift @@ -1,5 +1,5 @@ // -// OutlookRulesFile.swift +// OutlookRules.swift // // // Created by Hugh Bellamy on 28/07/2020. @@ -8,8 +8,9 @@ import DataStream import Foundation -public struct OutlookRulesFile: CustomDebugStringConvertible { - public var rules: [Rule] = [] +public struct OutlookRules: CustomDebugStringConvertible { + public let rules: [Rule] + private var header: RulesHeader private var footer: RulesFooter? public var templateDirectory: String { get { @@ -21,6 +22,7 @@ public struct OutlookRulesFile: CustomDebugStringConvertible { public init(rules: [Rule] = []) { self.rules = rules + self.header = RulesHeader(numberOfRules: 0) self.footer = RulesFooter() } @@ -30,7 +32,7 @@ public struct OutlookRulesFile: CustomDebugStringConvertible { } public init(dataStream: inout DataStream) throws { - let header = try RulesHeader(dataStream: &dataStream) + self.header = try RulesHeader(dataStream: &dataStream) var rules: [Rule] = [] rules.reserveCapacity(Int(header.numberOfRules)) @@ -48,18 +50,20 @@ public struct OutlookRulesFile: CustomDebugStringConvertible { } } - public func getData() -> Data { + public func getData(version: OutlookRulesVersion? = nil) -> Data { + let version = version ?? self.header.version + var dataStream = OutputDataStream() let header = RulesHeader(numberOfRules: UInt16(rules.count)) - header.write(to: &dataStream) + header.write(to: &dataStream, version: version) for (index, rule) in rules.enumerated() { - rule.write(to: &dataStream, index: index) + rule.write(to: &dataStream, index: index, version: version) } let footer = RulesFooter() - footer.write(to: &dataStream) + footer.write(to: &dataStream, version: version) return dataStream.data } diff --git a/Sources/OutlookRulesReader/OutlookRulesReadError.swift b/Sources/OutlookRulesReader/OutlookRulesReadError.swift index 63cc94b..5a6928c 100644 --- a/Sources/OutlookRulesReader/OutlookRulesReadError.swift +++ b/Sources/OutlookRulesReader/OutlookRulesReadError.swift @@ -1,5 +1,5 @@ // -// OutlookRulesFileError.swift +// OutlookRulesError.swift // // // Created by Hugh Bellamy on 28/07/2020. diff --git a/Sources/OutlookRulesReader/Rule.swift b/Sources/OutlookRulesReader/Rule.swift index ddc5003..ccc582b 100644 --- a/Sources/OutlookRulesReader/Rule.swift +++ b/Sources/OutlookRulesReader/Rule.swift @@ -10,265 +10,45 @@ import DataStream public struct Rule: CustomDebugStringConvertible { public var name: String public var enabled: Bool - public var applyCondition: ApplyConditionFlags! + public var eventFlags: RuleEventFlags - public var conditions: [RuleElement] = [] - public var actions: [RuleElement] = [] - public var exceptions: [RuleElement] = [] + public var elements: [RuleElement] = [] + + public var conditions: [RuleElement] { + elements.filter { $0.identifier.rawValue >= 200 && $0.identifier.rawValue < 300 } + } + public var actions: [RuleElement] { + elements.filter { $0.identifier.rawValue >= 300 && $0.identifier.rawValue < 400 } + } + public var exceptions: [RuleElement] { + elements.filter { $0.identifier.rawValue >= 500 && $0.identifier.rawValue < 600 } + } public init( - applyCondition: ApplyConditionFlags, + eventFlags: RuleEventFlags, name: String, enabled: Bool = true, conditions: [RuleElement] = [], actions: [RuleElement] = [], exceptions: [RuleElement] = [] ) { - self.applyCondition = applyCondition + self.eventFlags = eventFlags self.name = name self.enabled = enabled - self.conditions = conditions - self.actions = actions - self.exceptions = exceptions + self.elements = conditions + actions + exceptions } public init(dataStream: inout DataStream, index: Int, version: OutlookRulesVersion) throws { + /// Header (n bytes) let header = try RuleHeader(dataStream: &dataStream, index: index, version: version) self.name = header.name self.enabled = header.enabled + /// Elements (variable) + var elements: [RuleElement] = [] + elements.reserveCapacity(Int(header.numberOfElements)) for i in 0..(type: T.Type) throws where T: RuleElementData { - let data = try T(dataStream: &dataStream, version: version) - conditions.append(RuleElement(identifier: identifier, data: data)) - } - - func addAction(type: T.Type) throws where T: RuleElementData { - let data = try T(dataStream: &dataStream, version: version) - actions.append(RuleElement(identifier: identifier, data: data)) - } - - func addException(type: T.Type) throws where T: RuleElementData { - let data = try T(dataStream: &dataStream, version: version) - exceptions.append(RuleElement(identifier: identifier, data: data)) - } - - switch identifier { - /// Mandatory Elements - case .applyCondition: // 0x0190 - applyCondition = try ApplyConditionRuleElementData(dataStream: &dataStream, version: version).flags - case .unknown0x64: // 0x0064 - let _ = try RuleElement0x64Data(dataStream: &dataStream, version: version) - - /// Conditions - case .nameInToBoxCondition: // 0x000C8 - try addCondition(type: SimpleRuleElementData.self) - case .sentOnlyToMeCondition: // 0x000C9 - try addCondition(type: SimpleRuleElementData.self) - case .nameNotInToBoxCondition: // 0x00CA - try addCondition(type: SimpleRuleElementData.self) - case .fromCondition: // 0x00CB - try addCondition(type: PeopleOrPublicGroupListRuleElementData.self) - case .sentToCondition: // 0x00CC - try addCondition(type: PeopleOrPublicGroupListRuleElementData.self) - case .specificWordsInSubjectCondition: // 0x00CD - try addCondition(type: StringsListRuleElementData.self) - case .specificWordsInBodyCondition: // 0x00CE - try addCondition(type: StringsListRuleElementData.self) - case .specificWordsInSubjectOrBodyCondition: // 0x00CF - try addCondition(type: StringsListRuleElementData.self) - case .flaggedForActionCondition: // 0x00D0 - try addCondition(type: FlaggedForActionRuleElementData.self) - case .importanceCondition: // 0x00D2 - try addCondition(type: ImportanceRuleElementData.self) - case .sensitivityCondition: // 0x00D3 - try addCondition(type: SensitivityRuleElementData.self) - case .assignedToCategoryCondition: // 0x00D7 - try addCondition(type: CategoriesListRuleElementData.self) - case .automaticReplyCondition: // 0x00DC - try addCondition(type: SimpleRuleElementData.self) - case .hasAttachmentCondition: // 0x00DE - try addCondition(type: SimpleRuleElementData.self) - case .withSelectedPropertiesOfDocumentOrFormsCondition: // 0x00DF - try addCondition(type: WithSelectedPropertiesOfDocumentOrFormsRuleElementData.self) - case .sizeInSpecificRangeCondition: // 0x00E0 - try addCondition(type: SizeInSpecificRangeRuleElementData.self) - case .receivedInSpecificDateSpanCondition: // 0x00E1 - try addCondition(type: ReceivedInSpecificDateSpanRuleElementData.self) - case .nameInCcBoxCondition: // 0x00E2 - try addCondition(type: SimpleRuleElementData.self) - case .nameInToOrCcBoxCondition: // 0x00E3 - try addCondition(type: SimpleRuleElementData.self) - case .usesFormCondition: // 0x00E4 - try addCondition(type: FormTypeRuleElementData.self) - case .specificWordsInRecipientsAddressCondition: // 0x00E5 - try addCondition(type: StringsListRuleElementData.self) - case .specificWordsInSendersAddressCondition: // 0x00E6 - try addCondition(type: StringsListRuleElementData.self) - case .specificWordsInMessageHeaderCondition: // 0x00E8 - try addCondition(type: StringsListRuleElementData.self) - case .exceptionListCondition: // 0x00E9 - try addCondition(type: SendersListRuleElementData.self) - case .junkCondition: // 0x00EB - try addCondition(type: SendersListRuleElementData.self) - case .adultCondition: // 0x00EC - try addCondition(type: SendersListRuleElementData.self) - case .relevanceInSpecificRangeCondition: // 0x00ED - try addCondition(type: RelevanceInSpecificRangeRuleElementData.self) - case .throughSpecifiedAccountCondition: // 0x00EE - try addCondition(type: ThroughAccountRuleElementData.self) - case .onThisComputerOnlyCondition: // 0x00EF - try addCondition(type: OnThisComputerOnlyRuleElementData.self) - case .senderInSpecifiedAddressBookCondition: // 0x00F0 - try addCondition(type: SenderInSpecifiedAddressBookRuleElementData.self) - case .whichIsAMeetingInvitationOrInviteCondition: // 0x00F1 - try addCondition(type: SimpleRuleElementData.self) - case .alertCondition: // 0x00F3 - try addCondition(type: AlertRuleElementData.self) - case .specificInfoPathFormCondition: // 0x00F4 - try addCondition(type: FormTypeRuleElementData.self) - case .fromRSSFeedsWithSpecifiedTextInTitleCondition: // 0x00F5 - try addCondition(type: StringsListRuleElementData.self) - case .assignedToAnyCategoryCondition: // 0x00F6 - try addCondition(type: SimpleRuleElementData.self) - case .fromAnyRSSFeedCondition: // 0x00F7 - try addCondition(type: SimpleRuleElementData.self) - - /// Actions - case .forwardAction: // 0x012B - try addAction(type: PeopleOrPublicGroupListRuleElementData.self) - case .moveToFolderAction: // 0x012C - try addAction(type: MoveToFolderRuleElementData.self) - case .deleteAction: // 0x012D - try addAction(type: SimpleRuleElementData.self) - case .replyUsingTemplateAction: // 0x012F - try addAction(type: PathRuleElementData.self) - case .displayMessageInNewItemAlertWindowAction: // 0x0130 - try addAction(type: DisplayMessageInNewItemAlertWindowRuleElementData.self) - case .flagAction: // 0x0131 - try addAction(type: FlagRuleElementData.self) - case .clearFlagAction: // 0x0132 - try addAction(type: SimpleRuleElementData.self) - case .assignToCategoryAction: // 0x0133 - try addAction(type: CategoriesListRuleElementData.self) - case .playSoundAction: // 0x0136 - try addAction(type: PathRuleElementData.self) - case .markImportanceAction: // 0x0137 - try addAction(type: ImportanceRuleElementData.self) - case .markSensitivityAction: // 0x0138 - try addAction(type: SensitivityRuleElementData.self) - case .moveCopyToFolderAction: // 0x0139 - try addAction(type: MoveToFolderRuleElementData.self) - case .notifyReadAction: // 0x013A - try addAction(type: SimpleRuleElementData.self) - case .notifyDeliveredAction: // 0x013B - try addAction(type: SimpleRuleElementData.self) - case .ccAction: // 0x013C - try addAction(type: PeopleOrPublicGroupListRuleElementData.self) - case .deferDeliveryAction: // 0x013E - try addAction(type: DeferDeliveryRuleElementData.self) - case .performCustomActionAction: - try addAction(type: PerformCustomActionRuleElementData.self) - case .stopProcessingMoreRulesAction: // 0x0142 - try addAction(type: SimpleRuleElementData.self) - case .doNotSearchForCommercialOrAdultContentAction: // 0x0143 - try addAction(type: SimpleRuleElementData.self) - case .redirectAction: // 0x0144 - try addAction(type: PeopleOrPublicGroupListRuleElementData.self) - case .addToRelevanceAction: // 0x0145 - try addAction(type: AddToRelevanceRuleElementData.self) - case .automaticReply: // 0x0146 - try addAction(type: AutomaticReplyRuleElementData.self) - case .forwardAsAttachmentAction: // 0x0147 - try addAction(type: PeopleOrPublicGroupListRuleElementData.self) - case .printAction: // 0x0148 - try addAction(type: SimpleRuleElementData.self) - case .startApplicationAction: // 0x0149 - try addAction(type: PathRuleElementData.self) - case .permanentlyDeleteAction: // 0x014A - try addAction(type: SimpleRuleElementData.self) - case .runScriptAction: // 0x014B - try addAction(type: RunScriptRuleElementData.self) - case .markAsReadAction: // 0x014C - try addAction(type: SimpleRuleElementData.self) - case .displayDesktopAlertAction: // 0x014F - try addAction(type: SimpleRuleElementData.self) - case .flagForFollowUpAction: // 0x0151 - try addAction(type: FlagForFollowUpRuleElementData.self) - case .clearCategoriesAction: // 0x0152 - try addAction(type: SimpleRuleElementData.self) - case .applyRetentionPolicyAction: // 0x0153 - try addAction(type: ApplyRetentionPolicyRuleElementData.self) - - /// Exceptions - case .nameInToBoxException: // 0x01F4 - try addException(type: SimpleRuleElementData.self) - case .sentOnlyToMeException: // 0x01F5 - try addException(type: SimpleRuleElementData.self) - case .nameNotInToBoxException: // 0x01F6 - try addException(type: SimpleRuleElementData.self) - case .fromException: // 0x01F7 - try addException(type: PeopleOrPublicGroupListRuleElementData.self) - case .toException: // 0x01F8 - try addException(type: PeopleOrPublicGroupListRuleElementData.self) - case .specificWordsInSubjectException: // 0x01F9 - try addException(type: StringsListRuleElementData.self) - case .specificWordsInBodyException: // 0x01FA - try addException(type: StringsListRuleElementData.self) - case .specificWordsInSubjectOrBodyException: // 0x01FB - try addException(type: StringsListRuleElementData.self) - case .flaggedForActionException: // 0x1FC - try addException(type: FlaggedForActionRuleElementData.self) - case .importanceException: // 0x01FE - try addException(type: ImportanceRuleElementData.self) - case .sensitivityConditionException: // 0x01FF - try addException(type: SensitivityRuleElementData.self) - case .assignedToCategoryException: // 0x0203 - try addException(type: CategoriesListRuleElementData.self) - case .automaticReplyException: // 0x0208 - try addException(type: SimpleRuleElementData.self) - case .hasAttachmentException: // 0x020A - try addException(type: SimpleRuleElementData.self) - case .withSelectedPropertiesOfDocumentOrFormsException: // 0x020B - try addException(type: WithSelectedPropertiesOfDocumentOrFormsRuleElementData.self) - case .sizeInSpecificRangeException: // 0x020C - try addException(type: SizeInSpecificRangeRuleElementData.self) - case .receivedInSpecificDateSpanException: // 0x020D - try addException(type: ReceivedInSpecificDateSpanRuleElementData.self) - case .nameInCcBoxException: // 0x020E - try addException(type: SimpleRuleElementData.self) - case .nameInToOrCcBoxException: // 0x020F - try addException(type: SimpleRuleElementData.self) - case .usesFormException: // 0x0210 - try addException(type: FormTypeRuleElementData.self) - case .specificWordsInRecipientsAddressException: // 0x0211 - try addException(type: StringsListRuleElementData.self) - case .specificWordsInSendersAddressException: // 0x0212 - try addException(type: StringsListRuleElementData.self) - case .specificWordsInMessageHeaderException: // 0x0213 - try addException(type: StringsListRuleElementData.self) - case .throughSpecifiedAccountException: // 0x0214 - try addException(type: ThroughAccountRuleElementData.self) - case .senderInSpecifiedAddressBookException: // 0x0215 - try addException(type: SenderInSpecifiedAddressBookRuleElementData.self) - case .whichIsAMeetingInvitationOrInviteException: // 0x0216 - try addException(type: SimpleRuleElementData.self) - case .specificInfoPathFormException: // 0x0218 - try addException(type: FormTypeRuleElementData.self) - case .fromRSSFeedsWithSpecifiedTextInTitleException: // 0x0219 - try addException(type: StringsListRuleElementData.self) - case .assignedToAnyCategoryException: // 0x021A - try addException(type: SimpleRuleElementData.self) - case .fromAnyRSSFeedException: // 0x021B - try addException(type: SimpleRuleElementData.self) - } + elements.append(try RuleElement(dataStream: &dataStream, version: version)) /// Separator (2 bytes) if i != header.numberOfElements - 1 { @@ -278,6 +58,15 @@ public struct Rule: CustomDebugStringConvertible { } } } + + self.elements = elements + + guard let eventElement = elements.first(where: { $0.identifier == .eventFlags }), + let eventParameter = eventElement.parameter as? EventParameter else { + throw OutlookRulesReadError.corrupted + } + + self.eventFlags = eventParameter.flags } public var debugDescription: String { @@ -286,23 +75,24 @@ public struct Rule: CustomDebugStringConvertible { return s } - public func write(to dataStream: inout OutputDataStream, index: Int) { + public func write(to dataStream: inout OutputDataStream, index: Int, version: OutlookRulesVersion) { var elements: [RuleElement] = [ // First element is rule condition - RuleElement(identifier: .applyCondition, data: ApplyConditionRuleElementData(flags: self.applyCondition)), + RuleElement(identifier: .eventFlags, parameter: EventParameter(flags: self.eventFlags)), // Second element is unknown (0x0064). - RuleElement(identifier: .unknown0x64, data: RuleElement0x64Data()) + RuleElement(identifier: .unknown0x64, parameter: Unknown0x64Parameter()) ] elements.append(contentsOf: conditions) elements.append(contentsOf: actions) - + elements.append(contentsOf: exceptions) + let numberOfElements = UInt16(elements.count) let separatorDataSize = UInt32(2 * (elements.count - 1)) /// Number of Rule Elements (2 bytes) /// Separator (2 bytes) - /// Magic (2 bytes) + /// Padding (2 bytes) /// Class Name Length (2 bytes) /// Class Name (12 bytes - CRuleElement) let remainingLength: UInt32 = 2 + 2 + 2 + 2 + 12 @@ -312,8 +102,8 @@ public struct Rule: CustomDebugStringConvertible { header.write(to: &dataStream, index: index) for (i, element) in elements.enumerated() { - // Element (variable) - element.write(to: &dataStream) + /// Element (variable) + element.write(to: &dataStream, version: version) if i != elements.count - 1 { /// Separator (2 bytes) diff --git a/Sources/OutlookRulesReader/RuleElement.swift b/Sources/OutlookRulesReader/RuleElement.swift index 34c1db1..e1e2125 100644 --- a/Sources/OutlookRulesReader/RuleElement.swift +++ b/Sources/OutlookRulesReader/RuleElement.swift @@ -1,6 +1,6 @@ // // RuleElement.swift -// +// // // Created by Hugh Bellamy on 11/08/2020. // @@ -9,25 +9,271 @@ import DataStream public struct RuleElement { public var dataSize: UInt32 { - return 4 + data.dataSize + 8 + parameters.reduce(0, { $0 + $1.dataSize }) } public var identifier: RuleElementIdentifier - public var data: RuleElementData + public var parameters: [RuleParameter] + + public var parameter: RuleParameter? { + parameters.first + } + + public init(identifier: RuleElementIdentifier, parameter: RuleParameter) { + self.init(identifier: identifier, parameters: [parameter]) + } - public init(identifier: RuleElementIdentifier, data: RuleElementData) { + public init(identifier: RuleElementIdentifier, parameters: [RuleParameter] = []) { /// Identifier (4 bytes) self.identifier = identifier - /// Data (variable) - self.data = data + /// Parameters (variable) + self.parameters = parameters + } + + public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { + /// Identifier (4 bytes) + let identifierRaw: UInt32 = try dataStream.read(endianess: .littleEndian) + guard let identifier = RuleElementIdentifier(rawValue: identifierRaw) else { + throw OutlookRulesReadError.corrupted + } + + self.identifier = identifier + + /// Number of Parameters (4 bytes) + let numberOfParameters: UInt32 = try dataStream.read(endianess: .littleEndian) + + /// Parameters (variable) + var parameters: [RuleParameter] = [] + parameters.reserveCapacity(Int(numberOfParameters)) + for _ in 0..= .outlook2002 { + UTF16String(value: field).write(to: &dataStream) + } else { + ASCIIString(value: field).write(to: &dataStream) + } /// Tag (4 bytes) tag.write(to: &dataStream) @@ -141,7 +145,11 @@ public struct DocumentProperty { dataStream.write(rawStringMatchType, endianess: .littleEndian) /// String Value (variable) - UTF16String(value: stringValue).write(to: &dataStream) + if version >= .outlook2002 { + UTF16String(value: stringValue).write(to: &dataStream) + } else { + ASCIIString(value: stringValue).write(to: &dataStream) + } /// Number Match Type (4 bytes) dataStream.write(rawNumberMatchType, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Objects/DateWithTimestamp.swift b/Sources/OutlookRulesReader/Structures/Objects/OleDateTime.swift similarity index 100% rename from Sources/OutlookRulesReader/Structures/Objects/DateWithTimestamp.swift rename to Sources/OutlookRulesReader/Structures/Objects/OleDateTime.swift diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/ThroughAccountRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/AccountParameter.swift similarity index 69% rename from Sources/OutlookRulesReader/Structures/Rule Elements/ThroughAccountRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/AccountParameter.swift index cf36328..8213800 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/ThroughAccountRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/AccountParameter.swift @@ -1,5 +1,5 @@ // -// ThroughAccountCondition.swift +// AccountParameter.swift // // // Created by Hugh Bellamy on 29/07/2020. @@ -7,15 +7,14 @@ import DataStream -public struct ThroughAccountRuleElementData: RuleElementData { +public struct AccountParameter: RuleParameter { public var dataSize: UInt32 { - var baseSize: UInt32 = 8 + var baseSize: UInt32 = 4 baseSize += UTF16String(value: accountName).dataSize baseSize += ASCIIString(value: accountName).dataSize return baseSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var accountName: String public var unknown: String @@ -26,12 +25,6 @@ public struct ThroughAccountRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -42,10 +35,7 @@ public struct ThroughAccountRuleElementData: RuleElementData { self.unknown = try ASCIIString(dataStream: &dataStream).value } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/SenderInSpecifiedAddressBookRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/AddressBookParameter.swift similarity index 66% rename from Sources/OutlookRulesReader/Structures/Rule Elements/SenderInSpecifiedAddressBookRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/AddressBookParameter.swift index 00c282c..2ef076d 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/SenderInSpecifiedAddressBookRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/AddressBookParameter.swift @@ -1,5 +1,5 @@ // -// SenderInSpecifiedAddressBookRuleElementData.swift +// AddressBookParameter.swift // // // Created by Hugh Bellamy on 28/07/2020. @@ -8,15 +8,14 @@ import DataStream import MAPI -public struct SenderInSpecifiedAddressBookRuleElementData: RuleElementData { +public struct AddressBookParameter: RuleParameter { public var dataSize: UInt32 { - var baseSize: UInt32 = 12 + var baseSize: UInt32 = 4 baseSize += UInt32(FlatEntry(entryID: entryId).dataSize) baseSize += UTF16String(value: name).dataSize return baseSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var entryId: EntryID public var name: String @@ -27,12 +26,6 @@ public struct SenderInSpecifiedAddressBookRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -43,10 +36,7 @@ public struct SenderInSpecifiedAddressBookRuleElementData: RuleElementData { self.name = try UTF16String(dataStream: &dataStream).value } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/PeopleOrPublicGroupListRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/AddressParameter.swift similarity index 61% rename from Sources/OutlookRulesReader/Structures/Rule Elements/PeopleOrPublicGroupListRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/AddressParameter.swift index bb0d1ff..dc866a6 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/PeopleOrPublicGroupListRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/AddressParameter.swift @@ -1,5 +1,5 @@ // -// PeopleOrPublicGroupList.swift +// AddressParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -7,44 +7,35 @@ import DataStream -public struct PeopleOrPublicGroupListRuleElementData: RuleElementData { +public struct AddressParameter: RuleParameter { public var dataSize: UInt32 { - let result: UInt32 = 20 + let result: UInt32 = 16 for _ in values { // TODO } return result } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 - public var numberOfValues: UInt32 = 0 public var values: [[UInt16 : Any]] = [] public var unknown1: UInt32 = 1 public var unknown2: UInt32 = 0 public init(values: [[UInt16: Any]]) { - self.numberOfValues = UInt32(values.count) self.values = values } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) /// Number of Values (4 bytes) - self.numberOfValues = try dataStream.read(endianess: .littleEndian) + let numberOfValues: UInt32 = try dataStream.read(endianess: .littleEndian) /// Values (variable) var values: [[UInt16 : Any]] = [] - values.reserveCapacity(Int(self.numberOfValues)) - for _ in 0..= .outlook2002 { + UTF16String(value: rawCategories).write(to: &dataStream) + } else { + ASCIIString(value: rawCategories).write(to: &dataStream) + } } } diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/PerformCustomActionRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/CustomActionParameter.swift similarity index 69% rename from Sources/OutlookRulesReader/Structures/Rule Elements/PerformCustomActionRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/CustomActionParameter.swift index 27ee226..0952b73 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/PerformCustomActionRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/CustomActionParameter.swift @@ -1,5 +1,5 @@ // -// PerformCustomActionRuleElementData.swift +// CustomActionParameter.swift // // // Created by Hugh Bellamy on 31/01/2021. @@ -7,16 +7,15 @@ import DataStream -public struct PerformCustomActionRuleElementData: RuleElementData { +public struct CustomActionParameter: RuleParameter { public var dataSize: UInt32 { - var baseSize: UInt32 = 8 + var baseSize: UInt32 = 4 baseSize += UTF16String(value: location).dataSize baseSize += UTF16String(value: name).dataSize baseSize += UTF16String(value: actionValue).dataSize return baseSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var location: String public var name: String @@ -31,12 +30,6 @@ public struct PerformCustomActionRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -69,23 +62,36 @@ public struct PerformCustomActionRuleElementData: RuleElementData { } } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) /// Location (variable) - UTF16String(value: location).write(to: &dataStream) + if version >= .outlook2002 { + UTF16String(value: location).write(to: &dataStream) + } else { + ASCIIString(value: location).write(to: &dataStream) + } /// Name (variable) - UTF16String(value: name).write(to: &dataStream) + if version >= .outlook2002 { + UTF16String(value: name).write(to: &dataStream) + } else { + ASCIIString(value: name).write(to: &dataStream) + } /// Options (variable) - UTF16String(value: options).write(to: &dataStream) + if version >= .outlook2002 { + UTF16String(value: options).write(to: &dataStream) + } else { + ASCIIString(value: options).write(to: &dataStream) + } /// Action Value (variable) - UTF16String(value: actionValue).write(to: &dataStream) + if version >= .outlook2002 { + UTF16String(value: actionValue).write(to: &dataStream) + } else { + ASCIIString(value: actionValue).write(to: &dataStream) + } } } diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/DeferDeliveryRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/DeferParameter.swift similarity index 56% rename from Sources/OutlookRulesReader/Structures/Rule Elements/DeferDeliveryRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/DeferParameter.swift index 72047af..8451230 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/DeferDeliveryRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/DeferParameter.swift @@ -1,5 +1,5 @@ // -// DeferDeliveryRuleElementData.swift +// DeferParameter.swift // // // Created by Hugh Bellamy on 28/07/2020. @@ -7,10 +7,9 @@ import DataStream -public struct DeferDeliveryRuleElementData: RuleElementData { - public let dataSize: UInt32 = 12 +public struct DeferParameter: RuleParameter { + public let dataSize: UInt32 = 8 - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var minutes: UInt32 @@ -19,12 +18,6 @@ public struct DeferDeliveryRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -32,10 +25,7 @@ public struct DeferDeliveryRuleElementData: RuleElementData { self.minutes = try dataStream.read(endianess: .littleEndian) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/FlagForFollowUpRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/FlagForFollowUpParameter.swift similarity index 69% rename from Sources/OutlookRulesReader/Structures/Rule Elements/FlagForFollowUpRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/FlagForFollowUpParameter.swift index 52d9e38..d8639bb 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/FlagForFollowUpRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/FlagForFollowUpParameter.swift @@ -1,5 +1,5 @@ // -// FlagForFollowUpRuleElementData.swift +// FlagForFollowUpParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -7,6 +7,7 @@ import DataStream +/// Specifies the time period for which an Outlook item is marked as a task. public enum FollowUp: UInt32 { case today = 0x00000001 case tomorrow = 0x00000002 @@ -16,14 +17,11 @@ public enum FollowUp: UInt32 { case completed = 0x0000000A } -public struct FlagForFollowUpRuleElementData: RuleElementData { +public struct FlagForFollowUpParameter: RuleParameter { public var dataSize: UInt32 { - var baseSize: UInt32 = 12 - baseSize += UTF16String(value: actionName).dataSize - return baseSize + 4 + UTF16String(value: actionName).dataSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var rawFollowUp: UInt32 public var followUp: FollowUp { @@ -41,12 +39,6 @@ public struct FlagForFollowUpRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -57,10 +49,7 @@ public struct FlagForFollowUpRuleElementData: RuleElementData { self.actionName = try UTF16String(dataStream: &dataStream).value } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/FlagRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/FlagRuleElementData.swift similarity index 75% rename from Sources/OutlookRulesReader/Structures/Rule Elements/FlagRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/FlagRuleElementData.swift index a8882cb..164847a 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/FlagRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/FlagRuleElementData.swift @@ -7,14 +7,13 @@ import DataStream -public struct FlagRuleElementData: RuleElementData { +public struct FlagRuleElementData: RuleParameter { public var dataSize: UInt32 { - var baseSize: UInt32 = 16 + var baseSize: UInt32 = 12 baseSize += UTF16String(value: actionName).dataSize return baseSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var days: UInt32 public var actionName: String @@ -26,12 +25,6 @@ public struct FlagRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -49,10 +42,7 @@ public struct FlagRuleElementData: RuleElementData { self.unknown = try dataStream.read(endianess: .littleEndian) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/FlaggedForActionRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/FlaggedForActionParameter.swift similarity index 74% rename from Sources/OutlookRulesReader/Structures/Rule Elements/FlaggedForActionRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/FlaggedForActionParameter.swift index de3680f..c743c32 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/FlaggedForActionRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/FlaggedForActionParameter.swift @@ -1,5 +1,5 @@ // -// FlaggedForActionCondition.swift +// FlaggedForActionParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -7,7 +7,7 @@ import DataStream -public struct FlaggedForActionRuleElementData: RuleElementData { +public struct FlaggedForActionParameter: RuleParameter { public var dataSize: UInt32 { var baseSize: UInt32 = 12 baseSize += UTF16String(value: action).dataSize @@ -15,7 +15,6 @@ public struct FlaggedForActionRuleElementData: RuleElementData { return baseSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var unknown1: UInt32 = 0 public var action: String @@ -26,12 +25,6 @@ public struct FlaggedForActionRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -49,10 +42,7 @@ public struct FlaggedForActionRuleElementData: RuleElementData { self.unknown2 = try dataStream.read(endianess: .littleEndian) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/MoveToFolderRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/FolderParameter.swift similarity index 77% rename from Sources/OutlookRulesReader/Structures/Rule Elements/MoveToFolderRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/FolderParameter.swift index 79f8bff..099c97d 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/MoveToFolderRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/FolderParameter.swift @@ -1,5 +1,5 @@ // -// MoveToFolderRuleElementData.swift +// FolderParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -8,7 +8,7 @@ import DataStream import MAPI -public struct MoveToFolderRuleElementData: RuleElementData { +public struct FolderParameter: RuleParameter { public var dataSize: UInt32 { var baseSize: UInt32 = 8 baseSize += UInt32(FlatEntry(entryID: folderEntryId).dataSize) @@ -17,7 +17,6 @@ public struct MoveToFolderRuleElementData: RuleElementData { return baseSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var folderEntryId: EntryID public var storeEntryId: EntryID @@ -31,12 +30,6 @@ public struct MoveToFolderRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -61,10 +54,7 @@ public struct MoveToFolderRuleElementData: RuleElementData { } } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) @@ -77,9 +67,9 @@ public struct MoveToFolderRuleElementData: RuleElementData { /// Folder Name (variable) UTF16String(value: folderName).write(to: &dataStream) - if let secondaryUserStore = secondaryUserStore { + if version != .noSignature { /// Secondary User Store (4 bytes) - dataStream.write((secondaryUserStore ? 1 : 0) as UInt32, endianess: .littleEndian) + dataStream.write((secondaryUserStore! ? 1 : 0) as UInt32, endianess: .littleEndian) } } } diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/WithSelectedPropertiesOfDocumentOrFormsRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/FormParameter.swift similarity index 83% rename from Sources/OutlookRulesReader/Structures/Rule Elements/WithSelectedPropertiesOfDocumentOrFormsRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/FormParameter.swift index a454010..e6bd180 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/WithSelectedPropertiesOfDocumentOrFormsRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/FormParameter.swift @@ -1,5 +1,5 @@ // -// UsesFormRuleElementData.swift +// FormParameter.swift // // // Created by Hugh Bellamy on 29/07/2020. @@ -9,9 +9,9 @@ import DataStream import Foundation import MAPI -public struct WithSelectedPropertiesOfDocumentOrFormsRuleElementData: RuleElementData { +public struct FormParameter: RuleParameter { public var dataSize: UInt32 { - var baseSize: UInt32 = 8 + var baseSize: UInt32 = 4 for form in forms { baseSize += UTF16String(value: form).dataSize } @@ -27,7 +27,6 @@ public struct WithSelectedPropertiesOfDocumentOrFormsRuleElementData: RuleElemen return baseSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var forms: [String] public var documentProperties: [DocumentProperty] @@ -40,12 +39,6 @@ public struct WithSelectedPropertiesOfDocumentOrFormsRuleElementData: RuleElemen } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -86,10 +79,7 @@ public struct WithSelectedPropertiesOfDocumentOrFormsRuleElementData: RuleElemen self.classes = classes } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) @@ -101,7 +91,7 @@ public struct WithSelectedPropertiesOfDocumentOrFormsRuleElementData: RuleElemen /// Document Properties (variable) for documentProperty in documentProperties { - documentProperty.write(to: &dataStream) + documentProperty.write(to: &dataStream, version: version) } /// Number of Classes (4 bytes) diff --git a/Sources/OutlookRulesReader/Structures/Objects/Form.swift b/Sources/OutlookRulesReader/Structures/Parameters/FormTypeParameter.swift similarity index 75% rename from Sources/OutlookRulesReader/Structures/Objects/Form.swift rename to Sources/OutlookRulesReader/Structures/Parameters/FormTypeParameter.swift index 0bbfeff..b41e236 100644 --- a/Sources/OutlookRulesReader/Structures/Objects/Form.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/FormTypeParameter.swift @@ -1,13 +1,13 @@ // -// Form.swift -// +// FormTypeParameter.swift // -// Created by Hugh Bellamy on 04/02/2021. +// +// Created by Hugh Bellamy on 29/07/2020. // import DataStream -public struct Form { +public struct FormTypeParameter: RuleParameter { public var dataSize: UInt32 { var baseSize: UInt32 = 4 baseSize += UTF16String(value: name).dataSize @@ -39,12 +39,16 @@ public struct Form { self.className = try ASCIIString(dataStream: &dataStream).value } - public func write(to dataStream: inout OutputDataStream) { + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) /// Name (variable) - UTF16String(value: name).write(to: &dataStream) + if version >= .outlook2002 { + UTF16String(value: name).write(to: &dataStream) + } else { + ASCIIString(value: name).write(to: &dataStream) + } /// Class Name (variable) ASCIIString(value: name).write(to: &dataStream) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/ImportanceRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/ImportanceParameter.swift similarity index 66% rename from Sources/OutlookRulesReader/Structures/Rule Elements/ImportanceRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/ImportanceParameter.swift index 00cf2f9..cfac010 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/ImportanceRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/ImportanceParameter.swift @@ -1,5 +1,5 @@ // -// ImportanceRuleElementData.swift +// ImportanceParameter.swift // // // Created by Hugh Bellamy on 28/07/2020. @@ -8,10 +8,9 @@ import DataStream import MAPI -public struct ImportanceRuleElementData: RuleElementData { +public struct ImportanceParameter: RuleParameter { public let dataSize: UInt32 = 12 - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var rawImportance: UInt32 public var importance: MessageImportance { @@ -27,12 +26,6 @@ public struct ImportanceRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -40,10 +33,7 @@ public struct ImportanceRuleElementData: RuleElementData { self.rawImportance = try dataStream.read(endianess: .littleEndian) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/DisplayMessageInNewItemAlertWindowRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/MessageParameter.swift similarity index 56% rename from Sources/OutlookRulesReader/Structures/Rule Elements/DisplayMessageInNewItemAlertWindowRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/MessageParameter.swift index 19e2ebe..f3398a7 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/DisplayMessageInNewItemAlertWindowRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/MessageParameter.swift @@ -1,5 +1,5 @@ // -// DisplayMessageInNewItemAlertWindowRuleElementData.swift +// MessageParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -7,12 +7,11 @@ import DataStream -public struct DisplayMessageInNewItemAlertWindowRuleElementData: RuleElementData { +public struct MessageParameter: RuleParameter { public var dataSize: UInt32 { - return 8 + UTF16String(value: message).dataSize + 4 + UTF16String(value: message).dataSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var message: String @@ -21,12 +20,6 @@ public struct DisplayMessageInNewItemAlertWindowRuleElementData: RuleElementData } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -38,14 +31,15 @@ public struct DisplayMessageInNewItemAlertWindowRuleElementData: RuleElementData } } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) /// Message (variable) - UTF16String(value: message).write(to: &dataStream) + if version >= .outlook2002 { + UTF16String(value: message).write(to: &dataStream) + } else { + ASCIIString(value: message).write(to: &dataStream) + } } } diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/PathRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/PathParameter.swift similarity index 58% rename from Sources/OutlookRulesReader/Structures/Rule Elements/PathRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/PathParameter.swift index a431a4a..8ce5445 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/PathRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/PathParameter.swift @@ -1,5 +1,5 @@ // -// PathRuleElementData.swift +// PathParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -7,12 +7,11 @@ import DataStream -public struct PathRuleElementData: RuleElementData { +public struct PathParameter: RuleParameter { public var dataSize: UInt32 { - return 8 + UTF16String(value: path).dataSize + 4 + UTF16String(value: path).dataSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var path: String @@ -21,12 +20,6 @@ public struct PathRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -38,14 +31,15 @@ public struct PathRuleElementData: RuleElementData { } } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) /// Path (variable) - UTF16String(value: path).write(to: &dataStream) + if version >= .outlook2002 { + UTF16String(value: path).write(to: &dataStream) + } else { + ASCIIString(value: path).write(to: &dataStream) + } } } diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/OnThisComputerOnlyRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/ProfileStampParameter.swift similarity index 60% rename from Sources/OutlookRulesReader/Structures/Rule Elements/OnThisComputerOnlyRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/ProfileStampParameter.swift index 243ae6a..e0d5794 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/OnThisComputerOnlyRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/ProfileStampParameter.swift @@ -1,5 +1,5 @@ // -// OnThisComputerOnlyCondition.swift +// ProfileStampParameter.swift // // // Created by Hugh Bellamy on 07/08/2020. @@ -8,10 +8,9 @@ import DataStream import WindowsDataTypes -public struct OnThisComputerOnlyRuleElementData: RuleElementData { - public let dataSize: UInt32 = 24 +public struct ProfileStampParameter: RuleParameter { + public let dataSize: UInt32 = 20 - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var uuid: GUID @@ -20,9 +19,6 @@ public struct OnThisComputerOnlyRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -30,10 +26,7 @@ public struct OnThisComputerOnlyRuleElementData: RuleElementData { self.uuid = try GUID(dataStream: &dataStream) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Parameters/RelevanceParameter.swift b/Sources/OutlookRulesReader/Structures/Parameters/RelevanceParameter.swift new file mode 100644 index 0000000..89df3cd --- /dev/null +++ b/Sources/OutlookRulesReader/Structures/Parameters/RelevanceParameter.swift @@ -0,0 +1,35 @@ +// +// RelevanceParameter.swift +// +// +// Created by Hugh Bellamy on 28/07/2020. +// + +import DataStream + +internal struct RelevanceParameter: RuleParameter { + public let dataSize: UInt32 = 8 + + public var reserved: UInt32 = 0 + public var value: UInt32 = 1 + + public init(value: UInt32) { + self.value = value + } + + public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { + /// Reserved (4 bytes) + self.reserved = try dataStream.read(endianess: .littleEndian) + + /// Value (4 bytes) + self.value = try dataStream.read(endianess: .littleEndian) + } + + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { + /// Reserved (4 bytes) + dataStream.write(reserved, endianess: .littleEndian) + + /// Value (4 bytes) + dataStream.write(value, endianess: .littleEndian) + } +} diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/RelevanceInSpecificRangeRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/RelevanceRangeParameter.swift similarity index 68% rename from Sources/OutlookRulesReader/Structures/Rule Elements/RelevanceInSpecificRangeRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/RelevanceRangeParameter.swift index 5b8a39e..0031b86 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/RelevanceInSpecificRangeRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/RelevanceRangeParameter.swift @@ -1,5 +1,5 @@ // -// RelevanceInSpecificRangeRuleElementData.swift +// RelevanceRangeParameter.swift // // // Created by Hugh Bellamy on 28/07/2020. @@ -7,10 +7,9 @@ import DataStream -public struct RelevanceInSpecificRangeRuleElementData: RuleElementData { +public struct RelevanceRangeParameter: RuleParameter { public let dataSize: UInt32 = 12 - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var minimumRelevance: UInt32 public var maximumRelevance: UInt32 @@ -21,12 +20,6 @@ public struct RelevanceInSpecificRangeRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -37,10 +30,7 @@ public struct RelevanceInSpecificRangeRuleElementData: RuleElementData { self.maximumRelevance = try dataStream.read(endianess: .littleEndian) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/ApplyRetentionPolicyRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/RetentionPolicyParameter.swift similarity index 62% rename from Sources/OutlookRulesReader/Structures/Rule Elements/ApplyRetentionPolicyRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/RetentionPolicyParameter.swift index b2f2251..ab6eac1 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/ApplyRetentionPolicyRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/RetentionPolicyParameter.swift @@ -1,5 +1,5 @@ // -// ApplyRetentionPolicyRuleElementData.swift +// RetentionPolicyParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -8,12 +8,11 @@ import DataStream import WindowsDataTypes -public struct ApplyRetentionPolicyRuleElementData: RuleElementData { +public struct RetentionPolicyParameter: RuleParameter { public var dataSize: UInt32 { - return 24 + UTF16String(value: name).dataSize + return 20 + UTF16String(value: name).dataSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var guid: GUID public var name: String @@ -24,12 +23,6 @@ public struct ApplyRetentionPolicyRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -40,10 +33,7 @@ public struct ApplyRetentionPolicyRuleElementData: RuleElementData { self.name = try UTF16String(dataStream: &dataStream).value } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/RunScriptRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/ScriptParameter.swift similarity index 63% rename from Sources/OutlookRulesReader/Structures/Rule Elements/RunScriptRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/ScriptParameter.swift index d4b5361..1c4910d 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/RunScriptRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/ScriptParameter.swift @@ -1,5 +1,5 @@ // -// RunScriptRuleElementData.swift +// ScriptParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -7,12 +7,11 @@ import DataStream -public struct RunScriptRuleElementData: RuleElementData { +public struct ScriptParameter: RuleParameter { public var dataSize: UInt32 { - return 8 + UTF16String(value: name).dataSize + UTF16String(value: function).dataSize + 4 + UTF16String(value: name).dataSize + UTF16String(value: function).dataSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var name: String public var function: String @@ -23,12 +22,6 @@ public struct RunScriptRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -39,10 +32,7 @@ public struct RunScriptRuleElementData: RuleElementData { self.function = try UTF16String(dataStream: &dataStream).value } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/JunkRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/SendersListParameter.swift similarity index 56% rename from Sources/OutlookRulesReader/Structures/Rule Elements/JunkRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/SendersListParameter.swift index 26cb0a3..e0c1463 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/JunkRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/SendersListParameter.swift @@ -1,5 +1,5 @@ // -// SendersListRuleElementData.swift +// SendersListParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -7,12 +7,11 @@ import DataStream -public struct SendersListRuleElementData: RuleElementData { +public struct SendersListParameter: RuleParameter { public var dataSize: UInt32 { - return 8 + ASCIIString(value: name).dataSize + 4 + ASCIIString(value: name).dataSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var name: String @@ -21,12 +20,6 @@ public struct SendersListRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -34,10 +27,7 @@ public struct SendersListRuleElementData: RuleElementData { self.name = try ASCIIString(dataStream: &dataStream).value } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/SensitivityRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/SensitivityParameter.swift similarity index 66% rename from Sources/OutlookRulesReader/Structures/Rule Elements/SensitivityRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/SensitivityParameter.swift index 8c1f4a1..439b2b0 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/SensitivityRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/SensitivityParameter.swift @@ -1,5 +1,5 @@ // -// SensitivityRuleElementData.swift +// SensitivityParameter.swift // // // Created by Hugh Bellamy on 28/07/2020. @@ -8,10 +8,9 @@ import DataStream import MAPI -public struct SensitivityRuleElementData: RuleElementData { +public struct SensitivityParameter: RuleParameter { public let dataSize: UInt32 = 12 - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var rawSensitivity: UInt32 @@ -28,12 +27,6 @@ public struct SensitivityRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -41,10 +34,7 @@ public struct SensitivityRuleElementData: RuleElementData { self.rawSensitivity = try dataStream.read(endianess: .littleEndian) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/SizeInSpecificRangeRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/SizeParameter.swift similarity index 69% rename from Sources/OutlookRulesReader/Structures/Rule Elements/SizeInSpecificRangeRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/SizeParameter.swift index 3403620..d49df46 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/SizeInSpecificRangeRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/SizeParameter.swift @@ -1,5 +1,5 @@ // -// SizeInSpecificRangeRuleElementData.swift +// SizeParameter.swift // // // Created by Hugh Bellamy on 28/07/2020. @@ -7,10 +7,9 @@ import DataStream -public struct SizeInSpecificRangeRuleElementData: RuleElementData { +public struct SizeParameter: RuleParameter { public let dataSize: UInt32 = 12 - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var minSizeInKilobytes: UInt32 public var maxSizeInKilobytes: UInt32 @@ -21,12 +20,6 @@ public struct SizeInSpecificRangeRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -37,10 +30,7 @@ public struct SizeInSpecificRangeRuleElementData: RuleElementData { self.maxSizeInKilobytes = try dataStream.read(endianess: .littleEndian) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Objects/SearchEntry.swift b/Sources/OutlookRulesReader/Structures/Parameters/StringsListRuleElementData.swift similarity index 76% rename from Sources/OutlookRulesReader/Structures/Objects/SearchEntry.swift rename to Sources/OutlookRulesReader/Structures/Parameters/StringsListRuleElementData.swift index e600e1e..ec32c61 100644 --- a/Sources/OutlookRulesReader/Structures/Objects/SearchEntry.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/StringsListRuleElementData.swift @@ -1,15 +1,15 @@ // -// SearchEntry.swift +// StringParameter.swift // // -// Created by Hugh Bellamy on 03/02/2021. +// Created by Hugh Bellamy on 08/08/2020. // import DataStream -internal struct SearchEntry { +public struct StringParameter: RuleParameter { public var dataSize: UInt32 { - return 4 + UTF16String(value: value).dataSize + 4 + UTF16String(value: value).dataSize } public var flags: UInt32 = 0 @@ -31,7 +31,7 @@ internal struct SearchEntry { } } - public func write(to dataStream: inout OutputDataStream) { + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Flags (4 bytes) dataStream.write(flags, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/AutomaticReplyRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/TemplateParameter.swift similarity index 69% rename from Sources/OutlookRulesReader/Structures/Rule Elements/AutomaticReplyRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/TemplateParameter.swift index 7af4a44..2e10ad0 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/AutomaticReplyRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/TemplateParameter.swift @@ -1,5 +1,5 @@ // -// AutomaticReplyRuleElementData.swift +// TemplateParameter.swift // // // Created by Hugh Bellamy on 29/07/2020. @@ -8,15 +8,14 @@ import DataStream import MAPI -public struct AutomaticReplyRuleElementData: RuleElementData { +public struct TemplateParameter: RuleParameter { public var dataSize: UInt32 { - var baseSize: UInt32 = 8 + var baseSize: UInt32 = 4 baseSize += UInt32(FlatEntry(entryID: messageEntryId).dataSize) baseSize += UTF16String(value: name).dataSize return baseSize } - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var messageEntryId: EntryID public var name: String @@ -27,12 +26,6 @@ public struct AutomaticReplyRuleElementData: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -43,10 +36,7 @@ public struct AutomaticReplyRuleElementData: RuleElementData { self.name = try UTF16String(dataStream: &dataStream).value } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/ReceivedInSpecificDateSpanRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Parameters/TimeParameter.swift similarity index 72% rename from Sources/OutlookRulesReader/Structures/Rule Elements/ReceivedInSpecificDateSpanRuleElementData.swift rename to Sources/OutlookRulesReader/Structures/Parameters/TimeParameter.swift index 7ea7c95..b02996a 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/ReceivedInSpecificDateSpanRuleElementData.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/TimeParameter.swift @@ -1,5 +1,5 @@ // -// ReceivedInSpecificDateSpanRuleElementData.swift +// TimeParameter.swift // // // Created by Hugh Bellamy on 08/08/2020. @@ -8,10 +8,9 @@ import DataStream import Foundation -public struct ReceivedInSpecificDateSpanRuleElementData: RuleElementData { - public let dataSize: UInt32 = 12 +public struct TimeParameter: RuleParameter { + public let dataSize: UInt32 = 40 - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var includeAfterDate: Bool public var afterDate: OleDateTime @@ -19,12 +18,6 @@ public struct ReceivedInSpecificDateSpanRuleElementData: RuleElementData { public var beforeDate: OleDateTime public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - /// Reserved (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -41,10 +34,7 @@ public struct ReceivedInSpecificDateSpanRuleElementData: RuleElementData { self.beforeDate = try OleDateTime(dataStream: &dataStream) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reserved (4 bytes) dataStream.write(reserved, endianess: .littleEndian) @@ -59,7 +49,7 @@ public struct ReceivedInSpecificDateSpanRuleElementData: RuleElementData { let includeBeforeDateRaw: UInt32 = includeBeforeDate ? 0x00000001 : 0x00000000 dataStream.write(includeBeforeDateRaw, endianess: .littleEndian) - /// Before Date (4 bytes) + /// Before Date (12 bytes) beforeDate.write(to: &dataStream) } } diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/RuleElement0x64Data.swift b/Sources/OutlookRulesReader/Structures/Parameters/Unknown0x64Parameter.swift similarity index 60% rename from Sources/OutlookRulesReader/Structures/Rule Elements/RuleElement0x64Data.swift rename to Sources/OutlookRulesReader/Structures/Parameters/Unknown0x64Parameter.swift index fbdb64e..de23b82 100644 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/RuleElement0x64Data.swift +++ b/Sources/OutlookRulesReader/Structures/Parameters/Unknown0x64Parameter.swift @@ -1,5 +1,5 @@ // -// RuleElement0x64Condition.swift +// Unknown0x64Parameter.swift // // // Created by Hugh Bellamy on 28/07/2020. @@ -7,10 +7,9 @@ import DataStream -internal struct RuleElement0x64Data: RuleElementData { - public let dataSize: UInt32 = 12 +internal struct Unknown0x64Parameter: RuleParameter { + public let dataSize: UInt32 = 8 - public var extended: UInt32 = 1 public var reserved: UInt32 = 0 public var flags: UInt32 = 1 @@ -18,9 +17,6 @@ internal struct RuleElement0x64Data: RuleElementData { } public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Unknown1 (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - /// Unknown1 (4 bytes) self.reserved = try dataStream.read(endianess: .littleEndian) @@ -28,10 +24,7 @@ internal struct RuleElement0x64Data: RuleElementData { self.flags = try dataStream.read(endianess: .littleEndian) } - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - + public func write(to dataStream: inout OutputDataStream, version: OutlookRulesVersion) { /// Reservd (4 bytes) dataStream.write(reserved, endianess: .littleEndian) diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/AddToRelevanceRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Rule Elements/AddToRelevanceRuleElementData.swift deleted file mode 100644 index c6d49e4..0000000 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/AddToRelevanceRuleElementData.swift +++ /dev/null @@ -1,41 +0,0 @@ -// -// AddToRelevanceRuleElementData.swift -// -// -// Created by Hugh Bellamy on 28/07/2020. -// - -import DataStream - -internal struct AddToRelevanceRuleElementData: RuleElementData { - public let dataSize: UInt32 = 12 - - public var extended: UInt32 = 1 - public var reserved: UInt32 = 0 - public var number: UInt32 = 1 - - public init() { - } - - public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - - /// Reserved (4 bytes) - self.reserved = try dataStream.read(endianess: .littleEndian) - - /// Number (4 bytes) - self.number = try dataStream.read(endianess: .littleEndian) - } - - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - - /// Reserved (4 bytes) - dataStream.write(reserved, endianess: .littleEndian) - - /// Number (4 bytes) - dataStream.write(number, endianess: .littleEndian) - } -} diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/ApplyConditionRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Rule Elements/ApplyConditionRuleElementData.swift deleted file mode 100644 index 04615a1..0000000 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/ApplyConditionRuleElementData.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// ApplyCondition.swift -// -// -// Created by Hugh Bellamy on 28/07/2020. -// - -import DataStream - -public struct ApplyConditionFlags: OptionSet { - public let rawValue: UInt32 - - public init(rawValue: UInt32) { - self.rawValue = rawValue - } - - public static let afterReceived = ApplyConditionFlags(rawValue: 0x01) - public static let afterSent = ApplyConditionFlags(rawValue: 0x04) - public static let afterServerReceived = ApplyConditionFlags(rawValue: 0x08) -} - -public struct ApplyConditionRuleElementData: RuleElementData { - public let dataSize: UInt32 = 12 - - public var extended: UInt32 = 1 - public var reserved: UInt32 = 0 - public let flags: ApplyConditionFlags - - public init(flags: ApplyConditionFlags) { - self.flags = flags - } - - public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Extended (4 bytes) - self.extended = try dataStream.read(endianess: .littleEndian) - guard self.extended == 0x00000001 else { - throw OutlookRulesReadError.corrupted - } - - /// Reserved (4 bytes) - self.reserved = try dataStream.read(endianess: .littleEndian) - - /// Flags (4 bytes) - self.flags = ApplyConditionFlags(rawValue: try dataStream.read(endianess: .littleEndian)) - } - - public func write(to dataStream: inout OutputDataStream) { - /// Extended (4 bytes) - dataStream.write(extended, endianess: .littleEndian) - - /// Reserved (4 bytes) - dataStream.write(reserved, endianess: .littleEndian) - - /// Flags (4 bytes) - dataStream.write(flags.rawValue, endianess: .littleEndian) - } -} diff --git a/Sources/OutlookRulesReader/Structures/Rule Elements/FormTypeRuleElementData.swift b/Sources/OutlookRulesReader/Structures/Rule Elements/FormTypeRuleElementData.swift deleted file mode 100644 index 06b1ea7..0000000 --- a/Sources/OutlookRulesReader/Structures/Rule Elements/FormTypeRuleElementData.swift +++ /dev/null @@ -1,52 +0,0 @@ -// -// UsesFormRuleElementData.swift -// -// -// Created by Hugh Bellamy on 29/07/2020. -// - -import DataStream - -public struct FormTypeRuleElementData: RuleElementData { - public var dataSize: UInt32 { - var baseSize: UInt32 = 4 - for form in forms { - baseSize += form.dataSize - } - - return baseSize - } - - public var numberOfForms: UInt32 = 0 - public var forms: [Form] - - public init(forms: [Form]) { - self.numberOfForms = UInt32(forms.count) - self.forms = forms - } - - public init(dataStream: inout DataStream, version: OutlookRulesVersion) throws { - /// Number of Forms (4 bytes) - self.numberOfForms = try dataStream.read(endianess: .littleEndian) - - /// Forms (variable) - var forms: [Form] = [] - forms.reserveCapacity(Int(self.numberOfForms)) - for _ in 0..1. + +Outlook Rules began as an add-in to Outlook 972 called `RulesWiz.dll `and were integrated in-box automatically in Outlook 983. + +## Storage +Outlook stores Rules Wizard Files differently depending on the version of Outlook4. + +Outlook allows users to import and export Rules to a rules file with the file extension .rwz . The resulting file is known as a Rules Wizard File (shorted to RWZ file). Users can specify backwards compatibility to the latest version of Outlook, Outlook 2002, Outlook 2000 and Outlook 98. +![Rules Export](assets/RulesExport.png) + +### Outlook 2002 and Later +User-created rules and alerts are stored in an account's PST5. + +The rules stream is located in the `PR_RW_RULES_STREAM/PidTagRwRulesStream (0x68020102)` property of a message named `Outlook Rules Organizer` of class `IPM.RuleOrganizer`6 inside the Associated Contents Table7 of the Inbox folder +![Rules Stream](assets/RulesStream.png) + +### Outlook 2000 and Earlier. + +User-created rules and alerts are stored in the file system. + +The rules stream is located in the `C:\Documents and Settings\\Application Data\Microsoft\Outlook\.rwz` file. + +### Additional Notes + +The format of `.rwz` files and the corresponding `PidTagRwRulesStream` property is client-specific and opaque to the server8. Some values within the header are, for example, different between the stream contained in `PidTagRwRulesStream` and the corresponding `.rwz` exported files. However, this document refers to `.rwz` files and the binary value of the `PidTagRwRulesStream` property interchangeably as, by-and-large, they have the same format. + +# Introduction +The Outlook Rules (.rwz) File Format is used to store exported Outlook rules. + +A rules file is a series of variable-length records, called Rules which contain variable-length records. Rules are a series of variable-length records called Rule Elements which contain conditions, actions and exceptions. + +## Glossary +This document uses the following terms: + +**ASCII**: The American Standard Code for Information Interchange (ASCII) is an 8-bit character-encoding scheme based on the English alphabet. ASCII codes represent text in computers, communications equipment, and other devices that work with text. ASCII refers to a single 8-bit ASCII character or an array of 8-bit ASCII characters with the high bit of each character set to zero. + +**big-endian**: Multiple-byte values that are byte-ordered with the most significant byte stored in the +memory location with the lowest address. + +**globally unique identifier (GUID)**: A term used interchangeably with universally unique +identifier (UUID) in Microsoft protocol technical documents (TDs). Interchanging the usage of these terms does not imply or require a specific algorithm or mechanism to generate the value. +Specifically, the use of this term does not imply or require that the algorithms described in +[RFC4122] or [C706] must be used for generating the GUID. See also universally unique identifier (UUID). + +**little-endian**: Multiple-byte values that are byte-ordered with the least significant byte stored in the memory location with the lowest address. + +**timestamp**: A variant time is stored as an 8-byte real value (double), representing a date between January 1, 100 and December 31, 9999, inclusive. The value 2.0 represents January 1, 1900; 3.0 represents January 2, 1900, and so on. Adding 1 to the value increments the date by a day. The fractional part of the value represents the time of day. Therefore, 2.5 represents noon on January 1, 1900; 3.25 represents 6:00 A.M. on January 2, 1900, and so on. Negative numbers represent dates prior to December 30, 1899. The variant time resolves to one second. Any milliseconds in the input date are ignored. + +**UTF-16**: A standard for encoding Unicode characters, defined in the Unicode standard, in which the most commonly used characters are defined as double-byte characters. Unless specified otherwise, this term refers to the UTF-16 encoding form specified in [UNICODE5.0.0/2007] section 3.9. + +**MAY, SHOULD, MUST, SHOULD NOT, MUST NOT**: These terms (in all caps) are used as defined in [RFC2119]. All statements of optional behavior use either MAY, SHOULD, or SHOULD NOT. + +## References +### Normative References +[MS-DTYP] Microsoft Corporation, ["Windows Data Types"](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-dtyp). + +[MS-OXCDATA] Microsoft Corporation, ["Data Structures"](https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcdata/). + +[MS-OXCMSG] Microsoft Corporation, ["Message and Attachment Object Protocol"](https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcmsg/). + +[RFC2119] Bradner, S., “Key words for use in RFCs to Indicate Requirement Levels”, BCP 14, RFC 2119, March 1997, [http://www.rfc-editor.org/rfc/rfc2119.txt](http://www.rfc-editor.org/rfc/rfc2119.txt) + +[UNICODE5.0.0] The Unicode Consortium, “Unicode Default Case Conversion Algorithm 5.0.0”, March 2006, [http://www.unicode.org/Public/5.0.0/ucd/CaseFolding.txt](http://www.unicode.org/Public/5.0.0/ucd/CaseFolding.txt) + +## Overview + +### Rules Structure +A rules file stores a list of rules into a single file or memory buffer. A rule consists of a list of conditions, actions and exceptions that are defined in this specification. +![Rule Structure](assets/RulesStructure.png) +**Figure 1: rules files** + +### Byte Ordering +Data in the rules stream are stored in little-endian format. + +Some computer architectures number bytes in a binary word from left to right, which is referred to as big-endian. The byte numbering used for bitfields in this specification is big-endian. Other +architectures number the bytes in a binary word from right to left, which is referred to as little-endian. + +The byte numbering used for enumerations, objects, and records in this specification is little-endian. + +Using the big-endian and little-endian methods, the number 0x12345678 would be stored as shown in the following table. + +| Byte order | Byte 0 | Byte 1 | Byte 2 | Byte 3 | +|---------------|--------|--------|--------|--------| +| Big-endian | 0x12 | 0x34 | 0x56 | 0x78 | +| Little-endian | 0x78 | 0x56 | 0x34 | 0x12 | + +# References +- [1] https://support.microsoft.com/en-us/office/manage-email-messages-by-using-rules-c24f5dea-9465-4df4-ad17-a50704d66c59 +- [2] https://www.computerhope.com/download/updates.htm +- [3] https://www.slipstick.com/outlook/rules/rules-wizard/ +- [4] https://www.itprotoday.com/email-and-calendaring/how-do-you-delete-and-recreate-corrupt-outlook-rules +- [5] https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxprops/f1fbd19a-9b2c-4c16-a07b-2242b2c0dece +- [6] https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxorule/950a82ff-acde-40b3-8f2f-fc46ceb7a182 +- [7] https://docs.microsoft.com/en-us/office/client-developer/outlook/mapi/contents-tables +- [8] https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxorule/ee0fd52b-1161-49b8-adab-6b8c2e31c3f3 diff --git a/spec/assets/RulesExport.png b/spec/assets/RulesExport.png new file mode 100644 index 0000000..90b6201 Binary files /dev/null and b/spec/assets/RulesExport.png differ diff --git a/spec/assets/RulesStream.png b/spec/assets/RulesStream.png new file mode 100644 index 0000000..0d6fae1 Binary files /dev/null and b/spec/assets/RulesStream.png differ diff --git a/spec/assets/RulesStructure.png b/spec/assets/RulesStructure.png new file mode 100644 index 0000000..b97b620 Binary files /dev/null and b/spec/assets/RulesStructure.png differ