2 OpenChange MAPI implementation.
4 Copyright (C) Julien Kerihuel 2007-2008.
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.
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.
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/>.
20 #include "libmapi/libmapi.h"
21 #include "libmapi/libmapi_private.h"
27 \brief Functions for operating on Streams on MAPI objects
32 \details Open a stream
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
38 \param obj_related the object to open.
39 \param PropertyTag the property name for the object to create a stream
41 \param OpenModeFlags sets the access mode for the stream and is one
42 of the following values:
47 \param obj_stream the resulting stream object.
49 \return MAPI_E_SUCCESS on success, otherwise MAPI error. Possible MAPI
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
57 \note Developers may also call GetLastError() to retrieve the last
60 \sa ReadStream, WriteStream, GetLastError
63 _PUBLIC_ enum MAPISTATUS OpenStream(mapi_object_t *obj_related, enum MAPITAGS PropertyTag,
64 enum OpenStream_OpenModeFlags OpenModeFlags,
65 mapi_object_t *obj_stream)
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;
73 enum MAPISTATUS retval;
79 session = mapi_object_get_session(obj_related);
80 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
82 if ((retval = mapi_object_get_logon_id(obj_related, &logon_id)) != MAPI_E_SUCCESS)
85 mem_ctx = talloc_named(session, 0, "OpenStream");
89 /* Fill the OpenStream operation */
90 request.handle_idx = 0x1;
91 request.PropertyTag = PropertyTag;
93 /* STGM_XXX (obj_base.h windows header) */
94 request.OpenModeFlags = OpenModeFlags;
95 size += sizeof(uint8_t) + sizeof(uint32_t) + sizeof(uint8_t);
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;
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;
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);
120 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
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);
127 talloc_free(mapi_response);
128 talloc_free(mem_ctx);
130 return MAPI_E_SUCCESS;
135 \details Read buffer from a stream
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.
141 \param obj_stream the opened stream object
142 \param buf_data the buffer where data read from the stream will be
144 \param ByteCount the number of bytes requested to be read from the
146 \param ByteRead the number of bytes read from the stream
148 \return MAPI_E_SUCCESS on success, otherwise MAPI error. Possible MAPI
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
155 \note Developers may also call GetLastError() to retrieve the last
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.
163 \sa OpenStream, WriteStream, GetLastError
165 _PUBLIC_ enum MAPISTATUS ReadStream(mapi_object_t *obj_stream, unsigned char *buf_data,
166 uint16_t ByteCount, uint16_t *ByteRead)
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;
174 enum MAPISTATUS retval;
177 uint8_t logon_id = 0;
180 session = mapi_object_get_session(obj_stream);
181 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
183 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
186 mem_ctx = talloc_named(session, 0, "ReadStream");
191 /* Fill the ReadStream operation */
192 request.ByteCount = ByteCount;
193 size += sizeof(uint16_t);
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;
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);
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);
217 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
219 /* copy no more than sz_data into buffer */
220 *ByteRead = mapi_response->mapi_repl->u.mapi_ReadStream.data.length;
222 if (*ByteRead > ByteCount) {
223 *ByteRead = ByteCount;
225 memcpy(buf_data, mapi_response->mapi_repl->u.mapi_ReadStream.data.data, *ByteRead);
228 talloc_free(mapi_response);
229 talloc_free(mem_ctx);
231 return MAPI_E_SUCCESS;
236 \details Write buffer to the stream
238 This function writes the stream specified as a DATA_BLOB in data to
239 the stream obj_stream.
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
246 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
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
255 - MAPI_E_TOO_BIG: the data blob was too large to process
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.
262 \sa OpenStream, ReadStream, GetLastError
264 _PUBLIC_ enum MAPISTATUS WriteStream(mapi_object_t *obj_stream, DATA_BLOB *blob, uint16_t *WrittenSize)
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;
272 enum MAPISTATUS retval;
275 uint8_t logon_id = 0;
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);
283 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
286 mem_ctx = talloc_named(session, 0, "WriteStream");
290 /* Fill the WriteStream operation */
291 request.data = *blob;
292 size += blob->length;
293 /* size for subcontext(2) */
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;
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);
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);
318 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
320 *WrittenSize = mapi_response->mapi_repl->u.mapi_WriteStream.WrittenSize;
322 talloc_free(mapi_response);
323 talloc_free(mem_ctx);
326 return MAPI_E_SUCCESS;
331 \details Commits stream operations
333 \param obj_stream the stream object to commit
335 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
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
345 \sa OpenStream, ReadStream, WriteStream
347 _PUBLIC_ enum MAPISTATUS CommitStream(mapi_object_t *obj_stream)
349 struct mapi_request *mapi_request;
350 struct mapi_response *mapi_response;
351 struct EcDoRpc_MAPI_REQ *mapi_req;
352 struct mapi_session *session;
354 enum MAPISTATUS retval;
357 uint8_t logon_id = 0;
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);
364 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
367 mem_ctx = talloc_named(session, 0, "CommitStream");
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;
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);
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);
391 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
393 talloc_free(mapi_response);
394 talloc_free(mem_ctx);
396 return MAPI_E_SUCCESS;
401 \details Gets the size of a stream
403 \param obj_stream the stream object we retrieve size from
404 \param StreamSize pointer on the stream size
406 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
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
416 \sa OpenStream, ReadStream
418 _PUBLIC_ enum MAPISTATUS GetStreamSize(mapi_object_t *obj_stream, uint32_t *StreamSize)
420 struct mapi_request *mapi_request;
421 struct mapi_response *mapi_response;
422 struct EcDoRpc_MAPI_REQ *mapi_req;
423 struct mapi_session *session;
425 enum MAPISTATUS retval;
428 uint8_t logon_id = 0;
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);
435 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
438 mem_ctx = talloc_named(session, 0, "GetStreamSize");
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;
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);
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);
462 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
464 *StreamSize = mapi_response->mapi_repl->u.mapi_GetStreamSize.StreamSize;
466 talloc_free(mapi_response);
467 talloc_free(mem_ctx);
469 return MAPI_E_SUCCESS;
474 \details Seek a specific position within the stream
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
481 Origin can either take one of the following values:
483 * 0x0 The new seek pointer is an offset relative to the beginning
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
490 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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
500 \sa OpenStream, ReadStream
502 _PUBLIC_ enum MAPISTATUS SeekStream(mapi_object_t *obj_stream, uint8_t Origin, uint64_t Offset,
503 uint64_t *NewPosition)
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;
511 enum MAPISTATUS retval;
514 uint8_t logon_id = 0;
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);
523 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
526 mem_ctx = talloc_named(session, 0, "SeekStream");
529 /* Fill the SeekStream operation */
530 request.Origin = Origin;
531 size += sizeof (uint8_t);
533 request.Offset = Offset;
534 size += sizeof (uint64_t);
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;
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);
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);
558 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
560 *NewPosition = mapi_response->mapi_repl->u.mapi_SeekStream.NewPosition;
562 talloc_free(mapi_response);
563 talloc_free(mem_ctx);
565 return MAPI_E_SUCCESS;
570 \details Set the stream size
572 \param obj_stream the stream object
573 \param SizeStream the size of the stream
575 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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
584 \sa OpenStream, GetStreamSize
586 _PUBLIC_ enum MAPISTATUS SetStreamSize(mapi_object_t *obj_stream, uint64_t SizeStream)
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;
594 enum MAPISTATUS retval;
597 uint8_t logon_id = 0;
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);
604 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
607 mem_ctx = talloc_named(session, 0, "SetStreamSize");
610 /* Fill the SetStreamSize operation */
611 request.SizeStream = SizeStream;
612 size += sizeof (uint64_t);
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;
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);
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);
636 OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
638 talloc_free(mapi_response);
639 talloc_free(mem_ctx);
641 return MAPI_E_SUCCESS;
646 \details Copy a number of bytes from a source stream to another
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
654 \param WrittenByteCount pointer on the number of bytes written to
655 the destination object
657 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
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
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)
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];
679 enum MAPISTATUS retval;
682 uint8_t logon_id = 0;
685 OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
686 OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
688 session[0] = mapi_object_get_session(obj_src);
689 session[1] = mapi_object_get_session(obj_dst);
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);
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);
699 if ((retval = mapi_object_get_logon_id(obj_src, &logon_id)) != MAPI_E_SUCCESS)
702 mem_ctx = talloc_named(session[0], 0, "CopyToStream");
705 /* Fill the CopyToStream operation */
706 request.handle_idx = 0x1;
707 size += sizeof (uint8_t);
709 request.ByteCount = ByteCount;
710 size += sizeof (uint64_t);
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;
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);
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);
735 OPENCHANGE_CHECK_NOTIFICATION(session[0], mapi_response);
737 *ReadByteCount = mapi_response->mapi_repl->u.mapi_CopyToStream.ReadByteCount;
738 *WrittenByteCount = mapi_response->mapi_repl->u.mapi_CopyToStream.WrittenByteCount;
740 talloc_free(mapi_response);
741 talloc_free(mem_ctx);
743 return MAPI_E_SUCCESS;
747 \details Lock a range of bytes within the stream
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
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
759 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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
768 \sa UnlockRegionStream
770 _PUBLIC_ enum MAPISTATUS LockRegionStream(mapi_object_t *obj_stream, uint64_t RegionOffset,
771 uint64_t RegionSize, uint32_t LockFlags)
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;
779 enum MAPISTATUS retval;
782 uint8_t logon_id = 0;
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);
789 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
792 mem_ctx = talloc_named(session, 0, "LockRegionStream");
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);
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;
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);
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);
825 talloc_free(mapi_response);
826 talloc_free(mem_ctx);
828 return MAPI_E_SUCCESS;
832 \details Unlock a range of bytes within the stream
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
839 LockFlags used in unlocking must match the LockFlags used in locking.
841 \return MAPI_E_SUCCESS on success, otherwise MAPI error
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
850 \sa UnlockRegionStream
852 _PUBLIC_ enum MAPISTATUS UnlockRegionStream(mapi_object_t *obj_stream, uint64_t RegionOffset,
853 uint64_t RegionSize, uint32_t LockFlags)
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;
861 enum MAPISTATUS retval;
864 uint8_t logon_id = 0;
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);
871 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
874 mem_ctx = talloc_named(session, 0, "UnlockRegionStream");
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);
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;
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);
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);
907 talloc_free(mapi_response);
908 talloc_free(mem_ctx);
910 return MAPI_E_SUCCESS;
914 \details Clone a source stream to another stream
916 \param obj_src the source stream object
917 \param obj_dst the destination stream object
919 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
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
930 _PUBLIC_ enum MAPISTATUS CloneStream(mapi_object_t *obj_src, mapi_object_t *obj_dst)
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;
938 enum MAPISTATUS retval;
944 OPENCHANGE_RETVAL_IF(!obj_src, MAPI_E_INVALID_PARAMETER, NULL);
945 OPENCHANGE_RETVAL_IF(!obj_dst, MAPI_E_INVALID_PARAMETER, NULL);
947 session = mapi_object_get_session(obj_src);
948 OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
950 if ((retval = mapi_object_get_logon_id(obj_src, &logon_id)) != MAPI_E_SUCCESS)
953 mem_ctx = talloc_named(session, 0, "CloneStream");
956 /* Fill the CloneStream operation */
957 request.handle_idx = 0x1; /* destionation */
958 size += sizeof (uint8_t);
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;
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;
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);
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);
987 talloc_free(mapi_response);
988 talloc_free(mem_ctx);
990 return MAPI_E_SUCCESS;
994 \details Write and commit a buffer to the stream
996 This function writes and commits the contents of a DATA_BLOB to
997 the stream obj_stream.
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
1004 \return MAPI_E_SUCCESS on success, otherwise MAPI error.
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
1013 - MAPI_E_TOO_BIG: the data blob was too large to process
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.
1020 \sa WriteStream, CommitStream
1022 _PUBLIC_ enum MAPISTATUS WriteAndCommitStream(mapi_object_t *obj_stream, DATA_BLOB *blob, uint16_t *WrittenSize)
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;
1030 enum MAPISTATUS retval;
1031 TALLOC_CTX *mem_ctx;
1033 uint8_t logon_id = 0;
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);
1042 if ((retval = mapi_object_get_logon_id(obj_stream, &logon_id)) != MAPI_E_SUCCESS)
1045 mem_ctx = talloc_named(session, 0, "WriteAndCommitStream");
1049 /* Fill the WriteStream operation */
1050 request.data = *blob;
1051 size += blob->length;
1052 /* size for subcontext(2) */
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;
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);
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);
1077 *WrittenSize = mapi_response->mapi_repl->u.mapi_WriteAndCommitStream.WrittenSize;
1079 talloc_free(mapi_response);
1080 talloc_free(mem_ctx);
1083 return MAPI_E_SUCCESS;