Merge r3352 from sogo branch
[jelmer/openchange.git] / libmapi / IMAPIProp.c
1 /*
2    OpenChange MAPI implementation.
3
4    Copyright (C) Julien Kerihuel 2007-2008.
5    Copyright (C) Brad Hards 2008.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "libmapi/libmapi.h"
22 #include "libmapi/mapi_nameid.h"
23 #include "libmapi/libmapi_private.h"
24
25
26 /**
27    \file IMAPIProp.c
28
29    \brief Properties and named properties operations.
30  */
31
32
33 /**
34    \details Returns values of one or more properties for an object
35  
36    The function takes a pointer on the object obj, a MAPITAGS array
37    specified in mapitags, and the count of properties.  The function
38    returns associated values within the SPropValue values pointer.
39
40    The array of MAPI property tags can be filled with both known and
41    named properties.
42
43    \param obj the object to get properties on
44    \param flags Flags for behaviour; can be bit-OR of MAPI_UNICODE and
45       MAPI_PROPS_SKIP_NAMEDID_CHECK constants
46    \param SPropTagArray an array of MAPI property tags
47    \param lpProps the result of the query
48    \param PropCount the count of property tags
49
50    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
51
52    \note Developers may also call GetLastError() to retrieve the last
53    MAPI error code. Possible MAPI error codes are:
54    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
55    - MAPI_E_INVALID_PARAMETER: obj or SPropTagArray are null, or the
56    session context could not be obtained
57    - MAPI_E_CALL_FAILED: A network problem was encountered during the
58      transaction
59
60    \sa SetProps, GetPropList, GetPropsAll, DeleteProps, GetLastError
61 */
62 _PUBLIC_ enum MAPISTATUS GetProps(mapi_object_t *obj,
63                                   uint32_t flags,
64                                   struct SPropTagArray *SPropTagArray,
65                                   struct SPropValue **lpProps, 
66                                   uint32_t *PropCount)
67 {
68         struct mapi_context     *mapi_ctx;
69         struct mapi_request     *mapi_request;
70         struct mapi_response    *mapi_response;
71         struct EcDoRpc_MAPI_REQ *mapi_req;
72         struct GetProps_req     request;
73         struct mapi_session     *session;
74         struct mapi_nameid      *nameid;
75         struct SPropTagArray    properties;
76         struct SPropTagArray    *SPropTagArray2 = NULL;
77         NTSTATUS                status;
78         enum MAPISTATUS         retval;
79         enum MAPISTATUS         mapistatus;
80         uint32_t                size;
81         TALLOC_CTX              *mem_ctx;
82         bool                    named = false;
83         uint8_t                 logon_id;
84
85         /* Sanity checks */
86         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
87         OPENCHANGE_RETVAL_IF(!SPropTagArray, MAPI_E_INVALID_PARAMETER, NULL);
88
89         session = mapi_object_get_session(obj);
90         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
91
92         mapi_ctx = session->mapi_ctx;
93         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
94
95         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
96                 return retval;
97
98         mem_ctx = talloc_named(NULL, 0, "GetProps");
99
100         /* Named property mapping */
101         nameid = mapi_nameid_new(mem_ctx);
102         if (!(flags & MAPI_PROPS_SKIP_NAMEDID_CHECK)) {
103                 retval = mapi_nameid_lookup_SPropTagArray(nameid, SPropTagArray);
104                 if (retval == MAPI_E_SUCCESS) {
105                         named = true;
106                         SPropTagArray2 = talloc_zero(mem_ctx, struct SPropTagArray);
107                         retval = GetIDsFromNames(obj, nameid->count, nameid->nameid, 0, &SPropTagArray2);
108                         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);          
109                         mapi_nameid_map_SPropTagArray(nameid, SPropTagArray, SPropTagArray2);
110                         MAPIFreeBuffer(SPropTagArray2);
111                 }
112         }
113         errno = 0;
114
115         /* Reset */
116         *PropCount = 0;
117         *lpProps = 0;
118         size = 0;
119
120         /* Fill the GetProps operation */
121         request.PropertySizeLimit = 0x0;
122         size += sizeof (uint16_t);
123         request.WantUnicode = (flags & MAPI_UNICODE) != 0 ? true : 0x0;
124         size += sizeof (uint16_t);
125         request.prop_count = (uint16_t) SPropTagArray->cValues;
126         size += sizeof (uint16_t);
127         properties.cValues = SPropTagArray->cValues;
128         properties.aulPropTag = talloc_memdup(mem_ctx, SPropTagArray->aulPropTag, SPropTagArray->cValues * sizeof(enum MAPITAGS));
129         request.properties = properties.aulPropTag;
130         size += request.prop_count * sizeof(uint32_t);
131
132         /* Fill the MAPI_REQ request */
133         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
134         mapi_req->opnum = op_MAPI_GetProps;
135         mapi_req->logon_id = logon_id;
136         mapi_req->handle_idx = 0;
137         mapi_req->u.mapi_GetProps = request;
138         size += 5;
139        
140         /* Fill the mapi_request structure */
141         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
142         mapi_request->mapi_len = size + sizeof (uint32_t);
143         mapi_request->length = size;
144         mapi_request->mapi_req = mapi_req;
145         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
146         mapi_request->handles[0] = mapi_object_get_handle(obj);
147
148         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
149         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
150         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
151         retval = mapi_response->mapi_repl->error_code;
152         OPENCHANGE_RETVAL_IF((retval && retval != MAPI_W_ERRORS_RETURNED), retval, mem_ctx);
153
154         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
155         
156         /* Read the SPropValue array from data blob.
157            fixme: replace the memory context by the object one.
158         */
159         if (named == true) {
160                 mapi_nameid_unmap_SPropTagArray(nameid, SPropTagArray);
161         }
162         talloc_free(nameid);
163
164         mapistatus = emsmdb_get_SPropValue((TALLOC_CTX *)session,
165                                            mapi_ctx->lp_ctx,
166                                            &mapi_response->mapi_repl->u.mapi_GetProps.prop_data,
167                                            &properties, lpProps, PropCount, 
168                                            mapi_response->mapi_repl->u.mapi_GetProps.layout);
169         OPENCHANGE_RETVAL_IF(!mapistatus && (retval == MAPI_W_ERRORS_RETURNED), retval, mem_ctx);
170         
171         talloc_free(mapi_response);
172         talloc_free(mem_ctx);
173         
174         return MAPI_E_SUCCESS;
175 }
176
177
178 /**
179    \details Set one or more properties on a given object
180
181    This function sets one or more properties on a specified object.
182
183    \param obj the object to set properties on
184    \param flags Flags for behaviour; can be MAPI_PROPS_SKIP_NAMEDID_CHECK
185    \param lpProps the list of properties to set
186    \param PropCount the number of properties
187
188    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
189
190    \note Developers may also call GetLastError() to retrieve the last
191    MAPI error code. Possible MAPI error codes are:
192    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
193    - MAPI_E_CALL_FAILED: A network problem was encountered during the
194      transaction
195
196    \sa GetProps, GetPropList, GetPropsAll, DeleteProps, GetLastError
197 */
198 _PUBLIC_ enum MAPISTATUS SetProps(mapi_object_t *obj,
199                                   uint32_t flags,
200                                   struct SPropValue *lpProps, 
201                                   unsigned long PropCount)
202 {
203         TALLOC_CTX              *mem_ctx;
204         struct mapi_request     *mapi_request;
205         struct mapi_response    *mapi_response;
206         struct EcDoRpc_MAPI_REQ *mapi_req;
207         struct SetProps_req     request;
208         struct mapi_session     *session;
209         struct mapi_nameid      *nameid;
210         struct SPropTagArray    *SPropTagArray = NULL;
211         NTSTATUS                status;
212         enum MAPISTATUS         retval;
213         uint32_t                size = 0;
214         unsigned long           i;
215         struct mapi_SPropValue  *mapi_props;
216         bool                    named = false;
217         uint8_t                 logon_id;
218
219         /* Sanity checks */
220         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
221
222         session = mapi_object_get_session(obj);
223         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
224
225         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
226                 return retval;
227
228         mem_ctx = talloc_named(NULL, 0, "SetProps");
229         size = 0;
230
231         /* Named property mapping */
232         nameid = mapi_nameid_new(mem_ctx);
233         if (!(flags & MAPI_PROPS_SKIP_NAMEDID_CHECK)) {
234                 retval = mapi_nameid_lookup_SPropValue(nameid, lpProps, PropCount);
235                 if (retval == MAPI_E_SUCCESS) {
236                         named = true;
237                         SPropTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
238                         retval = GetIDsFromNames(obj, nameid->count, nameid->nameid, 0, &SPropTagArray);
239                         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
240                         mapi_nameid_map_SPropValue(nameid, lpProps, PropCount, SPropTagArray);
241                         MAPIFreeBuffer(SPropTagArray);
242                 }
243         }
244         errno = 0;
245
246         /* build the array */
247         request.values.lpProps = talloc_array(mem_ctx, struct mapi_SPropValue, PropCount);
248         mapi_props = request.values.lpProps;
249         for (i = 0; i < PropCount; i++) {
250                 size += cast_mapi_SPropValue((TALLOC_CTX *)request.values.lpProps, &mapi_props[i], &lpProps[i]);
251                 size += sizeof(uint32_t);
252         }
253
254         request.values.cValues = PropCount;
255         size += sizeof(uint16_t);
256
257         /* add the size of the subcontext that will be added on ndr layer */
258         size += sizeof(uint16_t);
259
260         /* Fill the MAPI_REQ request */
261         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
262         mapi_req->opnum = op_MAPI_SetProps;
263         mapi_req->logon_id = logon_id;
264         mapi_req->handle_idx = 0;
265         mapi_req->u.mapi_SetProps = request;
266         size += 5;
267
268         /* Fill the mapi_request structure */
269         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
270         mapi_request->mapi_len = size + sizeof (uint32_t);
271         mapi_request->length = size;
272         mapi_request->mapi_req = mapi_req;
273         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
274         mapi_request->handles[0] = mapi_object_get_handle(obj);
275
276         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
277         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
278         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
279         retval = mapi_response->mapi_repl->error_code;
280         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
281
282         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
283
284         if (named == true) {
285                 mapi_nameid_unmap_SPropValue(nameid, lpProps, PropCount);
286         }
287         talloc_free(nameid);
288
289         talloc_free(mapi_response);
290         talloc_free(mem_ctx);
291
292         return MAPI_E_SUCCESS;
293 }
294
295
296 /**
297    \details Makes permanent any changes made to an attachment since the
298    last save operation.
299
300    \param obj_parent the parent of the object to save changes for
301    \param obj_child the object to save changes for
302    \param flags the access flags to set on the saved object 
303
304    Possible flags:
305    - KeepOpenReadOnly
306    - KeepOpenReadWrite
307    - ForceSave
308
309    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
310
311    \note Developers may also call GetLastError() to retrieve the last
312    MAPI error code. Possible MAPI error codes are:
313    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
314    - MAPI_E_CALL_FAILED: A network problem was encountered during the
315      transaction
316
317    \sa SetProps, ModifyRecipients, GetLastError
318  */
319 _PUBLIC_ enum MAPISTATUS SaveChangesAttachment(mapi_object_t *obj_parent, 
320                                                mapi_object_t *obj_child,
321                                                enum SaveFlags flags)
322 {
323         struct mapi_request                     *mapi_request;
324         struct mapi_response                    *mapi_response;
325         struct EcDoRpc_MAPI_REQ                 *mapi_req;
326         struct SaveChangesAttachment_req        request;
327         struct mapi_session                     *session[2];
328         NTSTATUS                                status;
329         enum MAPISTATUS                         retval;
330         uint32_t                                size = 0;
331         TALLOC_CTX                              *mem_ctx;
332         uint8_t                                 logon_id;
333
334         /* Sanity Checks */
335         OPENCHANGE_RETVAL_IF(!obj_parent, MAPI_E_INVALID_PARAMETER, NULL);
336         OPENCHANGE_RETVAL_IF(!obj_child, MAPI_E_INVALID_PARAMETER, NULL);
337         OPENCHANGE_RETVAL_IF((flags != 0x9) && (flags != 0xA) && (flags != 0xC), 
338                        MAPI_E_INVALID_PARAMETER, NULL);
339
340         session[0] = mapi_object_get_session(obj_parent);
341         session[1] = mapi_object_get_session(obj_child);
342         OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
343         OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
344         OPENCHANGE_RETVAL_IF(session[0] != session[1], MAPI_E_INVALID_PARAMETER, NULL);
345
346         if ((retval = mapi_object_get_logon_id(obj_parent, &logon_id)) != MAPI_E_SUCCESS)
347                 return retval;
348
349         mem_ctx = talloc_named(NULL, 0, "SaveChangesAttachment");
350         size = 0;
351
352         /* Fill the SaveChangesAttachment operation */
353         request.handle_idx = 0x0;
354         request.SaveFlags = flags;
355         size += sizeof(uint8_t) + sizeof(uint8_t);
356
357         /* Fill the MAPI_REQ request */
358         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
359         mapi_req->opnum = op_MAPI_SaveChangesAttachment;
360         mapi_req->logon_id = logon_id;
361         mapi_req->handle_idx = 0;
362         mapi_req->u.mapi_SaveChangesAttachment = request;
363         size += 5;
364
365         /* Fill the mapi_request structure */
366         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
367         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
368         mapi_request->length = size;
369         mapi_request->mapi_req = mapi_req;
370         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
371         mapi_request->handles[0] = mapi_object_get_handle(obj_child);
372         mapi_request->handles[1] = mapi_object_get_handle(obj_parent);
373
374         status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
375         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
376         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
377         retval = mapi_response->mapi_repl->error_code;
378         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
379
380         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
381
382         talloc_free(mapi_response);
383         talloc_free(mem_ctx);
384
385         return MAPI_E_SUCCESS;
386 }
387
388
389 /**
390    \details Retrieve all the properties associated with a given object
391
392    \param obj the object to retrieve properties for
393    \param proptags the resulting list of properties associated with
394    the object
395
396    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
397
398    \note Developers may also call GetLastError() to retrieve the last
399    MAPI error code. Possible MAPI error codes are:   
400    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
401    - MAPI_E_CALL_FAILED: A network problem was encountered during the
402      transaction
403
404      The developer MUST provide an allocated SPropTagArray structure
405      to the function.
406
407    \sa GetProps, GetPropsAll, GetLastError
408  */
409 _PUBLIC_ enum MAPISTATUS GetPropList(mapi_object_t *obj, 
410                                      struct SPropTagArray *proptags)
411 {
412         struct mapi_request     *mapi_request;
413         struct mapi_response    *mapi_response;
414         struct EcDoRpc_MAPI_REQ *mapi_req;
415         struct mapi_session     *session;
416         NTSTATUS                status;
417         enum MAPISTATUS         retval;
418         uint32_t                size = 0;
419         TALLOC_CTX              *mem_ctx;
420         uint8_t                 logon_id;
421
422         /* sanity checks */
423         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
424         
425         session = mapi_object_get_session(obj);
426         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
427
428         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
429                 return retval;
430
431         mem_ctx = talloc_named(NULL, 0, "GetPropList");
432
433         /* Reset */
434         proptags->cValues = 0;
435         size = 0;
436
437         /* Fill the MAPI_REQ request */
438         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
439         mapi_req->opnum = op_MAPI_GetPropList;
440         mapi_req->logon_id = logon_id;
441         mapi_req->handle_idx = 0;
442         size += 5;
443
444         /* Fill the mapi_request structure */
445         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
446         mapi_request->mapi_len = size + sizeof (uint32_t) * 1;
447         mapi_request->length = size;
448         mapi_request->mapi_req = mapi_req;
449         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
450         mapi_request->handles[0] = mapi_object_get_handle(obj);
451
452         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
453         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
454         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
455         retval = mapi_response->mapi_repl->error_code;
456         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
457
458         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
459
460         /* Get the repsonse */
461         proptags->cValues = mapi_response->mapi_repl->u.mapi_GetPropList.count;
462         if (proptags->cValues) {
463                 size = proptags->cValues * sizeof(enum MAPITAGS);
464                 proptags->aulPropTag = talloc_array((TALLOC_CTX *) proptags, enum MAPITAGS, proptags->cValues);
465                 memcpy((void*)proptags->aulPropTag,
466                        (void*)mapi_response->mapi_repl->u.mapi_GetPropList.tags,
467                        size);
468         }
469
470         talloc_free(mapi_response);
471         talloc_free(mem_ctx);
472
473         return MAPI_E_SUCCESS;
474 }
475
476
477 /**
478    \details Retrieve all properties and values associated with an
479    object
480
481    This function returns all the properties and and associated values
482    for a given object.
483
484    \param obj the object to get the properties for
485    \param flags Flags for behaviour; can be a MAPI_UNICODE constant
486    \param properties the properties / values for the object
487
488    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
489
490    \note Developers may also call GetLastError() to retrieve the last
491    MAPI error code. Possible MAPI error codes are:
492    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
493    - MAPI_E_CALL_FAILED: A network problem was encountered during the
494      transaction
495
496    \sa GetProps, GetPropList, GetLastError
497 */
498 _PUBLIC_ enum MAPISTATUS GetPropsAll(mapi_object_t *obj,
499                                      uint32_t flags,
500                                      struct mapi_SPropValue_array *properties)
501 {
502         TALLOC_CTX              *mem_ctx;
503         struct mapi_request     *mapi_request;
504         struct mapi_response    *mapi_response;
505         struct EcDoRpc_MAPI_REQ *mapi_req;
506         struct GetPropsAll_req  request;
507         struct GetPropsAll_repl *reply;
508         struct mapi_session     *session;
509         NTSTATUS                status;
510         enum MAPISTATUS         retval;
511         uint32_t                size;
512         uint8_t                 logon_id;
513
514         /* Sanity checks */
515         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
516
517         session = mapi_object_get_session(obj);
518         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
519
520         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
521                 return retval;
522
523         mem_ctx = talloc_named(NULL, 0, "GetPropsAll");
524         size = 0;
525
526         /* Fill the GetPropsAll operation */
527         request.PropertySizeLimit = 0;
528         size += sizeof (uint16_t);
529         request.WantUnicode = (flags & MAPI_UNICODE) != 0 ? true : 0x0;
530         size += sizeof (uint16_t);
531
532         /* Fill the MAPI_REQ request */
533         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
534         mapi_req->opnum = op_MAPI_GetPropsAll;
535         mapi_req->logon_id = logon_id;
536         mapi_req->handle_idx = 0;
537         mapi_req->u.mapi_GetPropsAll = request;
538         size += 5;
539
540         /* Fill the mapi_request structure */
541         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
542         mapi_request->mapi_len = size + sizeof (uint32_t);
543         mapi_request->length = size;
544         mapi_request->mapi_req = mapi_req;
545         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
546         mapi_request->handles[0] = mapi_object_get_handle(obj);
547
548         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
549         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
550         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
551         retval = mapi_response->mapi_repl->error_code;
552         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
553
554         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
555
556         reply = &mapi_response->mapi_repl->u.mapi_GetPropsAll;
557         properties->cValues = reply->properties.cValues;
558         properties->lpProps = talloc_steal((TALLOC_CTX *)session, reply->properties.lpProps);
559
560         talloc_free(mapi_response);
561         talloc_free(mem_ctx);
562         return MAPI_E_SUCCESS;
563 }
564
565
566 /**
567    \details Delete one or more properties from an object
568
569    \param obj the object to remove properties from
570    \param proptags the properties to remove from the given object
571        
572    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
573
574    \note Developers may also call GetLastError() to retrieve the last
575    MAPI error code. Possible MAPI error codes are:
576    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
577    - MAPI_E_CALL_FAILED: A network problem was encountered during the
578      transaction
579
580    \sa SetProps, GetLastError
581 */
582 _PUBLIC_ enum MAPISTATUS DeleteProps(mapi_object_t *obj, 
583                                      struct SPropTagArray *proptags)
584 {
585         TALLOC_CTX              *mem_ctx;
586         struct mapi_request     *mapi_request;
587         struct mapi_response    *mapi_response;
588         struct EcDoRpc_MAPI_REQ *mapi_req;
589         struct DeleteProps_req  request;
590         struct mapi_session     *session;
591         NTSTATUS                status;
592         enum MAPISTATUS         retval;
593         uint32_t                size;
594         uint8_t                 logon_id;
595
596         /* Sanity checks */
597         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
598         OPENCHANGE_RETVAL_IF(!proptags, MAPI_E_INVALID_PARAMETER, NULL);
599
600         session = mapi_object_get_session(obj);
601         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
602
603         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
604                 return retval;
605
606         mem_ctx = talloc_named(NULL, 0, "DeleteProps");
607         size = 0;
608
609         /* Fill the DeleteProps operation */
610         request.count = proptags->cValues;
611         size += sizeof(uint16_t);
612         request.tags = proptags->aulPropTag;
613         size += proptags->cValues * sizeof(enum MAPITAGS);
614
615         /* Fill the MAPI_REQ request */
616         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
617         mapi_req->opnum = op_MAPI_DeleteProps;
618         mapi_req->logon_id = logon_id;
619         mapi_req->handle_idx = 0;
620         mapi_req->u.mapi_DeleteProps = request;
621         size += 5;
622
623         /* Fill the mapi_request structure */
624         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
625         mapi_request->mapi_len = size + sizeof (uint32_t);
626         mapi_request->length = size;
627         mapi_request->mapi_req = mapi_req;
628         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
629         mapi_request->handles[0] = mapi_object_get_handle(obj);
630
631         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
632         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
633         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
634         retval = mapi_response->mapi_repl->error_code;
635         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
636
637         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
638
639         talloc_free(mapi_response);
640         talloc_free(mem_ctx);
641
642         return MAPI_E_SUCCESS;
643 }
644
645 /**
646    \details Set one or more properties on a given object without 
647     invoking replication.
648
649    This function sets one or more properties on a specified object. It
650    is the same as SetProps, except if the object is a folder, where
651    this function does not result in folder properties being replicated.
652
653    \param obj the object to set properties on
654    \param flags Flags for behaviour; can be MAPI_PROPS_SKIP_NAMEDID_CHECK
655    \param lpProps the list of properties to set
656    \param PropCount the number of properties
657
658    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
659
660    \note Developers may also call GetLastError() to retrieve the last
661    MAPI error code. Possible MAPI error codes are:
662    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
663    - MAPI_E_INVALID_PARAMETER: obj is not valid
664    - MAPI_E_CALL_FAILED: A network problem was encountered during the
665      transaction
666
667    \sa SetProps, DeletePropertiesNoReplicate
668 */
669 _PUBLIC_ enum MAPISTATUS SetPropertiesNoReplicate(mapi_object_t *obj,
670                                                   uint32_t flags,
671                                                   struct SPropValue *lpProps, 
672                                                   unsigned long PropCount)
673 {
674         TALLOC_CTX                              *mem_ctx;
675         struct mapi_request                     *mapi_request;
676         struct mapi_response                    *mapi_response;
677         struct EcDoRpc_MAPI_REQ                 *mapi_req;
678         struct SetPropertiesNoReplicate_req     request;
679         struct mapi_session                     *session;
680         struct mapi_nameid                      *nameid;
681         struct SPropTagArray                    *SPropTagArray = NULL;
682         NTSTATUS                                status;
683         enum MAPISTATUS                         retval;
684         uint32_t                                size = 0;
685         unsigned long                           i;
686         struct mapi_SPropValue                  *mapi_props;
687         bool                                    named = false;
688         uint8_t                                 logon_id;
689
690         /* Sanity checks */
691         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
692
693         session = mapi_object_get_session(obj);
694         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
695
696         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
697                 return retval;
698
699         mem_ctx = talloc_named(NULL, 0, "SetPropertiesNoReplicate");
700         size = 0;
701
702         /* Named property mapping */
703         nameid = mapi_nameid_new(mem_ctx);
704         if (!(flags & MAPI_PROPS_SKIP_NAMEDID_CHECK)) {
705                 retval = mapi_nameid_lookup_SPropValue(nameid, lpProps, PropCount);
706                 if (retval == MAPI_E_SUCCESS) {
707                         named = true;
708                         SPropTagArray = talloc_zero(mem_ctx, struct SPropTagArray);
709                         retval = GetIDsFromNames(obj, nameid->count, nameid->nameid, 0, &SPropTagArray);
710                         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
711                         mapi_nameid_map_SPropValue(nameid, lpProps, PropCount, SPropTagArray);
712                         MAPIFreeBuffer(SPropTagArray);
713                 }
714         }
715         errno = 0;
716
717         /* build the array */
718         request.values.lpProps = talloc_array(mem_ctx, struct mapi_SPropValue, PropCount);
719         mapi_props = request.values.lpProps;
720         for (i = 0; i < PropCount; i++) {
721                 size += cast_mapi_SPropValue((TALLOC_CTX *)request.values.lpProps, &mapi_props[i], &lpProps[i]);
722                 size += sizeof(uint32_t);
723         }
724
725         request.values.cValues = PropCount;
726         size += sizeof(uint16_t);
727
728         /* add the size of the subcontext that will be added on ndr layer */
729         size += sizeof(uint16_t);
730
731         /* Fill the MAPI_REQ request */
732         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
733         mapi_req->opnum = op_MAPI_SetPropertiesNoReplicate;
734         mapi_req->logon_id = logon_id;
735         mapi_req->handle_idx = 0;
736         mapi_req->u.mapi_SetPropertiesNoReplicate = request;
737         size += 5;
738
739         /* Fill the mapi_request structure */
740         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
741         mapi_request->mapi_len = size + sizeof (uint32_t);
742         mapi_request->length = size;
743         mapi_request->mapi_req = mapi_req;
744         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
745         mapi_request->handles[0] = mapi_object_get_handle(obj);
746
747         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
748         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
749         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
750         retval = mapi_response->mapi_repl->error_code;
751         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
752
753         if (named == true) {
754                 mapi_nameid_unmap_SPropValue(nameid, lpProps, PropCount);
755         }
756         talloc_free(nameid);
757
758         talloc_free(mapi_response);
759         talloc_free(mem_ctx);
760
761         return MAPI_E_SUCCESS;
762 }
763
764
765 /**
766    \details Deletes property values from an object without invoking
767    replication.
768
769    \param obj the object to remove properties from
770    \param proptags the properties to remove from the given object
771
772    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
773
774    \note Developers may also call GetLastError() to retrieve the last
775    MAPI error code. Possible MAPI error codes are:
776    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
777    - MAPI_E_CALL_FAILED: A network problem was encountered during the
778      transaction
779
780      \sa DeleteProps
781  */
782 _PUBLIC_ enum MAPISTATUS DeletePropertiesNoReplicate(mapi_object_t *obj,
783                                                      struct SPropTagArray *proptags)
784 {
785         TALLOC_CTX                              *mem_ctx;
786         struct mapi_request                     *mapi_request;
787         struct mapi_response                    *mapi_response;
788         struct EcDoRpc_MAPI_REQ                 *mapi_req;
789         struct DeletePropertiesNoReplicate_req  request;
790         struct mapi_session                     *session;
791         NTSTATUS                                status;
792         enum MAPISTATUS                         retval;
793         uint32_t                                size;
794         uint8_t                                 logon_id;
795
796         /* Sanity checks */
797         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
798         OPENCHANGE_RETVAL_IF(!proptags, MAPI_E_INVALID_PARAMETER, NULL);
799
800         session = mapi_object_get_session(obj);
801         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
802
803         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
804                 return retval;
805
806         mem_ctx = talloc_named(NULL, 0, "DeletePropertiesNoReplicate");
807         size = 0;
808
809         /* Fill the DeletePropertiesNoReplicate operation */
810         request.PropertyTags.cValues = proptags->cValues;
811         size += sizeof (uint16_t);
812         request.PropertyTags.aulPropTag = proptags->aulPropTag;
813         size += proptags->cValues * sizeof (enum MAPITAGS);
814
815         /* Fill the MAPI_REQ request */
816         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
817         mapi_req->opnum = op_MAPI_DeletePropertiesNoReplicate;
818         mapi_req->logon_id = logon_id;
819         mapi_req->handle_idx = 0;
820         mapi_req->u.mapi_DeletePropertiesNoReplicate = request;
821         size += 5;
822
823         /* Fill the mapi_request structure */
824         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
825         mapi_request->mapi_len = size + sizeof (uint32_t);
826         mapi_request->length = size;
827         mapi_request->mapi_req = mapi_req;
828         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
829         mapi_request->handles[0] = mapi_object_get_handle(obj);
830
831         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
832         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
833         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
834         retval = mapi_response->mapi_repl->error_code;
835         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
836
837         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
838
839         talloc_free(mapi_response);
840         talloc_free(mem_ctx);
841
842         return MAPI_E_SUCCESS;  
843 }
844
845
846 /**
847    \details Provides the property names that correspond to one
848    or more property identifiers.
849    
850    \param obj the object we are retrieving the names from
851    \param ulPropTag the mapped property tag
852    \param count count of property names pointed to by the nameid
853    parameter returned by the server
854    \param nameid pointer to a pointer to property names returned by
855    the server
856
857    ulPropTag must be a property with type set to PT_NULL
858  
859    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
860   
861    \note Developers may also call GetLastError() to retrieve the last
862    MAPI error code. Possible MAPI error codes are:
863    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
864    - MAPI_E_CALL_FAILED: A network problem was encountered during the
865      transaction
866
867    \sa GetIDsFromNames, QueryNamesFromIDs
868 */
869 _PUBLIC_ enum MAPISTATUS GetNamesFromIDs(mapi_object_t *obj,
870                                          enum MAPITAGS ulPropTag,
871                                          uint16_t *count,
872                                          struct MAPINAMEID **nameid)
873 {
874         struct mapi_request             *mapi_request;
875         struct mapi_response            *mapi_response;
876         struct EcDoRpc_MAPI_REQ         *mapi_req;
877         struct GetNamesFromIDs_req      request;
878         struct GetNamesFromIDs_repl     *reply;
879         struct mapi_session             *session;
880         NTSTATUS                        status;
881         enum MAPISTATUS                 retval;
882         uint32_t                        size= 0;
883         TALLOC_CTX                      *mem_ctx;
884         uint8_t                         logon_id;
885
886         /* sanity checks */
887         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
888
889         session = mapi_object_get_session(obj);
890         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
891
892         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
893                 return retval;
894
895         /* Initialization */
896         mem_ctx = talloc_named(NULL, 0, "GetNamesFromIDs");
897         size = 0;
898
899         /* Fill the GetNamesFromIDs operation */
900         request.PropertyIdCount = 0x1;
901         size += sizeof (uint16_t);
902         request.PropertyIds = talloc_array(mem_ctx, uint16_t, request.PropertyIdCount);
903         request.PropertyIds[0] = ((ulPropTag & 0xFFFF0000) >> 16);
904         size += request.PropertyIdCount * sizeof (uint16_t);
905
906         /* Fill the MAPI_REQ request */
907         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
908         mapi_req->opnum = op_MAPI_GetNamesFromIDs;
909         mapi_req->logon_id = logon_id;
910         mapi_req->handle_idx = 0;
911         mapi_req->u.mapi_GetNamesFromIDs = request;
912         size += 5;
913
914         /* Fill the mapi_request structure */
915         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
916         mapi_request->mapi_len = size + sizeof (uint32_t);
917         mapi_request->length = size;
918         mapi_request->mapi_req = mapi_req;
919         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
920         mapi_request->handles[0] = mapi_object_get_handle(obj);
921
922         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
923         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
924         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
925         retval = mapi_response->mapi_repl->error_code;
926         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
927
928         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
929
930         /* Fill in count */
931         reply = &mapi_response->mapi_repl->u.mapi_GetNamesFromIDs;
932         *count = reply->count;
933
934         /* Fill MAPINAMEID struct */
935         *nameid = talloc_steal((TALLOC_CTX *)session, reply->nameid);
936
937         talloc_free(mapi_response);
938         talloc_free(mem_ctx);
939
940         return MAPI_E_SUCCESS;
941 }
942
943
944 /**
945    \details Provides the property identifiers that correspond to one
946    or more property names.
947    
948    \param obj the object we are retrieving the identifiers from
949    \param count count of property names pointed to by the nameid
950    parameter.
951    \param nameid pointer to an array of property names
952    \param ulFlags indicates how the property identifiers should be
953    returned
954    \param proptags pointer to a pointer to an array of property tags
955    containing existing or newly assigned property
956    identifiers. Property types in this array are set to PT_NULL.
957
958    ulFlags can be set to:
959    - 0 retrieves named properties from the server
960    - MAPI_CREATE create the named properties if they don't exist on
961      the server
962
963    \note count and nameid parameter can automatically be built
964    using the mapi_nameid API.
965
966    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
967    
968    \note Developers may also call GetLastError() to retrieve the last
969    MAPI error code. Possible MAPI error codes are:
970    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
971    - MAPI_E_CALL_FAILED: A network problem was encountered during the
972      transaction
973
974    \sa GetNamesFromIds, QueryNamesFromIDs, mapi_nameid_new
975 */
976 _PUBLIC_ enum MAPISTATUS GetIDsFromNames(mapi_object_t *obj,
977                                          uint16_t count,
978                                          struct MAPINAMEID *nameid,
979                                          uint32_t ulFlags,
980                                          struct SPropTagArray **proptags)
981 {
982         struct mapi_request             *mapi_request;
983         struct mapi_response            *mapi_response;
984         struct EcDoRpc_MAPI_REQ         *mapi_req;
985         struct GetIDsFromNames_req      request;
986         struct mapi_session             *session;
987         NTSTATUS                        status;
988         enum MAPISTATUS                 retval;
989         uint32_t                        size = 0;
990         TALLOC_CTX                      *mem_ctx;
991         uint32_t                        i;
992         uint8_t                         logon_id;
993
994         /* sanity checks */
995         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
996         OPENCHANGE_RETVAL_IF(!count, MAPI_E_INVALID_PARAMETER, NULL);
997         OPENCHANGE_RETVAL_IF(!nameid, MAPI_E_INVALID_PARAMETER, NULL);
998         OPENCHANGE_RETVAL_IF(!proptags, MAPI_E_INVALID_PARAMETER, NULL);
999         OPENCHANGE_RETVAL_IF(!proptags[0], MAPI_E_INVALID_PARAMETER, NULL);
1000
1001         session = mapi_object_get_session(obj);
1002         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1003
1004         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
1005                 return retval;
1006
1007         /* Initialization */
1008         mem_ctx = talloc_named(NULL, 0, "GetIDsFromNames");
1009         size = 0;
1010         
1011         /* Fill the GetIDsFromNames operation */
1012         request.ulFlags = ulFlags;
1013         request.count = count;
1014         size += sizeof (uint8_t) + sizeof (uint16_t);
1015
1016         request.nameid = nameid;
1017         for (i = 0; i < count; i++) {
1018                 size += sizeof (uint8_t) + sizeof (request.nameid[i].lpguid);
1019                 switch (request.nameid[i].ulKind) {
1020                 case MNID_ID:
1021                         size += sizeof (request.nameid[i].kind.lid);
1022                         break;
1023                 case MNID_STRING:
1024                   size +=  get_utf8_utf16_conv_length(request.nameid[i].kind.lpwstr.Name);
1025                         size += sizeof (uint8_t);
1026                         break;
1027                 default:
1028                         break;
1029                 }
1030         }
1031
1032         /* Fill the MAPI_REQ request */
1033         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1034         mapi_req->opnum = op_MAPI_GetIDsFromNames;
1035         mapi_req->logon_id = logon_id;
1036         mapi_req->handle_idx = 0;
1037         mapi_req->u.mapi_GetIDsFromNames = request;
1038         size += 5;
1039
1040         /* Fill the mapi_request structure */
1041         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1042         mapi_request->mapi_len = size + sizeof (uint32_t);
1043         mapi_request->length = size;
1044         mapi_request->mapi_req = mapi_req;
1045         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1046         mapi_request->handles[0] = mapi_object_get_handle(obj);
1047
1048         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1049         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1050         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1051         retval = mapi_response->mapi_repl->error_code;
1052         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1053
1054         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1055
1056         /* Fill the SPropTagArray */
1057         proptags[0] = talloc_zero(NULL, struct SPropTagArray);
1058         proptags[0]->cValues = mapi_response->mapi_repl->u.mapi_GetIDsFromNames.count;
1059         proptags[0]->aulPropTag = (enum MAPITAGS *) talloc_array((TALLOC_CTX *)proptags[0], uint32_t, proptags[0]->cValues);
1060         for (i = 0; i < proptags[0]->cValues; i++) {
1061                 proptags[0]->aulPropTag[i] = (mapi_response->mapi_repl->u.mapi_GetIDsFromNames.propID[i] << 16) | PT_UNSPECIFIED;
1062         }
1063         
1064         talloc_free(mapi_response);
1065         talloc_free(mem_ctx);
1066
1067         return MAPI_E_SUCCESS;
1068 }
1069
1070
1071 /**
1072    \details Provides the property names that correspond to one or more
1073    property identifiers.
1074
1075    \param obj the object to obtain the properties for
1076    \param queryFlags A set of flags that can restrict the type of properties
1077    \param guid a pointer to the GUID for the property set to fetch (null for all
1078    property sets.
1079    \param count count of property names pointed to by the nameid and propID
1080    parameters returned by the server
1081    \param propID pointer to an array of property IDs returned by the server
1082    \param nameid pointer to an array of property names returned by
1083    the server
1084
1085    \note queryFlags can be NoStrings (0x1) or NoIds (0x2), neither or both.
1086    NoStrings will produce only ID properties, NoIds will produce only named
1087    properties, and both will result in no output.
1088
1089    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1090
1091    \sa GetNamesFromIDs
1092 */
1093 _PUBLIC_ enum MAPISTATUS QueryNamedProperties(mapi_object_t *obj,
1094                                               uint8_t queryFlags,
1095                                               struct GUID *guid,
1096                                               uint16_t *count,
1097                                               uint16_t **propID,
1098                                               struct MAPINAMEID **nameid)
1099 {
1100         struct mapi_request                     *mapi_request;
1101         struct mapi_response                    *mapi_response;
1102         struct EcDoRpc_MAPI_REQ                 *mapi_req;
1103         struct QueryNamedProperties_req         request;
1104         struct QueryNamedProperties_repl        *reply;
1105         struct mapi_session                     *session;
1106         NTSTATUS                                status;
1107         enum MAPISTATUS                         retval;
1108         uint32_t                                size;
1109         TALLOC_CTX                              *mem_ctx;
1110         uint8_t                                 logon_id;
1111
1112         /* Sanity checks */
1113         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
1114
1115         session = mapi_object_get_session(obj);
1116         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1117
1118         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
1119                 return retval;
1120
1121         /* Initialization */
1122         mem_ctx = talloc_named(NULL, 0, "QueryNamesFromIDs");
1123         size = 0;
1124
1125         /* Fill the QueryNamedProperties operation */
1126         request.QueryFlags = queryFlags;
1127         size += sizeof (uint8_t);
1128
1129         if (guid) {
1130                 request.HasGuid = 0x1; /* true */
1131                 size += sizeof (uint8_t);
1132                 request.PropertyGuid.guid = *guid;
1133                 size += sizeof (struct GUID);
1134         } else {
1135                 request.HasGuid = 0x0; /* false */
1136                 size += sizeof (uint8_t);
1137         }
1138
1139         /* Fill the MAPI_REQ request */
1140         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1141         mapi_req->opnum = op_MAPI_QueryNamedProperties;
1142         mapi_req->logon_id = logon_id;
1143         mapi_req->handle_idx = 0;
1144         mapi_req->u.mapi_QueryNamedProperties = request;
1145         size += 5;
1146
1147         /* Fill the mapi_request structure */
1148         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1149         mapi_request->mapi_len = size + sizeof (uint32_t);
1150         mapi_request->length = size;
1151         mapi_request->mapi_req = mapi_req;
1152         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1153         mapi_request->handles[0] = mapi_object_get_handle(obj);
1154
1155         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1156         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1157         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1158         retval = mapi_response->mapi_repl->error_code;
1159         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1160
1161         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
1162
1163         /* Fill [out] parameters */
1164         reply = &mapi_response->mapi_repl->u.mapi_QueryNamedProperties;
1165
1166         *count = reply->IdCount;
1167         *propID = talloc_steal((TALLOC_CTX *)session, reply->PropertyIds);
1168         *nameid = talloc_steal((TALLOC_CTX *)session, reply->PropertyNames);
1169
1170         talloc_free(mapi_response);
1171         talloc_free(mem_ctx);
1172         
1173         return MAPI_E_SUCCESS;
1174 }
1175
1176
1177 /**
1178    \details Copy properties from one object to another
1179
1180    This function copies (or moves) specified properties from
1181    one object to another.
1182
1183    \param obj_src the object to copy properties from
1184    \param obj_dst the object to set properties on
1185    \param copyFlags flags to determine whether to copy or
1186    move, and whether to overwrite existing properties.
1187    \param tags the list of properties to copy
1188    \param problemCount (return value) number of entries in the problems array
1189    \param problems (return value) array of problemCount entries.
1190
1191    The caller is responsible for freeing the \b problems array
1192    using MAPIFreeBuffer(). If the \b problemCount pointer is NULL,
1193    then the problems array will not be returned.
1194
1195    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1196
1197    \note Developers may also call GetLastError() to retrieve the last
1198    MAPI error code. Possible MAPI error codes are:
1199    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1200    - MAPI_E_CALL_FAILED: A network problem was encountered during the
1201      transaction
1202
1203    \sa GetProps, SetProps, DeleteProps, CopyTo, GetLastError
1204 */
1205 _PUBLIC_ enum MAPISTATUS CopyProps(mapi_object_t *obj_src,
1206                                    mapi_object_t *obj_dst,
1207                                    struct SPropTagArray *tags,
1208                                    uint8_t copyFlags,
1209                                    uint16_t *problemCount,
1210                                    struct PropertyProblem **problems)
1211
1212 {
1213         TALLOC_CTX                      *mem_ctx;
1214         struct mapi_request             *mapi_request;
1215         struct mapi_response            *mapi_response;
1216         struct EcDoRpc_MAPI_REQ         *mapi_req;
1217         struct CopyProperties_req       request;
1218         struct mapi_session             *session[2];
1219         NTSTATUS                        status;
1220         enum MAPISTATUS                 retval;
1221         uint32_t                        size;
1222         int                             i;
1223         uint8_t                         logon_id;
1224
1225         /* Sanity checks */
1226         OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
1227         OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
1228         OPENCHANGE_RETVAL_IF(!tags, MAPI_E_INVALID_PARAMETER, NULL);
1229
1230         session[0] = mapi_object_get_session(obj_src);
1231         session[1] = mapi_object_get_session(obj_dst);
1232         OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
1233         OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
1234         OPENCHANGE_RETVAL_IF(session[0] != session[1], MAPI_E_INVALID_PARAMETER, NULL);
1235
1236         if ((retval = mapi_object_get_logon_id(obj_src, &logon_id)) != MAPI_E_SUCCESS)
1237                 return retval;
1238
1239         mem_ctx = talloc_named(NULL, 0, "CopyProps");
1240         size = 0;
1241
1242         /* Fill the CopyProperties operation */
1243         request.handle_idx = 0x1;
1244         size += sizeof(uint8_t);
1245         request.WantAsynchronous = 0x0;
1246         size += sizeof(uint8_t);
1247         request.CopyFlags = copyFlags;
1248         size += sizeof(uint8_t);
1249         request.PropertyTags.cValues = tags->cValues;
1250         size += sizeof(uint16_t);
1251         request.PropertyTags.aulPropTag = tags->aulPropTag;
1252         size += tags->cValues * sizeof(enum MAPITAGS);
1253
1254         /* Fill the MAPI_REQ request */
1255         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1256         mapi_req->opnum = op_MAPI_CopyProperties;
1257         mapi_req->logon_id = logon_id;
1258         mapi_req->handle_idx = 0;
1259         mapi_req->u.mapi_CopyProperties = request;
1260         size += 5; // sizeof( EcDoRpc_MAPI_REQ )
1261
1262         /* Fill the mapi_request structure */
1263         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1264         mapi_request->mapi_len = size + sizeof (uint32_t) *2;
1265         mapi_request->length = size;
1266         mapi_request->mapi_req = mapi_req;
1267         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
1268         mapi_request->handles[0] = mapi_object_get_handle(obj_src);
1269         mapi_request->handles[1] = mapi_object_get_handle(obj_dst);
1270
1271         status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
1272         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1273         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1274         retval = mapi_response->mapi_repl->error_code;
1275         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1276
1277         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1278
1279         if (problemCount) {
1280                 *problemCount = mapi_response->mapi_repl->u.mapi_CopyProperties.PropertyProblemCount;
1281                 *problems = talloc_array((TALLOC_CTX *)session[0], struct PropertyProblem, *problemCount);
1282                 for(i = 0; i < *problemCount; i++) {
1283                         (*(problems[i])).index = mapi_response->mapi_repl->u.mapi_CopyProperties.PropertyProblem[i].index;
1284                         (*(problems[i])).property_tag = mapi_response->mapi_repl->u.mapi_CopyProperties.PropertyProblem[i].property_tag;
1285                         (*(problems[i])).error_code = mapi_response->mapi_repl->u.mapi_CopyProperties.PropertyProblem[i].error_code;
1286                 }
1287         }
1288
1289         talloc_free(mapi_response);
1290         talloc_free(mem_ctx);
1291
1292         return MAPI_E_SUCCESS;
1293 }
1294
1295 /**
1296    \details Copy multiple properties from one object to another
1297
1298    This function copies (or moves) properties from one object to
1299    another. Unlike CopyProperties, this function copies all properties
1300    except those identified.
1301
1302    \param obj_src the object to copy properties from
1303    \param obj_dst the object to set properties on
1304    \param excludeTags the list of properties to \em not copy
1305    \param copyFlags flags to determine whether to copy or
1306    move, and whether to overwrite existing properties.
1307    \param problemCount (return value) number of entries in the problems array
1308    \param problems (return value) array of problemCount entries.
1309
1310    The caller is responsible for freeing the \b problems array
1311    using MAPIFreeBuffer(). If the \b problemCount pointer is NULL,
1312    then the problems array will not be returned.
1313
1314    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1315
1316    \note Developers may also call GetLastError() to retrieve the last
1317    MAPI error code. Possible MAPI error codes are:
1318    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1319    - MAPI_E_CALL_FAILED: A network problem was encountered during the
1320      transaction
1321
1322    \sa GetProps, SetProps, DeleteProps, CopyProps
1323 */
1324 _PUBLIC_ enum MAPISTATUS CopyTo(mapi_object_t *obj_src,
1325                                 mapi_object_t *obj_dst,
1326                                 struct SPropTagArray *excludeTags,
1327                                 uint8_t copyFlags,
1328                                 uint16_t *problemCount,
1329                                 struct PropertyProblem **problems)
1330
1331 {
1332         TALLOC_CTX              *mem_ctx;
1333         struct mapi_request     *mapi_request;
1334         struct mapi_response    *mapi_response;
1335         struct EcDoRpc_MAPI_REQ *mapi_req;
1336         struct CopyTo_req       request;
1337         struct mapi_session     *session[2];
1338         NTSTATUS                status;
1339         enum MAPISTATUS         retval;
1340         uint32_t                size;
1341         int                     i;
1342         uint8_t                 logon_id;
1343
1344         /* Sanity checks */
1345         OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
1346         OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
1347         OPENCHANGE_RETVAL_IF(!excludeTags, MAPI_E_INVALID_PARAMETER, NULL);
1348
1349         session[0] = mapi_object_get_session(obj_src);
1350         session[1] = mapi_object_get_session(obj_dst);
1351         OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
1352         OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
1353         OPENCHANGE_RETVAL_IF(session[0] != session[1], MAPI_E_INVALID_PARAMETER, NULL);
1354
1355         if ((retval = mapi_object_get_logon_id(obj_src, &logon_id)) != MAPI_E_SUCCESS)
1356                 return retval;
1357
1358         mem_ctx = talloc_named(NULL, 0, "CopyProps");
1359         size = 0;
1360
1361         /* Fill the CopyProperties operation */
1362         request.handle_idx = 0x1;
1363         size += sizeof(uint8_t);
1364         request.WantAsynchronous = 0x0;
1365         size += sizeof(uint8_t);
1366         request.WantSubObjects = 0x1;
1367         size += sizeof(uint8_t);
1368         request.CopyFlags = copyFlags;
1369         size += sizeof(uint8_t);
1370         request.ExcludedTags.cValues = (uint16_t)excludeTags->cValues;
1371         size += sizeof(uint16_t);
1372         request.ExcludedTags.aulPropTag = excludeTags->aulPropTag;
1373         size += excludeTags->cValues * sizeof(enum MAPITAGS);
1374
1375         /* Fill the MAPI_REQ request */
1376         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1377         mapi_req->opnum = op_MAPI_CopyTo;
1378         mapi_req->logon_id = logon_id;
1379         mapi_req->handle_idx = 0;
1380         mapi_req->u.mapi_CopyTo = request;
1381         size += 5; // sizeof( EcDoRpc_MAPI_REQ )
1382
1383         /* Fill the mapi_request structure */
1384         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1385         mapi_request->mapi_len = size + sizeof (uint32_t) *2;
1386         mapi_request->length = size;
1387         mapi_request->mapi_req = mapi_req;
1388         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
1389         mapi_request->handles[0] = mapi_object_get_handle(obj_src);
1390         mapi_request->handles[1] = mapi_object_get_handle(obj_dst);
1391
1392         status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
1393         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1394         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1395         retval = mapi_response->mapi_repl->error_code;
1396         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1397
1398         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
1399
1400         if (problemCount) {
1401                 *problemCount = mapi_response->mapi_repl->u.mapi_CopyTo.PropertyProblemCount;
1402                 *problems = talloc_array((TALLOC_CTX *)session[0], struct PropertyProblem, *problemCount);
1403                 for(i=0; i < *problemCount; ++i) {
1404                         (*(problems[i])).index = mapi_response->mapi_repl->u.mapi_CopyTo.PropertyProblem[i].index;
1405                         (*(problems[i])).property_tag = mapi_response->mapi_repl->u.mapi_CopyTo.PropertyProblem[i].property_tag;
1406                         (*(problems[i])).error_code = mapi_response->mapi_repl->u.mapi_CopyTo.PropertyProblem[i].error_code;
1407                 }
1408         }
1409
1410         talloc_free(mapi_response);
1411         talloc_free(mem_ctx);
1412
1413         return MAPI_E_SUCCESS;
1414 }