@rapidmx/mapi-plugin 1.0.0-beta.3 → 1.0.0-beta.5
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 +229 -37
- 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 +118 -77
- package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -1
- package/dist/lib/rop/RopDeleteMessagesHandler.js +26 -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 +148 -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 +59 -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 +40 -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,3 +1,4 @@
|
|
|
1
|
+
import { loadFastTransferBuffer } from "./FastTransferStream.js";
|
|
1
2
|
const ROP_ID_GET_BUFFER = 0x4e;
|
|
2
3
|
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a
|
|
3
4
|
* `fastTransfer` handle (or doesn't exist)" - the same constant `RopGetPropertiesSpecificHandler` uses for its
|
|
@@ -6,32 +7,33 @@ const ERROR_INVALID_OBJECT = 0x80070005;
|
|
|
6
7
|
/** The `BufferSize` sentinel (`[MS-OXCROPS]`'s own documented value) meaning "let the server pick the chunk
|
|
7
8
|
* size". */
|
|
8
9
|
const BUFFER_SIZE_SERVER_DETERMINED = 0xbabe;
|
|
9
|
-
/** The response's own `TransferBufferSize` field is a 16-bit count
|
|
10
|
-
* response-buffer page), so a single call can never actually return more than this many bytes. For the
|
|
11
|
-
* `0xBABE` "server-determined" sentinel this caps what would otherwise be "the entire remaining buffer in one
|
|
12
|
-
* call" (only spec-valid when that buffer happens to fit in a `uint16`) down to the same paging behavior a
|
|
13
|
-
* client-specified `BufferSize` already gets - `writeUInt16LE` throwing `RangeError` for an out-of-range value
|
|
14
|
-
* is not spec-valid for any size of transfer. */
|
|
10
|
+
/** The response's own `TransferBufferSize` field is a 16-bit count, so a single call never returns more than this. */
|
|
15
11
|
const MAX_TRANSFER_BUFFER_SIZE = 0xffff;
|
|
16
|
-
/** `
|
|
17
|
-
|
|
18
|
-
|
|
12
|
+
/** `MAPI_E_TOO_BIG`: rebuilding the stream passed `MAX_FAST_TRANSFER_BYTES`. */
|
|
13
|
+
const ERROR_TOO_BIG = 0x80040305;
|
|
14
|
+
/** `MAPI_E_CALL_FAILED`: the stream was lost part-way through paging and can't be continued - see
|
|
15
|
+
* `loadFastTransferBuffer`. The client starts the transfer again. */
|
|
16
|
+
const ERROR_TRANSFER_LOST = 0x80004005;
|
|
17
|
+
/** The response bytes before `TransferBuffer`: RopId, InputHandleIndex, ReturnValue, TransferStatus,
|
|
18
|
+
* InProgressCount, TotalStepCount, Reserved, TransferBufferSize. */
|
|
19
|
+
const RESPONSE_HEADER_BYTES = 15;
|
|
20
|
+
/** `TransferStatus` values (`[MS-OXCFXICS]` §2.2.3.1.1.5.2). */
|
|
19
21
|
const TRANSFER_STATUS_PARTIAL = 0x0001;
|
|
22
|
+
const TRANSFER_STATUS_NO_ROOM = 0x0002;
|
|
20
23
|
const TRANSFER_STATUS_DONE = 0x0003;
|
|
21
24
|
/**
|
|
22
25
|
* `RopFastTransferSourceGetBuffer` (`[MS-OXCFXICS]`/`[MS-OXCROPS]`, RopId `0x4E`): pages the FastTransfer
|
|
23
26
|
* stream a prior `RopFastTransferSourceCopyTo`/`CopyProperties` built (`FastTransferStream.ts`) out of its
|
|
24
|
-
* `"fastTransfer"` handle, `BufferSize` bytes at a time
|
|
25
|
-
*
|
|
26
|
-
* in that case, is decoded to advance the reader correctly but not honored, since honoring it would mean
|
|
27
|
-
* returning *more* than one chunk can carry, not less). Reports `Done` once the whole buffer has been returned
|
|
28
|
-
* across one or more calls, `Partial` otherwise - `NoRoom` and `Error` are never produced (a `"fastTransfer"`
|
|
29
|
-
* handle, once created, always has a complete, already-valid buffer to page from).
|
|
27
|
+
* `"fastTransfer"` handle, `BufferSize` bytes at a time. For the `0xBABE` "server-determined" sentinel the server
|
|
28
|
+
* picks the size, up to the client's `MaximumBufferSize`.
|
|
30
29
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
30
|
+
* Every chunk is also held to the room left in this request's ROP output buffer (`context.ropOutputRemaining`) and
|
|
31
|
+
* the 16-bit `TransferBufferSize`. Reports `Done` once the whole stream has been returned, `Partial` otherwise, and
|
|
32
|
+
* `NoRoom` when the output buffer has no space for any bytes this time (the client asks again in a new request).
|
|
33
|
+
*
|
|
34
|
+
* Fails with `MAPI_E_TOO_BIG` when a stream that had to be rebuilt is too large, and with `MAPI_E_CALL_FAILED` when
|
|
35
|
+
* the stream was lost part-way through (see `loadFastTransferBuffer`) - never with bytes from a different stream.
|
|
36
|
+
* Failure responses carry only `ReturnValue`, like every other failing handler here. `BackoffTime` is never emitted.
|
|
35
37
|
*
|
|
36
38
|
* @author Jean-Philippe Steinmetz
|
|
37
39
|
*/
|
|
@@ -39,32 +41,31 @@ export class RopFastTransferSourceGetBufferHandler {
|
|
|
39
41
|
constructor() {
|
|
40
42
|
this.ropId = ROP_ID_GET_BUFFER;
|
|
41
43
|
}
|
|
42
|
-
handle(reader, writer, context) {
|
|
44
|
+
async handle(reader, writer, context) {
|
|
43
45
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
44
46
|
const inputHandleIndex = reader.readUInt8();
|
|
45
47
|
const bufferSize = reader.readUInt16LE();
|
|
46
|
-
|
|
47
|
-
reader.readUInt16LE(); // MaximumBufferSize - see class doc comment
|
|
48
|
-
}
|
|
48
|
+
const requestedSize = bufferSize === BUFFER_SIZE_SERVER_DETERMINED ? reader.readUInt16LE() : bufferSize;
|
|
49
49
|
const handle = context.session.handles[inputHandleIndex];
|
|
50
|
-
|
|
50
|
+
const loaded = handle?.type === "fastTransfer" ? await loadFastTransferBuffer(context, inputHandleIndex, handle) : undefined;
|
|
51
|
+
if (!loaded || typeof loaded === "string") {
|
|
51
52
|
writer.writeUInt8(ROP_ID_GET_BUFFER);
|
|
52
53
|
writer.writeUInt8(inputHandleIndex);
|
|
53
|
-
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
54
|
+
writer.writeUInt32LE(!loaded ? ERROR_INVALID_OBJECT : loaded === "tooBig" ? ERROR_TOO_BIG : ERROR_TRANSFER_LOST);
|
|
54
55
|
return;
|
|
55
56
|
}
|
|
56
|
-
const fullBuffer = Buffer.from(handle.transferBufferBase64 ?? "", "base64");
|
|
57
57
|
const position = handle.transferPosition ?? 0;
|
|
58
|
-
const remaining =
|
|
59
|
-
const
|
|
60
|
-
const chunkSize = Math.min(requestedSize, remaining, MAX_TRANSFER_BUFFER_SIZE);
|
|
61
|
-
const chunk =
|
|
58
|
+
const remaining = loaded.length - position;
|
|
59
|
+
const room = Math.max(0, (context.ropOutputRemaining ?? Infinity) - RESPONSE_HEADER_BYTES);
|
|
60
|
+
const chunkSize = Math.min(requestedSize, remaining, MAX_TRANSFER_BUFFER_SIZE, room);
|
|
61
|
+
const chunk = loaded.subarray(position, position + chunkSize);
|
|
62
62
|
handle.transferPosition = position + chunk.length;
|
|
63
|
-
const done =
|
|
63
|
+
const done = position + chunk.length >= loaded.length;
|
|
64
|
+
const status = done ? TRANSFER_STATUS_DONE : room === 0 ? TRANSFER_STATUS_NO_ROOM : TRANSFER_STATUS_PARTIAL;
|
|
64
65
|
writer.writeUInt8(ROP_ID_GET_BUFFER);
|
|
65
66
|
writer.writeUInt8(inputHandleIndex);
|
|
66
67
|
writer.writeUInt32LE(0); // ReturnValue - success
|
|
67
|
-
writer.writeUInt16LE(
|
|
68
|
+
writer.writeUInt16LE(status);
|
|
68
69
|
writer.writeUInt16LE(0); // InProgressCount - no real progress tracking in this pragmatic subset
|
|
69
70
|
writer.writeUInt16LE(1); // TotalStepCount - pragmatic constant, only ever used for progress-bar display
|
|
70
71
|
writer.writeUInt8(0); // Reserved
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopFastTransferSourceGetBufferHandler.js","sourceRoot":"","sources":["../../../src/rop/RopFastTransferSourceGetBufferHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RopFastTransferSourceGetBufferHandler.js","sourceRoot":"","sources":["../../../src/rop/RopFastTransferSourceGetBufferHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
-
import { FolderType } from "@rapidmx/restapi";
|
|
6
|
-
import { resolveFolderCalendarEvents } from "./CalendarEventTarget.js";
|
|
7
|
-
import { resolveFolderContacts } from "./ContactTarget.js";
|
|
8
|
-
import { resolveFolderMessages } from "./MessageTarget.js";
|
|
9
|
-
import { resolveFolderTasks } from "./TaskTarget.js";
|
|
1
|
+
import { assignHandle } from "../MapiSessionManager.js";
|
|
2
|
+
import { resolveContentsKind } from "./ContentsTable.js";
|
|
10
3
|
const ROP_ID_GET_CONTENTS_TABLE = 0x05;
|
|
11
4
|
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a folder (or
|
|
12
5
|
* doesn't exist)" - the same constant `RopGetHierarchyTableHandler` uses for its own analogous check. */
|
|
@@ -16,28 +9,23 @@ const ERROR_INVALID_OBJECT = 0x80070005;
|
|
|
16
9
|
* messages, producing a new `"table"` Server object handle `RopSetColumns`/`RopQueryRows` reference by
|
|
17
10
|
* `InputHandleIndex` - the exact same request/response shape as `RopGetHierarchyTable` (confirmed identical
|
|
18
11
|
* field-by-field against `[MS-OXCROPS]`'s own request-buffer page, differing only in `RopId`), just listing
|
|
19
|
-
* messages instead of child folders.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
12
|
+
* messages instead of child folders.
|
|
13
|
+
*
|
|
14
|
+
* The table holds no rows. It records which kind of item the folder contains (`contentsKind`, decided once here
|
|
15
|
+
* from the folder's own `type`: Calendar folders list `"calendarEvent:<uid>"` rows, Contacts `"contact:<uid>"`,
|
|
16
|
+
* Tasks `"task:<uid>"`, everything else `"message:<uid>"`), and `RopQueryRows` reads each requested window from
|
|
17
|
+
* the database - see `ContentsTable.ts`.
|
|
23
18
|
*
|
|
24
19
|
* A folder's contents table is only ever non-empty for a real folder (`"folder:<uid>"`) - the virtual special
|
|
25
20
|
* folders (`RopLogonHandler`'s own doc comment) have no real backing row to hold messages under, so opening a
|
|
26
21
|
* contents table on one always yields an empty table rather than an error.
|
|
27
22
|
*
|
|
28
|
-
* **Calendar folders** (`Folder.type === FolderType.CALENDAR`) list `"calendarEvent:<uid>"` rows resolved via
|
|
29
|
-
* `calendarEventRepo` instead of `"message:<uid>"` rows - a single table handle only ever holds one kind of
|
|
30
|
-
* row, decided once here by checking the folder's own `type`, exactly the same "resolve by target-string
|
|
31
|
-
* prefix downstream" design `MessageTarget`/`FolderTarget` already use for their own rows. **Contacts and
|
|
32
|
-
* Tasks** folders (`FolderType.CONTACTS`/`TASKS`) list `"contact:<uid>"`/`"task:<uid>"` rows the same way, via
|
|
33
|
-
* `contactRepo`/`taskRepo` - empty (rather than an error) when the context has neither wired up, the same
|
|
34
|
-
* optional-repo degradation `RopContext`'s own doc comment describes.
|
|
35
|
-
*
|
|
36
23
|
* @author Jean-Philippe Steinmetz
|
|
37
24
|
*/
|
|
38
25
|
export class RopGetContentsTableHandler {
|
|
39
26
|
constructor() {
|
|
40
27
|
this.ropId = ROP_ID_GET_CONTENTS_TABLE;
|
|
28
|
+
this.responseHandleIndexOffset = 3; // OutputHandleIndex
|
|
41
29
|
}
|
|
42
30
|
async handle(reader, writer, context) {
|
|
43
31
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
@@ -51,26 +39,17 @@ export class RopGetContentsTableHandler {
|
|
|
51
39
|
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
52
40
|
return;
|
|
53
41
|
}
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
:
|
|
57
|
-
|
|
42
|
+
const entityUid = folderHandle.entityUid;
|
|
43
|
+
if (entityUid.startsWith("folder:")) {
|
|
44
|
+
const contentsKind = await resolveContentsKind(entityUid.slice("folder:".length), context);
|
|
45
|
+
assignHandle(context.session, outputHandleIndex, { type: "table", entityUid, contentsKind, cursor: 0 });
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
assignHandle(context.session, outputHandleIndex, { type: "table", entityUid, rows: [], cursor: 0 });
|
|
49
|
+
}
|
|
58
50
|
writer.writeUInt8(ROP_ID_GET_CONTENTS_TABLE);
|
|
59
51
|
writer.writeUInt8(outputHandleIndex);
|
|
60
52
|
writer.writeUInt32LE(0); // ReturnValue - success
|
|
61
53
|
}
|
|
62
|
-
async resolveRows(folderUid, context) {
|
|
63
|
-
const folder = await context.folderRepo.findOne(folderUid, { ignoreACL: true });
|
|
64
|
-
if (folder?.type === FolderType.CALENDAR) {
|
|
65
|
-
return resolveFolderCalendarEvents(folderUid, context.calendarEventRepo);
|
|
66
|
-
}
|
|
67
|
-
if (folder?.type === FolderType.CONTACTS) {
|
|
68
|
-
return context.contactRepo ? resolveFolderContacts(folderUid, context.contactRepo) : [];
|
|
69
|
-
}
|
|
70
|
-
if (folder?.type === FolderType.TASKS) {
|
|
71
|
-
return context.taskRepo ? resolveFolderTasks(folderUid, context.taskRepo) : [];
|
|
72
|
-
}
|
|
73
|
-
return resolveFolderMessages(folderUid, context.messageRepo);
|
|
74
|
-
}
|
|
75
54
|
}
|
|
76
55
|
//# sourceMappingURL=RopGetContentsTableHandler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopGetContentsTableHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetContentsTableHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RopGetContentsTableHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetContentsTableHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGzD,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAEvC;yGACyG;AACzG,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,0BAA0B;IAAvC;QACoB,UAAK,GAAG,yBAAyB,CAAC;QAClC,8BAAyB,GAAG,CAAC,CAAC,CAAC,oBAAoB;IA4BvE,CAAC;IA1BU,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,iBAAiB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACrD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,6GAA6G;QAEjI,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC/D,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClD,MAAM,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC;YAC7C,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,OAAO;QACX,CAAC;QAED,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC;QACzC,IAAI,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAClC,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;YAC3F,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAC5G,CAAC;aAAM,CAAC;YACJ,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QACxG,CAAC;QAED,MAAM,CAAC,UAAU,CAAC,yBAAyB,CAAC,CAAC;QAC7C,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;IACrD,CAAC;CACJ"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assignHandle } from "../MapiSessionManager.js";
|
|
1
2
|
import { resolveFolderChildren } from "./FolderTarget.js";
|
|
2
3
|
const ROP_ID_GET_HIERARCHY_TABLE = 0x04;
|
|
3
4
|
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a folder
|
|
@@ -17,6 +18,7 @@ const ERROR_INVALID_OBJECT = 0x80070005;
|
|
|
17
18
|
export class RopGetHierarchyTableHandler {
|
|
18
19
|
constructor() {
|
|
19
20
|
this.ropId = ROP_ID_GET_HIERARCHY_TABLE;
|
|
21
|
+
this.responseHandleIndexOffset = 3; // OutputHandleIndex
|
|
20
22
|
}
|
|
21
23
|
async handle(reader, writer, context) {
|
|
22
24
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
@@ -30,8 +32,8 @@ export class RopGetHierarchyTableHandler {
|
|
|
30
32
|
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
|
-
const rows = await resolveFolderChildren(context.mailboxUid, folderHandle.entityUid, context.folderRepo);
|
|
34
|
-
context.session
|
|
35
|
+
const rows = await resolveFolderChildren(context.mailboxUid, folderHandle.entityUid, context.folderRepo, undefined, context.budget);
|
|
36
|
+
assignHandle(context.session, outputHandleIndex, { type: "table", entityUid: folderHandle.entityUid, rows, cursor: 0 });
|
|
35
37
|
writer.writeUInt8(ROP_ID_GET_HIERARCHY_TABLE);
|
|
36
38
|
writer.writeUInt8(outputHandleIndex);
|
|
37
39
|
writer.writeUInt32LE(0); // ReturnValue - success
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopGetHierarchyTableHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetHierarchyTableHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAExC;0BAC0B;AAC1B,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;GAUG;AACH,MAAM,OAAO,2BAA2B;IAAxC;QACoB,UAAK,GAAG,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"RopGetHierarchyTableHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetHierarchyTableHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,MAAM,0BAA0B,GAAG,IAAI,CAAC;AAExC;0BAC0B;AAC1B,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;GAUG;AACH,MAAM,OAAO,2BAA2B;IAAxC;QACoB,UAAK,GAAG,0BAA0B,CAAC;QACnC,8BAAyB,GAAG,CAAC,CAAC,CAAC,oBAAoB;IAuBvE,CAAC;IArBU,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,iBAAiB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACrD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,iFAAiF;QAErG,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC/D,IAAI,CAAC,YAAY,IAAI,YAAY,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAClD,MAAM,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC;YAC9C,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,OAAO;QACX,CAAC;QAED,MAAM,IAAI,GAAa,MAAM,qBAAqB,CAAC,OAAO,CAAC,UAAU,EAAE,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,EAAE,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QAC9I,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;QAExH,MAAM,CAAC,UAAU,CAAC,0BAA0B,CAAC,CAAC;QAC9C,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;IACrD,CAAC;CACJ"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { readPropertyTagArray, writePropertyValue } from "../codec/PropertyValue.js";
|
|
2
2
|
import { resolvePropertyValues } from "./PropertyResolvers.js";
|
|
3
3
|
const ROP_ID_GET_PROPERTIES_SPECIFIC = 0x07;
|
|
4
4
|
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a
|
|
@@ -6,6 +6,8 @@ const ROP_ID_GET_PROPERTIES_SPECIFIC = 0x07;
|
|
|
6
6
|
* use for their own analogous checks. Attachment/Logon objects (also spec-valid targets for this ROP) aren't
|
|
7
7
|
* supported in this pragmatic subset. */
|
|
8
8
|
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
9
|
+
/** `MAPI_E_TOO_BIG`, for more than `MAX_PROPERTY_TAG_COUNT` requested tags. */
|
|
10
|
+
const ERROR_TOO_BIG = 0x80040305;
|
|
9
11
|
/**
|
|
10
12
|
* `RopGetPropertiesSpecific` (`[MS-OXCPRPT]`/`[MS-OXCROPS]`): fetches named property values for a single
|
|
11
13
|
* already-opened Folder or Message object (`RopOpenFolder`/`RopOpenMessage`), by an explicit `PropertyTags`
|
|
@@ -32,16 +34,12 @@ export class RopGetPropertiesSpecificHandler {
|
|
|
32
34
|
const inputHandleIndex = reader.readUInt8();
|
|
33
35
|
reader.readUInt16LE(); // PropertySizeLimit - no truncation support in this pragmatic subset
|
|
34
36
|
reader.readUInt16LE(); // WantUnicode - this pragmatic subset always encodes strings the same way regardless
|
|
35
|
-
const
|
|
36
|
-
const propertyTags = [];
|
|
37
|
-
for (let i = 0; i < propertyTagCount; i++) {
|
|
38
|
-
propertyTags.push(readPropertyTag(reader));
|
|
39
|
-
}
|
|
37
|
+
const propertyTags = readPropertyTagArray(reader, reader.readUInt16LE());
|
|
40
38
|
const handle = context.session.handles[inputHandleIndex];
|
|
41
|
-
if (!handle || (handle.type !== "folder" && handle.type !== "message")) {
|
|
39
|
+
if (!handle || (handle.type !== "folder" && handle.type !== "message") || !propertyTags) {
|
|
42
40
|
writer.writeUInt8(ROP_ID_GET_PROPERTIES_SPECIFIC);
|
|
43
41
|
writer.writeUInt8(inputHandleIndex);
|
|
44
|
-
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
42
|
+
writer.writeUInt32LE(propertyTags ? ERROR_INVALID_OBJECT : ERROR_TOO_BIG);
|
|
45
43
|
return;
|
|
46
44
|
}
|
|
47
45
|
const values = await resolvePropertyValues(handle.entityUid, propertyTags, context);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopGetPropertiesSpecificHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetPropertiesSpecificHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"RopGetPropertiesSpecificHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetPropertiesSpecificHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACrF,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAG/D,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAE5C;;;yCAGyC;AACzC,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC,+EAA+E;AAC/E,MAAM,aAAa,GAAG,UAAU,CAAC;AAEjC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,+BAA+B;IAA5C;QACoB,UAAK,GAAG,8BAA8B,CAAC;IAyB3D,CAAC;IAvBU,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,YAAY,EAAE,CAAC,CAAC,qEAAqE;QAC5F,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,qFAAqF;QAC5G,MAAM,YAAY,GAAG,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;QAEzE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;YACtF,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC;YAClD,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;YAC1E,OAAO;QACX,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,MAAM,CAAC,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC;QAEpF,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC;QAClD,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,iEAAiE;QAC1F,YAAY,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,MAAM,EAAE,GAAG,CAAC,YAAY,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACtG,CAAC;CACJ"}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { defaultHandleDataStore } from "./HandleDataCache.js";
|
|
2
|
+
/** The `HandleDataStore` a handler should use for `context`. */
|
|
3
|
+
export function handleDataStoreOf(context) {
|
|
4
|
+
return context.handleData ?? defaultHandleDataStore;
|
|
5
|
+
}
|
|
2
6
|
//# sourceMappingURL=RopHandler.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopHandler.js","sourceRoot":"","sources":["../../../src/rop/RopHandler.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"RopHandler.js","sourceRoot":"","sources":["../../../src/rop/RopHandler.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,sBAAsB,EAAwB,MAAM,sBAAsB,CAAC;AA8EpF,gEAAgE;AAChE,MAAM,UAAU,iBAAiB,CAAC,OAAuC;IACrE,OAAO,OAAO,CAAC,UAAU,IAAI,sBAAsB,CAAC;AACxD,CAAC"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { BufferWriter } from "../codec/BufferCursor.js";
|
|
6
6
|
import { encodeGuid } from "../codec/MapiGuid.js";
|
|
7
7
|
import { FolderType } from "@rapidmx/restapi";
|
|
8
|
+
import { assignHandle } from "../MapiSessionManager.js";
|
|
8
9
|
import { assignOrGetFid } from "./FolderTarget.js";
|
|
9
10
|
const ROP_ID_LOGON = 0xfe;
|
|
10
11
|
/** A fixed replica identity shared by every logon in this deployment - legitimate per `[MS-OXCSTOR]`'s own
|
|
@@ -66,7 +67,7 @@ export class RopLogonHandler {
|
|
|
66
67
|
reader.readBytes(essdnSize); // Essdn - never trusted for mailbox identity, see class doc comment
|
|
67
68
|
}
|
|
68
69
|
const fids = await this.assignFolderIds(context);
|
|
69
|
-
context.session
|
|
70
|
+
assignHandle(context.session, outputHandleIndex, { type: "logon", entityUid: context.mailboxUid });
|
|
70
71
|
writer.writeUInt8(ROP_ID_LOGON);
|
|
71
72
|
writer.writeUInt8(outputHandleIndex);
|
|
72
73
|
writer.writeUInt32LE(0); // ReturnValue - success
|
|
@@ -105,7 +106,9 @@ export class RopLogonHandler {
|
|
|
105
106
|
if (!folder.folderType) {
|
|
106
107
|
return `virtual:${folder.name}`;
|
|
107
108
|
}
|
|
108
|
-
|
|
109
|
+
// The oldest folder of the type, like restapi's findOrCreateWellKnownFolder, so a mailbox that somehow
|
|
110
|
+
// has two gets the same one every time.
|
|
111
|
+
const existing = await context.folderRepo.find({ mailboxUid: context.mailboxUid, type: folder.folderType, sort: { dateCreated: "ASC", uid: "ASC" }, limit: 1 }, { ignoreACL: true, limit: 1 });
|
|
109
112
|
return existing[0] ? `folder:${existing[0].uid}` : `virtual:${folder.name}`;
|
|
110
113
|
}));
|
|
111
114
|
const fids = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopLogonHandler.js","sourceRoot":"","sources":["../../../src/rop/RopLogonHandler.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAgB,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAU,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGnD,MAAM,YAAY,GAAG,IAAI,CAAC;AAE1B;;;2GAG2G;AAC3G,MAAM,OAAO,GAAG,CAAC,CAAC;AAClB,MAAM,SAAS,GAAG,sCAAsC,CAAC;AAEzD;;;;;;;;;;;;GAYG;AACH,MAAM,eAAe,GAAgD;IACjE,EAAE,IAAI,EAAE,MAAM,EAAE;IAChB,EAAE,IAAI,EAAE,gBAAgB,EAAE;IAC1B,EAAE,IAAI,EAAE,cAAc,EAAE;IACxB,EAAE,IAAI,EAAE,YAAY,EAAE;IACtB,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE;IAC/C,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE;IACjD,EAAE,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,CAAC,UAAU,EAAE;IACxD,EAAE,IAAI,EAAE,cAAc,EAAE,UAAU,EAAE,UAAU,CAAC,aAAa,EAAE;IAC9D,EAAE,IAAI,EAAE,aAAa,EAAE;IACvB,EAAE,IAAI,EAAE,UAAU,EAAE;IACpB,EAAE,IAAI,EAAE,QAAQ,EAAE;IAClB,EAAE,IAAI,EAAE,OAAO,EAAE;IACjB,EAAE,IAAI,EAAE,WAAW,EAAE;CACxB,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,OAAO,eAAe;IAA5B;QACoB,UAAK,GAAG,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"RopLogonHandler.js","sourceRoot":"","sources":["../../../src/rop/RopLogonHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assignHandle } from "../MapiSessionManager.js";
|
|
1
2
|
const ROP_ID_OPEN_FOLDER = 0x02;
|
|
2
3
|
/** The well-known MAPI HRESULT `MAPI_E_NOT_FOUND`, reused as this handler's only failure `ReturnValue` (an
|
|
3
4
|
* unrecognized `FolderId` - one not present in `session.folderIds`, i.e. not something `RopLogon` handed out
|
|
@@ -19,6 +20,7 @@ const ERROR_NOT_FOUND = 0x8004010f;
|
|
|
19
20
|
export class RopOpenFolderHandler {
|
|
20
21
|
constructor() {
|
|
21
22
|
this.ropId = ROP_ID_OPEN_FOLDER;
|
|
23
|
+
this.responseHandleIndexOffset = 3; // OutputHandleIndex
|
|
22
24
|
}
|
|
23
25
|
handle(reader, writer, context) {
|
|
24
26
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
@@ -35,7 +37,7 @@ export class RopOpenFolderHandler {
|
|
|
35
37
|
writer.writeUInt32LE(ERROR_NOT_FOUND);
|
|
36
38
|
return;
|
|
37
39
|
}
|
|
38
|
-
context.session
|
|
40
|
+
assignHandle(context.session, outputHandleIndex, { type: "folder", entityUid: target });
|
|
39
41
|
writer.writeUInt8(ROP_ID_OPEN_FOLDER);
|
|
40
42
|
writer.writeUInt8(outputHandleIndex);
|
|
41
43
|
writer.writeUInt32LE(0); // ReturnValue - success
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopOpenFolderHandler.js","sourceRoot":"","sources":["../../../src/rop/RopOpenFolderHandler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"RopOpenFolderHandler.js","sourceRoot":"","sources":["../../../src/rop/RopOpenFolderHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGxD,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC;;oBAEoB;AACpB,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,oBAAoB;IAAjC;QACoB,UAAK,GAAG,kBAAkB,CAAC;QAC3B,8BAAyB,GAAG,CAAC,CAAC,CAAC,oBAAoB;IA2BvE,CAAC;IAzBU,MAAM,CAAC,MAAoB,EAAE,MAAoB,EAAE,OAAmB;QACzE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,uFAAuF;QAC3G,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,+EAA+E;QACnG,sGAAsG;QACtG,kCAAkC;QAClC,MAAM,iBAAiB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACrD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,yEAAyE;QAC7F,MAAM,QAAQ,GAAW,MAAM,CAAC,eAAe,EAAE,CAAC;QAElD,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,kBAAkB,CAAC,CAAC;YACtC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;YACtC,OAAO;QACX,CAAC;QAED,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC;QAExF,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;QACtC,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,qCAAqC;QAC3D,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,iDAAiD;IAC3E,CAAC;CACJ"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { writeTypedString } from "../codec/TypedString.js";
|
|
2
|
+
import { assignHandle } from "../MapiSessionManager.js";
|
|
2
3
|
import { resolveCalendarEventInfo } from "./CalendarEventTarget.js";
|
|
3
4
|
import { resolveContactInfo } from "./ContactTarget.js";
|
|
4
5
|
import { resolveMessageInfo } from "./MessageTarget.js";
|
|
@@ -33,6 +34,7 @@ const ERROR_NOT_FOUND = 0x8004010f;
|
|
|
33
34
|
export class RopOpenMessageHandler {
|
|
34
35
|
constructor() {
|
|
35
36
|
this.ropId = ROP_ID_OPEN_MESSAGE;
|
|
37
|
+
this.responseHandleIndexOffset = 3; // OutputHandleIndex
|
|
36
38
|
}
|
|
37
39
|
async handle(reader, writer, context) {
|
|
38
40
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
@@ -66,7 +68,7 @@ export class RopOpenMessageHandler {
|
|
|
66
68
|
else {
|
|
67
69
|
subject = (await resolveMessageInfo(target, context.messageRepo)).subject;
|
|
68
70
|
}
|
|
69
|
-
context.session
|
|
71
|
+
assignHandle(context.session, outputHandleIndex, { type: "message", entityUid: target });
|
|
70
72
|
writer.writeUInt8(ROP_ID_OPEN_MESSAGE);
|
|
71
73
|
writer.writeUInt8(outputHandleIndex);
|
|
72
74
|
writer.writeUInt32LE(0); // ReturnValue - success
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopOpenMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopOpenMessageHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;;;2CAG2C;AAC3C,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,qBAAqB;IAAlC;QACoB,UAAK,GAAG,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"RopOpenMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopOpenMessageHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { PropertyType, readPropertyTag } from "../codec/PropertyValue.js";
|
|
2
|
-
import {
|
|
2
|
+
import { assignHandle } from "../MapiSessionManager.js";
|
|
3
|
+
import { loadStreamBody, PID_TAG_BODY } from "./MessageBodyStream.js";
|
|
3
4
|
const ROP_ID_OPEN_STREAM = 0x2b;
|
|
4
5
|
/** `[MS-OXCPRPT]` §2.2.14.1 `OpenModeFlags` values - `ReadOnly` opens the existing value for reading;
|
|
5
6
|
* `ReadWrite`/`Create` both open for writing (`Create` additionally discards any existing value first, "the
|
|
@@ -34,6 +35,7 @@ const ERROR_NOT_FOUND = 0x8004010f;
|
|
|
34
35
|
export class RopOpenStreamHandler {
|
|
35
36
|
constructor() {
|
|
36
37
|
this.ropId = ROP_ID_OPEN_STREAM;
|
|
38
|
+
this.responseHandleIndexOffset = 3; // OutputHandleIndex
|
|
37
39
|
}
|
|
38
40
|
async handle(reader, writer, context) {
|
|
39
41
|
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
@@ -51,26 +53,27 @@ export class RopOpenStreamHandler {
|
|
|
51
53
|
}
|
|
52
54
|
let streamSize;
|
|
53
55
|
if (openModeFlags === OPEN_MODE_READ_ONLY) {
|
|
54
|
-
const
|
|
55
|
-
streamSize = bytes.length;
|
|
56
|
-
context.session.handles[outputHandleIndex] = {
|
|
56
|
+
const stream = assignHandle(context.session, outputHandleIndex, {
|
|
57
57
|
type: "stream",
|
|
58
58
|
entityUid: handle.entityUid,
|
|
59
59
|
propertyId: propertyTag.propertyId,
|
|
60
60
|
propertyType: propertyTag.propertyType,
|
|
61
61
|
streamPosition: 0,
|
|
62
|
-
};
|
|
62
|
+
});
|
|
63
|
+
// Parsed once here and cached per handle, not re-parsed by every RopReadStream.
|
|
64
|
+
streamSize = (await loadStreamBody(context, outputHandleIndex, stream)).length;
|
|
63
65
|
}
|
|
64
66
|
else {
|
|
65
67
|
streamSize = 0;
|
|
66
|
-
context.session
|
|
68
|
+
assignHandle(context.session, outputHandleIndex, {
|
|
67
69
|
type: "stream",
|
|
68
70
|
entityUid: handle.entityUid,
|
|
69
71
|
propertyId: propertyTag.propertyId,
|
|
70
72
|
propertyType: propertyTag.propertyType,
|
|
71
73
|
writeTargetHandleIndex: inputHandleIndex,
|
|
72
|
-
|
|
73
|
-
|
|
74
|
+
writeTargetGeneration: handle.generation,
|
|
75
|
+
writeSize: 0,
|
|
76
|
+
});
|
|
74
77
|
}
|
|
75
78
|
writer.writeUInt8(ROP_ID_OPEN_STREAM);
|
|
76
79
|
writer.writeUInt8(outputHandleIndex);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopOpenStreamHandler.js","sourceRoot":"","sources":["../../../src/rop/RopOpenStreamHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,
|
|
1
|
+
{"version":3,"file":"RopOpenStreamHandler.js","sourceRoot":"","sources":["../../../src/rop/RopOpenStreamHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAe,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAGtE,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC;;;8GAG8G;AAC9G,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;;kDAEkD;AAClD,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,OAAO,oBAAoB;IAAjC;QACoB,UAAK,GAAG,kBAAkB,CAAC;QAC3B,8BAAyB,GAAG,CAAC,CAAC,CAAC,oBAAoB;IA+CvE,CAAC;IA7CU,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,iBAAiB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACrD,MAAM,WAAW,GAAgB,eAAe,CAAC,MAAM,CAAC,CAAC;QACzD,MAAM,aAAa,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QAEjD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzD,MAAM,mBAAmB,GAAG,WAAW,CAAC,UAAU,KAAK,YAAY,IAAI,WAAW,CAAC,YAAY,KAAK,YAAY,CAAC,UAAU,CAAC;QAC5H,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC/D,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;YACtC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;YACtC,OAAO;QACX,CAAC;QAED,IAAI,UAAkB,CAAC;QACvB,IAAI,aAAa,KAAK,mBAAmB,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE;gBAC5D,IAAI,EAAE,QAAQ;gBACd,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,UAAU,EAAE,WAAW,CAAC,UAAU;gBAClC,YAAY,EAAE,WAAW,CAAC,YAAY;gBACtC,cAAc,EAAE,CAAC;aACpB,CAAC,CAAC;YACH,gFAAgF;YAChF,UAAU,GAAG,CAAC,MAAM,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;QACnF,CAAC;aAAM,CAAC;YACJ,UAAU,GAAG,CAAC,CAAC;YACf,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE;gBAC7C,IAAI,EAAE,QAAQ;gBACd,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,UAAU,EAAE,WAAW,CAAC,UAAU;gBAClC,YAAY,EAAE,WAAW,CAAC,YAAY;gBACtC,sBAAsB,EAAE,gBAAgB;gBACxC,qBAAqB,EAAE,MAAM,CAAC,UAAU;gBACxC,SAAS,EAAE,CAAC;aACf,CAAC,CAAC;QACP,CAAC;QAED,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC;QACtC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,aAAa;IACnD,CAAC;CACJ"}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
///////////////////////////////////////////////////////////////////////////////
|
|
5
5
|
import { BufferWriter } from "../codec/BufferCursor.js";
|
|
6
6
|
import { writePropertyValue } from "../codec/PropertyValue.js";
|
|
7
|
+
import { resolveContentsWindow } from "./ContentsTable.js";
|
|
7
8
|
import { resolvePropertyValues } from "./PropertyResolvers.js";
|
|
8
9
|
const ROP_ID_QUERY_ROWS = 0x15;
|
|
9
10
|
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a table (or
|
|
@@ -12,6 +13,13 @@ const ERROR_INVALID_OBJECT = 0x80070005;
|
|
|
12
13
|
/** `BOOKMARK_END` (`[MS-OXCTABL]`'s `Origin` field) - this pragmatic subset has no separate seek/bookmark ROP
|
|
13
14
|
* support, so every response reports the cursor as having landed at the table's current end. */
|
|
14
15
|
const ORIGIN_BOOKMARK_END = 0x02;
|
|
16
|
+
/** The most rows one `RopQueryRows` returns. Fewer rows than requested is normal table paging: the client asks
|
|
17
|
+
* again from the new cursor position. */
|
|
18
|
+
export const MAX_ROWS_PER_QUERY = 500;
|
|
19
|
+
/** `ecBufferTooSmall`: not even one row fits in the room left in the ROP output buffer. */
|
|
20
|
+
const ERROR_BUFFER_TOO_SMALL = 0x0000047d;
|
|
21
|
+
/** RopId, InputHandleIndex, ReturnValue, Origin and RowCount. */
|
|
22
|
+
const RESPONSE_HEADER_BYTES = 9;
|
|
15
23
|
/**
|
|
16
24
|
* `RopQueryRows` (`[MS-OXCTABL]`/`[MS-OXCROPS]`): fetches up to `RowCount` rows from an already-configured
|
|
17
25
|
* table (`RopGetHierarchyTable` + `RopSetColumns`), advancing the table's cursor. Confirmed field-by-field
|
|
@@ -58,24 +66,42 @@ export class RopQueryRowsHandler {
|
|
|
58
66
|
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
59
67
|
return;
|
|
60
68
|
}
|
|
61
|
-
const rows = table.rows ?? [];
|
|
62
69
|
const cursor = table.cursor ?? 0;
|
|
63
|
-
const
|
|
64
|
-
table
|
|
70
|
+
const count = Math.min(requestedCount, MAX_ROWS_PER_QUERY);
|
|
71
|
+
// A hierarchy table carries its rows; a contents table reads just this window from the database.
|
|
72
|
+
const slice = table.contentsKind
|
|
73
|
+
? await resolveContentsWindow(context, table, cursor, count)
|
|
74
|
+
: (table.rows ?? []).slice(cursor, cursor + count);
|
|
65
75
|
// Shared across every row this call resolves - see ResolutionCache's own doc comment for why: without
|
|
66
76
|
// it, a hierarchy table's `hasChildren` column (or a calendar table's organizer/attendee resolution)
|
|
67
77
|
// would re-fetch the same whole-mailbox folder list/mailbox record once per row instead of once per
|
|
68
78
|
// call.
|
|
69
79
|
const cache = {};
|
|
70
80
|
const rowBuffers = [];
|
|
81
|
+
// Only as many rows as fit in the room left in this request's ROP output buffer; the rest stay for the next
|
|
82
|
+
// call, since the cursor only advances past rows actually returned.
|
|
83
|
+
let room = (context.ropOutputRemaining ?? Infinity) - RESPONSE_HEADER_BYTES;
|
|
71
84
|
for (const target of slice) {
|
|
72
|
-
|
|
85
|
+
const row = await this.buildRow(context, target, table.columns ?? [], cache);
|
|
86
|
+
if (row.length > room) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
room -= row.length;
|
|
90
|
+
rowBuffers.push(row);
|
|
73
91
|
}
|
|
92
|
+
if (rowBuffers.length === 0 && slice.length > 0) {
|
|
93
|
+
// Not even one row fits: [MS-OXCTABL] ecBufferTooSmall, and the cursor stays put.
|
|
94
|
+
writer.writeUInt8(ROP_ID_QUERY_ROWS);
|
|
95
|
+
writer.writeUInt8(inputHandleIndex);
|
|
96
|
+
writer.writeUInt32LE(ERROR_BUFFER_TOO_SMALL);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
table.cursor = cursor + rowBuffers.length;
|
|
74
100
|
writer.writeUInt8(ROP_ID_QUERY_ROWS);
|
|
75
101
|
writer.writeUInt8(inputHandleIndex);
|
|
76
102
|
writer.writeUInt32LE(0); // ReturnValue - success
|
|
77
103
|
writer.writeUInt8(ORIGIN_BOOKMARK_END);
|
|
78
|
-
writer.writeUInt16LE(
|
|
104
|
+
writer.writeUInt16LE(rowBuffers.length);
|
|
79
105
|
for (const rowBuffer of rowBuffers) {
|
|
80
106
|
writer.writeBytes(rowBuffer);
|
|
81
107
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopQueryRowsHandler.js","sourceRoot":"","sources":["../../../src/rop/RopQueryRowsHandler.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAgB,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAmB,MAAM,wBAAwB,CAAC;AAGhF,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B;yGACyG;AACzG,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;gGACgG;AAChG,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,OAAO,mBAAmB;IAAhC;QACoB,UAAK,GAAG,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"RopQueryRowsHandler.js","sourceRoot":"","sources":["../../../src/rop/RopQueryRowsHandler.ts"],"names":[],"mappings":"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"}
|