Fix typo err in AbortSubmit
[jelmer/openchange-proposed.git/.git] / libmapi / IMessage.c
1 /*
2    OpenChange MAPI implementation.
3
4    Copyright (C) Julien Kerihuel 2007-2008.
5    Copyright (C) Fabien Le Mentec 2007.
6
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.
11    
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.
16    
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/>.
19  */
20
21 #include "libmapi/libmapi.h"
22 #include "libmapi/libmapi_private.h"
23 #include "gen_ndr/ndr_exchange.h"
24 #include <param.h>
25
26
27 /**
28    \file IMessage.c
29
30    \brief Operations on messages
31  */
32
33
34 /**
35    \details Create a new attachment
36
37    This function creates a new attachment to an existing message.
38
39    \param obj_message the message to attach to
40    \param obj_attach the attachment
41
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 
44    initialised.
45
46    \code
47    enum MAPISTATUS         retval;
48    mapi_object_t           obj_message;
49    mapi_object_t           obj_attach;
50
51    ... open or create the obj_message ...
52
53    mapi_object_init(&obj_attach);
54    retval = CreateAttach(&obj_message, &obj_attach);
55    ... check the return value ...
56
57    ... use SetProps() to set the attachment up ...
58    ... perhaps OpenStream() / WriteStream() / CommitStream() on obj_attach ...
59
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 ...
65    \endcode
66
67    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
68
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
73      transaction
74
75    \sa CreateMessage, GetAttachmentTable, OpenAttach, GetLastError
76 */
77 _PUBLIC_ enum MAPISTATUS CreateAttach(mapi_object_t *obj_message, 
78                                       mapi_object_t *obj_attach)
79 {
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;
85         NTSTATUS                status;
86         enum MAPISTATUS         retval;
87         uint32_t                size = 0;
88         TALLOC_CTX              *mem_ctx;
89         uint8_t                 logon_id;
90
91         /* Sanity checks */
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);
95
96         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
97                 return retval;
98
99         mem_ctx = talloc_named(session, 0, "CreateAttach");
100         size = 0;
101
102         /* Fill the CreateAttach operation */
103         request.handle_idx = 0x1;
104         size += sizeof (uint8_t);
105
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;
112         size += 5;
113
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;
122
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);
128
129         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
130
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);
135
136         talloc_free(mapi_response);
137         talloc_free(mem_ctx);
138
139         return MAPI_E_SUCCESS;
140 }
141
142
143 /**
144    \details Delete an attachment from a message
145
146    This function deletes one attachment from a message. The attachment
147    to be deleted is specified by its PR_ATTACH_NUM
148
149    \param obj_message the message to operate on
150    \param AttachmentID the attachment number
151
152    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
153
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
158      transaction
159
160    \sa CreateMessage, GetAttachmentTable, GetLastError
161  */
162 _PUBLIC_ enum MAPISTATUS DeleteAttach(mapi_object_t *obj_message, uint32_t AttachmentID)
163 {
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;
169         NTSTATUS                status;
170         enum MAPISTATUS         retval;
171         uint32_t                size = 0;
172         TALLOC_CTX              *mem_ctx;
173         uint8_t                 logon_id;
174
175         /* Sanity checks */
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);
179
180         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
181                 return retval;
182
183         mem_ctx = talloc_named(session, 0, "DeleteAttach");
184         size = 0;
185
186         /* Fill the DeleteAttach operation */
187         request.AttachmentID = AttachmentID;
188         size += sizeof (uint32_t);
189
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;
196         size += 5;
197
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);
205
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);
211
212         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
213
214         talloc_free(mapi_response);
215         talloc_free(mem_ctx);
216         
217         return MAPI_E_SUCCESS;
218 }
219
220
221 /**
222    \details Retrieve the attachment table for a message
223
224    \param obj_message the message
225    \param obj_table the attachment table for the message
226
227    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
228
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
233      transaction
234
235    \sa CreateMessage, OpenMessage, CreateAttach, OpenAttach, GetLastError
236 */
237 _PUBLIC_ enum MAPISTATUS GetAttachmentTable(mapi_object_t *obj_message, 
238                                             mapi_object_t *obj_table)
239 {
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;
245         NTSTATUS                        status;
246         enum MAPISTATUS                 retval;
247         TALLOC_CTX                      *mem_ctx;
248         uint32_t                        size = 0;
249         uint8_t                         logon_id;
250
251         /* Sanity checks */
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);
256
257         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
258                 return retval;
259
260         mem_ctx = talloc_named(session, 0, "GetAttachmentTable");
261         size = 0;
262
263         /* Fill the GetAttachmentTable operation */
264         request.handle_idx = 1;
265         size += sizeof (uint8_t);
266
267         request.TableFlags = 0x0;
268         size += sizeof (uint8_t);
269
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;
276         size += 5;
277
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;
286
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);
292
293         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
294
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);
299
300         talloc_free(mapi_response);
301         talloc_free(mem_ctx);
302
303         return MAPI_E_SUCCESS;
304 }
305
306
307 /**
308    \details Get the valid attachment IDs for a message
309
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.
312
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
316
317    The AttachmentIds array has NumAttachments elements.
318
319    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
320
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
326      transaction
327
328    \sa OpenAttach, DeleteAttach
329  */
330 _PUBLIC_ enum MAPISTATUS GetValidAttach(mapi_object_t *obj_message, uint16_t *NumAttachments, uint32_t **AttachmentIds)
331 {
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;
337         NTSTATUS                        status;
338         enum MAPISTATUS                 retval;
339         uint32_t                        size = 0;
340         TALLOC_CTX                      *mem_ctx;
341         uint8_t                         logon_id;
342
343         /* Sanity checks */
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);
349
350         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
351                 return retval;
352         mem_ctx = talloc_named(session, 0, "GetValidAttach");
353         size = 0;
354
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;
360         size += 5;
361
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);
369
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);
375
376         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
377
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); 
382         
383         talloc_free(mapi_response);
384         talloc_free(mem_ctx);
385         
386         return MAPI_E_SUCCESS;
387 }
388
389 /**
390    \details Open an attachment to a message
391
392    This function opens one attachment from a message. The attachment
393    to be opened is specified by its PR_ATTACH_NUM.
394
395    \param obj_message the message to operate on
396    \param AttachmentID the attachment number
397    \param obj_attach the resulting attachment object
398
399    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
400
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
405      transaction
406
407    \sa CreateMessage, CreateAttach, GetAttachmentTable, GetLastError
408 */
409 _PUBLIC_ enum MAPISTATUS OpenAttach(mapi_object_t *obj_message, uint32_t AttachmentID,
410                                     mapi_object_t *obj_attach)
411 {
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;
417         NTSTATUS                status;
418         enum MAPISTATUS         retval;
419         uint32_t                size = 0;
420         TALLOC_CTX              *mem_ctx;
421         uint8_t                 logon_id;
422
423         /* Sanity checks */
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);
427
428         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
429                 return retval;
430
431         mem_ctx = talloc_named(session, 0, "OpenAttach");
432         size = 0;
433
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);
441
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;
448         size += 5;
449
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;
458
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);
464
465         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
466
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);
471
472         talloc_free(mapi_response);
473         talloc_free(mem_ctx);
474
475         return MAPI_E_SUCCESS;
476 }
477
478
479 /**
480    \details Set the type of a recipient
481
482    The function sets the recipient type (RecipClass) in the aRow
483    parameter.  ResolveNames should be used to fill the SRow structure.
484
485    \param aRow the row to set
486    \param RecipClass the type of recipient to set on the specified row
487
488    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
489
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
493      properly.
494
495    \sa ResolveNames, ModifyRecipients, GetLastError
496 */
497 _PUBLIC_ enum MAPISTATUS SetRecipientType(struct SRow *aRow, enum ulRecipClass RecipClass)
498 {
499         enum MAPISTATUS         retval;
500         struct SPropValue       lpProp;
501
502         lpProp.ulPropTag = PR_RECIPIENT_TYPE;
503         lpProp.value.l = RecipClass;
504
505         retval = SRow_addprop(aRow, lpProp);
506         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
507
508         return MAPI_E_SUCCESS;
509 }
510
511
512 /*
513  * retrieve the organization length for Exchange recipients
514  */
515 uint8_t mapi_recipients_get_org_length(struct mapi_profile *profile)
516 {
517         if (profile->mailbox && profile->username)
518                 return (strlen(profile->mailbox) - strlen(profile->username));
519         return 0;
520 }
521
522
523 /**
524    \details RecipientFlags bitmask calculation for RecipientRows
525    structure.
526
527    \param aRow pointer to the SRow structures with the properties to
528    pass to ModifyRecipients.
529
530    According to MS-OXCDATA 2.9.3.1 RecipientFlags structure, the bitmask
531    can be represented as the following:
532
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    +------+---+---+---+---+---+---+---+---+----------+---+
537    
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
549
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.
553
554    For further information about PidTagAddressType, refer to
555    [MS-OXCMAIL] section 2.1.1.9
556
557    \return uint16_t holding the RecipientFlags value. 0 is returned
558    when an inconsistency or a failure occurs
559
560  */
561 uint16_t mapi_recipients_RecipientFlags(struct SRow *aRow)
562 {
563         uint16_t                bitmask;
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;
570
571         /* Sanity Checks */
572         if (!aRow) return 0;
573
574         bitmask = 0;
575
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;
580         } else {
581                 lpProp = get_SPropValue_SRow(aRow, PR_ADDRTYPE_UNICODE);
582                 if (lpProp && lpProp->value.lpszW) {
583                         unicode = true;
584                         addrtype = lpProp->value.lpszW;
585                 } 
586         }
587
588         if (!addrtype) {
589                 return 0;
590         }
591         /* WARNING: This check is yet incomplete */
592         if (!strcmp("EX", addrtype)) { 
593                 bitmask |= 0x1;
594         } else if (!strcmp("SMTP", addrtype)) {
595                 bitmask |= 0x3;
596         }
597
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);
601                 if (lpProp) {
602                         tmp = (unicode == true) ? lpProp->value.lpszW : lpProp->value.lpszA;
603                         if (tmp) {
604                                 bitmask |= 0x8;
605                         }
606                 }
607         }
608
609         /* (D) - 0x10: PR_DISPLAY_NAME */
610         lpProp = get_SPropValue_SRow(aRow, (unicode == true) ? PR_DISPLAY_NAME_UNICODE : PR_DISPLAY_NAME);
611         if (lpProp) {
612                 display_name = (unicode == true) ? lpProp->value.lpszW : lpProp->value.lpszA;
613                 if (display_name) {
614                         bitmask |= 0x10;
615                 }
616         }
617
618         /* (T) - 0x20: PR_TRANSMITTABLE_DISPLAY_NAME */
619         lpProp = get_SPropValue_SRow(aRow, (unicode == true) ? PR_TRANSMITTABLE_DISPLAY_NAME_UNICODE : PR_TRANSMITTABLE_DISPLAY_NAME);
620         if (lpProp) {
621                 transmit_display_name = (unicode == true) ? lpProp->value.lpszW : lpProp->value.lpszA;
622                 if (transmit_display_name) {
623                         if (!display_name) {
624                                 bitmask |= 0x20;
625                         } else if (display_name && strcmp(display_name, transmit_display_name)) {
626                                 bitmask |= 0x20;
627                         }
628                 }
629         }
630
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)) {
634                         bitmask |= 0x40;
635                 }
636         }
637
638         /* (R) - 0x80: Different transport is responsible for delivery */
639         if (addrtype && strcmp(addrtype, "EX")) {
640                 bitmask |= 0x80;
641         }
642
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)) {
646                 bitmask |= 0x100;
647         }
648
649         /* (U) - 0x200: Unicode properties */
650         if (unicode == true) {
651                 bitmask |= 0x200;
652         }
653
654         /* (I) - 0x400: PR_7BIT_DISPLAY_NAME */
655         lpProp = get_SPropValue_SRow(aRow, (unicode == true) ? PR_7BIT_DISPLAY_NAME_UNICODE : PR_7BIT_DISPLAY_NAME);
656         if (lpProp) {
657                 tmp = (unicode == true) ? lpProp->value.lpszW : lpProp->value.lpszA;
658                 if (tmp) {
659                         bitmask |= 0x400;
660                 }
661         }
662
663         return bitmask;
664 }
665
666
667 /**
668    \details Adds, deletes or modifies message recipients
669
670    \param obj_message the message to change the recipients for
671    \param SRowSet the recipients to add
672
673    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
674
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).
682
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
687      transaction
688
689    \bug ModifyRecipients can only add recipients.
690
691    \sa CreateMessage, ResolveNames, SetRecipientType, GetLastError
692
693 */
694 _PUBLIC_ enum MAPISTATUS ModifyRecipients(mapi_object_t *obj_message, 
695                                           struct SRowSet *SRowSet)
696 {
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;
702         NTSTATUS                        status;
703         enum MAPISTATUS                 retval;
704         uint32_t                        size = 0;
705         TALLOC_CTX                      *mem_ctx;
706         unsigned long                   i_prop, j;
707         unsigned long                   i_recip;
708         uint32_t                        count;
709         uint8_t                         logon_id;
710
711         /* Sanity checks */
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);
715
716         session = mapi_object_get_session(obj_message);
717         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
718         
719         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
720                 return retval;
721
722         mem_ctx = talloc_named(session, 0, "ModifyRecipients");
723         size = 0;
724
725         /* Fill the ModifyRecipients operation */
726         request.prop_count = SRowSet->aRow[0].cValues;
727         size += sizeof(uint16_t);
728
729         /* 
730          * append here property tags that can be fetched with
731          * ResolveNames but shouldn't be included in ModifyRecipients rows
732          */
733         request.properties = get_MAPITAGS_SRow(mem_ctx, &SRowSet->aRow[0], &count);
734         request.prop_count = MAPITAGS_delete_entries(request.properties, count, 19,
735                                                      PR_ENTRYID,
736                                                      PR_DISPLAY_NAME,
737                                                      PR_DISPLAY_NAME_UNICODE,
738                                                      PR_DISPLAY_NAME_ERROR,
739                                                      PR_GIVEN_NAME,
740                                                      PR_GIVEN_NAME_UNICODE,
741                                                      PR_GIVEN_NAME_ERROR,
742                                                      PR_EMAIL_ADDRESS,
743                                                      PR_EMAIL_ADDRESS_UNICODE,
744                                                      PR_TRANSMITTABLE_DISPLAY_NAME,
745                                                      PR_TRANSMITTABLE_DISPLAY_NAME_UNICODE,
746                                                      PR_RECIPIENT_TYPE,
747                                                      PR_ADDRTYPE,
748                                                      PR_ADDRTYPE_UNICODE,
749                                                      PR_ADDRTYPE_ERROR,
750                                                      PR_SEND_INTERNET_ENCODING,
751                                                      PR_SEND_INTERNET_ENCODING_ERROR,
752                                                      PR_SEND_RICH_INFO,
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);
758
759         for (i_recip = 0; i_recip < request.cValues; i_recip++) {
760                 struct SRow                     *aRow;
761                 struct RecipientRow             *RecipientRow;
762                 struct ndr_push                 *ndr;
763                 struct mapi_SPropValue          mapi_sprop;
764                 const uint32_t                  *RecipClass = 0;
765
766                 ndr = talloc_zero(mem_ctx, struct ndr_push);
767
768                 aRow = &(SRowSet->aRow[i_recip]);
769                 RecipientRow = &(request.RecipientRow[i_recip].RecipientRow);
770                 
771                 request.RecipientRow[i_recip].idx = i_recip;
772                 size += sizeof(uint32_t);
773
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);
778                 
779                 RecipientRow->RecipientFlags = mapi_recipients_RecipientFlags(aRow);
780                 
781                 /* (Type) - 0x0 to 0x7: Recipient type (Exchange, SMTP or other?) */
782                 switch (RecipientRow->RecipientFlags & 0x7) {
783                 case 0x1: 
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) {
788                         case 0x0:
789                                 RecipientRow->X500DN.recipient_x500name = (const char *) find_SPropValue_data(aRow, PR_EMAIL_ADDRESS);
790                                 break;
791                         case 0x200:
792                                 RecipientRow->X500DN.recipient_x500name = (const char *) find_SPropValue_data(aRow, PR_EMAIL_ADDRESS_UNICODE);
793                                 break;
794                         }
795                         size += sizeof(uint32_t) + strlen(RecipientRow->X500DN.recipient_x500name) + 1;
796                         break;
797                 case 0x3:
798                         size += sizeof(uint16_t);
799                         break;
800                 }
801
802                 /* (E) - 0x8: PR_SMTP_ADDRESS */
803                 switch (RecipientRow->RecipientFlags & 0x208) {
804                 case (0x8):
805                         RecipientRow->EmailAddress.lpszA = (const char *) find_SPropValue_data(aRow, PR_SMTP_ADDRESS);
806                         size += strlen(RecipientRow->EmailAddress.lpszA) + 1;
807                         break;
808                 case (0x208):
809                         RecipientRow->EmailAddress.lpszW = (const char *) find_SPropValue_data(aRow, PR_SMTP_ADDRESS_UNICODE);
810                         size += get_utf8_utf16_conv_length(RecipientRow->EmailAddress.lpszW);
811                         break;
812                 default:
813                         break;
814                 }
815
816                 /* (D) - 0x10: PR_DISPLAY_NAME */
817                 switch (RecipientRow->RecipientFlags & 0x210) {
818                 case (0x10):
819                         RecipientRow->DisplayName.lpszA = (const char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME);
820                         size += strlen(RecipientRow->DisplayName.lpszA) + 1;
821                         break;
822                 case (0x210):
823                         RecipientRow->DisplayName.lpszW = (const char *) find_SPropValue_data(aRow, PR_DISPLAY_NAME_UNICODE);
824                         size += get_utf8_utf16_conv_length(RecipientRow->DisplayName.lpszW);
825                         break;
826                 default:
827                         break;
828                 }
829
830                 /* (T) - 0x20: PR_TRANSMITTABLE_DISPLAY_NAME */
831                 switch (RecipientRow->RecipientFlags & 0x260) {
832                 case (0x20):
833                         RecipientRow->TransmittableDisplayName.lpszA = (const char *) find_SPropValue_data(aRow, PR_TRANSMITTABLE_DISPLAY_NAME);
834                         size += strlen(RecipientRow->TransmittableDisplayName.lpszA) + 1;
835                         break;
836                 case (0x220):
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);
839                         break;
840                 default:
841                         break;
842                 }
843                 
844                 
845                 /* (I) - 0x400: PR_7BIT_DISPLAY_NAME */
846                 switch(RecipientRow->RecipientFlags & 0x600) {
847                 case (0x400):
848                         RecipientRow->SimpleDisplayName.lpszA = (const char *) find_SPropValue_data(aRow, PR_7BIT_DISPLAY_NAME);
849                         size += strlen(RecipientRow->SimpleDisplayName.lpszA) + 1;
850                         break;
851                 case (0x600):
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);
854                         break;
855                 default:
856                         break;
857                 }
858
859                 RecipientRow->prop_count = request.prop_count;
860                 size += sizeof(uint16_t);
861                 RecipientRow->layout = 0;
862                 size += sizeof(uint8_t);
863                 
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;
874
875                                         cast_mapi_SPropValue(mem_ctx, &mapi_sprop, &aRow->lpProps[j]);
876                                         ndr_push_mapi_SPropValue_CTR(ndr, NDR_SCALARS, &mapi_sprop.value);
877                                 }
878                         }
879                 }
880                 
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;
886         }
887         
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;
894         size += 5;
895
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);
903
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);
909
910         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
911
912         talloc_free(mapi_response);
913         talloc_free(mem_ctx);
914
915         errno = 0;
916         return MAPI_E_SUCCESS;
917 }
918
919
920 /**
921    \details Read Recipients from a message
922
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
927
928    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
929
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
934      transaction
935
936    \sa ModifyRecipients, RemoveAllRecipients, GetRecipientTable,
937    OpenMessage
938  */
939 _PUBLIC_ enum MAPISTATUS ReadRecipients(mapi_object_t *obj_message, 
940                                         uint32_t RowId, uint8_t *RowCount,
941                                         struct ReadRecipientRow **RecipientRows)
942 {
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;
949         NTSTATUS                        status;
950         enum MAPISTATUS                 retval;
951         uint32_t                        size = 0;
952         TALLOC_CTX                      *mem_ctx;
953         uint8_t                         logon_id;
954
955         /* Sanity checks */
956         OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
957
958         session = mapi_object_get_session(obj_message);
959         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
960
961         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
962                 return retval;
963
964         mem_ctx = talloc_named(session, 0, "ReadRecipients");
965         size = 0;
966
967         /* Fill the ReadRecipients operation */
968         request.RowId = RowId;
969         size += sizeof (uint32_t);
970
971         request.ulReserved = 0;
972         size += sizeof (uint16_t);
973
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;
980         size += 5;
981
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);
989         
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);
995
996         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
997
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);
1002
1003         talloc_free(mapi_response);
1004         talloc_free(mem_ctx);
1005
1006         return MAPI_E_SUCCESS;
1007 }
1008
1009
1010 /**
1011    \details Deletes all recipients from a message
1012
1013    \param obj_message the message we want to remove all recipients from
1014
1015    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1016
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
1021      transaction
1022
1023    \sa ModifyRecipients, ReadRecipients
1024 */
1025 _PUBLIC_ enum MAPISTATUS RemoveAllRecipients(mapi_object_t *obj_message)
1026 {
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;
1032         NTSTATUS                        status;
1033         enum MAPISTATUS                 retval;
1034         uint32_t                        size = 0;
1035         TALLOC_CTX                      *mem_ctx;
1036         uint8_t                         logon_id;
1037
1038         /* Sanity checks */
1039         OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1040
1041         session = mapi_object_get_session(obj_message);
1042         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1043
1044         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
1045                 return retval;
1046
1047         mem_ctx = talloc_named(session, 0, "RemoveAllRecipients");
1048         size = 0;
1049
1050         /* Fill the RemoveAllRecipients operation */
1051         request.ulReserved = 0;
1052         size += sizeof (uint32_t);
1053
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;
1060         size += 5;
1061
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);
1069
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);
1075
1076         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1077
1078         talloc_free(mapi_response);
1079         talloc_free(mem_ctx);
1080         
1081         return MAPI_E_SUCCESS;
1082 }
1083
1084
1085 /**
1086    \details Saves all changes to the message and marks it as ready for
1087    sending.
1088
1089    This function saves all changes made to a message and marks it
1090    ready to be sent.
1091
1092    \param obj_message the message to mark complete
1093
1094    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1095
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
1100      transaction
1101
1102    \sa CreateMessage, SetProps, ModifyRecipients, SetRecipientType,
1103    GetLastError
1104 */
1105 _PUBLIC_ enum MAPISTATUS SubmitMessage(mapi_object_t *obj_message)
1106 {
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;
1112         NTSTATUS                        status;
1113         enum MAPISTATUS                 retval;
1114         uint32_t                        size = 0;
1115         TALLOC_CTX                      *mem_ctx;
1116         uint8_t                         logon_id;
1117
1118         /* Sanity checks */
1119         OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1120
1121         session = mapi_object_get_session(obj_message);
1122         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1123
1124         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
1125                 return retval;
1126
1127         mem_ctx = talloc_named(session, 0, "SubmitMessage");
1128         size = 0;
1129
1130         /* Fill the SubmitMessage operation */
1131         request.SubmitFlags = None;
1132         size += sizeof(uint8_t);
1133
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;
1140         size += 5;
1141
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);
1149
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);
1155
1156         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1157
1158         talloc_free(mapi_response);
1159         talloc_free(mem_ctx);
1160
1161         return MAPI_E_SUCCESS;
1162 }
1163
1164
1165 /**
1166    \details Aborts a previous message submission.
1167
1168    \param obj_store the store object
1169    \param obj_folder the folder object where the message has been
1170    submitted
1171    \param obj_message the submitted message object
1172
1173    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1174
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
1179      transaction
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
1182      spooler queue
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.
1186
1187     \sa SubmitMessage
1188  */
1189 _PUBLIC_ enum MAPISTATUS AbortSubmit(mapi_object_t *obj_store,
1190                                      mapi_object_t *obj_folder, 
1191                                      mapi_object_t *obj_message)
1192 {
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];
1198         NTSTATUS                status;
1199         enum MAPISTATUS         retval;
1200         uint32_t                size = 0;
1201         TALLOC_CTX              *mem_ctx;
1202         uint8_t                 logon_id;
1203
1204         /* Sanity checks */
1205         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
1206         OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1207
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);
1213
1214         if ((retval = mapi_object_get_logon_id(obj_store, &logon_id)) != MAPI_E_SUCCESS)
1215                 return retval;
1216
1217         mem_ctx = talloc_named(session[0], 0, "AbortSubmit");
1218         size = 0;
1219
1220         /* Fill the AbortSubmit operation */
1221         request.FolderId = mapi_object_get_id(obj_folder);
1222         size += sizeof (uint64_t);
1223
1224         request.MessageId = mapi_object_get_id(obj_message);
1225         size += sizeof (uint64_t);
1226
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;
1233         size += 5;
1234
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);
1242
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);
1248
1249         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1250
1251         talloc_free(mapi_response);
1252         talloc_free(mem_ctx);
1253         
1254         return MAPI_E_SUCCESS;
1255 }
1256
1257
1258 /**
1259    \details Saves all changes to the message
1260
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
1264
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
1268       access
1269    -# ForceSave Commit the changes and keep the message object open
1270       with read-write access
1271
1272    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1273
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
1278      transaction
1279
1280    \sa SetProps, ModifyRecipients, GetLastError
1281  */
1282 _PUBLIC_ enum MAPISTATUS SaveChangesMessage(mapi_object_t *parent,
1283                                             mapi_object_t *obj_message,
1284                                             uint8_t SaveFlags)
1285 {
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];
1291         NTSTATUS                        status;
1292         enum MAPISTATUS                 retval;
1293         uint32_t                        size = 0;
1294         TALLOC_CTX                      *mem_ctx;
1295         uint8_t                         logon_id;
1296
1297         /* Sanity checks */
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);
1302
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);
1307
1308         if ((retval = mapi_object_get_logon_id(parent, &logon_id)) != MAPI_E_SUCCESS)
1309                 return retval;
1310
1311         mem_ctx = talloc_named(session[0], 0, "SaveChangesMessage");
1312         size = 0;
1313
1314         /* Fill the SaveChangesMessage operation */
1315         request.handle_idx = 0x1;
1316         size += sizeof (uint8_t);
1317
1318         request.SaveFlags = SaveFlags;
1319         size += sizeof(uint8_t);
1320
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;
1327         size += 5;
1328
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);
1337
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);
1343
1344         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1345
1346         /* store the message_id */
1347         mapi_object_set_id(obj_message, mapi_response->mapi_repl->u.mapi_SaveChangesMessage.MessageId);
1348
1349         talloc_free(mapi_response);
1350         talloc_free(mem_ctx);
1351
1352         return MAPI_E_SUCCESS;
1353 }
1354
1355 /**
1356    \details Sends the specified Message object out for message
1357    delivery.
1358
1359 */
1360 _PUBLIC_ enum MAPISTATUS TransportSend(mapi_object_t *obj_message, 
1361                                        struct mapi_SPropValue_array *lpProps)
1362 {
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;
1368         NTSTATUS                        status;
1369         enum MAPISTATUS                 retval;
1370         uint32_t                        size = 0;
1371         TALLOC_CTX                      *mem_ctx;
1372         uint8_t                         logon_id;
1373
1374         /* Sanity checks */
1375         OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
1376         OPENCHANGE_RETVAL_IF(!lpProps, MAPI_E_INVALID_PARAMETER, NULL);
1377
1378         session = mapi_object_get_session(obj_message);
1379         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1380
1381         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
1382                 return retval;
1383
1384         mem_ctx = talloc_named(session, 0, "TransportSend");
1385         size = 0;
1386
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;
1392         size += 5;
1393
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);
1401
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);
1407
1408         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1409
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);
1415         } else {
1416                 lpProps->cValues = 0;
1417                 lpProps->lpProps = NULL;
1418         }
1419
1420         talloc_free(mapi_response);
1421         talloc_free(mem_ctx);
1422
1423         return MAPI_E_SUCCESS;
1424 }
1425
1426
1427 /**
1428    \details Returns the message recipient table
1429
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
1433    the recipient table
1434
1435    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1436
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
1440
1441      \sa OpenMessage
1442  */
1443 _PUBLIC_ enum MAPISTATUS GetRecipientTable(mapi_object_t *obj_message, 
1444                                            struct SRowSet *SRowSet,
1445                                            struct SPropTagArray *SPropTagArray)
1446 {
1447         mapi_object_message_t   *message;
1448
1449         message = (mapi_object_message_t *)obj_message->private_data;
1450
1451         OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_NOT_INITIALIZED, NULL);
1452         OPENCHANGE_RETVAL_IF(!message, MAPI_E_NOT_INITIALIZED, NULL);
1453
1454         *SRowSet = message->SRowSet;
1455         *SPropTagArray = message->SPropTagArray;
1456
1457         return MAPI_E_SUCCESS;
1458 }
1459
1460
1461 /**
1462    \details Clear or set the MSGFLAG_READ flag for a given message
1463
1464    This function clears or sets the MSGFLAG_READ flag in the
1465    PR_MESSAGE_FLAGS property of a given message.
1466
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
1470
1471    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1472
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
1477      transaction
1478
1479    \sa OpenMessage, GetLastError
1480  */
1481 _PUBLIC_ enum MAPISTATUS SetMessageReadFlag(mapi_object_t *obj_folder, 
1482                                             mapi_object_t *obj_child,
1483                                             uint8_t flags)
1484 {
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];
1490         NTSTATUS                        status;
1491         enum MAPISTATUS                 retval;
1492         uint32_t                        size;
1493         TALLOC_CTX                      *mem_ctx;
1494         uint8_t                         logon_id;
1495
1496         /* Sanity checks */
1497         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
1498         OPENCHANGE_RETVAL_IF(!obj_child, MAPI_E_INVALID_PARAMETER, NULL);
1499
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);
1504
1505         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
1506                 return retval;
1507
1508         mem_ctx = talloc_named(session[0], 0, "SetMessageReadFlags");
1509         size = 0;
1510
1511         /* Fill the SetMessageReadFlags operation */
1512         request.handle_idx = 0x1;
1513         size += sizeof(uint8_t);
1514         request.flags = flags;
1515         size += sizeof(uint8_t);
1516
1517         /* TEMP HACK, see exchange.idl:
1518            request.clientdata.length = 0;
1519            request.clientdata.data = NULL;
1520         */
1521
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;
1528         size += 5;
1529
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);
1538
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);
1544
1545         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1546
1547         talloc_free(mapi_response);
1548         talloc_free(mem_ctx);
1549
1550         return MAPI_E_SUCCESS;
1551 }
1552
1553 /**
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.
1556
1557    This function essentially takes an attachment and gives you back
1558    a message.
1559
1560    \param obj_attach the attachment object
1561    \param obj_embeddedmsg the embedded message
1562    \param ulFlags access rights on the embedded message
1563
1564    Possible ulFlags values:
1565    - 0x0: read only access
1566    - 0x1: Read / Write access
1567    - 0x2: Create 
1568
1569    \code
1570         ... assume we have a message - obj_message ...
1571         // Initialise the attachment object
1572         mapi_object_init(&obj_attach);
1573
1574         // Create an attachment to the message
1575         retval = CreateAttach(&obj_message, &obj_attach);
1576         ... check the return value ...
1577
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 ...
1585
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 ...
1590
1591         // Fill in the embedded message properties, just like any other message (e.g. resulting from CreateMessage())
1592
1593         // Save the changes to the embedded message
1594         retval = SaveChangesMessage(&obj_message, &obj_embeddedmsg, KeepOpenReadOnly);
1595         ... check the return value ...
1596
1597         // Save the changes to the attachment
1598         retval = SaveChangesAttachment(&obj_message, &obj_attach, KeepOpenReadOnly);
1599         ... check the return value ...
1600
1601         // Save the changes to the original message
1602         retval = SaveChangesMessage(&obj_folder, &obj_message, KeepOpenReadOnly);
1603         ... check the return value ...
1604    \endcode
1605
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
1611      transaction
1612
1613    \note Developers may also call GetLastError() to retrieve the last
1614    MAPI error code. 
1615
1616    \sa CreateAttach, OpenMessage, GetLastError
1617 */
1618 _PUBLIC_ enum MAPISTATUS OpenEmbeddedMessage(mapi_object_t *obj_attach,
1619                                              mapi_object_t *obj_embeddedmsg,
1620                                              enum OpenEmbeddedMessage_OpenModeFlags ulFlags)
1621 {
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;
1631         NTSTATUS                        status;
1632         enum MAPISTATUS                 retval;
1633         uint32_t                        size = 0;
1634         TALLOC_CTX                      *mem_ctx;
1635         uint32_t                        i = 0;
1636         uint8_t                         logon_id;
1637
1638         /* Sanity checks */
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);
1643
1644         mapi_ctx = session->mapi_ctx;
1645         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1646
1647         if ((retval = mapi_object_get_logon_id(obj_attach, &logon_id)) != MAPI_E_SUCCESS)
1648                 return retval;
1649
1650         mem_ctx = talloc_named(session, 0, "OpenEmbeddedMessage");
1651
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);
1659
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;
1666         size += 5;
1667
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);
1676
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);
1682
1683         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1684
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);
1689
1690         /* Store OpenEmbeddedMessage reply data */
1691         reply = &mapi_response->mapi_repl->u.mapi_OpenEmbeddedMessage;
1692
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);
1697
1698         message->SPropTagArray.cValues = reply->RecipientColumns.cValues;
1699         message->SPropTagArray.aulPropTag = talloc_steal(message, reply->RecipientColumns.aulPropTag);
1700
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);
1707
1708                 lpProp.ulPropTag = PR_RECIPIENT_TYPE;
1709                 lpProp.value.l = reply->RecipientRows[i].RecipientType;
1710                 SRow_addprop(&(message->SRowSet.aRow[i]), lpProp);
1711
1712                 lpProp.ulPropTag = PR_INTERNET_CPID;
1713                 lpProp.value.l = reply->RecipientRows[i].CodePageId;
1714                 SRow_addprop(&(message->SRowSet.aRow[i]), lpProp);
1715         }
1716
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);
1720         
1721         obj_embeddedmsg->private_data = (void *) message;
1722
1723         talloc_free(mapi_response);
1724         talloc_free(mem_ctx);
1725
1726         return MAPI_E_SUCCESS;
1727 }
1728