Fix issue #376, patch from Milan Crha:
[jelmer/openchange-proposed.git/.git] / libmapi / IStream.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 IStream.c
26
27    \brief Functions for operating on Streams on MAPI objects
28  */
29
30
31 /**
32    \details Open a stream
33
34    This function opens a stream on the property \a prop set in \a
35    obj_related with access flags set to \a access_flags and returns an
36    object \a obj_stream.
37
38    \param obj_related the object to open.
39    \param PropertyTag the property name for the object to create a stream
40    for.
41    \param OpenModeFlags sets the access mode for the stream and is one
42    of the following values:
43    * 0x0: ReadOnly
44    * 0x1: ReadWrite
45    * 0x2: Create
46    * 0x3: BestAccess
47    \param obj_stream the resulting stream object.
48
49    \return MAPI_E_SUCCESS on success, otherwise MAPI error. Possible MAPI
50    error codes are:
51    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
52    - MAPI_E_INVALID_PARAMETER: A problem occurred obtaining the session context
53    - MAPI_E_CALL_FAILED: A network problem was encountered during the
54      transaction
55
56
57    \note Developers may also call GetLastError() to retrieve the last
58    MAPI error code. 
59
60    \sa ReadStream, WriteStream, GetLastError
61  */
62
63 _PUBLIC_ enum MAPISTATUS OpenStream(mapi_object_t *obj_related, enum MAPITAGS PropertyTag,
64                                     enum OpenStream_OpenModeFlags OpenModeFlags,
65                                     mapi_object_t *obj_stream)
66 {
67         struct mapi_request     *mapi_request;
68         struct mapi_response    *mapi_response;
69         struct EcDoRpc_MAPI_REQ *mapi_req;
70         struct OpenStream_req   request;
71         struct mapi_session     *session;
72         NTSTATUS                status;
73         enum MAPISTATUS         retval;
74         uint32_t                size = 0;
75         TALLOC_CTX              *mem_ctx;
76         uint8_t                 logon_id;
77
78         /* Sanity checks */
79         session = mapi_object_get_session(obj_related);
80         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
81
82         if ((retval = mapi_object_get_logon_id(obj_related, &logon_id)) != MAPI_E_SUCCESS)
83                 return retval;
84
85         mem_ctx = talloc_named(session, 0, "OpenStream");
86
87         size = 0;
88
89         /* Fill the OpenStream operation */
90         request.handle_idx = 0x1;
91         request.PropertyTag = PropertyTag;
92
93         /* STGM_XXX (obj_base.h windows header) */
94         request.OpenModeFlags = OpenModeFlags;
95         size += sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t);
96
97         /* Fill the MAPI_REQ request */
98         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
99         mapi_req->opnum = op_MAPI_OpenStream;
100         mapi_req->logon_id = logon_id;
101         mapi_req->handle_idx = 0;
102         mapi_req->u.mapi_OpenStream = request;
103         size += 5;
104
105         /* Fill the mapi_request structure */
106         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
107         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
108         mapi_request->length = size;
109         mapi_request->mapi_req = mapi_req;
110         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
111         mapi_request->handles[0] = mapi_object_get_handle(obj_related);
112         mapi_request->handles[1] = 0xffffffff;
113
114         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
115         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
116         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
117         retval = mapi_response->mapi_repl->error_code;
118         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
119
120         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
121
122         /* Set object session and handle */
123         mapi_object_set_session(obj_stream, session);
124         mapi_object_set_handle(obj_stream, mapi_response->handles[1]);
125         mapi_object_set_logon_id(obj_stream, logon_id);
126
127         talloc_free(mapi_response);
128         talloc_free(mem_ctx);
129
130         return MAPI_E_SUCCESS;
131 }
132
133
134 /**
135    \details Read buffer from a stream
136
137    This function reads from an open data stream. It will read up to
138    ByteCount bytes from the stream, and return the data in data_buf.
139    ByteRead is set to the number of bytes actually read.
140
141    \param obj_stream the opened stream object
142    \param buf_data the buffer where data read from the stream will be
143    stored
144    \param ByteCount the number of bytes requested to be read from the
145    stream
146    \param ByteRead the number of bytes read from the stream
147
148    \return MAPI_E_SUCCESS on success, otherwise MAPI error. Possible MAPI
149    error codes are:
150    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
151    - MAPI_E_INVALID_PARAMETER: A problem occurred obtaining the session context
152    - MAPI_E_CALL_FAILED: A network problem was encountered during the
153      transaction
154
155    \note Developers may also call GetLastError() to retrieve the last
156    MAPI error code. 
157
158    \note The data size intended to be read from the stream shouldn't
159    extend a maximum size each time you call ReadStream. This size
160    depends on Exchange server version. However 0x1000 is known to be a
161    reliable read size value.
162
163    \sa OpenStream, WriteStream, GetLastError
164 */
165 _PUBLIC_ enum MAPISTATUS ReadStream(mapi_object_t *obj_stream, unsigned char *buf_data, 
166                                     uint16_t ByteCount, uint16_t *ByteRead)
167 {
168         struct mapi_request     *mapi_request;
169         struct mapi_response    *mapi_response;
170         struct EcDoRpc_MAPI_REQ *mapi_req;
171         struct ReadStream_req   request;
172         struct mapi_session     *session;
173         NTSTATUS                status;
174         enum MAPISTATUS         retval;
175         uint32_t                size = 0;
176         TALLOC_CTX              *mem_ctx;
177         uint8_t                 logon_id = 0;
178
179         /* Sanity checks */
180         session = mapi_object_get_session(obj_stream);
181         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
182
183         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
184                 return retval;
185
186         mem_ctx = talloc_named(session, 0, "ReadStream");
187
188         *ByteRead = 0;
189         size = 0;
190
191         /* Fill the ReadStream operation */
192         request.ByteCount = ByteCount;
193         size += sizeof(uint16_t);
194
195         /* Fill the MAPI_REQ request */
196         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
197         mapi_req->opnum = op_MAPI_ReadStream;
198         mapi_req->logon_id = logon_id;
199         mapi_req->handle_idx = 0;
200         mapi_req->u.mapi_ReadStream = request;
201         size += 5;
202
203         /* Fill the mapi_request structure */
204         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
205         mapi_request->mapi_len = size + sizeof (uint32_t) * 1;
206         mapi_request->length = size;
207         mapi_request->mapi_req = mapi_req;
208         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
209         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
210
211         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
212         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
213         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
214         retval = mapi_response->mapi_repl->error_code;
215         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
216
217         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
218
219         /* copy no more than sz_data into buffer */
220         *ByteRead = mapi_response->mapi_repl->u.mapi_ReadStream.data.length;
221         if (*ByteRead > 0) {
222                 if (*ByteRead > ByteCount) {
223                         *ByteRead = ByteCount;
224                 }
225                 memcpy(buf_data, mapi_response->mapi_repl->u.mapi_ReadStream.data.data, *ByteRead);
226         }
227
228         talloc_free(mapi_response);
229         talloc_free(mem_ctx);
230
231         return MAPI_E_SUCCESS;
232 }
233
234
235 /**
236    \details Write buffer to the stream
237
238    This function writes the stream specified as a DATA_BLOB in data to
239    the stream obj_stream.
240
241    \param obj_stream the opened stream object
242    \param blob the DATA_BLOB to write to the stream
243    \param WrittenSize the actual number of bytes written to the
244    stream
245
246    \return MAPI_E_SUCCESS on success, otherwise MAPI error. 
247
248    \note Developers may also call GetLastError() to retrieve the last
249    MAPI error code. Possible MAPI error codes are:
250    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
251    - MAPI_E_INVALID_PARAMETER: A problem occurred obtaining the session
252      context, or blob was null.
253    - MAPI_E_CALL_FAILED: A network problem was encountered during the
254      transaction
255    - MAPI_E_TOO_BIG: the data blob was too large to process
256
257    \note The data size intended to be written to the stream should not
258    exceed a maximum size each time you call WriteStream. This size
259    depends on Exchange server version. However 0x1000 is known to be a
260    reliable write size value.
261
262    \sa OpenStream, ReadStream, GetLastError
263   */
264 _PUBLIC_ enum MAPISTATUS WriteStream(mapi_object_t *obj_stream, DATA_BLOB *blob, uint16_t *WrittenSize)
265 {
266         struct mapi_request     *mapi_request;
267         struct mapi_response    *mapi_response;
268         struct EcDoRpc_MAPI_REQ *mapi_req;
269         struct WriteStream_req  request;
270         struct mapi_session     *session;
271         NTSTATUS                status;
272         enum MAPISTATUS         retval;
273         TALLOC_CTX              *mem_ctx;
274         uint32_t                size;
275         uint8_t                 logon_id = 0;
276
277         /* Sanity Checks */
278         session = mapi_object_get_session(obj_stream);
279         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
280         OPENCHANGE_RETVAL_IF(!blob, MAPI_E_INVALID_PARAMETER, NULL);
281         OPENCHANGE_RETVAL_IF(blob->length > 0x7000, MAPI_E_TOO_BIG, NULL);
282
283         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
284                 return retval;
285
286         mem_ctx = talloc_named(session, 0, "WriteStream");
287
288         size = 0;
289
290         /* Fill the WriteStream operation */
291         request.data = *blob;
292         size +=  blob->length;
293         /* size for subcontext(2) */
294         size += 2;
295
296         /* Fill the MAPI_REQ request */
297         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
298         mapi_req->opnum = op_MAPI_WriteStream;
299         mapi_req->logon_id = logon_id;
300         mapi_req->handle_idx = 0;
301         mapi_req->u.mapi_WriteStream = request;
302         size += 5;
303
304         /* Fill the mapi_request structure */
305         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
306         mapi_request->mapi_len = size + sizeof (uint32_t);
307         mapi_request->length = size;
308         mapi_request->mapi_req = mapi_req;
309         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
310         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
311
312         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
313         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
314         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
315         retval = mapi_response->mapi_repl->error_code;
316         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
317
318         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
319
320         *WrittenSize = mapi_response->mapi_repl->u.mapi_WriteStream.WrittenSize;
321
322         talloc_free(mapi_response);
323         talloc_free(mem_ctx);
324         
325         errno = 0;
326         return MAPI_E_SUCCESS;
327 }
328
329
330 /**
331    \details Commits stream operations
332
333    \param obj_stream the stream object to commit
334
335    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
336
337    \note Developers may also call GetLastError() to retrieve the last
338    MAPI error code. Possible MAPI error codes are:
339    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
340    - MAPI_E_INVALID_PARAMETER: Either the network stream or session
341    context are not valid.
342    - MAPI_E_CALL_FAILED: A network problem was encountered during the
343    transaction
344    
345    \sa OpenStream, ReadStream, WriteStream
346  */
347 _PUBLIC_ enum MAPISTATUS CommitStream(mapi_object_t *obj_stream)
348 {
349         struct mapi_request     *mapi_request;
350         struct mapi_response    *mapi_response;
351         struct EcDoRpc_MAPI_REQ *mapi_req;
352         struct mapi_session     *session;
353         NTSTATUS                status;
354         enum MAPISTATUS         retval;
355         uint32_t                size;
356         TALLOC_CTX              *mem_ctx;
357         uint8_t                 logon_id = 0;
358
359         /* Sanity checks */
360         session = mapi_object_get_session(obj_stream);
361         OPENCHANGE_RETVAL_IF(!obj_stream, MAPI_E_INVALID_PARAMETER, NULL);
362         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
363
364         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
365                 return retval;
366
367         mem_ctx = talloc_named(session, 0, "CommitStream");
368         size = 0;
369
370         /* Fill the MAPI_REQ request */
371         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
372         mapi_req->opnum = op_MAPI_CommitStream;
373         mapi_req->logon_id = logon_id;
374         mapi_req->handle_idx = 0;
375         size += 5;
376
377         /* Fill the mapi_request structure */
378         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
379         mapi_request->mapi_len = size + sizeof (uint32_t);
380         mapi_request->length = size;
381         mapi_request->mapi_req = mapi_req;
382         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
383         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
384
385         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
386         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
387         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
388         retval = mapi_response->mapi_repl->error_code;
389         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
390
391         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
392
393         talloc_free(mapi_response);
394         talloc_free(mem_ctx);
395
396         return MAPI_E_SUCCESS;
397 }
398
399
400 /**
401    \details Gets the size of a stream
402
403    \param obj_stream the stream object we retrieve size from
404    \param StreamSize pointer on the stream size
405
406    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
407
408    \note Developers may also call GetLastError() to retrieve the last
409    MAPI error code. Possible MAPI error codes are:
410    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
411    - MAPI_E_INVALID_PARAMETER: obj_stream is not initialized, or there
412      was a problem obtaining the session context
413    - MAPI_E_CALL_FAILED: A network problem was encountered during the
414    transaction
415    
416    \sa OpenStream, ReadStream
417  */
418 _PUBLIC_ enum MAPISTATUS GetStreamSize(mapi_object_t *obj_stream, uint32_t *StreamSize)
419 {
420         struct mapi_request             *mapi_request;
421         struct mapi_response            *mapi_response;
422         struct EcDoRpc_MAPI_REQ         *mapi_req;
423         struct mapi_session             *session;
424         NTSTATUS                        status;
425         enum MAPISTATUS                 retval;
426         uint32_t                        size;
427         TALLOC_CTX                      *mem_ctx;
428         uint8_t                         logon_id = 0;
429
430         /* Sanity checks */
431         OPENCHANGE_RETVAL_IF(!obj_stream, MAPI_E_INVALID_PARAMETER, NULL);
432         session = mapi_object_get_session(obj_stream);
433         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
434
435         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
436                 return retval;
437
438         mem_ctx = talloc_named(session, 0, "GetStreamSize");
439         size = 0;
440
441         /* Fill the MAPI_REQ request */
442         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
443         mapi_req->opnum = op_MAPI_GetStreamSize;
444         mapi_req->logon_id = logon_id;
445         mapi_req->handle_idx = 0;
446         size += 5;
447
448         /* Fill the mapi_request structure */
449         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
450         mapi_request->mapi_len = size + sizeof (uint32_t);
451         mapi_request->length = size;
452         mapi_request->mapi_req = mapi_req;
453         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
454         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
455
456         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
457         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
458         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
459         retval = mapi_response->mapi_repl->error_code;
460         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
461
462         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
463
464         *StreamSize = mapi_response->mapi_repl->u.mapi_GetStreamSize.StreamSize;
465
466         talloc_free(mapi_response);
467         talloc_free(mem_ctx);
468
469         return MAPI_E_SUCCESS;
470 }
471
472
473 /**
474    \details Seek a specific position within the stream
475
476    \param obj_stream the stream object
477    \param Origin origin location for the seek operation
478    \param Offset the seek offset
479    \param NewPosition pointer on the new position after the operation
480
481    Origin can either take one of the following values:
482
483    * 0x0 The new seek pointer is an offset relative to the beginning
484    of the stream.
485    * 0x1 The new seek pointer is an offset relative to the current
486    seek pointer location.
487    * 0x2 The new seek pointer is an offset relative to the end of the
488    stream.
489
490    \return MAPI_E_SUCCESS on success, otherwise MAPI error
491
492    \note Developers may also call GetLastError() to retrieve the last
493    MAPI error code. Possible MAPI error codes are:
494    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
495    - MAPI_E_INVALID_PARAMETER: obj_stream is not valid, Origin is out
496    of limits, or NewPosition is null.
497    - MAPI_E_CALL_FAILED: A network problem was encountered during the
498    transaction
499    
500    \sa OpenStream, ReadStream 
501  */
502 _PUBLIC_ enum MAPISTATUS SeekStream(mapi_object_t *obj_stream, uint8_t Origin, uint64_t Offset, 
503                                     uint64_t *NewPosition)
504 {
505         struct mapi_request     *mapi_request;
506         struct mapi_response    *mapi_response;
507         struct EcDoRpc_MAPI_REQ *mapi_req;
508         struct SeekStream_req   request;
509         struct mapi_session     *session;
510         NTSTATUS                status;
511         enum MAPISTATUS         retval;
512         TALLOC_CTX              *mem_ctx;
513         uint32_t                size;
514         uint8_t                 logon_id = 0;
515
516         /* Sanity checks */
517         OPENCHANGE_RETVAL_IF(!obj_stream, MAPI_E_INVALID_PARAMETER, NULL);
518         session = mapi_object_get_session(obj_stream);
519         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
520         OPENCHANGE_RETVAL_IF((Origin > 2), MAPI_E_INVALID_PARAMETER, NULL);
521         OPENCHANGE_RETVAL_IF(!NewPosition, MAPI_E_INVALID_PARAMETER, NULL);
522
523         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
524                 return retval;
525
526         mem_ctx = talloc_named(session, 0, "SeekStream");
527         size = 0;
528
529         /* Fill the SeekStream operation */
530         request.Origin = Origin;
531         size += sizeof (uint8_t);
532
533         request.Offset = Offset;
534         size += sizeof (uint64_t);
535
536         /* Fill the MAPI_REQ request */
537         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
538         mapi_req->opnum = op_MAPI_SeekStream;
539         mapi_req->logon_id = logon_id;
540         mapi_req->handle_idx = 0;
541         mapi_req->u.mapi_SeekStream = request;
542         size += 5;
543
544         /* Fill the mapi_request structure */
545         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
546         mapi_request->mapi_len = size + sizeof (uint32_t);
547         mapi_request->length = size;
548         mapi_request->mapi_req = mapi_req;
549         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
550         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
551
552         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
553         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
554         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
555         retval = mapi_response->mapi_repl->error_code;
556         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
557
558         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
559
560         *NewPosition = mapi_response->mapi_repl->u.mapi_SeekStream.NewPosition;
561
562         talloc_free(mapi_response);
563         talloc_free(mem_ctx);
564
565         return MAPI_E_SUCCESS;
566 }
567
568
569 /**
570    \details Set the stream size
571
572    \param obj_stream the stream object
573    \param SizeStream the size of the stream
574
575    \return MAPI_E_SUCCESS on success, otherwise MAPI error
576
577    \note Developers may also call GetLastError() to retrieve the last
578    MAPI error code. Possible MAPI error codes are:
579    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
580    - MAPI_E_INVALID_PARAMETER: obj_stream is not valid
581    - MAPI_E_CALL_FAILED: A network problem was encountered during the
582    transaction
583    
584    \sa OpenStream, GetStreamSize
585  */
586 _PUBLIC_ enum MAPISTATUS SetStreamSize(mapi_object_t *obj_stream, uint64_t SizeStream)
587 {
588         struct mapi_request             *mapi_request;
589         struct mapi_response            *mapi_response;
590         struct EcDoRpc_MAPI_REQ         *mapi_req;
591         struct SetStreamSize_req        request;
592         struct mapi_session             *session;
593         NTSTATUS                        status;
594         enum MAPISTATUS                 retval;
595         TALLOC_CTX                      *mem_ctx;
596         uint32_t                        size;
597         uint8_t                         logon_id = 0;
598
599         /* Sanity checks */
600         OPENCHANGE_RETVAL_IF(!obj_stream, MAPI_E_INVALID_PARAMETER, NULL);
601         session = mapi_object_get_session(obj_stream);
602         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
603
604         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
605                 return retval;
606
607         mem_ctx = talloc_named(session, 0, "SetStreamSize");
608         size = 0;
609
610         /* Fill the SetStreamSize operation */
611         request.SizeStream = SizeStream;
612         size += sizeof (uint64_t);
613
614         /* Fill the MAPI_REQ request */
615         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
616         mapi_req->opnum = op_MAPI_SetStreamSize;
617         mapi_req->logon_id = logon_id;
618         mapi_req->handle_idx = 0;
619         mapi_req->u.mapi_SetStreamSize = request;
620         size += 5;
621
622         /* Fill the mapi_request structure */
623         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
624         mapi_request->mapi_len = size + sizeof (uint32_t);
625         mapi_request->length = size;
626         mapi_request->mapi_req = mapi_req;
627         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
628         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
629
630         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
631         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
632         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
633         retval = mapi_response->mapi_repl->error_code;
634         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
635
636         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
637
638         talloc_free(mapi_response);
639         talloc_free(mem_ctx);
640
641         return MAPI_E_SUCCESS;
642 }
643
644
645 /**
646    \details Copy a number of bytes from a source stream to another
647    stream
648
649    \param obj_src the source stream object
650    \param obj_dst the destination stream object
651    \param ByteCount the number of bytes to copy
652    \param ReadByteCount pointer on the number of bytes read from the
653    source object
654    \param WrittenByteCount pointer on the number of bytes written to
655    the destination object
656  
657    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
658
659    \note Developers may also call GetLastError() to retrieve the last
660    MAPI error code. Possible MAPI error codes are:
661    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
662    - MAPI_E_INVALID_BOOKMARK: the bookmark specified is invalid or
663      beyond the last row requested.
664    - MAPI_E_CALL_FAILED: A network problem was encountered during the
665    transaction
666    
667    \sa OpenStream
668 */
669 _PUBLIC_ enum MAPISTATUS CopyToStream(mapi_object_t *obj_src, mapi_object_t *obj_dst,
670                                       uint64_t ByteCount, uint64_t *ReadByteCount,
671                                       uint64_t *WrittenByteCount)
672 {
673         struct mapi_request     *mapi_request;
674         struct mapi_response    *mapi_response;
675         struct EcDoRpc_MAPI_REQ *mapi_req;
676         struct CopyToStream_req request;
677         struct mapi_session     *session[2];
678         NTSTATUS                status;
679         enum MAPISTATUS         retval;
680         TALLOC_CTX              *mem_ctx;
681         uint32_t                size;
682         uint8_t                 logon_id = 0;
683
684         /* Sanity Check */
685         OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
686         OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
687
688         session[0] = mapi_object_get_session(obj_src);
689         session[1] = mapi_object_get_session(obj_dst);
690
691         OPENCHANGE_RETVAL_IF(!session[0], MAPI_E_INVALID_PARAMETER, NULL);
692         OPENCHANGE_RETVAL_IF(!session[1], MAPI_E_INVALID_PARAMETER, NULL);
693         OPENCHANGE_RETVAL_IF(session[0] != session[1], MAPI_E_INVALID_PARAMETER, NULL);
694
695         OPENCHANGE_RETVAL_IF(!ByteCount, MAPI_E_INVALID_PARAMETER, NULL);
696         OPENCHANGE_RETVAL_IF(!ReadByteCount, MAPI_E_INVALID_PARAMETER, NULL);
697         OPENCHANGE_RETVAL_IF(!WrittenByteCount, MAPI_E_INVALID_PARAMETER, NULL);
698
699         if ((retval = mapi_object_get_logon_id(obj_src, &logon_id)) != MAPI_E_SUCCESS)
700                 return retval;
701
702         mem_ctx = talloc_named(session[0], 0, "CopyToStream");
703         size = 0;
704
705         /* Fill the CopyToStream operation */
706         request.handle_idx = 0x1;
707         size += sizeof (uint8_t);
708
709         request.ByteCount = ByteCount;
710         size += sizeof (uint64_t);
711
712         /* Fill the MAPI_REQ request */
713         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
714         mapi_req->opnum = op_MAPI_CopyToStream;
715         mapi_req->logon_id = logon_id;
716         mapi_req->handle_idx = 0;
717         mapi_req->u.mapi_CopyToStream = request;
718         size += 5;
719
720         /* Fill the mapi_request structure */
721         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
722         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
723         mapi_request->length = size;
724         mapi_request->mapi_req = mapi_req;
725         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
726         mapi_request->handles[0] = mapi_object_get_handle(obj_src);
727         mapi_request->handles[1] = mapi_object_get_handle(obj_dst);
728
729         status = emsmdb_transaction_wrapper(session[0], mem_ctx, mapi_request, &mapi_response);
730         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
731         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
732         retval = mapi_response->mapi_repl->error_code;
733         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
734
735         OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
736
737         *ReadByteCount = mapi_response->mapi_repl->u.mapi_CopyToStream.ReadByteCount;
738         *WrittenByteCount = mapi_response->mapi_repl->u.mapi_CopyToStream.WrittenByteCount;
739
740         talloc_free(mapi_response);
741         talloc_free(mem_ctx);
742
743         return MAPI_E_SUCCESS;
744 }
745
746 /**
747    \details Lock a range of bytes within the stream
748
749    \param obj_stream the stream object
750    \param RegionOffset starting point for the range
751    \param RegionSize length of the range
752    \param LockFlags type of locking to apply
753
754    Setting LockFlags to 0x00000001 will provide a write lock (i.e. one
755    writer, any number of readers). Setting LockFlags to any other value
756    will provide a read-write lock (one reader/writer, no other readers
757    or writers).
758
759    \return MAPI_E_SUCCESS on success, otherwise MAPI error
760
761    \note Developers may also call GetLastError() to retrieve the last
762    MAPI error code. Possible MAPI error codes are:
763    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
764    - MAPI_E_INVALID_PARAMETER: obj_stream is not valid
765    - MAPI_E_CALL_FAILED: A network problem was encountered during the
766    transaction
767    
768    \sa UnlockRegionStream 
769  */
770 _PUBLIC_ enum MAPISTATUS LockRegionStream(mapi_object_t *obj_stream, uint64_t RegionOffset, 
771                                           uint64_t RegionSize, uint32_t LockFlags)
772 {
773         struct mapi_request             *mapi_request;
774         struct mapi_response            *mapi_response;
775         struct EcDoRpc_MAPI_REQ         *mapi_req;
776         struct LockRegionStream_req     request;
777         struct mapi_session             *session;
778         NTSTATUS                        status;
779         enum MAPISTATUS                 retval;
780         TALLOC_CTX                      *mem_ctx;
781         uint32_t                        size;
782         uint8_t                         logon_id = 0;
783
784         /* Sanity checks */
785         OPENCHANGE_RETVAL_IF(!obj_stream, MAPI_E_INVALID_PARAMETER, NULL);
786         session = mapi_object_get_session(obj_stream);
787         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
788
789         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
790                 return retval;
791
792         mem_ctx = talloc_named(session, 0, "LockRegionStream");
793         size = 0;
794
795         /* Fill the LockRegionStream operation */
796         request.RegionOffset = RegionOffset;
797         size += sizeof (uint64_t);
798         request.RegionSize = RegionSize;
799         size += sizeof (uint64_t);
800         request.LockFlags = LockFlags;
801         size += sizeof (uint32_t);
802
803         /* Fill the MAPI_REQ request */
804         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
805         mapi_req->opnum = op_MAPI_LockRegionStream;
806         mapi_req->logon_id = logon_id;
807         mapi_req->handle_idx = 0;
808         mapi_req->u.mapi_LockRegionStream = request;
809         size += 5;
810
811         /* Fill the mapi_request structure */
812         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
813         mapi_request->mapi_len = size + sizeof (uint32_t);
814         mapi_request->length = size;
815         mapi_request->mapi_req = mapi_req;
816         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
817         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
818
819         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
820         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
821         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
822         retval = mapi_response->mapi_repl->error_code;
823         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
824
825         talloc_free(mapi_response);
826         talloc_free(mem_ctx);
827
828         return MAPI_E_SUCCESS;
829 }
830
831 /**
832    \details Unlock a range of bytes within the stream
833
834    \param obj_stream the stream object
835    \param RegionOffset starting point for the range
836    \param RegionSize length of the range
837    \param LockFlags type of locking
838
839    LockFlags used in unlocking must match the LockFlags used in locking.
840
841    \return MAPI_E_SUCCESS on success, otherwise MAPI error
842
843    \note Developers may also call GetLastError() to retrieve the last
844    MAPI error code. Possible MAPI error codes are:
845    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
846    - MAPI_E_INVALID_PARAMETER: obj_stream is not valid
847    - MAPI_E_CALL_FAILED: A network problem was encountered during the
848    transaction
849    
850    \sa UnlockRegionStream 
851  */
852 _PUBLIC_ enum MAPISTATUS UnlockRegionStream(mapi_object_t *obj_stream, uint64_t RegionOffset, 
853                                             uint64_t RegionSize, uint32_t LockFlags)
854 {
855         struct mapi_request             *mapi_request;
856         struct mapi_response            *mapi_response;
857         struct EcDoRpc_MAPI_REQ         *mapi_req;
858         struct UnlockRegionStream_req   request;
859         struct mapi_session             *session;
860         NTSTATUS                        status;
861         enum MAPISTATUS                 retval;
862         TALLOC_CTX                      *mem_ctx;
863         uint32_t                        size;
864         uint8_t                         logon_id = 0;
865
866         /* Sanity checks */
867         OPENCHANGE_RETVAL_IF(!obj_stream, MAPI_E_INVALID_PARAMETER, NULL);
868         session = mapi_object_get_session(obj_stream);
869         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
870
871         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
872                 return retval;
873
874         mem_ctx = talloc_named(session, 0, "UnlockRegionStream");
875         size = 0;
876
877         /* Fill the LockRegionStream operation */
878         request.RegionOffset = RegionOffset;
879         size += sizeof (uint64_t);
880         request.RegionSize = RegionSize;
881         size += sizeof (uint64_t);
882         request.LockFlags = LockFlags;
883         size += sizeof (uint32_t);
884
885         /* Fill the MAPI_REQ request */
886         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
887         mapi_req->opnum = op_MAPI_UnlockRegionStream;
888         mapi_req->logon_id = logon_id;
889         mapi_req->handle_idx = 0;
890         mapi_req->u.mapi_UnlockRegionStream = request;
891         size += 5;
892
893         /* Fill the mapi_request structure */
894         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
895         mapi_request->mapi_len = size + sizeof (uint32_t);
896         mapi_request->length = size;
897         mapi_request->mapi_req = mapi_req;
898         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
899         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
900
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         talloc_free(mapi_response);
908         talloc_free(mem_ctx);
909
910         return MAPI_E_SUCCESS;
911 }
912
913 /**
914    \details Clone a source stream to another stream
915
916    \param obj_src the source stream object
917    \param obj_dst the destination stream object
918  
919    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
920
921    \note Developers may also call GetLastError() to retrieve the last
922    MAPI error code. Possible MAPI error codes are:
923    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
924    - MAPI_E_INVALID_PARAMETER: source or destination streams are not valid.
925    - MAPI_E_CALL_FAILED: A network problem was encountered during the
926    transaction
927    
928    \sa OpenStream
929 */
930 _PUBLIC_ enum MAPISTATUS CloneStream(mapi_object_t *obj_src, mapi_object_t *obj_dst)
931 {
932         struct mapi_request     *mapi_request;
933         struct mapi_response    *mapi_response;
934         struct EcDoRpc_MAPI_REQ *mapi_req;
935         struct CloneStream_req  request;
936         struct mapi_session     *session;
937         NTSTATUS                status;
938         enum MAPISTATUS         retval;
939         TALLOC_CTX              *mem_ctx;
940         uint32_t                size;
941         uint8_t                 logon_id;
942
943         /* Sanity Check */
944         OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
945         OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
946
947         session = mapi_object_get_session(obj_src);
948         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
949
950         if ((retval = mapi_object_get_logon_id(obj_src, &logon_id)) != MAPI_E_SUCCESS)
951                 return retval;
952
953         mem_ctx = talloc_named(session, 0, "CloneStream");
954         size = 0;
955
956         /* Fill the CloneStream operation */
957         request.handle_idx = 0x1; /* destionation */
958         size += sizeof (uint8_t);
959
960         /* Fill the MAPI_REQ request */
961         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
962         mapi_req->opnum = op_MAPI_CloneStream;
963         mapi_req->logon_id = logon_id;
964         mapi_req->handle_idx = 0;
965         mapi_req->u.mapi_CloneStream = request;
966         size += 5;
967
968         /* Fill the mapi_request structure */
969         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
970         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
971         mapi_request->length = size;
972         mapi_request->mapi_req = mapi_req;
973         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
974         mapi_request->handles[0] = mapi_object_get_handle(obj_src);
975         mapi_request->handles[1] = 0xFFFFFFFF;
976
977         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
978         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
979         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
980         retval = mapi_response->mapi_repl->error_code;
981         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
982
983         mapi_object_set_handle(obj_dst, mapi_response->handles[1]);
984         mapi_object_set_session(obj_dst, session);
985         mapi_object_set_logon_id(obj_dst, logon_id);
986
987         talloc_free(mapi_response);
988         talloc_free(mem_ctx);
989
990         return MAPI_E_SUCCESS;
991 }
992
993 /**
994    \details Write and commit a buffer to the stream
995
996    This function writes and commits the contents of a DATA_BLOB to
997    the stream obj_stream.
998
999    \param obj_stream the opened stream object
1000    \param blob the DATA_BLOB to write to the stream
1001    \param WrittenSize the actual number of bytes written to the
1002    stream
1003
1004    \return MAPI_E_SUCCESS on success, otherwise MAPI error. 
1005
1006    \note Developers may also call GetLastError() to retrieve the last
1007    MAPI error code. Possible MAPI error codes are:
1008    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1009    - MAPI_E_INVALID_PARAMETER: A problem occurred obtaining the session
1010      context, or the stream or blob were null.
1011    - MAPI_E_CALL_FAILED: A network problem was encountered during the
1012      transaction
1013    - MAPI_E_TOO_BIG: the data blob was too large to process
1014
1015    \note The data size intended to be written to the stream should not
1016    exceed a maximum size each time you call WriteStream. This size
1017    depends on Exchange server version. However 0x1000 is known to be a
1018    reliable write size value.
1019
1020    \sa WriteStream, CommitStream
1021   */
1022 _PUBLIC_ enum MAPISTATUS WriteAndCommitStream(mapi_object_t *obj_stream, DATA_BLOB *blob, uint16_t *WrittenSize)
1023 {
1024         struct mapi_request             *mapi_request;
1025         struct mapi_response            *mapi_response;
1026         struct EcDoRpc_MAPI_REQ         *mapi_req;
1027         struct WriteAndCommitStream_req request;
1028         struct mapi_session             *session;
1029         NTSTATUS                        status;
1030         enum MAPISTATUS                 retval;
1031         TALLOC_CTX                      *mem_ctx;
1032         uint32_t                        size;
1033         uint8_t                         logon_id = 0;
1034
1035         /* Sanity Checks */
1036         OPENCHANGE_RETVAL_IF(!obj_stream, MAPI_E_INVALID_PARAMETER, NULL);
1037         session = mapi_object_get_session(obj_stream);
1038         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
1039         OPENCHANGE_RETVAL_IF(!blob, MAPI_E_INVALID_PARAMETER, NULL);
1040         OPENCHANGE_RETVAL_IF(blob->length > 0x7000, MAPI_E_TOO_BIG, NULL);
1041
1042         if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
1043                 return retval;
1044
1045         mem_ctx = talloc_named(session, 0, "WriteAndCommitStream");
1046
1047         size = 0;
1048
1049         /* Fill the WriteStream operation */
1050         request.data = *blob;
1051         size +=  blob->length;
1052         /* size for subcontext(2) */
1053         size += 2;
1054
1055         /* Fill the MAPI_REQ request */
1056         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
1057         mapi_req->opnum = op_MAPI_WriteAndCommitStream;
1058         mapi_req->logon_id = logon_id;
1059         mapi_req->handle_idx = 0;
1060         mapi_req->u.mapi_WriteAndCommitStream = request;
1061         size += 5;
1062
1063         /* Fill the mapi_request structure */
1064         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
1065         mapi_request->mapi_len = size + sizeof (uint32_t);
1066         mapi_request->length = size;
1067         mapi_request->mapi_req = mapi_req;
1068         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
1069         mapi_request->handles[0] = mapi_object_get_handle(obj_stream);
1070
1071         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
1072         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
1073         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
1074         retval = mapi_response->mapi_repl->error_code;
1075         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1076
1077         *WrittenSize = mapi_response->mapi_repl->u.mapi_WriteAndCommitStream.WrittenSize;
1078
1079         talloc_free(mapi_response);
1080         talloc_free(mem_ctx);
1081         
1082         errno = 0;
1083         return MAPI_E_SUCCESS;
1084 }
1085