@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.
Files changed (180) hide show
  1. package/LICENSE +382 -0
  2. package/README.md +60 -0
  3. package/dist/lib/BaseMapiEmsmdbRoute.js +297 -0
  4. package/dist/lib/BaseMapiEmsmdbRoute.js.map +1 -0
  5. package/dist/lib/BaseMapiNspiRoute.js +114 -0
  6. package/dist/lib/BaseMapiNspiRoute.js.map +1 -0
  7. package/dist/lib/MapiSessionManager.js +119 -0
  8. package/dist/lib/MapiSessionManager.js.map +1 -0
  9. package/dist/lib/RopDispatcher.js +34 -0
  10. package/dist/lib/RopDispatcher.js.map +1 -0
  11. package/dist/lib/codec/AppointmentRecurrence.js +314 -0
  12. package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
  13. package/dist/lib/codec/BufferCursor.js +213 -0
  14. package/dist/lib/codec/BufferCursor.js.map +1 -0
  15. package/dist/lib/codec/GlobalObjectId.js +92 -0
  16. package/dist/lib/codec/GlobalObjectId.js.map +1 -0
  17. package/dist/lib/codec/MapiGuid.js +41 -0
  18. package/dist/lib/codec/MapiGuid.js.map +1 -0
  19. package/dist/lib/codec/MapiTimeZone.js +93 -0
  20. package/dist/lib/codec/MapiTimeZone.js.map +1 -0
  21. package/dist/lib/codec/PropertyValue.js +214 -0
  22. package/dist/lib/codec/PropertyValue.js.map +1 -0
  23. package/dist/lib/codec/RopBuffer.js +26 -0
  24. package/dist/lib/codec/RopBuffer.js.map +1 -0
  25. package/dist/lib/codec/TypedString.js +54 -0
  26. package/dist/lib/codec/TypedString.js.map +1 -0
  27. package/dist/lib/index.js +99 -0
  28. package/dist/lib/index.js.map +1 -0
  29. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +84 -0
  30. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -0
  31. package/dist/lib/mongo/MapiNspiRouteMongo.js +33 -0
  32. package/dist/lib/mongo/MapiNspiRouteMongo.js.map +1 -0
  33. package/dist/lib/mongo/index.js +7 -0
  34. package/dist/lib/mongo/index.js.map +1 -0
  35. package/dist/lib/mongo.js +6 -0
  36. package/dist/lib/mongo.js.map +1 -0
  37. package/dist/lib/nspi/NspiBindHandler.js +54 -0
  38. package/dist/lib/nspi/NspiBindHandler.js.map +1 -0
  39. package/dist/lib/nspi/NspiCodec.js +106 -0
  40. package/dist/lib/nspi/NspiCodec.js.map +1 -0
  41. package/dist/lib/nspi/NspiGetMatchesHandler.js +142 -0
  42. package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -0
  43. package/dist/lib/rop/CalendarEventTarget.js +27 -0
  44. package/dist/lib/rop/CalendarEventTarget.js.map +1 -0
  45. package/dist/lib/rop/CalendarNamedProperties.js +57 -0
  46. package/dist/lib/rop/CalendarNamedProperties.js.map +1 -0
  47. package/dist/lib/rop/ContactTarget.js +23 -0
  48. package/dist/lib/rop/ContactTarget.js.map +1 -0
  49. package/dist/lib/rop/FastTransferStream.js +98 -0
  50. package/dist/lib/rop/FastTransferStream.js.map +1 -0
  51. package/dist/lib/rop/FolderTarget.js +111 -0
  52. package/dist/lib/rop/FolderTarget.js.map +1 -0
  53. package/dist/lib/rop/MeetingMessageClassHandler.js +95 -0
  54. package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
  55. package/dist/lib/rop/MessageBodyStream.js +42 -0
  56. package/dist/lib/rop/MessageBodyStream.js.map +1 -0
  57. package/dist/lib/rop/MessageTarget.js +44 -0
  58. package/dist/lib/rop/MessageTarget.js.map +1 -0
  59. package/dist/lib/rop/NamedPropertyRegistry.js +66 -0
  60. package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
  61. package/dist/lib/rop/PropertyResolvers.js +313 -0
  62. package/dist/lib/rop/PropertyResolvers.js.map +1 -0
  63. package/dist/lib/rop/RopCreateMessageHandler.js +53 -0
  64. package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
  65. package/dist/lib/rop/RopDeleteFolderHandler.js +133 -0
  66. package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
  67. package/dist/lib/rop/RopDeleteMessagesHandler.js +70 -0
  68. package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -0
  69. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +61 -0
  70. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -0
  71. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +61 -0
  72. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
  73. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +75 -0
  74. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
  75. package/dist/lib/rop/RopGetContentsTableHandler.js +76 -0
  76. package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
  77. package/dist/lib/rop/RopGetHierarchyTableHandler.js +40 -0
  78. package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
  79. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +55 -0
  80. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -0
  81. package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js +92 -0
  82. package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js.map +1 -0
  83. package/dist/lib/rop/RopHandler.js +2 -0
  84. package/dist/lib/rop/RopHandler.js.map +1 -0
  85. package/dist/lib/rop/RopLogonHandler.js +132 -0
  86. package/dist/lib/rop/RopLogonHandler.js.map +1 -0
  87. package/dist/lib/rop/RopOpenFolderHandler.js +46 -0
  88. package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
  89. package/dist/lib/rop/RopOpenMessageHandler.js +81 -0
  90. package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
  91. package/dist/lib/rop/RopOpenStreamHandler.js +81 -0
  92. package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
  93. package/dist/lib/rop/RopQueryRowsHandler.js +91 -0
  94. package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
  95. package/dist/lib/rop/RopReadStreamHandler.js +55 -0
  96. package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
  97. package/dist/lib/rop/RopReleaseHandler.js +20 -0
  98. package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
  99. package/dist/lib/rop/RopSaveChangesMessageHandler.js +210 -0
  100. package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
  101. package/dist/lib/rop/RopSetColumnsHandler.js +52 -0
  102. package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
  103. package/dist/lib/rop/RopSetPropertiesHandler.js +162 -0
  104. package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
  105. package/dist/lib/rop/RopSubmitMessageHandler.js +314 -0
  106. package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
  107. package/dist/lib/rop/RopWriteStreamHandler.js +45 -0
  108. package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -0
  109. package/dist/lib/rop/TaskNamedProperties.js +29 -0
  110. package/dist/lib/rop/TaskNamedProperties.js.map +1 -0
  111. package/dist/lib/rop/TaskTarget.js +19 -0
  112. package/dist/lib/rop/TaskTarget.js.map +1 -0
  113. package/dist/lib/sql/MapiEmsmdbRouteSQL.js +84 -0
  114. package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -0
  115. package/dist/lib/sql/MapiNspiRouteSQL.js +33 -0
  116. package/dist/lib/sql/MapiNspiRouteSQL.js.map +1 -0
  117. package/dist/lib/sql/index.js +7 -0
  118. package/dist/lib/sql/index.js.map +1 -0
  119. package/dist/lib/sql.js +6 -0
  120. package/dist/lib/sql.js.map +1 -0
  121. package/dist/types/BaseMapiEmsmdbRoute.d.ts +82 -0
  122. package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
  123. package/dist/types/MapiSessionManager.d.ts +130 -0
  124. package/dist/types/RopDispatcher.d.ts +17 -0
  125. package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
  126. package/dist/types/codec/BufferCursor.d.ts +78 -0
  127. package/dist/types/codec/GlobalObjectId.d.ts +11 -0
  128. package/dist/types/codec/MapiGuid.d.ts +6 -0
  129. package/dist/types/codec/MapiTimeZone.d.ts +7 -0
  130. package/dist/types/codec/PropertyValue.d.ts +77 -0
  131. package/dist/types/codec/RopBuffer.d.ts +25 -0
  132. package/dist/types/codec/TypedString.d.ts +17 -0
  133. package/dist/types/index.d.ts +94 -0
  134. package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +19 -0
  135. package/dist/types/mongo/MapiNspiRouteMongo.d.ts +13 -0
  136. package/dist/types/mongo/index.d.ts +2 -0
  137. package/dist/types/mongo.d.ts +1 -0
  138. package/dist/types/nspi/NspiBindHandler.d.ts +22 -0
  139. package/dist/types/nspi/NspiCodec.d.ts +59 -0
  140. package/dist/types/nspi/NspiGetMatchesHandler.d.ts +24 -0
  141. package/dist/types/rop/CalendarEventTarget.d.ts +29 -0
  142. package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
  143. package/dist/types/rop/ContactTarget.d.ts +29 -0
  144. package/dist/types/rop/FastTransferStream.d.ts +18 -0
  145. package/dist/types/rop/FolderTarget.d.ts +63 -0
  146. package/dist/types/rop/MeetingMessageClassHandler.d.ts +36 -0
  147. package/dist/types/rop/MessageBodyStream.d.ts +26 -0
  148. package/dist/types/rop/MessageTarget.d.ts +38 -0
  149. package/dist/types/rop/NamedPropertyRegistry.d.ts +46 -0
  150. package/dist/types/rop/PropertyResolvers.d.ts +60 -0
  151. package/dist/types/rop/RopCreateMessageHandler.d.ts +23 -0
  152. package/dist/types/rop/RopDeleteFolderHandler.d.ts +38 -0
  153. package/dist/types/rop/RopDeleteMessagesHandler.d.ts +31 -0
  154. package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +24 -0
  155. package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +24 -0
  156. package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +23 -0
  157. package/dist/types/rop/RopGetContentsTableHandler.d.ts +31 -0
  158. package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +17 -0
  159. package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +23 -0
  160. package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
  161. package/dist/types/rop/RopHandler.d.ts +67 -0
  162. package/dist/types/rop/RopLogonHandler.d.ts +31 -0
  163. package/dist/types/rop/RopOpenFolderHandler.d.ts +19 -0
  164. package/dist/types/rop/RopOpenMessageHandler.d.ts +27 -0
  165. package/dist/types/rop/RopOpenStreamHandler.d.ts +27 -0
  166. package/dist/types/rop/RopQueryRowsHandler.d.ts +36 -0
  167. package/dist/types/rop/RopReadStreamHandler.d.ts +18 -0
  168. package/dist/types/rop/RopReleaseHandler.d.ts +14 -0
  169. package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +44 -0
  170. package/dist/types/rop/RopSetColumnsHandler.d.ts +21 -0
  171. package/dist/types/rop/RopSetPropertiesHandler.d.ts +38 -0
  172. package/dist/types/rop/RopSubmitMessageHandler.d.ts +70 -0
  173. package/dist/types/rop/RopWriteStreamHandler.d.ts +21 -0
  174. package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
  175. package/dist/types/rop/TaskTarget.d.ts +24 -0
  176. package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +19 -0
  177. package/dist/types/sql/MapiNspiRouteSQL.d.ts +13 -0
  178. package/dist/types/sql/index.d.ts +2 -0
  179. package/dist/types/sql.d.ts +1 -0
  180. package/package.json +104 -0
