@rapidmx/mapi-plugin 1.0.0-beta.3 → 1.0.0-beta.4
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/README.md +4 -4
- package/dist/lib/BaseMapiEmsmdbRoute.js +211 -36
- package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -1
- package/dist/lib/MapiSessionManager.js +404 -48
- package/dist/lib/MapiSessionManager.js.map +1 -1
- package/dist/lib/RegexPatternUtils.js +30 -0
- package/dist/lib/RegexPatternUtils.js.map +1 -0
- package/dist/lib/RopDispatcher.js +130 -19
- package/dist/lib/RopDispatcher.js.map +1 -1
- package/dist/lib/codec/AppointmentRecurrence.js +22 -21
- package/dist/lib/codec/AppointmentRecurrence.js.map +1 -1
- package/dist/lib/codec/BufferCursor.js +41 -12
- package/dist/lib/codec/BufferCursor.js.map +1 -1
- package/dist/lib/codec/GlobalObjectId.js +26 -20
- package/dist/lib/codec/GlobalObjectId.js.map +1 -1
- package/dist/lib/codec/MapiTimeZone.js +43 -10
- package/dist/lib/codec/MapiTimeZone.js.map +1 -1
- package/dist/lib/codec/PropertyValue.js +28 -2
- package/dist/lib/codec/PropertyValue.js.map +1 -1
- package/dist/lib/codec/RopBuffer.js +15 -3
- package/dist/lib/codec/RopBuffer.js.map +1 -1
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +2 -1
- package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -1
- package/dist/lib/nspi/NspiCodec.js +5 -5
- package/dist/lib/nspi/NspiCodec.js.map +1 -1
- package/dist/lib/nspi/NspiGetMatchesHandler.js +14 -14
- package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -1
- package/dist/lib/rop/AddressList.js +109 -0
- package/dist/lib/rop/AddressList.js.map +1 -0
- package/dist/lib/rop/CalendarEventTarget.js +7 -4
- package/dist/lib/rop/CalendarEventTarget.js.map +1 -1
- package/dist/lib/rop/ContactTarget.js +2 -6
- package/dist/lib/rop/ContactTarget.js.map +1 -1
- package/dist/lib/rop/ContentsTable.js +60 -0
- package/dist/lib/rop/ContentsTable.js.map +1 -0
- package/dist/lib/rop/ExecuteBudget.js +82 -0
- package/dist/lib/rop/ExecuteBudget.js.map +1 -0
- package/dist/lib/rop/FastTransferStream.js +99 -2
- package/dist/lib/rop/FastTransferStream.js.map +1 -1
- package/dist/lib/rop/FolderTarget.js +13 -6
- package/dist/lib/rop/FolderTarget.js.map +1 -1
- package/dist/lib/rop/HandleDataCache.js +412 -0
- package/dist/lib/rop/HandleDataCache.js.map +1 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js +194 -48
- package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -1
- package/dist/lib/rop/MessageBodyStream.js +33 -7
- package/dist/lib/rop/MessageBodyStream.js.map +1 -1
- package/dist/lib/rop/MessageTarget.js +17 -4
- package/dist/lib/rop/MessageTarget.js.map +1 -1
- package/dist/lib/rop/NamedPropertyRegistry.js +8 -5
- package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -1
- package/dist/lib/rop/PropertyResolvers.js +3 -1
- package/dist/lib/rop/PropertyResolvers.js.map +1 -1
- package/dist/lib/rop/RepoPaging.js +54 -0
- package/dist/lib/rop/RepoPaging.js.map +1 -0
- package/dist/lib/rop/RestapiRules.js +52 -0
- package/dist/lib/rop/RestapiRules.js.map +1 -0
- package/dist/lib/rop/RopCreateMessageHandler.js +4 -2
- package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -1
- package/dist/lib/rop/RopDeleteFolderHandler.js +112 -77
- package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -1
- package/dist/lib/rop/RopDeleteMessagesHandler.js +17 -1
- package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -1
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +14 -14
- package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -1
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +13 -14
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -1
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +33 -32
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -1
- package/dist/lib/rop/RopGetContentsTableHandler.js +17 -38
- package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -1
- package/dist/lib/rop/RopGetHierarchyTableHandler.js +4 -2
- package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -1
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +6 -8
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -1
- package/dist/lib/rop/RopHandler.js +5 -1
- package/dist/lib/rop/RopHandler.js.map +1 -1
- package/dist/lib/rop/RopLogonHandler.js +5 -2
- package/dist/lib/rop/RopLogonHandler.js.map +1 -1
- package/dist/lib/rop/RopOpenFolderHandler.js +3 -1
- package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -1
- package/dist/lib/rop/RopOpenMessageHandler.js +3 -1
- package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -1
- package/dist/lib/rop/RopOpenStreamHandler.js +11 -8
- package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -1
- package/dist/lib/rop/RopQueryRowsHandler.js +31 -5
- package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -1
- package/dist/lib/rop/RopReadStreamHandler.js +22 -4
- package/dist/lib/rop/RopReadStreamHandler.js.map +1 -1
- package/dist/lib/rop/RopReleaseHandler.js +4 -1
- package/dist/lib/rop/RopReleaseHandler.js.map +1 -1
- package/dist/lib/rop/RopSaveChangesMessageHandler.js +66 -7
- package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -1
- package/dist/lib/rop/RopSetColumnsHandler.js +6 -8
- package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -1
- package/dist/lib/rop/RopSetPropertiesHandler.js +23 -12
- package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -1
- package/dist/lib/rop/RopSubmitMessageHandler.js +144 -120
- package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -1
- package/dist/lib/rop/RopWriteStreamHandler.js +37 -10
- package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -1
- package/dist/lib/rop/TaskTarget.js +2 -6
- package/dist/lib/rop/TaskTarget.js.map +1 -1
- package/dist/lib/rop/TransportSend.js +16 -0
- package/dist/lib/rop/TransportSend.js.map +1 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js +2 -1
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -1
- package/dist/types/BaseMapiEmsmdbRoute.d.ts +52 -2
- package/dist/types/MapiSessionManager.d.ts +218 -63
- package/dist/types/RegexPatternUtils.d.ts +14 -0
- package/dist/types/RopDispatcher.d.ts +47 -11
- package/dist/types/codec/BufferCursor.d.ts +14 -0
- package/dist/types/codec/GlobalObjectId.d.ts +9 -5
- package/dist/types/codec/PropertyValue.d.ts +10 -0
- package/dist/types/codec/RopBuffer.d.ts +7 -0
- package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +1 -0
- package/dist/types/nspi/NspiGetMatchesHandler.d.ts +2 -0
- package/dist/types/rop/AddressList.d.ts +48 -0
- package/dist/types/rop/CalendarEventTarget.d.ts +7 -3
- package/dist/types/rop/ContactTarget.d.ts +3 -3
- package/dist/types/rop/ContentsTable.d.ts +16 -0
- package/dist/types/rop/ExecuteBudget.d.ts +48 -0
- package/dist/types/rop/FastTransferStream.d.ts +41 -2
- package/dist/types/rop/FolderTarget.d.ts +3 -2
- package/dist/types/rop/HandleDataCache.d.ts +145 -0
- package/dist/types/rop/MeetingMessageClassHandler.d.ts +23 -29
- package/dist/types/rop/MessageBodyStream.d.ts +16 -7
- package/dist/types/rop/MessageTarget.d.ts +10 -3
- package/dist/types/rop/NamedPropertyRegistry.d.ts +6 -2
- package/dist/types/rop/PropertyResolvers.d.ts +1 -1
- package/dist/types/rop/RepoPaging.d.ts +30 -0
- package/dist/types/rop/RestapiRules.d.ts +32 -0
- package/dist/types/rop/RopCreateMessageHandler.d.ts +1 -0
- package/dist/types/rop/RopDeleteFolderHandler.d.ts +36 -21
- package/dist/types/rop/RopDeleteMessagesHandler.d.ts +7 -0
- package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +1 -0
- package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +1 -0
- package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +10 -11
- package/dist/types/rop/RopGetContentsTableHandler.d.ts +7 -13
- package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +1 -0
- package/dist/types/rop/RopHandler.d.ts +25 -1
- package/dist/types/rop/RopOpenFolderHandler.d.ts +1 -0
- package/dist/types/rop/RopOpenMessageHandler.d.ts +1 -0
- package/dist/types/rop/RopOpenStreamHandler.d.ts +1 -0
- package/dist/types/rop/RopQueryRowsHandler.d.ts +3 -0
- package/dist/types/rop/RopReadStreamHandler.d.ts +3 -1
- package/dist/types/rop/RopReleaseHandler.d.ts +1 -0
- package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +16 -1
- package/dist/types/rop/RopSubmitMessageHandler.d.ts +33 -23
- package/dist/types/rop/RopWriteStreamHandler.d.ts +18 -8
- package/dist/types/rop/TaskTarget.d.ts +3 -3
- package/dist/types/rop/TransportSend.d.ts +10 -0
- package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +1 -0
- package/package.json +3 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { loadStreamBody } from "./MessageBodyStream.js";
|
|
2
2
|
const ROP_ID_READ_STREAM = 0x2c;
|
|
3
3
|
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a stream (or
|
|
4
4
|
* doesn't exist)" - the same constant `RopGetHierarchyTableHandler` uses for its own analogous check. */
|
|
@@ -12,12 +12,15 @@ const BYTE_COUNT_USE_MAXIMUM = 0xbabe;
|
|
|
12
12
|
* requested is spec-legal (the client just calls `RopReadStream` again for the rest, exactly how paging a large
|
|
13
13
|
* stream is meant to work) - `writeUInt16LE` throwing `RangeError` for an out-of-range value is not. */
|
|
14
14
|
const MAX_DATA_SIZE = 0xffff;
|
|
15
|
+
/** RopId, InputHandleIndex, ReturnValue and DataSize. */
|
|
16
|
+
const RESPONSE_HEADER_BYTES = 8;
|
|
15
17
|
/**
|
|
16
18
|
* `RopReadStream` (`[MS-OXCPRPT]`/`[MS-OXCROPS]`): reads up to `ByteCount` (or `MaximumByteCount`, if
|
|
17
19
|
* `ByteCount` is the `0xBABE` sentinel) bytes from an already-opened stream (`RopOpenStream`), advancing the
|
|
18
20
|
* stream's read position - clamped to `MAX_DATA_SIZE` (`0xFFFF`) regardless of what the client asked for, since
|
|
19
21
|
* the response's own `DataSize` field can't carry more than that; a client wanting more of a large body simply
|
|
20
|
-
* calls `RopReadStream` again from the advanced `streamPosition`, the same paging behavior real Exchange uses.
|
|
22
|
+
* calls `RopReadStream` again from the advanced `streamPosition`, the same paging behavior real Exchange uses. It is
|
|
23
|
+
* likewise held to the room left in the request's ROP output buffer (`context.ropOutputRemaining`).
|
|
21
24
|
* Unlike most other ROPs in this pragmatic subset, `[MS-OXCROPS]` documents only one combined response-buffer
|
|
22
25
|
* shape for this ROP (no separate Success/Failure pages) - `DataSize`/`Data` are always present, `DataSize = 0`
|
|
23
26
|
* (empty `Data`) standing in for the failure case rather than the fields being omitted entirely.
|
|
@@ -27,6 +30,7 @@ const MAX_DATA_SIZE = 0xffff;
|
|
|
27
30
|
export class RopReadStreamHandler {
|
|
28
31
|
constructor() {
|
|
29
32
|
this.ropId = ROP_ID_READ_STREAM;
|
|
33
|
+
this.failureTailBytes = 2; // DataSize/WrittenSize
|
|
30
34
|
}
|
|
31
35
|
async handle(reader, writer, context) {
|
|
32
36
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
@@ -41,9 +45,23 @@ export class RopReadStreamHandler {
|
|
|
41
45
|
writer.writeUInt16LE(0); // DataSize - see class doc comment on why this is still written on failure
|
|
42
46
|
return;
|
|
43
47
|
}
|
|
44
|
-
const bytes = await
|
|
48
|
+
const bytes = await loadStreamBody(context, inputHandleIndex, handle);
|
|
45
49
|
const position = handle.streamPosition ?? 0;
|
|
46
|
-
|
|
50
|
+
// Also held to the room left in this request's ROP output buffer, after this response's 8 fixed bytes.
|
|
51
|
+
const room = Math.max(0, (context.ropOutputRemaining ?? Infinity) - RESPONSE_HEADER_BYTES);
|
|
52
|
+
const wanted = Math.min(requestedCount, MAX_DATA_SIZE);
|
|
53
|
+
const available = bytes.subarray(position, position + wanted);
|
|
54
|
+
if (room === 0 && available.length > 0) {
|
|
55
|
+
// No room for even one byte: a DataSize of 0 would read as the end of the stream. Answer with what the read
|
|
56
|
+
// needs instead, which doesn't fit, so the dispatcher turns it into RopBufferTooSmall. The position stays.
|
|
57
|
+
writer.writeUInt8(ROP_ID_READ_STREAM);
|
|
58
|
+
writer.writeUInt8(inputHandleIndex);
|
|
59
|
+
writer.writeUInt32LE(0);
|
|
60
|
+
writer.writeUInt16LE(available.length);
|
|
61
|
+
writer.writeBytes(available);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const slice = available.subarray(0, room);
|
|
47
65
|
handle.streamPosition = position + slice.length;
|
|
48
66
|
writer.writeUInt8(ROP_ID_READ_STREAM);
|
|
49
67
|
writer.writeUInt8(inputHandleIndex);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopReadStreamHandler.js","sourceRoot":"","sources":["../../../src/rop/RopReadStreamHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"RopReadStreamHandler.js","sourceRoot":"","sources":["../../../src/rop/RopReadStreamHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { releaseHandle } from "../MapiSessionManager.js";
|
|
1
2
|
const ROP_ID_RELEASE = 0x01;
|
|
2
3
|
/**
|
|
3
4
|
* `RopRelease` (`[MS-OXCROPS]`): releases a Server object handle. Confirmed against the spec's own real
|
|
@@ -10,11 +11,13 @@ const ROP_ID_RELEASE = 0x01;
|
|
|
10
11
|
export class RopReleaseHandler {
|
|
11
12
|
constructor() {
|
|
12
13
|
this.ropId = ROP_ID_RELEASE;
|
|
14
|
+
this.hasNoResponse = true;
|
|
13
15
|
}
|
|
14
16
|
handle(reader, _writer, context) {
|
|
15
17
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track per-logon-id state separately
|
|
16
18
|
const inputHandleIndex = reader.readUInt8();
|
|
17
|
-
|
|
19
|
+
// Also releases write streams opened against this handle and drops its cached data - see releaseHandle.
|
|
20
|
+
releaseHandle(context.session, inputHandleIndex);
|
|
18
21
|
}
|
|
19
22
|
}
|
|
20
23
|
//# sourceMappingURL=RopReleaseHandler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopReleaseHandler.js","sourceRoot":"","sources":["../../../src/rop/RopReleaseHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RopReleaseHandler.js","sourceRoot":"","sources":["../../../src/rop/RopReleaseHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzD,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B;;;;;;;GAOG;AACH,MAAM,OAAO,iBAAiB;IAA9B;QACoB,UAAK,GAAG,cAAc,CAAC;QACvB,kBAAa,GAAG,IAAI,CAAC;IAQzC,CAAC;IANU,MAAM,CAAC,MAAoB,EAAE,OAAqB,EAAE,OAAmB;QAC1E,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,8EAA8E;QAClG,MAAM,gBAAgB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACpD,wGAAwG;QACxG,aAAa,CAAC,OAAO,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC;IACrD,CAAC;CACJ"}
|
|
@@ -10,11 +10,15 @@ import { decodeTimeZoneStruct } from "../codec/MapiTimeZone.js";
|
|
|
10
10
|
import { BUSY_STATUS_FROM_CODE, LID_APPOINTMENT_END_WHOLE, LID_APPOINTMENT_RECUR, LID_APPOINTMENT_START_WHOLE, LID_BUSY_STATUS, LID_LOCATION, LID_REMINDER_DELTA, LID_TIME_ZONE_STRUCT, PSETID_APPOINTMENT, PSETID_COMMON, } from "./CalendarNamedProperties.js";
|
|
11
11
|
import { assignOrGetMid } from "./MessageTarget.js";
|
|
12
12
|
import { resolveNamedProperty } from "./NamedPropertyRegistry.js";
|
|
13
|
+
import { MAX_RECIPIENTS_PER_MESSAGE } from "./AddressList.js";
|
|
14
|
+
import { asEntity, isInvitePending } from "./RestapiRules.js";
|
|
13
15
|
import { parseAddressList } from "./RopSubmitMessageHandler.js";
|
|
14
16
|
const ROP_ID_SAVE_CHANGES_MESSAGE = 0x0c;
|
|
15
17
|
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a message (or
|
|
16
18
|
* doesn't exist)" - the same constant `RopGetPropertiesSpecificHandler` uses for its own analogous check. */
|
|
17
19
|
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
20
|
+
/** `MAPI_E_TOO_BIG`: a meeting with more than `MAX_RECIPIENTS_PER_MESSAGE` attendees. */
|
|
21
|
+
const ERROR_TOO_BIG = 0x80040305;
|
|
18
22
|
// The same well-known property IDs RopSetPropertiesHandler tracks - duplicated here (rather than imported)
|
|
19
23
|
// since importing them would only save a handful of literals; see that file for the real documentation of what
|
|
20
24
|
// each means.
|
|
@@ -50,7 +54,11 @@ const MESSAGE_CLASS_APPOINTMENT_PREFIX = "IPM.Appointment";
|
|
|
50
54
|
* `"calendarEvent:<uid>"`) a real `CalendarEvent` row, so a subsequent `RopGetPropertiesSpecific` can read it
|
|
51
55
|
* back before `RopSubmitMessage` is ever called (a calendar item must exist as soon as it's saved, the same way
|
|
52
56
|
* a real Exchange server behaves - unlike a mail draft, which this pragmatic subset never persists at all until
|
|
53
|
-
* Submit).
|
|
57
|
+
* Submit). Saving never invites anyone: a saved revision is stamped as already handled (`inviteSequenceSent =
|
|
58
|
+
* sequence`), so restapi's `MeetingSchedulingJob` skips it until `RopSubmitMessageHandler.submitAppointment` asks for
|
|
59
|
+
* invites. Attendees of a submitted meeting are then mailed by that job, which is why a meeting is capped at
|
|
60
|
+
* `MAX_RECIPIENTS_PER_MESSAGE` attendees here. Client-supplied times and reminder minutes that don't parse are ignored (the field keeps its
|
|
61
|
+
* existing or default value) rather than stored as `Invalid Date`/`NaN`, and an update is versioned (`asEntity`).
|
|
54
62
|
*
|
|
55
63
|
* @author Jean-Philippe Steinmetz
|
|
56
64
|
*/
|
|
@@ -75,6 +83,12 @@ export class RopSaveChangesMessageHandler {
|
|
|
75
83
|
const mid = messageClass.startsWith(MESSAGE_CLASS_APPOINTMENT_PREFIX)
|
|
76
84
|
? await this.saveAppointment(handle, draftProperties, context)
|
|
77
85
|
: BigInt(assignOrGetMid(context.session, handle.entityUid !== "" ? handle.entityUid : `draft:${inputHandleIndex}`));
|
|
86
|
+
if (mid === undefined) {
|
|
87
|
+
writer.writeUInt8(ROP_ID_SAVE_CHANGES_MESSAGE);
|
|
88
|
+
writer.writeUInt8(responseHandleIndex);
|
|
89
|
+
writer.writeUInt32LE(ERROR_TOO_BIG);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
78
92
|
writer.writeUInt8(ROP_ID_SAVE_CHANGES_MESSAGE);
|
|
79
93
|
writer.writeUInt8(responseHandleIndex);
|
|
80
94
|
writer.writeUInt32LE(0); // ReturnValue - success
|
|
@@ -88,9 +102,15 @@ export class RopSaveChangesMessageHandler {
|
|
|
88
102
|
* below - the write-side mirror of `PropertyResolvers.calendarEventValueFor`'s read-side switch. A field the
|
|
89
103
|
* client never set (e.g. no `RopSetProperties` call touched `PidLidBusyStatus`) falls back to the existing
|
|
90
104
|
* row's own value on an update, or the entity class's own default on a fresh create.
|
|
105
|
+
*
|
|
106
|
+
* Returns `undefined`, saving nothing, for more than `MAX_RECIPIENTS_PER_MESSAGE` attendees: restapi's
|
|
107
|
+
* `MeetingSchedulingJob` mails every attendee of a saved meeting.
|
|
91
108
|
*/
|
|
92
109
|
async saveAppointment(handle, draftProperties, context) {
|
|
93
110
|
const decoded = decodeCalendarFieldsFromDraft(context.session, draftProperties);
|
|
111
|
+
if (decoded.attendeeAddresses.length > MAX_RECIPIENTS_PER_MESSAGE) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
94
114
|
const attendees = decoded.attendeeAddresses.map((address) => ({
|
|
95
115
|
address,
|
|
96
116
|
role: AttendeeRole.REQUIRED,
|
|
@@ -103,7 +123,7 @@ export class RopSaveChangesMessageHandler {
|
|
|
103
123
|
ignoreACL: true,
|
|
104
124
|
});
|
|
105
125
|
if (existing) {
|
|
106
|
-
|
|
126
|
+
const updated = {
|
|
107
127
|
uid: existing.uid,
|
|
108
128
|
version: existing.version,
|
|
109
129
|
title: decoded.title ?? existing.title,
|
|
@@ -114,8 +134,20 @@ export class RopSaveChangesMessageHandler {
|
|
|
114
134
|
recurrenceRule: decoded.recurrenceRule ?? existing.recurrenceRule,
|
|
115
135
|
timezone: decoded.timezone ?? existing.timezone,
|
|
116
136
|
reminderMinutesBeforeStart: decoded.reminderMinutesBeforeStart ?? existing.reminderMinutesBeforeStart,
|
|
117
|
-
|
|
118
|
-
|
|
137
|
+
// An attendee who is still invited keeps their recorded response.
|
|
138
|
+
attendees: attendees.length > 0
|
|
139
|
+
? attendees.map((attendee) => existing.attendees.find((prior) => prior.address.toLowerCase() === attendee.address.toLowerCase()) ??
|
|
140
|
+
attendee)
|
|
141
|
+
: existing.attendees,
|
|
142
|
+
};
|
|
143
|
+
const sequence = (existing.sequence ?? 0) + (isSchedulingRelevantChange(existing, updated) ? 1 : 0);
|
|
144
|
+
await context.calendarEventRepo.update({
|
|
145
|
+
...updated,
|
|
146
|
+
sequence,
|
|
147
|
+
// Saving sends nothing, so this revision counts as handled - unless a submitted revision is still
|
|
148
|
+
// waiting for the job, which then sends the meeting as it now stands rather than not at all.
|
|
149
|
+
inviteSequenceSent: isInvitePending(existing) ? (existing.inviteSequenceSent ?? null) : sequence,
|
|
150
|
+
}, asEntity(context.calendarEventRepo, existing), { ignoreACL: true });
|
|
119
151
|
}
|
|
120
152
|
return BigInt(assignOrGetMid(context.session, handle.entityUid));
|
|
121
153
|
}
|
|
@@ -139,11 +171,27 @@ export class RopSaveChangesMessageHandler {
|
|
|
139
171
|
reminderMinutesBeforeStart: decoded.reminderMinutesBeforeStart,
|
|
140
172
|
icalUid: `${crypto.randomUUID()}@mapi`,
|
|
141
173
|
sequence: 0,
|
|
174
|
+
// Handled until submitted: saving a meeting doesn't invite its attendees.
|
|
175
|
+
inviteSequenceSent: 0,
|
|
142
176
|
}), { ignoreACL: true });
|
|
143
177
|
handle.entityUid = `calendarEvent:${created.uid}`;
|
|
144
178
|
return BigInt(assignOrGetMid(context.session, handle.entityUid));
|
|
145
179
|
}
|
|
146
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* `true` when an update changes what attendees were invited to: the start or end time, location, recurrence, or
|
|
183
|
+
* who is invited. The same fields restapi's `BaseCalendarEventRoute.update()` bumps `sequence` for (a MAPI save
|
|
184
|
+
* never sets `status`), so an edit made in Outlook is re-sent to attendees and supersedes their copy (RFC 5546
|
|
185
|
+
* `SEQUENCE`) exactly like one made through REST.
|
|
186
|
+
*/
|
|
187
|
+
export function isSchedulingRelevantChange(existing, updated) {
|
|
188
|
+
const addresses = (attendees) => JSON.stringify(attendees.map((attendee) => attendee.address.toLowerCase()).sort());
|
|
189
|
+
return (new Date(updated.startDate).getTime() !== new Date(existing.startDate).getTime() ||
|
|
190
|
+
new Date(updated.endDate).getTime() !== new Date(existing.endDate).getTime() ||
|
|
191
|
+
(updated.location ?? "") !== (existing.location ?? "") ||
|
|
192
|
+
JSON.stringify(updated.recurrenceRule ?? null) !== JSON.stringify(existing.recurrenceRule ?? null) ||
|
|
193
|
+
addresses(updated.attendees) !== addresses(existing.attendees));
|
|
194
|
+
}
|
|
147
195
|
/** Decodes a draft message handle's accumulated `RopSetProperties` values (`Record<string, string>`, keyed by
|
|
148
196
|
* decimal `PropertyId`) back into typed `CalendarEvent` fields - the write-side mirror of
|
|
149
197
|
* `PropertyResolvers.calendarEventValueFor`'s read-side switch, sharing the same `CalendarNamedProperties.ts`
|
|
@@ -183,10 +231,10 @@ function decodeCalendarFieldsFromDraft(session, properties) {
|
|
|
183
231
|
decoded.location = value;
|
|
184
232
|
break;
|
|
185
233
|
case LID_APPOINTMENT_START_WHOLE:
|
|
186
|
-
decoded.startDate =
|
|
234
|
+
decoded.startDate = validDate(value);
|
|
187
235
|
break;
|
|
188
236
|
case LID_APPOINTMENT_END_WHOLE:
|
|
189
|
-
decoded.endDate =
|
|
237
|
+
decoded.endDate = validDate(value);
|
|
190
238
|
break;
|
|
191
239
|
case LID_BUSY_STATUS:
|
|
192
240
|
decoded.busyStatus = BUSY_STATUS_FROM_CODE[Number(value)] ?? BusyStatus.BUSY;
|
|
@@ -202,9 +250,20 @@ function decodeCalendarFieldsFromDraft(session, properties) {
|
|
|
202
250
|
}
|
|
203
251
|
}
|
|
204
252
|
else if (guid === PSETID_COMMON && named.lid === LID_REMINDER_DELTA) {
|
|
205
|
-
decoded.reminderMinutesBeforeStart =
|
|
253
|
+
decoded.reminderMinutesBeforeStart = validMinutes(value);
|
|
206
254
|
}
|
|
207
255
|
}
|
|
208
256
|
return decoded;
|
|
209
257
|
}
|
|
258
|
+
/** `value` as a date, or `undefined` (the field is left as it was) when it doesn't parse. A client picks the property
|
|
259
|
+
* type it sends, so a "time" can arrive as any string. */
|
|
260
|
+
function validDate(value) {
|
|
261
|
+
const date = new Date(value);
|
|
262
|
+
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
263
|
+
}
|
|
264
|
+
/** `value` as a whole, non-negative number of minutes, or `undefined` when it isn't one. */
|
|
265
|
+
function validMinutes(value) {
|
|
266
|
+
const minutes = Number(value);
|
|
267
|
+
return value.trim() !== "" && Number.isSafeInteger(minutes) && minutes >= 0 ? minutes : undefined;
|
|
268
|
+
}
|
|
210
269
|
//# sourceMappingURL=RopSaveChangesMessageHandler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopSaveChangesMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSaveChangesMessageHandler.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EACH,sBAAsB,EACtB,YAAY,EACZ,UAAU,EACV,aAAa,GAIhB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,YAAY,EAAqB,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,2BAA2B,EAC3B,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,GAChB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEzC;6GAC6G;AAC7G,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC,2GAA2G;AAC3G,+GAA+G;AAC/G,cAAc;AACd,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,MAAM,qBAAqB,GAAG,MAAM,CAAC;AACrC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC;kFACkF;AAClF,MAAM,gCAAgC,GAAG,iBAAiB,CAAC;AAE3D
|
|
1
|
+
{"version":3,"file":"RopSaveChangesMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSaveChangesMessageHandler.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EACH,sBAAsB,EACtB,YAAY,EACZ,UAAU,EACV,aAAa,GAIhB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,2BAA2B,EAAE,MAAM,mCAAmC,CAAC;AAChF,OAAO,EAAE,YAAY,EAAqB,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EACH,qBAAqB,EACrB,yBAAyB,EACzB,qBAAqB,EACrB,2BAA2B,EAC3B,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,GAChB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAGhE,MAAM,2BAA2B,GAAG,IAAI,CAAC;AAEzC;6GAC6G;AAC7G,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC,yFAAyF;AACzF,MAAM,aAAa,GAAG,UAAU,CAAC;AAEjC,2GAA2G;AAC3G,+GAA+G;AAC/G,cAAc;AACd,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,MAAM,qBAAqB,GAAG,MAAM,CAAC;AACrC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC;kFACkF;AAClF,MAAM,gCAAgC,GAAG,iBAAiB,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,OAAO,4BAA4B;IAAzC;QACoB,UAAK,GAAG,2BAA2B,CAAC;IAkIxD,CAAC;IAhIU,KAAK,CAAC,MAAM,CAAC,MAAoB,EAAE,MAAoB,EAAE,OAAmB;QAC/E,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,uFAAuF;QAC3G,MAAM,mBAAmB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACvD,MAAM,gBAAgB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACpD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,oCAAoC;QAExD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;YACvC,MAAM,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC;YAC/C,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;YACvC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,OAAO;QACX,CAAC;QAED,MAAM,eAAe,GAAG,MAAM,CAAC,eAAe,IAAI,EAAE,CAAC;QACrD,MAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC,IAAI,UAAU,CAAC;QAClF,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,gCAAgC,CAAC;YACjE,CAAC,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC;YAC9D,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,gBAAgB,EAAE,CAAC,CAAC,CAAC;QACxH,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACpB,MAAM,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC;YAC/C,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;YACvC,MAAM,CAAC,aAAa,CAAC,aAAa,CAAC,CAAC;YACpC,OAAO;QACX,CAAC;QAED,MAAM,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC;QAC/C,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QACvC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IAED;;;;;;;;;;OAUG;IACK,KAAK,CAAC,eAAe,CAAC,MAAwB,EAAE,eAAuC,EAAE,OAAmB;QAChH,MAAM,OAAO,GAAG,6BAA6B,CAAC,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;QAChF,IAAI,OAAO,CAAC,iBAAiB,CAAC,MAAM,GAAG,0BAA0B,EAAE,CAAC;YAChE,OAAO,SAAS,CAAC;QACrB,CAAC;QACD,MAAM,SAAS,GAAe,OAAO,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YACtE,OAAO;YACP,IAAI,EAAE,YAAY,CAAC,QAAQ;YAC3B,cAAc,EAAE,sBAAsB,CAAC,YAAY;YACnD,WAAW,EAAE,KAAK;SACrB,CAAC,CAAC,CAAC;QAEJ,IAAI,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAChD,MAAM,GAAG,GAAG,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC5D,MAAM,QAAQ,GAAmE,MAAM,OAAO,CAAC,iBAAiB,CAAC,OAAO,CAAC,GAAG,EAAE;gBAC1H,SAAS,EAAE,IAAI;aAClB,CAAC,CAAC;YACH,IAAI,QAAQ,EAAE,CAAC;gBACX,MAAM,OAAO,GAAG;oBACZ,GAAG,EAAE,QAAQ,CAAC,GAAG;oBACjB,OAAO,EAAE,QAAQ,CAAC,OAAO;oBACzB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,QAAQ,CAAC,KAAK;oBACtC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;oBAC/C,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS;oBAClD,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;oBAC5C,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU;oBACrD,cAAc,EAAE,OAAO,CAAC,cAAc,IAAI,QAAQ,CAAC,cAAc;oBACjE,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,QAAQ,CAAC,QAAQ;oBAC/C,0BAA0B,EAAE,OAAO,CAAC,0BAA0B,IAAI,QAAQ,CAAC,0BAA0B;oBACrG,kEAAkE;oBAClE,SAAS,EACL,SAAS,CAAC,MAAM,GAAG,CAAC;wBAChB,CAAC,CAAC,SAAS,CAAC,GAAG,CACT,CAAC,QAAQ,EAAE,EAAE,CACT,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC;4BAClG,QAAQ,CACf;wBACH,CAAC,CAAC,QAAQ,CAAC,SAAS;iBAC/B,CAAC;gBACF,MAAM,QAAQ,GAAW,CAAC,QAAQ,CAAC,QAAQ,IAAI,CAAC,CAAC,GAAG,CAAC,0BAA0B,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC5G,MAAM,OAAO,CAAC,iBAAiB,CAAC,MAAM,CAClC;oBACI,GAAG,OAAO;oBACV,QAAQ;oBACR,kGAAkG;oBAClG,6FAA6F;oBAC7F,kBAAkB,EAAE,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,kBAAkB,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ;iBACnG,EACD,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC,EAC7C,EAAE,SAAS,EAAE,IAAI,EAAE,CACtB,CAAC;YACN,CAAC;YACD,OAAO,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3F,qGAAqG;QACrG,qGAAqG;QACrG,MAAM,iBAAiB,GAAG,MAAM,CAAC,cAAc,IAAI,EAAE,CAAC;QACtD,MAAM,SAAS,GAAG,iBAAiB,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;QAC1H,MAAM,OAAO,GAAoC,MAAM,OAAO,CAAC,iBAAiB,CAAC,MAAM,CACnF,IAAI,OAAO,CAAC,kBAAkB,CAAC;YAC3B,SAAS;YACT,UAAU,EAAE,OAAO,CAAC,UAAU;YAC9B,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,EAAE;YAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE;YAC1C,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI,IAAI,EAAE;YACtC,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,KAAK;YACnC,SAAS,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,kBAAkB,IAAI,EAAE,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,CAAC,EAAE,EAAE;YACpH,SAAS;YACT,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,UAAU,CAAC,IAAI;YACjD,cAAc,EAAE,OAAO,CAAC,cAAc;YACtC,0BAA0B,EAAE,OAAO,CAAC,0BAA0B;YAC9D,OAAO,EAAE,GAAG,MAAM,CAAC,UAAU,EAAE,OAAO;YACtC,QAAQ,EAAE,CAAC;YACX,0EAA0E;YAC1E,kBAAkB,EAAE,CAAC;SACxB,CAAC,EACF,EAAE,SAAS,EAAE,IAAI,EAAE,CACtB,CAAC;QACF,MAAM,CAAC,SAAS,GAAG,iBAAiB,OAAO,CAAC,GAAG,EAAE,CAAC;QAClD,OAAO,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC;IACrE,CAAC;CACJ;AAED;;;;;GAKG;AACH,MAAM,UAAU,0BAA0B,CACtC,QAAoG,EACpG,OAAmG;IAEnG,MAAM,SAAS,GAAG,CAAC,SAAqB,EAAU,EAAE,CAChD,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvF,OAAO,CACH,IAAI,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE;QAChF,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE;QAC5E,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,cAAc,IAAI,IAAI,CAAC;QAClG,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CACjE,CAAC;AACN,CAAC;AAmBD;;;;;;;;;;;;;qFAaqF;AACrF,SAAS,6BAA6B,CAAC,OAA2B,EAAE,UAAkC;IAClG,MAAM,UAAU,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;IAC3C,MAAM,OAAO,GAA0B;QACnC,KAAK,EAAE,UAAU,IAAI,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS;QACpE,iBAAiB,EAAE;YACf,GAAG,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;YAC3D,GAAG,gBAAgB,CAAC,UAAU,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;SAC9D;KACJ,CAAC;IAEF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;QACpD,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,UAAU,GAAG,MAAM,EAAE,CAAC;YACtB,SAAS;QACb,CAAC;QACD,MAAM,KAAK,GAAG,oBAAoB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;QACxD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;YACjC,SAAS;QACb,CAAC;QACD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QACtC,IAAI,IAAI,KAAK,kBAAkB,EAAE,CAAC;YAC9B,QAAQ,KAAK,CAAC,GAAG,EAAE,CAAC;gBAChB,KAAK,YAAY;oBACb,OAAO,CAAC,QAAQ,GAAG,KAAK,CAAC;oBACzB,MAAM;gBACV,KAAK,2BAA2B;oBAC5B,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;oBACrC,MAAM;gBACV,KAAK,yBAAyB;oBAC1B,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;oBACnC,MAAM;gBACV,KAAK,eAAe;oBAChB,OAAO,CAAC,UAAU,GAAG,qBAAqB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC;oBAC7E,MAAM;gBACV,KAAK,qBAAqB;oBACtB,OAAO,CAAC,cAAc,GAAG,2BAA2B,CAAC,IAAI,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;oBACrG,MAAM;gBACV,KAAK,oBAAoB;oBACrB,OAAO,CAAC,QAAQ,GAAG,oBAAoB,CAAC,IAAI,YAAY,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;oBACxF,MAAM;gBACV;oBACI,MAAM;YACd,CAAC;QACL,CAAC;aAAM,IAAI,IAAI,KAAK,aAAa,IAAI,KAAK,CAAC,GAAG,KAAK,kBAAkB,EAAE,CAAC;YACpE,OAAO,CAAC,0BAA0B,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;QAC7D,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;0DAC0D;AAC1D,SAAS,SAAS,CAAC,KAAa;IAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3D,CAAC;AAED,4FAA4F;AAC5F,SAAS,YAAY,CAAC,KAAa;IAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;AACtG,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readPropertyTagArray } from "../codec/PropertyValue.js";
|
|
2
2
|
const ROP_ID_SET_COLUMNS = 0x12;
|
|
3
3
|
/** `TBLSTAT_COMPLETE` - this pragmatic subset's tables are always populated synchronously, so `RopSetColumns`
|
|
4
4
|
* (and every other table ROP) never reports any other `TableStatus` value. */
|
|
@@ -7,6 +7,8 @@ const TABLE_STATUS_COMPLETE = 0x00;
|
|
|
7
7
|
* doesn't exist)" - the same constant `RopQueryRowsHandler`/`RopGetHierarchyTableHandler` use for their own
|
|
8
8
|
* analogous checks. */
|
|
9
9
|
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
10
|
+
/** `MAPI_E_TOO_BIG`, for more than `MAX_PROPERTY_TAG_COUNT` columns. */
|
|
11
|
+
const ERROR_TOO_BIG = 0x80040305;
|
|
10
12
|
/**
|
|
11
13
|
* `RopSetColumns` (`[MS-OXCTABL]`/`[MS-OXCROPS]`): configures which properties a table's subsequent
|
|
12
14
|
* `RopQueryRows` calls return, and in what order. Unlike `RopOpenFolder`/`RopGetHierarchyTable`, this ROP
|
|
@@ -30,16 +32,12 @@ export class RopSetColumnsHandler {
|
|
|
30
32
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
31
33
|
const inputHandleIndex = reader.readUInt8();
|
|
32
34
|
reader.readUInt8(); // SetColumnsFlags - this pragmatic subset has no async/deferred column-set variant
|
|
33
|
-
const
|
|
34
|
-
const columns = [];
|
|
35
|
-
for (let i = 0; i < propertyTagCount; i++) {
|
|
36
|
-
columns.push(readPropertyTag(reader));
|
|
37
|
-
}
|
|
35
|
+
const columns = readPropertyTagArray(reader, reader.readUInt16LE());
|
|
38
36
|
const handle = context.session.handles[inputHandleIndex];
|
|
39
|
-
if (!handle || handle.type !== "table") {
|
|
37
|
+
if (!handle || handle.type !== "table" || !columns) {
|
|
40
38
|
writer.writeUInt8(ROP_ID_SET_COLUMNS);
|
|
41
39
|
writer.writeUInt8(inputHandleIndex);
|
|
42
|
-
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
40
|
+
writer.writeUInt32LE(columns ? ERROR_INVALID_OBJECT : ERROR_TOO_BIG);
|
|
43
41
|
return;
|
|
44
42
|
}
|
|
45
43
|
handle.columns = columns;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopSetColumnsHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSetColumnsHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"RopSetColumnsHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSetColumnsHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAGjE,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC;8EAC8E;AAC9E,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC;;uBAEuB;AACvB,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC,wEAAwE;AACxE,MAAM,aAAa,GAAG,UAAU,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,oBAAoB;IAAjC;QACoB,UAAK,GAAG,kBAAkB,CAAC;IAsB/C,CAAC;IApBU,MAAM,CAAC,MAAoB,EAAE,MAAoB,EAAE,OAAmB;QACzE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,uFAAuF;QAC3G,MAAM,gBAAgB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACpD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,mFAAmF;QACvG,MAAM,OAAO,GAAG,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAEpE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;YACjD,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;YACtC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;YACrE,OAAO;QACX,CAAC;QACD,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;QAEzB,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;QACtC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;IAC7C,CAAC;CACJ"}
|
|
@@ -7,6 +7,8 @@ const ROP_ID_SET_PROPERTIES = 0x0a;
|
|
|
7
7
|
* `RopSetProperties` is also spec-valid on Folder/Attachment/Logon objects, none of which this pragmatic
|
|
8
8
|
* subset's compose/send path ever needs to set properties on. */
|
|
9
9
|
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
10
|
+
/** `MAPI_E_INVALID_PARAMETER`: `PropertyValues` couldn't be decoded, or didn't match `PropertyValueSize`. */
|
|
11
|
+
const ERROR_INVALID_PARAMETER = 0x80070057;
|
|
10
12
|
// The small, well-known set of plain (non-named) properties this pragmatic subset's compose/send path tracks -
|
|
11
13
|
// exactly what RopSubmitMessageHandler/RopSaveChangesMessageHandler need to build a MIME message or persist a
|
|
12
14
|
// CalendarEvent (Subject, an inline small body, the PidTagDisplayTo/Cc/Bcc "cached recipient display string"
|
|
@@ -94,21 +96,30 @@ export class RopSetPropertiesHandler {
|
|
|
94
96
|
// PropertyValueSize covers the PropertyValueCount field itself plus PropertyValues, counted from right
|
|
95
97
|
// here (immediately after the PropertyValueSize field, before PropertyValueCount is read).
|
|
96
98
|
const propertyValuesEnd = reader.position + propertyValueSize;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
let values = [];
|
|
100
|
+
try {
|
|
101
|
+
const propertyValueCount = reader.readUInt16LE();
|
|
102
|
+
for (let i = 0; i < propertyValueCount; i++) {
|
|
103
|
+
values.push(readTaggedPropertyValue(reader));
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
values = undefined; // e.g. an unsupported property type, whose size can't be known
|
|
101
108
|
}
|
|
102
|
-
// PropertyValueSize
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
+
// PropertyValueSize frames this ROP, so a list that couldn't be decoded, or decoded to a different length, is
|
|
110
|
+
// skipped by it and only this ROP fails; the ROPs after it are still where PropertyValueSize says. When
|
|
111
|
+
// PropertyValueSize itself points past the request, seek throws and the whole request is rejected.
|
|
112
|
+
const decodedEnd = reader.position;
|
|
113
|
+
reader.seek(propertyValuesEnd);
|
|
114
|
+
if (!values || decodedEnd !== propertyValuesEnd) {
|
|
115
|
+
writer.writeUInt8(ROP_ID_SET_PROPERTIES);
|
|
116
|
+
writer.writeUInt8(inputHandleIndex);
|
|
117
|
+
writer.writeUInt32LE(ERROR_INVALID_PARAMETER);
|
|
118
|
+
return;
|
|
109
119
|
}
|
|
110
120
|
const handle = context.session.handles[inputHandleIndex];
|
|
111
|
-
|
|
121
|
+
// A draft already submitted is finished: changing it can't change what was sent, and must not set up a resend.
|
|
122
|
+
if (!handle || handle.type !== "message" || handle.submitted) {
|
|
112
123
|
writer.writeUInt8(ROP_ID_SET_PROPERTIES);
|
|
113
124
|
writer.writeUInt8(inputHandleIndex);
|
|
114
125
|
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopSetPropertiesHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSetPropertiesHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAA4B,MAAM,2BAA2B,CAAC;AAC5G,OAAO,EACH,yBAAyB,EACzB,qBAAqB,EACrB,2BAA2B,EAC3B,eAAe,EACf,oBAAoB,EACpB,YAAY,EAEZ,kBAAkB,EAElB,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,cAAc,GACjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAGlE,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC;;;iEAGiE;AACjE,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC,+GAA+G;AAC/G,8GAA8G;AAC9G,6GAA6G;AAC7G,6GAA6G;AAC7G,+FAA+F;AAC/F,2GAA2G;AAC3G,4GAA4G;AAC5G,0GAA0G;AAC1G,+GAA+G;AAC/G,iHAAiH;AACjH,sDAAsD;AACtD,MAAM,eAAe,GAAG,MAAM,CAAC;AAC/B,MAAM,qBAAqB,GAAG,MAAM,CAAC;AACrC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AACnC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAClC,MAAM,YAAY,GAAG,MAAM,CAAC;AAC5B;;8GAE8G;AAC9G,MAAM,CAAC,MAAM,8BAA8B,GAAG,MAAM,CAAC;AACrD;;;qCAGqC;AACrC,MAAM,CAAC,MAAM,0BAA0B,GAAG,MAAM,CAAC;AACjD,MAAM,oBAAoB,GAAwB,IAAI,GAAG,CAAC;IACtD,eAAe;IACf,qBAAqB;IACrB,mBAAmB;IACnB,kBAAkB;IAClB,kBAAkB;IAClB,YAAY;IACZ,8BAA8B;IAC9B,0BAA0B;CAC7B,CAAC,CAAC;AAEH;;;;4GAI4G;AAC5G,MAAM,wBAAwB,GAAwB,IAAI,GAAG,CAAC;IAC1D,YAAY;IACZ,2BAA2B;IAC3B,yBAAyB;IACzB,eAAe;IACf,qBAAqB;IACrB,oBAAoB;CACvB,CAAC,CAAC;AACH,MAAM,mBAAmB,GAAwB,IAAI,GAAG,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAE/E;;sCAEsC;AACtC,MAAM,oBAAoB,GAAwB,IAAI,GAAG,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC;AAElF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,OAAO,uBAAuB;IAApC;QACoB,UAAK,GAAG,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"RopSetPropertiesHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSetPropertiesHandler.ts"],"names":[],"mappings":"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"}
|