2 OpenChange MAPI implementation.
4 Copyright (C) Julien Kerihuel 2007-2008.
5 Copyright (C) Fabien Le Mentec 2007.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "libmapi/libmapi.h"
22 #include "libmapi/libmapi_private.h"
23 #include "gen_ndr/ndr_exchange.h"
30 \brief Operations on messages
35 \details Create a new attachment
37 This function creates a new attachment to an existing message.
39 \param obj_message the message to attach to
40 \param obj_attach the attachment
42 Both objects need to exist before you call this message. obj_message
43 should be a valid message on the server. obj_attach needs to be
47 enum MAPISTATUS retval;
48 mapi_object_t obj_message;
49 mapi_object_t obj_attach;
51 ... open or create the obj_message ...
53 mapi_object_init(&obj_attach);
54 retval = CreateAttach(&obj_message, &obj_attach);
55 ... check the return value ...
57 ... use SetProps() to set the attachment up ...
58 ... perhaps OpenStream() / WriteStream() / CommitStream() on obj_attach ...
60 // Save the changes to the attachment and then the message
61 retval = SaveChangesAttachment(&obj_message, &obj_attach, KeepOpenReadOnly);
62 ... check the return value ...
63 retval = SaveChangesMessage(&obj_folder, &obj_message, KeepOpenReadOnly);
64 ... check the return value ...
67 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
69 \note Developers may also call GetLastError() to retrieve the last
70 MAPI error code. Possible MAPI error codes are:
71 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
72 - MAPI_E_CALL_FAILED: A network problem was encountered during the
75 \sa CreateMessage, GetAttachmentTable, OpenAttach, GetLastError
77 _PUBLIC_ enum MAPISTATUS CreateAttach(mapi_object_t *obj_message,
78 mapi_object_t *obj_attach)
80 struct mapi_request *mapi_request;
81 struct mapi_response *mapi_response;
82 struct EcDoRpc_MAPI_REQ *mapi_req;
83 struct CreateAttach_req request;
84 struct mapi_session *session;
86 enum MAPISTATUS retval;
92 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
93 session = mapi_object_get_session(obj_message);
94 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
96 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
99 mem_ctx = talloc_named(session, 0, "CreateAttach");
102 /* Fill the CreateAttach operation */
103 request.handle_idx = 0x1;
104 size += sizeof (uint8_t);
106 /* Fill the MAPI_REQ request */
107 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
108 mapi_req->opnum = op_MAPI_CreateAttach;
109 mapi_req->logon_id = logon_id;
110 mapi_req->handle_idx = 0;
111 mapi_req->u.mapi_CreateAttach = request;
114 /* Fill the mapi_request structure */
115 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
116 mapi_request->mapi_len = size + (sizeof (uint32_t) * 2);
117 mapi_request->length = size;
118 mapi_request->mapi_req = mapi_req;
119 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
120 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
121 mapi_request->handles[1] = 0xffffffff;
123 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
124 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
125 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
126 retval = mapi_response->mapi_repl->error_code;
127 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
129 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
131 /* Set object session and handle */
132 mapi_object_set_session(obj_attach, session);
133 mapi_object_set_handle(obj_attach, mapi_response->handles[1]);
134 mapi_object_set_logon_id(obj_attach, logon_id);
136 talloc_free(mapi_response);
137 talloc_free(mem_ctx);
139 return MAPI_E_SUCCESS;
144 \details Delete an attachment from a message
146 This function deletes one attachment from a message. The attachment
147 to be deleted is specified by its PR_ATTACH_NUM
149 \param obj_message the message to operate on
150 \param AttachmentID the attachment number
152 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
154 \note Developers may also call GetLastError() to retrieve the last
155 MAPI error code. Possible MAPI error codes are:
156 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
157 - MAPI_E_CALL_FAILED: A network problem was encountered during the
160 \sa CreateMessage, GetAttachmentTable, GetLastError
162 _PUBLIC_ enum MAPISTATUS DeleteAttach(mapi_object_t *obj_message, uint32_t AttachmentID)
164 struct mapi_request *mapi_request;
165 struct mapi_response *mapi_response;
166 struct EcDoRpc_MAPI_REQ *mapi_req;
167 struct DeleteAttach_req request;
168 struct mapi_session *session;
170 enum MAPISTATUS retval;
176 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
177 session = mapi_object_get_session(obj_message);
178 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
180 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
183 mem_ctx = talloc_named(session, 0, "DeleteAttach");
186 /* Fill the DeleteAttach operation */
187 request.AttachmentID = AttachmentID;
188 size += sizeof (uint32_t);
190 /* Fill the MAPI_REQ request */
191 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
192 mapi_req->opnum = op_MAPI_DeleteAttach;
193 mapi_req->logon_id = logon_id;
194 mapi_req->handle_idx = 0;
195 mapi_req->u.mapi_DeleteAttach = request;
198 /* Fill the mapi_request structure */
199 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
200 mapi_request->mapi_len = size + sizeof (uint32_t);
201 mapi_request->length = size;
202 mapi_request->mapi_req = mapi_req;
203 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
204 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
206 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
207 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
208 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
209 retval = mapi_response->mapi_repl->error_code;
210 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
212 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
214 talloc_free(mapi_response);
215 talloc_free(mem_ctx);
217 return MAPI_E_SUCCESS;
222 \details Retrieve the attachment table for a message
224 \param obj_message the message
225 \param obj_table the attachment table for the message
227 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
229 \note Developers may also call GetLastError() to retrieve the last
230 MAPI error code. Possible MAPI error codes are:
231 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
232 - MAPI_E_CALL_FAILED: A network problem was encountered during the
235 \sa CreateMessage, OpenMessage, CreateAttach, OpenAttach, GetLastError
237 _PUBLIC_ enum MAPISTATUS GetAttachmentTable(mapi_object_t *obj_message,
238 mapi_object_t *obj_table)
240 struct mapi_request *mapi_request;
241 struct mapi_response *mapi_response;
242 struct EcDoRpc_MAPI_REQ *mapi_req;
243 struct GetAttachmentTable_req request;
244 struct mapi_session *session;
246 enum MAPISTATUS retval;
252 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
253 OPENCHANGE_RETVAL_IF(!obj_table, MAPI_E_INVALID_PARAMETER, NULL);
254 session = mapi_object_get_session(obj_message);
255 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
257 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
260 mem_ctx = talloc_named(session, 0, "GetAttachmentTable");
263 /* Fill the GetAttachmentTable operation */
264 request.handle_idx = 1;
265 size += sizeof (uint8_t);
267 request.TableFlags = 0x0;
268 size += sizeof (uint8_t);
270 /* Fill the MAPI_REQ request */
271 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
272 mapi_req->opnum = op_MAPI_GetAttachmentTable;
273 mapi_req->logon_id = logon_id;
274 mapi_req->handle_idx = 0;
275 mapi_req->u.mapi_GetAttachmentTable = request;
278 /* Fill the mapi_request structure */
279 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
280 mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
281 mapi_request->length = size;
282 mapi_request->mapi_req = mapi_req;
283 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
284 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
285 mapi_request->handles[1] = 0xffffffff;
287 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
288 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
289 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
290 retval = mapi_response->mapi_repl->error_code;
291 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
293 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
295 /* Set object session and handle */
296 mapi_object_set_session(obj_table, session);
297 mapi_object_set_handle(obj_table, mapi_response->handles[mapi_response->mapi_repl->handle_idx]);
298 mapi_object_set_logon_id(obj_table, logon_id);
300 talloc_free(mapi_response);
301 talloc_free(mem_ctx);
303 return MAPI_E_SUCCESS;
308 \details Get the valid attachment IDs for a message
310 This function returns the list of valid attachment IDs for a message.
311 You can then use these IDs with the OpenAttach and DeleteAttach functions.
313 \param obj_message the message to operate on
314 \param NumAttachments the number of attachments for the message
315 \param AttachmentIds array of attachment Ids
317 The AttachmentIds array has NumAttachments elements.
319 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
321 \note Developers may also call GetLastError() to retrieve the last
322 MAPI error code. Possible MAPI error codes are:
323 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
324 - MAPI_E_INVALID_PARAMETER: a parameter is incorrect (e.g. null pointer)
325 - MAPI_E_CALL_FAILED: A network problem was encountered during the
328 \sa OpenAttach, DeleteAttach
330 _PUBLIC_ enum MAPISTATUS GetValidAttach(mapi_object_t *obj_message, uint16_t *NumAttachments, uint32_t **AttachmentIds)
332 struct mapi_request *mapi_request;
333 struct mapi_response *mapi_response;
334 struct EcDoRpc_MAPI_REQ *mapi_req;
335 struct GetValidAttachments_repl *reply;
336 struct mapi_session *session;
338 enum MAPISTATUS retval;
344 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
345 OPENCHANGE_RETVAL_IF(!NumAttachments, MAPI_E_INVALID_PARAMETER, NULL);
346 OPENCHANGE_RETVAL_IF(!AttachmentIds, MAPI_E_INVALID_PARAMETER, NULL);
347 session = mapi_object_get_session(obj_message);
348 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
350 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
352 mem_ctx = talloc_named(session, 0, "GetValidAttach");
355 /* Fill the MAPI_REQ request */
356 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
357 mapi_req->opnum = op_MAPI_GetValidAttachments;
358 mapi_req->logon_id = logon_id;
359 mapi_req->handle_idx = 0;
362 /* Fill the mapi_request structure */
363 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
364 mapi_request->mapi_len = size + sizeof (uint32_t);
365 mapi_request->length = size;
366 mapi_request->mapi_req = mapi_req;
367 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
368 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
370 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
371 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
372 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
373 retval = mapi_response->mapi_repl->error_code;
374 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
376 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
378 /* Retrieve the result */
379 reply = &(mapi_response->mapi_repl->u.mapi_GetValidAttachments);
380 *NumAttachments = reply->AttachmentIdCount;
381 *AttachmentIds = talloc_steal((TALLOC_CTX *)session, reply->AttachmentIdArray);
383 talloc_free(mapi_response);
384 talloc_free(mem_ctx);
386 return MAPI_E_SUCCESS;
390 \details Open an attachment to a message
392 This function opens one attachment from a message. The attachment
393 to be opened is specified by its PR_ATTACH_NUM.
395 \param obj_message the message to operate on
396 \param AttachmentID the attachment number
397 \param obj_attach the resulting attachment object
399 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
401 \note Developers may also call GetLastError() to retrieve the last
402 MAPI error code. Possible MAPI error codes are:
403 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
404 - MAPI_E_CALL_FAILED: A network problem was encountered during the
407 \sa CreateMessage, CreateAttach, GetAttachmentTable, GetLastError
409 _PUBLIC_ enum MAPISTATUS OpenAttach(mapi_object_t *obj_message, uint32_t AttachmentID,
410 mapi_object_t *obj_attach)
412 struct mapi_request *mapi_request;
413 struct mapi_response *mapi_response;
414 struct EcDoRpc_MAPI_REQ *mapi_req;
415 struct OpenAttach_req request;
416 struct mapi_session *session;
418 enum MAPISTATUS retval;
424 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
425 session = mapi_object_get_session(obj_message);
426 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
428 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
431 mem_ctx = talloc_named(session, 0, "OpenAttach");
434 /* Fill the OpenAttach operation */
435 request.handle_idx = 0x1;
436 size += sizeof(uint8_t);
437 request.OpenAttachmentFlags = OpenAttachmentFlags_ReadOnly;
438 size += sizeof(uint8_t);
439 request.AttachmentID = AttachmentID;
440 size += sizeof(uint32_t);
442 /* Fill the MAPI_REQ request */
443 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
444 mapi_req->opnum = op_MAPI_OpenAttach;
445 mapi_req->logon_id = logon_id;
446 mapi_req->handle_idx = 0;
447 mapi_req->u.mapi_OpenAttach = request;
450 /* Fill the mapi_request structure */
451 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
452 mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
453 mapi_request->length = size;
454 mapi_request->mapi_req = mapi_req;
455 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
456 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
457 mapi_request->handles[1] = 0xffffffff;
459 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
460 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
461 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
462 retval = mapi_response->mapi_repl->error_code;
463 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
465 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
467 /* Set object session and handle */
468 mapi_object_set_session(obj_attach, session);
469 mapi_object_set_handle(obj_attach, mapi_response->handles[1]);
470 mapi_object_set_logon_id(obj_attach, logon_id);
472 talloc_free(mapi_response);
473 talloc_free(mem_ctx);
475 return MAPI_E_SUCCESS;
480 \details Set the type of a recipient
482 The function sets the recipient type (RecipClass) in the aRow
483 parameter. ResolveNames should be used to fill the SRow structure.
485 \param aRow the row to set
486 \param RecipClass the type of recipient to set on the specified row
488 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
490 \note Developers may also call GetLastError() to retrieve the last
491 MAPI error code. Possible MAPI error codes are:
492 - MAPI_E_INVALID_PARAMETER: The aRow parameter was not set
495 \sa ResolveNames, ModifyRecipients, GetLastError
497 _PUBLIC_ enum MAPISTATUS SetRecipientType(struct SRow *aRow, enum ulRecipClass RecipClass)
499 enum MAPISTATUS retval;
500 struct SPropValue lpProp;
502 lpProp.ulPropTag = PR_RECIPIENT_TYPE;
503 lpProp.value.l = RecipClass;
505 retval = SRow_addprop(aRow, lpProp);
506 OPENCHANGE_RETVAL_IF(retval, retval, NULL);
508 return MAPI_E_SUCCESS;
513 * retrieve the organization length for Exchange recipients
515 uint8_t mapi_recipients_get_org_length(struct mapi_profile *profile)
517 if (profile->mailbox && profile->username)
518 return (strlen(profile->mailbox) - strlen(profile->username));
524 \details RecipientFlags bitmask calculation for RecipientRows
527 \param aRow pointer to the SRow structures with the properties to
528 pass to ModifyRecipients.
530 According to MS-OXCDATA 2.9.3.1 RecipientFlags structure, the bitmask
531 can be represented as the following:
533 0 3 4 5 6 7 8 9 10 11 15 16
534 +------+---+---+---+---+---+---+---+---+----------+---+
535 | Type | E | D | T | S | R | N | U | I | Reserved | O |
536 +------+---+---+---+---+---+---+---+---+----------+---+
538 Type: (0x7 mask) 3-bit enumeration describing the Address Type (PR_ADDRTYPE)
539 E: (0x8) Email address included (PR_SMTP_ADDRESS)
540 D: (0x10) Display Name included (PR_DISPLAY_NAME)
541 T: (0x20) Transmittable Display Name included (PR_TRANSMITTABLE_DISPLAY_NAME)
542 S: (0x40) If Transmittable Display Name is the same than Display Name (D == T)
543 R: (0x80) Different transport is responsible for delivery
544 N: (0x100) Recipient does not support receiving Rich Text messages
545 U: (0x200) If we are using Unicode properties
546 I: (0x400) If Simple Display Name is included (PR_7BIT_DISPLAY_NAME)
547 Reserved: Must be zero
548 O: (0x8000) Non-standard address type is used
550 The PidTag property to bitmask mapping was unclear for some
551 fields. mapiproxy between Outlook 2003 and Exchange 2010 has been
552 used for this purpose.
554 For further information about PidTagAddressType, refer to
555 [MS-OXCMAIL] section 2.1.1.9
557 \return uint16_t holding the RecipientFlags value. 0 is returned
558 when an inconsistency or a failure occurs
561 uint16_t mapi_recipients_RecipientFlags(struct SRow *aRow)
564 struct SPropValue *lpProp = NULL;
565 bool unicode = false;
566 const char *addrtype = NULL;
567 const char *tmp = NULL;
568 const char *display_name = NULL;
569 const char *transmit_display_name = NULL;
576 /* (Type) - 0x0 to 0x7: PR_ADDRTYPE */
577 lpProp = get_SPropValue_SRow(aRow, PR_ADDRTYPE);
578 if (lpProp && lpProp->value.lpszA) {
579 addrtype = lpProp->value.lpszA;
581 lpProp = get_SPropValue_SRow(aRow, PR_ADDRTYPE_UNICODE);
582 if (lpProp && lpProp->value.lpszW) {
584 addrtype = lpProp->value.lpszW;
591 /* WARNING: This check is yet incomplete */
592 if (!strcmp("EX", addrtype)) {
594 } else if (!strcmp("SMTP", addrtype)) {
598 /* (E) - 0x8: PR_SMTP_ADDRESS (If we have Exchange type, we don't need it) */
599 if (strcmp(addrtype, "EX")) {
600 lpProp = get_SPropValue_SRow(aRow, (unicode == true) ? PR_SMTP_ADDRESS_UNICODE: PR_SMTP_ADDRESS);
602 tmp = (unicode == true) ? lpProp->value.lpszW : lpProp->value.lpszA;
609 /* (D) - 0x10: PR_DISPLAY_NAME */
610 lpProp = get_SPropValue_SRow(aRow, (unicode == true) ? PR_DISPLAY_NAME_UNICODE : PR_DISPLAY_NAME);
612 display_name = (unicode == true) ? lpProp->value.lpszW : lpProp->value.lpszA;
618 /* (T) - 0x20: PR_TRANSMITTABLE_DISPLAY_NAME */
619 lpProp = get_SPropValue_SRow(aRow, (unicode == true) ? PR_TRANSMITTABLE_DISPLAY_NAME_UNICODE : PR_TRANSMITTABLE_DISPLAY_NAME);
621 transmit_display_name = (unicode == true) ? lpProp->value.lpszW : lpProp->value.lpszA;
622 if (transmit_display_name) {
625 } else if (display_name && strcmp(display_name, transmit_display_name)) {
631 /* (S) - 0x40: Does D equals T? If so, we shouldn't include PR_TRANSMITTABLE_DISPLAY_NAME within RecipientRows */
632 if (display_name && transmit_display_name) {
633 if (!strcmp(display_name, transmit_display_name)) {
638 /* (R) - 0x80: Different transport is responsible for delivery */
639 if (addrtype && strcmp(addrtype, "EX")) {
643 /* (N) - 0x100: Recipient doesn't support rich-text messages */
644 lpProp = get_SPropValue_SRow(aRow, PR_SEND_RICH_INFO);
645 if (lpProp && (lpProp->value.b == false)) {
649 /* (U) - 0x200: Unicode properties */
650 if (unicode == true) {
654 /* (I) - 0x400: PR_7BIT_DISPLAY_NAME */
655 lpProp = get_SPropValue_SRow(aRow, (unicode == true) ? PR_7BIT_DISPLAY_NAME_UNICODE : PR_7BIT_DISPLAY_NAME);
657 tmp = (unicode == true) ? lpProp->value.lpszW : lpProp->value.lpszA;
668 \details Adds, deletes or modifies message recipients
670 \param obj_message the message to change the recipients for
671 \param SRowSet the recipients to add
673 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
675 When using this function, take care to ensure that the properties
676 that are present on the first row in the rowset are also present
677 in all the following rows. If any are missing, this function will
678 suffer NDR errors. This includes making sure that any string
679 properties are present in the same encoding (e.g. if you use
680 PR_SMTP_ADDRESS_UNICODE on the first row, don't provide
681 PR_SMTP_ADDRESS on subsequent rows).
683 \note Developers may also call GetLastError() to retrieve the last
684 MAPI error code. Possible MAPI error codes are:
685 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
686 - MAPI_E_CALL_FAILED: A network problem was encountered during the
689 \bug ModifyRecipients can only add recipients.
691 \sa CreateMessage, ResolveNames, SetRecipientType, GetLastError
694 _PUBLIC_ enum MAPISTATUS ModifyRecipients(mapi_object_t *obj_message,
695 struct SRowSet *SRowSet)
697 struct mapi_request *mapi_request;
698 struct mapi_response *mapi_response;
699 struct EcDoRpc_MAPI_REQ *mapi_req;
700 struct ModifyRecipients_req request;
701 struct mapi_session *session;
703 enum MAPISTATUS retval;
706 unsigned long i_prop, j;
707 unsigned long i_recip;
712 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
713 OPENCHANGE_RETVAL_IF(!SRowSet, MAPI_E_NOT_INITIALIZED, NULL);
714 OPENCHANGE_RETVAL_IF(!SRowSet->aRow, MAPI_E_NOT_INITIALIZED, NULL);
716 session = mapi_object_get_session(obj_message);
717 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
719 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
722 mem_ctx = talloc_named(session, 0, "ModifyRecipients");
725 /* Fill the ModifyRecipients operation */
726 request.prop_count = SRowSet->aRow[0].cValues;
727 size += sizeof(uint16_t);
730 * append here property tags that can be fetched with
731 * ResolveNames but shouldn't be included in ModifyRecipients rows
733 request.properties = get_MAPITAGS_SRow(mem_ctx, &SRowSet->aRow[0], &count);
734 request.prop_count = MAPITAGS_delete_entries(request.properties, count, 19,
737 PR_DISPLAY_NAME_UNICODE,
738 PR_DISPLAY_NAME_ERROR,
740 PR_GIVEN_NAME_UNICODE,
743 PR_EMAIL_ADDRESS_UNICODE,
744 PR_TRANSMITTABLE_DISPLAY_NAME,
745 PR_TRANSMITTABLE_DISPLAY_NAME_UNICODE,
750 PR_SEND_INTERNET_ENCODING,
751 PR_SEND_INTERNET_ENCODING_ERROR,
753 PR_SEND_RICH_INFO_ERROR);
754 size += request.prop_count * sizeof(uint32_t);
755 request.cValues = SRowSet->cRows;
756 size += sizeof(uint16_t);
757 request.RecipientRow = talloc_array(mem_ctx, struct ModifyRecipientRow, request.cValues);
759 for (i_recip = 0; i_recip < request.cValues; i_recip++) {
761 struct RecipientRow *RecipientRow;
762 struct ndr_push *ndr;
763 struct mapi_SPropValue mapi_sprop;
764 const uint32_t *RecipClass = 0;
766 ndr = talloc_zero(mem_ctx, struct ndr_push);
768 aRow = &(SRowSet->aRow[i_recip]);
769 RecipientRow = &(request.RecipientRow[i_recip].RecipientRow);
771 request.RecipientRow[i_recip].idx = i_recip;
772 size += sizeof(uint32_t);
774 RecipClass = (const uint32_t *) find_SPropValue_data(aRow, PR_RECIPIENT_TYPE);
775 OPENCHANGE_RETVAL_IF(!RecipClass, MAPI_E_INVALID_PARAMETER, mem_ctx);
776 request.RecipientRow[i_recip].RecipClass = (enum ulRecipClass) *RecipClass;
777 size += sizeof(uint8_t);
779 RecipientRow->RecipientFlags = mapi_recipients_RecipientFlags(aRow);
781 /* (Type) - 0x0 to 0x7: Recipient type (Exchange, SMTP or other?) */
782 switch (RecipientRow->RecipientFlags & 0x7) {
784 // RecipientRow->type.EXCHANGE.organization_length = mapi_recipients_get_org_length(session->profile);
785 RecipientRow->AddressPrefixUsed.prefix_size = 0;
786 RecipientRow->DisplayType.display_type = SINGLE_RECIPIENT;
787 switch (RecipientRow->RecipientFlags & 0x200) {
789 RecipientRow->X500DN.recipient_x500name = (const char *) find_SPropValue_data(aRow, PR_EMAIL_ADDRESS);
792 RecipientRow->X500DN.recipient_x500name = (const char *) find_SPropValue_data(aRow, PR_EMAIL_ADDRESS_UNICODE);
795 size += sizeof(uint32_t) + strlen(RecipientRow->X500DN.recipient_x500name) + 1;
798 size += sizeof(uint16_t);
802 /* (E) - 0x8: PR_SMTP_ADDRESS */
803 switch (RecipientRow->RecipientFlags & 0x208) {
805 RecipientRow->EmailAddress.lpszA = (const char *) find_SPropValue_data(aRow, PR_SMTP_ADDRESS);
806 size += strlen(RecipientRow->EmailAddress.lpszA) + 1;
809 RecipientRow->EmailAddress.lpszW = (const char *) find_SPropValue_data(aRow, PR_SMTP_ADDRESS_UNICODE);
810 size += get_utf8_utf16_conv_length(RecipientRow->EmailAddress.lpszW);
816 /* (D) - 0x10: PR_DISPLAY_NAME */
817 switch (RecipientRow->RecipientFlags & 0x210) {
819 RecipientRow->DisplayName.lpszA = (const char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME);
820 size += strlen(RecipientRow->DisplayName.lpszA) + 1;
823 RecipientRow->DisplayName.lpszW = (const char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME_UNICODE);
824 size += get_utf8_utf16_conv_length(RecipientRow->DisplayName.lpszW);
830 /* (T) - 0x20: PR_TRANSMITTABLE_DISPLAY_NAME */
831 switch (RecipientRow->RecipientFlags & 0x260) {
833 RecipientRow->TransmittableDisplayName.lpszA = (const char *) find_SPropValue_data(aRow, PR_TRANSMITTABLE_DISPLAY_NAME);
834 size += strlen(RecipientRow->TransmittableDisplayName.lpszA) + 1;
837 RecipientRow->TransmittableDisplayName.lpszW = (const char *) find_SPropValue_data(aRow, PR_TRANSMITTABLE_DISPLAY_NAME_UNICODE);
838 size += get_utf8_utf16_conv_length(RecipientRow->TransmittableDisplayName.lpszW);
845 /* (I) - 0x400: PR_7BIT_DISPLAY_NAME */
846 switch(RecipientRow->RecipientFlags & 0x600) {
848 RecipientRow->SimpleDisplayName.lpszA = (const char *) find_SPropValue_data(aRow, PR_7BIT_DISPLAY_NAME);
849 size += strlen(RecipientRow->SimpleDisplayName.lpszA) + 1;
852 RecipientRow->SimpleDisplayName.lpszW = (const char *) find_SPropValue_data(aRow, PR_7BIT_DISPLAY_NAME_UNICODE);
853 size += get_utf8_utf16_conv_length(RecipientRow->SimpleDisplayName.lpszW);
859 RecipientRow->prop_count = request.prop_count;
860 size += sizeof(uint16_t);
861 RecipientRow->layout = 0;
862 size += sizeof(uint8_t);
864 /* for each property, we set the switch values and ndr_flags then call mapi_SPropValue_CTR */
865 ndr_set_flags(&ndr->flags, LIBNDR_FLAG_NOALIGN);
866 for (i_prop = 0; i_prop < request.prop_count; i_prop++) {
867 for (j = 0; j < aRow->cValues; j++) {
868 if (aRow->lpProps[j].ulPropTag == request.properties[i_prop]) {
869 enum ndr_err_code ndr_retval;
870 ndr_retval = ndr_push_set_switch_value(ndr, &mapi_sprop.value,
871 (aRow->lpProps[j].ulPropTag & 0xFFFF));
872 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_retval))
873 return MAPI_E_CALL_FAILED;
875 cast_mapi_SPropValue(mem_ctx, &mapi_sprop, &aRow->lpProps[j]);
876 ndr_push_mapi_SPropValue_CTR(ndr, NDR_SCALARS, &mapi_sprop.value);
881 RecipientRow->prop_values.length = ndr->offset;
882 RecipientRow->prop_values.data = ndr->data;
883 /* add the blob size field */
884 size += sizeof(uint16_t);
885 size += RecipientRow->prop_values.length;
888 /* Fill the MAPI_REQ request */
889 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
890 mapi_req->opnum = op_MAPI_ModifyRecipients;
891 mapi_req->logon_id = logon_id;
892 mapi_req->handle_idx = 0;
893 mapi_req->u.mapi_ModifyRecipients = request;
896 /* Fill the mapi_request structure */
897 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
898 mapi_request->mapi_len = size + sizeof(uint32_t);
899 mapi_request->length = size;
900 mapi_request->mapi_req = mapi_req;
901 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
902 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
904 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
905 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
906 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
907 retval = mapi_response->mapi_repl->error_code;
908 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
910 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
912 talloc_free(mapi_response);
913 talloc_free(mem_ctx);
916 return MAPI_E_SUCCESS;
921 \details Read Recipients from a message
923 \param obj_message the message we want to read recipients from
924 \param RowId the row index we start reading recipients from
925 \param RowCount pointer on the number of recipients
926 \param RecipientRows pointer on the recipients array
928 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
930 \note Developers may also call GetLastError() to retrieve the last
931 MAPI error code. Possible MAPI error codes are:
932 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
933 - MAPI_E_CALL_FAILED: A network problem was encountered during the
936 \sa ModifyRecipients, RemoveAllRecipients, GetRecipientTable,
939 _PUBLIC_ enum MAPISTATUS ReadRecipients(mapi_object_t *obj_message,
940 uint32_t RowId, uint8_t *RowCount,
941 struct ReadRecipientRow **RecipientRows)
943 struct mapi_request *mapi_request;
944 struct mapi_response *mapi_response;
945 struct EcDoRpc_MAPI_REQ *mapi_req;
946 struct ReadRecipients_req request;
947 struct ReadRecipients_repl *reply;
948 struct mapi_session *session;
950 enum MAPISTATUS retval;
956 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
958 session = mapi_object_get_session(obj_message);
959 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
961 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
964 mem_ctx = talloc_named(session, 0, "ReadRecipients");
967 /* Fill the ReadRecipients operation */
968 request.RowId = RowId;
969 size += sizeof (uint32_t);
971 request.ulReserved = 0;
972 size += sizeof (uint16_t);
974 /* Fill the MAPI_REQ request */
975 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
976 mapi_req->opnum = op_MAPI_ReadRecipients;
977 mapi_req->logon_id = logon_id;
978 mapi_req->handle_idx = 0;
979 mapi_req->u.mapi_ReadRecipients = request;
982 /* Fill the mapi_request structure */
983 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
984 mapi_request->mapi_len = size + sizeof (uint32_t);
985 mapi_request->length = size;
986 mapi_request->mapi_req = mapi_req;
987 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
988 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
990 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
991 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
992 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
993 retval = mapi_response->mapi_repl->error_code;
994 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
996 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
998 /* Retrieve the recipients */
999 reply = &mapi_response->mapi_repl->u.mapi_ReadRecipients;
1000 *RowCount = reply->RowCount;
1001 *RecipientRows = talloc_steal((TALLOC_CTX *)session, reply->RecipientRows);
1003 talloc_free(mapi_response);
1004 talloc_free(mem_ctx);
1006 return MAPI_E_SUCCESS;
1011 \details Deletes all recipients from a message
1013 \param obj_message the message we want to remove all recipients from
1015 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1017 \note Developers may also call GetLastError() to retrieve the last
1018 MAPI error code. Possible MAPI error codes are:
1019 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1020 - MAPI_E_CALL_FAILED: A network problem was encountered during the
1023 \sa ModifyRecipients, ReadRecipients
1025 _PUBLIC_ enum MAPISTATUS RemoveAllRecipients(mapi_object_t *obj_message)
1027 struct mapi_request *mapi_request;
1028 struct mapi_response *mapi_response;
1029 struct EcDoRpc_MAPI_REQ *mapi_req;
1030 struct RemoveAllRecipients_req request;
1031 struct mapi_session *session;
1033 enum MAPISTATUS retval;
1035 TALLOC_CTX *mem_ctx;
1039 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1041 session = mapi_object_get_session(obj_message);
1042 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1044 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
1047 mem_ctx = talloc_named(session, 0, "RemoveAllRecipients");
1050 /* Fill the RemoveAllRecipients operation */
1051 request.ulReserved = 0;
1052 size += sizeof (uint32_t);
1054 /* Fill the MAPI_REQ request */
1055 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1056 mapi_req->opnum = op_MAPI_RemoveAllRecipients;
1057 mapi_req->logon_id = logon_id;
1058 mapi_req->handle_idx = 0;
1059 mapi_req->u.mapi_RemoveAllRecipients = request;
1062 /* Fill the mapi_request structure */
1063 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1064 mapi_request->mapi_len = size + sizeof (uint32_t);
1065 mapi_request->length = size;
1066 mapi_request->mapi_req = mapi_req;
1067 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1068 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
1070 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1071 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1072 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1073 retval = mapi_response->mapi_repl->error_code;
1074 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1076 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1078 talloc_free(mapi_response);
1079 talloc_free(mem_ctx);
1081 return MAPI_E_SUCCESS;
1086 \details Saves all changes to the message and marks it as ready for
1089 This function saves all changes made to a message and marks it
1092 \param obj_message the message to mark complete
1094 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1096 \note Developers may also call GetLastError() to retrieve the last
1097 MAPI error code. Possible MAPI error codes are:
1098 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1099 - MAPI_E_CALL_FAILED: A network problem was encountered during the
1102 \sa CreateMessage, SetProps, ModifyRecipients, SetRecipientType,
1105 _PUBLIC_ enum MAPISTATUS SubmitMessage(mapi_object_t *obj_message)
1107 struct mapi_request *mapi_request;
1108 struct mapi_response *mapi_response;
1109 struct EcDoRpc_MAPI_REQ *mapi_req;
1110 struct SubmitMessage_req request;
1111 struct mapi_session *session;
1113 enum MAPISTATUS retval;
1115 TALLOC_CTX *mem_ctx;
1119 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1121 session = mapi_object_get_session(obj_message);
1122 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1124 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
1127 mem_ctx = talloc_named(session, 0, "SubmitMessage");
1130 /* Fill the SubmitMessage operation */
1131 request.SubmitFlags = None;
1132 size += sizeof(uint8_t);
1134 /* Fill the MAPI_REQ request */
1135 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1136 mapi_req->opnum = op_MAPI_SubmitMessage;
1137 mapi_req->logon_id = logon_id;
1138 mapi_req->handle_idx = 0;
1139 mapi_req->u.mapi_SubmitMessage = request;
1142 /* Fill the mapi_request structure */
1143 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1144 mapi_request->mapi_len = size + sizeof (uint32_t);
1145 mapi_request->length = size;
1146 mapi_request->mapi_req = mapi_req;
1147 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1148 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
1150 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1151 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1152 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1153 retval = mapi_response->mapi_repl->error_code;
1154 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1156 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1158 talloc_free(mapi_response);
1159 talloc_free(mem_ctx);
1161 return MAPI_E_SUCCESS;
1166 \details Aborts a previous message submission.
1168 \param obj_store the store object
1169 \param obj_folder the folder object where the message has been
1171 \param obj_message the submitted message object
1173 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1175 \note Developers may also call GetLastError() to retrieve the last
1176 MAPI error code. Possible MAPI error codes are:
1177 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1178 - MAPI_E_CALL_FAILED: A network problem was encountered during the
1180 - MAPI_E_UNABLE_TO_ABORT: The operation can not be aborted
1181 - MAPI_E_NOT_IN_QUEUE: The message is no longer in the message store's
1183 - MAPI_E_NO_SUPPORT: the server object associated with the input
1184 handle index in the server object table is not of type Logon or
1185 the current logon session is a public logon.
1189 _PUBLIC_ enum MAPISTATUS AbortSubmit(mapi_object_t *obj_store,
1190 mapi_object_t *obj_folder,
1191 mapi_object_t *obj_message)
1193 struct mapi_request *mapi_request;
1194 struct mapi_response *mapi_response;
1195 struct EcDoRpc_MAPI_REQ *mapi_req;
1196 struct AbortSubmit_req request;
1197 struct mapi_session *session[2];
1199 enum MAPISTATUS retval;
1201 TALLOC_CTX *mem_ctx;
1205 OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
1206 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1208 session[0] = mapi_object_get_session(obj_store);
1209 session[1] = mapi_object_get_session(obj_message);
1210 OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
1211 OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
1212 OPENCHANGE_RETVAL_IF(session[0] != session[1], MAPI_E_INVALID_PARAMETER, NULL);
1214 if ((retval = mapi_object_get_logon_id(obj_store, &logon_id)) != MAPI_E_SUCCESS)
1217 mem_ctx = talloc_named(session[0], 0, "AbortSubmit");
1220 /* Fill the AbortSubmit operation */
1221 request.FolderId = mapi_object_get_id(obj_folder);
1222 size += sizeof (uint64_t);
1224 request.MessageId = mapi_object_get_id(obj_message);
1225 size += sizeof (uint64_t);
1227 /* Fill the MAPI_REQ request */
1228 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1229 mapi_req->opnum = op_MAPI_AbortSubmit;
1230 mapi_req->logon_id = logon_id;
1231 mapi_req->handle_idx = 0;
1232 mapi_req->u.mapi_AbortSubmit = request;
1235 /* Fill the mapi_request structure */
1236 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1237 mapi_request->mapi_len = size + sizeof (uint32_t);
1238 mapi_request->length = size;
1239 mapi_request->mapi_req = mapi_req;
1240 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1241 mapi_request->handles[0] = mapi_object_get_handle(obj_store);
1243 status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
1244 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1245 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1246 retval = mapi_response->mapi_repl->error_code;
1247 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1249 OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1251 talloc_free(mapi_response);
1252 talloc_free(mem_ctx);
1254 return MAPI_E_SUCCESS;
1259 \details Saves all changes to the message
1261 \param parent the parent object for the message
1262 \param obj_message the message to save
1263 \param SaveFlags specify how the save operation behaves
1265 Possible value for SaveFlags:
1266 -# KeepReadOnly Keep the Message object open with read-only access
1267 -# KeepOpenReadWrite Keep the Message object open with read-write
1269 -# ForceSave Commit the changes and keep the message object open
1270 with read-write access
1272 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1274 \note Developers may also call GetLastError() to retrieve the last
1275 MAPI error code. Possible MAPI error codes are:
1276 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1277 - MAPI_E_CALL_FAILED: A network problem was encountered during the
1280 \sa SetProps, ModifyRecipients, GetLastError
1282 _PUBLIC_ enum MAPISTATUS SaveChangesMessage(mapi_object_t *parent,
1283 mapi_object_t *obj_message,
1286 struct mapi_request *mapi_request;
1287 struct mapi_response *mapi_response;
1288 struct EcDoRpc_MAPI_REQ *mapi_req;
1289 struct SaveChangesMessage_req request;
1290 struct mapi_session *session[2];
1292 enum MAPISTATUS retval;
1294 TALLOC_CTX *mem_ctx;
1298 OPENCHANGE_RETVAL_IF(!parent, MAPI_E_INVALID_PARAMETER, NULL);
1299 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1300 OPENCHANGE_RETVAL_IF((SaveFlags != 0x9) && (SaveFlags != 0xA) &&
1301 (SaveFlags != 0xC), MAPI_E_INVALID_PARAMETER, NULL);
1303 session[0] = mapi_object_get_session(parent);
1304 session[1] = mapi_object_get_session(obj_message);
1305 OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
1306 OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
1308 if ((retval = mapi_object_get_logon_id(parent, &logon_id)) != MAPI_E_SUCCESS)
1311 mem_ctx = talloc_named(session[0], 0, "SaveChangesMessage");
1314 /* Fill the SaveChangesMessage operation */
1315 request.handle_idx = 0x1;
1316 size += sizeof (uint8_t);
1318 request.SaveFlags = SaveFlags;
1319 size += sizeof(uint8_t);
1321 /* Fill the MAPI_REQ request */
1322 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1323 mapi_req->opnum = op_MAPI_SaveChangesMessage;
1324 mapi_req->logon_id = logon_id;
1325 mapi_req->handle_idx = 0;
1326 mapi_req->u.mapi_SaveChangesMessage = request;
1329 /* Fill the mapi_request structure */
1330 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1331 mapi_request->mapi_len = size + (2 * sizeof (uint32_t));
1332 mapi_request->length = size;
1333 mapi_request->mapi_req = mapi_req;
1334 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
1335 mapi_request->handles[0] = mapi_object_get_handle(parent);
1336 mapi_request->handles[1] = mapi_object_get_handle(obj_message);
1338 status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
1339 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1340 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1341 retval = mapi_response->mapi_repl->error_code;
1342 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1344 OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1346 /* store the message_id */
1347 mapi_object_set_id(obj_message, mapi_response->mapi_repl->u.mapi_SaveChangesMessage.MessageId);
1349 talloc_free(mapi_response);
1350 talloc_free(mem_ctx);
1352 return MAPI_E_SUCCESS;
1356 \details Sends the specified Message object out for message
1360 _PUBLIC_ enum MAPISTATUS TransportSend(mapi_object_t *obj_message,
1361 struct mapi_SPropValue_array *lpProps)
1363 struct mapi_request *mapi_request;
1364 struct mapi_response *mapi_response;
1365 struct EcDoRpc_MAPI_REQ *mapi_req;
1366 struct TransportSend_repl *reply;
1367 struct mapi_session *session;
1369 enum MAPISTATUS retval;
1371 TALLOC_CTX *mem_ctx;
1375 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1376 OPENCHANGE_RETVAL_IF(!lpProps, MAPI_E_INVALID_PARAMETER, NULL);
1378 session = mapi_object_get_session(obj_message);
1379 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1381 if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
1384 mem_ctx = talloc_named(session, 0, "TransportSend");
1387 /* Fill the MAPI_REQ request */
1388 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1389 mapi_req->opnum = op_MAPI_TransportSend;
1390 mapi_req->logon_id = logon_id;
1391 mapi_req->handle_idx = 0;
1394 /* Fill the mapi_request structure */
1395 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1396 mapi_request->mapi_len = size + sizeof (uint32_t);
1397 mapi_request->length = size;
1398 mapi_request->mapi_req = mapi_req;
1399 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1400 mapi_request->handles[0] = mapi_object_get_handle(obj_message);
1402 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1403 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1404 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1405 retval = mapi_response->mapi_repl->error_code;
1406 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1408 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1410 /* Retrieve reply parameters */
1411 reply = &mapi_response->mapi_repl->u.mapi_TransportSend;
1412 if (!reply->NoPropertiesReturned) {
1413 lpProps->cValues = reply->properties.lpProps.cValues;
1414 lpProps->lpProps = talloc_steal((TALLOC_CTX *)session, reply->properties.lpProps.lpProps);
1416 lpProps->cValues = 0;
1417 lpProps->lpProps = NULL;
1420 talloc_free(mapi_response);
1421 talloc_free(mem_ctx);
1423 return MAPI_E_SUCCESS;
1428 \details Returns the message recipient table
1430 \param obj_message the message to receive recipients from
1431 \param SRowSet pointer to the recipient table
1432 \param SPropTagArray pointer to the array of properties listed in
1435 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1437 \note Developers may also call GetLastError() to retrieve the last
1438 MAPI error code. Possible MAPI error codes are:
1439 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1443 _PUBLIC_ enum MAPISTATUS GetRecipientTable(mapi_object_t *obj_message,
1444 struct SRowSet *SRowSet,
1445 struct SPropTagArray *SPropTagArray)
1447 mapi_object_message_t *message;
1449 message = (mapi_object_message_t *)obj_message->private_data;
1451 OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_NOT_INITIALIZED, NULL);
1452 OPENCHANGE_RETVAL_IF(!message, MAPI_E_NOT_INITIALIZED, NULL);
1454 *SRowSet = message->SRowSet;
1455 *SPropTagArray = message->SPropTagArray;
1457 return MAPI_E_SUCCESS;
1462 \details Clear or set the MSGFLAG_READ flag for a given message
1464 This function clears or sets the MSGFLAG_READ flag in the
1465 PR_MESSAGE_FLAGS property of a given message.
1467 \param obj_folder the folder to operate in
1468 \param obj_child the message to set flags on
1469 \param flags the new flags (MSGFLAG_READ) value
1471 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1473 \note Developers may also call GetLastError() to retrieve the last
1474 MAPI error code. Possible MAPI error codes are:
1475 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1476 - MAPI_E_CALL_FAILED: A network problem was encountered during the
1479 \sa OpenMessage, GetLastError
1481 _PUBLIC_ enum MAPISTATUS SetMessageReadFlag(mapi_object_t *obj_folder,
1482 mapi_object_t *obj_child,
1485 struct mapi_request *mapi_request;
1486 struct mapi_response *mapi_response;
1487 struct EcDoRpc_MAPI_REQ *mapi_req;
1488 struct SetMessageReadFlag_req request;
1489 struct mapi_session *session[2];
1491 enum MAPISTATUS retval;
1493 TALLOC_CTX *mem_ctx;
1497 OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
1498 OPENCHANGE_RETVAL_IF(!obj_child, MAPI_E_INVALID_PARAMETER, NULL);
1500 session[0] = mapi_object_get_session(obj_folder);
1501 session[1] = mapi_object_get_session(obj_child);
1502 OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
1503 OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
1505 if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
1508 mem_ctx = talloc_named(session[0], 0, "SetMessageReadFlags");
1511 /* Fill the SetMessageReadFlags operation */
1512 request.handle_idx = 0x1;
1513 size += sizeof(uint8_t);
1514 request.flags = flags;
1515 size += sizeof(uint8_t);
1517 /* TEMP HACK, see exchange.idl:
1518 request.clientdata.length = 0;
1519 request.clientdata.data = NULL;
1522 /* Fill the MAPI_REQ request */
1523 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1524 mapi_req->opnum = op_MAPI_SetMessageReadFlag;
1525 mapi_req->logon_id = logon_id;
1526 mapi_req->handle_idx = 0;
1527 mapi_req->u.mapi_SetMessageReadFlag = request;
1530 /* Fill the mapi_request structure */
1531 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1532 mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
1533 mapi_request->length = size;
1534 mapi_request->mapi_req = mapi_req;
1535 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
1536 mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
1537 mapi_request->handles[1] = mapi_object_get_handle(obj_child);
1539 status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
1540 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1541 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1542 retval = mapi_response->mapi_repl->error_code;
1543 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1545 OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1547 talloc_free(mapi_response);
1548 talloc_free(mem_ctx);
1550 return MAPI_E_SUCCESS;
1554 \details Opens an embedded message object and retrieves a MAPI object that
1555 can be used to get or set properties on the embedded message.
1557 This function essentially takes an attachment and gives you back
1560 \param obj_attach the attachment object
1561 \param obj_embeddedmsg the embedded message
1562 \param ulFlags access rights on the embedded message
1564 Possible ulFlags values:
1565 - 0x0: read only access
1566 - 0x1: Read / Write access
1570 ... assume we have a message - obj_message ...
1571 // Initialise the attachment object
1572 mapi_object_init(&obj_attach);
1574 // Create an attachment to the message
1575 retval = CreateAttach(&obj_message, &obj_attach);
1576 ... check the return value ...
1578 // use SetProps() to set the attachment up, noting the special PR_ATTACHM_METHOD property
1579 attach[0].ulPropTag = PR_ATTACH_METHOD;
1580 attach[0].value.l = ATTACH_EMBEDDED_MSG;
1581 attach[1].ulPropTag = PR_RENDERING_POSITION;
1582 attach[1].value.l = 0;
1583 retval = SetProps(&obj_attach, 0, attach, 2);
1584 ... check the return value ...
1586 // Initialise the embedded message object
1587 mapi_object_init(&obj_embeddedmsg);
1588 retval = OpenEmbeddedMessage(&obj_attach, &obj_embeddedmsg, MAPI_CREATE);
1589 ... check the return value ...
1591 // Fill in the embedded message properties, just like any other message (e.g. resulting from CreateMessage())
1593 // Save the changes to the embedded message
1594 retval = SaveChangesMessage(&obj_message, &obj_embeddedmsg, KeepOpenReadOnly);
1595 ... check the return value ...
1597 // Save the changes to the attachment
1598 retval = SaveChangesAttachment(&obj_message, &obj_attach, KeepOpenReadOnly);
1599 ... check the return value ...
1601 // Save the changes to the original message
1602 retval = SaveChangesMessage(&obj_folder, &obj_message, KeepOpenReadOnly);
1603 ... check the return value ...
1606 \return MAPI_E_SUCCESS on success, otherwise MAPI error. Possible
1607 MAPI error codes are:
1608 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1609 - MAPI_E_INVALID_PARAMETER: obj_store is undefined
1610 - MAPI_E_CALL_FAILED: A network problem was encountered during the
1613 \note Developers may also call GetLastError() to retrieve the last
1616 \sa CreateAttach, OpenMessage, GetLastError
1618 _PUBLIC_ enum MAPISTATUS OpenEmbeddedMessage(mapi_object_t *obj_attach,
1619 mapi_object_t *obj_embeddedmsg,
1620 enum OpenEmbeddedMessage_OpenModeFlags ulFlags)
1622 struct mapi_context *mapi_ctx;
1623 struct mapi_request *mapi_request;
1624 struct mapi_response *mapi_response;
1625 struct EcDoRpc_MAPI_REQ *mapi_req;
1626 struct OpenEmbeddedMessage_req request;
1627 struct OpenEmbeddedMessage_repl *reply;
1628 struct mapi_session *session;
1629 mapi_object_message_t *message;
1630 struct SPropValue lpProp;
1632 enum MAPISTATUS retval;
1634 TALLOC_CTX *mem_ctx;
1639 OPENCHANGE_RETVAL_IF(!obj_attach, MAPI_E_INVALID_PARAMETER, NULL);
1640 session = mapi_object_get_session(obj_attach);
1641 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1642 OPENCHANGE_RETVAL_IF(!obj_embeddedmsg, MAPI_E_INVALID_PARAMETER, NULL);
1644 mapi_ctx = session->mapi_ctx;
1645 OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1647 if ((retval = mapi_object_get_logon_id(obj_attach, &logon_id)) != MAPI_E_SUCCESS)
1650 mem_ctx = talloc_named(session, 0, "OpenEmbeddedMessage");
1652 /* Fill the OpenEmbeddedMessage request */
1653 request.handle_idx = 0x1;
1654 size += sizeof(uint8_t);
1655 request.CodePageId = 0xfff;
1656 size += sizeof(uint16_t);
1657 request.OpenModeFlags = ulFlags;
1658 size += sizeof(uint8_t);
1660 /* Fill the MAPI_REQ request */
1661 mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1662 mapi_req->opnum = op_MAPI_OpenEmbeddedMessage;
1663 mapi_req->logon_id = logon_id;
1664 mapi_req->handle_idx = 0;
1665 mapi_req->u.mapi_OpenEmbeddedMessage = request;
1668 /* Fill the mapi_request structure */
1669 mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1670 mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
1671 mapi_request->length = size;
1672 mapi_request->mapi_req = mapi_req;
1673 mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
1674 mapi_request->handles[0] = mapi_object_get_handle(obj_attach);
1675 mapi_request->handles[1] = mapi_object_get_handle(obj_embeddedmsg);
1677 status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1678 OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1679 OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1680 retval = mapi_response->mapi_repl->error_code;
1681 OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1683 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1685 /* Set object session and handle */
1686 mapi_object_set_session(obj_embeddedmsg, session);
1687 mapi_object_set_handle(obj_embeddedmsg, mapi_response->handles[1]);
1688 mapi_object_set_logon_id(obj_embeddedmsg, logon_id);
1690 /* Store OpenEmbeddedMessage reply data */
1691 reply = &mapi_response->mapi_repl->u.mapi_OpenEmbeddedMessage;
1693 message = talloc_zero((TALLOC_CTX *)session, mapi_object_message_t);
1694 message->cValues = reply->RecipientCount;
1695 message->SRowSet.cRows = reply->RowCount;
1696 message->SRowSet.aRow = talloc_array((TALLOC_CTX *)message, struct SRow, reply->RowCount + 1);
1698 message->SPropTagArray.cValues = reply->RecipientColumns.cValues;
1699 message->SPropTagArray.aulPropTag = talloc_steal(message, reply->RecipientColumns.aulPropTag);
1701 for (i = 0; i < reply->RowCount; i++) {
1702 emsmdb_get_SRow((TALLOC_CTX *)message, mapi_ctx->lp_ctx,
1703 &(message->SRowSet.aRow[i]), &message->SPropTagArray,
1704 reply->RecipientRows[i].RecipientRow.prop_count,
1705 &reply->RecipientRows[i].RecipientRow.prop_values,
1706 reply->RecipientRows[i].RecipientRow.layout, 1);
1708 lpProp.ulPropTag = PR_RECIPIENT_TYPE;
1709 lpProp.value.l = reply->RecipientRows[i].RecipientType;
1710 SRow_addprop(&(message->SRowSet.aRow[i]), lpProp);
1712 lpProp.ulPropTag = PR_INTERNET_CPID;
1713 lpProp.value.l = reply->RecipientRows[i].CodePageId;
1714 SRow_addprop(&(message->SRowSet.aRow[i]), lpProp);
1717 /* add SPropTagArray elements we automatically append to SRow */
1718 SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_RECIPIENT_TYPE);
1719 SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_INTERNET_CPID);
1721 obj_embeddedmsg->private_data = (void *) message;
1723 talloc_free(mapi_response);
1724 talloc_free(mem_ctx);
1726 return MAPI_E_SUCCESS;