@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,61 @@
|
|
|
1
|
+
import { readPropertyTag } from "../codec/PropertyValue.js";
|
|
2
|
+
import { buildFastTransferStream } from "./FastTransferStream.js";
|
|
3
|
+
const ROP_ID_COPY_PROPERTIES = 0x69;
|
|
4
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a folder or
|
|
5
|
+
* message (or doesn't exist)" - the same constant `RopGetPropertiesSpecificHandler` uses for its own analogous
|
|
6
|
+
* check. */
|
|
7
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
8
|
+
/**
|
|
9
|
+
* `RopFastTransferSourceCopyProperties` (`[MS-OXCFXICS]`/`[MS-OXCROPS]`, RopId `0x69`): the explicit-column
|
|
10
|
+
* sibling of `RopFastTransferSourceCopyTo` - `PropertyTags` here is the properties to **copy** (an include
|
|
11
|
+
* list, per `[MS-OXCROPS]`'s own wording, the opposite of `CopyTo`'s exclude list), applied uniformly at both
|
|
12
|
+
* folder- and message-level wherever `FastTransferStream.ts` builds a `propList` - see that file's own doc
|
|
13
|
+
* comment for this pragmatic subset's overall ICS scope. An empty `PropertyTags` list is honored literally
|
|
14
|
+
* (copies zero properties, i.e. empty `propList`s) rather than falling back to `CopyTo`'s own default column
|
|
15
|
+
* set - that fallback belongs to `CopyTo` alone, since an explicit "copy nothing" request here is spec-valid
|
|
16
|
+
* and distinguishable from "use the default set" (`CopyTo` simply has no `PropertyTags`-supplied alternative to
|
|
17
|
+
* fall back from).
|
|
18
|
+
*
|
|
19
|
+
* `Level`/`CopyFlags`/`SendOptions` are decoded to advance the reader correctly but not honored - see
|
|
20
|
+
* `RopFastTransferSourceCopyToHandler`'s own doc comment for the identical reasoning. Note `CopyFlags` here is
|
|
21
|
+
* **1 byte**, not 4 like `CopyTo`'s own field of the same name - confirmed against each ROP's own request-buffer
|
|
22
|
+
* page separately, not assumed identical.
|
|
23
|
+
*
|
|
24
|
+
* @author Jean-Philippe Steinmetz
|
|
25
|
+
*/
|
|
26
|
+
export class RopFastTransferSourceCopyPropertiesHandler {
|
|
27
|
+
constructor() {
|
|
28
|
+
this.ropId = ROP_ID_COPY_PROPERTIES;
|
|
29
|
+
}
|
|
30
|
+
async handle(reader, writer, context) {
|
|
31
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
32
|
+
const inputHandleIndex = reader.readUInt8();
|
|
33
|
+
const outputHandleIndex = reader.readUInt8();
|
|
34
|
+
reader.readUInt8(); // Level - subfolder recursion not honored, see class doc comment
|
|
35
|
+
reader.readUInt8(); // CopyFlags (1 byte here, unlike CopyTo's 4) - not honored, see class doc comment
|
|
36
|
+
reader.readUInt8(); // SendOptions - not honored, see class doc comment
|
|
37
|
+
const propertyTagCount = reader.readUInt16LE();
|
|
38
|
+
const columns = [];
|
|
39
|
+
for (let i = 0; i < propertyTagCount; i++) {
|
|
40
|
+
columns.push(readPropertyTag(reader));
|
|
41
|
+
}
|
|
42
|
+
const handle = context.session.handles[inputHandleIndex];
|
|
43
|
+
if (!handle || (handle.type !== "folder" && handle.type !== "message")) {
|
|
44
|
+
writer.writeUInt8(ROP_ID_COPY_PROPERTIES);
|
|
45
|
+
writer.writeUInt8(outputHandleIndex);
|
|
46
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const transferBuffer = await buildFastTransferStream(handle, context, { columns });
|
|
50
|
+
context.session.handles[outputHandleIndex] = {
|
|
51
|
+
type: "fastTransfer",
|
|
52
|
+
entityUid: handle.entityUid,
|
|
53
|
+
transferBufferBase64: transferBuffer.toString("base64"),
|
|
54
|
+
transferPosition: 0,
|
|
55
|
+
};
|
|
56
|
+
writer.writeUInt8(ROP_ID_COPY_PROPERTIES);
|
|
57
|
+
writer.writeUInt8(outputHandleIndex);
|
|
58
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=RopFastTransferSourceCopyPropertiesHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopFastTransferSourceCopyPropertiesHandler.js","sourceRoot":"","sources":["../../../src/rop/RopFastTransferSourceCopyPropertiesHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAoB,MAAM,2BAA2B,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAGlE,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAEpC;;YAEY;AACZ,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,0CAA0C;IAAvD;QACoB,UAAK,GAAG,sBAAsB,CAAC;IAmCnD,CAAC;IAjCU,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,iEAAiE;QACrF,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,kFAAkF;QACtG,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,mDAAmD;QACvE,MAAM,gBAAgB,GAAW,MAAM,CAAC,YAAY,EAAE,CAAC;QACvD,MAAM,OAAO,GAAkB,EAAE,CAAC;QAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,OAAO,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1C,CAAC;QAED,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,EAAE,CAAC;YACrE,MAAM,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;YAC1C,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,OAAO;QACX,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;QACnF,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG;YACzC,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,oBAAoB,EAAE,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACvD,gBAAgB,EAAE,CAAC;SACtB,CAAC;QAEF,MAAM,CAAC,UAAU,CAAC,sBAAsB,CAAC,CAAC;QAC1C,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;IACrD,CAAC;CACJ"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { readPropertyTag } from "../codec/PropertyValue.js";
|
|
2
|
+
import { buildFastTransferStream } from "./FastTransferStream.js";
|
|
3
|
+
const ROP_ID_COPY_TO = 0x4d;
|
|
4
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a folder or
|
|
5
|
+
* message (or doesn't exist)" - the same constant `RopGetPropertiesSpecificHandler` uses for its own analogous
|
|
6
|
+
* check. */
|
|
7
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
8
|
+
/**
|
|
9
|
+
* `RopFastTransferSourceCopyTo` (`[MS-OXCFXICS]`/`[MS-OXCROPS]`, RopId `0x4D`): begins a FastTransfer download
|
|
10
|
+
* of an already-open Folder or Message (or Calendar item, itself a Message object on the wire) object,
|
|
11
|
+
* producing a new `"fastTransfer"` Server object handle `RopFastTransferSourceGetBuffer` pages the built stream
|
|
12
|
+
* out of. See `FastTransferStream.ts`'s own doc comment for this pragmatic subset's "full, non-differential
|
|
13
|
+
* dump" ICS scope and its default property columns.
|
|
14
|
+
*
|
|
15
|
+
* `Level` (whether to recurse into subfolders) is decoded to advance the reader correctly but not honored -
|
|
16
|
+
* this pragmatic subset never recurses into subfolders regardless. `CopyFlags`/`SendOptions` (Move mode, best-
|
|
17
|
+
* body preference, Unicode preference, recoverable-mode, ...) are likewise decoded but not honored - this
|
|
18
|
+
* pragmatic subset always copies (never moves) and always encodes the same way regardless of client
|
|
19
|
+
* preference, matching `RopGetPropertiesSpecificHandler`'s own treatment of its analogous `WantUnicode` field.
|
|
20
|
+
* `PropertyTags` is the properties to *exclude* from the default column set (`[MS-OXCROPS]`'s own wording) -
|
|
21
|
+
* see `FastTransferStream.ts` for why an explicit include list instead is `RopFastTransferSourceCopyProperties`'s
|
|
22
|
+
* own job, not this ROP's.
|
|
23
|
+
*
|
|
24
|
+
* @author Jean-Philippe Steinmetz
|
|
25
|
+
*/
|
|
26
|
+
export class RopFastTransferSourceCopyToHandler {
|
|
27
|
+
constructor() {
|
|
28
|
+
this.ropId = ROP_ID_COPY_TO;
|
|
29
|
+
}
|
|
30
|
+
async handle(reader, writer, context) {
|
|
31
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
32
|
+
const inputHandleIndex = reader.readUInt8();
|
|
33
|
+
const outputHandleIndex = reader.readUInt8();
|
|
34
|
+
reader.readUInt8(); // Level - subfolder recursion not honored, see class doc comment
|
|
35
|
+
reader.readUInt32LE(); // CopyFlags - not honored, see class doc comment
|
|
36
|
+
reader.readUInt8(); // SendOptions - not honored, see class doc comment
|
|
37
|
+
const propertyTagCount = reader.readUInt16LE();
|
|
38
|
+
const excludePropertyIds = new Set();
|
|
39
|
+
for (let i = 0; i < propertyTagCount; i++) {
|
|
40
|
+
excludePropertyIds.add(readPropertyTag(reader).propertyId);
|
|
41
|
+
}
|
|
42
|
+
const handle = context.session.handles[inputHandleIndex];
|
|
43
|
+
if (!handle || (handle.type !== "folder" && handle.type !== "message")) {
|
|
44
|
+
writer.writeUInt8(ROP_ID_COPY_TO);
|
|
45
|
+
writer.writeUInt8(outputHandleIndex);
|
|
46
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const transferBuffer = await buildFastTransferStream(handle, context, { excludePropertyIds });
|
|
50
|
+
context.session.handles[outputHandleIndex] = {
|
|
51
|
+
type: "fastTransfer",
|
|
52
|
+
entityUid: handle.entityUid,
|
|
53
|
+
transferBufferBase64: transferBuffer.toString("base64"),
|
|
54
|
+
transferPosition: 0,
|
|
55
|
+
};
|
|
56
|
+
writer.writeUInt8(ROP_ID_COPY_TO);
|
|
57
|
+
writer.writeUInt8(outputHandleIndex);
|
|
58
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=RopFastTransferSourceCopyToHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopFastTransferSourceCopyToHandler.js","sourceRoot":"","sources":["../../../src/rop/RopFastTransferSourceCopyToHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAGlE,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B;;YAEY;AACZ,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,kCAAkC;IAA/C;QACoB,UAAK,GAAG,cAAc,CAAC;IAmC3C,CAAC;IAjCU,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,iEAAiE;QACrF,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,iDAAiD;QACxE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,mDAAmD;QACvE,MAAM,gBAAgB,GAAW,MAAM,CAAC,YAAY,EAAE,CAAC;QACvD,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAU,CAAC;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,kBAAkB,CAAC,GAAG,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC;QAC/D,CAAC;QAED,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,EAAE,CAAC;YACrE,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAClC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,OAAO;QACX,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,uBAAuB,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC9F,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG;YACzC,IAAI,EAAE,cAAc;YACpB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,oBAAoB,EAAE,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACvD,gBAAgB,EAAE,CAAC;SACtB,CAAC;QAEF,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAClC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;IACrD,CAAC;CACJ"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
const ROP_ID_GET_BUFFER = 0x4e;
|
|
2
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a
|
|
3
|
+
* `fastTransfer` handle (or doesn't exist)" - the same constant `RopGetPropertiesSpecificHandler` uses for its
|
|
4
|
+
* own analogous check. */
|
|
5
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
6
|
+
/** The `BufferSize` sentinel (`[MS-OXCROPS]`'s own documented value) meaning "let the server pick the chunk
|
|
7
|
+
* size". */
|
|
8
|
+
const BUFFER_SIZE_SERVER_DETERMINED = 0xbabe;
|
|
9
|
+
/** The response's own `TransferBufferSize` field is a 16-bit count (`[MS-OXCFXICS]`'s own `RopFastTransferSourceGetBuffer`
|
|
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. */
|
|
15
|
+
const MAX_TRANSFER_BUFFER_SIZE = 0xffff;
|
|
16
|
+
/** `TransferStatus` values (`[MS-OXCFXICS]` §2.2.3.1.1.5.2, confirmed this session) - only the two this
|
|
17
|
+
* pragmatic subset (which never errors mid-transfer once a `"fastTransfer"` handle exists, and never returns
|
|
18
|
+
* `NoRoom`) ever produces. */
|
|
19
|
+
const TRANSFER_STATUS_PARTIAL = 0x0001;
|
|
20
|
+
const TRANSFER_STATUS_DONE = 0x0003;
|
|
21
|
+
/**
|
|
22
|
+
* `RopFastTransferSourceGetBuffer` (`[MS-OXCFXICS]`/`[MS-OXCROPS]`, RopId `0x4E`): pages the FastTransfer
|
|
23
|
+
* stream a prior `RopFastTransferSourceCopyTo`/`CopyProperties` built (`FastTransferStream.ts`) out of its
|
|
24
|
+
* `"fastTransfer"` handle, `BufferSize` bytes at a time (or the entire remaining buffer, capped to
|
|
25
|
+
* `MAX_TRANSFER_BUFFER_SIZE`, for the `0xBABE` "server-determined" sentinel - `MaximumBufferSize`, present only
|
|
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).
|
|
30
|
+
*
|
|
31
|
+
* `BackoffTime` is never emitted (this pragmatic subset never returns the one `ReturnValue` that field is
|
|
32
|
+
* conditional on), and the failure path (`ERROR_INVALID_OBJECT`) omits every field after `ReturnValue` entirely
|
|
33
|
+
* - the same "just the fixed header, no success-only tail" shape every other failing handler in this pragmatic
|
|
34
|
+
* subset already uses, not a specific claim about the real spec's own error-path byte layout.
|
|
35
|
+
*
|
|
36
|
+
* @author Jean-Philippe Steinmetz
|
|
37
|
+
*/
|
|
38
|
+
export class RopFastTransferSourceGetBufferHandler {
|
|
39
|
+
constructor() {
|
|
40
|
+
this.ropId = ROP_ID_GET_BUFFER;
|
|
41
|
+
}
|
|
42
|
+
handle(reader, writer, context) {
|
|
43
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
44
|
+
const inputHandleIndex = reader.readUInt8();
|
|
45
|
+
const bufferSize = reader.readUInt16LE();
|
|
46
|
+
if (bufferSize === BUFFER_SIZE_SERVER_DETERMINED) {
|
|
47
|
+
reader.readUInt16LE(); // MaximumBufferSize - see class doc comment
|
|
48
|
+
}
|
|
49
|
+
const handle = context.session.handles[inputHandleIndex];
|
|
50
|
+
if (!handle || handle.type !== "fastTransfer") {
|
|
51
|
+
writer.writeUInt8(ROP_ID_GET_BUFFER);
|
|
52
|
+
writer.writeUInt8(inputHandleIndex);
|
|
53
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const fullBuffer = Buffer.from(handle.transferBufferBase64 ?? "", "base64");
|
|
57
|
+
const position = handle.transferPosition ?? 0;
|
|
58
|
+
const remaining = fullBuffer.length - position;
|
|
59
|
+
const requestedSize = bufferSize === BUFFER_SIZE_SERVER_DETERMINED ? remaining : bufferSize;
|
|
60
|
+
const chunkSize = Math.min(requestedSize, remaining, MAX_TRANSFER_BUFFER_SIZE);
|
|
61
|
+
const chunk = fullBuffer.subarray(position, position + chunkSize);
|
|
62
|
+
handle.transferPosition = position + chunk.length;
|
|
63
|
+
const done = handle.transferPosition >= fullBuffer.length;
|
|
64
|
+
writer.writeUInt8(ROP_ID_GET_BUFFER);
|
|
65
|
+
writer.writeUInt8(inputHandleIndex);
|
|
66
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
67
|
+
writer.writeUInt16LE(done ? TRANSFER_STATUS_DONE : TRANSFER_STATUS_PARTIAL);
|
|
68
|
+
writer.writeUInt16LE(0); // InProgressCount - no real progress tracking in this pragmatic subset
|
|
69
|
+
writer.writeUInt16LE(1); // TotalStepCount - pragmatic constant, only ever used for progress-bar display
|
|
70
|
+
writer.writeUInt8(0); // Reserved
|
|
71
|
+
writer.writeUInt16LE(chunk.length); // TransferBufferSize
|
|
72
|
+
writer.writeBytes(chunk); // TransferBuffer
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=RopFastTransferSourceGetBufferHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopFastTransferSourceGetBufferHandler.js","sourceRoot":"","sources":["../../../src/rop/RopFastTransferSourceGetBufferHandler.ts"],"names":[],"mappings":"AAOA,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAE/B;;0BAE0B;AAC1B,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;YACY;AACZ,MAAM,6BAA6B,GAAG,MAAM,CAAC;AAE7C;;;;;iDAKiD;AACjD,MAAM,wBAAwB,GAAG,MAAM,CAAC;AAExC;;8BAE8B;AAC9B,MAAM,uBAAuB,GAAG,MAAM,CAAC;AACvC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAEpC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,qCAAqC;IAAlD;QACoB,UAAK,GAAG,iBAAiB,CAAC;IAqC9C,CAAC;IAnCU,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,UAAU,GAAW,MAAM,CAAC,YAAY,EAAE,CAAC;QACjD,IAAI,UAAU,KAAK,6BAA6B,EAAE,CAAC;YAC/C,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,4CAA4C;QACvE,CAAC;QAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5C,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,OAAO;QACX,CAAC;QAED,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC5E,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,IAAI,CAAC,CAAC;QAC9C,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,GAAG,QAAQ,CAAC;QAC/C,MAAM,aAAa,GAAG,UAAU,KAAK,6BAA6B,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,UAAU,CAAC;QAC5F,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,SAAS,EAAE,wBAAwB,CAAC,CAAC;QAC/E,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,SAAS,CAAC,CAAC;QAClE,MAAM,CAAC,gBAAgB,GAAG,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,CAAC,gBAAgB,IAAI,UAAU,CAAC,MAAM,CAAC;QAE1D,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,uBAAuB,CAAC,CAAC;QAC5E,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,uEAAuE;QAChG,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,+EAA+E;QACxG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW;QACjC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,qBAAqB;QACzD,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,iBAAiB;IAC/C,CAAC;CACJ"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
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";
|
|
10
|
+
const ROP_ID_GET_CONTENTS_TABLE = 0x05;
|
|
11
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a folder (or
|
|
12
|
+
* doesn't exist)" - the same constant `RopGetHierarchyTableHandler` uses for its own analogous check. */
|
|
13
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
14
|
+
/**
|
|
15
|
+
* `RopGetContentsTable` (`[MS-OXCFOLD]`/`[MS-OXCROPS]`): opens a table listing an already-opened folder's
|
|
16
|
+
* messages, producing a new `"table"` Server object handle `RopSetColumns`/`RopQueryRows` reference by
|
|
17
|
+
* `InputHandleIndex` - the exact same request/response shape as `RopGetHierarchyTable` (confirmed identical
|
|
18
|
+
* field-by-field against `[MS-OXCROPS]`'s own request-buffer page, differing only in `RopId`), just listing
|
|
19
|
+
* messages instead of child folders. `RopSetColumns`/`RopQueryRows` themselves need no changes at all to
|
|
20
|
+
* support this - they already operate generically on whatever `rows`/`columns` a table handle carries,
|
|
21
|
+
* dispatching to `FolderTarget`'s or `MessageTarget`'s resolvers by row-target prefix (`"folder:"`/`"virtual:"`
|
|
22
|
+
* vs `"message:"`).
|
|
23
|
+
*
|
|
24
|
+
* A folder's contents table is only ever non-empty for a real folder (`"folder:<uid>"`) - the virtual special
|
|
25
|
+
* folders (`RopLogonHandler`'s own doc comment) have no real backing row to hold messages under, so opening a
|
|
26
|
+
* contents table on one always yields an empty table rather than an error.
|
|
27
|
+
*
|
|
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
|
+
* @author Jean-Philippe Steinmetz
|
|
37
|
+
*/
|
|
38
|
+
export class RopGetContentsTableHandler {
|
|
39
|
+
constructor() {
|
|
40
|
+
this.ropId = ROP_ID_GET_CONTENTS_TABLE;
|
|
41
|
+
}
|
|
42
|
+
async handle(reader, writer, context) {
|
|
43
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
44
|
+
const inputHandleIndex = reader.readUInt8();
|
|
45
|
+
const outputHandleIndex = reader.readUInt8();
|
|
46
|
+
reader.readUInt8(); // TableFlags - only the Standard (0x00) case is supported; see RopGetHierarchyTableHandler's own doc comment
|
|
47
|
+
const folderHandle = context.session.handles[inputHandleIndex];
|
|
48
|
+
if (!folderHandle || folderHandle.type !== "folder") {
|
|
49
|
+
writer.writeUInt8(ROP_ID_GET_CONTENTS_TABLE);
|
|
50
|
+
writer.writeUInt8(outputHandleIndex);
|
|
51
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const rows = folderHandle.entityUid.startsWith("folder:")
|
|
55
|
+
? await this.resolveRows(folderHandle.entityUid.slice("folder:".length), context)
|
|
56
|
+
: [];
|
|
57
|
+
context.session.handles[outputHandleIndex] = { type: "table", entityUid: folderHandle.entityUid, rows, cursor: 0 };
|
|
58
|
+
writer.writeUInt8(ROP_ID_GET_CONTENTS_TABLE);
|
|
59
|
+
writer.writeUInt8(outputHandleIndex);
|
|
60
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
61
|
+
}
|
|
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
|
+
}
|
|
76
|
+
//# sourceMappingURL=RopGetContentsTableHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopGetContentsTableHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetContentsTableHandler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { resolveFolderChildren } from "./FolderTarget.js";
|
|
2
|
+
const ROP_ID_GET_HIERARCHY_TABLE = 0x04;
|
|
3
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a folder
|
|
4
|
+
* (or doesn't exist)". */
|
|
5
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
6
|
+
/**
|
|
7
|
+
* `RopGetHierarchyTable` (`[MS-OXCFOLD]`/`[MS-OXCROPS]`): opens a table listing an already-opened folder's
|
|
8
|
+
* direct child folders, producing a new `"table"` Server object handle `RopSetColumns`/`RopQueryRows`
|
|
9
|
+
* reference by `InputHandleIndex`. Only `TableFlags = 0x00` ("Standard") is supported - this pragmatic subset
|
|
10
|
+
* has no deferred/async table population, so the immediate-row-count-returning variants some `TableFlags`
|
|
11
|
+
* values request are moot, and the response omits the row-count field those variants add (confirmed absent
|
|
12
|
+
* for the Standard case against `[MS-OXCROPS]`'s own request-buffer page, which explicitly lists `TableFlags`
|
|
13
|
+
* as this ROP's only request payload beyond the common handle-index header).
|
|
14
|
+
*
|
|
15
|
+
* @author Jean-Philippe Steinmetz
|
|
16
|
+
*/
|
|
17
|
+
export class RopGetHierarchyTableHandler {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.ropId = ROP_ID_GET_HIERARCHY_TABLE;
|
|
20
|
+
}
|
|
21
|
+
async handle(reader, writer, context) {
|
|
22
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
23
|
+
const inputHandleIndex = reader.readUInt8();
|
|
24
|
+
const outputHandleIndex = reader.readUInt8();
|
|
25
|
+
reader.readUInt8(); // TableFlags - only the Standard (0x00) case is supported; see class doc comment
|
|
26
|
+
const folderHandle = context.session.handles[inputHandleIndex];
|
|
27
|
+
if (!folderHandle || folderHandle.type !== "folder") {
|
|
28
|
+
writer.writeUInt8(ROP_ID_GET_HIERARCHY_TABLE);
|
|
29
|
+
writer.writeUInt8(outputHandleIndex);
|
|
30
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const rows = await resolveFolderChildren(context.mailboxUid, folderHandle.entityUid, context.folderRepo);
|
|
34
|
+
context.session.handles[outputHandleIndex] = { type: "table", entityUid: folderHandle.entityUid, rows, cursor: 0 };
|
|
35
|
+
writer.writeUInt8(ROP_ID_GET_HIERARCHY_TABLE);
|
|
36
|
+
writer.writeUInt8(outputHandleIndex);
|
|
37
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=RopGetHierarchyTableHandler.js.map
|
|
@@ -0,0 +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;IAuBvD,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,CAAC,CAAC;QACnH,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QAEnH,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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readPropertyTag, writePropertyValue } from "../codec/PropertyValue.js";
|
|
2
|
+
import { resolvePropertyValues } from "./PropertyResolvers.js";
|
|
3
|
+
const ROP_ID_GET_PROPERTIES_SPECIFIC = 0x07;
|
|
4
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a
|
|
5
|
+
* folder/message (or doesn't exist)" - the same constant `RopGetHierarchyTableHandler`/`RopGetContentsTableHandler`
|
|
6
|
+
* use for their own analogous checks. Attachment/Logon objects (also spec-valid targets for this ROP) aren't
|
|
7
|
+
* supported in this pragmatic subset. */
|
|
8
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
9
|
+
/**
|
|
10
|
+
* `RopGetPropertiesSpecific` (`[MS-OXCPRPT]`/`[MS-OXCROPS]`): fetches named property values for a single
|
|
11
|
+
* already-opened Folder or Message object (`RopOpenFolder`/`RopOpenMessage`), by an explicit `PropertyTags`
|
|
12
|
+
* list - the single-object analog of `RopQueryRows`' per-row column fetch, reusing the exact same
|
|
13
|
+
* `PropertyResolvers` value-resolution logic (a folder/message handle's `entityUid` is already the same
|
|
14
|
+
* `"folder:"`/`"virtual:"`/`"message:"` target-string format a table row uses). Like `RopQueryRows`, this
|
|
15
|
+
* pragmatic subset always emits a `StandardPropertyRow` (`Flags = 0x00`, confirmed as the response's `RowData`
|
|
16
|
+
* format via `[MS-OXCROPS]`'s own "Success Response Buffer" page, which names `[MS-OXCDATA]` §2.8's
|
|
17
|
+
* `PropertyRow` structure directly) - an unsupported property falls back to a type-appropriate default rather
|
|
18
|
+
* than a `FlaggedPropertyRow`'s per-column error signaling, exactly as `RopQueryRows` already does.
|
|
19
|
+
*
|
|
20
|
+
* `PropertySizeLimit`/`WantUnicode` are decoded (to advance the reader correctly) but not honored - this
|
|
21
|
+
* pragmatic subset never truncates a property value and always encodes strings the same way regardless of the
|
|
22
|
+
* client's Unicode preference (see `PropertyValue.ts`'s own string-encoding doc comments).
|
|
23
|
+
*
|
|
24
|
+
* @author Jean-Philippe Steinmetz
|
|
25
|
+
*/
|
|
26
|
+
export class RopGetPropertiesSpecificHandler {
|
|
27
|
+
constructor() {
|
|
28
|
+
this.ropId = ROP_ID_GET_PROPERTIES_SPECIFIC;
|
|
29
|
+
}
|
|
30
|
+
async handle(reader, writer, context) {
|
|
31
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
32
|
+
const inputHandleIndex = reader.readUInt8();
|
|
33
|
+
reader.readUInt16LE(); // PropertySizeLimit - no truncation support in this pragmatic subset
|
|
34
|
+
reader.readUInt16LE(); // WantUnicode - this pragmatic subset always encodes strings the same way regardless
|
|
35
|
+
const propertyTagCount = reader.readUInt16LE();
|
|
36
|
+
const propertyTags = [];
|
|
37
|
+
for (let i = 0; i < propertyTagCount; i++) {
|
|
38
|
+
propertyTags.push(readPropertyTag(reader));
|
|
39
|
+
}
|
|
40
|
+
const handle = context.session.handles[inputHandleIndex];
|
|
41
|
+
if (!handle || (handle.type !== "folder" && handle.type !== "message")) {
|
|
42
|
+
writer.writeUInt8(ROP_ID_GET_PROPERTIES_SPECIFIC);
|
|
43
|
+
writer.writeUInt8(inputHandleIndex);
|
|
44
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const values = await resolvePropertyValues(handle.entityUid, propertyTags, context);
|
|
48
|
+
writer.writeUInt8(ROP_ID_GET_PROPERTIES_SPECIFIC);
|
|
49
|
+
writer.writeUInt8(inputHandleIndex);
|
|
50
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
51
|
+
writer.writeUInt8(0x00); // PropertyRow Flags - StandardPropertyRow, see class doc comment
|
|
52
|
+
propertyTags.forEach((tag, index) => writePropertyValue(writer, tag.propertyType, values[index]));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=RopGetPropertiesSpecificHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopGetPropertiesSpecificHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetPropertiesSpecificHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAG/D,MAAM,8BAA8B,GAAG,IAAI,CAAC;AAE5C;;;yCAGyC;AACzC,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,+BAA+B;IAA5C;QACoB,UAAK,GAAG,8BAA8B,CAAC;IA6B3D,CAAC;IA3BU,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,gBAAgB,GAAW,MAAM,CAAC,YAAY,EAAE,CAAC;QACvD,MAAM,YAAY,GAAmD,EAAE,CAAC;QACxE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,gBAAgB,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,YAAY,CAAC,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,CAAC;QAED,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,EAAE,CAAC;YACrE,MAAM,CAAC,UAAU,CAAC,8BAA8B,CAAC,CAAC;YAClD,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { decodeGuid } from "../codec/MapiGuid.js";
|
|
2
|
+
import { assignOrGetNamedPropertyId } from "./NamedPropertyRegistry.js";
|
|
3
|
+
const ROP_ID_GET_PROPERTY_IDS_FROM_NAMES = 0x56;
|
|
4
|
+
/** `PropertyName.Kind` (`[MS-OXCDATA]` §2.6.1) values. */
|
|
5
|
+
const KIND_LID = 0x00;
|
|
6
|
+
const KIND_NAME = 0x01;
|
|
7
|
+
// KIND_NONE = 0xFF ("the property does not have an associated PropertyName field") is a real, spec-defined
|
|
8
|
+
// value but never resolvable to a real named property - handled by readPropertyName()'s default/`undefined`
|
|
9
|
+
// return rather than its own named constant.
|
|
10
|
+
/** The trailing UTF-16LE null-terminator code unit `PropertyName.Name` (Kind=0x01) is documented to always
|
|
11
|
+
* carry - stripped by `charCodeAt`/numeric comparison rather than a string literal containing the null
|
|
12
|
+
* character itself, to avoid embedding a raw control character in source text. */
|
|
13
|
+
const NULL_CODE_UNIT = 0;
|
|
14
|
+
/** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle doesn't exist" - the
|
|
15
|
+
* same constant `RopGetPropertiesSpecificHandler` uses for its own analogous check. Real Exchange resolves
|
|
16
|
+
* named properties per-logon regardless of which specific object handle a client happens to call this ROP
|
|
17
|
+
* against (Store/Folder/Message all share one mailbox-wide mapping table) - this pragmatic subset only
|
|
18
|
+
* requires *some* real handle to exist, not a particular type, matching that "any object will do" semantics. */
|
|
19
|
+
const ERROR_INVALID_OBJECT = 0x80070005;
|
|
20
|
+
/** Decodes one `PropertyName` structure (`[MS-OXCDATA]` §2.6.1, confirmed field order this session: `Kind`
|
|
21
|
+
* **then** `GUID` - not the reverse). Returns `undefined` for `Kind = 0xFF` ("no associated PropertyName"),
|
|
22
|
+
* which cannot resolve to any real named property. */
|
|
23
|
+
function readPropertyName(reader) {
|
|
24
|
+
const kind = reader.readUInt8();
|
|
25
|
+
const guid = decodeGuid(reader);
|
|
26
|
+
if (kind === KIND_LID) {
|
|
27
|
+
return { guid, kind: "lid", lid: reader.readUInt32LE() };
|
|
28
|
+
}
|
|
29
|
+
if (kind === KIND_NAME) {
|
|
30
|
+
const nameSize = reader.readUInt8();
|
|
31
|
+
const nameBytes = reader.readBytes(nameSize);
|
|
32
|
+
// The spec text describing NameSize ("the number of bytes in the Name string that follows it") doesn't
|
|
33
|
+
// unambiguously say whether that count includes the field's own trailing 2-zero-byte terminator - this
|
|
34
|
+
// pragmatic subset treats it as inclusive (the common real-world convention for this style of
|
|
35
|
+
// length-prefixed MAPI string) and strips one trailing null code unit if present. Never exercised by
|
|
36
|
+
// this pragmatic subset's own Calendar property table (every property it needs is Kind=LID), so this
|
|
37
|
+
// is defensive completeness for an arbitrary client request, not a property on the critical path.
|
|
38
|
+
let name = nameBytes.toString("utf16le");
|
|
39
|
+
if (name.length > 0 && name.charCodeAt(name.length - 1) === NULL_CODE_UNIT) {
|
|
40
|
+
name = name.slice(0, -1);
|
|
41
|
+
}
|
|
42
|
+
return { guid, kind: "name", name };
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* `RopGetPropertyIdsFromNames` (`[MS-OXCPRPT]`/`[MS-OXCROPS]` §2.2.8.1): resolves a list of named properties
|
|
48
|
+
* (`PropertyName` structures - a property-set `GUID` plus a numeric `LID` or string `Name`) into numeric
|
|
49
|
+
* property IDs a subsequent `RopSetProperties`/`RopGetPropertiesSpecific`/`RopQueryRows` call can use directly.
|
|
50
|
+
* This is the mechanism almost every Calendar-specific property (`PidLidAppointmentStartWhole`,
|
|
51
|
+
* `PidLidBusyStatus`, `PidLidAppointmentRecur`, ...) requires, since none of them have a fixed numeric
|
|
52
|
+
* `PidTag*`-style ID the way `PidTagSubject` does - see `NamedPropertyRegistry.ts`'s own doc comment for the
|
|
53
|
+
* session-scoped registry this delegates to.
|
|
54
|
+
*
|
|
55
|
+
* An unresolvable `PropertyName` (`Kind = 0xFF`) maps to `0x0000` in the response, per spec - this pragmatic
|
|
56
|
+
* subset has no other unmappable case (no permission/quota/hard-limit checks), so every `Kind = 0x00`/`0x01`
|
|
57
|
+
* entry always succeeds. `Flags` is decoded to advance past it correctly but not honored - see
|
|
58
|
+
* `assignOrGetNamedPropertyId`'s own doc comment for why "probe" and "assign" collapse to the same behavior
|
|
59
|
+
* for a purely session-scoped registry.
|
|
60
|
+
*
|
|
61
|
+
* @author Jean-Philippe Steinmetz
|
|
62
|
+
*/
|
|
63
|
+
export class RopGetPropertyIdsFromNamesHandler {
|
|
64
|
+
constructor() {
|
|
65
|
+
this.ropId = ROP_ID_GET_PROPERTY_IDS_FROM_NAMES;
|
|
66
|
+
}
|
|
67
|
+
handle(reader, writer, context) {
|
|
68
|
+
reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
|
|
69
|
+
const inputHandleIndex = reader.readUInt8();
|
|
70
|
+
reader.readUInt8(); // Flags - see class doc comment
|
|
71
|
+
const propertyNameCount = reader.readUInt16LE();
|
|
72
|
+
const propertyNames = [];
|
|
73
|
+
for (let i = 0; i < propertyNameCount; i++) {
|
|
74
|
+
propertyNames.push(readPropertyName(reader));
|
|
75
|
+
}
|
|
76
|
+
if (!context.session.handles[inputHandleIndex]) {
|
|
77
|
+
writer.writeUInt8(ROP_ID_GET_PROPERTY_IDS_FROM_NAMES);
|
|
78
|
+
writer.writeUInt8(inputHandleIndex);
|
|
79
|
+
writer.writeUInt32LE(ERROR_INVALID_OBJECT);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const propertyIds = propertyNames.map((name) => (name ? assignOrGetNamedPropertyId(context.session, name) : 0x0000));
|
|
83
|
+
writer.writeUInt8(ROP_ID_GET_PROPERTY_IDS_FROM_NAMES);
|
|
84
|
+
writer.writeUInt8(inputHandleIndex);
|
|
85
|
+
writer.writeUInt32LE(0); // ReturnValue - success
|
|
86
|
+
writer.writeUInt16LE(propertyIds.length);
|
|
87
|
+
for (const id of propertyIds) {
|
|
88
|
+
writer.writeUInt16LE(id);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=RopGetPropertyIdsFromNamesHandler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopGetPropertyIdsFromNamesHandler.js","sourceRoot":"","sources":["../../../src/rop/RopGetPropertyIdsFromNamesHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,0BAA0B,EAAqB,MAAM,4BAA4B,CAAC;AAG3F,MAAM,kCAAkC,GAAG,IAAI,CAAC;AAEhD,0DAA0D;AAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC;AACtB,MAAM,SAAS,GAAG,IAAI,CAAC;AACvB,2GAA2G;AAC3G,4GAA4G;AAC5G,6CAA6C;AAE7C;;kFAEkF;AAClF,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB;;;;gHAIgH;AAChH,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;sDAEsD;AACtD,SAAS,gBAAgB,CAAC,MAAoB;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IAChC,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACpB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC;IAC7D,CAAC;IACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC7C,uGAAuG;QACvG,uGAAuG;QACvG,8FAA8F;QAC9F,qGAAqG;QACrG,qGAAqG;QACrG,kGAAkG;QAClG,IAAI,IAAI,GAAG,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACzC,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,cAAc,EAAE,CAAC;YACzE,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,SAAS,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,iCAAiC;IAA9C;QACoB,UAAK,GAAG,kCAAkC,CAAC;IA6B/D,CAAC;IA3BU,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,gCAAgC;QACpD,MAAM,iBAAiB,GAAW,MAAM,CAAC,YAAY,EAAE,CAAC;QACxD,MAAM,aAAa,GAAiC,EAAE,CAAC;QACvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAC,EAAE,EAAE,CAAC;YACzC,aAAa,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;QACjD,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC7C,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC;YACtD,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,OAAO;QACX,CAAC;QAED,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,0BAA0B,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAErH,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC;QACtD,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,aAAa,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;QACzC,KAAK,MAAM,EAAE,IAAI,WAAW,EAAE,CAAC;YAC3B,MAAM,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QAC7B,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopHandler.js","sourceRoot":"","sources":["../../../src/rop/RopHandler.ts"],"names":[],"mappings":""}
|