Merge r3352 from sogo branch
[jelmer/openchange.git] / libmapi / FXICS.c
1 /*
2    OpenChange MAPI implementation.
3
4    Copyright (C) Julien Kerihuel 2007-2008.
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 FXICS.c
26
27    \brief Incremental Change Synchronization operations
28  */
29
30
31 /**
32    \details Reserves a range of IDs to be used by a local replica
33
34    \param obj_store pointer on the store MAPI object
35    \param IdCount ID range length to reserve
36    \param ReplGuid pointer to the GUID structure returned by the
37    server
38    \param GlobalCount byte array that specifies the first allocated
39    field
40
41    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
42
43    \note Developers may also call GetLastError() to retrieve the last
44    MAPI error code. Possible MAPI error codes are:
45    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
46    - MAPI_E_INVALID_PARAMETER: one of the function parameters is
47      invalid
48    - MAPI_E_CALL_FAILED: A network problem was encountered during the
49    transaction
50  */
51 _PUBLIC_ enum MAPISTATUS GetLocalReplicaIds(mapi_object_t *obj_store, 
52                                             uint32_t IdCount,
53                                             struct GUID *ReplGuid,
54                                             uint8_t GlobalCount[6])
55 {
56         struct mapi_request             *mapi_request;
57         struct mapi_response            *mapi_response;
58         struct EcDoRpc_MAPI_REQ         *mapi_req;
59         struct GetLocalReplicaIds_req   request;
60         struct GetLocalReplicaIds_repl  *reply;
61         struct mapi_session             *session;
62         NTSTATUS                        status;
63         enum MAPISTATUS                 retval;
64         uint32_t                        size = 0;
65         TALLOC_CTX                      *mem_ctx;
66         uint8_t                         logon_id = 0;
67
68         /* Sanity checks */
69         OPENCHANGE_RETVAL_IF(!obj_store, MAPI_E_INVALID_PARAMETER, NULL);
70         OPENCHANGE_RETVAL_IF(!ReplGuid, MAPI_E_INVALID_PARAMETER, NULL);
71
72         session = mapi_object_get_session(obj_store);
73         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
74
75         if ((retval = mapi_object_get_logon_id(obj_store, &logon_id)) != MAPI_E_SUCCESS)
76                 return retval;
77
78         mem_ctx = talloc_named(NULL, 0, "GetLocalReplicaIds");
79         size = 0;
80
81         /* Fill the GetLocalReplicaIds operation */
82         request.IdCount = IdCount;
83         size += sizeof (uint32_t);
84
85         /* Fill the MAPI_REQ structure */
86         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
87         mapi_req->opnum = op_MAPI_GetLocalReplicaIds;
88         mapi_req->logon_id = logon_id;
89         mapi_req->handle_idx = 0;
90         mapi_req->u.mapi_GetLocalReplicaIds = request;
91         size += 5;
92
93         /* Fill the mapi_request structure */
94         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
95         mapi_request->mapi_len = size + sizeof (uint32_t);
96         mapi_request->length = (uint16_t)size;
97         mapi_request->mapi_req = mapi_req;
98         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
99         mapi_request->handles[0] = mapi_object_get_handle(obj_store);
100
101         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
102         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
103         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
104         retval = mapi_response->mapi_repl->error_code;
105         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
106
107         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
108         
109         /* Retrieve output parameters */
110         reply = &mapi_response->mapi_repl->u.mapi_GetLocalReplicaIds;
111         *ReplGuid = reply->ReplGuid;
112         memcpy(GlobalCount, reply->GlobalCount, 6);
113
114         talloc_free(mapi_response);
115         talloc_free(mem_ctx);
116
117         return MAPI_E_SUCCESS;
118 }
119
120 /**
121    \details Prepare a server for Fast Transfer receive
122
123    This function is used to configure a server for fast-transfer receive operation.
124    This could be the target server in a server->client->server copy, or for a
125    client->server upload.
126
127    \param obj the target object for the upload (folder, message or attachment)
128    \param sourceOperation the type of transfer (one of FastTransferDest_CopyTo,
129    FastTransferDest_CopyProperties,FastTransferDest_CopyMessages or
130    FastTransferDest_CopyFolder)
131    \param obj_destination_context the fast transfer context for future ROPs.
132
133    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
134
135    \note Developers may also call GetLastError() to retrieve the last
136    MAPI error code. Possible MAPI error codes are:
137    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
138    - MAPI_E_INVALID_PARAMETER: one of the function parameters is
139      invalid
140    - MAPI_E_CALL_FAILED: A network problem was encountered during the
141    transaction
142  */
143 _PUBLIC_ enum MAPISTATUS FXDestConfigure(mapi_object_t *obj,
144                                          enum FastTransferDestConfig_SourceOperation sourceOperation,
145                                          mapi_object_t *obj_destination_context)
146 {
147         struct mapi_request                             *mapi_request;
148         struct mapi_response                            *mapi_response;
149         struct EcDoRpc_MAPI_REQ                         *mapi_req;
150         struct FastTransferDestinationConfigure_req     request;
151         struct mapi_session                             *session;
152         NTSTATUS                                        status;
153         enum MAPISTATUS                                 retval;
154         uint32_t                                        size = 0;
155         TALLOC_CTX                                      *mem_ctx;
156         uint8_t                                         logon_id = 0;
157
158         /* Sanity checks */
159         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
160
161         session = mapi_object_get_session(obj);
162         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
163         OPENCHANGE_RETVAL_IF(!obj_destination_context, MAPI_E_INVALID_PARAMETER, NULL);
164
165         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
166                 return retval;
167
168         mem_ctx = talloc_named(NULL, 0, "FXDestConfigure");
169         size = 0;
170
171         /* Fill the ConfigureDestination operation */
172         request.handle_idx = 0x01;
173         size += sizeof(uint8_t);
174         request.SourceOperation = sourceOperation;
175         size += sizeof(uint8_t);
176         request.CopyFlags = 0x00; /* we don't support move yet */
177         size += sizeof(uint8_t);
178
179         /* Fill the MAPI_REQ structure */
180         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
181         mapi_req->opnum = op_MAPI_FastTransferDestConfigure;
182         mapi_req->logon_id = logon_id;
183         mapi_req->handle_idx = 0;
184         mapi_req->u.mapi_FastTransferDestinationConfigure = request;
185         size += 5;
186
187         /* Fill the mapi_request structure */
188         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
189         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
190         mapi_request->length = (uint16_t)size;
191         mapi_request->mapi_req = mapi_req;
192         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
193         mapi_request->handles[0] = mapi_object_get_handle(obj);
194         mapi_request->handles[1] = 0xFFFFFFFF;
195
196         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
197         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
198         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
199         retval = mapi_response->mapi_repl->error_code;
200         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
201
202         /* Set object session and handle */
203         mapi_object_set_session(obj_destination_context, session);
204         mapi_object_set_handle(obj_destination_context, mapi_response->handles[1]);
205         mapi_object_set_logon_id(obj_destination_context, logon_id);
206
207         talloc_free(mapi_response);
208         talloc_free(mem_ctx);
209
210         return MAPI_E_SUCCESS;
211 }
212
213 /**
214    \details Advise a server of the "other server" version
215
216    This function is used to set up a fast server-client-server transfer.
217
218    \param obj_store pointer to the store MAPI object
219    \param version the server version
220
221    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
222
223    \note Developers may also call GetLastError() to retrieve the last
224    MAPI error code. Possible MAPI error codes are:
225    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
226    - MAPI_E_INVALID_PARAMETER: one of the function parameter is
227      invalid
228    - MAPI_E_CALL_FAILED: A network problem was encountered during the
229    transaction
230  */
231 _PUBLIC_ enum MAPISTATUS TellVersion(mapi_object_t *obj_store, uint16_t version[3])
232 {
233         struct mapi_request             *mapi_request;
234         struct mapi_response            *mapi_response;
235         struct EcDoRpc_MAPI_REQ         *mapi_req;
236         struct TellVersion_req          request;
237         struct mapi_session             *session;
238         NTSTATUS                        status;
239         enum MAPISTATUS                 retval;
240         uint32_t                        size = 0;
241         TALLOC_CTX                      *mem_ctx;
242         uint8_t                         logon_id = 0;
243
244         /* Sanity checks */
245         OPENCHANGE_RETVAL_IF(!obj_store, MAPI_E_INVALID_PARAMETER, NULL);
246         OPENCHANGE_RETVAL_IF(!version, MAPI_E_INVALID_PARAMETER, NULL);
247
248         session = mapi_object_get_session(obj_store);
249         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
250
251         if ((retval = mapi_object_get_logon_id(obj_store, &logon_id)) != MAPI_E_SUCCESS)
252                 return retval;
253
254         mem_ctx = talloc_named(NULL, 0, "TellVersion");
255         size = 0;
256
257         /* Fill the operation */
258         request.version[0] = version[0];
259         request.version[1] = version[1];
260         request.version[2] = version[2];
261         size += 3 * sizeof (uint16_t);
262
263
264
265         /* Fill the MAPI_REQ structure */
266         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
267         mapi_req->opnum = op_MAPI_TellVersion;
268         mapi_req->logon_id = logon_id;
269         mapi_req->handle_idx = 0;
270         mapi_req->u.mapi_TellVersion = request;
271         size += 5;
272
273         /* Fill the mapi_request structure */
274         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
275         mapi_request->mapi_len = size + sizeof (uint32_t);
276         mapi_request->length = (uint16_t)size;
277         mapi_request->mapi_req = mapi_req;
278         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
279         mapi_request->handles[0] = mapi_object_get_handle(obj_store);
280
281         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
282         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
283         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
284         retval = mapi_response->mapi_repl->error_code;
285         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
286
287         talloc_free(mapi_response);
288         talloc_free(mem_ctx);
289
290         return MAPI_E_SUCCESS;
291 }
292
293 /**
294    \details Prepare a server for Fast Transfer transmission of a folder hierachy
295
296    This function is used to configure a server for a fast-transfer folder hierachy 
297    send operation. This could be the origin server in a server->client->server copy, or for a
298    server to client download.
299    
300    This operation copies the folder object, and any sub-objects (including folder properties
301    and messages). It can optionally copy sub-folders, depending on copyFlags.
302
303    \param obj the source object for the operation (folder)
304    \param copyFlags flags that change the copy behaviour (see below)
305    \param sendOptions flags that change the format of the transfer (see FXCopyMessages)
306    \param obj_source_context the fast transfer source context for future ROPs
307
308    \a copyflags can be zero or more of the following:
309    - FastTransferCopyFolder_CopySubfolders to recursively copy any sub-folders and contained messages
310    - FastTransferCopyFolder_NoGhostedContent to omit any ghosted content when copying public folders
311
312    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
313
314    \note Developers may also call GetLastError() to retrieve the last
315    MAPI error code. Possible MAPI error codes are:
316    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
317    - MAPI_E_INVALID_PARAMETER: one of the function parameters is
318      invalid
319    - MAPI_E_CALL_FAILED: A network problem was encountered during the
320    transaction
321  */
322 _PUBLIC_ enum MAPISTATUS FXCopyFolder(mapi_object_t *obj, uint8_t copyFlags, uint8_t sendOptions,
323                                       mapi_object_t *obj_source_context)
324 {
325         struct mapi_request                             *mapi_request;
326         struct mapi_response                            *mapi_response;
327         struct EcDoRpc_MAPI_REQ                         *mapi_req;
328         struct FastTransferSourceCopyFolder_req         request;
329         struct mapi_session                             *session;
330         NTSTATUS                                        status;
331         enum MAPISTATUS                                 retval;
332         uint32_t                                        size = 0;
333         TALLOC_CTX                                      *mem_ctx;
334         uint8_t                                         logon_id = 0;
335
336         /* Sanity checks */
337         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
338
339         session = mapi_object_get_session(obj);
340         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
341         OPENCHANGE_RETVAL_IF(!obj_source_context, MAPI_E_INVALID_PARAMETER, NULL);
342
343         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
344                 return retval;
345
346         mem_ctx = talloc_named(NULL, 0, "FXCopyFolder");
347         size = 0;
348
349         /* Fill the CopyFolder operation */
350         request.handle_idx = 0x01;
351         size += sizeof(uint8_t);
352         request.CopyFlags = copyFlags;
353         size += sizeof(uint8_t);
354         request.SendOptions = sendOptions;
355         size += sizeof(uint8_t);
356
357         /* Fill the MAPI_REQ structure */
358         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
359         mapi_req->opnum = op_MAPI_FastTransferSourceCopyFolder;
360         mapi_req->logon_id = logon_id;
361         mapi_req->handle_idx = 0;
362         mapi_req->u.mapi_FastTransferSourceCopyFolder = 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 = (uint16_t)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);
372         mapi_request->handles[1] = 0xffffffff;
373
374         status = emsmdb_transaction_wrapper(session, 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         /* Set object session and handle */
381         mapi_object_set_session(obj_source_context, session);
382         mapi_object_set_handle(obj_source_context, mapi_response->handles[1]);
383         mapi_object_set_logon_id(obj_source_context, logon_id);
384
385         talloc_free(mapi_response);
386         talloc_free(mem_ctx);
387
388         return MAPI_E_SUCCESS;
389 }
390
391 /**
392    \details Prepare a server for Fast Transfer transmission of a list of messages
393    
394    This function is used to configure a server for a fast-transfer message
395    send operation. This could be the origin server in a server->client->server copy, or for a
396    server to client download.
397    
398    This operation copies the message objects, and any sub-objects (including attachments and embedded
399    messages).
400
401    \param obj the source object for the operation (folder)
402    \param message_ids the message IDs for the messages to copy.
403    \param copyFlags flags that change the copy behaviour (see below)
404    \param sendOptions flags that change the format of the transfer (see below)
405    \param obj_source_context the fast transfer source context for future ROPs
406
407    \a copyflags can be zero or more of the following:
408    - FastTransferCopyMessage_Move - configure output for move
409    - FastTransferCopyMessage_BestBody - output message bodies in original format (if not set, output in RTF)
410    - FastTransferCopyMessage_SendEntryId - include message and change identification in the output stream
411
412    \a sendOptions can be zero or more of the following:
413    - FastTransfer_Unicode - enable Unicode output
414    - FastTransfer_UseCpid (not normally used directly - implied by ForUpload)
415    - FastTransfer_ForUpload - (enable Unicode, and advise the server that transfer is server->client->server)
416    - FastTransfer_RecoverMode - advise the server that the client supports recovery mode
417    - FastTransfer_ForceUnicode - force Unicode output
418    - FastTransfer_PartialItem - used for synchronisation download
419    
420    If the \a FastTransfer_ForUpload is set, the next call must be TellVersion()
421
422    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
423
424    \note Developers may also call GetLastError() to retrieve the last
425    MAPI error code. Possible MAPI error codes are:
426    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
427    - MAPI_E_INVALID_PARAMETER: one of the function parameters is
428      invalid
429    - MAPI_E_CALL_FAILED: A network problem was encountered during the
430    transaction
431  */
432 _PUBLIC_ enum MAPISTATUS FXCopyMessages(mapi_object_t *obj, mapi_id_array_t *message_ids,
433                                         uint8_t copyFlags, uint8_t sendOptions,
434                                         mapi_object_t *obj_source_context)
435 {
436         struct mapi_request                             *mapi_request;
437         struct mapi_response                            *mapi_response;
438         struct EcDoRpc_MAPI_REQ                         *mapi_req;
439         struct FastTransferSourceCopyMessages_req       request;
440         struct mapi_session                             *session;
441         NTSTATUS                                        status;
442         enum MAPISTATUS                                 retval;
443         uint32_t                                        size = 0;
444         TALLOC_CTX                                      *mem_ctx;
445         uint8_t                                         logon_id = 0;
446
447         /* Sanity checks */
448         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
449
450         session = mapi_object_get_session(obj);
451         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
452         OPENCHANGE_RETVAL_IF(!obj_source_context, MAPI_E_INVALID_PARAMETER, NULL);
453         OPENCHANGE_RETVAL_IF(!message_ids, MAPI_E_INVALID_PARAMETER, NULL);
454         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
455                 return retval;
456
457         mem_ctx = talloc_named(NULL, 0, "FXCopyMessages");
458         size = 0;
459
460         /* Fill the CopyMessages operation */
461         request.handle_idx = 0x01;
462         size += sizeof(uint8_t);
463         request.MessageIdCount = message_ids->count;
464         size += sizeof (uint16_t);
465         retval = mapi_id_array_get(mem_ctx, message_ids, &(request.MessageIds));
466         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
467         size += request.MessageIdCount * sizeof (mapi_id_t);
468         request.CopyFlags = copyFlags;
469         size += sizeof(uint8_t);
470         request.SendOptions = sendOptions;
471         size += sizeof(uint8_t);
472
473         /* Fill the MAPI_REQ structure */
474         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
475         mapi_req->opnum = op_MAPI_FastTransferSourceCopyMessages;
476         mapi_req->logon_id = logon_id;
477         mapi_req->handle_idx = 0;
478         mapi_req->u.mapi_FastTransferSourceCopyMessages = request;
479         size += 5;
480
481         /* Fill the mapi_request structure */
482         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
483         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
484         mapi_request->length = (uint16_t)size;
485         mapi_request->mapi_req = mapi_req;
486         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
487         mapi_request->handles[0] = mapi_object_get_handle(obj);
488         mapi_request->handles[1] = 0xffffffff;
489
490         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
491         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
492         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
493         retval = mapi_response->mapi_repl->error_code;
494         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
495
496         /* Set object session and handle */
497         mapi_object_set_session(obj_source_context, session);
498         mapi_object_set_handle(obj_source_context, mapi_response->handles[1]);
499         mapi_object_set_logon_id(obj_source_context, logon_id);
500
501         talloc_free(mapi_response);
502         talloc_free(mem_ctx);
503
504         return MAPI_E_SUCCESS;
505 }
506
507 /**
508    \details Prepare a server for Fast Transfer transmission of a folder, message or attachment
509
510    This function is used to configure a server for a fast-transfer download of a folder, message
511    or attachment. This could be the origin server in a server->client->server copy, or for a
512    server to client download.
513    
514    This operation copies the source object, potentially omitting some properties. It can optionally
515    copy sub-objects, depending on \a Level.
516
517    \param obj the source object for the operation (folder, message or attachment)
518    \param level whether to copy sub-objects of folders or messages (set to 0) or not (set to any other value)
519    \param copyFlags flags that change the copy behaviour (see below)
520    \param sendOptions flags that change the format of the transfer (see FXCopyMessages)
521    \param excludes the list of properties to exclude from the transfer
522    \param obj_source_context the fast transfer source context for future ROPs
523
524    \a copyflags can be zero or more of the following:
525    - FastTransferCopyTo_Move to configure as part of a move operation
526    - FastTransferCopyTo_BestBody to use original format for message bodies (if not set, use RTF instead)
527
528    Be careful in setting \a level to something other than zero. In particular, if \a level is
529    non-zero for a message, then the list of recipients, and any attachments or embedded messages, will
530    not be transferred.
531
532    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
533
534    \note Developers may also call GetLastError() to retrieve the last
535    MAPI error code. Possible MAPI error codes are:
536    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
537    - MAPI_E_INVALID_PARAMETER: one of the function parameters is
538      invalid
539    - MAPI_E_CALL_FAILED: A network problem was encountered during the
540    transaction
541  */
542 _PUBLIC_ enum MAPISTATUS FXCopyTo(mapi_object_t *obj, uint8_t level, uint32_t copyFlags,
543                                   uint8_t sendOptions, struct SPropTagArray *excludes,
544                                   mapi_object_t *obj_source_context)
545 {
546         struct mapi_request                             *mapi_request;
547         struct mapi_response                            *mapi_response;
548         struct EcDoRpc_MAPI_REQ                         *mapi_req;
549         struct FastTransferSourceCopyTo_req             request;
550         struct mapi_session                             *session;
551         NTSTATUS                                        status;
552         enum MAPISTATUS                                 retval;
553         uint32_t                                        size = 0;
554         TALLOC_CTX                                      *mem_ctx;
555         uint8_t                                         logon_id = 0;
556
557         /* Sanity checks */
558         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
559
560         session = mapi_object_get_session(obj);
561         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
562         OPENCHANGE_RETVAL_IF(!obj_source_context, MAPI_E_INVALID_PARAMETER, NULL);
563         OPENCHANGE_RETVAL_IF(!excludes, MAPI_E_INVALID_PARAMETER, NULL);
564
565         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
566                 return retval;
567
568         mem_ctx = talloc_named(NULL, 0, "FXCopyTo");
569         size = 0;
570
571         /* Fill the CopyTo operation */
572         request.handle_idx = 0x01;
573         size += sizeof(uint8_t);
574         request.Level = level;
575         size += sizeof(uint8_t);
576         request.CopyFlags = copyFlags;
577         size += sizeof(uint32_t);
578         request.SendOptions = sendOptions;
579         size += sizeof(uint8_t);
580         request.PropertyTags.cValues = excludes->cValues;
581         size += sizeof(uint16_t);
582         request.PropertyTags.aulPropTag = excludes->aulPropTag;
583         size += excludes->cValues * sizeof(enum MAPITAGS);
584
585         /* Fill the MAPI_REQ structure */
586         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
587         mapi_req->opnum = op_MAPI_FastTransferSourceCopyTo;
588         mapi_req->logon_id = logon_id;
589         mapi_req->handle_idx = 0;
590         mapi_req->u.mapi_FastTransferSourceCopyTo = request;
591         size += 5;
592
593         /* Fill the mapi_request structure */
594         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
595         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
596         mapi_request->length = (uint16_t)size;
597         mapi_request->mapi_req = mapi_req;
598         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
599         mapi_request->handles[0] = mapi_object_get_handle(obj);
600         mapi_request->handles[1] = 0xffffffff;
601
602         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
603         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
604         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
605         retval = mapi_response->mapi_repl->error_code;
606         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
607
608         /* Set object session and handle */
609         mapi_object_set_session(obj_source_context, session);
610         mapi_object_set_handle(obj_source_context, mapi_response->handles[1]);
611         mapi_object_set_logon_id(obj_source_context, logon_id);
612
613         talloc_free(mapi_response);
614         talloc_free(mem_ctx);
615
616         return MAPI_E_SUCCESS;
617 }
618
619 /**
620    \details Prepare a server for Fast Transfer transmission of the properties of a folder, message or attachment
621
622    This function is used to configure a server for a fast-transfer download of properties. This could be the
623    origin server in a server->client->server copy, or for a server to client download.
624    
625    This operation copies the specified properties of the source object. It can optionally copy properties of
626    sub-objects, depending on \a Level.
627
628    \param obj the source object for the operation (folder, message or attachment)
629    \param level whether to copy properties of sub-objects of folders or messages (set to 0) or not (set to any other value)
630    \param copyFlags flags that change the copy behaviour (see below)
631    \param sendOptions flags that change the format of the transfer (see FXCopyMessages)
632    \param properties the list of properties to transfer
633    \param obj_source_context the fast transfer source context for future ROPs
634
635    \a copyflags may be the following:
636    - FastTransferCopyProperties_Move to configure as part of a move operation
637
638    Be careful in setting \a level to something other than zero. In particular, if \a level is
639    non-zero for a message, then the list of recipients, and any attachments or embedded messages, will
640    not be transferred.
641
642    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
643
644    \note Developers may also call GetLastError() to retrieve the last
645    MAPI error code. Possible MAPI error codes are:
646    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
647    - MAPI_E_INVALID_PARAMETER: one of the function parameters is
648      invalid
649    - MAPI_E_CALL_FAILED: A network problem was encountered during the
650    transaction
651  */
652 _PUBLIC_ enum MAPISTATUS FXCopyProperties(mapi_object_t *obj, uint8_t level, uint32_t copyFlags,
653                                           uint8_t sendOptions, struct SPropTagArray *properties,
654                                           mapi_object_t *obj_source_context)
655 {
656         struct mapi_request                             *mapi_request;
657         struct mapi_response                            *mapi_response;
658         struct EcDoRpc_MAPI_REQ                         *mapi_req;
659         struct FastTransferSourceCopyProperties_req     request;
660         struct mapi_session                             *session;
661         NTSTATUS                                        status;
662         enum MAPISTATUS                                 retval;
663         uint32_t                                        size = 0;
664         TALLOC_CTX                                      *mem_ctx;
665         uint8_t                                         logon_id = 0;
666
667         /* Sanity checks */
668         OPENCHANGE_RETVAL_IF(!obj, MAPI_E_INVALID_PARAMETER, NULL);
669
670         session = mapi_object_get_session(obj);
671         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
672         OPENCHANGE_RETVAL_IF(!obj_source_context, MAPI_E_INVALID_PARAMETER, NULL);
673         OPENCHANGE_RETVAL_IF(!properties, MAPI_E_INVALID_PARAMETER, NULL);
674
675         if ((retval = mapi_object_get_logon_id(obj, &logon_id)) != MAPI_E_SUCCESS)
676                 return retval;
677
678         mem_ctx = talloc_named(NULL, 0, "FXCopyProperties");
679         size = 0;
680
681         /* Fill the CopyProperties operation */
682         request.handle_idx = 0x01;
683         size += sizeof(uint8_t);
684         request.Level = level;
685         size += sizeof(uint8_t);
686         request.CopyFlags = copyFlags;
687         size += sizeof(uint8_t);
688         request.SendOptions = sendOptions;
689         size += sizeof(uint8_t);
690         request.PropertyTags.cValues = properties->cValues;
691         size += sizeof(uint16_t);
692         request.PropertyTags.aulPropTag = properties->aulPropTag;
693         size += properties->cValues * sizeof(enum MAPITAGS);
694
695         /* Fill the MAPI_REQ structure */
696         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
697         mapi_req->opnum = op_MAPI_FastTransferSourceCopyProps;
698         mapi_req->logon_id = logon_id;
699         mapi_req->handle_idx = 0;
700         mapi_req->u.mapi_FastTransferSourceCopyProperties = request;
701         size += 5;
702
703         /* Fill the mapi_request structure */
704         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
705         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
706         mapi_request->length = (uint16_t)size;
707         mapi_request->mapi_req = mapi_req;
708         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
709         mapi_request->handles[0] = mapi_object_get_handle(obj);
710         mapi_request->handles[1] = 0xffffffff;
711
712         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
713         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
714         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
715         retval = mapi_response->mapi_repl->error_code;
716         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
717
718         /* Set object session and handle */
719         mapi_object_set_session(obj_source_context, session);
720         mapi_object_set_handle(obj_source_context, mapi_response->handles[1]);
721         mapi_object_set_logon_id(obj_source_context, logon_id);
722
723         talloc_free(mapi_response);
724         talloc_free(mem_ctx);
725
726         return MAPI_E_SUCCESS;
727 }
728
729 /**
730     Get data from source fast transfer object
731
732     Fast transfers are done in blocks, each block transfered over a call to FXGetBuffer. If the block
733     is small, it will fit into a single call, and the transferStatus will indicate completion. However
734     larger transfers will require multiple calls.
735
736     \param obj_source_context the source object (from FXCopyTo, FXCopyProperties, FXCopyFolder or FXCopyMessages)
737     \param maxSize the maximum size (pass 0 to indicate maximum available size)
738     \param transferStatus result of the transfer
739     \param progressStepCount the approximate number of steps (of totalStepCount) completed
740     \param totalStepCount the approximate number of steps (total)
741     \param blob this part of the transfer
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_INVALID_PARAMETER: one of the function parameters is
749      invalid
750    - MAPI_E_CALL_FAILED: A network problem was encountered during the
751    transaction
752 */
753 _PUBLIC_ enum MAPISTATUS FXGetBuffer(mapi_object_t *obj_source_context, uint16_t maxSize, enum TransferStatus *transferStatus,
754                                      uint16_t *progressStepCount, uint16_t *totalStepCount, DATA_BLOB *blob)
755 {
756         struct mapi_request                             *mapi_request;
757         struct mapi_response                            *mapi_response;
758         struct EcDoRpc_MAPI_REQ                         *mapi_req;
759         struct FastTransferSourceGetBuffer_req          request;
760         struct FastTransferSourceGetBuffer_repl         *reply;
761         struct mapi_session                             *session;
762         NTSTATUS                                        status;
763         enum MAPISTATUS                                 retval;
764         uint32_t                                        size = 0;
765         TALLOC_CTX                                      *mem_ctx;
766         uint8_t                                         logon_id = 0;
767
768         /* Sanity checks */
769         OPENCHANGE_RETVAL_IF(!obj_source_context, MAPI_E_INVALID_PARAMETER, NULL);
770
771         session = mapi_object_get_session(obj_source_context);
772         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
773
774         if ((retval = mapi_object_get_logon_id(obj_source_context, &logon_id)) != MAPI_E_SUCCESS)
775                 return retval;
776
777         mem_ctx = talloc_named(NULL, 0, "FXGetBuffer");
778         size = 0;
779
780         /* Fill the GetBuffer operation */
781         if ((maxSize == 0) || (maxSize < 15480)) {
782                 request.BufferSize = 0xBABE;
783                 size += sizeof(uint16_t);
784                 request.MaximumBufferSize.MaximumBufferSize = 0x8000;
785                 size += sizeof(uint16_t);
786         } else {
787                 request.BufferSize = maxSize;
788                 size += sizeof(uint16_t);
789         }
790
791         /* Fill the MAPI_REQ structure */
792         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
793         mapi_req->opnum = op_MAPI_FastTransferSourceGetBuffer;
794         mapi_req->logon_id = logon_id;
795         mapi_req->handle_idx = 0;
796         mapi_req->u.mapi_FastTransferSourceGetBuffer = request;
797         size += 5;
798
799         /* Fill the mapi_request structure */
800         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
801         mapi_request->mapi_len = size + sizeof (uint32_t);
802         mapi_request->length = (uint16_t)size;
803         mapi_request->mapi_req = mapi_req;
804         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
805         mapi_request->handles[0] = mapi_object_get_handle(obj_source_context);
806
807         // TODO: handle backoff (0x00000480)
808         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
809         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
810         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
811         retval = mapi_response->mapi_repl->error_code;
812         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
813
814         /* Retrieve the result */
815         reply = &(mapi_response->mapi_repl->u.mapi_FastTransferSourceGetBuffer);
816         *transferStatus = reply->TransferStatus;
817         *progressStepCount = reply->InProgressCount;
818         *totalStepCount = reply->TotalStepCount;
819         blob->length = reply->TransferBufferSize;
820         blob->data = talloc_size((TALLOC_CTX *)session, blob->length);
821         memcpy(blob->data, reply->TransferBuffer.data, blob->length);
822
823         talloc_free(mapi_response);
824         talloc_free(mem_ctx);
825
826         return MAPI_E_SUCCESS;
827 }
828
829 /**
830     Send data to a destination fast transfer object
831
832     Fast transfers are done in blocks, each block transfered over a call to FXGetBuffer. If the block
833     is small, it will fit into a single call, and the transferStatus will indicate completion. However
834     larger transfers will require multiple calls.
835
836     \param obj_dest_context the destination object (from FXDestConfigure)
837     \param blob this part of the transfer
838     \param usedSize how many bytes of this part of the transfer that were used (only less than the total if an error occurred)
839     
840     \return MAPI_E_SUCCESS on success, otherwise MAPI error.
841
842     \note Developers may also call GetLastError() to retrieve the last
843     MAPI error code. Possible MAPI error codes are:
844     - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
845     - MAPI_E_INVALID_PARAMETER: one of the function parameters is
846       invalid
847     - MAPI_E_CALL_FAILED: A network problem was encountered during the
848       transaction
849 */
850 _PUBLIC_ enum MAPISTATUS FXPutBuffer(mapi_object_t *obj_dest_context, DATA_BLOB *blob, uint16_t *usedSize)
851 {
852         struct mapi_request                             *mapi_request;
853         struct mapi_response                            *mapi_response;
854         struct EcDoRpc_MAPI_REQ                         *mapi_req;
855         struct FastTransferDestinationPutBuffer_req     request;
856         struct FastTransferDestinationPutBuffer_repl    *reply;
857         struct mapi_session                             *session;
858         NTSTATUS                                        status;
859         enum MAPISTATUS                                 retval;
860         uint32_t                                        size = 0;
861         TALLOC_CTX                                      *mem_ctx;
862         uint8_t                                         logon_id = 0;
863
864         /* Sanity checks */
865         OPENCHANGE_RETVAL_IF(!obj_dest_context, MAPI_E_INVALID_PARAMETER, NULL);
866         OPENCHANGE_RETVAL_IF(!blob, MAPI_E_INVALID_PARAMETER, NULL);
867         OPENCHANGE_RETVAL_IF(!usedSize, MAPI_E_INVALID_PARAMETER, NULL);
868
869         session = mapi_object_get_session(obj_dest_context);
870         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
871
872         if ((retval = mapi_object_get_logon_id(obj_dest_context, &logon_id)) != MAPI_E_SUCCESS)
873                 return retval;
874
875         mem_ctx = talloc_named(NULL, 0, "FXPutBuffer");
876         size = 0;
877
878         /* Fill the PutBuffer operation */
879         request.TransferBufferSize = blob->length;
880         size += sizeof(uint16_t);
881         request.TransferBuffer = *blob;
882         size += blob->length;
883
884         /* Fill the MAPI_REQ structure */
885         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
886         mapi_req->opnum = op_MAPI_FastTransferDestPutBuffer;
887         mapi_req->logon_id = logon_id;
888         mapi_req->handle_idx = 0;
889         mapi_req->u.mapi_FastTransferDestinationPutBuffer = request;
890         size += 5;
891
892         /* Fill the mapi_request structure */
893         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
894         mapi_request->mapi_len = size + sizeof (uint32_t);
895         mapi_request->length = (uint16_t)size;
896         mapi_request->mapi_req = mapi_req;
897         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
898         mapi_request->handles[0] = mapi_object_get_handle(obj_dest_context);
899
900         // TODO: handle backoff (0x00000480)
901         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
902         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
903         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
904         retval = mapi_response->mapi_repl->error_code;
905         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
906
907         /* Retrieve the result */
908         reply = &(mapi_response->mapi_repl->u.mapi_FastTransferDestinationPutBuffer);
909         *usedSize = reply->BufferUsedCount;
910         /* we could pull more stuff here, but it doesn't seem useful */
911
912         talloc_free(mapi_response);
913         talloc_free(mem_ctx);
914
915         return MAPI_E_SUCCESS;
916 }