@rapidmx/mapi-plugin 1.0.0-beta.10
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 +489 -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 +475 -0
- package/dist/lib/MapiSessionManager.js.map +1 -0
- package/dist/lib/RegexPatternUtils.js +30 -0
- package/dist/lib/RegexPatternUtils.js.map +1 -0
- package/dist/lib/RopDispatcher.js +145 -0
- package/dist/lib/RopDispatcher.js.map +1 -0
- package/dist/lib/codec/AppointmentRecurrence.js +315 -0
- package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
- package/dist/lib/codec/BufferCursor.js +242 -0
- package/dist/lib/codec/BufferCursor.js.map +1 -0
- package/dist/lib/codec/GlobalObjectId.js +98 -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 +126 -0
- package/dist/lib/codec/MapiTimeZone.js.map +1 -0
- package/dist/lib/codec/PropertyValue.js +240 -0
- package/dist/lib/codec/PropertyValue.js.map +1 -0
- package/dist/lib/codec/RopBuffer.js +38 -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 +85 -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/AddressList.js +114 -0
- package/dist/lib/rop/AddressList.js.map +1 -0
- package/dist/lib/rop/CalendarEventTarget.js +30 -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 +19 -0
- package/dist/lib/rop/ContactTarget.js.map +1 -0
- package/dist/lib/rop/ContentsTable.js +60 -0
- package/dist/lib/rop/ContentsTable.js.map +1 -0
- package/dist/lib/rop/ExecuteBudget.js +82 -0
- package/dist/lib/rop/ExecuteBudget.js.map +1 -0
- package/dist/lib/rop/FastTransferStream.js +195 -0
- package/dist/lib/rop/FastTransferStream.js.map +1 -0
- package/dist/lib/rop/FolderTarget.js +118 -0
- package/dist/lib/rop/FolderTarget.js.map +1 -0
- package/dist/lib/rop/HandleDataCache.js +412 -0
- package/dist/lib/rop/HandleDataCache.js.map +1 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js +241 -0
- package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
- package/dist/lib/rop/MessageBodyStream.js +68 -0
- package/dist/lib/rop/MessageBodyStream.js.map +1 -0
- package/dist/lib/rop/MessageTarget.js +57 -0
- package/dist/lib/rop/MessageTarget.js.map +1 -0
- package/dist/lib/rop/NamedPropertyRegistry.js +69 -0
- package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
- package/dist/lib/rop/PropertyResolvers.js +353 -0
- package/dist/lib/rop/PropertyResolvers.js.map +1 -0
- package/dist/lib/rop/RepoPaging.js +54 -0
- package/dist/lib/rop/RepoPaging.js.map +1 -0
- package/dist/lib/rop/RestapiRules.js +52 -0
- package/dist/lib/rop/RestapiRules.js.map +1 -0
- package/dist/lib/rop/RopCreateMessageHandler.js +55 -0
- package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js +174 -0
- package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopDeleteMessagesHandler.js +110 -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 +60 -0
- package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +76 -0
- package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js +55 -0
- package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js +42 -0
- package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
- package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +56 -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 +6 -0
- package/dist/lib/rop/RopHandler.js.map +1 -0
- package/dist/lib/rop/RopLogonHandler.js +135 -0
- package/dist/lib/rop/RopLogonHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenFolderHandler.js +48 -0
- package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenMessageHandler.js +83 -0
- package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopOpenStreamHandler.js +84 -0
- package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopQueryRowsHandler.js +120 -0
- package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
- package/dist/lib/rop/RopReadStreamHandler.js +73 -0
- package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
- package/dist/lib/rop/RopReleaseHandler.js +23 -0
- package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js +269 -0
- package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopSetColumnsHandler.js +50 -0
- package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js +173 -0
- package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js +342 -0
- package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
- package/dist/lib/rop/RopWriteStreamHandler.js +72 -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 +15 -0
- package/dist/lib/rop/TaskTarget.js.map +1 -0
- package/dist/lib/rop/TransportSend.js +16 -0
- package/dist/lib/rop/TransportSend.js.map +1 -0
- package/dist/lib/sql/MapiEmsmdbRouteSQL.js +85 -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 +139 -0
- package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
- package/dist/types/MapiSessionManager.d.ts +285 -0
- package/dist/types/RegexPatternUtils.d.ts +14 -0
- package/dist/types/RopDispatcher.d.ts +53 -0
- package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
- package/dist/types/codec/BufferCursor.d.ts +92 -0
- package/dist/types/codec/GlobalObjectId.d.ts +15 -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 +87 -0
- package/dist/types/codec/RopBuffer.d.ts +32 -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 +20 -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 +26 -0
- package/dist/types/rop/AddressList.d.ts +48 -0
- package/dist/types/rop/CalendarEventTarget.d.ts +33 -0
- package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
- package/dist/types/rop/ContactTarget.d.ts +29 -0
- package/dist/types/rop/ContentsTable.d.ts +16 -0
- package/dist/types/rop/ExecuteBudget.d.ts +48 -0
- package/dist/types/rop/FastTransferStream.d.ts +57 -0
- package/dist/types/rop/FolderTarget.d.ts +64 -0
- package/dist/types/rop/HandleDataCache.d.ts +145 -0
- package/dist/types/rop/MeetingMessageClassHandler.d.ts +30 -0
- package/dist/types/rop/MessageBodyStream.d.ts +35 -0
- package/dist/types/rop/MessageTarget.d.ts +45 -0
- package/dist/types/rop/NamedPropertyRegistry.d.ts +50 -0
- package/dist/types/rop/PropertyResolvers.d.ts +86 -0
- package/dist/types/rop/RepoPaging.d.ts +30 -0
- package/dist/types/rop/RestapiRules.d.ts +32 -0
- package/dist/types/rop/RopCreateMessageHandler.d.ts +24 -0
- package/dist/types/rop/RopDeleteFolderHandler.d.ts +53 -0
- package/dist/types/rop/RopDeleteMessagesHandler.d.ts +43 -0
- package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +25 -0
- package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +25 -0
- package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +22 -0
- package/dist/types/rop/RopGetContentsTableHandler.d.ts +25 -0
- package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +18 -0
- package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +26 -0
- package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
- package/dist/types/rop/RopHandler.d.ts +106 -0
- package/dist/types/rop/RopLogonHandler.d.ts +31 -0
- package/dist/types/rop/RopOpenFolderHandler.d.ts +20 -0
- package/dist/types/rop/RopOpenMessageHandler.d.ts +28 -0
- package/dist/types/rop/RopOpenStreamHandler.d.ts +28 -0
- package/dist/types/rop/RopQueryRowsHandler.d.ts +43 -0
- package/dist/types/rop/RopReadStreamHandler.d.ts +20 -0
- package/dist/types/rop/RopReleaseHandler.d.ts +15 -0
- package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +59 -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 +80 -0
- package/dist/types/rop/RopWriteStreamHandler.d.ts +31 -0
- package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
- package/dist/types/rop/TaskTarget.d.ts +24 -0
- package/dist/types/rop/TransportSend.d.ts +10 -0
- package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +20 -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,80 @@
|
|
|
1
|
+
import type { BufferReader, BufferWriter } from "../codec/BufferCursor.js";
|
|
2
|
+
import { type RopContext, type RopHandler } from "./RopHandler.js";
|
|
3
|
+
export { isPlainEmailAddress, parseAddressList } from "./AddressList.js";
|
|
4
|
+
/**
|
|
5
|
+
* `RopSubmitMessage` (`[MS-OXOMSG]`/`[MS-OXCROPS]`): sends a composed message - the actual trigger point for
|
|
6
|
+
* this pragmatic subset's compose/send pipeline, since `RopSaveChangesMessage` itself does no real persistence
|
|
7
|
+
* (see its own doc comment). Builds a raw MIME buffer from whatever `RopSetProperties`/`RopWriteStream` calls
|
|
8
|
+
* accumulated on the draft handle (`Subject`, the `PidTagBody` stream or an inline `PidTagBody` property, and
|
|
9
|
+
* addressing - see below), via `nodemailer`'s `MailComposer` (already a dependency, used elsewhere in this
|
|
10
|
+
* library only to *send*, not build, MIME - this is its first use purely as a RFC 5322 serializer), then calls
|
|
11
|
+
* the exact same `scanAndRelay()` scan-then-relay pipeline `BaseMessageRoute.send()`/EAS's `ComposeMailCommand`
|
|
12
|
+
* already share, and persists a Sent Items copy (mirroring `ComposeMailCommand`'s own always-committed Sent
|
|
13
|
+
* Items behavior for MAPI submission specifically, since - unlike EAS's optional `SaveInSentItems` - a MAPI
|
|
14
|
+
* `RopSubmitMessage` call has no "don't keep a copy" option to honor).
|
|
15
|
+
*
|
|
16
|
+
* **Known, deliberate limitation - no `RopModifyRecipients` support**: real recipient rows (`[MS-OXCMSG]`
|
|
17
|
+
* §2.2.3.2, each with its own `PidTagEmailAddress`/`PidTagRecipientType`) are a substantial structure this
|
|
18
|
+
* pragmatic subset's ROP coverage doesn't include. Instead, addressing is read from `PidTagDisplayTo`/
|
|
19
|
+
* `DisplayCc`/`DisplayBcc` - the same semicolon-separated "cached recipient display string" properties real
|
|
20
|
+
* Outlook *also* always sets via `RopSetProperties` alongside `RopModifyRecipients` (as a display-only
|
|
21
|
+
* convenience cache). Entries are separated by `;` and parsed with nodemailer's `addressparser`, so both bare
|
|
22
|
+
* addresses and resolved `Name <address>` forms work. A client that resolved a name against an address book may
|
|
23
|
+
* write the display name alone; that is looked up among the caller's own contacts (see `resolveRecipientList`), and
|
|
24
|
+
* a name matching no single contact fails the submit with `MAPI_E_NOT_FOUND`. It is still **not** a substitute for
|
|
25
|
+
* real recipient rows (there is no recipient table to fall back on), so the whole send is refused rather than sent to
|
|
26
|
+
* fewer people than the user addressed. A malformed recipient fails with `MAPI_E_INVALID_PARAMETER`.
|
|
27
|
+
*
|
|
28
|
+
* `SubmitFlags` (`PreprocessOnly`, ...) is decoded to advance past it correctly but not honored - this
|
|
29
|
+
* pragmatic subset has no transport-agent preprocessing distinction to vary by flag.
|
|
30
|
+
*
|
|
31
|
+
* **`PidTagDeferredSendTime`** ("Do not deliver before"), if set to a future time via `RopSetProperties`,
|
|
32
|
+
* parks the message in Outbox with `Message.scheduledSendTime` set instead of relaying immediately - mirroring
|
|
33
|
+
* `BaseMessageRoute.send()`'s own identical branch - for `ScheduledSendJob` to relay later via this same
|
|
34
|
+
* `scanAndRelay()` pipeline. **`PidTagReadReceiptRequested`**, if `true`, attaches a real
|
|
35
|
+
* `Disposition-Notification-To` header (see `util/ReceiptUtils.ts`) and is recorded on the persisted message's
|
|
36
|
+
* own `requestReceipt` field - honored only when the client explicitly sets it, not this mailbox's
|
|
37
|
+
* `alwaysRequestReceiptInternal`/`External` defaults (those apply to the REST/webmail compose path only).
|
|
38
|
+
*
|
|
39
|
+
* **Once per draft.** A mail or meeting-response draft is marked `submitted` as soon as a submit gets past the handle
|
|
40
|
+
* check, whatever the outcome, and a submitted draft can't be submitted again (`MAPI_E_INVALID_OBJECT`) or changed by
|
|
41
|
+
* `RopSetProperties`/`RopWriteStream`; its write-stream chunks are deleted once read. Each `Execute` runs at most
|
|
42
|
+
* `MAX_SUBMITS_PER_EXECUTE` submits, and a message may have at most `MAX_RECIPIENTS_PER_MESSAGE` recipients
|
|
43
|
+
* (`MAPI_E_TOO_BIG`), counted before any display name is looked up.
|
|
44
|
+
*
|
|
45
|
+
* **Calendar branches**: a draft whose `PidTagMessageClass` starts with `"IPM.Appointment"` is routed to
|
|
46
|
+
* `submitAppointment()` instead of the mail path below - see that method's own doc comment. One starting with
|
|
47
|
+
* `"IPM.Schedule.Meeting.Resp."` (an attendee's own accept/decline/tentative response to a meeting this server
|
|
48
|
+
* previously invited them to) is routed to `MeetingMessageClassHandler.submitMeetingResponse()` instead - see
|
|
49
|
+
* that function's own doc comment.
|
|
50
|
+
*
|
|
51
|
+
* @author Jean-Philippe Steinmetz
|
|
52
|
+
*/
|
|
53
|
+
export declare class RopSubmitMessageHandler implements RopHandler {
|
|
54
|
+
readonly ropId = 50;
|
|
55
|
+
handle(reader: BufferReader, writer: BufferWriter, context: RopContext): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Submits a Calendar item. The appointment itself is already persisted (`RopSaveChangesMessageHandler` writes the
|
|
58
|
+
* real `CalendarEvent` row at Save time, unlike a mail draft, which stays purely in-session until Submit), so there
|
|
59
|
+
* is nothing left to store and nothing is sent from here.
|
|
60
|
+
*
|
|
61
|
+
* **Invites are restapi's `MeetingSchedulingJob`'s job.** That job sends an iTIP `REQUEST` for every
|
|
62
|
+
* organizer-owned event whose `inviteSequenceSent` differs from its `sequence`, claiming each revision with a
|
|
63
|
+
* versioned update before sending and building the invite with restapi's own `buildEventIcs` (so a recurring
|
|
64
|
+
* meeting's invite carries its `RRULE` and exceptions). Saving stamps `inviteSequenceSent = sequence`, so a meeting
|
|
65
|
+
* that is only saved ("Save & Close", or "save changes but don't send") invites no one. Submitting clears the stamp
|
|
66
|
+
* (`inviteSequenceSent: null`) with a versioned update, which makes the job send the current revision exactly once.
|
|
67
|
+
* - A revision that is already waiting for the job (submitted and not yet sent, or never stamped) is left alone, so
|
|
68
|
+
* submitting it again before the job runs doesn't cause a second invite.
|
|
69
|
+
* - The update is versioned (`asEntity`). The job only ever claims a waiting revision, so a conflict here comes from
|
|
70
|
+
* some other edit (an attendee's reply updating the row, a REST edit); the row is read again and the check repeated,
|
|
71
|
+
* up to `MAX_INVITE_REQUEST_ATTEMPTS` times, after which the ROP fails (`MAPI_E_CALL_FAILED`).
|
|
72
|
+
* - Submitting a revision the job has already sent sends it again: the client asked to send.
|
|
73
|
+
*
|
|
74
|
+
* Only the organizer's own copy may be submitted (an attendee's copy of someone else's meeting answers
|
|
75
|
+
* `MAPI_E_INVALID_OBJECT`, as before, and nothing is changed).
|
|
76
|
+
*/
|
|
77
|
+
private submitAppointment;
|
|
78
|
+
}
|
|
79
|
+
/** How many times `requestInvites` re-reads a row whose versioned update lost to another edit before giving up. */
|
|
80
|
+
export declare const MAX_INVITE_REQUEST_ATTEMPTS = 3;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { BufferReader, BufferWriter } from "../codec/BufferCursor.js";
|
|
2
|
+
import type { MapiObjectHandle } from "../MapiSessionManager.js";
|
|
3
|
+
import { type RopContext, type RopHandler } from "./RopHandler.js";
|
|
4
|
+
/** The largest body a write stream accumulates. */
|
|
5
|
+
export declare const MAX_WRITE_STREAM_BYTES: number;
|
|
6
|
+
/** How long a write stream's chunks are kept after its last write - the session's own idle lifetime. */
|
|
7
|
+
export declare const WRITE_STREAM_TTL_SECONDS: number;
|
|
8
|
+
export { writeStreamKey } from "./HandleDataCache.js";
|
|
9
|
+
/**
|
|
10
|
+
* `RopWriteStream` (`[MS-OXCPRPT]`/`[MS-OXCROPS]`): writes bytes to a stream opened in `ReadWrite`/`Create`
|
|
11
|
+
* mode (`RopOpenStreamHandler`'s write-mode branch - the only kind of writable stream this pragmatic subset
|
|
12
|
+
* ever produces, always a `RopCreateMessage` draft's `PidTagBody`). Each write is stored as a chunk keyed by its
|
|
13
|
+
* offset in the `HandleDataStore` (Redis when configured), not in the session: only `writeSize` is session state.
|
|
14
|
+
* Keying by offset makes a retried write (after a request whose session save lost a conflict) replace its chunk
|
|
15
|
+
* instead of appending it twice. Up to `MAX_WRITE_STREAM_BYTES`; a write past that fails with `MAPI_E_TOO_BIG` and
|
|
16
|
+
* nothing is stored, as it is when the session's or user's handle data quota (`handleDataOwners`) is used up. A stream
|
|
17
|
+
* whose draft has already been submitted takes no more writes. `RopSubmitMessageHandler` reassembles the body (`readWriteStream`) once composing is complete.
|
|
18
|
+
*
|
|
19
|
+
* Like `RopReadStream`, `[MS-OXCROPS]` documents only one combined response-buffer shape for this ROP (no
|
|
20
|
+
* separate Success/Failure pages) - `WrittenSize` is always present, `0` standing in for the failure case.
|
|
21
|
+
*
|
|
22
|
+
* @author Jean-Philippe Steinmetz
|
|
23
|
+
*/
|
|
24
|
+
export declare class RopWriteStreamHandler implements RopHandler {
|
|
25
|
+
readonly ropId = 45;
|
|
26
|
+
readonly failureTailBytes = 2;
|
|
27
|
+
handle(reader: BufferReader, writer: BufferWriter, context: RopContext): Promise<void>;
|
|
28
|
+
}
|
|
29
|
+
/** The bytes written so far to the write stream `stream` at `handleIndex`, or `undefined` when they can no longer be
|
|
30
|
+
* reassembled (a chunk expired or was evicted). */
|
|
31
|
+
export declare function readWriteStream(context: RopContext, handleIndex: number, stream: MapiObjectHandle): Promise<Buffer | undefined>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Task named-property identity table (`(PropertySet GUID, LID)` pairs) this pragmatic subset supports, per
|
|
3
|
+
* `[MS-OXPROPS]`/`[MS-OXOTASK]` - the exact `CalendarNamedProperties.ts` precedent, adapted for `PSETID_Task`,
|
|
4
|
+
* shared by `PropertyResolvers.ts` (the read side: `taskValueFor`). Read-only in this pass - see
|
|
5
|
+
* `TaskTarget.ts`'s own doc comment for why there's no write-side (`RopSetProperties`/`RopSaveChangesMessage`)
|
|
6
|
+
* counterpart yet.
|
|
7
|
+
*/
|
|
8
|
+
export declare const PSETID_TASK = "00062003-0000-0000-c000-000000000046";
|
|
9
|
+
/** `PidLidTaskStatus` (`PT_LONG`) - `[MS-OXOTASK]` §2.2.2.1.5's own `olTaskNotStarted`(0)/`olTaskInProgress`(1)/
|
|
10
|
+
* `olTaskComplete`(2)/`olTaskWaiting`(3)/`olTaskDeferred`(4) values. This data model's `Task.completed` is a
|
|
11
|
+
* plain boolean with no in-progress/waiting/deferred distinction, so only `olTaskNotStarted`/`olTaskComplete`
|
|
12
|
+
* are ever produced - a documented, harmless approximation, the same category as `CalendarNamedProperties.ts`'s
|
|
13
|
+
* own `olWorkingElsewhere` gap. */
|
|
14
|
+
export declare const LID_TASK_STATUS = 33025;
|
|
15
|
+
export declare const TASK_STATUS_NOT_STARTED = 0;
|
|
16
|
+
export declare const TASK_STATUS_COMPLETE = 2;
|
|
17
|
+
/** `PidLidPercentComplete` (`PT_R8`, `[MS-OXOTASK]` §2.2.2.1.6) - `0.0`-`1.0`. No partial-progress tracking in
|
|
18
|
+
* this data model either, so this is always `1.0` (complete) or `0.0` (not started), mirroring
|
|
19
|
+
* `LID_TASK_STATUS`'s own two-value approximation. */
|
|
20
|
+
export declare const LID_PERCENT_COMPLETE = 33026;
|
|
21
|
+
/** `PidLidTaskDueDate` (`PT_SYSTIME`, `[MS-OXOTASK]` §2.2.2.2.4). */
|
|
22
|
+
export declare const LID_TASK_DUE_DATE = 33029;
|
|
23
|
+
/** `PidLidTaskComplete` (`PT_BOOLEAN`, `[MS-OXOTASK]` §2.2.2.1.9) - maps directly to `Task.completed`. */
|
|
24
|
+
export declare const LID_TASK_COMPLETE = 33052;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { RepoUtils } from "@rapidrest/service-core";
|
|
2
|
+
import type { RepoSort } from "./RepoPaging.js";
|
|
3
|
+
/**
|
|
4
|
+
* The `RopGetContentsTable`/`RopOpenMessage` analog of `MessageTarget.ts`, for a `Folder` of type `TASKS`:
|
|
5
|
+
* resolves a `"task:<uid>"` row/handle target into the display data a task-item row or an opened task's
|
|
6
|
+
* properties need. A `Task` is addressed by MID exactly the same way a `Message`/`CalendarEvent`/`Contact` is -
|
|
7
|
+
* `MessageTarget.assignOrGetMid`/`session.messageIds` are reused as-is, so this file adds no MID-registry code
|
|
8
|
+
* of its own.
|
|
9
|
+
*
|
|
10
|
+
* Read-only in this pragmatic subset - a client checking off a task (`RopSetProperties`/`RopSaveChangesMessage`
|
|
11
|
+
* against a `"task:"` handle) is a documented gap, same as Contacts (see `ContactTarget.ts`'s own note); the
|
|
12
|
+
* REST API's own `PUT`/`PATCH` `/tasks/:id` remains the way to mutate a `Task` today.
|
|
13
|
+
*/
|
|
14
|
+
export interface TaskTargetInfo {
|
|
15
|
+
title: string;
|
|
16
|
+
completed: boolean;
|
|
17
|
+
dueDate?: Date;
|
|
18
|
+
}
|
|
19
|
+
/** Degrades to empty-looking values for a `"task:<uid>"` target whose real `Task` has since vanished
|
|
20
|
+
* (soft-deleted or otherwise) - the same "don't fail the whole ROP over one stale row" principle
|
|
21
|
+
* `MessageTarget.resolveMessageInfo`/`ContactTarget.resolveContactInfo` already apply. */
|
|
22
|
+
export declare function resolveTaskInfo(target: string, taskRepo: RepoUtils<any>): Promise<TaskTargetInfo>;
|
|
23
|
+
/** The order a `TASKS` folder's contents table lists tasks in (see `ContentsTable.ts`). */
|
|
24
|
+
export declare const TASK_SORT: RepoSort;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MailTransport, OutboundMessage, TransportResult } from "@rapidmx/restapi";
|
|
2
|
+
/**
|
|
3
|
+
* Sends `message` and throws unless the transport accepted it for at least one recipient and rejected none.
|
|
4
|
+
*
|
|
5
|
+
* The same rule as restapi's own `sendOrThrow()` (`transport/TransportResultUtils.ts`), which isn't exported from
|
|
6
|
+
* the `@rapidmx/restapi` package root, so it can't be imported here; keep the two in sync. Every bundled transport
|
|
7
|
+
* reports a failed relay through `TransportResult.rejected` rather than throwing, so a bare `send()` would treat a
|
|
8
|
+
* rejected message as sent.
|
|
9
|
+
*/
|
|
10
|
+
export declare function sendOrThrow(transport: MailTransport, message: OutboundMessage): Promise<TransportResult>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MailboxSQL } from "@rapidmx/restapi/sql";
|
|
2
|
+
import { BaseMapiEmsmdbRoute } from "../BaseMapiEmsmdbRoute.js";
|
|
3
|
+
/**
|
|
4
|
+
* SQL-backed concrete `BaseMapiEmsmdbRoute`, mounted at `/mapi/emsmdb`. Exported from this plugin's
|
|
5
|
+
* `./sql` entry point, so the server host mounts it without a wrapper class of its
|
|
6
|
+
* own.
|
|
7
|
+
*
|
|
8
|
+
* @author Jean-Philippe Steinmetz
|
|
9
|
+
*/
|
|
10
|
+
export declare class MapiEmsmdbRouteSQL extends BaseMapiEmsmdbRoute<MailboxSQL> {
|
|
11
|
+
protected mailboxClass: any;
|
|
12
|
+
protected folderClass: any;
|
|
13
|
+
protected messageClass: any;
|
|
14
|
+
protected calendarEventClass: any;
|
|
15
|
+
protected contactClass: any;
|
|
16
|
+
protected taskClass: any;
|
|
17
|
+
protected labelClass: any;
|
|
18
|
+
protected auditLogClass: any;
|
|
19
|
+
protected ropHandlerClasses: any[];
|
|
20
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MailboxSQL } from "@rapidmx/restapi/sql";
|
|
2
|
+
import { BaseMapiNspiRoute } from "../BaseMapiNspiRoute.js";
|
|
3
|
+
/**
|
|
4
|
+
* SQL-backed concrete `BaseMapiNspiRoute`, mounted at `/mapi/nspi`. Exported from this plugin's
|
|
5
|
+
* `./sql` entry point, so the server host mounts it without a wrapper class of its
|
|
6
|
+
* own.
|
|
7
|
+
*
|
|
8
|
+
* @author Jean-Philippe Steinmetz
|
|
9
|
+
*/
|
|
10
|
+
export declare class MapiNspiRouteSQL extends BaseMapiNspiRoute<MailboxSQL> {
|
|
11
|
+
protected mailboxClass: any;
|
|
12
|
+
protected contactClass: any;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./sql/index.js";
|
package/package.json
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rapidmx/mapi-plugin",
|
|
3
|
+
"version": "1.0.0-beta.10",
|
|
4
|
+
"description": "A RapidMX plugin that provides MAPI over HTTP protocol support.",
|
|
5
|
+
"repository": "https://github.com/rapidmx/mapi-plugin.git",
|
|
6
|
+
"author": "RapidREST <rapidrests@gmail.com>",
|
|
7
|
+
"license": "MPL-2.0",
|
|
8
|
+
"contributors": [
|
|
9
|
+
"Jean-Philippe Steinmetz"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "yarn lint && rimraf dist && tsc",
|
|
13
|
+
"lint": "eslint ./src ./test",
|
|
14
|
+
"local-audit": "yarn install && yarn npm audit -A -R \"$@\"",
|
|
15
|
+
"checkup": "yarn dlx @yarnpkg/doctor \"$@\"",
|
|
16
|
+
"dependency-check": "yarn dlx depcheck \"$@\"",
|
|
17
|
+
"report-coverage": "cat ./coverage/lcov.info | coveralls",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:prod": "npm run lint && vitest run --coverage",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"release": "npx @rapidrest/cli release",
|
|
22
|
+
"prepublish": "yarn build"
|
|
23
|
+
},
|
|
24
|
+
"peerDependencies": {
|
|
25
|
+
"@rapidmx/restapi": "0.x",
|
|
26
|
+
"@rapidrest/core": "5.x",
|
|
27
|
+
"@rapidrest/service-core": "2.x"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"mailparser": "^3.9.23",
|
|
31
|
+
"nodemailer": "^10.0.1"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@rapidmx/restapi": "^0.22.1",
|
|
35
|
+
"@rapidrest/core": "^6.0.0",
|
|
36
|
+
"@rapidrest/service-core": "^2.3.0",
|
|
37
|
+
"@swc/core": "^1.16.2",
|
|
38
|
+
"@types/mailparser": "^3.4.6",
|
|
39
|
+
"@types/nconf": "^0.10.7",
|
|
40
|
+
"@types/node": "^26.5.0",
|
|
41
|
+
"@types/nodemailer": "^8.0.1",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^8.70.0",
|
|
43
|
+
"@typescript-eslint/parser": "^8.70.0",
|
|
44
|
+
"@vitest/coverage-v8": "^5.0.0",
|
|
45
|
+
"better-sqlite3": "^13.0.3",
|
|
46
|
+
"eslint": "^10.10.0",
|
|
47
|
+
"eslint-config-prettier": "^10.1.8",
|
|
48
|
+
"eslint-plugin-import": "^2.32.0",
|
|
49
|
+
"eslint-plugin-jsdoc": "^64.3.6",
|
|
50
|
+
"globals": "^17.12.0",
|
|
51
|
+
"lodash-es": "^4.18.1",
|
|
52
|
+
"mongodb": "^7.6.0",
|
|
53
|
+
"mongodb-memory-server": "^11.2.0",
|
|
54
|
+
"nconf": "^0.13.0",
|
|
55
|
+
"openapi3-ts": "^4.6.1",
|
|
56
|
+
"prom-client": "^15.1.3",
|
|
57
|
+
"redis": "^6.2.1",
|
|
58
|
+
"reflect-metadata": "^0.2.2",
|
|
59
|
+
"rimraf": "^6.1.3",
|
|
60
|
+
"ts-node": "^10.9.2",
|
|
61
|
+
"tsx": "^4.23.13",
|
|
62
|
+
"typeorm": "^1.1.1",
|
|
63
|
+
"typescript": "^6.0.3",
|
|
64
|
+
"unplugin-swc": "^1.6.0",
|
|
65
|
+
"vite": "^8.2.2",
|
|
66
|
+
"vitest": "^5.0.0",
|
|
67
|
+
"winston": "^3.19.0"
|
|
68
|
+
},
|
|
69
|
+
"packageManager": "yarn@4.5.3",
|
|
70
|
+
"engines": {
|
|
71
|
+
"node": ">=24.0.0"
|
|
72
|
+
},
|
|
73
|
+
"publishConfig": {
|
|
74
|
+
"registry": "https://registry.npmjs.org/"
|
|
75
|
+
},
|
|
76
|
+
"type": "module",
|
|
77
|
+
"main": "dist/lib/index.js",
|
|
78
|
+
"exports": {
|
|
79
|
+
".": {
|
|
80
|
+
"import": "./dist/lib/index.js",
|
|
81
|
+
"types": "./dist/types/index.d.ts"
|
|
82
|
+
},
|
|
83
|
+
"./mongo": {
|
|
84
|
+
"import": "./dist/lib/mongo.js",
|
|
85
|
+
"types": "./dist/types/mongo.d.ts"
|
|
86
|
+
},
|
|
87
|
+
"./sql": {
|
|
88
|
+
"import": "./dist/lib/sql.js",
|
|
89
|
+
"types": "./dist/types/sql.d.ts"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"typings": "dist/types/index.d.ts",
|
|
93
|
+
"files": [
|
|
94
|
+
"dist"
|
|
95
|
+
],
|
|
96
|
+
"rapidmx": {
|
|
97
|
+
"plugin": {
|
|
98
|
+
"apiVersion": 1,
|
|
99
|
+
"displayName": "MAPI over HTTP",
|
|
100
|
+
"description": "Lets Outlook for Windows connect with the MAPI/HTTP protocol (served at /mapi/emsmdb and /mapi/nspi).",
|
|
101
|
+
"settings": []
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|