@rapidmx/mapi-plugin 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +382 -0
- package/README.md +60 -0
- package/dist/lib/BaseMapiEmsmdbRoute.js +297 -0
- package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -0
- package/dist/lib/BaseMapiNspiRoute.js +114 -0
- package/dist/lib/BaseMapiNspiRoute.js.map +1 -0
- package/dist/lib/MapiSessionManager.js +119 -0
- package/dist/lib/MapiSessionManager.js.map +1 -0
- package/dist/lib/RopDispatcher.js +34 -0
- package/dist/lib/RopDispatcher.js.map +1 -0
- package/dist/lib/codec/AppointmentRecurrence.js +314 -0
- package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
- package/dist/lib/codec/BufferCursor.js +213 -0
- package/dist/lib/codec/BufferCursor.js.map +1 -0
- package/dist/lib/codec/GlobalObjectId.js +92 -0
- package/dist/lib/codec/GlobalObjectId.js.map +1 -0
- package/dist/lib/codec/MapiGuid.js +41 -0
- package/dist/lib/codec/MapiGuid.js.map +1 -0
- package/dist/lib/codec/MapiTimeZone.js +93 -0
- package/dist/lib/codec/MapiTimeZone.js.map +1 -0
- package/dist/lib/codec/PropertyValue.js +214 -0
- package/dist/lib/codec/PropertyValue.js.map +1 -0
- package/dist/lib/codec/RopBuffer.js +26 -0
- package/dist/lib/codec/RopBuffer.js.map +1 -0
- package/dist/lib/codec/TypedString.js +54 -0
- package/dist/lib/codec/TypedString.js.map +1 -0
- package/dist/lib/index.js +99 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +84 -0
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -0
- package/dist/lib/mongo/MapiNspiRouteMongo.js +33 -0
- package/dist/lib/mongo/MapiNspiRouteMongo.js.map +1 -0
- package/dist/lib/mongo/index.js +7 -0
- package/dist/lib/mongo/index.js.map +1 -0
- package/dist/lib/mongo.js +6 -0
- package/dist/lib/mongo.js.map +1 -0
- package/dist/lib/nspi/NspiBindHandler.js +54 -0
- package/dist/lib/nspi/NspiBindHandler.js.map +1 -0
- package/dist/lib/nspi/NspiCodec.js +106 -0
- package/dist/lib/nspi/NspiCodec.js.map +1 -0
- package/dist/lib/nspi/NspiGetMatchesHandler.js +142 -0
- package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -0
- package/dist/lib/rop/CalendarEventTarget.js +27 -0
- package/dist/lib/rop/CalendarEventTarget.js.map +1 -0
- package/dist/lib/rop/CalendarNamedProperties.js +57 -0
- package/dist/lib/rop/CalendarNamedProperties.js.map +1 -0
- package/dist/lib/rop/ContactTarget.js +23 -0
- package/dist/lib/rop/ContactTarget.js.map +1 -0
- package/dist/lib/rop/FastTransferStream.js +98 -0
- package/dist/lib/rop/FastTransferStream.js.map +1 -0
- package/dist/lib/rop/FolderTarget.js +111 -0
- package/dist/lib/rop/FolderTarget.js.map +1 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js +95 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
- package/dist/lib/rop/MessageBodyStream.js +42 -0
- package/dist/lib/rop/MessageBodyStream.js.map +1 -0
- package/dist/lib/rop/MessageTarget.js +44 -0
- package/dist/lib/rop/MessageTarget.js.map +1 -0
- package/dist/lib/rop/NamedPropertyRegistry.js +66 -0
- package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
- package/dist/lib/rop/PropertyResolvers.js +313 -0
- package/dist/lib/rop/PropertyResolvers.js.map +1 -0
- package/dist/lib/rop/RopCreateMessageHandler.js +53 -0
- package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js +133 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js +70 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +61 -0
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +61 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +75 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js +76 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js +40 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +55 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js +92 -0
- package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js.map +1 -0
- package/dist/lib/rop/RopHandler.js +2 -0
- package/dist/lib/rop/RopHandler.js.map +1 -0
- package/dist/lib/rop/RopLogonHandler.js +132 -0
- package/dist/lib/rop/RopLogonHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenFolderHandler.js +46 -0
- package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenMessageHandler.js +81 -0
- package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenStreamHandler.js +81 -0
- package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopQueryRowsHandler.js +91 -0
- package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
- package/dist/lib/rop/RopReadStreamHandler.js +55 -0
- package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopReleaseHandler.js +20 -0
- package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js +210 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopSetColumnsHandler.js +52 -0
- package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js +162 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js +314 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopWriteStreamHandler.js +45 -0
- package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -0
- package/dist/lib/rop/TaskNamedProperties.js +29 -0
- package/dist/lib/rop/TaskNamedProperties.js.map +1 -0
- package/dist/lib/rop/TaskTarget.js +19 -0
- package/dist/lib/rop/TaskTarget.js.map +1 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js +84 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -0
- package/dist/lib/sql/MapiNspiRouteSQL.js +33 -0
- package/dist/lib/sql/MapiNspiRouteSQL.js.map +1 -0
- package/dist/lib/sql/index.js +7 -0
- package/dist/lib/sql/index.js.map +1 -0
- package/dist/lib/sql.js +6 -0
- package/dist/lib/sql.js.map +1 -0
- package/dist/types/BaseMapiEmsmdbRoute.d.ts +82 -0
- package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
- package/dist/types/MapiSessionManager.d.ts +130 -0
- package/dist/types/RopDispatcher.d.ts +17 -0
- package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
- package/dist/types/codec/BufferCursor.d.ts +78 -0
- package/dist/types/codec/GlobalObjectId.d.ts +11 -0
- package/dist/types/codec/MapiGuid.d.ts +6 -0
- package/dist/types/codec/MapiTimeZone.d.ts +7 -0
- package/dist/types/codec/PropertyValue.d.ts +77 -0
- package/dist/types/codec/RopBuffer.d.ts +25 -0
- package/dist/types/codec/TypedString.d.ts +17 -0
- package/dist/types/index.d.ts +94 -0
- package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +19 -0
- package/dist/types/mongo/MapiNspiRouteMongo.d.ts +13 -0
- package/dist/types/mongo/index.d.ts +2 -0
- package/dist/types/mongo.d.ts +1 -0
- package/dist/types/nspi/NspiBindHandler.d.ts +22 -0
- package/dist/types/nspi/NspiCodec.d.ts +59 -0
- package/dist/types/nspi/NspiGetMatchesHandler.d.ts +24 -0
- package/dist/types/rop/CalendarEventTarget.d.ts +29 -0
- package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
- package/dist/types/rop/ContactTarget.d.ts +29 -0
- package/dist/types/rop/FastTransferStream.d.ts +18 -0
- package/dist/types/rop/FolderTarget.d.ts +63 -0
- package/dist/types/rop/MeetingMessageClassHandler.d.ts +36 -0
- package/dist/types/rop/MessageBodyStream.d.ts +26 -0
- package/dist/types/rop/MessageTarget.d.ts +38 -0
- package/dist/types/rop/NamedPropertyRegistry.d.ts +46 -0
- package/dist/types/rop/PropertyResolvers.d.ts +60 -0
- package/dist/types/rop/RopCreateMessageHandler.d.ts +23 -0
- package/dist/types/rop/RopDeleteFolderHandler.d.ts +38 -0
- package/dist/types/rop/RopDeleteMessagesHandler.d.ts +31 -0
- package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +24 -0
- package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +24 -0
- package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +23 -0
- package/dist/types/rop/RopGetContentsTableHandler.d.ts +31 -0
- package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +17 -0
- package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +23 -0
- package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
- package/dist/types/rop/RopHandler.d.ts +67 -0
- package/dist/types/rop/RopLogonHandler.d.ts +31 -0
- package/dist/types/rop/RopOpenFolderHandler.d.ts +19 -0
- package/dist/types/rop/RopOpenMessageHandler.d.ts +27 -0
- package/dist/types/rop/RopOpenStreamHandler.d.ts +27 -0
- package/dist/types/rop/RopQueryRowsHandler.d.ts +36 -0
- package/dist/types/rop/RopReadStreamHandler.d.ts +18 -0
- package/dist/types/rop/RopReleaseHandler.d.ts +14 -0
- package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +44 -0
- package/dist/types/rop/RopSetColumnsHandler.d.ts +21 -0
- package/dist/types/rop/RopSetPropertiesHandler.d.ts +38 -0
- package/dist/types/rop/RopSubmitMessageHandler.d.ts +70 -0
- package/dist/types/rop/RopWriteStreamHandler.d.ts +21 -0
- package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
- package/dist/types/rop/TaskTarget.d.ts +24 -0
- package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +19 -0
- package/dist/types/sql/MapiNspiRouteSQL.d.ts +13 -0
- package/dist/types/sql/index.d.ts +2 -0
- package/dist/types/sql.d.ts +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { encodeAppointmentRecurrence } from "../codec/AppointmentRecurrence.js";
|
|
6
|
+
import { encodeTimeZoneStruct } from "../codec/MapiTimeZone.js";
|
|
7
|
+
import { PropertyType } from "../codec/PropertyValue.js";
|
|
8
|
+
import { BUSY_STATUS_CODES, LID_APPOINTMENT_END_WHOLE, LID_APPOINTMENT_RECUR, LID_APPOINTMENT_START_WHOLE, LID_BUSY_STATUS, LID_LOCATION, LID_RECURRING, LID_REMINDER_DELTA, LID_REMINDER_SET, LID_RESPONSE_STATUS, LID_TIME_ZONE_STRUCT, PSETID_APPOINTMENT, PSETID_COMMON, RESPONSE_STATUS_CODES, RESPONSE_STATUS_NONE, RESPONSE_STATUS_ORGANIZED, } from "./CalendarNamedProperties.js";
|
|
9
|
+
import { resolveCalendarEventInfo } from "./CalendarEventTarget.js";
|
|
10
|
+
import { resolveContactInfo } from "./ContactTarget.js";
|
|
11
|
+
import { assignOrGetFid, resolveFolderInfo } from "./FolderTarget.js";
|
|
12
|
+
import { assignOrGetMid, resolveMessageInfo } from "./MessageTarget.js";
|
|
13
|
+
import { resolveNamedProperty } from "./NamedPropertyRegistry.js";
|
|
14
|
+
import { LID_PERCENT_COMPLETE, LID_TASK_COMPLETE, LID_TASK_DUE_DATE, LID_TASK_STATUS, PSETID_TASK, TASK_STATUS_COMPLETE, TASK_STATUS_NOT_STARTED, } from "./TaskNamedProperties.js";
|
|
15
|
+
import { resolveTaskInfo } from "./TaskTarget.js";
|
|
16
|
+
// Well-known folder property IDs this pragmatic subset supports - the small set a real client needs to render
|
|
17
|
+
// a folder-hierarchy view. Add more as a real need arises, not speculatively.
|
|
18
|
+
const PID_TAG_DISPLAY_NAME = 0x3001;
|
|
19
|
+
const PID_TAG_FOLDER_ID = 0x6748;
|
|
20
|
+
const PID_TAG_CONTENT_COUNT = 0x3602;
|
|
21
|
+
const PID_TAG_CONTENT_UNREAD_COUNT = 0x3603;
|
|
22
|
+
const PID_TAG_SUBFOLDERS = 0x360a;
|
|
23
|
+
// Well-known message property IDs this pragmatic subset supports - the small set a real client needs to render
|
|
24
|
+
// a message list or a single message's metadata.
|
|
25
|
+
const PID_TAG_SUBJECT = 0x0037;
|
|
26
|
+
const PID_TAG_MESSAGE_FLAGS = 0x0e07;
|
|
27
|
+
const PID_TAG_HAS_ATTACHMENTS = 0x0e1b;
|
|
28
|
+
const PID_TAG_MESSAGE_DELIVERY_TIME = 0x0e06;
|
|
29
|
+
const PID_TAG_MID = 0x674a;
|
|
30
|
+
/** `MSGFLAG_READ`, the one `PidTagMessageFlags` bit this pragmatic subset ever sets. */
|
|
31
|
+
const MSGFLAG_READ = 0x01;
|
|
32
|
+
/** `PidNameKeywords` ([MS-OXPROPS] "Keywords") - Outlook's Categories feature, a `Kind=name` named property
|
|
33
|
+
* (unlike every other named property this pragmatic subset resolves, all `Kind=lid` - see
|
|
34
|
+
* `NamedPropertyRegistry.ts`'s own `PropertyName` shape for why both kinds are supported). Maps directly onto
|
|
35
|
+
* this data model's Gmail-style `Message.labelUids`: Outlook only understands free-text category names, not a
|
|
36
|
+
* `Label.uid` reference, so `resolvePropertyValues` resolves each uid to its `Label.name` before this property
|
|
37
|
+
* is ever read. `PT_MV_UNICODE` (`PtypMultipleString` in this codebase's own enum naming). */
|
|
38
|
+
const PSETID_PUBLIC_STRINGS = "00020329-0000-0000-c000-000000000046";
|
|
39
|
+
const NAME_KEYWORDS = "Keywords";
|
|
40
|
+
// Well-known Contact property IDs this pragmatic subset supports - all plain (non-named) PidTags, per
|
|
41
|
+
// [MS-OXOCNTC], since a Contact needs no PSETID/LID lookup the way Calendar/Task properties do.
|
|
42
|
+
const PID_TAG_GIVEN_NAME = 0x3a06;
|
|
43
|
+
const PID_TAG_SURNAME = 0x3a11;
|
|
44
|
+
const PID_TAG_EMAIL_ADDRESS = 0x3003;
|
|
45
|
+
const PID_TAG_BUSINESS_TELEPHONE_NUMBER = 0x3a08;
|
|
46
|
+
const PID_TAG_COMPANY_NAME = 0x3a16;
|
|
47
|
+
const PID_TAG_TITLE = 0x3a17;
|
|
48
|
+
// Calendar named-property identity (`(PropertySet GUID, LID)` pairs) this pragmatic subset supports - see
|
|
49
|
+
// CalendarNamedProperties.ts's own doc comment. A calendar item's property IDs `>= 0x8000` are resolved back
|
|
50
|
+
// to one of these via `NamedPropertyRegistry.resolveNamedProperty` before this switch can run, since MAPI has
|
|
51
|
+
// no fixed numeric ID for any of them the way `PidTagSubject` has one.
|
|
52
|
+
/** A type-appropriate zero/empty value for a requested property this handler has no real data for - keeps
|
|
53
|
+
* `StandardPropertyRow` encoding valid (a real value of the right type, per `writePropertyValue`'s
|
|
54
|
+
* expectations) without needing to model every property a client could ever ask for. Shared by
|
|
55
|
+
* `RopQueryRowsHandler` (table rows) and `RopGetPropertiesSpecificHandler` (single-object property fetch). */
|
|
56
|
+
export function defaultValueForType(propertyType) {
|
|
57
|
+
switch (propertyType) {
|
|
58
|
+
case PropertyType.PtypBoolean:
|
|
59
|
+
return false;
|
|
60
|
+
case PropertyType.PtypInteger16:
|
|
61
|
+
case PropertyType.PtypInteger32:
|
|
62
|
+
case PropertyType.PtypFloating32:
|
|
63
|
+
case PropertyType.PtypFloating64:
|
|
64
|
+
return 0;
|
|
65
|
+
case PropertyType.PtypInteger64:
|
|
66
|
+
return 0n;
|
|
67
|
+
case PropertyType.PtypTime:
|
|
68
|
+
return new Date(0);
|
|
69
|
+
case PropertyType.PtypGuid:
|
|
70
|
+
return "00000000-0000-0000-0000-000000000000";
|
|
71
|
+
case PropertyType.PtypBinary:
|
|
72
|
+
return Buffer.alloc(0);
|
|
73
|
+
case PropertyType.PtypMultipleInteger32:
|
|
74
|
+
case PropertyType.PtypMultipleString:
|
|
75
|
+
case PropertyType.PtypMultipleString8:
|
|
76
|
+
case PropertyType.PtypMultipleBinary:
|
|
77
|
+
return [];
|
|
78
|
+
case PropertyType.PtypString:
|
|
79
|
+
case PropertyType.PtypString8:
|
|
80
|
+
default:
|
|
81
|
+
return "";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/** Resolves one requested property's value for a `"folder:<uid>"`/`"virtual:<name>"` target. */
|
|
85
|
+
export function folderValueFor(session, propertyId, propertyType, target, info) {
|
|
86
|
+
switch (propertyId) {
|
|
87
|
+
case PID_TAG_DISPLAY_NAME:
|
|
88
|
+
return info.displayName;
|
|
89
|
+
case PID_TAG_FOLDER_ID:
|
|
90
|
+
return BigInt(assignOrGetFid(session, target));
|
|
91
|
+
case PID_TAG_CONTENT_COUNT:
|
|
92
|
+
return info.totalCount;
|
|
93
|
+
case PID_TAG_CONTENT_UNREAD_COUNT:
|
|
94
|
+
return info.unreadCount;
|
|
95
|
+
case PID_TAG_SUBFOLDERS:
|
|
96
|
+
return info.hasChildren;
|
|
97
|
+
default:
|
|
98
|
+
return defaultValueForType(propertyType);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/** Resolves one requested property's value for a `"message:<uid>"` target. `labelNames` is this message's own
|
|
102
|
+
* `labelUids` already resolved to display names (see `resolvePropertyValues`'s own doc comment) - a plain
|
|
103
|
+
* parameter rather than a repo lookup here, since this function (like every other `xxxValueFor`) is
|
|
104
|
+
* synchronous and can't do its own async DB access. */
|
|
105
|
+
export function messageValueFor(session, propertyId, propertyType, target, info, labelNames = []) {
|
|
106
|
+
switch (propertyId) {
|
|
107
|
+
case PID_TAG_SUBJECT:
|
|
108
|
+
return info.subject;
|
|
109
|
+
case PID_TAG_MESSAGE_FLAGS:
|
|
110
|
+
return info.read ? MSGFLAG_READ : 0;
|
|
111
|
+
case PID_TAG_HAS_ATTACHMENTS:
|
|
112
|
+
return info.hasAttachments;
|
|
113
|
+
case PID_TAG_MESSAGE_DELIVERY_TIME:
|
|
114
|
+
return info.receivedDate;
|
|
115
|
+
case PID_TAG_MID:
|
|
116
|
+
return BigInt(assignOrGetMid(session, target));
|
|
117
|
+
default: {
|
|
118
|
+
if (propertyId >= 0x8000) {
|
|
119
|
+
const named = resolveNamedProperty(session, propertyId);
|
|
120
|
+
if (named && named.kind === "name" && named.name === NAME_KEYWORDS && named.guid.toLowerCase() === PSETID_PUBLIC_STRINGS) {
|
|
121
|
+
return labelNames;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return defaultValueForType(propertyType);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/** Resolves one requested property's value for a `"calendarEvent:<uid>"` target. Almost every Appointment
|
|
129
|
+
* property is a *named* property (`PidLid*`, no fixed numeric ID) rather than a plain `PidTag*` - a property ID
|
|
130
|
+
* `>= 0x8000` is resolved back to its `(PropertySet GUID, LID)` identity via `resolveNamedProperty` before this
|
|
131
|
+
* can dispatch on it (see `NamedPropertyRegistry.ts`'s own doc comment and the architecture plan's "Calendar
|
|
132
|
+
* support" section for the full named-property table this switch implements). */
|
|
133
|
+
export function calendarEventValueFor(session, propertyId, propertyType, target, info, callerAddress) {
|
|
134
|
+
if (propertyId === PID_TAG_SUBJECT) {
|
|
135
|
+
return info.title;
|
|
136
|
+
}
|
|
137
|
+
if (propertyId === PID_TAG_MID) {
|
|
138
|
+
return BigInt(assignOrGetMid(session, target));
|
|
139
|
+
}
|
|
140
|
+
if (propertyId < 0x8000) {
|
|
141
|
+
return defaultValueForType(propertyType);
|
|
142
|
+
}
|
|
143
|
+
const namedProperty = resolveNamedProperty(session, propertyId);
|
|
144
|
+
if (!namedProperty || namedProperty.kind !== "lid") {
|
|
145
|
+
return defaultValueForType(propertyType);
|
|
146
|
+
}
|
|
147
|
+
const guid = namedProperty.guid.toLowerCase();
|
|
148
|
+
const isAppointmentProperty = guid === PSETID_APPOINTMENT;
|
|
149
|
+
const isCommonProperty = guid === PSETID_COMMON;
|
|
150
|
+
switch (namedProperty.lid) {
|
|
151
|
+
case LID_LOCATION:
|
|
152
|
+
return isAppointmentProperty ? (info.location ?? "") : defaultValueForType(propertyType);
|
|
153
|
+
case LID_APPOINTMENT_START_WHOLE:
|
|
154
|
+
return isAppointmentProperty ? info.startDate : defaultValueForType(propertyType);
|
|
155
|
+
case LID_APPOINTMENT_END_WHOLE:
|
|
156
|
+
return isAppointmentProperty ? info.endDate : defaultValueForType(propertyType);
|
|
157
|
+
case LID_BUSY_STATUS:
|
|
158
|
+
return isAppointmentProperty ? BUSY_STATUS_CODES[info.busyStatus] : defaultValueForType(propertyType);
|
|
159
|
+
case LID_RECURRING:
|
|
160
|
+
return isAppointmentProperty ? info.recurrenceRule !== undefined : defaultValueForType(propertyType);
|
|
161
|
+
case LID_APPOINTMENT_RECUR:
|
|
162
|
+
return isAppointmentProperty && info.recurrenceRule
|
|
163
|
+
? encodeAppointmentRecurrence(info.recurrenceRule, info.startDate, info.endDate)
|
|
164
|
+
: defaultValueForType(propertyType);
|
|
165
|
+
case LID_TIME_ZONE_STRUCT:
|
|
166
|
+
return isAppointmentProperty ? encodeTimeZoneStruct(info.timezone, info.startDate) : defaultValueForType(propertyType);
|
|
167
|
+
case LID_RESPONSE_STATUS:
|
|
168
|
+
return isAppointmentProperty ? responseStatusFor(info, callerAddress) : defaultValueForType(propertyType);
|
|
169
|
+
case LID_REMINDER_SET:
|
|
170
|
+
return isCommonProperty ? info.reminderMinutesBeforeStart != null : defaultValueForType(propertyType);
|
|
171
|
+
case LID_REMINDER_DELTA:
|
|
172
|
+
return isCommonProperty ? (info.reminderMinutesBeforeStart ?? 0) : defaultValueForType(propertyType);
|
|
173
|
+
default:
|
|
174
|
+
return defaultValueForType(propertyType);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/** The caller's own `PidLidResponseStatus` value: `respOrganized` if the caller mailbox *is* this event's
|
|
178
|
+
* organizer, else the matching `Attendee.responseStatus` (by address, case-insensitive), else `respNone` if the
|
|
179
|
+
* caller isn't party to this event at all (e.g. a shared/delegate calendar view). */
|
|
180
|
+
function responseStatusFor(info, callerAddress) {
|
|
181
|
+
if (callerAddress && info.organizerAddress.toLowerCase() === callerAddress.toLowerCase()) {
|
|
182
|
+
return RESPONSE_STATUS_ORGANIZED;
|
|
183
|
+
}
|
|
184
|
+
const attendee = info.attendees.find((a) => a.address.toLowerCase() === callerAddress.toLowerCase());
|
|
185
|
+
return attendee ? RESPONSE_STATUS_CODES[attendee.responseStatus] : RESPONSE_STATUS_NONE;
|
|
186
|
+
}
|
|
187
|
+
/** Resolves one requested property's value for a `"contact:<uid>"` target - a `Folder` of type `CONTACTS`'s
|
|
188
|
+
* content-table rows/opened items. Every field here is a plain fixed `PidTag` (`[MS-OXOCNTC]`), unlike Calendar/
|
|
189
|
+
* Task's named-property tables, since Contact's own well-known fields all have real numeric IDs. */
|
|
190
|
+
export function contactValueFor(session, propertyId, propertyType, target, info) {
|
|
191
|
+
switch (propertyId) {
|
|
192
|
+
case PID_TAG_SUBJECT:
|
|
193
|
+
return info.displayName;
|
|
194
|
+
case PID_TAG_MID:
|
|
195
|
+
return BigInt(assignOrGetMid(session, target));
|
|
196
|
+
case PID_TAG_GIVEN_NAME:
|
|
197
|
+
return info.givenName ?? "";
|
|
198
|
+
case PID_TAG_SURNAME:
|
|
199
|
+
return info.surname ?? "";
|
|
200
|
+
case PID_TAG_EMAIL_ADDRESS:
|
|
201
|
+
return info.email ?? "";
|
|
202
|
+
case PID_TAG_BUSINESS_TELEPHONE_NUMBER:
|
|
203
|
+
return info.businessPhone ?? "";
|
|
204
|
+
case PID_TAG_COMPANY_NAME:
|
|
205
|
+
return info.companyName ?? "";
|
|
206
|
+
case PID_TAG_TITLE:
|
|
207
|
+
return info.jobTitle ?? "";
|
|
208
|
+
default:
|
|
209
|
+
return defaultValueForType(propertyType);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/** Resolves one requested property's value for a `"task:<uid>"` target - a `Folder` of type `TASKS`'s
|
|
213
|
+
* content-table rows/opened items. Almost every Task-specific property is a *named* property (`PidLid*`) under
|
|
214
|
+
* `PSETID_Task`, resolved back to its `(PropertySet GUID, LID)` identity via `resolveNamedProperty` exactly the
|
|
215
|
+
* same way `calendarEventValueFor` handles `PSETID_Appointment`/`PSETID_Common` - see `TaskNamedProperties.ts`'s
|
|
216
|
+
* own doc comment for the LID table this switch implements. */
|
|
217
|
+
export function taskValueFor(session, propertyId, propertyType, target, info) {
|
|
218
|
+
if (propertyId === PID_TAG_SUBJECT) {
|
|
219
|
+
return info.title;
|
|
220
|
+
}
|
|
221
|
+
if (propertyId === PID_TAG_MID) {
|
|
222
|
+
return BigInt(assignOrGetMid(session, target));
|
|
223
|
+
}
|
|
224
|
+
if (propertyId < 0x8000) {
|
|
225
|
+
return defaultValueForType(propertyType);
|
|
226
|
+
}
|
|
227
|
+
const namedProperty = resolveNamedProperty(session, propertyId);
|
|
228
|
+
if (!namedProperty || namedProperty.kind !== "lid" || namedProperty.guid.toLowerCase() !== PSETID_TASK) {
|
|
229
|
+
return defaultValueForType(propertyType);
|
|
230
|
+
}
|
|
231
|
+
switch (namedProperty.lid) {
|
|
232
|
+
case LID_TASK_STATUS:
|
|
233
|
+
return info.completed ? TASK_STATUS_COMPLETE : TASK_STATUS_NOT_STARTED;
|
|
234
|
+
case LID_PERCENT_COMPLETE:
|
|
235
|
+
return info.completed ? 1.0 : 0.0;
|
|
236
|
+
case LID_TASK_DUE_DATE:
|
|
237
|
+
return info.dueDate ?? defaultValueForType(propertyType);
|
|
238
|
+
case LID_TASK_COMPLETE:
|
|
239
|
+
return info.completed;
|
|
240
|
+
default:
|
|
241
|
+
return defaultValueForType(propertyType);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Resolves every column in `columns` for a single `target` (a `"folder:"`/`"virtual:"`/`"message:"`/
|
|
245
|
+
* `"calendarEvent:"`/`"contact:"`/`"task:"` target string), in order - the shared implementation behind both
|
|
246
|
+
* `RopQueryRowsHandler` (one call per table row) and `RopGetPropertiesSpecificHandler` (one call for the single
|
|
247
|
+
* object a handle refers to). */
|
|
248
|
+
export async function resolvePropertyValues(target, columns, context, cache) {
|
|
249
|
+
const isMessage = target.startsWith("message:");
|
|
250
|
+
const isCalendarEvent = target.startsWith("calendarEvent:");
|
|
251
|
+
const isContact = target.startsWith("contact:");
|
|
252
|
+
const isTask = target.startsWith("task:");
|
|
253
|
+
const folderInfo = isMessage || isCalendarEvent || isContact || isTask
|
|
254
|
+
? undefined
|
|
255
|
+
: await resolveFolderInfo(context.mailboxUid, target, context.folderRepo, cache);
|
|
256
|
+
const messageInfo = isMessage ? await resolveMessageInfo(target, context.messageRepo) : undefined;
|
|
257
|
+
const calendarEventInfo = isCalendarEvent ? await resolveCalendarEventInfo(target, context.calendarEventRepo) : undefined;
|
|
258
|
+
const contactInfo = isContact && context.contactRepo ? await resolveContactInfo(target, context.contactRepo) : undefined;
|
|
259
|
+
const taskInfo = isTask && context.taskRepo ? await resolveTaskInfo(target, context.taskRepo) : undefined;
|
|
260
|
+
let labelNames = [];
|
|
261
|
+
if (messageInfo && messageInfo.labelUids.length > 0 && context.labelRepo) {
|
|
262
|
+
let labelNamesByUid;
|
|
263
|
+
if (cache) {
|
|
264
|
+
if (!cache.labelNamesByUid) {
|
|
265
|
+
const labels = await context.labelRepo.find({ mailboxUid: context.mailboxUid }, { ignoreACL: true });
|
|
266
|
+
cache.labelNamesByUid = new Map(labels.map((l) => [l.uid, l.name]));
|
|
267
|
+
}
|
|
268
|
+
labelNamesByUid = cache.labelNamesByUid;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
const labels = await context.labelRepo.find({ mailboxUid: context.mailboxUid }, { ignoreACL: true });
|
|
272
|
+
labelNamesByUid = new Map(labels.map((l) => [l.uid, l.name]));
|
|
273
|
+
}
|
|
274
|
+
labelNames = messageInfo.labelUids.map((uid) => labelNamesByUid.get(uid)).filter((name) => name !== undefined);
|
|
275
|
+
}
|
|
276
|
+
let callerAddress = "";
|
|
277
|
+
if (isCalendarEvent) {
|
|
278
|
+
if (cache) {
|
|
279
|
+
if (cache.callerAddress === undefined) {
|
|
280
|
+
const mailbox = await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true });
|
|
281
|
+
cache.callerAddress = mailbox?.primarySmtpAddress ?? "";
|
|
282
|
+
}
|
|
283
|
+
callerAddress = cache.callerAddress ?? "";
|
|
284
|
+
}
|
|
285
|
+
else {
|
|
286
|
+
const mailbox = await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true });
|
|
287
|
+
callerAddress = mailbox?.primarySmtpAddress ?? "";
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return columns.map((column) => {
|
|
291
|
+
if (calendarEventInfo) {
|
|
292
|
+
return calendarEventValueFor(context.session, column.propertyId, column.propertyType, target, calendarEventInfo, callerAddress);
|
|
293
|
+
}
|
|
294
|
+
if (contactInfo) {
|
|
295
|
+
return contactValueFor(context.session, column.propertyId, column.propertyType, target, contactInfo);
|
|
296
|
+
}
|
|
297
|
+
if (taskInfo) {
|
|
298
|
+
return taskValueFor(context.session, column.propertyId, column.propertyType, target, taskInfo);
|
|
299
|
+
}
|
|
300
|
+
if (messageInfo) {
|
|
301
|
+
return messageValueFor(context.session, column.propertyId, column.propertyType, target, messageInfo, labelNames);
|
|
302
|
+
}
|
|
303
|
+
if (isContact || isTask) {
|
|
304
|
+
// contactRepo/taskRepo absent (see RopHandler.ts's own doc comment on why they're optional) - no
|
|
305
|
+
// real data to resolve against, so every column degrades to its type-appropriate default rather
|
|
306
|
+
// than falling through to the folder-info branch below (folderInfo is never populated for these
|
|
307
|
+
// target prefixes, see above - forcing that branch would throw on the `!` assertion).
|
|
308
|
+
return defaultValueForType(column.propertyType);
|
|
309
|
+
}
|
|
310
|
+
return folderValueFor(context.session, column.propertyId, column.propertyType, target, folderInfo);
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
//# sourceMappingURL=PropertyResolvers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PropertyResolvers.js","sourceRoot":"","sources":["../../../src/rop/PropertyResolvers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const ROP_ID_CREATE_MESSAGE = 0x06;
|
|
2
|
+
/** The well-known MAPI HRESULT `MAPI_E_NOT_FOUND`, reused as this handler's only failure `ReturnValue` - an
|
|
3
|
+
* unrecognized `FolderId`, the same constant `RopOpenFolderHandler` uses for its own analogous lookup miss. */
|
|
4
|
+
const ERROR_NOT_FOUND = 0x8004010f;
|
|
5
|
+
/**
|
|
6
|
+
* `RopCreateMessage` (`[MS-OXCMSG]`/`[MS-OXCROPS]`): begins composing a new message in a folder, producing a
|
|
7
|
+
* new `"message"` Server object handle later ROPs (`RopSetProperties`, `RopOpenStream`, `RopSaveChangesMessage`)
|
|
8
|
+
* reference by `InputHandleIndex`. Unlike `RopOpenMessage`'s handle (an already-real, already-saved message),
|
|
9
|
+
* this handle's `entityUid` is deliberately left `""` - there is no real backing `Message` row, and won't be
|
|
10
|
+
* one until `RopSubmitMessage` actually sends it (this pragmatic subset has no separate Drafts-folder
|
|
11
|
+
* persistence step; see `RopSaveChangesMessageHandler`'s own doc comment). `draftFolderUid` remembers the
|
|
12
|
+
* target folder for that eventual send, and `draftProperties` starts empty, filled in by later
|
|
13
|
+
* `RopSetProperties`/`RopWriteStream` calls.
|
|
14
|
+
*
|
|
15
|
+
* `CodePageId` is decoded to advance past it correctly but not otherwise acted on (this pragmatic subset always
|
|
16
|
+
* encodes strings as UTF-16LE/UTF-8 directly, the same treatment `RopOpenMessageHandler` gives it).
|
|
17
|
+
* `AssociatedFlag` (FAI messages - hidden configuration/rules objects, not real mail) is decoded but not
|
|
18
|
+
* honored - this pragmatic subset's compose/send path only ever produces ordinary mail messages.
|
|
19
|
+
*
|
|
20
|
+
* @author Jean-Philippe Steinmetz
|
|
21
|
+
*/
|
|
22
|
+
export class RopCreateMessageHandler {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.ropId = ROP_ID_CREATE_MESSAGE;
|
|
25
|
+
}
|
|
26
|
+
handle(reader, writer, context) {
|
|
27
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
28
|
+
reader.readUInt8(); // InputHandleIndex - the logon handle this create is performed against; not
|
|
29
|
+
// separately validated, matching RopOpenFolderHandler's own treatment of its input handle.
|
|
30
|
+
const outputHandleIndex = reader.readUInt8();
|
|
31
|
+
reader.readUInt16LE(); // CodePageId - see class doc comment
|
|
32
|
+
const folderId = reader.readBigUInt64LE();
|
|
33
|
+
reader.readUInt8(); // AssociatedFlag - see class doc comment
|
|
34
|
+
const target = context.session.folderIds[folderId.toString()];
|
|
35
|
+
if (!target) {
|
|
36
|
+
writer.writeUInt8(ROP_ID_CREATE_MESSAGE);
|
|
37
|
+
writer.writeUInt8(outputHandleIndex);
|
|
38
|
+
writer.writeUInt32LE(ERROR_NOT_FOUND);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
context.session.handles[outputHandleIndex] = {
|
|
42
|
+
type: "message",
|
|
43
|
+
entityUid: "",
|
|
44
|
+
draftFolderUid: target,
|
|
45
|
+
draftProperties: {},
|
|
46
|
+
};
|
|
47
|
+
writer.writeUInt8(ROP_ID_CREATE_MESSAGE);
|
|
48
|
+
writer.writeUInt8(outputHandleIndex);
|
|
49
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
50
|
+
writer.writeUInt8(0); // HasMessageId - no MID is assigned until RopSaveChangesMessage
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=RopCreateMessageHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopCreateMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopCreateMessageHandler.ts"],"names":[],"mappings":"AAOA,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC;+GAC+G;AAC/G,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,uBAAuB;IAApC;QACoB,UAAK,GAAG,qBAAqB,CAAC;IA+BlD,CAAC;IA7BU,MAAM,CAAC,MAAoB,EAAE,MAAoB,EAAE,OAAmB;QACzE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,uFAAuF;QAC3G,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,4EAA4E;QAChG,2FAA2F;QAC3F,MAAM,iBAAiB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACrD,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,qCAAqC;QAC5D,MAAM,QAAQ,GAAW,MAAM,CAAC,eAAe,EAAE,CAAC;QAClD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,yCAAyC;QAE7D,MAAM,MAAM,GAAuB,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;YACzC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;YACtC,OAAO;QACX,CAAC;QAED,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG;YACzC,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,EAAE;YACb,cAAc,EAAE,MAAM;YACtB,eAAe,EAAE,EAAE;SACtB,CAAC;QAEF,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;QACzC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,gEAAgE;IAC1F,CAAC;CACJ"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
const ROP_ID_DELETE_FOLDER = 0x1d;
|
|
2
|
+
/** The well-known MAPI HRESULT `MAPI_E_NOT_FOUND`, reused for an unrecognized `FolderId` - the same constant
|
|
3
|
+
* `RopOpenFolderHandler` uses for its own analogous lookup miss. */
|
|
4
|
+
const ERROR_NOT_FOUND = 0x8004010f;
|
|
5
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for both "the referenced handle isn't a folder"
|
|
6
|
+
* and "the folder has content/subfolders but the matching cascade flag wasn't set" - the same constant reused
|
|
7
|
+
* throughout this pragmatic subset as a generic "can't do this" signal, not a claim of exact per-condition
|
|
8
|
+
* `[MS-OXCFOLD]` return-value-table parity (the real spec's own `ecFolderNotEmpty` isn't separately modeled). */
|
|
9
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
10
|
+
/** `DeleteFolderFlags` bits (`[MS-OXCFOLD]` §2.2.1.3.1, confirmed this session). */
|
|
11
|
+
const DEL_MESSAGES = 0x01;
|
|
12
|
+
const DEL_FOLDERS = 0x04;
|
|
13
|
+
const DELETE_HARD_DELETE = 0x10;
|
|
14
|
+
/**
|
|
15
|
+
* `RopDeleteFolder` (`[MS-OXCFOLD]`/`[MS-OXCROPS]`, RopId `0x1D`): deletes a folder by `FolderId`. Reuses
|
|
16
|
+
* `RecoverableRepoUtils.delete()` exactly as-built in Phase 2 for `Folder`/`Message`/`CalendarEvent` - see
|
|
17
|
+
* `RopDeleteMessagesHandler.ts`'s own doc comment for why that matters (EAS's watermark-based incremental
|
|
18
|
+
* delete detection depends on it).
|
|
19
|
+
*
|
|
20
|
+
* **Real spec semantics honored, not simplified away**: per `[MS-OXCFOLD]`, `RopDeleteFolder` only operates on
|
|
21
|
+
* an empty folder by default - `DEL_MESSAGES` must be set to also delete the folder's own messages/calendar
|
|
22
|
+
* events/contacts/tasks, and `DEL_FOLDERS` to also delete (recursively) its subfolders; a non-empty folder
|
|
23
|
+
* deleted without the matching flag fails rather than silently cascading. `DELETE_HARD_DELETE` maps directly
|
|
24
|
+
* onto `RepoDeleteOptions.purge` - real, exact semantic overlap with this library's own soft-delete model, not
|
|
25
|
+
* a coincidence this codec papers over.
|
|
26
|
+
*
|
|
27
|
+
* **Contacts/Tasks folders**: emptiness is checked against `contactRepo`/`taskRepo` alongside `messageRepo`/
|
|
28
|
+
* `calendarEventRepo`, and both are included in the delete cascade - a `CONTACTS`/`TASKS` folder's real content
|
|
29
|
+
* lives in those repos (see `ContactTarget.ts`/`TaskTarget.ts`), not `messageRepo`, so checking only the latter
|
|
30
|
+
* would let a non-empty Contacts/Tasks folder be deleted without `DEL_MESSAGES` and orphan its rows. Guarded
|
|
31
|
+
* with `context.contactRepo`/`taskRepo` presence checks the same way `RopGetContentsTableHandler` does, since
|
|
32
|
+
* `RopContext`'s doc comment documents both as optional.
|
|
33
|
+
*
|
|
34
|
+
* The request's own `InputHandleIndex` (nominally the *parent* folder of the one being deleted) is validated to
|
|
35
|
+
* be a real, open folder handle but not cross-checked against the target folder's actual `parentFolderUid` -
|
|
36
|
+
* the same pragmatic simplification `RopOpenMessageHandler`'s own doc comment documents for its analogous
|
|
37
|
+
* `FolderId` field.
|
|
38
|
+
*
|
|
39
|
+
* @author Jean-Philippe Steinmetz
|
|
40
|
+
*/
|
|
41
|
+
export class RopDeleteFolderHandler {
|
|
42
|
+
constructor() {
|
|
43
|
+
this.ropId = ROP_ID_DELETE_FOLDER;
|
|
44
|
+
}
|
|
45
|
+
async handle(reader, writer, context) {
|
|
46
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
47
|
+
const inputHandleIndex = reader.readUInt8();
|
|
48
|
+
const deleteFolderFlags = reader.readUInt8();
|
|
49
|
+
const folderId = reader.readBigUInt64LE();
|
|
50
|
+
const handle = context.session.handles[inputHandleIndex];
|
|
51
|
+
if (!handle || handle.type !== "folder") {
|
|
52
|
+
writer.writeUInt8(ROP_ID_DELETE_FOLDER);
|
|
53
|
+
writer.writeUInt8(inputHandleIndex);
|
|
54
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const target = context.session.folderIds[folderId.toString()];
|
|
58
|
+
if (!target?.startsWith("folder:")) {
|
|
59
|
+
writer.writeUInt8(ROP_ID_DELETE_FOLDER);
|
|
60
|
+
writer.writeUInt8(inputHandleIndex);
|
|
61
|
+
writer.writeUInt32LE(ERROR_NOT_FOUND);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const uid = target.slice("folder:".length);
|
|
65
|
+
const purge = (deleteFolderFlags & DELETE_HARD_DELETE) !== 0;
|
|
66
|
+
const messages = await context.messageRepo.find({ folderUid: uid }, { ignoreACL: true });
|
|
67
|
+
const events = await context.calendarEventRepo.find({ folderUid: uid }, { ignoreACL: true });
|
|
68
|
+
const contacts = context.contactRepo ? await context.contactRepo.find({ folderUid: uid }, { ignoreACL: true }) : [];
|
|
69
|
+
const tasks = context.taskRepo ? await context.taskRepo.find({ folderUid: uid }, { ignoreACL: true }) : [];
|
|
70
|
+
const childFolders = await context.folderRepo.find({ parentFolderUid: uid }, { ignoreACL: true });
|
|
71
|
+
if ((messages.length > 0 || events.length > 0 || contacts.length > 0 || tasks.length > 0) &&
|
|
72
|
+
(deleteFolderFlags & DEL_MESSAGES) === 0) {
|
|
73
|
+
writer.writeUInt8(ROP_ID_DELETE_FOLDER);
|
|
74
|
+
writer.writeUInt8(inputHandleIndex);
|
|
75
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (childFolders.length > 0 && (deleteFolderFlags & DEL_FOLDERS) === 0) {
|
|
79
|
+
writer.writeUInt8(ROP_ID_DELETE_FOLDER);
|
|
80
|
+
writer.writeUInt8(inputHandleIndex);
|
|
81
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
for (const message of messages) {
|
|
85
|
+
await context.messageRepo.delete(message.uid, { ignoreACL: true, purge });
|
|
86
|
+
}
|
|
87
|
+
for (const event of events) {
|
|
88
|
+
await context.calendarEventRepo.delete(event.uid, { ignoreACL: true, purge });
|
|
89
|
+
}
|
|
90
|
+
for (const contact of contacts) {
|
|
91
|
+
await context.contactRepo.delete(contact.uid, { ignoreACL: true, purge });
|
|
92
|
+
}
|
|
93
|
+
for (const task of tasks) {
|
|
94
|
+
await context.taskRepo.delete(task.uid, { ignoreACL: true, purge });
|
|
95
|
+
}
|
|
96
|
+
for (const childFolder of childFolders) {
|
|
97
|
+
await this.deleteFolderRecursive(childFolder.uid, context, purge);
|
|
98
|
+
}
|
|
99
|
+
await context.folderRepo.delete(uid, { ignoreACL: true, purge });
|
|
100
|
+
writer.writeUInt8(ROP_ID_DELETE_FOLDER);
|
|
101
|
+
writer.writeUInt8(inputHandleIndex);
|
|
102
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
103
|
+
writer.writeUInt8(0); // PartialCompletion - always false; a partial failure above already returned early
|
|
104
|
+
}
|
|
105
|
+
/** Cascades a `DEL_FOLDERS` delete into `folderUid`'s own messages/calendar events/subfolders before
|
|
106
|
+
* deleting it - this data model's folder hierarchy is a plain parent-pointer tree (never a graph), so
|
|
107
|
+
* unbounded recursion here needs no cycle protection, the same assumption `FolderTarget.resolveFolderChildren`
|
|
108
|
+
* already makes. */
|
|
109
|
+
async deleteFolderRecursive(folderUid, context, purge) {
|
|
110
|
+
const messages = await context.messageRepo.find({ folderUid }, { ignoreACL: true });
|
|
111
|
+
const events = await context.calendarEventRepo.find({ folderUid }, { ignoreACL: true });
|
|
112
|
+
const contacts = context.contactRepo ? await context.contactRepo.find({ folderUid }, { ignoreACL: true }) : [];
|
|
113
|
+
const tasks = context.taskRepo ? await context.taskRepo.find({ folderUid }, { ignoreACL: true }) : [];
|
|
114
|
+
const childFolders = await context.folderRepo.find({ parentFolderUid: folderUid }, { ignoreACL: true });
|
|
115
|
+
for (const message of messages) {
|
|
116
|
+
await context.messageRepo.delete(message.uid, { ignoreACL: true, purge });
|
|
117
|
+
}
|
|
118
|
+
for (const event of events) {
|
|
119
|
+
await context.calendarEventRepo.delete(event.uid, { ignoreACL: true, purge });
|
|
120
|
+
}
|
|
121
|
+
for (const contact of contacts) {
|
|
122
|
+
await context.contactRepo.delete(contact.uid, { ignoreACL: true, purge });
|
|
123
|
+
}
|
|
124
|
+
for (const task of tasks) {
|
|
125
|
+
await context.taskRepo.delete(task.uid, { ignoreACL: true, purge });
|
|
126
|
+
}
|
|
127
|
+
for (const childFolder of childFolders) {
|
|
128
|
+
await this.deleteFolderRecursive(childFolder.uid, context, purge);
|
|
129
|
+
}
|
|
130
|
+
await context.folderRepo.delete(folderUid, { ignoreACL: true, purge });
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=RopDeleteFolderHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopDeleteFolderHandler.js","sourceRoot":"","sources":["../../../src/rop/RopDeleteFolderHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const ROP_ID_DELETE_MESSAGES = 0x1e;
|
|
2
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a folder (or
|
|
3
|
+
* doesn't exist)" - the same constant `RopGetContentsTableHandler` uses for its own analogous check. */
|
|
4
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
5
|
+
/**
|
|
6
|
+
* `RopDeleteMessages` (`[MS-OXCMSG]`/`[MS-OXCROPS]`, RopId `0x1E`): deletes one or more messages by `MessageId`
|
|
7
|
+
* from an already-open folder handle. Reuses `RecoverableRepoUtils.delete()` exactly as-built in Phase 2 - the
|
|
8
|
+
* same soft-delete-with-watermark-bump machinery EAS's own `Sync`/`FolderSync` incremental-delete detection
|
|
9
|
+
* already relies on (see `BaseMapiEmsmdbRoute.ts`'s own doc comment for why `folderRepo`/`messageRepo`/
|
|
10
|
+
* `calendarEventRepo` are built as `RecoverableRepoUtils`, not plain `RepoUtils`) - no new deletion-tracking
|
|
11
|
+
* code, zero duplication.
|
|
12
|
+
*
|
|
13
|
+
* A `MessageId` resolves via `session.messageIds` (`MessageTarget.assignOrGetMid`'s own registry, already
|
|
14
|
+
* generic over both `"message:<uid>"` and `"calendarEvent:<uid>"` target strings, since a Calendar item is
|
|
15
|
+
* itself a Message object on the wire - see `CalendarEventTarget.ts`'s own doc comment) directly to the entity
|
|
16
|
+
* to delete, the same "the session already knows what this small integer refers to" design every other MID-
|
|
17
|
+
* consuming ROP in this pragmatic subset already uses (`RopOpenMessage`, `RopSaveChangesMessage`) - the
|
|
18
|
+
* request's own `InputHandleIndex` (nominally the messages' shared parent folder) is validated to be a real,
|
|
19
|
+
* open folder handle but not cross-checked against each message's actual `folderUid`, the same pragmatic
|
|
20
|
+
* simplification `RopOpenMessageHandler`'s own doc comment documents for its analogous `FolderId` field.
|
|
21
|
+
*
|
|
22
|
+
* `WantAsynchronous` (`RopProgress`-reported async completion) and `NotifyNonRead` (non-read-receipt generation
|
|
23
|
+
* to the original sender) are decoded to advance the reader correctly but not honored - this pragmatic subset
|
|
24
|
+
* has no async-ROP or non-read-receipt machinery. `PartialCompletion` is reported `true` if any requested
|
|
25
|
+
* `MessageId` didn't resolve to a real message/calendar-event target - the rest are still deleted, matching
|
|
26
|
+
* this pragmatic subset's "don't fail the whole ROP over one stale reference" principle used throughout.
|
|
27
|
+
*
|
|
28
|
+
* @author Jean-Philippe Steinmetz
|
|
29
|
+
*/
|
|
30
|
+
export class RopDeleteMessagesHandler {
|
|
31
|
+
constructor() {
|
|
32
|
+
this.ropId = ROP_ID_DELETE_MESSAGES;
|
|
33
|
+
}
|
|
34
|
+
async handle(reader, writer, context) {
|
|
35
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
36
|
+
const inputHandleIndex = reader.readUInt8();
|
|
37
|
+
reader.readUInt8(); // WantAsynchronous - no RopProgress/async-ROP support in this pragmatic subset
|
|
38
|
+
reader.readUInt8(); // NotifyNonRead - no non-read-receipt generation support
|
|
39
|
+
const messageIdCount = reader.readUInt16LE();
|
|
40
|
+
const messageIds = [];
|
|
41
|
+
for (let i = 0; i < messageIdCount; i++) {
|
|
42
|
+
messageIds.push(reader.readBigUInt64LE());
|
|
43
|
+
}
|
|
44
|
+
const handle = context.session.handles[inputHandleIndex];
|
|
45
|
+
if (!handle || handle.type !== "folder") {
|
|
46
|
+
writer.writeUInt8(ROP_ID_DELETE_MESSAGES);
|
|
47
|
+
writer.writeUInt8(inputHandleIndex);
|
|
48
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
let partialCompletion = false;
|
|
52
|
+
for (const messageId of messageIds) {
|
|
53
|
+
const target = context.session.messageIds[messageId.toString()];
|
|
54
|
+
if (target?.startsWith("message:")) {
|
|
55
|
+
await context.messageRepo.delete(target.slice("message:".length), { ignoreACL: true });
|
|
56
|
+
}
|
|
57
|
+
else if (target?.startsWith("calendarEvent:")) {
|
|
58
|
+
await context.calendarEventRepo.delete(target.slice("calendarEvent:".length), { ignoreACL: true });
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
partialCompletion = true;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
writer.writeUInt8(ROP_ID_DELETE_MESSAGES);
|
|
65
|
+
writer.writeUInt8(inputHandleIndex);
|
|
66
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
67
|
+
writer.writeUInt8(partialCompletion ? 1 : 0); // PartialCompletion
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=RopDeleteMessagesHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopDeleteMessagesHandler.js","sourceRoot":"","sources":["../../../src/rop/RopDeleteMessagesHandler.ts"],"names":[],"mappings":"AAOA,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAEpC;wGACwG;AACxG,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,OAAO,wBAAwB;IAArC;QACoB,UAAK,GAAG,sBAAsB,CAAC;IAsCnD,CAAC;IApCU,KAAK,CAAC,MAAM,CAAC,MAAoB,EAAE,MAAoB,EAAE,OAAmB;QAC/E,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,uFAAuF;QAC3G,MAAM,gBAAgB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACpD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,+EAA+E;QACnG,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,yDAAyD;QAC7E,MAAM,cAAc,GAAW,MAAM,CAAC,YAAY,EAAE,CAAC;QACrD,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,cAAc,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;YAC1C,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,OAAO;QACX,CAAC;QAED,IAAI,iBAAiB,GAAG,KAAK,CAAC;QAC9B,KAAK,MAAM,SAAS,IAAI,UAAU,EAAE,CAAC;YACjC,MAAM,MAAM,GAAuB,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;YACpF,IAAI,MAAM,EAAE,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;gBACjC,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC3F,CAAC;iBAAM,IAAI,MAAM,EAAE,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAC9C,MAAM,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACvG,CAAC;iBAAM,CAAC;gBACJ,iBAAiB,GAAG,IAAI,CAAC;YAC7B,CAAC;QACL,CAAC;QAED,MAAM,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;QAC1C,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAoB;IACtE,CAAC;CACJ"}
|