@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 @@
|
|
|
1
|
+
{"version":3,"file":"GlobalObjectId.js","sourceRoot":"","sources":["../../../src/codec/GlobalObjectId.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { BufferWriter } from "./BufferCursor.js";
|
|
6
|
+
/**
|
|
7
|
+
* Encodes/decodes the 16-byte binary GUID layout `[MS-DTYP]`'s `GUID` structure defines and every MAPI wire
|
|
8
|
+
* structure that embeds a GUID (EntryIDs, `PidTagStoreRecordKey`, `PtypGuid` property values, property set
|
|
9
|
+
* IDs) uses: `Data1`/`Data2`/`Data3` in little-endian order, followed by `Data4`'s 8 bytes unchanged (the same
|
|
10
|
+
* order they appear in a standard textual GUID's last two hyphen-separated groups). This is distinct from a
|
|
11
|
+
* plain RFC 4122 UUID's all-big-endian textual byte order, so a generic UUID library's byte form can't be
|
|
12
|
+
* reused directly - hand-built here, same "no library, build the wire format precisely" precedent as the
|
|
13
|
+
* WBXML codec and the Autodiscover XML helpers.
|
|
14
|
+
*
|
|
15
|
+
* @author Jean-Philippe Steinmetz
|
|
16
|
+
*/
|
|
17
|
+
const GUID_STRING_PATTERN = /^([0-9a-f]{8})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{4})-([0-9a-f]{12})$/i;
|
|
18
|
+
/** Encodes a standard hyphenated GUID/UUID string into its 16-byte MS wire form. */
|
|
19
|
+
export function encodeGuid(guid) {
|
|
20
|
+
const match = GUID_STRING_PATTERN.exec(guid);
|
|
21
|
+
if (!match) {
|
|
22
|
+
throw new Error(`Invalid GUID string: ${guid}`);
|
|
23
|
+
}
|
|
24
|
+
const [, data1, data2, data3, data4a, data4b] = match;
|
|
25
|
+
const writer = new BufferWriter();
|
|
26
|
+
writer.writeUInt32LE(parseInt(data1, 16));
|
|
27
|
+
writer.writeUInt16LE(parseInt(data2, 16));
|
|
28
|
+
writer.writeUInt16LE(parseInt(data3, 16));
|
|
29
|
+
writer.writeBytes(Buffer.from(data4a + data4b, "hex"));
|
|
30
|
+
return writer.toBuffer();
|
|
31
|
+
}
|
|
32
|
+
/** Decodes a 16-byte MS wire-form GUID (read from `reader`'s current position) into a standard hyphenated
|
|
33
|
+
* GUID/UUID string. */
|
|
34
|
+
export function decodeGuid(reader) {
|
|
35
|
+
const data1 = reader.readUInt32LE().toString(16).padStart(8, "0");
|
|
36
|
+
const data2 = reader.readUInt16LE().toString(16).padStart(4, "0");
|
|
37
|
+
const data3 = reader.readUInt16LE().toString(16).padStart(4, "0");
|
|
38
|
+
const data4 = reader.readBytes(8).toString("hex");
|
|
39
|
+
return `${data1}-${data2}-${data3}-${data4.slice(0, 4)}-${data4.slice(4)}`;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=MapiGuid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapiGuid.js","sourceRoot":"","sources":["../../../src/codec/MapiGuid.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAgB,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,MAAM,mBAAmB,GAAG,2EAA2E,CAAC;AAExG,oFAAoF;AACpF,MAAM,UAAU,UAAU,CAAC,IAAY;IACnC,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,wBAAwB,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;IAEtD,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;IAC1C,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACvD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED;uBACuB;AACvB,MAAM,UAAU,UAAU,CAAC,MAAoB;IAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClE,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,OAAO,GAAG,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { BufferWriter } from "./BufferCursor.js";
|
|
6
|
+
/**
|
|
7
|
+
* Encodes/decodes `CalendarEvent.timezone` (a plain IANA zone identifier) to/from `PidLidTimeZoneStruct`'s
|
|
8
|
+
* `TimeZoneStruct` BLOB (`[MS-OXOCAL]` §2.2.1.39, confirmed field-by-field this session, including a real
|
|
9
|
+
* worked example: `lBias(4,LONG)+lStandardBias(4,LONG)+lDaylightBias(4,LONG)+wStandardYear(2,WORD)+
|
|
10
|
+
* stStandardDate(16,SYSTEMTIME)+wDaylightYear(2,WORD)+stDaylightDate(16,SYSTEMTIME)` = 48 bytes total, all
|
|
11
|
+
* little-endian. `SYSTEMTIME` (`[MS-DTYP]`) is 8 `WORD` fields (`wYear`/`wMonth`/`wDayOfWeek`/`wDay`/`wHour`/
|
|
12
|
+
* `wMinute`/`wSecond`/`wMilliseconds`), 16 bytes.
|
|
13
|
+
*
|
|
14
|
+
* This is deliberately the older, simpler `TimeZoneStruct` - not the newer `TimeZoneDefinition`/
|
|
15
|
+
* `PidLidAppointmentTimeZoneDefinitionStartDisplay`, which additionally encodes named DST transition rules.
|
|
16
|
+
*
|
|
17
|
+
* **Pragmatic scope, matching the same limits `CalendarSyncAdapter` (EAS) already carries for timezones**:
|
|
18
|
+
* - `"UTC"` encodes as an all-zero struct (no bias, no DST) - the spec-legitimate representation of "no offset,
|
|
19
|
+
* no DST".
|
|
20
|
+
* - Any other IANA zone is approximated as a **fixed-offset** zone: `lBias` is derived from that zone's actual
|
|
21
|
+
* UTC offset at the given reference instant (via `Intl`), with `lStandardBias`/`lDaylightBias` always `0` and
|
|
22
|
+
* both `SYSTEMTIME` transition dates all-zero (`wMonth=0`, the spec's own documented way to say "this zone
|
|
23
|
+
* does not observe daylight saving time"). **This is wrong across a real DST boundary** for a zone that
|
|
24
|
+
* actually observes DST - a real client will show the correct offset only for occurrences near the reference
|
|
25
|
+
* instant used at encode time, not a spec violation but a real, documented fidelity gap.
|
|
26
|
+
* - Decoding a struct back into an IANA identifier is fundamentally lossy (a bias alone doesn't identify a
|
|
27
|
+
* unique zone name) - this codec resolves it to a synthetic-but-valid `Etc/GMT±N` IANA identifier (note the
|
|
28
|
+
* IANA `Etc/GMT` area's own sign convention is POSIX-inverted from common usage: `Etc/GMT+8` means UTC-8, not
|
|
29
|
+
* UTC+8) rounded to the nearest whole hour, since `Etc/GMT` zones only support integer-hour offsets - a further
|
|
30
|
+
* documented approximation for zones with a half-hour/quarter-hour offset (e.g. India, Nepal).
|
|
31
|
+
*
|
|
32
|
+
* @author Jean-Philippe Steinmetz
|
|
33
|
+
*/
|
|
34
|
+
const SYSTEMTIME_FIELD_COUNT = 8;
|
|
35
|
+
function writeZeroTransitionBlock(writer) {
|
|
36
|
+
writer.writeUInt16LE(0); // wStandardYear / wDaylightYear
|
|
37
|
+
for (let i = 0; i < SYSTEMTIME_FIELD_COUNT; i++) {
|
|
38
|
+
writer.writeUInt16LE(0);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function skipTransitionBlock(reader) {
|
|
42
|
+
reader.readUInt16LE(); // wStandardYear / wDaylightYear
|
|
43
|
+
for (let i = 0; i < SYSTEMTIME_FIELD_COUNT; i++) {
|
|
44
|
+
reader.readUInt16LE();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** The zone's UTC offset in minutes at instant `at` (standard convention: local minus UTC, e.g. `-480` for
|
|
48
|
+
* `America/Los_Angeles` in winter), read via `Intl`'s `shortOffset` formatting rather than hand-rolling a
|
|
49
|
+
* zone database. Throws the same way `Intl.DateTimeFormat` itself does for an unrecognized zone identifier. */
|
|
50
|
+
function utcOffsetMinutes(timezone, at) {
|
|
51
|
+
const formatter = new Intl.DateTimeFormat("en-US", { timeZone: timezone, timeZoneName: "shortOffset" });
|
|
52
|
+
// `formatToParts` always includes a "timeZoneName" part when `timeZoneName` is requested in the
|
|
53
|
+
// formatter's own options, so the non-null assertion below reflects a real `Intl` guarantee, not an
|
|
54
|
+
// unverified assumption.
|
|
55
|
+
const tzName = formatter.formatToParts(at).find((part) => part.type === "timeZoneName").value;
|
|
56
|
+
const match = /^GMT([+-])(\d+)(?::(\d+))?$/.exec(tzName);
|
|
57
|
+
if (!match) {
|
|
58
|
+
return 0; // Bare "GMT", i.e. UTC itself.
|
|
59
|
+
}
|
|
60
|
+
const sign = match[1] === "-" ? -1 : 1;
|
|
61
|
+
const hours = parseInt(match[2], 10);
|
|
62
|
+
const minutes = match[3] ? parseInt(match[3], 10) : 0;
|
|
63
|
+
return sign * (hours * 60 + minutes);
|
|
64
|
+
}
|
|
65
|
+
/** Encodes `timezone` (an IANA identifier, or `"UTC"`) into a 48-byte `TimeZoneStruct` BLOB, using `at` as the
|
|
66
|
+
* reference instant for resolving a non-UTC zone's current fixed offset. */
|
|
67
|
+
export function encodeTimeZoneStruct(timezone, at) {
|
|
68
|
+
const writer = new BufferWriter();
|
|
69
|
+
const bias = timezone === "UTC" ? 0 : -utcOffsetMinutes(timezone, at);
|
|
70
|
+
writer.writeInt32LE(bias); // lBias
|
|
71
|
+
writer.writeInt32LE(0); // lStandardBias - no DST modeled
|
|
72
|
+
writer.writeInt32LE(0); // lDaylightBias - no DST modeled
|
|
73
|
+
writeZeroTransitionBlock(writer); // wStandardYear + stStandardDate
|
|
74
|
+
writeZeroTransitionBlock(writer); // wDaylightYear + stDaylightDate
|
|
75
|
+
return writer.toBuffer();
|
|
76
|
+
}
|
|
77
|
+
/** Decodes a `TimeZoneStruct` BLOB (read from `reader`'s current position) into an approximate IANA zone
|
|
78
|
+
* identifier - see this file's own doc comment for the lossy `Etc/GMT±N` fallback's exact rounding rules. */
|
|
79
|
+
export function decodeTimeZoneStruct(reader) {
|
|
80
|
+
const bias = reader.readInt32LE();
|
|
81
|
+
reader.readInt32LE(); // lStandardBias - not reconstructable into a real DST rule, ignored
|
|
82
|
+
reader.readInt32LE(); // lDaylightBias - ditto
|
|
83
|
+
skipTransitionBlock(reader); // wStandardYear + stStandardDate
|
|
84
|
+
skipTransitionBlock(reader); // wDaylightYear + stDaylightDate
|
|
85
|
+
if (bias === 0) {
|
|
86
|
+
return "UTC";
|
|
87
|
+
}
|
|
88
|
+
const offsetMinutes = -bias;
|
|
89
|
+
const wholeHours = Math.round(offsetMinutes / 60);
|
|
90
|
+
const etcSign = wholeHours <= 0 ? "+" : "-";
|
|
91
|
+
return `Etc/GMT${etcSign}${Math.abs(wholeHours)}`;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=MapiTimeZone.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MapiTimeZone.js","sourceRoot":"","sources":["../../../src/codec/MapiTimeZone.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { decodeGuid, encodeGuid } from "./MapiGuid.js";
|
|
2
|
+
/**
|
|
3
|
+
* The property-value system every meaningful ROP depends on (`RopGetPropertiesSpecific`/`RopSetProperties`,
|
|
4
|
+
* table row data in `RopQueryRows`, ...), per `[MS-OXCDATA]` §2.11. Only the property types this phase's
|
|
5
|
+
* planned ROP handlers actually need are implemented (`readPropertyValue`/`writePropertyValue` throw a clear
|
|
6
|
+
* error for anything else) - add more as a real handler needs them, not speculatively.
|
|
7
|
+
*
|
|
8
|
+
* Numeric values and member names (`Ptyp*`) are exactly as published in `[MS-OXCDATA]`'s "Property Data
|
|
9
|
+
* Types" table - the full `Ptyp`-prefixed spec names are used rather than shorter aliases (`String`,
|
|
10
|
+
* `Boolean`, ...) both for fidelity to the spec and because those shorter names collide with this project's
|
|
11
|
+
* lint config's `id-denylist` rule (which exists to stop primitive-wrapper-like names shadowing globals).
|
|
12
|
+
*/
|
|
13
|
+
export var PropertyType;
|
|
14
|
+
(function (PropertyType) {
|
|
15
|
+
PropertyType[PropertyType["PtypNull"] = 1] = "PtypNull";
|
|
16
|
+
PropertyType[PropertyType["PtypInteger16"] = 2] = "PtypInteger16";
|
|
17
|
+
PropertyType[PropertyType["PtypInteger32"] = 3] = "PtypInteger32";
|
|
18
|
+
PropertyType[PropertyType["PtypFloating32"] = 4] = "PtypFloating32";
|
|
19
|
+
PropertyType[PropertyType["PtypFloating64"] = 5] = "PtypFloating64";
|
|
20
|
+
PropertyType[PropertyType["PtypBoolean"] = 11] = "PtypBoolean";
|
|
21
|
+
PropertyType[PropertyType["PtypInteger64"] = 20] = "PtypInteger64";
|
|
22
|
+
PropertyType[PropertyType["PtypString8"] = 30] = "PtypString8";
|
|
23
|
+
PropertyType[PropertyType["PtypString"] = 31] = "PtypString";
|
|
24
|
+
PropertyType[PropertyType["PtypTime"] = 64] = "PtypTime";
|
|
25
|
+
PropertyType[PropertyType["PtypGuid"] = 72] = "PtypGuid";
|
|
26
|
+
PropertyType[PropertyType["PtypBinary"] = 258] = "PtypBinary";
|
|
27
|
+
PropertyType[PropertyType["PtypMultipleInteger32"] = 4099] = "PtypMultipleInteger32";
|
|
28
|
+
PropertyType[PropertyType["PtypMultipleString8"] = 4126] = "PtypMultipleString8";
|
|
29
|
+
PropertyType[PropertyType["PtypMultipleString"] = 4127] = "PtypMultipleString";
|
|
30
|
+
PropertyType[PropertyType["PtypMultipleBinary"] = 4354] = "PtypMultipleBinary";
|
|
31
|
+
})(PropertyType || (PropertyType = {}));
|
|
32
|
+
/**
|
|
33
|
+
* `PropertyTag` structure (`[MS-OXCDATA]` §2.9): a 4-byte value with **`PropertyType` in the low-order 16
|
|
34
|
+
* bits and `PropertyId` in the high-order 16 bits** - confirmed against the spec's own bit-range description
|
|
35
|
+
* and cross-checked against the well-known real property-tag constant `PR_SUBJECT = 0x0037001F` (`PidTagSubject`
|
|
36
|
+
* = property ID `0x0037`, `PtypString` = type `0x001F`), which only decodes correctly with `PropertyType` as
|
|
37
|
+
* the low half. On the wire (little-endian), that means `PropertyType` is read/written first.
|
|
38
|
+
*/
|
|
39
|
+
export function readPropertyTag(reader) {
|
|
40
|
+
const propertyType = reader.readUInt16LE();
|
|
41
|
+
const propertyId = reader.readUInt16LE();
|
|
42
|
+
return { propertyId, propertyType };
|
|
43
|
+
}
|
|
44
|
+
export function writePropertyTag(writer, tag) {
|
|
45
|
+
writer.writeUInt16LE(tag.propertyType);
|
|
46
|
+
writer.writeUInt16LE(tag.propertyId);
|
|
47
|
+
}
|
|
48
|
+
/** `TypedPropertyValue` structure (`[MS-OXCDATA]` §2.11.4): `PropertyType` (2 bytes) followed by the value
|
|
49
|
+
* itself, encoded per `readPropertyValue`/`writePropertyValue` below. */
|
|
50
|
+
export function readTypedPropertyValue(reader) {
|
|
51
|
+
const propertyType = reader.readUInt16LE();
|
|
52
|
+
const value = readPropertyValue(reader, propertyType);
|
|
53
|
+
return { propertyType, value };
|
|
54
|
+
}
|
|
55
|
+
export function writeTypedPropertyValue(writer, typed) {
|
|
56
|
+
writer.writeUInt16LE(typed.propertyType);
|
|
57
|
+
writePropertyValue(writer, typed.propertyType, typed.value);
|
|
58
|
+
}
|
|
59
|
+
/** `TaggedPropertyValue` structure (`[MS-OXCDATA]` §2.11.4, confirmed via `RopSetProperties`'s own request-buffer
|
|
60
|
+
* page): a full `PropertyTag` (4 bytes - `PropertyId` **and** `PropertyType`, unlike `TypedPropertyValue`'s bare
|
|
61
|
+
* `PropertyType`) followed by the value itself. Used where a property's identity can't be inferred from
|
|
62
|
+
* context (e.g. `RopSetProperties`, which sets an arbitrary, client-chosen set of properties in one call). */
|
|
63
|
+
export function readTaggedPropertyValue(reader) {
|
|
64
|
+
const tag = readPropertyTag(reader);
|
|
65
|
+
const value = readPropertyValue(reader, tag.propertyType);
|
|
66
|
+
return { propertyId: tag.propertyId, propertyType: tag.propertyType, value };
|
|
67
|
+
}
|
|
68
|
+
export function writeTaggedPropertyValue(writer, tagged) {
|
|
69
|
+
writePropertyTag(writer, { propertyId: tagged.propertyId, propertyType: tagged.propertyType });
|
|
70
|
+
writePropertyValue(writer, tagged.propertyType, tagged.value);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Reads a bare `PropertyValue` (`[MS-OXCDATA]` §2.11.2) of the given, already-known `type`. `PtypBinary`'s
|
|
74
|
+
* length prefix is 16 bits and every `PtypMultiple*`'s value count is 32 bits wide, per the spec's explicit
|
|
75
|
+
* "in the context of ROP buffers" sizing rule - the only context every planned caller of this function
|
|
76
|
+
* operates in (the wider 32-bit `PtypBinary` count only applies to extended rules / a specific MAPI/HTTP
|
|
77
|
+
* structure this library doesn't implement).
|
|
78
|
+
*/
|
|
79
|
+
export function readPropertyValue(reader, type) {
|
|
80
|
+
switch (type) {
|
|
81
|
+
case PropertyType.PtypNull:
|
|
82
|
+
return 0;
|
|
83
|
+
case PropertyType.PtypInteger16:
|
|
84
|
+
return reader.readInt16LE();
|
|
85
|
+
case PropertyType.PtypInteger32:
|
|
86
|
+
return reader.readInt32LE();
|
|
87
|
+
case PropertyType.PtypFloating32:
|
|
88
|
+
return reader.readFloatLE();
|
|
89
|
+
case PropertyType.PtypFloating64:
|
|
90
|
+
return reader.readDoubleLE();
|
|
91
|
+
case PropertyType.PtypBoolean:
|
|
92
|
+
return reader.readUInt8() !== 0;
|
|
93
|
+
case PropertyType.PtypInteger64:
|
|
94
|
+
return reader.readBigInt64LE();
|
|
95
|
+
case PropertyType.PtypTime:
|
|
96
|
+
return filetimeToDate(reader.readBigUInt64LE());
|
|
97
|
+
case PropertyType.PtypGuid:
|
|
98
|
+
return decodeGuid(reader);
|
|
99
|
+
case PropertyType.PtypString:
|
|
100
|
+
return reader.readNullTerminatedUtf16LE();
|
|
101
|
+
case PropertyType.PtypString8:
|
|
102
|
+
return reader.readNullTerminatedString8();
|
|
103
|
+
case PropertyType.PtypBinary:
|
|
104
|
+
return reader.readBytes(reader.readUInt16LE());
|
|
105
|
+
case PropertyType.PtypMultipleInteger32:
|
|
106
|
+
return readCountedArray(reader, () => reader.readInt32LE());
|
|
107
|
+
case PropertyType.PtypMultipleString:
|
|
108
|
+
return readCountedArray(reader, () => reader.readNullTerminatedUtf16LE());
|
|
109
|
+
case PropertyType.PtypMultipleString8:
|
|
110
|
+
return readCountedArray(reader, () => reader.readNullTerminatedString8());
|
|
111
|
+
case PropertyType.PtypMultipleBinary:
|
|
112
|
+
return readCountedArray(reader, () => reader.readBytes(reader.readUInt16LE()));
|
|
113
|
+
default:
|
|
114
|
+
throw new Error(`PropertyValue: unsupported PropertyType 0x${type.toString(16)}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export function writePropertyValue(writer, type, value) {
|
|
118
|
+
switch (type) {
|
|
119
|
+
case PropertyType.PtypNull:
|
|
120
|
+
return;
|
|
121
|
+
case PropertyType.PtypInteger16:
|
|
122
|
+
writer.writeInt16LE(value);
|
|
123
|
+
return;
|
|
124
|
+
case PropertyType.PtypInteger32:
|
|
125
|
+
writer.writeInt32LE(value);
|
|
126
|
+
return;
|
|
127
|
+
case PropertyType.PtypFloating32:
|
|
128
|
+
writer.writeFloatLE(value);
|
|
129
|
+
return;
|
|
130
|
+
case PropertyType.PtypFloating64:
|
|
131
|
+
writer.writeDoubleLE(value);
|
|
132
|
+
return;
|
|
133
|
+
case PropertyType.PtypBoolean:
|
|
134
|
+
writer.writeUInt8(value ? 1 : 0);
|
|
135
|
+
return;
|
|
136
|
+
case PropertyType.PtypInteger64:
|
|
137
|
+
writer.writeBigInt64LE(value);
|
|
138
|
+
return;
|
|
139
|
+
case PropertyType.PtypTime:
|
|
140
|
+
writer.writeBigUInt64LE(dateToFiletime(value));
|
|
141
|
+
return;
|
|
142
|
+
case PropertyType.PtypGuid:
|
|
143
|
+
writer.writeBytes(encodeGuid(value));
|
|
144
|
+
return;
|
|
145
|
+
case PropertyType.PtypString:
|
|
146
|
+
writer.writeNullTerminatedUtf16LE(value);
|
|
147
|
+
return;
|
|
148
|
+
case PropertyType.PtypString8:
|
|
149
|
+
writer.writeNullTerminatedString8(value);
|
|
150
|
+
return;
|
|
151
|
+
case PropertyType.PtypBinary: {
|
|
152
|
+
const buf = value;
|
|
153
|
+
writer.writeUInt16LE(buf.length);
|
|
154
|
+
writer.writeBytes(buf);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
case PropertyType.PtypMultipleInteger32:
|
|
158
|
+
writeCountedArray(writer, value, (v) => writer.writeInt32LE(v));
|
|
159
|
+
return;
|
|
160
|
+
case PropertyType.PtypMultipleString:
|
|
161
|
+
writeCountedArray(writer, value, (v) => writer.writeNullTerminatedUtf16LE(v));
|
|
162
|
+
return;
|
|
163
|
+
case PropertyType.PtypMultipleString8:
|
|
164
|
+
writeCountedArray(writer, value, (v) => writer.writeNullTerminatedString8(v));
|
|
165
|
+
return;
|
|
166
|
+
case PropertyType.PtypMultipleBinary:
|
|
167
|
+
writeCountedArray(writer, value, (v) => {
|
|
168
|
+
writer.writeUInt16LE(v.length);
|
|
169
|
+
writer.writeBytes(v);
|
|
170
|
+
});
|
|
171
|
+
return;
|
|
172
|
+
default:
|
|
173
|
+
throw new Error(`PropertyValue: unsupported PropertyType 0x${type.toString(16)}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** `count` is a fully client-controlled `uint32` (up to ~4.29 billion). Every element type this reads needs at
|
|
177
|
+
* least 1 byte on the wire, so a `count` exceeding the buffer's actual remaining bytes can never be genuine -
|
|
178
|
+
* rejecting it immediately, before looping at all, turns a client lying about the count into an instant, clear
|
|
179
|
+
* `RangeError` instead of a loop that runs until either the heap is exhausted or (for the two `PtypMultipleString*`
|
|
180
|
+
* variants specifically, whose element reader used to tolerate running past the buffer's end - see
|
|
181
|
+
* `BufferCursor.ts`'s own doc comment) it simply never terminates. Defense in depth alongside that fix, not a
|
|
182
|
+
* replacement for it - this also fails fast for a merely-oversized-but-technically-satisfiable count instead of
|
|
183
|
+
* allocating a huge array first. */
|
|
184
|
+
function readCountedArray(reader, readOne) {
|
|
185
|
+
const count = reader.readUInt32LE();
|
|
186
|
+
if (count > reader.remaining) {
|
|
187
|
+
throw new RangeError(`PropertyValue.readCountedArray(): element count ${count} exceeds the remaining buffer size (${reader.remaining}).`);
|
|
188
|
+
}
|
|
189
|
+
const values = [];
|
|
190
|
+
for (let i = 0; i < count; i++) {
|
|
191
|
+
values.push(readOne());
|
|
192
|
+
}
|
|
193
|
+
return values;
|
|
194
|
+
}
|
|
195
|
+
function writeCountedArray(writer, values, writeOne) {
|
|
196
|
+
writer.writeUInt32LE(values.length);
|
|
197
|
+
for (const value of values) {
|
|
198
|
+
writeOne(value);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/** 100-nanosecond intervals between the FILETIME epoch (1601-01-01T00:00:00Z) and the Unix epoch
|
|
202
|
+
* (1970-01-01T00:00:00Z) - `[MS-DTYP]`'s `FILETIME` structure, which `PtypTime` uses. */
|
|
203
|
+
const FILETIME_EPOCH_DIFF_100NS = 116444736000000000n;
|
|
204
|
+
/** Converts a `PtypTime` value (100-ns intervals since 1601-01-01) into a JS `Date`. Sub-millisecond
|
|
205
|
+
* precision is truncated - `Date` has no finer resolution, a real, bounded, documented gap. */
|
|
206
|
+
export function filetimeToDate(filetime) {
|
|
207
|
+
const millis = (filetime - FILETIME_EPOCH_DIFF_100NS) / 10000n;
|
|
208
|
+
return new Date(Number(millis));
|
|
209
|
+
}
|
|
210
|
+
/** Converts a JS `Date` into a `PtypTime` value (100-ns intervals since 1601-01-01). */
|
|
211
|
+
export function dateToFiletime(date) {
|
|
212
|
+
return BigInt(date.getTime()) * 10000n + FILETIME_EPOCH_DIFF_100NS;
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=PropertyValue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PropertyValue.js","sourceRoot":"","sources":["../../../src/codec/PropertyValue.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { BufferReader, BufferWriter } from "./BufferCursor.js";
|
|
6
|
+
export function encodeRopBuffer(buf) {
|
|
7
|
+
const writer = new BufferWriter();
|
|
8
|
+
// RopSize covers itself (2 bytes) plus ropsList - the handle table isn't part of RopSize's count.
|
|
9
|
+
writer.writeUInt16LE(2 + buf.ropsList.length);
|
|
10
|
+
writer.writeBytes(buf.ropsList);
|
|
11
|
+
for (const handle of buf.handleTable) {
|
|
12
|
+
writer.writeUInt32LE(handle);
|
|
13
|
+
}
|
|
14
|
+
return writer.toBuffer();
|
|
15
|
+
}
|
|
16
|
+
export function decodeRopBuffer(buffer) {
|
|
17
|
+
const reader = new BufferReader(buffer);
|
|
18
|
+
const ropSize = reader.readUInt16LE();
|
|
19
|
+
const ropsList = reader.readBytes(ropSize - 2);
|
|
20
|
+
const handleTable = [];
|
|
21
|
+
while (reader.hasMore()) {
|
|
22
|
+
handleTable.push(reader.readUInt32LE());
|
|
23
|
+
}
|
|
24
|
+
return { ropsList, handleTable };
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=RopBuffer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RopBuffer.js","sourceRoot":"","sources":["../../../src/codec/RopBuffer.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AA0B/D,MAAM,UAAU,eAAe,CAAC,GAAc;IAC1C,MAAM,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IAClC,kGAAkG;IAClG,MAAM,CAAC,aAAa,CAAC,CAAC,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9C,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAChC,KAAK,MAAM,MAAM,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QACnC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,MAAc;IAC1C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC;IACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC;IAC/C,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,OAAO,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACtB,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** `TypedString` (`[MS-OXCDATA]` §2.11.7) `StringType` enumeration values. */
|
|
2
|
+
const STRING_TYPE_NONE = 0x00;
|
|
3
|
+
const STRING_TYPE_EMPTY = 0x01;
|
|
4
|
+
const STRING_TYPE_STRING8 = 0x02;
|
|
5
|
+
const STRING_TYPE_REDUCED_UNICODE = 0x03;
|
|
6
|
+
const STRING_TYPE_UNICODE = 0x04;
|
|
7
|
+
/**
|
|
8
|
+
* `TypedString` (`[MS-OXCDATA]` §2.11.7): a leading `StringType` byte followed by an optional string in the
|
|
9
|
+
* format that byte names - used by `RopOpenMessage`'s success response (`SubjectPrefix`/`NormalizedSubject`).
|
|
10
|
+
* `writeTypedString` never produces the "reduced Unicode" (`0x03`) form - that's purely a wire-size
|
|
11
|
+
* optimization real Exchange applies when every character happens to fit in one byte, not something a peer is
|
|
12
|
+
* ever required to send, so this codec always writes plain UTF-16LE (`0x04`) for non-empty strings. `undefined`
|
|
13
|
+
* writes as "no string" (`0x00`), matching a field the spec allows to be entirely absent (e.g. no subject
|
|
14
|
+
* prefix at all, as opposed to an empty one).
|
|
15
|
+
*/
|
|
16
|
+
export function writeTypedString(writer, value) {
|
|
17
|
+
if (value === undefined) {
|
|
18
|
+
writer.writeUInt8(STRING_TYPE_NONE);
|
|
19
|
+
}
|
|
20
|
+
else if (value === "") {
|
|
21
|
+
writer.writeUInt8(STRING_TYPE_EMPTY);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
writer.writeUInt8(STRING_TYPE_UNICODE);
|
|
25
|
+
writer.writeNullTerminatedUtf16LE(value);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
/** Reads a `TypedString`, supporting every `StringType` value a peer could legally send (`0x00`-`0x04`) even
|
|
29
|
+
* though `writeTypedString` only ever produces `0x00`/`0x01`/`0x04` itself - this side of the codec is only
|
|
30
|
+
* ever exercised in this library's own round-trip tests, since a real MAPI/HTTP client never sends a
|
|
31
|
+
* `TypedString` value to the server. Returns `undefined` for `StringType = 0x00` ("no string"), matching
|
|
32
|
+
* `writeTypedString`'s own `undefined` input. */
|
|
33
|
+
export function readTypedString(reader) {
|
|
34
|
+
const stringType = reader.readUInt8();
|
|
35
|
+
switch (stringType) {
|
|
36
|
+
case STRING_TYPE_NONE:
|
|
37
|
+
return undefined;
|
|
38
|
+
case STRING_TYPE_EMPTY:
|
|
39
|
+
return "";
|
|
40
|
+
case STRING_TYPE_STRING8:
|
|
41
|
+
return reader.readNullTerminatedString8();
|
|
42
|
+
case STRING_TYPE_REDUCED_UNICODE: {
|
|
43
|
+
let value = "";
|
|
44
|
+
for (let code = reader.readUInt8(); code !== 0; code = reader.readUInt8()) {
|
|
45
|
+
value += String.fromCharCode(code);
|
|
46
|
+
}
|
|
47
|
+
return value;
|
|
48
|
+
}
|
|
49
|
+
case STRING_TYPE_UNICODE:
|
|
50
|
+
default:
|
|
51
|
+
return reader.readNullTerminatedUtf16LE();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=TypedString.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TypedString.js","sourceRoot":"","sources":["../../../src/codec/TypedString.ts"],"names":[],"mappings":"AAMA,8EAA8E;AAC9E,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAC9B,MAAM,iBAAiB,GAAG,IAAI,CAAC;AAC/B,MAAM,mBAAmB,GAAG,IAAI,CAAC;AACjC,MAAM,2BAA2B,GAAG,IAAI,CAAC;AACzC,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAoB,EAAE,KAAyB;IAC5E,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACtB,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;IACxC,CAAC;SAAM,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACtB,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACJ,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QACvC,MAAM,CAAC,0BAA0B,CAAC,KAAK,CAAC,CAAC;IAC7C,CAAC;AACL,CAAC;AAED;;;;iDAIiD;AACjD,MAAM,UAAU,eAAe,CAAC,MAAoB;IAChD,MAAM,UAAU,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;IACtC,QAAQ,UAAU,EAAE,CAAC;QACjB,KAAK,gBAAgB;YACjB,OAAO,SAAS,CAAC;QACrB,KAAK,iBAAiB;YAClB,OAAO,EAAE,CAAC;QACd,KAAK,mBAAmB;YACpB,OAAO,MAAM,CAAC,yBAAyB,EAAE,CAAC;QAC9C,KAAK,2BAA2B,CAAC,CAAC,CAAC;YAC/B,IAAI,KAAK,GAAG,EAAE,CAAC;YACf,KAAK,IAAI,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,EAAE,IAAI,KAAK,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;gBACxE,KAAK,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,KAAK,mBAAmB,CAAC;QACzB;YACI,OAAO,MAAM,CAAC,yBAAyB,EAAE,CAAC;IAClD,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
/**
|
|
6
|
+
* MAPI-over-HTTP protocol compatibility (Phase 3 of this library's roadmap): a hand-built ROP (Remote
|
|
7
|
+
* Operation) codec and buffer-framing layer (`[MS-OXCROPS]`), JWT-secured EMSMDB transport (`BaseMapiEmsmdbRoute`,
|
|
8
|
+
* reusing the framework's existing `@Auth(["jwt"])` strategy - no MAPI-specific auth code of its own), and a
|
|
9
|
+
* minimal NSPI address-book endpoint (`BaseMapiNspiRoute`) for GAL "search as you type" lookups.
|
|
10
|
+
*
|
|
11
|
+
* This module exports only the backend-agnostic surface: the wire-format codecs, the abstract route base
|
|
12
|
+
* classes, `MapiSessionManager`, the ROP dispatcher, and every ROP/NSPI handler class (each takes a generic
|
|
13
|
+
* `RopContext`/repo argument, not a concrete entity class, so none of them are backend-specific). The concrete
|
|
14
|
+
* Mongo/SQL classes a deployment actually instantiates (`MapiEmsmdbRouteMongo`/`SQL`,
|
|
15
|
+
* `MapiNspiRouteMongo`/`SQL`) are exported from this package's `./mongo`/`./sql` subpaths instead, alongside
|
|
16
|
+
* every other entity/route/job this library defines - see `src/eas/index.ts`'s identical doc comment for the
|
|
17
|
+
* same convention.
|
|
18
|
+
*
|
|
19
|
+
* A deployment mounts both MAPI endpoints with a trivial one-line subclass each, the same pattern
|
|
20
|
+
* `src/eas/index.ts`'s doc comment describes for `BaseEasRoute`:
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { MapiEmsmdbRouteMongo, MapiNspiRouteMongo } from "@rapidrest/mail/mongo";
|
|
23
|
+
* import { RouteDecorators } from "@rapidrest/service-core";
|
|
24
|
+
* const { Route } = RouteDecorators;
|
|
25
|
+
*
|
|
26
|
+
* @Route("/mapi/emsmdb")
|
|
27
|
+
* export class MyMapiEmsmdbRoute extends MapiEmsmdbRouteMongo {}
|
|
28
|
+
*
|
|
29
|
+
* @Route("/mapi/nspi")
|
|
30
|
+
* export class MyMapiNspiRoute extends MapiNspiRouteMongo {}
|
|
31
|
+
* ```
|
|
32
|
+
* Real Outlook desktop locates both URLs via `@rapidrest/mail/autodiscover`'s Outlook/EXCH response
|
|
33
|
+
* (`BaseAutodiscoverRoute`'s `mapiUrl` property) - see that module's own doc comment.
|
|
34
|
+
*
|
|
35
|
+
* **Documented gaps in this pragmatic subset** (see the architecture plan's "MAPI over HTTP (Phase 3)" section
|
|
36
|
+
* for the full reasoning behind each):
|
|
37
|
+
* - Incremental sync (`RopFastTransferSourceCopyTo`/`CopyProperties`/`GetBuffer`) always builds a full,
|
|
38
|
+
* non-differential dump, not real IDSET-based ICS (`[MS-OXCFXICS]`) - a real client still works correctly
|
|
39
|
+
* against this, just less efficiently than byte-perfect ICS.
|
|
40
|
+
* - Calendar/meetings: no counter-proposals, meeting-forwarding, delegate scheduling, or resource-booking
|
|
41
|
+
* auto-accept; no DST-aware timezones (fixed-offset approximation only); no recurrence exceptions/modified
|
|
42
|
+
* instances; no Hijri/`MonthEnd` recurrence patterns.
|
|
43
|
+
* - No `RopModifyRecipients` - attendees/recipients are always added via the same `PidTagDisplayTo`/`Cc`
|
|
44
|
+
* pragmatic path used for ordinary mail.
|
|
45
|
+
* - No public-folder support, no delegate/shared-mailbox access, no rules/permissions/search-folder ROPs, no
|
|
46
|
+
* client-certificate enrollment.
|
|
47
|
+
* - Calendar named properties (location/recurrence/timezone/etc.) are excluded from FastTransfer streams -
|
|
48
|
+
* only the columns in `FastTransferStream.ts`'s `DEFAULT_*_COLUMNS` tables are included.
|
|
49
|
+
* - NSPI is limited to `Bind`/`Unbind`/`GetMatches` only - no row/name lookups beyond a single content-
|
|
50
|
+
* restriction search, no directory replication.
|
|
51
|
+
*/
|
|
52
|
+
export * from "./codec/BufferCursor.js";
|
|
53
|
+
export * from "./codec/MapiGuid.js";
|
|
54
|
+
export * from "./codec/TypedString.js";
|
|
55
|
+
export * from "./codec/PropertyValue.js";
|
|
56
|
+
export * from "./codec/RopBuffer.js";
|
|
57
|
+
export * from "./codec/AppointmentRecurrence.js";
|
|
58
|
+
export * from "./codec/MapiTimeZone.js";
|
|
59
|
+
export * from "./codec/GlobalObjectId.js";
|
|
60
|
+
export * from "./RopDispatcher.js";
|
|
61
|
+
export * from "./MapiSessionManager.js";
|
|
62
|
+
export * from "./BaseMapiEmsmdbRoute.js";
|
|
63
|
+
export * from "./BaseMapiNspiRoute.js";
|
|
64
|
+
export * from "./rop/RopHandler.js";
|
|
65
|
+
export * from "./rop/FolderTarget.js";
|
|
66
|
+
export * from "./rop/MessageTarget.js";
|
|
67
|
+
export * from "./rop/CalendarEventTarget.js";
|
|
68
|
+
export * from "./rop/MessageBodyStream.js";
|
|
69
|
+
export * from "./rop/PropertyResolvers.js";
|
|
70
|
+
export * from "./rop/NamedPropertyRegistry.js";
|
|
71
|
+
export * from "./rop/CalendarNamedProperties.js";
|
|
72
|
+
export * from "./rop/FastTransferStream.js";
|
|
73
|
+
export * from "./rop/MeetingMessageClassHandler.js";
|
|
74
|
+
export * from "./rop/RopLogonHandler.js";
|
|
75
|
+
export * from "./rop/RopReleaseHandler.js";
|
|
76
|
+
export * from "./rop/RopOpenFolderHandler.js";
|
|
77
|
+
export * from "./rop/RopGetHierarchyTableHandler.js";
|
|
78
|
+
export * from "./rop/RopSetColumnsHandler.js";
|
|
79
|
+
export * from "./rop/RopQueryRowsHandler.js";
|
|
80
|
+
export * from "./rop/RopGetContentsTableHandler.js";
|
|
81
|
+
export * from "./rop/RopOpenMessageHandler.js";
|
|
82
|
+
export * from "./rop/RopGetPropertiesSpecificHandler.js";
|
|
83
|
+
export * from "./rop/RopOpenStreamHandler.js";
|
|
84
|
+
export * from "./rop/RopReadStreamHandler.js";
|
|
85
|
+
export * from "./rop/RopCreateMessageHandler.js";
|
|
86
|
+
export * from "./rop/RopSetPropertiesHandler.js";
|
|
87
|
+
export * from "./rop/RopWriteStreamHandler.js";
|
|
88
|
+
export * from "./rop/RopSaveChangesMessageHandler.js";
|
|
89
|
+
export * from "./rop/RopSubmitMessageHandler.js";
|
|
90
|
+
export * from "./rop/RopGetPropertyIdsFromNamesHandler.js";
|
|
91
|
+
export * from "./rop/RopDeleteMessagesHandler.js";
|
|
92
|
+
export * from "./rop/RopDeleteFolderHandler.js";
|
|
93
|
+
export * from "./rop/RopFastTransferSourceCopyToHandler.js";
|
|
94
|
+
export * from "./rop/RopFastTransferSourceCopyPropertiesHandler.js";
|
|
95
|
+
export * from "./rop/RopFastTransferSourceGetBufferHandler.js";
|
|
96
|
+
export * from "./nspi/NspiCodec.js";
|
|
97
|
+
export * from "./nspi/NspiBindHandler.js";
|
|
98
|
+
export * from "./nspi/NspiGetMatchesHandler.js";
|
|
99
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAE/E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AACH,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kCAAkC,CAAC;AACjD,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,wBAAwB,CAAC;AACvC,cAAc,qBAAqB,CAAC;AACpC,cAAc,uBAAuB,CAAC;AACtC,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAC7C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,qCAAqC,CAAC;AACpD,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sCAAsC,CAAC;AACrD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qCAAqC,CAAC;AACpD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0CAA0C,CAAC;AACzD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,kCAAkC,CAAC;AACjD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uCAAuC,CAAC;AACtD,cAAc,kCAAkC,CAAC;AACjD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,mCAAmC,CAAC;AAClD,cAAc,iCAAiC,CAAC;AAChD,cAAc,6CAA6C,CAAC;AAC5D,cAAc,qDAAqD,CAAC;AACpE,cAAc,gDAAgD,CAAC;AAC/D,cAAc,qBAAqB,CAAC;AACpC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,iCAAiC,CAAC"}
|