@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.
Files changed (204) hide show
  1. package/LICENSE +382 -0
  2. package/README.md +60 -0
  3. package/dist/lib/BaseMapiEmsmdbRoute.js +489 -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 +475 -0
  8. package/dist/lib/MapiSessionManager.js.map +1 -0
  9. package/dist/lib/RegexPatternUtils.js +30 -0
  10. package/dist/lib/RegexPatternUtils.js.map +1 -0
  11. package/dist/lib/RopDispatcher.js +145 -0
  12. package/dist/lib/RopDispatcher.js.map +1 -0
  13. package/dist/lib/codec/AppointmentRecurrence.js +315 -0
  14. package/dist/lib/codec/AppointmentRecurrence.js.map +1 -0
  15. package/dist/lib/codec/BufferCursor.js +242 -0
  16. package/dist/lib/codec/BufferCursor.js.map +1 -0
  17. package/dist/lib/codec/GlobalObjectId.js +98 -0
  18. package/dist/lib/codec/GlobalObjectId.js.map +1 -0
  19. package/dist/lib/codec/MapiGuid.js +41 -0
  20. package/dist/lib/codec/MapiGuid.js.map +1 -0
  21. package/dist/lib/codec/MapiTimeZone.js +126 -0
  22. package/dist/lib/codec/MapiTimeZone.js.map +1 -0
  23. package/dist/lib/codec/PropertyValue.js +240 -0
  24. package/dist/lib/codec/PropertyValue.js.map +1 -0
  25. package/dist/lib/codec/RopBuffer.js +38 -0
  26. package/dist/lib/codec/RopBuffer.js.map +1 -0
  27. package/dist/lib/codec/TypedString.js +54 -0
  28. package/dist/lib/codec/TypedString.js.map +1 -0
  29. package/dist/lib/index.js +99 -0
  30. package/dist/lib/index.js.map +1 -0
  31. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js +85 -0
  32. package/dist/lib/mongo/MapiEmsmdbRouteMongo.js.map +1 -0
  33. package/dist/lib/mongo/MapiNspiRouteMongo.js +33 -0
  34. package/dist/lib/mongo/MapiNspiRouteMongo.js.map +1 -0
  35. package/dist/lib/mongo/index.js +7 -0
  36. package/dist/lib/mongo/index.js.map +1 -0
  37. package/dist/lib/mongo.js +6 -0
  38. package/dist/lib/mongo.js.map +1 -0
  39. package/dist/lib/nspi/NspiBindHandler.js +54 -0
  40. package/dist/lib/nspi/NspiBindHandler.js.map +1 -0
  41. package/dist/lib/nspi/NspiCodec.js +106 -0
  42. package/dist/lib/nspi/NspiCodec.js.map +1 -0
  43. package/dist/lib/nspi/NspiGetMatchesHandler.js +142 -0
  44. package/dist/lib/nspi/NspiGetMatchesHandler.js.map +1 -0
  45. package/dist/lib/rop/AddressList.js +114 -0
  46. package/dist/lib/rop/AddressList.js.map +1 -0
  47. package/dist/lib/rop/CalendarEventTarget.js +30 -0
  48. package/dist/lib/rop/CalendarEventTarget.js.map +1 -0
  49. package/dist/lib/rop/CalendarNamedProperties.js +57 -0
  50. package/dist/lib/rop/CalendarNamedProperties.js.map +1 -0
  51. package/dist/lib/rop/ContactTarget.js +19 -0
  52. package/dist/lib/rop/ContactTarget.js.map +1 -0
  53. package/dist/lib/rop/ContentsTable.js +60 -0
  54. package/dist/lib/rop/ContentsTable.js.map +1 -0
  55. package/dist/lib/rop/ExecuteBudget.js +82 -0
  56. package/dist/lib/rop/ExecuteBudget.js.map +1 -0
  57. package/dist/lib/rop/FastTransferStream.js +195 -0
  58. package/dist/lib/rop/FastTransferStream.js.map +1 -0
  59. package/dist/lib/rop/FolderTarget.js +118 -0
  60. package/dist/lib/rop/FolderTarget.js.map +1 -0
  61. package/dist/lib/rop/HandleDataCache.js +412 -0
  62. package/dist/lib/rop/HandleDataCache.js.map +1 -0
  63. package/dist/lib/rop/MeetingMessageClassHandler.js +241 -0
  64. package/dist/lib/rop/MeetingMessageClassHandler.js.map +1 -0
  65. package/dist/lib/rop/MessageBodyStream.js +68 -0
  66. package/dist/lib/rop/MessageBodyStream.js.map +1 -0
  67. package/dist/lib/rop/MessageTarget.js +57 -0
  68. package/dist/lib/rop/MessageTarget.js.map +1 -0
  69. package/dist/lib/rop/NamedPropertyRegistry.js +69 -0
  70. package/dist/lib/rop/NamedPropertyRegistry.js.map +1 -0
  71. package/dist/lib/rop/PropertyResolvers.js +353 -0
  72. package/dist/lib/rop/PropertyResolvers.js.map +1 -0
  73. package/dist/lib/rop/RepoPaging.js +54 -0
  74. package/dist/lib/rop/RepoPaging.js.map +1 -0
  75. package/dist/lib/rop/RestapiRules.js +52 -0
  76. package/dist/lib/rop/RestapiRules.js.map +1 -0
  77. package/dist/lib/rop/RopCreateMessageHandler.js +55 -0
  78. package/dist/lib/rop/RopCreateMessageHandler.js.map +1 -0
  79. package/dist/lib/rop/RopDeleteFolderHandler.js +174 -0
  80. package/dist/lib/rop/RopDeleteFolderHandler.js.map +1 -0
  81. package/dist/lib/rop/RopDeleteMessagesHandler.js +110 -0
  82. package/dist/lib/rop/RopDeleteMessagesHandler.js.map +1 -0
  83. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js +61 -0
  84. package/dist/lib/rop/RopFastTransferSourceCopyPropertiesHandler.js.map +1 -0
  85. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js +60 -0
  86. package/dist/lib/rop/RopFastTransferSourceCopyToHandler.js.map +1 -0
  87. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js +76 -0
  88. package/dist/lib/rop/RopFastTransferSourceGetBufferHandler.js.map +1 -0
  89. package/dist/lib/rop/RopGetContentsTableHandler.js +55 -0
  90. package/dist/lib/rop/RopGetContentsTableHandler.js.map +1 -0
  91. package/dist/lib/rop/RopGetHierarchyTableHandler.js +42 -0
  92. package/dist/lib/rop/RopGetHierarchyTableHandler.js.map +1 -0
  93. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js +56 -0
  94. package/dist/lib/rop/RopGetPropertiesSpecificHandler.js.map +1 -0
  95. package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js +92 -0
  96. package/dist/lib/rop/RopGetPropertyIdsFromNamesHandler.js.map +1 -0
  97. package/dist/lib/rop/RopHandler.js +6 -0
  98. package/dist/lib/rop/RopHandler.js.map +1 -0
  99. package/dist/lib/rop/RopLogonHandler.js +135 -0
  100. package/dist/lib/rop/RopLogonHandler.js.map +1 -0
  101. package/dist/lib/rop/RopOpenFolderHandler.js +48 -0
  102. package/dist/lib/rop/RopOpenFolderHandler.js.map +1 -0
  103. package/dist/lib/rop/RopOpenMessageHandler.js +83 -0
  104. package/dist/lib/rop/RopOpenMessageHandler.js.map +1 -0
  105. package/dist/lib/rop/RopOpenStreamHandler.js +84 -0
  106. package/dist/lib/rop/RopOpenStreamHandler.js.map +1 -0
  107. package/dist/lib/rop/RopQueryRowsHandler.js +120 -0
  108. package/dist/lib/rop/RopQueryRowsHandler.js.map +1 -0
  109. package/dist/lib/rop/RopReadStreamHandler.js +73 -0
  110. package/dist/lib/rop/RopReadStreamHandler.js.map +1 -0
  111. package/dist/lib/rop/RopReleaseHandler.js +23 -0
  112. package/dist/lib/rop/RopReleaseHandler.js.map +1 -0
  113. package/dist/lib/rop/RopSaveChangesMessageHandler.js +269 -0
  114. package/dist/lib/rop/RopSaveChangesMessageHandler.js.map +1 -0
  115. package/dist/lib/rop/RopSetColumnsHandler.js +50 -0
  116. package/dist/lib/rop/RopSetColumnsHandler.js.map +1 -0
  117. package/dist/lib/rop/RopSetPropertiesHandler.js +173 -0
  118. package/dist/lib/rop/RopSetPropertiesHandler.js.map +1 -0
  119. package/dist/lib/rop/RopSubmitMessageHandler.js +342 -0
  120. package/dist/lib/rop/RopSubmitMessageHandler.js.map +1 -0
  121. package/dist/lib/rop/RopWriteStreamHandler.js +72 -0
  122. package/dist/lib/rop/RopWriteStreamHandler.js.map +1 -0
  123. package/dist/lib/rop/TaskNamedProperties.js +29 -0
  124. package/dist/lib/rop/TaskNamedProperties.js.map +1 -0
  125. package/dist/lib/rop/TaskTarget.js +15 -0
  126. package/dist/lib/rop/TaskTarget.js.map +1 -0
  127. package/dist/lib/rop/TransportSend.js +16 -0
  128. package/dist/lib/rop/TransportSend.js.map +1 -0
  129. package/dist/lib/sql/MapiEmsmdbRouteSQL.js +85 -0
  130. package/dist/lib/sql/MapiEmsmdbRouteSQL.js.map +1 -0
  131. package/dist/lib/sql/MapiNspiRouteSQL.js +33 -0
  132. package/dist/lib/sql/MapiNspiRouteSQL.js.map +1 -0
  133. package/dist/lib/sql/index.js +7 -0
  134. package/dist/lib/sql/index.js.map +1 -0
  135. package/dist/lib/sql.js +6 -0
  136. package/dist/lib/sql.js.map +1 -0
  137. package/dist/types/BaseMapiEmsmdbRoute.d.ts +139 -0
  138. package/dist/types/BaseMapiNspiRoute.d.ts +38 -0
  139. package/dist/types/MapiSessionManager.d.ts +285 -0
  140. package/dist/types/RegexPatternUtils.d.ts +14 -0
  141. package/dist/types/RopDispatcher.d.ts +53 -0
  142. package/dist/types/codec/AppointmentRecurrence.d.ts +14 -0
  143. package/dist/types/codec/BufferCursor.d.ts +92 -0
  144. package/dist/types/codec/GlobalObjectId.d.ts +15 -0
  145. package/dist/types/codec/MapiGuid.d.ts +6 -0
  146. package/dist/types/codec/MapiTimeZone.d.ts +7 -0
  147. package/dist/types/codec/PropertyValue.d.ts +87 -0
  148. package/dist/types/codec/RopBuffer.d.ts +32 -0
  149. package/dist/types/codec/TypedString.d.ts +17 -0
  150. package/dist/types/index.d.ts +94 -0
  151. package/dist/types/mongo/MapiEmsmdbRouteMongo.d.ts +20 -0
  152. package/dist/types/mongo/MapiNspiRouteMongo.d.ts +13 -0
  153. package/dist/types/mongo/index.d.ts +2 -0
  154. package/dist/types/mongo.d.ts +1 -0
  155. package/dist/types/nspi/NspiBindHandler.d.ts +22 -0
  156. package/dist/types/nspi/NspiCodec.d.ts +59 -0
  157. package/dist/types/nspi/NspiGetMatchesHandler.d.ts +26 -0
  158. package/dist/types/rop/AddressList.d.ts +48 -0
  159. package/dist/types/rop/CalendarEventTarget.d.ts +33 -0
  160. package/dist/types/rop/CalendarNamedProperties.d.ts +37 -0
  161. package/dist/types/rop/ContactTarget.d.ts +29 -0
  162. package/dist/types/rop/ContentsTable.d.ts +16 -0
  163. package/dist/types/rop/ExecuteBudget.d.ts +48 -0
  164. package/dist/types/rop/FastTransferStream.d.ts +57 -0
  165. package/dist/types/rop/FolderTarget.d.ts +64 -0
  166. package/dist/types/rop/HandleDataCache.d.ts +145 -0
  167. package/dist/types/rop/MeetingMessageClassHandler.d.ts +30 -0
  168. package/dist/types/rop/MessageBodyStream.d.ts +35 -0
  169. package/dist/types/rop/MessageTarget.d.ts +45 -0
  170. package/dist/types/rop/NamedPropertyRegistry.d.ts +50 -0
  171. package/dist/types/rop/PropertyResolvers.d.ts +86 -0
  172. package/dist/types/rop/RepoPaging.d.ts +30 -0
  173. package/dist/types/rop/RestapiRules.d.ts +32 -0
  174. package/dist/types/rop/RopCreateMessageHandler.d.ts +24 -0
  175. package/dist/types/rop/RopDeleteFolderHandler.d.ts +53 -0
  176. package/dist/types/rop/RopDeleteMessagesHandler.d.ts +43 -0
  177. package/dist/types/rop/RopFastTransferSourceCopyPropertiesHandler.d.ts +25 -0
  178. package/dist/types/rop/RopFastTransferSourceCopyToHandler.d.ts +25 -0
  179. package/dist/types/rop/RopFastTransferSourceGetBufferHandler.d.ts +22 -0
  180. package/dist/types/rop/RopGetContentsTableHandler.d.ts +25 -0
  181. package/dist/types/rop/RopGetHierarchyTableHandler.d.ts +18 -0
  182. package/dist/types/rop/RopGetPropertiesSpecificHandler.d.ts +26 -0
  183. package/dist/types/rop/RopGetPropertyIdsFromNamesHandler.d.ts +23 -0
  184. package/dist/types/rop/RopHandler.d.ts +106 -0
  185. package/dist/types/rop/RopLogonHandler.d.ts +31 -0
  186. package/dist/types/rop/RopOpenFolderHandler.d.ts +20 -0
  187. package/dist/types/rop/RopOpenMessageHandler.d.ts +28 -0
  188. package/dist/types/rop/RopOpenStreamHandler.d.ts +28 -0
  189. package/dist/types/rop/RopQueryRowsHandler.d.ts +43 -0
  190. package/dist/types/rop/RopReadStreamHandler.d.ts +20 -0
  191. package/dist/types/rop/RopReleaseHandler.d.ts +15 -0
  192. package/dist/types/rop/RopSaveChangesMessageHandler.d.ts +59 -0
  193. package/dist/types/rop/RopSetColumnsHandler.d.ts +21 -0
  194. package/dist/types/rop/RopSetPropertiesHandler.d.ts +38 -0
  195. package/dist/types/rop/RopSubmitMessageHandler.d.ts +80 -0
  196. package/dist/types/rop/RopWriteStreamHandler.d.ts +31 -0
  197. package/dist/types/rop/TaskNamedProperties.d.ts +24 -0
  198. package/dist/types/rop/TaskTarget.d.ts +24 -0
  199. package/dist/types/rop/TransportSend.d.ts +10 -0
  200. package/dist/types/sql/MapiEmsmdbRouteSQL.d.ts +20 -0
  201. package/dist/types/sql/MapiNspiRouteSQL.d.ts +13 -0
  202. package/dist/types/sql/index.d.ts +2 -0
  203. package/dist/types/sql.d.ts +1 -0
  204. package/package.json +104 -0
