server: intialize aux_header buffer to null if the data is missing.
[tridge/openchange.git] / branches / plugfest / mapiproxy / servers / default / emsmdb / oxcmsg.c
1 /*
2    OpenChange Server implementation
3
4    EMSMDBP: EMSMDB Provider implementation
5
6    Copyright (C) Julien Kerihuel 2009-2011
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23    \file oxcmsg.c
24
25    \brief Message and Attachment object routines and Rops
26  */
27
28 #include <sys/time.h>
29
30 #include "mapiproxy/dcesrv_mapiproxy.h"
31 #include "mapiproxy/libmapiproxy/libmapiproxy.h"
32 #include "mapiproxy/libmapiserver/libmapiserver.h"
33 #include "dcesrv_exchange_emsmdb.h"
34
35
36 /**
37    \details EcDoRpc OpenMessage (0x03) Rop. This operation opens an
38    existing message in a mailbox.
39
40    \param mem_ctx pointer to the memory context
41    \param emsmdbp_ctx pointer to the emsmdb provider context
42    \param mapi_req pointer to the OpenMessage EcDoRpc_MAPI_REQ
43    structure
44    \param mapi_repl pointer to the OpenMessage EcDoRpc_MAPI_REPL
45    structure
46    \param handles pointer to the MAPI handles array
47    \param size pointer to the mapi_response size to update
48
49    \return MAPI_E_SUCCESS on success, otherwise MAPI error
50  */
51 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopOpenMessage(TALLOC_CTX *mem_ctx,
52                                                 struct emsmdbp_context *emsmdbp_ctx,
53                                                 struct EcDoRpc_MAPI_REQ *mapi_req,
54                                                 struct EcDoRpc_MAPI_REPL *mapi_repl,
55                                                 uint32_t *handles, uint16_t *size)
56 {
57         enum MAPISTORE_ERROR            retval;
58         enum MAPISTATUS                 ret;
59         struct mapi_handles             *parent = NULL;
60         struct mapi_handles             *parent_handle = NULL;
61         struct mapi_handles             *rec = NULL;
62         struct emsmdbp_object           *object = NULL;
63         struct emsmdbp_object           *parent_object = NULL;
64         struct mapistore_message        msg;
65         void                            *data;
66         uint64_t                        folderID;
67         uint64_t                        messageID = 0;
68         uint32_t                        contextID;
69         uint32_t                        handle;
70         bool                            mapistore = false;
71         struct indexing_folders_list    *flist;
72         struct SPropTagArray            *SPropTagArray;
73         char                            *subject = NULL;
74         uint32_t                        i;
75
76
77         DEBUG(4, ("exchange_emsmdb: [OXCMSG] OpenMessage (0x03)\n"));
78
79         /* Sanity checks */
80         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
81         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
82         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
83         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
84         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
85
86         handle = handles[mapi_req->handle_idx];
87         ret = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent);
88         OPENCHANGE_RETVAL_IF(ret, ret, NULL);
89
90         mapi_repl->opnum = mapi_req->opnum;
91         mapi_repl->error_code = MAPI_E_SUCCESS;
92         mapi_repl->handle_idx = mapi_req->u.mapi_OpenMessage.handle_idx;
93         messageID = mapi_req->u.mapi_OpenMessage.MessageId;
94         folderID = mapi_req->u.mapi_OpenMessage.FolderId;
95
96         /* OpenMessage can only be called for mailbox/folder objects */
97         mapi_handles_get_private_data(parent, &data);
98         object = (struct emsmdbp_object *)data;
99         if (!object) {
100                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
101                 *size += libmapiserver_RopOpenMessage_size(NULL);
102                 return MAPI_E_SUCCESS;
103         }
104
105         switch (object->type) {
106         case EMSMDBP_OBJECT_MAILBOX:
107                 retval = mapistore_indexing_get_folder_list(emsmdbp_ctx->mstore_ctx, emsmdbp_ctx->username,
108                                                             messageID, &flist);
109                 if (retval || !flist->count) {
110                         DEBUG(0, ("No parent folder found for 0x%.16"PRIx64"\n", messageID));
111                 }
112                 /* If last element in the list doesn't match folderID, that's incorrect */
113                 if (folderID != flist->folderID[flist->count - 1]) {
114                         DEBUG(0, ("Last parent folder 0x%.16"PRIx64" doesn't match " \
115                                   "with expected 0x%.16"PRIx64"\n", 
116                                   flist->folderID[flist->count - 1], folderID));
117                 }
118
119                 /* Look if we have a parent folder already opened */
120                 for (i = flist->count - 1 ; i >= 0; i--) {
121                         parent_handle = emsmdbp_object_get_folder_handle_by_fid(emsmdbp_ctx->handles_ctx, 
122                                                                                 flist->folderID[i]);
123                         if (parent_handle) {
124                                 break; 
125                         }
126                         
127                 }
128
129                 /* If we have a parent handle, we have a context_id
130                  * and we can call subsequent OpenFolder - this will
131                  * increment ref_count whereas needed */
132                 if (parent_handle) {
133                 recursive_open:
134                         for (i = i + 1; i < flist->count; i++) {
135                                 mapi_handles_get_private_data(parent_handle, &data);
136                                 parent_object = (struct emsmdbp_object *) data;
137                                 folderID = parent_object->object.folder->folderID;
138                                 contextID = parent_object->object.folder->contextID;
139                                 retval = mapistore_opendir(emsmdbp_ctx->mstore_ctx, contextID, folderID,
140                                                            flist->folderID[i]);
141                                 mapi_handles_add(emsmdbp_ctx->handles_ctx, parent_handle->handle, &rec);
142                                 object = emsmdbp_object_folder_init((TALLOC_CTX *)emsmdbp_ctx, emsmdbp_ctx,
143                                                                     flist->folderID[i], parent_handle);
144                                 if (object) {
145                                         ret = mapi_handles_set_private_data(rec, object);
146                                 }
147
148                                 parent_handle = rec;
149                                 
150                         }
151                 } else {
152                         ret = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
153                         object = emsmdbp_object_folder_init((TALLOC_CTX *)emsmdbp_ctx, emsmdbp_ctx,
154                                                             flist->folderID[0], parent);
155                         if (object) {
156                                 ret = mapi_handles_set_private_data(rec, object);
157                         }
158                         parent_handle = rec;
159                         i = 0;
160                         /* now we have a context_id, we can use code above to open subfolders subsequently */
161                         goto recursive_open;
162                 }
163
164                 /* Add this stage our new parent_handle should point to the message */
165
166                 mapi_handles_get_private_data(parent_handle, &data);
167                 parent_object = (struct emsmdbp_object *) data;
168                 folderID = parent_object->object.folder->folderID;
169                 contextID = parent_object->object.folder->contextID;
170                 parent = parent_handle;
171                 break;
172         case EMSMDBP_OBJECT_FOLDER:
173                 folderID = object->object.folder->folderID;
174                 contextID = object->object.folder->contextID;
175                 break;
176         default:
177                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
178                 *size += libmapiserver_RopGetHierarchyTable_size(NULL);
179                 return MAPI_E_SUCCESS;
180         }
181
182         mapistore = emsmdbp_is_mapistore(parent);
183         switch (mapistore) {
184         case false:
185                 /* system/special folder */
186                 DEBUG(0, ("Not implemented yet - shouldn't occur\n"));
187                 break;
188         case true:
189                 /* mapistore implementation goes here */
190                 mapistore_openmessage(emsmdbp_ctx->mstore_ctx, contextID, folderID, messageID, &msg);
191
192                 /* Build the OpenMessage reply */
193                 subject = (char *) find_SPropValue_data(msg.properties, PR_SUBJECT);
194
195                 mapi_repl->u.mapi_OpenMessage.HasNamedProperties = false;
196                 mapi_repl->u.mapi_OpenMessage.SubjectPrefix.StringType = StringType_EMPTY;
197                 mapi_repl->u.mapi_OpenMessage.NormalizedSubject.StringType = StringType_UNICODE_REDUCED;
198                 mapi_repl->u.mapi_OpenMessage.NormalizedSubject.String.lpszW_reduced = talloc_strdup(mem_ctx, subject);
199                 mapi_repl->u.mapi_OpenMessage.RecipientCount = msg.recipients->cRows;
200
201                 SPropTagArray = set_SPropTagArray(mem_ctx, 0x4,
202                                                   PR_DISPLAY_TYPE,
203                                                   PR_OBJECT_TYPE,
204                                                   PR_7BIT_DISPLAY_NAME_UNICODE,
205                                                   PR_SMTP_ADDRESS_UNICODE);
206                 mapi_repl->u.mapi_OpenMessage.RecipientColumns.cValues = SPropTagArray->cValues;
207                 mapi_repl->u.mapi_OpenMessage.RecipientColumns.aulPropTag = SPropTagArray->aulPropTag;
208                 mapi_repl->u.mapi_OpenMessage.RowCount = msg.recipients->cRows;
209                 mapi_repl->u.mapi_OpenMessage.recipients = talloc_array(mem_ctx, 
210                                                                         struct OpenMessage_recipients, 
211                                                                         msg.recipients->cRows + 1);
212                 for (i = 0; i < msg.recipients->cRows; i++) {
213                         mapi_repl->u.mapi_OpenMessage.recipients[i].RecipClass = (enum ulRecipClass) msg.recipients->aRow[i].lpProps[0].value.l;
214                         mapi_repl->u.mapi_OpenMessage.recipients[i].codepage = CP_USASCII;
215                         mapi_repl->u.mapi_OpenMessage.recipients[i].Reserved = 0;
216                         emsmdbp_resolve_recipient(mem_ctx, emsmdbp_ctx, 
217                                                   (char *)msg.recipients->aRow[i].lpProps[1].value.lpszA,
218                                                   &(mapi_repl->u.mapi_OpenMessage.RecipientColumns),
219                                                   &(mapi_repl->u.mapi_OpenMessage.recipients[i].RecipientRow));
220                 }
221
222                 break;
223         }
224
225         /* Initialize Message object */
226         handle = handles[mapi_req->handle_idx];
227         ret = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
228         handles[mapi_repl->handle_idx] = rec->handle;
229
230         if (messageID) {
231                 object = emsmdbp_object_message_init((TALLOC_CTX *)rec, emsmdbp_ctx, messageID, parent_handle);
232                 if (object) {
233                         ret = mapi_handles_set_private_data(rec, object);
234                 }
235         }
236
237         *size += libmapiserver_RopOpenMessage_size(mapi_repl);
238
239         return MAPI_E_SUCCESS;
240 }
241
242
243 /**
244    \details EcDoRpc CreateMessage (0x06) Rop. This operation creates a
245    message object in the mailbox.
246
247    \param mem_ctx pointer to the memory context
248    \param emsmdbp_ctx pointer to the emsmdb provider context
249    \param mapi_req pointer to the CreateMessage EcDoRpc_MAPI_REQ
250    structure
251    \param mapi_repl pointer to the CreateMessage EcDoRpc_MAPI_REPL
252    structure
253    \param handles pointer to the MAPI handles array
254    \param size pointer to the mapi_response size to update
255
256    \return MAPI_E_SUCCESS on success, otherwise MAPI error
257  */
258 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopCreateMessage(TALLOC_CTX *mem_ctx,
259                                                   struct emsmdbp_context *emsmdbp_ctx,
260                                                   struct EcDoRpc_MAPI_REQ *mapi_req,
261                                                   struct EcDoRpc_MAPI_REPL *mapi_repl,
262                                                   uint32_t *handles, uint16_t *size)
263 {
264         enum MAPISTATUS                 retval;
265         struct mapi_handles             *rec = NULL;
266         struct mapi_handles             *parent = NULL;
267         struct mapi_handles             *parent_handle = NULL;
268         struct emsmdbp_object           *object = NULL;
269         uint32_t                        handle;
270         uint64_t                        folderID;
271         uint64_t                        messageID;
272         uint32_t                        contextID;
273         bool                            mapistore = false;
274         void                            *data;
275         struct SRow                     aRow;
276         uint32_t                        pt_long;
277         bool                            pt_boolean;
278         struct timeval                  tv;
279         struct FILETIME                 ft;
280         NTTIME                          time;
281
282         DEBUG(4, ("exchange_emsmdb: [OXCMSG] CreateMessage (0x06)\n"));
283
284         /* Sanity checks */
285         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
286         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
287         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
288         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
289         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
290
291         mapi_repl->opnum = mapi_req->opnum;
292         mapi_repl->error_code = MAPI_E_SUCCESS;
293         mapi_repl->handle_idx = mapi_req->u.mapi_CreateMessage.handle_idx;
294         mapi_repl->u.mapi_CreateMessage.HasMessageId = 0;
295
296         folderID = mapi_req->u.mapi_CreateMessage.FolderId;
297
298         /* CreateMessage can only be called for a mailbox/folder object */
299         handle = handles[mapi_req->handle_idx];
300         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &parent);
301         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
302
303         mapi_handles_get_private_data(parent, &data);
304         object = (struct emsmdbp_object *)data;
305         if (!object) {
306                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
307                 goto end;
308         }
309
310         /* FIXME: we can't assume the folder is already opened */
311         parent_handle = emsmdbp_object_get_folder_handle_by_fid(emsmdbp_ctx->handles_ctx, folderID);
312         if (!parent_handle) {
313                 mapi_repl->error_code = MAPI_E_NOT_FOUND;
314                 goto end;
315         }
316         contextID = emsmdbp_get_contextID(parent_handle);
317         mapistore = emsmdbp_is_mapistore(parent_handle);
318
319         switch (mapistore) {
320         case false:
321                 /* system/special folder */
322                 DEBUG(0, ("Not implemented yet - shouldn't occur\n"));
323                 break;
324         case true:
325                 /* This should be handled differently here: temporary hack */
326                 retval = openchangedb_get_new_folderID(emsmdbp_ctx->oc_ctx, &messageID);
327                 if (retval) {
328                         mapi_repl->error_code = MAPI_E_NO_SUPPORT;
329                         goto end;
330                 }
331                 mapi_repl->u.mapi_CreateMessage.HasMessageId = 1;
332                 mapi_repl->u.mapi_CreateMessage.MessageId.MessageId = messageID;
333                 mapistore_createmessage(emsmdbp_ctx->mstore_ctx, contextID, folderID, messageID);
334
335                 /* Set default properties for message: MS-OXCMSG 3.2.5.2 */
336                 aRow.lpProps = talloc_array(mem_ctx, struct SPropValue, 2);
337                 aRow.cValues = 0;
338
339                 pt_long = 0x1;
340                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_IMPORTANCE, (const void *)&pt_long);
341                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_MESSAGE_CLASS, (const void *)"IPM.Note");
342                 pt_long = 0x0;
343                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_SENSITIVITY, (const void *)&pt_long);
344                 pt_long = 0x9;
345                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_MESSAGE_FLAGS, (const void *)&pt_long);
346                 pt_boolean = false;
347                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_HASATTACH, (const void *)&pt_boolean);
348                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_URL_COMP_NAME_SET, (const void *)&pt_boolean);
349                 pt_long = 0x1;
350                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_TRUST_SENDER, (const void *)&pt_long);
351                 pt_long = 0x3;
352                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_ACCESS, (const void *)&pt_long);
353                 pt_long = 0x1;
354                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_ACCESS_LEVEL, (const void *)&pt_long);
355                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_URL_COMP_NAME, (const void *)"No Subject.EML");
356
357                 gettimeofday(&tv, NULL);
358                 time = timeval_to_nttime(&tv);
359                 ft.dwLowDateTime = (time << 32) >> 32;
360                 ft.dwHighDateTime = time >> 32;         
361                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_CREATION_TIME, (const void *)&ft);
362                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_LAST_MODIFICATION_TIME, (const void *)&ft);
363                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_LOCAL_COMMIT_TIME, (const void *)&ft);
364                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_MESSAGE_LOCALE_ID, (const void *)&mapi_req->u.mapi_CreateMessage.CodePageId);
365                 aRow.lpProps = add_SPropValue(mem_ctx, aRow.lpProps, &aRow.cValues, PR_LOCALE_ID, (const void *)&mapi_req->u.mapi_CreateMessage.CodePageId);
366
367                 mapistore_setprops(emsmdbp_ctx->mstore_ctx, contextID, messageID, MAPISTORE_MESSAGE, &aRow);
368                 break;
369         }
370
371         DEBUG(0, ("CreateMessage: 0x%.16"PRIx64": mapistore = %s\n", folderID, 
372                   emsmdbp_is_mapistore(parent_handle) == true ? "true" : "false"));
373
374         /* Initialize Message object */
375         handle = handles[mapi_req->handle_idx];
376         retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
377         handles[mapi_repl->handle_idx] = rec->handle;
378
379         if (messageID) {
380                 object = emsmdbp_object_message_init((TALLOC_CTX *)rec, emsmdbp_ctx, messageID, parent_handle);
381                 if (object) {
382                         /* Add default properties to message MS-OXCMSG 3.2.5.2 */
383                         retval = mapi_handles_set_private_data(rec, object);
384                 }
385         }
386
387 end:
388         *size += libmapiserver_RopCreateMessage_size(mapi_repl);
389
390         return MAPI_E_SUCCESS;
391 }
392
393
394 /**
395    \details EcDoRpc SaveChangesMessage (0x0c) Rop. This operation
396    operation commits the changes made to a message.
397
398    \param mem_ctx pointer to the memory context
399    \param emsmdbp_ctx pointer to the emsmdb provider context
400    \param mapi_req pointer to the SaveChangesMessage EcDoRpc_MAPI_REQ
401    structure
402    \param mapi_repl pointer to the SaveChangesMessage
403    EcDoRpc_MAPI_REPL structure
404
405    \param handles pointer to the MAPI handles array
406    \param size pointer to the mapi_response size to update
407
408    \return MAPI_E_SUCCESS on success, otherwise MAPI error
409  */
410 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopSaveChangesMessage(TALLOC_CTX *mem_ctx,
411                                                        struct emsmdbp_context *emsmdbp_ctx,
412                                                        struct EcDoRpc_MAPI_REQ *mapi_req,
413                                                        struct EcDoRpc_MAPI_REPL *mapi_repl,
414                                                        uint32_t *handles, uint16_t *size)
415 {
416         enum MAPISTATUS         retval;
417         uint32_t                handle;
418         struct mapi_handles     *rec = NULL;
419         void                    *private_data;
420         bool                    mapistore = false;
421         struct emsmdbp_object   *object;
422         uint64_t                messageID;
423         uint32_t                contextID;
424         uint8_t                 flags;
425
426         DEBUG(4, ("exchange_emsmdb: [OXCMSG] SaveChangesMessage (0x0c)\n"));
427
428         /* Sanity checks */
429         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
430         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
431         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
432         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
433         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
434
435         mapi_repl->opnum = mapi_req->opnum;
436         mapi_repl->error_code = MAPI_E_SUCCESS;
437         mapi_repl->handle_idx = mapi_req->handle_idx;
438
439         handle = handles[mapi_req->u.mapi_SaveChangesMessage.handle_idx];
440         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec);
441         if (retval) {
442                 mapi_repl->error_code = MAPI_E_NOT_FOUND;
443                 goto end;
444         }
445
446         retval = mapi_handles_get_private_data(rec, &private_data);
447         object = (struct emsmdbp_object *)private_data;
448         if (!object || object->type != EMSMDBP_OBJECT_MESSAGE) {
449                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
450                 goto end;
451         }
452
453         mapistore = emsmdbp_is_mapistore(rec);
454         switch (mapistore) {
455         case false:
456                 DEBUG(0, ("Not implement yet - shouldn't occur\n"));
457                 break;
458         case true:
459                 messageID = object->object.message->messageID;
460                 contextID = object->object.message->contextID;
461                 flags = mapi_req->u.mapi_SaveChangesMessage.SaveFlags;
462                 mapistore_savechangesmessage(emsmdbp_ctx->mstore_ctx, contextID, messageID, flags);
463                 mapistore_indexing_record_add_mid(emsmdbp_ctx->mstore_ctx, contextID, messageID);
464                 break;
465         }
466
467         mapi_repl->u.mapi_SaveChangesMessage.handle_idx = mapi_req->u.mapi_SaveChangesMessage.handle_idx;
468         mapi_repl->u.mapi_SaveChangesMessage.MessageId = object->object.message->messageID;
469
470 end:
471         *size += libmapiserver_RopSaveChangesMessage_size(mapi_repl);
472
473         return MAPI_E_SUCCESS;
474 }
475
476 /**
477    \details EcDoRpc ModifyRecipients (0x0e) Rop. This operation modifies an
478    existing message to add recipients (TO, CC, BCC).
479
480    \param mem_ctx pointer to the memory context
481    \param emsmdbp_ctx pointer to the emsmdb provider context
482    \param mapi_req pointer to the ModifyRecipients EcDoRpc_MAPI_REQ
483    structure
484    \param mapi_repl pointer to the ModifyRecipients EcDoRpc_MAPI_REPL
485    structure
486    \param handles pointer to the MAPI handles array
487    \param size pointer to the mapi_response size to update
488
489    \return MAPI_E_SUCCESS on success, otherwise MAPI error
490  */
491 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopModifyRecipients(TALLOC_CTX *mem_ctx,
492                                                      struct emsmdbp_context *emsmdbp_ctx,
493                                                      struct EcDoRpc_MAPI_REQ *mapi_req,
494                                                      struct EcDoRpc_MAPI_REPL *mapi_repl,
495                                                      uint32_t *handles, uint16_t *size)
496 {
497         DEBUG(4, ("exchange_emsmdb: [OXCMSG] ModifyRecipients (0x0e)\n"));
498
499         /* Sanity checks */
500         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
501         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
502         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
503         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
504         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
505
506         mapi_repl->opnum = mapi_req->opnum;
507         mapi_repl->error_code = MAPI_E_SUCCESS;
508
509         /* TODO: actually implement this */
510
511         *size += libmapiserver_RopModifyRecipients_size(mapi_repl);
512
513         return MAPI_E_SUCCESS;
514 }
515
516
517 /**
518    \details EcDoRpc ReloadCachedInformation (0x10) Rop. This operation
519    gets message and recipient information from a message.
520
521    \param mem_ctx pointer to the memory context
522    \param emsmdbp_ctx pointer to the emsmdb provider context
523    \param mapi_req pointer to the ReloadCachedInformation
524    EcDoRpc_MAPI_REQ structure
525    \param mapi_repl pointer to the ReloadCachedInformation
526    EcDoRpc_MAPI_REPL structure
527    \param handles pointer to the MAPI handles array
528    \param size pointer to the mapi_response size to update
529
530    \return MAPI_E_SUCCESS on success, otherwise MAPI error
531  */
532 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopReloadCachedInformation(TALLOC_CTX *mem_ctx,
533                                                             struct emsmdbp_context *emsmdbp_ctx,
534                                                             struct EcDoRpc_MAPI_REQ *mapi_req,
535                                                             struct EcDoRpc_MAPI_REPL *mapi_repl,
536                                                             uint32_t *handles, uint16_t *size)
537 {
538         enum MAPISTATUS                 retval;
539         uint32_t                        handle;
540         struct mapi_handles             *rec = NULL;
541         void                            *private_data;
542         bool                            mapistore = false;
543         struct mapistore_message        msg;
544         struct emsmdbp_object           *object;
545         uint64_t                        folderID;
546         uint64_t                        messageID;
547         uint32_t                        contextID;
548         struct SPropTagArray            *SPropTagArray;
549         char                            *subject = NULL;
550         uint32_t                        i;
551
552         DEBUG(4, ("exchange_emsmdb: [OXCMSG] ReloadCachedInformation (0x10)\n"));
553
554         /* Sanity checks */
555         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
556         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
557         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
558         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
559         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
560
561         mapi_repl->opnum = mapi_req->opnum;
562         mapi_repl->error_code = MAPI_E_SUCCESS;
563         mapi_repl->handle_idx = mapi_req->handle_idx;
564
565         handle = handles[mapi_req->handle_idx];
566         retval = mapi_handles_search(emsmdbp_ctx->handles_ctx, handle, &rec);
567         if (retval) {
568                 mapi_repl->error_code = MAPI_E_NOT_FOUND;
569                 goto end;
570         }
571
572         retval = mapi_handles_get_private_data(rec, &private_data);
573         object = (struct emsmdbp_object *)private_data;
574         if (!object || object->type != EMSMDBP_OBJECT_MESSAGE) {
575                 mapi_repl->error_code = MAPI_E_NO_SUPPORT;
576                 goto end;
577         }
578
579         mapistore = emsmdbp_is_mapistore(rec);
580         switch (mapistore) {
581         case false:
582                 DEBUG(0, ("Not implemented yet - shouldn't occur\n"));
583                 break;
584         case true:
585                 folderID = object->object.message->folderID;
586                 messageID = object->object.message->messageID;
587                 contextID = object->object.message->contextID;
588                 mapistore_openmessage(emsmdbp_ctx->mstore_ctx, contextID, folderID, messageID, &msg);
589
590                 /* Build the ReloadCachedInformation reply */
591                 subject = (char *) find_SPropValue_data(msg.properties, PR_SUBJECT);
592                 mapi_repl->u.mapi_ReloadCachedInformation.HasNamedProperties = false;
593                 mapi_repl->u.mapi_ReloadCachedInformation.SubjectPrefix.StringType = StringType_EMPTY;
594                 if (subject) {
595                         mapi_repl->u.mapi_ReloadCachedInformation.NormalizedSubject.StringType = StringType_UNICODE_REDUCED;
596                         mapi_repl->u.mapi_ReloadCachedInformation.NormalizedSubject.String.lpszW_reduced = talloc_strdup(mem_ctx, subject);
597                 } else {
598                         mapi_repl->u.mapi_ReloadCachedInformation.NormalizedSubject.StringType = StringType_EMPTY;
599                 }
600                 mapi_repl->u.mapi_ReloadCachedInformation.RecipientCount = msg.recipients->cRows;
601
602                 SPropTagArray = set_SPropTagArray(mem_ctx, 0x4,
603                                                   PR_DISPLAY_TYPE,
604                                                   PR_OBJECT_TYPE,
605                                                   PR_7BIT_DISPLAY_NAME_UNICODE,
606                                                   PR_SMTP_ADDRESS_UNICODE);
607                 mapi_repl->u.mapi_ReloadCachedInformation.RecipientColumns.cValues = SPropTagArray->cValues;
608                 mapi_repl->u.mapi_ReloadCachedInformation.RecipientColumns.aulPropTag = SPropTagArray->aulPropTag;
609                 mapi_repl->u.mapi_ReloadCachedInformation.RowCount = msg.recipients->cRows;
610                 mapi_repl->u.mapi_ReloadCachedInformation.RecipientRows = talloc_array(mem_ctx, 
611                                                                                        struct OpenRecipientRow, 
612                                                                                        msg.recipients->cRows + 1);
613                 for (i = 0; i < msg.recipients->cRows; i++) {
614                         mapi_repl->u.mapi_ReloadCachedInformation.RecipientRows[i].RecipientType = (enum ulRecipClass) msg.recipients->aRow[i].lpProps[0].value.l;
615                         mapi_repl->u.mapi_ReloadCachedInformation.RecipientRows[i].CodePageId = CP_USASCII;
616                         mapi_repl->u.mapi_ReloadCachedInformation.RecipientRows[i].Reserved = 0;
617                         emsmdbp_resolve_recipient(mem_ctx, emsmdbp_ctx, 
618                                                   (char *)msg.recipients->aRow[i].lpProps[1].value.lpszA,
619                                                   &(mapi_repl->u.mapi_ReloadCachedInformation.RecipientColumns),
620                                                   &(mapi_repl->u.mapi_ReloadCachedInformation.RecipientRows[i].RecipientRow));
621                 }
622                 break;
623         }
624
625 end:
626         *size += libmapiserver_RopReloadCachedInformation_size(mapi_repl);
627
628         return MAPI_E_SUCCESS;
629 }
630
631
632 /**
633    \details EcDoRpc SetMessageReadFlag (0x11) Rop. This operation sets
634    or clears the message read flag.
635
636    \param mem_ctx pointer to the memory context
637    \param emsmdbp_ctx pointer to the emsmdb provider context
638    \param mapi_req pointer to the SetMessageReadFlag EcDoRpc_MAPI_REQ
639    structure
640    \param mapi_repl pointer to the SetMessageReadFlag
641    EcDoRpc_MAPI_REPL structure
642
643    \param handles pointer to the MAPI handles array
644    \param size pointer to the mapi_response size to update
645
646    \return MAPI_E_SUCCESS on success, otherwise MAPI error
647  */
648 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopSetMessageReadFlag(TALLOC_CTX *mem_ctx,
649                                                        struct emsmdbp_context *emsmdbp_ctx,
650                                                        struct EcDoRpc_MAPI_REQ *mapi_req,
651                                                        struct EcDoRpc_MAPI_REPL *mapi_repl,
652                                                        uint32_t *handles, uint16_t *size)
653 {
654         DEBUG(4, ("exchange_emsmdb: [OXCMSG] SetMessageReadFlag (0x11)\n"));
655
656         /* Sanity checks */
657         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
658         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
659         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
660         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
661         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
662
663         mapi_repl->opnum = mapi_req->opnum;
664         mapi_repl->error_code = MAPI_E_SUCCESS;
665         mapi_repl->handle_idx = mapi_req->handle_idx;
666
667         /* TODO: actually implement this */
668         mapi_repl->u.mapi_SetMessageReadFlag.ReadStatusChanged = false;
669
670         *size += libmapiserver_RopSetMessageReadFlag_size(mapi_repl);
671
672         return MAPI_E_SUCCESS;
673 }
674
675
676 /**
677    \details EcDoRpc GetAttachmentTable (0x21) Rop. This operation gets
678    the attachment table of a message.
679
680    \param mem_ctx pointer to the memory context
681    \param emsmdbp_ctx pointer to the emsmdb provider context
682    \param mapi_req pointer to the GetAttachmentTable EcDoRpc_MAPI_REQ
683    structure
684    \param mapi_repl pointer to the GetAttachmentTable
685    EcDoRpc_MAPI_REPL structure
686    \param handles pointer to the MAPI handles array
687    \param size pointer to the mapi_response size to update
688
689    \return MAPI_E_SUCCESS on success, otherwise MAPI error
690  */
691 _PUBLIC_ enum MAPISTATUS EcDoRpc_RopGetAttachmentTable(TALLOC_CTX *mem_ctx,
692                                                        struct emsmdbp_context *emsmdbp_ctx,
693                                                        struct EcDoRpc_MAPI_REQ *mapi_req,
694                                                        struct EcDoRpc_MAPI_REPL *mapi_repl,
695                                                        uint32_t *handles, uint16_t *size)
696 {
697         enum MAPISTATUS         retval;
698         struct mapi_handles     *rec = NULL;
699         uint32_t                handle;
700
701         DEBUG(4, ("exchange_emsmdb: [OXCMSG] GetAttachmentTable (0x21)\n"));
702
703         /* Sanity checks */
704         OPENCHANGE_RETVAL_IF(!emsmdbp_ctx, MAPI_E_NOT_INITIALIZED, NULL);
705         OPENCHANGE_RETVAL_IF(!mapi_req, MAPI_E_INVALID_PARAMETER, NULL);
706         OPENCHANGE_RETVAL_IF(!mapi_repl, MAPI_E_INVALID_PARAMETER, NULL);
707         OPENCHANGE_RETVAL_IF(!handles, MAPI_E_INVALID_PARAMETER, NULL);
708         OPENCHANGE_RETVAL_IF(!size, MAPI_E_INVALID_PARAMETER, NULL);
709
710         mapi_repl->opnum = mapi_req->opnum;
711         mapi_repl->error_code = MAPI_E_SUCCESS;
712
713         /* TODO: actually implement this */
714
715         *size += libmapiserver_RopGetAttachmentTable_size(mapi_repl);
716
717         handle = handles[mapi_req->handle_idx];
718         retval = mapi_handles_add(emsmdbp_ctx->handles_ctx, handle, &rec);
719         handles[mapi_repl->handle_idx] = rec->handle;
720
721         return MAPI_E_SUCCESS;  
722 }