server: intialize aux_header buffer to null if the data is missing.
[tridge/openchange.git] / branches / plugfest / libmapi / IMAPIFolder.c
1 /*
2    OpenChange MAPI implementation.
3
4    Copyright (C) Julien Kerihuel 2007-2011.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "libmapi/libmapi.h"
21 #include "libmapi/libmapi_private.h"
22
23
24 /**
25    \file IMAPIFolder.c
26
27    \brief Folder related functions
28  */
29
30
31 /**
32    \details The function creates a message in the specified folder,
33    and returns a pointer on this message.
34
35    \param obj_folder the folder to create the message in.
36    \param obj_message pointer to the newly created message.
37
38    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
39
40    \note Developers may also call GetLastError() to retrieve the last
41    MAPI error code. Possible MAPI error codes are:
42    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
43    - MAPI_E_CALL_FAILED: A network problem was encountered during the
44      transaction
45
46    \sa OpenFolder, DeleteMessage, GetLastError
47 */
48 _PUBLIC_ enum MAPISTATUS CreateMessage(mapi_object_t *obj_folder, mapi_object_t *obj_message)
49 {
50         struct mapi_request             *mapi_request;
51         struct mapi_response            *mapi_response;
52         struct EcDoRpc_MAPI_REQ         *mapi_req;
53         struct CreateMessage_req        request;
54         struct mapi_session             *session;
55         NTSTATUS                        status;
56         enum MAPISTATUS                 retval;
57         uint32_t                        size;
58         TALLOC_CTX                      *mem_ctx;
59         uint8_t                         logon_id;
60
61         /* Sanity checks */
62         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
63         session = mapi_object_get_session(obj_folder);
64         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
65
66         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
67                 return retval;
68
69         mem_ctx = talloc_named(NULL, 0, "CreateMessage");
70         size = 0;
71
72         /* Fill the OpenFolder operation */
73         request.handle_idx = 0x1;
74         size += sizeof (uint8_t);
75         request.CodePageId = 0xfff;
76         size += sizeof (uint16_t);
77         request.FolderId = mapi_object_get_id(obj_folder);
78         size += sizeof (uint64_t);
79         request.AssociatedFlag = 0;
80         size += sizeof (uint8_t);
81
82         /* Fill the MAPI_REQ request */
83         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
84         mapi_req->opnum = op_MAPI_CreateMessage;
85         mapi_req->logon_id = logon_id;
86         mapi_req->handle_idx = 0;
87         mapi_req->u.mapi_CreateMessage = request;
88         size += 5;
89
90         /* Fill the mapi_request structure */
91         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
92         mapi_request->mapi_len = size + sizeof(mapi_handle_t) * 2;
93         mapi_request->length = size;
94         mapi_request->mapi_req = mapi_req;
95         mapi_request->handles = talloc_array(mem_ctx, mapi_handle_t, 2);
96         mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
97         mapi_request->handles[1] = 0xffffffff;
98
99         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
100         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
101         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
102         retval = mapi_response->mapi_repl->error_code;
103         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
104
105         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
106
107         /* set object session and handle */
108         mapi_object_set_session(obj_message, session);
109         mapi_object_set_handle(obj_message, mapi_response->handles[1]);
110         mapi_object_set_logon_id(obj_message, logon_id);
111
112         talloc_free(mapi_response);
113         talloc_free(mem_ctx);
114
115         return MAPI_E_SUCCESS;
116 }
117
118
119 /**
120    \details Delete one or more messages
121
122    This function deletes one or more messages based on their ids from
123    a specified folder.
124
125    \param obj_folder the folder to delete messages from
126    \param id_messages the list of ids
127    \param cn_messages the number of messages in the id list.
128
129    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
130
131    \note Developers may also call GetLastError() to retrieve the last
132    MAPI error code. Possible MAPI error codes are:
133    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
134    - MAPI_E_CALL_FAILED: A network problem was encountered during the
135      transaction
136
137    \sa OpenFolder, CreateMessage, GetLastError
138 */
139 _PUBLIC_ enum MAPISTATUS DeleteMessage(mapi_object_t *obj_folder, mapi_id_t *id_messages,
140                                        uint32_t cn_messages)
141 {
142         struct mapi_request             *mapi_request;
143         struct mapi_response            *mapi_response;
144         struct EcDoRpc_MAPI_REQ         *mapi_req;
145         struct DeleteMessages_req       request;
146         struct mapi_session             *session;
147         NTSTATUS                        status;
148         enum MAPISTATUS                 retval;
149         uint32_t                        size;
150         TALLOC_CTX                      *mem_ctx;
151         uint8_t                         logon_id;
152
153         /* Sanity checks */
154         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
155         session = mapi_object_get_session(obj_folder);
156         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
157         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
158                 return retval;
159
160         mem_ctx = talloc_named(NULL, 0, "DeleteMessages");
161         size = 0;
162
163         /* Fill the DeleteMessages operation */
164         request.WantAsynchronous = 0x0;
165         size += sizeof (uint8_t);
166         request.NotifyNonRead = 0x1;
167         size += sizeof(uint8_t);
168         request.cn_ids = (uint16_t)cn_messages;
169         size += sizeof(uint16_t);
170         request.message_ids = id_messages;
171         size += request.cn_ids * sizeof(mapi_id_t);
172
173         /* Fill the MAPI_REQ request */
174         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
175         mapi_req->opnum = op_MAPI_DeleteMessages;
176         mapi_req->logon_id = logon_id;
177         mapi_req->handle_idx = 0;
178         mapi_req->u.mapi_DeleteMessages = request;
179         size += 5;
180
181         /* Fill the mapi_request structure */
182         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
183         mapi_request->mapi_len = size + sizeof (uint32_t);
184         mapi_request->length = size;
185         mapi_request->mapi_req = mapi_req;
186         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
187         mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
188
189         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
190         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
191         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
192         retval = mapi_response->mapi_repl->error_code;
193         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
194
195         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
196
197         talloc_free(mapi_response);
198         talloc_free(mem_ctx);
199
200         return MAPI_E_SUCCESS;
201 }
202
203
204 /**
205    \details Hard delete one or more messages
206
207    This function hard deletes one or more messages based on their
208    ids from a specified folder.
209
210    \param obj_folder the folder to hard delete messages from
211    \param id_messages the list of ids
212    \param cn_messages the number of messages in the id list.
213
214    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
215
216    \note Developers may also call GetLastError() to retrieve the last
217    MAPI error code. Possible MAPI error codes are:
218    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
219    - MAPI_E_INVALID_PARAMETER: the parent folder was not valid
220    - MAPI_E_CALL_FAILED: A network problem was encountered during the
221      transaction
222
223    \sa OpenFolder, CreateMessage, GetLastError
224 */
225 _PUBLIC_ enum MAPISTATUS HardDeleteMessage(mapi_object_t *obj_folder,
226                                            mapi_id_t *id_messages,
227                                            uint16_t cn_messages)
228 {
229         struct mapi_request             *mapi_request;
230         struct mapi_response            *mapi_response;
231         struct EcDoRpc_MAPI_REQ         *mapi_req;
232         struct HardDeleteMessages_req   request;
233         struct mapi_session             *session;
234         NTSTATUS                        status;
235         enum MAPISTATUS                 retval;
236         uint32_t                        size;
237         TALLOC_CTX                      *mem_ctx;
238         uint8_t                         logon_id;
239
240         /* Sanity checks */
241         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
242         session = mapi_object_get_session(obj_folder);
243         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
244
245         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
246                 return retval;
247
248         mem_ctx = talloc_named(NULL, 0, "HardDeleteMessages");
249         size = 0;
250
251         /* Fill the HardDeleteMessages operation */
252         request.WantAsynchronous = 0x0;
253         size += sizeof (uint8_t);
254         request.NotifyNonRead = 0x1;
255         size += sizeof(uint8_t);
256         request.MessageIdCount = cn_messages;
257         size += sizeof(uint16_t);
258         request.MessageIds = id_messages;
259         size += request.MessageIdCount * sizeof(mapi_id_t);
260
261         /* Fill the MAPI_REQ request */
262         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
263         mapi_req->opnum = op_MAPI_HardDeleteMessages;
264         mapi_req->logon_id = logon_id;
265         mapi_req->handle_idx = 0;
266         mapi_req->u.mapi_HardDeleteMessages = request;
267         size += 5;
268
269         /* Fill the mapi_request structure */
270         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
271         mapi_request->mapi_len = size + sizeof (uint32_t);
272         mapi_request->length = size;
273         mapi_request->mapi_req = mapi_req;
274         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
275         mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
276
277         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
278         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
279         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
280         retval = mapi_response->mapi_repl->error_code;
281         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
282
283         talloc_free(mapi_response);
284         talloc_free(mem_ctx);
285
286         return MAPI_E_SUCCESS;
287 }
288
289
290 /**
291    \details Obtain the status associated with a message
292
293    This function obtains the status associated with a message in the
294    given folder.
295
296    \param obj_folder the folder where the message is located
297    \param msgid the message ID
298    \param ulStatus the message status
299
300    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
301
302    \note Developers may also call GetLastError() to retrieve the last
303    MAPI error code. Possible MAPI error codes are:
304    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
305    - MAPI_E_CALL_FAILED: A network problem was encountered during the
306      transaction
307  */
308 _PUBLIC_ enum MAPISTATUS GetMessageStatus(mapi_object_t *obj_folder, 
309                                           mapi_id_t msgid, 
310                                           uint32_t *ulStatus)
311 {
312         struct mapi_request             *mapi_request;
313         struct mapi_response            *mapi_response;
314         struct EcDoRpc_MAPI_REQ         *mapi_req;
315         struct GetMessageStatus_req     request;
316         struct mapi_session             *session;
317         NTSTATUS                        status;
318         enum MAPISTATUS                 retval;
319         uint32_t                        size;
320         TALLOC_CTX                      *mem_ctx;
321         uint8_t                         logon_id;
322
323         /* Sanity checks */
324         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
325         OPENCHANGE_RETVAL_IF(!msgid, MAPI_E_INVALID_PARAMETER, NULL);
326         session = mapi_object_get_session(obj_folder);
327         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
328
329         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
330                 return retval;
331
332         mem_ctx = talloc_named(NULL, 0, "GetMessageStatus");
333         size = 0;
334
335         /* Fill the GetMessageStatus operation */
336         request.msgid = msgid;
337         size += sizeof (uint64_t);
338
339         /* Fill the MAPI_REQ request */
340         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
341         mapi_req->opnum = op_MAPI_GetMessageStatus;
342         mapi_req->logon_id = logon_id;
343         mapi_req->handle_idx = 0;
344         mapi_req->u.mapi_GetMessageStatus = request;
345         size += 5;
346
347         /* Fill the mapi_request structure */
348         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
349         mapi_request->mapi_len = size + sizeof (uint32_t);
350         mapi_request->length = size;
351         mapi_request->mapi_req = mapi_req;
352         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
353         mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
354
355         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
356         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
357         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
358         retval = mapi_response->mapi_repl->error_code;
359         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
360
361         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
362
363         *ulStatus = mapi_response->mapi_repl->u.mapi_SetMessageStatus.ulOldStatus;
364
365         talloc_free(mapi_response);
366         talloc_free(mem_ctx);
367
368         return MAPI_E_SUCCESS;
369 }
370
371
372 /**
373    \details Set the status associated with a message
374
375    This function sets the status associated with a message in the
376    given folder.
377
378    \param obj_folder the folder where the message is located
379    \param msgid the message ID
380    \param ulNewStatus the new status to be assigned
381    \param ulNewStatusMask bitmask of flags hat is applied to the new
382    status indicating the flags to be set
383    \param ulOldStatus pointer on the previous status of the message
384
385    ulNewStatusMask possible values:
386    - MSGSTATUS_DELMARKED: the message is marked for deletion
387    - MSGSTATUS_HIDDEN: the message is not to be displayed
388    - MSGSTATUS_HIGHLIGHTED: the message is to be displayed highlighted
389    - MSGSTATUS_REMOTE_DELETE: the message has been marked for deletion
390      on the remote message store without downloading to the local
391      client.
392    - MSGSTATUS_REMOTE_DOWNLOAD: the message has been marked for
393      downloading from the remote message store to the local client.
394    - MSGSTATUS_TAGGED: The message has been tagged for a
395      client-defined purpose.
396
397    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
398
399    \note Developers may also call GetLastError() to retrieve the last
400    MAPI error code. Possible MAPI error codes are:
401    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
402    - MAPI_E_CALL_FAILED: A network problem was encountered during the
403      transaction
404  */
405 _PUBLIC_ enum MAPISTATUS SetMessageStatus(mapi_object_t *obj_folder,
406                                           mapi_id_t msgid,
407                                           uint32_t ulNewStatus,
408                                           uint32_t ulNewStatusMask,
409                                           uint32_t *ulOldStatus)
410 {
411         struct mapi_request             *mapi_request;
412         struct mapi_response            *mapi_response;
413         struct EcDoRpc_MAPI_REQ         *mapi_req;
414         struct SetMessageStatus_req     request;
415         struct mapi_session             *session;
416         NTSTATUS                        status;
417         enum MAPISTATUS                 retval;
418         uint32_t                        size;
419         TALLOC_CTX                      *mem_ctx;
420         uint8_t                         logon_id;
421
422         /* Sanity checks */
423         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
424         OPENCHANGE_RETVAL_IF(!msgid, MAPI_E_INVALID_PARAMETER, NULL);
425         session = mapi_object_get_session(obj_folder);
426         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
427
428         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
429                 return retval;
430
431         mem_ctx = talloc_named(NULL, 0, "SetMessageStatus");
432         size = 0;
433
434         /* Fill the SetMessageStatus operation */
435         request.msgid = msgid;
436         size += sizeof (uint64_t);
437
438         request.ulNewStatus = ulNewStatus;
439         size += sizeof (uint32_t);
440
441         request.ulNewStatusMask = ulNewStatusMask;
442         size += sizeof (uint32_t);
443
444         /* Fill the MAPI_REQ request */
445         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
446         mapi_req->opnum = op_MAPI_SetMessageStatus;
447         mapi_req->logon_id = logon_id;
448         mapi_req->handle_idx = 0;
449         mapi_req->u.mapi_SetMessageStatus = request;
450         size += 5;
451
452         /* Fill the mapi_request structure */
453         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
454         mapi_request->mapi_len = size + sizeof (uint32_t);
455         mapi_request->length = size;
456         mapi_request->mapi_req = mapi_req;
457         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
458         mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
459
460         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
461         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
462         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
463         retval = mapi_response->mapi_repl->error_code;
464         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
465
466         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
467
468         *ulOldStatus = mapi_response->mapi_repl->u.mapi_SetMessageStatus.ulOldStatus;
469
470         talloc_free(mapi_response);
471         talloc_free(mem_ctx);
472         
473         return MAPI_E_SUCCESS;
474 }
475
476
477 /**
478    \details Copy or Move a message from a folder to another
479
480    \param obj_src The source folder
481    \param obj_dst The destination folder
482    \param message_id pointer to container object for message ids.
483    \param WantCopy boolean value, defines whether the operation is a
484    copy or a move
485
486    Possible values for WantCopy:
487    -# 0: Move
488    -# 1: Copy
489
490    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
491
492    \note Developers may also call GetLastError() to retrieve the last
493    MAPI error code. Possible MAPI error codes are:
494    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
495    - MAPI_E_CALL_FAILED: A network problem was encountered during the
496      transaction
497
498    \sa OpenFolder, GetLastError
499 */
500 _PUBLIC_ enum MAPISTATUS MoveCopyMessages(mapi_object_t *obj_src,
501                                           mapi_object_t *obj_dst,
502                                           mapi_id_array_t *message_id,
503                                           bool WantCopy)
504 {
505         NTSTATUS                        status;
506         TALLOC_CTX                      *mem_ctx;
507         enum MAPISTATUS                 retval;
508         struct mapi_request             *mapi_request;
509         struct mapi_response            *mapi_response;
510         struct EcDoRpc_MAPI_REQ         *mapi_req;
511         struct MoveCopyMessages_req     request;
512         struct mapi_session             *session[2];
513         uint32_t                        size;
514         uint8_t                         logon_id;
515
516         /* Sanity checks */
517         OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
518         OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
519         session[0] = mapi_object_get_session(obj_src);
520         session[1] = mapi_object_get_session(obj_dst);
521         OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
522         OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
523         OPENCHANGE_RETVAL_IF(session[0] != session[1], MAPI_E_INVALID_PARAMETER, NULL);
524
525         if ((retval = mapi_object_get_logon_id(obj_src, &logon_id)) != MAPI_E_SUCCESS)
526                 return retval;
527
528         mem_ctx = talloc_named(NULL, 0, "MoveCopyMessages");
529         size = 0;
530
531         /* Fill the CopyMessage operation */
532         request.handle_idx = 0x1;
533         size += sizeof (uint8_t);
534
535         request.count = message_id->count;
536         size += sizeof (uint16_t);
537
538         retval = mapi_id_array_get(mem_ctx, message_id, &(request.message_id));
539         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
540         size += request.count * sizeof (mapi_id_t);
541
542         request.WantAsynchronous = 0;
543         size += sizeof (uint8_t);
544
545         request.WantCopy = WantCopy;
546         size += sizeof (uint8_t);
547
548         /* Fill the MAPI_REQ request */
549         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
550         mapi_req->opnum = op_MAPI_MoveCopyMessages;
551         mapi_req->logon_id = logon_id;
552         mapi_req->handle_idx = 0;
553         mapi_req->u.mapi_MoveCopyMessages = request;
554         size += 5;
555
556         /* Fill the mapi_request structure */
557         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
558         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
559         mapi_request->length = size;
560         mapi_request->mapi_req = mapi_req;
561         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
562         mapi_request->handles[0] = mapi_object_get_handle(obj_src);
563         mapi_request->handles[1] = mapi_object_get_handle(obj_dst);
564
565         status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
566         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
567         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
568         retval = mapi_response->mapi_repl->error_code;
569         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
570
571         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
572         
573         talloc_free(mapi_response);
574         talloc_free(mem_ctx);
575
576         return MAPI_E_SUCCESS;
577 }
578
579
580 /**
581    \details Create a folder
582
583    The function creates a folder (defined with its name, comment and type)
584    within a specified folder.
585
586    \param obj_parent the folder to create the new folder in
587    \param ulFolderType the type of the folder
588    \param name the name of the new folder
589    \param comment the comment associated with the new folder
590    \param ulFlags flags associated with folder creation
591    \param obj_child pointer to the newly created folder
592
593    ulFlags possible values:
594    - MAPI_UNICODE: use UNICODE folder name and comment
595    - OPEN_IF_EXISTS: open the folder if it already exists
596
597    ulFolderType possible values:
598    - FOLDER_GENERIC
599    - FOLDER_SEARCH
600
601    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
602
603    \note Developers may also call GetLastError() to retrieve the last
604    MAPI error code. Possible MAPI error codes are:
605    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
606    - MAPI_E_CALL_FAILED: A network problem was encountered during the
607      transaction
608
609    \sa OpenFolder, DeleteFolder, EmptyFolder, GetLastError
610 */
611 _PUBLIC_ enum MAPISTATUS CreateFolder(mapi_object_t *obj_parent, 
612                                       enum FOLDER_TYPE ulFolderType,
613                                       const char *name,
614                                       const char *comment, 
615                                       uint32_t ulFlags,
616                                       mapi_object_t *obj_child)
617 {
618         struct mapi_request     *mapi_request;
619         struct mapi_response    *mapi_response;
620         struct EcDoRpc_MAPI_REQ *mapi_req;
621         struct CreateFolder_req request;
622         struct mapi_session     *session;
623         NTSTATUS                status;
624         enum MAPISTATUS         retval;
625         uint32_t                size;
626         TALLOC_CTX              *mem_ctx;
627         uint8_t                 logon_id;
628
629         /* Sanity checks */
630         OPENCHANGE_RETVAL_IF(!obj_parent, MAPI_E_INVALID_PARAMETER, NULL);
631         OPENCHANGE_RETVAL_IF(!name, MAPI_E_NOT_INITIALIZED, NULL);
632         session = mapi_object_get_session(obj_parent);
633         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
634
635         if ((retval = mapi_object_get_logon_id(obj_parent, &logon_id)) != MAPI_E_SUCCESS)
636                 return retval;
637
638         /* Sanitify check on the folder type */
639         OPENCHANGE_RETVAL_IF((ulFolderType != FOLDER_GENERIC && 
640                         ulFolderType != FOLDER_SEARCH),
641                        MAPI_E_INVALID_PARAMETER, NULL);
642
643         mem_ctx = talloc_named(NULL, 0, "CreateFolder");
644         size = 0;
645
646         /* Fill the CreateFolder operation */
647         request.handle_idx = 0x1;
648         size+= sizeof(uint8_t);
649         switch (ulFlags & 0xFFFF0000) {
650         case MAPI_UNICODE:
651                 request.ulType = MAPI_FOLDER_UNICODE;
652                 break;
653         default:
654                 request.ulType = MAPI_FOLDER_ANSI;
655                 break;
656         }
657         request.ulFolderType = ulFolderType;
658         size += sizeof(uint16_t);
659         request.ulFlags = (enum FOLDER_FLAGS)((int)ulFlags & 0xFFFF);
660         size += sizeof(uint16_t);
661
662         switch (request.ulType) {
663         case MAPI_FOLDER_ANSI:
664                 request.FolderName.lpszA = name;
665                 size += strlen(name) + 1;
666                 break;
667         case MAPI_FOLDER_UNICODE:
668                 request.FolderName.lpszW = name;
669                 size += get_utf8_utf16_conv_length(name);
670                 break;
671         }
672
673         if (comment) {
674                 switch(request.ulType) {
675                 case MAPI_FOLDER_ANSI:
676                         request.FolderComment.lpszA = comment;
677                         size += strlen(comment) + 1;
678                         break;
679                 case MAPI_FOLDER_UNICODE:
680                         request.FolderComment.lpszW = comment;
681                         size +=  get_utf8_utf16_conv_length(comment);
682                         break;
683                 }
684         } else {
685                 switch(request.ulType) {
686                 case MAPI_FOLDER_ANSI:
687                         request.FolderComment.lpszA = "";
688                         size += 1;
689                         break;
690                 case MAPI_FOLDER_UNICODE:
691                         request.FolderComment.lpszW = "";
692                         size += 2;
693                         break;
694                 }
695         }
696
697         /* Fill the MAPI_REQ request */
698         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
699         mapi_req->opnum = op_MAPI_CreateFolder;
700         mapi_req->logon_id = logon_id;
701         mapi_req->handle_idx = 0;
702         mapi_req->u.mapi_CreateFolder = request;
703         size += 5;
704
705         /* Fill the mapi_request structure */
706         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
707         mapi_request->mapi_len = size + (2 * sizeof(uint32_t));
708         mapi_request->length = size;
709         mapi_request->mapi_req = mapi_req;
710         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
711         mapi_request->handles[0] = mapi_object_get_handle(obj_parent);
712         mapi_request->handles[1] = 0xffffffff;
713
714         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
715         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
716         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
717         retval = mapi_response->mapi_repl->error_code;
718         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
719
720         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
721
722         /* Set object session, handle and id */
723         mapi_object_init(obj_child);
724         mapi_object_set_session(obj_child, session);
725         mapi_object_set_handle(obj_child, mapi_response->handles[1]);
726         mapi_object_set_id(obj_child, mapi_response->mapi_repl->u.mapi_CreateFolder.folder_id);
727         mapi_object_set_logon_id(obj_child, logon_id);
728
729         talloc_free(mapi_response);
730         talloc_free(mem_ctx);
731
732         return MAPI_E_SUCCESS;
733 }
734
735
736 /**
737    \details Empty the contents of a folder
738
739    This function empties (clears) the contents of a specified folder.
740
741    \param obj_folder the folder to empty
742
743    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
744
745    \note Developers may also call GetLastError() to retrieve the last
746    MAPI error code. Possible MAPI error codes are:
747    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
748    - MAPI_E_CALL_FAILED: A network problem was encountered during the
749      transaction
750
751    \sa OpenFolder, CreateFolder, DeleteFolder, GetLastError
752 */
753 _PUBLIC_ enum MAPISTATUS EmptyFolder(mapi_object_t *obj_folder)
754 {
755         struct mapi_request     *mapi_request;
756         struct mapi_response    *mapi_response;
757         struct EcDoRpc_MAPI_REQ *mapi_req;
758         struct EmptyFolder_req  request;
759         struct mapi_session     *session;
760         NTSTATUS                status;
761         enum MAPISTATUS         retval;
762         uint32_t                size;
763         TALLOC_CTX              *mem_ctx;
764         uint8_t                 logon_id;
765
766         /* Sanity checks */
767         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
768         session = mapi_object_get_session(obj_folder);
769         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
770
771         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
772                 return retval;
773
774         mem_ctx = talloc_named(NULL, 0, "EmptyFolder");
775         size = 0;
776
777         /* Fill the EmptyFolder operation */
778         request.WantAsynchronous = 0x0;
779         size += sizeof (uint8_t);
780
781         request.WantDeleteAssociated = 0x0;
782         size += sizeof (uint8_t);
783
784         /* Fill the MAPI_REQ request */
785         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
786         mapi_req->opnum = op_MAPI_EmptyFolder;
787         mapi_req->logon_id = logon_id;
788         mapi_req->handle_idx = 0;
789         mapi_req->u.mapi_EmptyFolder = request;
790         size += 5;
791
792         /* Fill the mapi_request structure */
793         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
794         mapi_request->mapi_len = size + sizeof(uint32_t);
795         mapi_request->length = size;
796         mapi_request->mapi_req = mapi_req;
797         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
798         mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
799
800         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
801         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
802         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
803         retval = mapi_response->mapi_repl->error_code;
804         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
805
806         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
807
808         talloc_free(mapi_response);
809         talloc_free(mem_ctx);
810
811         return MAPI_E_SUCCESS;
812 }
813
814
815 /**
816    \details Delete a folder
817
818    The function deletes a specified folder.
819
820    \param obj_parent the folder containing the folder to be deleted
821    \param FolderId the ID of the folder to delete
822    \param DeleteFolderFlags control DeleteFolder operation behavior
823    \param PartialCompletion pointer on a boolean value which specify
824    whether the operation was partially completed or not
825
826    Possible values for DeleteFolderFlags are:
827    -# DEL_MESSAGES Delete all the messages in the folder
828    -# DEL_FOLDERS Delete the subfolder and all of its subfolders
829    -# DELETE_HARD_DELETE Hard delete the folder
830
831    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
832
833    \note Developers may also call GetLastError() to retrieve the last
834    MAPI error code. Possible MAPI error codes are:
835    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
836    - MAPI_E_CALL_FAILED: A network problem was encountered during the
837      transaction
838
839    \sa OpenFolder, CreateFolder, EmptyFolder, GetLastError
840 */
841 _PUBLIC_ enum MAPISTATUS DeleteFolder(mapi_object_t *obj_parent, 
842                                       mapi_id_t FolderId,
843                                       uint8_t DeleteFolderFlags,
844                                       bool *PartialCompletion)
845 {
846         struct mapi_request     *mapi_request;
847         struct mapi_response    *mapi_response;
848         struct EcDoRpc_MAPI_REQ *mapi_req;
849         struct DeleteFolder_req request;
850         struct mapi_session     *session;
851         NTSTATUS                status;
852         enum MAPISTATUS         retval;
853         uint32_t                size;
854         TALLOC_CTX              *mem_ctx;
855         uint8_t                 logon_id;
856
857         /* Sanity checks */
858         OPENCHANGE_RETVAL_IF(!obj_parent, MAPI_E_INVALID_PARAMETER, NULL);
859         session = mapi_object_get_session(obj_parent);
860         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
861         OPENCHANGE_RETVAL_IF((!(DeleteFolderFlags & 0x1)) &&
862                              (!(DeleteFolderFlags & 0x4)) &&
863                              (!(DeleteFolderFlags & 0x10)), 
864                              MAPI_E_INVALID_PARAMETER, NULL);
865
866         if ((retval = mapi_object_get_logon_id(obj_parent, &logon_id)) != MAPI_E_SUCCESS)
867                 return retval;
868
869         mem_ctx = talloc_named(NULL, 0, "DeleteFolder");
870         size = 0;
871
872         /* Fill the DeleteFolder operation */
873         request.DeleteFolderFlags = DeleteFolderFlags;
874         size += sizeof (uint8_t);
875         request.FolderId = FolderId;
876         size += sizeof (uint64_t);
877
878         /* Fill the MAPI_REQ request */
879         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
880         mapi_req->opnum = op_MAPI_DeleteFolder;
881         mapi_req->logon_id = logon_id;
882         mapi_req->handle_idx = 0;
883         mapi_req->u.mapi_DeleteFolder = request;
884         size += 5;
885
886         /* Fill the mapi_request structure */
887         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
888         mapi_request->mapi_len = size + sizeof(uint32_t);
889         mapi_request->length = size;
890         mapi_request->mapi_req = mapi_req;
891         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
892         mapi_request->handles[0] = mapi_object_get_handle(obj_parent);
893
894         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
895         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
896         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
897         retval = mapi_response->mapi_repl->error_code;
898         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
899
900         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
901
902         if (PartialCompletion) {
903                 *PartialCompletion = mapi_response->mapi_repl->u.mapi_DeleteFolder.PartialCompletion;
904         }
905
906         talloc_free(mapi_response);
907         talloc_free(mem_ctx);
908
909         return MAPI_E_SUCCESS;
910 }
911
912
913 /**
914    \details Moves a folder
915
916    \param obj_folder the folder to move
917    \param obj_src source object where the folder to move is stored
918    \param obj_dst destination object where the folder will be moved
919    \param NewFolderName the new folder name in the destination folder
920    \param UseUnicode whether the folder name is unicode encoded or not
921
922     \return MAPI_E_SUCCESS on success, otherwise MAPI error.
923
924    \note Developers may also call GetLastError() to retrieve the last
925    MAPI error code. Possible MAPI error codes are:
926    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
927    - MAPI_E_CALL_FAILED: A network problem was encountered during the
928      transaction
929
930    \sa OpenFolder, CopyFolder
931  */
932 _PUBLIC_ enum MAPISTATUS MoveFolder(mapi_object_t *obj_folder,
933                                     mapi_object_t *obj_src, 
934                                     mapi_object_t *obj_dst,
935                                     char *NewFolderName,
936                                     bool UseUnicode)
937 {
938         struct mapi_request     *mapi_request;
939         struct mapi_response    *mapi_response;
940         struct EcDoRpc_MAPI_REQ *mapi_req;
941         struct MoveFolder_req   request;
942         struct mapi_session     *session[3];
943         NTSTATUS                status;
944         enum MAPISTATUS         retval;
945         uint32_t                size;
946         TALLOC_CTX              *mem_ctx;
947         uint8_t                 logon_id;
948
949         /* Sanity checks */
950         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
951         OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
952         OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
953         OPENCHANGE_RETVAL_IF(!NewFolderName, MAPI_E_INVALID_PARAMETER, NULL);
954
955         session[0] = mapi_object_get_session(obj_folder);
956         session[1] = mapi_object_get_session(obj_src);
957         session[2] = mapi_object_get_session(obj_dst);
958         OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
959         OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
960         OPENCHANGE_RETVAL_IF(!session[2], MAPI_E_INVALID_PARAMETER, NULL);
961
962         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
963                 return retval;
964
965         mem_ctx = talloc_named(NULL, 0, "MoveFolder");
966         size = 0;
967
968         /* Fill the MoveFolder operation */
969         request.handle_idx = 0x1;
970         size += sizeof (uint8_t);
971
972         request.WantAsynchronous = 0;
973         size += sizeof (uint8_t);
974
975         request.UseUnicode = UseUnicode;
976         size += sizeof (uint8_t);
977
978         request.FolderId = mapi_object_get_id(obj_folder);
979         size += sizeof (uint64_t);
980
981         if (!request.UseUnicode) {
982                 request.NewFolderName.lpszA = NewFolderName;
983                 size += strlen(NewFolderName) + 1;
984         } else {
985                 request.NewFolderName.lpszW = NewFolderName;
986                 size += get_utf8_utf16_conv_length(NewFolderName);
987         }
988
989
990         /* Fill the MAPI_REQ request */
991         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
992         mapi_req->opnum = op_MAPI_MoveFolder;
993         mapi_req->logon_id = logon_id;
994         mapi_req->handle_idx = 0;
995         mapi_req->u.mapi_MoveFolder = request;
996         size += 5;
997
998         /* Fill the mapi_request structure */
999         mapi_request = talloc(mem_ctx, struct mapi_request);
1000         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
1001         mapi_request->length = size;
1002         mapi_request->mapi_req = mapi_req;
1003         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
1004         mapi_request->handles[0] = mapi_object_get_handle(obj_src);
1005         mapi_request->handles[1] = mapi_object_get_handle(obj_dst);
1006
1007         status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
1008         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1009         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1010         retval = mapi_response->mapi_repl->error_code;
1011         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1012
1013         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1014
1015         talloc_free(mapi_response);
1016         talloc_free(mem_ctx);
1017
1018         return MAPI_E_SUCCESS;
1019 }
1020
1021
1022 /**
1023    \details Copy a folder
1024
1025    \param obj_folder the folder to copy
1026    \param obj_src source object where the folder to copy is stored
1027    \param obj_dst destination object where the folder will be copied
1028    \param NewFolderName the new folder name in the destination folder
1029    \param UseUnicode whether the folder name is unicode encoded or not
1030    \param WantRecursive whether we should copy folder's subdirectories
1031    or not
1032
1033    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1034    
1035    \note Developer may also call GetLastError() to retrieve the last
1036    MAPI error code. Possible MAPI error codes are:
1037    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1038    - MAPI_E_CALL_FAILED: A network problem was encountered during the
1039      transaction
1040
1041    \sa OpenFolder, MoveFolder
1042  */
1043 _PUBLIC_ enum MAPISTATUS CopyFolder(mapi_object_t *obj_folder,
1044                                     mapi_object_t *obj_src,
1045                                     mapi_object_t *obj_dst,
1046                                     char *NewFolderName,
1047                                     bool UseUnicode,
1048                                     bool WantRecursive)
1049 {
1050         struct mapi_request     *mapi_request;
1051         struct mapi_response    *mapi_response;
1052         struct EcDoRpc_MAPI_REQ *mapi_req;
1053         struct CopyFolder_req   request;
1054         struct mapi_session     *session[3];
1055         NTSTATUS                status;
1056         enum MAPISTATUS         retval;
1057         uint32_t                size;
1058         TALLOC_CTX              *mem_ctx;
1059         uint8_t                 logon_id;
1060
1061         /* Sanity checks */
1062         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
1063         OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
1064         OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
1065         OPENCHANGE_RETVAL_IF(!NewFolderName, MAPI_E_INVALID_PARAMETER, NULL);
1066
1067         session[0] = mapi_object_get_session(obj_folder);
1068         session[1] = mapi_object_get_session(obj_src);
1069         session[2] = mapi_object_get_session(obj_dst);
1070         OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
1071         OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
1072         OPENCHANGE_RETVAL_IF(!session[2], MAPI_E_INVALID_PARAMETER, NULL);
1073
1074         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
1075                 return retval;
1076
1077         mem_ctx = talloc_named(NULL, 0, "CopyFolder");
1078
1079         size = 0;
1080
1081         /* Fill the CopyFolder operation */
1082         request.handle_idx = 0x1;
1083         size += sizeof (uint8_t);
1084         
1085         request.WantAsynchronous = 0x0;
1086         size += sizeof (uint8_t);
1087
1088         request.WantRecursive = WantRecursive;
1089         size += sizeof (uint8_t);
1090
1091         request.UseUnicode = UseUnicode;
1092         size += sizeof (uint8_t);
1093
1094         request.FolderId = mapi_object_get_id(obj_folder);
1095         size += sizeof (uint64_t);
1096
1097         if (!request.UseUnicode) {
1098                 request.NewFolderName.lpszA = NewFolderName;
1099                 size += strlen(NewFolderName) + 1;
1100         } else {
1101                 request.NewFolderName.lpszW = NewFolderName;
1102                 size += get_utf8_utf16_conv_length(NewFolderName);
1103         }
1104
1105         /* Fill the MAPI_REQ request */
1106         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1107         mapi_req->opnum = op_MAPI_CopyFolder;
1108         mapi_req->logon_id = logon_id;
1109         mapi_req->handle_idx = 0;
1110         mapi_req->u.mapi_CopyFolder = request;
1111         size += 5;
1112
1113         /* Fill the mapi_request structure */
1114         mapi_request = talloc(mem_ctx, struct mapi_request);
1115         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
1116         mapi_request->length = size;
1117         mapi_request->mapi_req = mapi_req;
1118         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
1119         mapi_request->handles[0] = mapi_object_get_handle(obj_src);
1120         mapi_request->handles[1] = mapi_object_get_handle(obj_dst);
1121
1122         status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
1123         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1124         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1125         retval = mapi_response->mapi_repl->error_code;
1126         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1127
1128         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1129
1130         talloc_free(mapi_response);
1131         talloc_free(mem_ctx);
1132         
1133         return MAPI_E_SUCCESS;
1134 }
1135
1136
1137 /**
1138    \details Set the Read Flags on one or more messages
1139
1140    \param obj_folder the folder containing the messages to change
1141    \param ReadFlags a bitmap of flags controlling the changes to
1142    PR_PROPERTY_FLAGS
1143    \param MessageIdCount the number of messages in the MessageIds array
1144    \param MessageIds an array of message ids to set Read flags for
1145
1146    Note that the obj_folder argument is the object corresponding to the
1147    folder containing the messages (e.g. the result of CreateFolder() or
1148    OpenFolder(). It is \em not the content table of that folder (unlike
1149    SetMessageReadFlag().)
1150
1151    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1152
1153    \note Developers may also call GetLastError() to retrieve the last
1154    MAPI error code. Possible MAPI error codes are:
1155    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1156    - MAPI_E_CALL_FAILED: A network problem was encountered during the
1157      transaction
1158
1159    \sa SetMessageReadFlags for a slightly different version, working on
1160    a single message
1161 */
1162 _PUBLIC_ enum MAPISTATUS SetReadFlags(mapi_object_t *obj_folder,
1163                                       uint8_t ReadFlags, 
1164                                       uint16_t MessageIdCount,
1165                                       uint64_t *MessageIds)
1166 {
1167         TALLOC_CTX              *mem_ctx;
1168         uint32_t                size;
1169         struct SetReadFlags_req request;
1170         struct EcDoRpc_MAPI_REQ *mapi_req;
1171         struct mapi_request     *mapi_request;
1172         struct mapi_session     *session;
1173         NTSTATUS                status;
1174         struct mapi_response    *mapi_response;
1175         enum MAPISTATUS         retval;
1176         uint8_t                 logon_id;
1177
1178         /* Sanity checks */
1179         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
1180         session = mapi_object_get_session(obj_folder);
1181         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1182
1183         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
1184                 return retval;
1185
1186         mem_ctx = talloc_named(NULL, 0, "SetReadFlags");
1187
1188         size = 0;
1189
1190         /* Fill the SetReadFlags operation */
1191         request.WantAsynchronous = 0;
1192         size += sizeof(uint8_t);
1193         request.ReadFlags = ReadFlags;
1194         size += sizeof(uint8_t);
1195         request.MessageIdCount = MessageIdCount;
1196         size += sizeof(uint16_t);
1197         request.MessageIds = MessageIds;
1198         size += sizeof(uint64_t) * MessageIdCount;
1199
1200
1201         /* Fill the MAPI_REQ request */
1202         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1203         mapi_req->opnum = op_MAPI_SetReadFlags;
1204         mapi_req->logon_id = logon_id;
1205         mapi_req->handle_idx = 0;
1206         mapi_req->u.mapi_SetReadFlags = request;
1207         size += 5;
1208
1209         /* Fill the mapi_request structure */
1210         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1211         mapi_request->mapi_len = size + sizeof(uint32_t);
1212         mapi_request->length = size;
1213         mapi_request->mapi_req = mapi_req;
1214         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1215         mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
1216
1217         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1218         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1219         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1220         retval = mapi_response->mapi_repl->error_code;
1221         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1222
1223         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1224
1225         /* TODO: parse response */
1226
1227         talloc_free(mapi_response);
1228         talloc_free(mem_ctx);
1229
1230         return MAPI_E_SUCCESS;
1231 }
1232
1233 /**
1234    \details Hard delete the contents of a folder, including subfolders
1235
1236    This function empties (clears) the contents of a specified folder.
1237
1238    \param obj_folder the folder to empty
1239
1240    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1241
1242    \note Developers may also call GetLastError() to retrieve the last
1243    MAPI error code. Possible MAPI error codes are:
1244    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1245    - MAPI_E_INVALID_PARAMETER: obj_folder is not valid
1246    - MAPI_E_CALL_FAILED: A network problem was encountered during the
1247      transaction
1248
1249    \sa DeleteFolder, EmptyFolder
1250 */
1251 _PUBLIC_ enum MAPISTATUS HardDeleteMessagesAndSubfolders(mapi_object_t *obj_folder)
1252 {
1253         struct mapi_request                             *mapi_request;
1254         struct mapi_response                            *mapi_response;
1255         struct EcDoRpc_MAPI_REQ                         *mapi_req;
1256         struct HardDeleteMessagesAndSubfolders_req      request;
1257         struct mapi_session                             *session;
1258         NTSTATUS                                        status;
1259         enum MAPISTATUS                                 retval;
1260         uint32_t                                        size;
1261         TALLOC_CTX                                      *mem_ctx;
1262         uint8_t                                         logon_id;
1263
1264         /* Sanity checks */
1265         OPENCHANGE_RETVAL_IF(!obj_folder, MAPI_E_INVALID_PARAMETER, NULL);
1266         session = mapi_object_get_session(obj_folder);
1267         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1268
1269         if ((retval = mapi_object_get_logon_id(obj_folder, &logon_id)) != MAPI_E_SUCCESS)
1270                 return retval;
1271
1272         mem_ctx = talloc_named(NULL, 0, "HardDeleteMessagesAndSubfolders");
1273         size = 0;
1274
1275         /* Fill the EmptyFolder operation */
1276         request.WantAsynchronous = 0x0;
1277         size += sizeof (uint8_t);
1278
1279         request.WantDeleteAssociated = 0x0;
1280         size += sizeof (uint8_t);
1281
1282         /* Fill the MAPI_REQ request */
1283         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1284         mapi_req->opnum = op_MAPI_HardDeleteMessagesAndSubfolders;
1285         mapi_req->logon_id = logon_id;
1286         mapi_req->handle_idx = 0;
1287         mapi_req->u.mapi_HardDeleteMessagesAndSubfolders = request;
1288         size += 5;
1289
1290         /* Fill the mapi_request structure */
1291         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1292         mapi_request->mapi_len = size + sizeof(uint32_t);
1293         mapi_request->length = size;
1294         mapi_request->mapi_req = mapi_req;
1295         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1296         mapi_request->handles[0] = mapi_object_get_handle(obj_folder);
1297
1298         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1299         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1300         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1301         retval = mapi_response->mapi_repl->error_code;
1302         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1303
1304         talloc_free(mapi_response);
1305         talloc_free(mem_ctx);
1306
1307         return MAPI_E_SUCCESS;
1308 }