@@ -0,0 +1,353 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { encodeAppointmentRecurrence } from "../codec/AppointmentRecurrence.js";
6
+ import { BufferWriter } from "../codec/BufferCursor.js";
7
+ import { encodeTimeZoneStruct } from "../codec/MapiTimeZone.js";
8
+ import { PropertyType, writePropertyValue } from "../codec/PropertyValue.js";
9
+ import { BUSY_STATUS_CODES, LID_APPOINTMENT_END_WHOLE, LID_APPOINTMENT_RECUR, LID_APPOINTMENT_START_WHOLE, LID_BUSY_STATUS, LID_LOCATION, LID_RECURRING, LID_REMINDER_DELTA, LID_REMINDER_SET, LID_RESPONSE_STATUS, LID_TIME_ZONE_STRUCT, PSETID_APPOINTMENT, PSETID_COMMON, RESPONSE_STATUS_CODES, RESPONSE_STATUS_NONE, RESPONSE_STATUS_ORGANIZED, } from "./CalendarNamedProperties.js";
10
+ import { resolveCalendarEventInfo } from "./CalendarEventTarget.js";
11
+ import { resolveContactInfo } from "./ContactTarget.js";
12
+ import { assignOrGetFid, resolveFolderInfo } from "./FolderTarget.js";
13
+ import { assignOrGetMid, resolveMessageInfo } from "./MessageTarget.js";
14
+ import { resolveNamedProperty } from "./NamedPropertyRegistry.js";
15
+ import { LID_PERCENT_COMPLETE, LID_TASK_COMPLETE, LID_TASK_DUE_DATE, LID_TASK_STATUS, PSETID_TASK, TASK_STATUS_COMPLETE, TASK_STATUS_NOT_STARTED, } from "./TaskNamedProperties.js";
16
+ import { resolveTaskInfo } from "./TaskTarget.js";
17
+ // Well-known folder property IDs this pragmatic subset supports - the small set a real client needs to render
18
+ // a folder-hierarchy view. Add more as a real need arises, not speculatively.
19
+ const PID_TAG_DISPLAY_NAME = 0x3001;
20
+ const PID_TAG_FOLDER_ID = 0x6748;
21
+ const PID_TAG_CONTENT_COUNT = 0x3602;
22
+ const PID_TAG_CONTENT_UNREAD_COUNT = 0x3603;
23
+ const PID_TAG_SUBFOLDERS = 0x360a;
24
+ // Well-known message property IDs this pragmatic subset supports - the small set a real client needs to render
25
+ // a message list or a single message's metadata.
26
+ const PID_TAG_SUBJECT = 0x0037;
27
+ const PID_TAG_MESSAGE_FLAGS = 0x0e07;
28
+ const PID_TAG_HAS_ATTACHMENTS = 0x0e1b;
29
+ const PID_TAG_MESSAGE_DELIVERY_TIME = 0x0e06;
30
+ const PID_TAG_MID = 0x674a;
31
+ /** `MSGFLAG_READ`, the one `PidTagMessageFlags` bit this pragmatic subset ever sets. */
32
+ const MSGFLAG_READ = 0x01;
33
+ /** `PidNameKeywords` ([MS-OXPROPS] "Keywords") - Outlook's Categories feature, a `Kind=name` named property
34
+ * (unlike every other named property this pragmatic subset resolves, all `Kind=lid` - see
35
+ * `NamedPropertyRegistry.ts`'s own `PropertyName` shape for why both kinds are supported). Maps directly onto
36
+ * this data model's Gmail-style `Message.labelUids`: Outlook only understands free-text category names, not a
37
+ * `Label.uid` reference, so `resolvePropertyValues` resolves each uid to its `Label.name` before this property
38
+ * is ever read. `PT_MV_UNICODE` (`PtypMultipleString` in this codebase's own enum naming). */
39
+ const PSETID_PUBLIC_STRINGS = "00020329-0000-0000-c000-000000000046";
40
+ const NAME_KEYWORDS = "Keywords";
41
+ // Well-known Contact property IDs this pragmatic subset supports - all plain (non-named) PidTags, per
42
+ // [MS-OXOCNTC], since a Contact needs no PSETID/LID lookup the way Calendar/Task properties do.
43
+ const PID_TAG_GIVEN_NAME = 0x3a06;
44
+ const PID_TAG_SURNAME = 0x3a11;
45
+ const PID_TAG_EMAIL_ADDRESS = 0x3003;
46
+ const PID_TAG_BUSINESS_TELEPHONE_NUMBER = 0x3a08;
47
+ const PID_TAG_COMPANY_NAME = 0x3a16;
48
+ const PID_TAG_TITLE = 0x3a17;
49
+ // Calendar named-property identity (`(PropertySet GUID, LID)` pairs) this pragmatic subset supports - see
50
+ // CalendarNamedProperties.ts's own doc comment. A calendar item's property IDs `>= 0x8000` are resolved back
51
+ // to one of these via `NamedPropertyRegistry.resolveNamedProperty` before this switch can run, since MAPI has
52
+ // no fixed numeric ID for any of them the way `PidTagSubject` has one.
53
+ /** A type-appropriate zero/empty value for a requested property this handler has no real data for - keeps
54
+ * `StandardPropertyRow` encoding valid (a real value of the right type, per `writePropertyValue`'s
55
+ * expectations) without needing to model every property a client could ever ask for. Shared by
56
+ * `RopQueryRowsHandler` (table rows) and `RopGetPropertiesSpecificHandler` (single-object property fetch). */
57
+ export function defaultValueForType(propertyType) {
58
+ switch (propertyType) {
59
+ case PropertyType.PtypBoolean:
60
+ return false;
61
+ case PropertyType.PtypInteger16:
62
+ case PropertyType.PtypInteger32:
63
+ case PropertyType.PtypFloating32:
64
+ case PropertyType.PtypFloating64:
65
+ return 0;
66
+ case PropertyType.PtypInteger64:
67
+ return 0n;
68
+ case PropertyType.PtypTime:
69
+ return new Date(0);
70
+ case PropertyType.PtypGuid:
71
+ return "00000000-0000-0000-0000-000000000000";
72
+ case PropertyType.PtypBinary:
73
+ return Buffer.alloc(0);
74
+ case PropertyType.PtypMultipleInteger32:
75
+ case PropertyType.PtypMultipleString:
76
+ case PropertyType.PtypMultipleString8:
77
+ case PropertyType.PtypMultipleBinary:
78
+ return [];
79
+ case PropertyType.PtypString:
80
+ case PropertyType.PtypString8:
81
+ default:
82
+ return "";
83
+ }
84
+ }
85
+ /**
86
+ * Encodes `value` as `propertyType` into `writer`, falling back to `defaultValueForType(propertyType)`'s own
87
+ * value if that throws - `RopQueryRowsHandler`/`RopGetPropertiesSpecificHandler`'s "an unsupported property
88
+ * falls back to a type-appropriate default, never an error" contract (see their own doc comments) was only true
89
+ * for a `propertyId` this codebase has no data for; it wasn't actually true for a `propertyId` it resolves fine
90
+ * whose value just doesn't fit the *client's own requested* `propertyType` for that column (`SetColumns` never
91
+ * cross-checks a column's declared type against what its resolver actually returns) - e.g. `PidTagSubject`'s
92
+ * plain string against a client-requested `PtypGuid` column throws inside `encodeGuid()`, well downstream of the
93
+ * `xxxValueFor` switch that only ever looks at `propertyId`. That escaped all the way to `RopDispatcher` and
94
+ * failed the *whole* ROP (discarding every row `RopQueryRows` had already built in that call) instead of just
95
+ * this one column degrading, the same as an actually-unmodeled property already does.
96
+ *
97
+ * Writes into a scratch `BufferWriter` first and only copies its bytes into `writer` once a whole value's worth
98
+ * encoded cleanly - several `PropertyType` cases (`PtypBinary`, every `PtypMultiple*`) write more than one field
99
+ * per value, and a value of the wrong *shape* (not just the wrong type) can throw partway through one of those,
100
+ * which would otherwise leave stray, wrongly-sized bytes in `writer` ahead of every column/row that follows -
101
+ * silent wire-format corruption worse than the original failure.
102
+ *
103
+ * `defaultValueForType(propertyType)` is built to match `writePropertyValue`'s own cases exactly, so the
104
+ * fallback only fails too when `propertyType` is a value neither function's `switch` recognizes at all (there's
105
+ * no way to encode a wire type this codec doesn't implement, and `RopSetColumns` never validates `propertyType`
106
+ * against the known enum) - that still throws, exactly as it already did before this function existed, since a
107
+ * genuinely unknown type isn't the "known type, mismatched value" case this exists to fix.
108
+ */
109
+ export function writePropertyValueSafely(writer, propertyType, value) {
110
+ const scratch = new BufferWriter();
111
+ try {
112
+ writePropertyValue(scratch, propertyType, value);
113
+ }
114
+ catch {
115
+ const fallback = new BufferWriter();
116
+ writePropertyValue(fallback, propertyType, defaultValueForType(propertyType));
117
+ writer.writeBytes(fallback.toBuffer());
118
+ return;
119
+ }
120
+ writer.writeBytes(scratch.toBuffer());
121
+ }
122
+ /** Resolves one requested property's value for a `"folder:<uid>"`/`"virtual:<name>"` target. */
123
+ export function folderValueFor(session, propertyId, propertyType, target, info) {
124
+ switch (propertyId) {
125
+ case PID_TAG_DISPLAY_NAME:
126
+ return info.displayName;
127
+ case PID_TAG_FOLDER_ID:
128
+ return BigInt(assignOrGetFid(session, target));
129
+ case PID_TAG_CONTENT_COUNT:
130
+ return info.totalCount;
131
+ case PID_TAG_CONTENT_UNREAD_COUNT:
132
+ return info.unreadCount;
133
+ case PID_TAG_SUBFOLDERS:
134
+ return info.hasChildren;
135
+ default:
136
+ return defaultValueForType(propertyType);
137
+ }
138
+ }
139
+ /** Resolves one requested property's value for a `"message:<uid>"` target. `labelNames` is this message's own
140
+ * `labelUids` already resolved to display names (see `resolvePropertyValues`'s own doc comment) - a plain
141
+ * parameter rather than a repo lookup here, since this function (like every other `xxxValueFor`) is
142
+ * synchronous and can't do its own async DB access. */
143
+ export function messageValueFor(session, propertyId, propertyType, target, info, labelNames = []) {
144
+ switch (propertyId) {
145
+ case PID_TAG_SUBJECT:
146
+ return info.subject;
147
+ case PID_TAG_MESSAGE_FLAGS:
148
+ return info.read ? MSGFLAG_READ : 0;
149
+ case PID_TAG_HAS_ATTACHMENTS:
150
+ return info.hasAttachments;
151
+ case PID_TAG_MESSAGE_DELIVERY_TIME:
152
+ return info.receivedDate;
153
+ case PID_TAG_MID:
154
+ return BigInt(assignOrGetMid(session, target));
155
+ default: {
156
+ if (propertyId >= 0x8000) {
157
+ const named = resolveNamedProperty(session, propertyId);
158
+ if (named && named.kind === "name" && named.name === NAME_KEYWORDS && named.guid.toLowerCase() === PSETID_PUBLIC_STRINGS) {
159
+ return labelNames;
160
+ }
161
+ }
162
+ return defaultValueForType(propertyType);
163
+ }
164
+ }
165
+ }
166
+ /** Resolves one requested property's value for a `"calendarEvent:<uid>"` target. Almost every Appointment
167
+ * property is a *named* property (`PidLid*`, no fixed numeric ID) rather than a plain `PidTag*` - a property ID
168
+ * `>= 0x8000` is resolved back to its `(PropertySet GUID, LID)` identity via `resolveNamedProperty` before this
169
+ * can dispatch on it (see `NamedPropertyRegistry.ts`'s own doc comment and the architecture plan's "Calendar
170
+ * support" section for the full named-property table this switch implements). */
171
+ export function calendarEventValueFor(session, propertyId, propertyType, target, info, callerAddress) {
172
+ if (propertyId === PID_TAG_SUBJECT) {
173
+ return info.title;
174
+ }
175
+ if (propertyId === PID_TAG_MID) {
176
+ return BigInt(assignOrGetMid(session, target));
177
+ }
178
+ if (propertyId < 0x8000) {
179
+ return defaultValueForType(propertyType);
180
+ }
181
+ const namedProperty = resolveNamedProperty(session, propertyId);
182
+ if (!namedProperty || namedProperty.kind !== "lid") {
183
+ return defaultValueForType(propertyType);
184
+ }
185
+ const guid = namedProperty.guid.toLowerCase();
186
+ const isAppointmentProperty = guid === PSETID_APPOINTMENT;
187
+ const isCommonProperty = guid === PSETID_COMMON;
188
+ switch (namedProperty.lid) {
189
+ case LID_LOCATION:
190
+ return isAppointmentProperty ? (info.location ?? "") : defaultValueForType(propertyType);
191
+ case LID_APPOINTMENT_START_WHOLE:
192
+ return isAppointmentProperty ? info.startDate : defaultValueForType(propertyType);
193
+ case LID_APPOINTMENT_END_WHOLE:
194
+ return isAppointmentProperty ? info.endDate : defaultValueForType(propertyType);
195
+ case LID_BUSY_STATUS:
196
+ return isAppointmentProperty ? BUSY_STATUS_CODES[info.busyStatus] : defaultValueForType(propertyType);
197
+ case LID_RECURRING:
198
+ return isAppointmentProperty ? info.recurrenceRule !== undefined : defaultValueForType(propertyType);
199
+ case LID_APPOINTMENT_RECUR:
200
+ return isAppointmentProperty && info.recurrenceRule
201
+ ? encodeAppointmentRecurrence(info.recurrenceRule, info.startDate, info.endDate)
202
+ : defaultValueForType(propertyType);
203
+ case LID_TIME_ZONE_STRUCT:
204
+ return isAppointmentProperty ? encodeTimeZoneStruct(info.timezone, info.startDate) : defaultValueForType(propertyType);
205
+ case LID_RESPONSE_STATUS:
206
+ return isAppointmentProperty ? responseStatusFor(info, callerAddress) : defaultValueForType(propertyType);
207
+ case LID_REMINDER_SET:
208
+ return isCommonProperty ? info.reminderMinutesBeforeStart != null : defaultValueForType(propertyType);
209
+ case LID_REMINDER_DELTA:
210
+ return isCommonProperty ? (info.reminderMinutesBeforeStart ?? 0) : defaultValueForType(propertyType);
211
+ default:
212
+ return defaultValueForType(propertyType);
213
+ }
214
+ }
215
+ /** The caller's own `PidLidResponseStatus` value: `respOrganized` if the caller mailbox *is* this event's
216
+ * organizer, else the matching `Attendee.responseStatus` (by address, case-insensitive), else `respNone` if the
217
+ * caller isn't party to this event at all (e.g. a shared/delegate calendar view). */
218
+ function responseStatusFor(info, callerAddress) {
219
+ if (callerAddress && info.organizerAddress.toLowerCase() === callerAddress.toLowerCase()) {
220
+ return RESPONSE_STATUS_ORGANIZED;
221
+ }
222
+ const attendee = info.attendees.find((a) => a.address.toLowerCase() === callerAddress.toLowerCase());
223
+ return attendee ? RESPONSE_STATUS_CODES[attendee.responseStatus] : RESPONSE_STATUS_NONE;
224
+ }
225
+ /** Resolves one requested property's value for a `"contact:<uid>"` target - a `Folder` of type `CONTACTS`'s
226
+ * content-table rows/opened items. Every field here is a plain fixed `PidTag` (`[MS-OXOCNTC]`), unlike Calendar/
227
+ * Task's named-property tables, since Contact's own well-known fields all have real numeric IDs. */
228
+ export function contactValueFor(session, propertyId, propertyType, target, info) {
229
+ switch (propertyId) {
230
+ case PID_TAG_SUBJECT:
231
+ return info.displayName;
232
+ case PID_TAG_MID:
233
+ return BigInt(assignOrGetMid(session, target));
234
+ case PID_TAG_GIVEN_NAME:
235
+ return info.givenName ?? "";
236
+ case PID_TAG_SURNAME:
237
+ return info.surname ?? "";
238
+ case PID_TAG_EMAIL_ADDRESS:
239
+ return info.email ?? "";
240
+ case PID_TAG_BUSINESS_TELEPHONE_NUMBER:
241
+ return info.businessPhone ?? "";
242
+ case PID_TAG_COMPANY_NAME:
243
+ return info.companyName ?? "";
244
+ case PID_TAG_TITLE:
245
+ return info.jobTitle ?? "";
246
+ default:
247
+ return defaultValueForType(propertyType);
248
+ }
249
+ }
250
+ /** Resolves one requested property's value for a `"task:<uid>"` target - a `Folder` of type `TASKS`'s
251
+ * content-table rows/opened items. Almost every Task-specific property is a *named* property (`PidLid*`) under
252
+ * `PSETID_Task`, resolved back to its `(PropertySet GUID, LID)` identity via `resolveNamedProperty` exactly the
253
+ * same way `calendarEventValueFor` handles `PSETID_Appointment`/`PSETID_Common` - see `TaskNamedProperties.ts`'s
254
+ * own doc comment for the LID table this switch implements. */
255
+ export function taskValueFor(session, propertyId, propertyType, target, info) {
256
+ if (propertyId === PID_TAG_SUBJECT) {
257
+ return info.title;
258
+ }
259
+ if (propertyId === PID_TAG_MID) {
260
+ return BigInt(assignOrGetMid(session, target));
261
+ }
262
+ if (propertyId < 0x8000) {
263
+ return defaultValueForType(propertyType);
264
+ }
265
+ const namedProperty = resolveNamedProperty(session, propertyId);
266
+ if (!namedProperty || namedProperty.kind !== "lid" || namedProperty.guid.toLowerCase() !== PSETID_TASK) {
267
+ return defaultValueForType(propertyType);
268
+ }
269
+ switch (namedProperty.lid) {
270
+ case LID_TASK_STATUS:
271
+ return info.completed ? TASK_STATUS_COMPLETE : TASK_STATUS_NOT_STARTED;
272
+ case LID_PERCENT_COMPLETE:
273
+ return info.completed ? 1.0 : 0.0;
274
+ case LID_TASK_DUE_DATE:
275
+ return info.dueDate ?? defaultValueForType(propertyType);
276
+ case LID_TASK_COMPLETE:
277
+ return info.completed;
278
+ default:
279
+ return defaultValueForType(propertyType);
280
+ }
281
+ }
282
+ /** Resolves every column in `columns` for a single `target` (a `"folder:"`/`"virtual:"`/`"message:"`/
283
+ * `"calendarEvent:"`/`"contact:"`/`"task:"` target string), in order - the shared implementation behind both
284
+ * `RopQueryRowsHandler` (one call per table row) and `RopGetPropertiesSpecificHandler` (one call for the single
285
+ * object a handle refers to). */
286
+ export async function resolvePropertyValues(target, columns, context, cache) {
287
+ // Every row resolved counts against the request's work budget - see ExecuteBudget.
288
+ context.budget?.chargeRows();
289
+ const isMessage = target.startsWith("message:");
290
+ const isCalendarEvent = target.startsWith("calendarEvent:");
291
+ const isContact = target.startsWith("contact:");
292
+ const isTask = target.startsWith("task:");
293
+ const folderInfo = isMessage || isCalendarEvent || isContact || isTask
294
+ ? undefined
295
+ : await resolveFolderInfo(context.mailboxUid, target, context.folderRepo, cache, context.budget);
296
+ const messageInfo = isMessage ? await resolveMessageInfo(target, context.messageRepo) : undefined;
297
+ const calendarEventInfo = isCalendarEvent ? await resolveCalendarEventInfo(target, context.calendarEventRepo) : undefined;
298
+ const contactInfo = isContact && context.contactRepo ? await resolveContactInfo(target, context.contactRepo) : undefined;
299
+ const taskInfo = isTask && context.taskRepo ? await resolveTaskInfo(target, context.taskRepo) : undefined;
300
+ let labelNames = [];
301
+ if (messageInfo && messageInfo.labelUids.length > 0 && context.labelRepo) {
302
+ let labelNamesByUid;
303
+ if (cache) {
304
+ if (!cache.labelNamesByUid) {
305
+ const labels = await context.labelRepo.find({ mailboxUid: context.mailboxUid }, { ignoreACL: true });
306
+ cache.labelNamesByUid = new Map(labels.map((l) => [l.uid, l.name]));
307
+ }
308
+ labelNamesByUid = cache.labelNamesByUid;
309
+ }
310
+ else {
311
+ const labels = await context.labelRepo.find({ mailboxUid: context.mailboxUid }, { ignoreACL: true });
312
+ labelNamesByUid = new Map(labels.map((l) => [l.uid, l.name]));
313
+ }
314
+ labelNames = messageInfo.labelUids.map((uid) => labelNamesByUid.get(uid)).filter((name) => name !== undefined);
315
+ }
316
+ let callerAddress = "";
317
+ if (isCalendarEvent) {
318
+ if (cache) {
319
+ if (cache.callerAddress === undefined) {
320
+ const mailbox = await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true });
321
+ cache.callerAddress = mailbox?.primarySmtpAddress ?? "";
322
+ }
323
+ callerAddress = cache.callerAddress ?? "";
324
+ }
325
+ else {
326
+ const mailbox = await context.mailboxRepo.findOne(context.mailboxUid, { ignoreACL: true });
327
+ callerAddress = mailbox?.primarySmtpAddress ?? "";
328
+ }
329
+ }
330
+ return columns.map((column) => {
331
+ if (calendarEventInfo) {
332
+ return calendarEventValueFor(context.session, column.propertyId, column.propertyType, target, calendarEventInfo, callerAddress);
333
+ }
334
+ if (contactInfo) {
335
+ return contactValueFor(context.session, column.propertyId, column.propertyType, target, contactInfo);
336
+ }
337
+ if (taskInfo) {
338
+ return taskValueFor(context.session, column.propertyId, column.propertyType, target, taskInfo);
339
+ }
340
+ if (messageInfo) {
341
+ return messageValueFor(context.session, column.propertyId, column.propertyType, target, messageInfo, labelNames);
342
+ }
343
+ if (isContact || isTask) {
344
+ // contactRepo/taskRepo absent (see RopHandler.ts's own doc comment on why they're optional) - no
345
+ // real data to resolve against, so every column degrades to its type-appropriate default rather
346
+ // than falling through to the folder-info branch below (folderInfo is never populated for these
347
+ // target prefixes, see above - forcing that branch would throw on the `!` assertion).
348
+ return defaultValueForType(column.propertyType);
349
+ }
350
+ return folderValueFor(context.session, column.propertyId, column.propertyType, target, folderInfo);
351
+ });
352
+ }
353
+ //# sourceMappingURL=PropertyResolvers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PropertyResolvers.js","sourceRoot":"","sources":["../../../src/rop/PropertyResolvers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /** `RepoUtils.find()`'s own largest page. */
2
+ export const REPO_PAGE_SIZE = 1000;
3
+ /** The most rows gathered by `findAllCapped`. */
4
+ export const MAX_COLLECTION_ROWS = 10000;
5
+ /**
6
+ * Fetches one page. `limit`/`page`/`sort` go in both the query (what the SQL query builder reads) and the options
7
+ * (what Mongo reads); without them each backend silently returns its own 100-row default in an unspecified order.
8
+ *
9
+ * With a `budget`, the query is charged before it runs and the rows it returned right after, so a request past its
10
+ * `ExecuteBudget` stops before the next query.
11
+ */
12
+ export async function findPage(repo, query, sort, page, pageSize = REPO_PAGE_SIZE, budget) {
13
+ budget?.chargeQueries();
14
+ const rows = await repo.find({ ...query, sort, limit: pageSize, page }, { ignoreACL: true, limit: pageSize, page });
15
+ budget?.chargeFetchedRows(rows.length);
16
+ return rows;
17
+ }
18
+ /**
19
+ * Fetches every row matching `query`, in `sort` order, up to `cap` rows. `truncated` is `true` when more rows may
20
+ * exist past the cap.
21
+ */
22
+ export async function findAllCapped(repo, query, sort, cap = MAX_COLLECTION_ROWS, budget) {
23
+ const items = [];
24
+ for (let page = 0;; page++) {
25
+ const rows = await findPage(repo, query, sort, page, REPO_PAGE_SIZE, budget);
26
+ items.push(...rows);
27
+ if (rows.length < REPO_PAGE_SIZE) {
28
+ return { items: items.slice(0, cap), truncated: items.length > cap };
29
+ }
30
+ if (items.length >= cap) {
31
+ return { items: items.slice(0, cap), truncated: true };
32
+ }
33
+ }
34
+ }
35
+ /**
36
+ * Fetches the rows at positions `[start, start + count)` of `query` in `sort` order, reading only the pages that
37
+ * window touches.
38
+ */
39
+ export async function findWindow(repo, query, sort, start, count, budget) {
40
+ const result = [];
41
+ let position = start;
42
+ while (result.length < count) {
43
+ const page = Math.floor(position / REPO_PAGE_SIZE);
44
+ const rows = await findPage(repo, query, sort, page, REPO_PAGE_SIZE, budget);
45
+ const taken = rows.slice(position - page * REPO_PAGE_SIZE, position - page * REPO_PAGE_SIZE + (count - result.length));
46
+ result.push(...taken);
47
+ position += taken.length;
48
+ if (rows.length < REPO_PAGE_SIZE) {
49
+ break;
50
+ }
51
+ }
52
+ return result;
53
+ }
54
+ //# sourceMappingURL=RepoPaging.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RepoPaging.js","sourceRoot":"","sources":["../../../src/rop/RepoPaging.ts"],"names":[],"mappings":"AAOA,6CAA6C;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AAEnC,iDAAiD;AACjD,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAC;AAMzC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC1B,IAAoB,EACpB,KAA0B,EAC1B,IAAc,EACd,IAAY,EACZ,WAAmB,cAAc,EACjC,MAAsB;IAEtB,MAAM,EAAE,aAAa,EAAE,CAAC;IACxB,MAAM,IAAI,GAAQ,MAAM,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;IAChI,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAC/B,IAAoB,EACpB,KAA0B,EAC1B,IAAc,EACd,MAAc,mBAAmB,EACjC,MAAsB;IAEtB,MAAM,KAAK,GAAQ,EAAE,CAAC;IACtB,KAAK,IAAI,IAAI,GAAG,CAAC,GAAI,IAAI,EAAE,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAQ,MAAM,QAAQ,CAAI,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;QACrF,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;QACpB,IAAI,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YAC/B,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACzE,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YACtB,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QAC3D,CAAC;IACL,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC5B,IAAoB,EACpB,KAA0B,EAC1B,IAAc,EACd,KAAa,EACb,KAAa,EACb,MAAsB;IAEtB,MAAM,MAAM,GAAQ,EAAE,CAAC;IACvB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,OAAO,MAAM,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,cAAc,CAAC,CAAC;QACnD,MAAM,IAAI,GAAQ,MAAM,QAAQ,CAAI,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;QACrF,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,GAAG,cAAc,EAAE,QAAQ,GAAG,IAAI,GAAG,cAAc,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACvH,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;QACtB,QAAQ,IAAI,KAAK,CAAC,MAAM,CAAC;QACzB,IAAI,IAAI,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YAC/B,MAAM;QACV,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC"}
@@ -0,0 +1,52 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz. All rights reserved.
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { createHash } from "crypto";
6
+ import { BaseEntity, ModelUtils } from "@rapidrest/service-core";
7
+ // Copies of restapi rules that @rapidmx/restapi 0.9.0 doesn't export from its package root. Keep them in sync with
8
+ // restapi's `util/ConversationUtils.ts` (`boundIndexedValue`) and `util/EntityUtils.ts` (`asEntity`).
9
+ /** The longest value `boundIndexedValue()` stores verbatim - restapi's `MAX_INDEXED_VALUE_LENGTH`. */
10
+ export const MAX_INDEXED_VALUE_LENGTH = 255;
11
+ /**
12
+ * restapi's `boundIndexedValue`: `value` unchanged when it's at most `MAX_INDEXED_VALUE_LENGTH` characters, otherwise
13
+ * `sha256:<64 hex digits>` of its UTF-8 bytes. restapi stores `CalendarEvent.icalUid` (and `Message.messageId`/
14
+ * `conversationId`) this way, so a lookup by one of those identifiers has to bound its value the same way to match.
15
+ */
16
+ export function boundIndexedValue(value) {
17
+ if (typeof value !== "string" || value.length <= MAX_INDEXED_VALUE_LENGTH) {
18
+ return value;
19
+ }
20
+ return `sha256:${createHash("sha256").update(value, "utf8").digest("hex")}`;
21
+ }
22
+ /**
23
+ * restapi's `asEntity`: `row` as an instance of `repo`'s model class. Before service-core 2.1.0, `RepoUtils.update()`
24
+ * only enforced its optimistic lock when `existing instanceof BaseEntity`, and the Mongo backend's `find()`/`findOne()`
25
+ * return plain documents, so passing one straight through turned a versioned update into an unconditional overwrite.
26
+ * 2.1.0 also locks plain documents carrying a numeric `version`, so this is now defence in depth, kept while restapi
27
+ * keeps its own copy. SQL rows are already instances and pass through as they are.
28
+ */
29
+ export function asEntity(repo, row) {
30
+ if (row instanceof BaseEntity) {
31
+ return row;
32
+ }
33
+ const modelClass = repo.modelClass;
34
+ return modelClass ? new modelClass(row) : row;
35
+ }
36
+ /**
37
+ * A `RepoUtils` query value that always matches `value` literally: service-core's `ModelUtils.literal()`, so a
38
+ * client- or sender-supplied value like `ne(x)` is never read as an operator and `me`/`null`/numeric strings are not
39
+ * substituted or coerced. Callers still compare the returned rows' field against `value` themselves.
40
+ */
41
+ export function literalQueryValue(value) {
42
+ return ModelUtils.literal(value);
43
+ }
44
+ /**
45
+ * restapi `MeetingSchedulingJob`'s eligibility rule (`jobs/MeetingSchedulingJob.ts`, `processInviteCandidates`): `true`
46
+ * while the job will still send invites for `event`'s current revision, i.e. its `inviteSequenceSent` is unset or
47
+ * differs from its `sequence`. Keep in sync with that job.
48
+ */
49
+ export function isInvitePending(event) {
50
+ return event.inviteSequenceSent == null || event.inviteSequenceSent !== event.sequence;
51
+ }
52
+ //# sourceMappingURL=RestapiRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RestapiRules.js","sourceRoot":"","sources":["../../../src/rop/RestapiRules.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,mEAAmE;AACnE,mCAAmC;AACnC,+EAA+E;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAqC,MAAM,yBAAyB,CAAC;AAEpG,mHAAmH;AACnH,sGAAsG;AAEtG,sGAAsG;AACtG,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAE5C;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAsC,KAAQ;IAC3E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,IAAI,wBAAwB,EAAE,CAAC;QACxE,OAAO,KAAK,CAAC;IACjB,CAAC;IACD,OAAO,UAAU,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAO,CAAC;AACrF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,QAAQ,CAAI,IAAoB,EAAE,GAAM;IACpD,IAAI,GAAG,YAAY,UAAU,EAAE,CAAC;QAC5B,OAAO,GAAG,CAAC;IACf,CAAC;IACD,MAAM,UAAU,GAAS,IAAY,CAAC,UAAU,CAAC;IACjD,OAAO,UAAU,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAClD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAa;IAC3C,OAAO,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,KAAgE;IAC5F,OAAO,KAAK,CAAC,kBAAkB,IAAI,IAAI,IAAI,KAAK,CAAC,kBAAkB,KAAK,KAAK,CAAC,QAAQ,CAAC;AAC3F,CAAC"}
@@ -0,0 +1,55 @@
1
+ import { assignHandle } from "../MapiSessionManager.js";
2
+ const ROP_ID_CREATE_MESSAGE = 0x06;
3
+ /** The well-known MAPI HRESULT `MAPI_E_NOT_FOUND`, reused as this handler's only failure `ReturnValue` - an
4
+ * unrecognized `FolderId`, the same constant `RopOpenFolderHandler` uses for its own analogous lookup miss. */
5
+ const ERROR_NOT_FOUND = 0x8004010f;
6
+ /**
7
+ * `RopCreateMessage` (`[MS-OXCMSG]`/`[MS-OXCROPS]`): begins composing a new message in a folder, producing a
8
+ * new `"message"` Server object handle later ROPs (`RopSetProperties`, `RopOpenStream`, `RopSaveChangesMessage`)
9
+ * reference by `InputHandleIndex`. Unlike `RopOpenMessage`'s handle (an already-real, already-saved message),
10
+ * this handle's `entityUid` is deliberately left `""` - there is no real backing `Message` row, and won't be
11
+ * one until `RopSubmitMessage` actually sends it (this pragmatic subset has no separate Drafts-folder
12
+ * persistence step; see `RopSaveChangesMessageHandler`'s own doc comment). `draftFolderUid` remembers the
13
+ * target folder for that eventual send, and `draftProperties` starts empty, filled in by later
14
+ * `RopSetProperties`/`RopWriteStream` calls.
15
+ *
16
+ * `CodePageId` is decoded to advance past it correctly but not otherwise acted on (this pragmatic subset always
17
+ * encodes strings as UTF-16LE/UTF-8 directly, the same treatment `RopOpenMessageHandler` gives it).
18
+ * `AssociatedFlag` (FAI messages - hidden configuration/rules objects, not real mail) is decoded but not
19
+ * honored - this pragmatic subset's compose/send path only ever produces ordinary mail messages.
20
+ *
21
+ * @author Jean-Philippe Steinmetz
22
+ */
23
+ export class RopCreateMessageHandler {
24
+ constructor() {
25
+ this.ropId = ROP_ID_CREATE_MESSAGE;
26
+ this.responseHandleIndexOffset = 3; // OutputHandleIndex
27
+ }
28
+ handle(reader, writer, context) {
29
+ reader.readUInt8(); // LogonId - this pragmatic subset doesn't track multiple concurrent logons per session
30
+ reader.readUInt8(); // InputHandleIndex - the logon handle this create is performed against; not
31
+ // separately validated, matching RopOpenFolderHandler's own treatment of its input handle.
32
+ const outputHandleIndex = reader.readUInt8();
33
+ reader.readUInt16LE(); // CodePageId - see class doc comment
34
+ const folderId = reader.readBigUInt64LE();
35
+ reader.readUInt8(); // AssociatedFlag - see class doc comment
36
+ const target = context.session.folderIds[folderId.toString()];
37
+ if (!target) {
38
+ writer.writeUInt8(ROP_ID_CREATE_MESSAGE);
39
+ writer.writeUInt8(outputHandleIndex);
40
+ writer.writeUInt32LE(ERROR_NOT_FOUND);
41
+ return;
42
+ }
43
+ assignHandle(context.session, outputHandleIndex, {
44
+ type: "message",
45
+ entityUid: "",
46
+ draftFolderUid: target,
47
+ draftProperties: {},
48
+ });
49
+ writer.writeUInt8(ROP_ID_CREATE_MESSAGE);
50
+ writer.writeUInt8(outputHandleIndex);
51
+ writer.writeUInt32LE(0); // ReturnValue - success
52
+ writer.writeUInt8(0); // HasMessageId - no MID is assigned until RopSaveChangesMessage
53
+ }
54
+ }
55
+ //# sourceMappingURL=RopCreateMessageHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RopCreateMessageHandler.js","sourceRoot":"","sources":["../../../src/rop/RopCreateMessageHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAGxD,MAAM,qBAAqB,GAAG,IAAI,CAAC;AAEnC;+GAC+G;AAC/G,MAAM,eAAe,GAAG,UAAU,CAAC;AAEnC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,OAAO,uBAAuB;IAApC;QACoB,UAAK,GAAG,qBAAqB,CAAC;QAC9B,8BAAyB,GAAG,CAAC,CAAC,CAAC,oBAAoB;IA+BvE,CAAC;IA7BU,MAAM,CAAC,MAAoB,EAAE,MAAoB,EAAE,OAAmB;QACzE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,uFAAuF;QAC3G,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,4EAA4E;QAChG,2FAA2F;QAC3F,MAAM,iBAAiB,GAAW,MAAM,CAAC,SAAS,EAAE,CAAC;QACrD,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,qCAAqC;QAC5D,MAAM,QAAQ,GAAW,MAAM,CAAC,eAAe,EAAE,CAAC;QAClD,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,yCAAyC;QAE7D,MAAM,MAAM,GAAuB,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;YACzC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;YACrC,MAAM,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;YACtC,OAAO;QACX,CAAC;QAED,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,iBAAiB,EAAE;YAC7C,IAAI,EAAE,SAAS;YACf,SAAS,EAAE,EAAE;YACb,cAAc,EAAE,MAAM;YACtB,eAAe,EAAE,EAAE;SACtB,CAAC,CAAC;QAEH,MAAM,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;QACzC,MAAM,CAAC,UAAU,CAAC,iBAAiB,CAAC,CAAC;QACrC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,wBAAwB;QACjD,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,gEAAgE;IAC1F,CAAC;CACJ"}