@@ -0,0 +1,314 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import * as crypto from "crypto";
6
+ import MailComposer from "nodemailer/lib/mail-composer/index.js";
7
+ import { findOrCreateWellKnownFolder, FolderType, MessageImportance, RecipientType, scanAndRelay, } from "@rapidmx/restapi";
8
+ import { submitMeetingResponse } from "./MeetingMessageClassHandler.js";
9
+ const ROP_ID_SUBMIT_MESSAGE = 0x32;
10
+ /** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for both "the referenced handle isn't a draft
11
+ * message" and "the draft has no resolvable recipients/sender" - the same constant reused throughout this
12
+ * pragmatic subset as a generic "can't do this" signal, not a claim of exact per-condition `[MS-OXCRPC]`
13
+ * return-value-table parity. */
14
+ const ERROR_INVALID_OBJECT = 0x80070005;
15
+ // The same well-known property IDs RopSetPropertiesHandler tracks - duplicated here (rather than imported)
16
+ // since importing them would only save a handful of literals; see that file for the real documentation of what
17
+ // each means.
18
+ const PID_TAG_SUBJECT = 0x0037;
19
+ const PID_TAG_MESSAGE_CLASS = 0x001a;
20
+ const PID_TAG_DISPLAY_BCC = 0x0e02;
21
+ const PID_TAG_DISPLAY_CC = 0x0e03;
22
+ const PID_TAG_DISPLAY_TO = 0x0e04;
23
+ const PID_TAG_BODY = 0x1000;
24
+ const PID_TAG_READ_RECEIPT_REQUESTED = 0x0029;
25
+ const PID_TAG_DEFERRED_SEND_TIME = 0x3fef;
26
+ /** `PidTagMessageClass` values starting with this prefix (`IPM.Appointment`, `IPM.Appointment.*`) route through
27
+ * `submitAppointment()` instead of the ordinary mail compose/send path below - see that method's own doc
28
+ * comment. */
29
+ const MESSAGE_CLASS_APPOINTMENT_PREFIX = "IPM.Appointment";
30
+ /** `PidTagMessageClass` values starting with this prefix (`IPM.Schedule.Meeting.Resp.{Pos,Neg,Tent}`) route
31
+ * through `MeetingMessageClassHandler.submitMeetingResponse()` instead of every other path here - see that
32
+ * function's own doc comment. */
33
+ const MESSAGE_CLASS_MEETING_RESPONSE_PREFIX = "IPM.Schedule.Meeting.Resp.";
34
+ /** Splits a `PidTagDisplayTo`/`Cc`/`Bcc`-style string on the semicolons real Outlook separates recipients
35
+ * with (also tolerating commas, in case a client or test harness uses that convention instead), trimming and
36
+ * dropping empty entries. Exported since `RopSaveChangesMessageHandler.ts` reads the same accumulated
37
+ * `PidTagDisplayTo`/`Cc` draft properties to build a Calendar item's attendee list. */
38
+ export function parseAddressList(value) {
39
+ if (!value) {
40
+ return [];
41
+ }
42
+ return value
43
+ .split(/[;,]/)
44
+ .map((s) => s.trim())
45
+ .filter((s) => s.length > 0);
46
+ }
47
+ /**
48
+ * `RopSubmitMessage` (`[MS-OXOMSG]`/`[MS-OXCROPS]`): sends a composed message - the actual trigger point for
49
+ * this pragmatic subset's compose/send pipeline, since `RopSaveChangesMessage` itself does no real persistence
50
+ * (see its own doc comment). Builds a raw MIME buffer from whatever `RopSetProperties`/`RopWriteStream` calls
51
+ * accumulated on the draft handle (`Subject`, the `PidTagBody` stream or an inline `PidTagBody` property, and
52
+ * addressing - see below), via `nodemailer`'s `MailComposer` (already a dependency, used elsewhere in this
53
+ * library only to *send*, not build, MIME - this is its first use purely as a RFC 5322 serializer), then calls
54
+ * the exact same `scanAndRelay()` scan-then-relay pipeline `BaseMessageRoute.send()`/EAS's `ComposeMailCommand`
55
+ * already share, and persists a Sent Items copy (mirroring `ComposeMailCommand`'s own always-committed Sent
56
+ * Items behavior for MAPI submission specifically, since - unlike EAS's optional `SaveInSentItems` - a MAPI
57
+ * `RopSubmitMessage` call has no "don't keep a copy" option to honor).
58
+ *
59
+ * **Known, deliberate limitation - no `RopModifyRecipients` support**: real recipient rows (`[MS-OXCMSG]`
60
+ * §2.2.3.2, each with its own `PidTagEmailAddress`/`PidTagRecipientType`) are a substantial structure this
61
+ * pragmatic subset's ROP coverage doesn't include. Instead, addressing is read from `PidTagDisplayTo`/
62
+ * `DisplayCc`/`DisplayBcc` - the same semicolon-separated "cached recipient display string" properties real
63
+ * Outlook *also* always sets via `RopSetProperties` alongside `RopModifyRecipients` (as a display-only
64
+ * convenience cache). This works correctly for the common case of composing to bare, unresolved email
65
+ * addresses (nothing to resolve to a distinct display name) - the case this library's own integration tests
66
+ * exercise - but is **not** a substitute for real recipient rows: a client that resolves typed names against an
67
+ * address book before submitting would populate these fields with display names, not addresses, and this
68
+ * pragmatic subset has no way to recover a real SMTP address from a bare display name. Documented here rather
69
+ * than silently producing wrong addressing.
70
+ *
71
+ * `SubmitFlags` (`PreprocessOnly`, ...) is decoded to advance past it correctly but not honored - this
72
+ * pragmatic subset has no transport-agent preprocessing distinction to vary by flag.
73
+ *
74
+ * **`PidTagDeferredSendTime`** ("Do not deliver before"), if set to a future time via `RopSetProperties`,
75
+ * parks the message in Outbox with `Message.scheduledSendTime` set instead of relaying immediately - mirroring
76
+ * `BaseMessageRoute.send()`'s own identical branch - for `ScheduledSendJob` to relay later via this same
77
+ * `scanAndRelay()` pipeline. **`PidTagReadReceiptRequested`**, if `true`, attaches a real
78
+ * `Disposition-Notification-To` header (see `util/ReceiptUtils.ts`) and is recorded on the persisted message's
79
+ * own `requestReceipt` field - honored only when the client explicitly sets it, not this mailbox's
80
+ * `alwaysRequestReceiptInternal`/`External` defaults (those apply to the REST/webmail compose path only).
81
+ *
82
+ * **Calendar branches**: a draft whose `PidTagMessageClass` starts with `"IPM.Appointment"` is routed to
83
+ * `submitAppointment()` instead of the mail path below - see that method's own doc comment. One starting with
84
+ * `"IPM.Schedule.Meeting.Resp."` (an attendee's own accept/decline/tentative response to a meeting this server
85
+ * previously invited them to) is routed to `MeetingMessageClassHandler.submitMeetingResponse()` instead - see
86
+ * that function's own doc comment.
87
+ *
88
+ * @author Jean-Philippe Steinmetz
89
+ */
90
+ export class RopSubmitMessageHandler {
91
+ constructor() {
92
+ this.ropId = ROP_ID_SUBMIT_MESSAGE;
93
+ }
94
+ async handle(reader, writer, context) {
95
+ reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
96
+ const inputHandleIndex = reader.readUInt8();
97
+ reader.readUInt8(); // SubmitFlags - see class doc comment
98
+ const handle = context.session.handles[inputHandleIndex];
99
+ if (!handle || handle.type !== "message") {
100
+ writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
101
+ writer.writeUInt8(inputHandleIndex);
102
+ writer.writeUInt32LE(ERROR_INVALID_OBJECT);
103
+ return;
104
+ }
105
+ const properties = handle.draftProperties ?? {};
106
+ const messageClass = properties[String(PID_TAG_MESSAGE_CLASS)] ?? "IPM.Note";
107
+ if (messageClass.startsWith(MESSAGE_CLASS_APPOINTMENT_PREFIX)) {
108
+ await this.submitAppointment(handle, context, writer, inputHandleIndex);
109
+ return;
110
+ }
111
+ if (messageClass.startsWith(MESSAGE_CLASS_MEETING_RESPONSE_PREFIX)) {
112
+ await submitMeetingResponse(messageClass, properties, context);
113
+ writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
114
+ writer.writeUInt8(inputHandleIndex);
115
+ writer.writeUInt32LE(0); // ReturnValue - success, see MeetingMessageClassHandler's own doc comment
116
+ // on why every failure mode there is a silent no-op rather than surfaced here.
117
+ return;
118
+ }
119
+ const to = parseAddressList(properties[String(PID_TAG_DISPLAY_TO)]);
120
+ const cc = parseAddressList(properties[String(PID_TAG_DISPLAY_CC)]);
121
+ const bcc = parseAddressList(properties[String(PID_TAG_DISPLAY_BCC)]);
122
+ const mailbox = await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true });
123
+ const envelopeFrom = mailbox?.primarySmtpAddress;
124
+ if (!envelopeFrom || to.length + cc.length + bcc.length === 0) {
125
+ writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
126
+ writer.writeUInt8(inputHandleIndex);
127
+ writer.writeUInt32LE(ERROR_INVALID_OBJECT);
128
+ return;
129
+ }
130
+ const subject = properties[String(PID_TAG_SUBJECT)] ?? "";
131
+ const bodyText = resolveDraftBody(context, inputHandleIndex, properties);
132
+ const requestReceipt = properties[String(PID_TAG_READ_RECEIPT_REQUESTED)] === "true";
133
+ // "Do not deliver before" - a real Outlook compose option, tracked as a plain ISO-8601 string by
134
+ // RopSetPropertiesHandler.stringifyValue()'s PtypTime encoding.
135
+ const deferredSendTimeRaw = properties[String(PID_TAG_DEFERRED_SEND_TIME)];
136
+ const deferredSendTime = deferredSendTimeRaw ? new Date(deferredSendTimeRaw) : undefined;
137
+ const isDeferred = deferredSendTime !== undefined && deferredSendTime.getTime() > Date.now();
138
+ const raw = await new MailComposer({
139
+ from: envelopeFrom,
140
+ to,
141
+ cc,
142
+ bcc,
143
+ subject,
144
+ text: bodyText,
145
+ // A real Disposition-Notification-To request, mirroring BaseMessageRoute.send()'s own explicit
146
+ // Message.requestReceipt handling (see util/ReceiptUtils.ts) - honored here only when the client
147
+ // itself asked for one via PidTagReadReceiptRequested, not this mailbox's own
148
+ // alwaysRequestReceiptInternal/External defaults (those apply to the REST/webmail compose path,
149
+ // which already goes through BaseMessageRoute.send() directly).
150
+ ...(requestReceipt ? { headers: [{ key: "Disposition-Notification-To", value: envelopeFrom }] } : {}),
151
+ })
152
+ .compile()
153
+ .build();
154
+ const envelopeTo = [...to, ...cc, ...bcc];
155
+ const bodyBlobKey = `bodies/${crypto.randomUUID()}`;
156
+ const recipients = [
157
+ ...to.map((address) => ({ address, type: RecipientType.TO })),
158
+ ...cc.map((address) => ({ address, type: RecipientType.CC })),
159
+ ...bcc.map((address) => ({ address, type: RecipientType.BCC })),
160
+ ];
161
+ if (isDeferred) {
162
+ // Mirrors BaseMessageRoute.send()'s own scheduledSendTime branch: park the message in Outbox,
163
+ // unscanned/unrelayed, for the same ScheduledSendJob to pick up and relay (via this exact
164
+ // scanAndRelay() pipeline) once due - see that job's own doc comment.
165
+ await context.blobStore.put(bodyBlobKey, raw, { contentType: "message/rfc822" });
166
+ const outbox = await findOrCreateWellKnownFolder(context.folderRepo, context.folderClass, context.mailboxUid, FolderType.OUTBOX);
167
+ await context.messageRepo.create(new context.messageClass({
168
+ folderUid: outbox.uid,
169
+ mailboxUid: context.mailboxUid,
170
+ messageId: `${crypto.randomUUID()}@mapi`,
171
+ subject,
172
+ from: { address: envelopeFrom, type: RecipientType.TO },
173
+ recipients,
174
+ sentDate: new Date(),
175
+ receivedDate: new Date(),
176
+ bodyBlobKey,
177
+ bodyPreview: bodyText.slice(0, 200),
178
+ flags: { read: true, flagged: false, answered: false, forwarded: false },
179
+ importance: MessageImportance.NORMAL,
180
+ references: [],
181
+ hasAttachments: false,
182
+ scheduledSendTime: deferredSendTime,
183
+ requestReceipt,
184
+ }), { ignoreACL: true });
185
+ writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
186
+ writer.writeUInt8(inputHandleIndex);
187
+ writer.writeUInt32LE(0); // ReturnValue - success
188
+ return;
189
+ }
190
+ const { sanitizedHtmlBlobKey } = await scanAndRelay(raw, envelopeFrom, envelopeTo, context.scanPipeline, context.mailTransport, context.blobStore);
191
+ await context.blobStore.put(bodyBlobKey, raw, { contentType: "message/rfc822" });
192
+ const sentFolder = await findOrCreateWellKnownFolder(context.folderRepo, context.folderClass, context.mailboxUid, FolderType.SENT_ITEMS);
193
+ await context.messageRepo.create(new context.messageClass({
194
+ folderUid: sentFolder.uid,
195
+ mailboxUid: context.mailboxUid,
196
+ messageId: `${crypto.randomUUID()}@mapi`,
197
+ subject,
198
+ from: { address: envelopeFrom, type: RecipientType.TO },
199
+ recipients,
200
+ sentDate: new Date(),
201
+ receivedDate: new Date(),
202
+ bodyBlobKey,
203
+ sanitizedHtmlBlobKey,
204
+ bodyPreview: bodyText.slice(0, 200),
205
+ flags: { read: true, flagged: false, answered: false, forwarded: false },
206
+ importance: MessageImportance.NORMAL,
207
+ references: [],
208
+ hasAttachments: false,
209
+ requestReceipt,
210
+ }), { ignoreACL: true });
211
+ writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
212
+ writer.writeUInt8(inputHandleIndex);
213
+ writer.writeUInt32LE(0); // ReturnValue - success
214
+ }
215
+ /**
216
+ * Submits a Calendar item. The appointment itself is already persisted (`RopSaveChangesMessageHandler`
217
+ * writes the real `CalendarEvent` row at Save time, unlike a mail draft, which stays purely in-session until
218
+ * Submit) - this method's only job is notifying attendees, if any were set (via `PidTagDisplayTo`/`Cc`,
219
+ * decoded into `CalendarEvent.attendees` at Save time). No attendees means no invite to send (e.g. a private,
220
+ * non-meeting appointment) - a well-formed success response either way, since the appointment already exists.
221
+ *
222
+ * Unlike ordinary mail, there is no separate "Sent Items copy" to create - the appointment's durable copy
223
+ * *is* the `CalendarEvent` row already sitting in the organizer's own Calendar folder.
224
+ *
225
+ * The invite itself is a minimal iCalendar (`RFC 5545`) `VEVENT` with `METHOD:REQUEST` (`RFC 5546`),
226
+ * attached via `nodemailer`'s own `MailComposer` `icalEvent` option (which produces both a `text/calendar;
227
+ * method=REQUEST` MIME alternative and an `.ics` attachment - the standard dual form real invite emails use)
228
+ * - reusing the identical `scanAndRelay()` pipeline the mail path above already calls.
229
+ */
230
+ async submitAppointment(handle, context, writer, inputHandleIndex) {
231
+ const uid = handle.entityUid.startsWith("calendarEvent:") ? handle.entityUid.slice("calendarEvent:".length) : undefined;
232
+ const event = uid ? await context.calendarEventRepo.findOne(uid, { ignoreACL: true }) : undefined;
233
+ if (!event) {
234
+ writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
235
+ writer.writeUInt8(inputHandleIndex);
236
+ writer.writeUInt32LE(ERROR_INVALID_OBJECT);
237
+ return;
238
+ }
239
+ if (event.attendees.length > 0) {
240
+ const mailbox = await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true });
241
+ const envelopeFrom = mailbox?.primarySmtpAddress;
242
+ if (envelopeFrom) {
243
+ const attendeeAddresses = event.attendees.map((attendee) => attendee.address);
244
+ const ics = buildMeetingRequestIcs(event, envelopeFrom);
245
+ const raw = await new MailComposer({
246
+ from: envelopeFrom,
247
+ to: attendeeAddresses,
248
+ subject: event.title,
249
+ text: `You have been invited to: ${event.title}`,
250
+ icalEvent: { method: "REQUEST", content: ics },
251
+ })
252
+ .compile()
253
+ .build();
254
+ await scanAndRelay(raw, envelopeFrom, attendeeAddresses, context.scanPipeline, context.mailTransport, context.blobStore);
255
+ }
256
+ }
257
+ writer.writeUInt8(ROP_ID_SUBMIT_MESSAGE);
258
+ writer.writeUInt8(inputHandleIndex);
259
+ writer.writeUInt32LE(0); // ReturnValue - success
260
+ }
261
+ }
262
+ /** `YYYYMMDDTHHMMSSZ` - the `RFC 5545` "form 2" (UTC) `DATE-TIME` format every field below uses. */
263
+ function formatIcsDateUtc(date) {
264
+ return date.toISOString().replace(/[-:]/g, "").split(".")[0] + "Z";
265
+ }
266
+ /** Escapes the `RFC 5545` §3.3.11 `TEXT` value special characters (backslash, semicolon, comma, newline) - the
267
+ * only value types this minimal builder ever emits unescaped text into (`SUMMARY`/`LOCATION`). */
268
+ function escapeIcsText(value) {
269
+ return value.replace(/\\/g, "\\\\").replace(/;/g, "\\;").replace(/,/g, "\\,").replace(/\r?\n/g, "\\n");
270
+ }
271
+ /**
272
+ * Builds a minimal `RFC 5545`/`RFC 5546` `METHOD:REQUEST` iCalendar document for `event`. Deliberately not a
273
+ * general-purpose iCalendar writer (see `AutodiscoverXml.ts`'s own doc comment for the same "hand-build just
274
+ * the fields this pass needs" precedent) - no `RRULE` (recurring meeting invites are a documented gap, same as
275
+ * this pragmatic subset's other recurrence-adjacent limitations), no line-folding at the 75-octet boundary
276
+ * `RFC 5545` §3.1 technically requires (every field emitted here is short enough in practice that folding would
277
+ * never trigger), no `VTIMEZONE` block (times are always emitted as UTC `Z`-suffixed values instead).
278
+ */
279
+ function buildMeetingRequestIcs(event, organizerAddress) {
280
+ const lines = [
281
+ "BEGIN:VCALENDAR",
282
+ "PRODID:-//RapidREST//Mail//EN",
283
+ "VERSION:2.0",
284
+ "METHOD:REQUEST",
285
+ "BEGIN:VEVENT",
286
+ `UID:${event.icalUid}`,
287
+ `SEQUENCE:${event.sequence}`,
288
+ `DTSTAMP:${formatIcsDateUtc(new Date())}`,
289
+ `DTSTART:${formatIcsDateUtc(event.startDate)}`,
290
+ `DTEND:${formatIcsDateUtc(event.endDate)}`,
291
+ `SUMMARY:${escapeIcsText(event.title)}`,
292
+ ...(event.location ? [`LOCATION:${escapeIcsText(event.location)}`] : []),
293
+ `ORGANIZER:mailto:${organizerAddress}`,
294
+ ...event.attendees.map((attendee) => `ATTENDEE;RSVP=TRUE:mailto:${attendee.address}`),
295
+ "STATUS:CONFIRMED",
296
+ "END:VEVENT",
297
+ "END:VCALENDAR",
298
+ ];
299
+ return lines.join("\r\n");
300
+ }
301
+ /** Prefers a `RopWriteStream`-accumulated body (the real path a large body takes) over an inline `PidTagBody`
302
+ * set directly via `RopSetProperties` (only realistic for a short body small enough to set inline) - see
303
+ * `RopOpenStreamHandler`'s write-mode branch for how `writeTargetHandleIndex` links a stream handle back to the
304
+ * draft message handle it was opened against. */
305
+ function resolveDraftBody(context, messageHandleIndex, properties) {
306
+ for (const candidate of Object.values(context.session.handles)) {
307
+ if (candidate.type === "stream" && candidate.writeTargetHandleIndex === messageHandleIndex && candidate.writeBufferBase64) {
308
+ const raw = Buffer.from(candidate.writeBufferBase64, "base64");
309
+ return raw.toString("utf16le").replace(/\0+$/, "");
310
+ }
311
+ }
312
+ return properties[String(PID_TAG_BODY)] ?? "";
313
+ }
314
+ //# sourceMappingURL=RopSubmitMessageHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RopSubmitMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopSubmitMessageHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ const ROP_ID_WRITE_STREAM = 0x2d;
2
+ /** The well-known MAPI HRESULT `MAPI_E_INVALID_OBJECT`, reused for "the referenced handle isn't a write-mode
3
+ * stream (or doesn't exist)" - the same constant `RopReadStreamHandler` uses for its own analogous check. */
4
+ const ERROR_INVALID_OBJECT = 0x80070005;
5
+ /**
6
+ * `RopWriteStream` (`[MS-OXCPRPT]`/`[MS-OXCROPS]`): writes bytes to a stream opened in `ReadWrite`/`Create`
7
+ * mode (`RopOpenStreamHandler`'s write-mode branch - the only kind of writable stream this pragmatic subset
8
+ * ever produces, always a `RopCreateMessage` draft's `PidTagBody`). Accumulates `Data` into the stream handle's
9
+ * `writeBufferBase64` field, decode-concat-reencode each call rather than a naive string concatenation of
10
+ * per-call base64 chunks - base64 is not concatenation-safe (a chunk's padding only belongs at the true end of
11
+ * the data), so reassembling the real bytes requires decoding what's accumulated so far, appending the new raw
12
+ * bytes, and re-encoding the whole thing. `RopSaveChangesMessageHandler`/`RopSubmitMessageHandler` decode this
13
+ * buffer back to the final body text once composing is complete.
14
+ *
15
+ * Like `RopReadStream`, `[MS-OXCROPS]` documents only one combined response-buffer shape for this ROP (no
16
+ * separate Success/Failure pages) - `WrittenSize` is always present, `0` standing in for the failure case.
17
+ *
18
+ * @author Jean-Philippe Steinmetz
19
+ */
20
+ export class RopWriteStreamHandler {
21
+ constructor() {
22
+ this.ropId = ROP_ID_WRITE_STREAM;
23
+ }
24
+ handle(reader, writer, context) {
25
+ reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
26
+ const inputHandleIndex = reader.readUInt8();
27
+ const dataSize = reader.readUInt16LE();
28
+ const data = reader.readBytes(dataSize);
29
+ const handle = context.session.handles[inputHandleIndex];
30
+ if (!handle || handle.type !== "stream" || handle.writeTargetHandleIndex === undefined) {
31
+ writer.writeUInt8(ROP_ID_WRITE_STREAM);
32
+ writer.writeUInt8(inputHandleIndex);
33
+ writer.writeUInt32LE(ERROR_INVALID_OBJECT);
34
+ writer.writeUInt16LE(0); // WrittenSize - see class doc comment on why this is still written on failure
35
+ return;
36
+ }
37
+ const existing = handle.writeBufferBase64 ? Buffer.from(handle.writeBufferBase64, "base64") : Buffer.alloc(0);
38
+ handle.writeBufferBase64 = Buffer.concat([existing, data]).toString("base64");
39
+ writer.writeUInt8(ROP_ID_WRITE_STREAM);
40
+ writer.writeUInt8(inputHandleIndex);
41
+ writer.writeUInt32LE(0); // ReturnValue - success
42
+ writer.writeUInt16LE(data.length); // WrittenSize
43
+ }
44
+ }
45
+ //# sourceMappingURL=RopWriteStreamHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RopWriteStreamHandler.js","sourceRoot":"","sources":["../../../src/rop/RopWriteStreamHandler.ts"],"names":[],"mappings":"AAOA,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;6GAC6G;AAC7G,MAAM,oBAAoB,GAAG,UAAU,CAAC;AAExC;;;;;;;;;;;;;;GAcG;AACH,MAAM,OAAO,qBAAqB;IAAlC;QACoB,UAAK,GAAG,mBAAmB,CAAC;IAyBhD,CAAC;IAvBU,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,QAAQ,GAAW,MAAM,CAAC,YAAY,EAAE,CAAC;QAC/C,MAAM,IAAI,GAAW,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,gBAAgB,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,sBAAsB,KAAK,SAAS,EAAE,CAAC;YACrF,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;YACvC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;YACpC,MAAM,CAAC,aAAa,CAAC,oBAAoB,CAAC,CAAC;YAC3C,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,8EAA8E;YACvG,OAAO;QACX,CAAC;QAED,MAAM,QAAQ,GAAW,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACtH,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAE9E,MAAM,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;QACvC,MAAM,CAAC,UAAU,CAAC,gBAAgB,CAAC,CAAC;QACpC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc;IACrD,CAAC;CACJ"}
@@ -0,0 +1,29 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ /**
6
+ * The Task named-property identity table (`(PropertySet GUID, LID)` pairs) this pragmatic subset supports, per
7
+ * `[MS-OXPROPS]`/`[MS-OXOTASK]` - the exact `CalendarNamedProperties.ts` precedent, adapted for `PSETID_Task`,
8
+ * shared by `PropertyResolvers.ts` (the read side: `taskValueFor`). Read-only in this pass - see
9
+ * `TaskTarget.ts`'s own doc comment for why there's no write-side (`RopSetProperties`/`RopSaveChangesMessage`)
10
+ * counterpart yet.
11
+ */
12
+ export const PSETID_TASK = "00062003-0000-0000-c000-000000000046";
13
+ /** `PidLidTaskStatus` (`PT_LONG`) - `[MS-OXOTASK]` §2.2.2.1.5's own `olTaskNotStarted`(0)/`olTaskInProgress`(1)/
14
+ * `olTaskComplete`(2)/`olTaskWaiting`(3)/`olTaskDeferred`(4) values. This data model's `Task.completed` is a
15
+ * plain boolean with no in-progress/waiting/deferred distinction, so only `olTaskNotStarted`/`olTaskComplete`
16
+ * are ever produced - a documented, harmless approximation, the same category as `CalendarNamedProperties.ts`'s
17
+ * own `olWorkingElsewhere` gap. */
18
+ export const LID_TASK_STATUS = 0x8101;
19
+ export const TASK_STATUS_NOT_STARTED = 0;
20
+ export const TASK_STATUS_COMPLETE = 2;
21
+ /** `PidLidPercentComplete` (`PT_R8`, `[MS-OXOTASK]` §2.2.2.1.6) - `0.0`-`1.0`. No partial-progress tracking in
22
+ * this data model either, so this is always `1.0` (complete) or `0.0` (not started), mirroring
23
+ * `LID_TASK_STATUS`'s own two-value approximation. */
24
+ export const LID_PERCENT_COMPLETE = 0x8102;
25
+ /** `PidLidTaskDueDate` (`PT_SYSTIME`, `[MS-OXOTASK]` §2.2.2.2.4). */
26
+ export const LID_TASK_DUE_DATE = 0x8105;
27
+ /** `PidLidTaskComplete` (`PT_BOOLEAN`, `[MS-OXOTASK]` §2.2.2.1.9) - maps directly to `Task.completed`. */
28
+ export const LID_TASK_COMPLETE = 0x811c;
29
+ //# sourceMappingURL=TaskNamedProperties.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskNamedProperties.js","sourceRoot":"","sources":["../../../src/rop/TaskNamedProperties.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAE/E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,sCAAsC,CAAC;AAElE;;;;mCAImC;AACnC,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC;AACtC,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC;AACzC,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC;AAEtC;;sDAEsD;AACtD,MAAM,CAAC,MAAM,oBAAoB,GAAG,MAAM,CAAC;AAE3C,qEAAqE;AACrE,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAExC,0GAA0G;AAC1G,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC"}
@@ -0,0 +1,19 @@
1
+ /** Degrades to empty-looking values for a `"task:<uid>"` target whose real `Task` has since vanished
2
+ * (soft-deleted or otherwise) - the same "don't fail the whole ROP over one stale row" principle
3
+ * `MessageTarget.resolveMessageInfo`/`ContactTarget.resolveContactInfo` already apply. */
4
+ export async function resolveTaskInfo(target, taskRepo) {
5
+ const uid = target.slice("task:".length);
6
+ const task = await taskRepo.findOne(uid, { ignoreACL: true });
7
+ return {
8
+ title: task?.title ?? "",
9
+ completed: task?.completed ?? false,
10
+ dueDate: task?.dueDate,
11
+ };
12
+ }
13
+ /** Resolves the tasks directly in `folderUid`, as `"task:<uid>"` target strings, for `RopGetContentsTable`
14
+ * against a `TASKS`-type folder. */
15
+ export async function resolveFolderTasks(folderUid, taskRepo) {
16
+ const tasks = await taskRepo.find({ folderUid }, { ignoreACL: true });
17
+ return tasks.map((t) => `task:${t.uid}`);
18
+ }
19
+ //# sourceMappingURL=TaskTarget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TaskTarget.js","sourceRoot":"","sources":["../../../src/rop/TaskTarget.ts"],"names":[],"mappings":"AAwBA;;0FAE0F;AAC1F,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,MAAc,EAAE,QAAwB;IAC1E,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,IAAI,GAAqB,MAAM,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChF,OAAO;QACH,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE;QACxB,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,KAAK;QACnC,OAAO,EAAE,IAAI,EAAE,OAAO;KACzB,CAAC;AACN,CAAC;AAED;oCACoC;AACpC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,SAAiB,EAAE,QAAwB;IAChF,MAAM,KAAK,GAAW,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9E,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,84 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ ///////////////////////////////////////////////////////////////////////////////
8
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
9
+ // SPDX-License-Identifier: MPL-2.0
10
+ ///////////////////////////////////////////////////////////////////////////////
11
+ import { CalendarEventSQL, ContactSQL, FolderSQL, LabelSQL, MailboxSQL, MessageSQL, TaskSQL } from "@rapidmx/restapi/sql";
12
+ import { BaseMapiEmsmdbRoute } from "../BaseMapiEmsmdbRoute.js";
13
+ import { RopLogonHandler } from "../rop/RopLogonHandler.js";
14
+ import { RopReleaseHandler } from "../rop/RopReleaseHandler.js";
15
+ import { RopOpenFolderHandler } from "../rop/RopOpenFolderHandler.js";
16
+ import { RopGetHierarchyTableHandler } from "../rop/RopGetHierarchyTableHandler.js";
17
+ import { RopGetContentsTableHandler } from "../rop/RopGetContentsTableHandler.js";
18
+ import { RopSetColumnsHandler } from "../rop/RopSetColumnsHandler.js";
19
+ import { RopQueryRowsHandler } from "../rop/RopQueryRowsHandler.js";
20
+ import { RopOpenMessageHandler } from "../rop/RopOpenMessageHandler.js";
21
+ import { RopGetPropertiesSpecificHandler } from "../rop/RopGetPropertiesSpecificHandler.js";
22
+ import { RopOpenStreamHandler } from "../rop/RopOpenStreamHandler.js";
23
+ import { RopReadStreamHandler } from "../rop/RopReadStreamHandler.js";
24
+ import { RopCreateMessageHandler } from "../rop/RopCreateMessageHandler.js";
25
+ import { RopSetPropertiesHandler } from "../rop/RopSetPropertiesHandler.js";
26
+ import { RopWriteStreamHandler } from "../rop/RopWriteStreamHandler.js";
27
+ import { RopSaveChangesMessageHandler } from "../rop/RopSaveChangesMessageHandler.js";
28
+ import { RopSubmitMessageHandler } from "../rop/RopSubmitMessageHandler.js";
29
+ import { RopGetPropertyIdsFromNamesHandler } from "../rop/RopGetPropertyIdsFromNamesHandler.js";
30
+ import { RopDeleteMessagesHandler } from "../rop/RopDeleteMessagesHandler.js";
31
+ import { RopDeleteFolderHandler } from "../rop/RopDeleteFolderHandler.js";
32
+ import { RopFastTransferSourceCopyToHandler } from "../rop/RopFastTransferSourceCopyToHandler.js";
33
+ import { RopFastTransferSourceCopyPropertiesHandler } from "../rop/RopFastTransferSourceCopyPropertiesHandler.js";
34
+ import { RopFastTransferSourceGetBufferHandler } from "../rop/RopFastTransferSourceGetBufferHandler.js";
35
+ import { RouteDecorators } from "@rapidrest/service-core";
36
+ const { Route } = RouteDecorators;
37
+ /**
38
+ * SQL-backed concrete `BaseMapiEmsmdbRoute`, mounted at `/mapi/emsmdb`. Exported from this plugin's
39
+ * `./sql` entry point, so the server host mounts it without a wrapper class of its
40
+ * own.
41
+ *
42
+ * @author Jean-Philippe Steinmetz
43
+ */
44
+ let MapiEmsmdbRouteSQL = class MapiEmsmdbRouteSQL extends BaseMapiEmsmdbRoute {
45
+ constructor() {
46
+ super(...arguments);
47
+ this.mailboxClass = MailboxSQL;
48
+ this.folderClass = FolderSQL;
49
+ this.messageClass = MessageSQL;
50
+ this.calendarEventClass = CalendarEventSQL;
51
+ this.contactClass = ContactSQL;
52
+ this.taskClass = TaskSQL;
53
+ this.labelClass = LabelSQL;
54
+ this.ropHandlerClasses = [
55
+ RopLogonHandler,
56
+ RopReleaseHandler,
57
+ RopOpenFolderHandler,
58
+ RopGetHierarchyTableHandler,
59
+ RopGetContentsTableHandler,
60
+ RopSetColumnsHandler,
61
+ RopQueryRowsHandler,
62
+ RopOpenMessageHandler,
63
+ RopGetPropertiesSpecificHandler,
64
+ RopOpenStreamHandler,
65
+ RopReadStreamHandler,
66
+ RopCreateMessageHandler,
67
+ RopSetPropertiesHandler,
68
+ RopWriteStreamHandler,
69
+ RopSaveChangesMessageHandler,
70
+ RopSubmitMessageHandler,
71
+ RopGetPropertyIdsFromNamesHandler,
72
+ RopDeleteMessagesHandler,
73
+ RopDeleteFolderHandler,
74
+ RopFastTransferSourceCopyToHandler,
75
+ RopFastTransferSourceCopyPropertiesHandler,
76
+ RopFastTransferSourceGetBufferHandler,
77
+ ];
78
+ }
79
+ };
80
+ MapiEmsmdbRouteSQL = __decorate([
81
+ Route("/mapi/emsmdb")
82
+ ], MapiEmsmdbRouteSQL);
83
+ export { MapiEmsmdbRouteSQL };
84
+ //# sourceMappingURL=MapiEmsmdbRouteSQL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapiEmsmdbRouteSQL.js","sourceRoot":"","sources":["../../../src/sql/MapiEmsmdbRouteSQL.ts"],"names":[],"mappings":";;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC1H,OAAO,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACpF,OAAO,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,+BAA+B,EAAE,MAAM,2CAA2C,CAAC;AAC5F,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,wCAAwC,CAAC;AACtF,OAAO,EAAE,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,iCAAiC,EAAE,MAAM,6CAA6C,CAAC;AAChG,OAAO,EAAE,wBAAwB,EAAE,MAAM,oCAAoC,CAAC;AAC9E,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,EAAE,kCAAkC,EAAE,MAAM,8CAA8C,CAAC;AAClG,OAAO,EAAE,0CAA0C,EAAE,MAAM,sDAAsD,CAAC;AAClH,OAAO,EAAE,qCAAqC,EAAE,MAAM,iDAAiD,CAAC;AACxG,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC;AAElC;;;;;;GAMG;AAEI,IAAM,kBAAkB,GAAxB,MAAM,kBAAmB,SAAQ,mBAA+B;IAAhE;;QACO,iBAAY,GAAQ,UAAU,CAAC;QAC/B,gBAAW,GAAQ,SAAS,CAAC;QAC7B,iBAAY,GAAQ,UAAU,CAAC;QAC/B,uBAAkB,GAAQ,gBAAgB,CAAC;QAC3C,iBAAY,GAAQ,UAAU,CAAC;QAC/B,cAAS,GAAQ,OAAO,CAAC;QACzB,eAAU,GAAQ,QAAQ,CAAC;QAC3B,sBAAiB,GAAU;YACjC,eAAe;YACf,iBAAiB;YACjB,oBAAoB;YACpB,2BAA2B;YAC3B,0BAA0B;YAC1B,oBAAoB;YACpB,mBAAmB;YACnB,qBAAqB;YACrB,+BAA+B;YAC/B,oBAAoB;YACpB,oBAAoB;YACpB,uBAAuB;YACvB,uBAAuB;YACvB,qBAAqB;YACrB,4BAA4B;YAC5B,uBAAuB;YACvB,iCAAiC;YACjC,wBAAwB;YACxB,sBAAsB;YACtB,kCAAkC;YAClC,0CAA0C;YAC1C,qCAAqC;SACxC,CAAC;IACN,CAAC;CAAA,CAAA;AAhCY,kBAAkB;IAD9B,KAAK,CAAC,cAAc,CAAC;GACT,kBAAkB,CAgC9B"}
@@ -0,0 +1,33 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ ///////////////////////////////////////////////////////////////////////////////
8
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
9
+ // SPDX-License-Identifier: MPL-2.0
10
+ ///////////////////////////////////////////////////////////////////////////////
11
+ import { ContactSQL, MailboxSQL } from "@rapidmx/restapi/sql";
12
+ import { BaseMapiNspiRoute } from "../BaseMapiNspiRoute.js";
13
+ import { RouteDecorators } from "@rapidrest/service-core";
14
+ const { Route } = RouteDecorators;
15
+ /**
16
+ * SQL-backed concrete `BaseMapiNspiRoute`, mounted at `/mapi/nspi`. Exported from this plugin's
17
+ * `./sql` entry point, so the server host mounts it without a wrapper class of its
18
+ * own.
19
+ *
20
+ * @author Jean-Philippe Steinmetz
21
+ */
22
+ let MapiNspiRouteSQL = class MapiNspiRouteSQL extends BaseMapiNspiRoute {
23
+ constructor() {
24
+ super(...arguments);
25
+ this.mailboxClass = MailboxSQL;
26
+ this.contactClass = ContactSQL;
27
+ }
28
+ };
29
+ MapiNspiRouteSQL = __decorate([
30
+ Route("/mapi/nspi")
31
+ ], MapiNspiRouteSQL);
32
+ export { MapiNspiRouteSQL };
33
+ //# sourceMappingURL=MapiNspiRouteSQL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapiNspiRouteSQL.js","sourceRoot":"","sources":["../../../src/sql/MapiNspiRouteSQL.ts"],"names":[],"mappings":";;;;;;AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,MAAM,EAAE,KAAK,EAAE,GAAG,eAAe,CAAC;AAElC;;;;;;GAMG;AAEI,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,iBAA6B;IAA5D;;QACO,iBAAY,GAAQ,UAAU,CAAC;QAC/B,iBAAY,GAAQ,UAAU,CAAC;IAC7C,CAAC;CAAA,CAAA;AAHY,gBAAgB;IAD5B,KAAK,CAAC,YAAY,CAAC;GACP,gBAAgB,CAG5B"}
@@ -0,0 +1,7 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ export * from "./MapiEmsmdbRouteSQL.js";
6
+ export * from "./MapiNspiRouteSQL.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sql/index.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
@@ -0,0 +1,6 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ export * from "./sql/index.js";
6
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,cAAc,gBAAgB,CAAC"}