server: intialize aux_header buffer to null if the data is missing.
[tridge/openchange.git] / branches / plugfest / libmapi / IStoreFolder.c
1 /*
2    OpenChange MAPI implementation.
3
4    Copyright (C) Julien Kerihuel 2007-2011.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "libmapi/libmapi.h"
21 #include "libmapi/libmapi_private.h"
22
23
24 /**
25    \file IStoreFolder.c
26  
27    \brief Open messages
28 */
29
30
31 /**
32    \details Opens a specific message and retrieves a MAPI object that
33    can be used to get or set message properties.
34
35    This function opens a specific message defined by a combination of
36    object store, folder ID, and message ID and which read/write access
37    is defined by ulFlags.
38
39    \param obj_store the store to read from
40    \param id_folder the folder ID
41    \param id_message the message ID
42    \param obj_message the resulting message object
43    \param ulFlags
44
45    Possible ulFlags values:
46    - 0x0: read only access
47    - 0x1: ReadWrite
48    - 0x3: Create
49    - 0x4: OpenSoftDeleted
50
51    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
52
53    \note Developers may also call GetLastError() to retrieve the last
54    MAPI error code. Possible MAPI error codes are:
55    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
56    - MAPI_E_INVALID_PARAMETER: obj_store is undefined
57    - MAPI_E_CALL_FAILED: A network problem was encountered during the
58      transaction
59
60    \sa MAPIInitialize, GetLastError
61 */
62 _PUBLIC_ enum MAPISTATUS OpenMessage(mapi_object_t *obj_store, 
63                                      mapi_id_t id_folder, 
64                                      mapi_id_t id_message, 
65                                      mapi_object_t *obj_message,
66                                      uint8_t ulFlags)
67 {
68         struct mapi_context             *mapi_ctx;
69         struct mapi_request             *mapi_request;
70         struct mapi_response            *mapi_response;
71         struct EcDoRpc_MAPI_REQ         *mapi_req;
72         struct OpenMessage_req          request;
73         struct OpenMessage_repl         *reply;
74         struct mapi_session             *session;
75         mapi_object_message_t           *message;
76         struct SPropValue               lpProp;
77         const char                      *tstring;
78         NTSTATUS                        status;
79         enum MAPISTATUS                 retval;
80         uint32_t                        size = 0;
81         TALLOC_CTX                      *mem_ctx;
82         uint32_t                        i = 0;
83         uint8_t                         logon_id;
84
85         /* Sanity checks */
86         OPENCHANGE_RETVAL_IF(!obj_store, MAPI_E_INVALID_PARAMETER, NULL);
87         session = mapi_object_get_session(obj_store);
88         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
89
90         mapi_ctx = session->mapi_ctx;
91         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
92
93         if ((retval = mapi_object_get_logon_id(obj_store, &logon_id)) != MAPI_E_SUCCESS)
94                 return retval;
95
96         mem_ctx = talloc_named(NULL, 0, "OpenMessage");
97
98         /* Fill the OpenMessage operation */
99         request.handle_idx = 0x1;
100         request.CodePageId = 0xfff;
101         request.FolderId = id_folder;
102         request.OpenModeFlags = (enum OpenMessage_OpenModeFlags)ulFlags;
103         request.MessageId = id_message;
104         size = sizeof (uint8_t) + sizeof(uint16_t) + sizeof(mapi_id_t) + sizeof(uint8_t) + sizeof(mapi_id_t);
105
106         /* Fill the MAPI_REQ request */
107         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
108         mapi_req->opnum = op_MAPI_OpenMessage;
109         mapi_req->logon_id = logon_id;
110         mapi_req->handle_idx = 0;
111         mapi_req->u.mapi_OpenMessage = request;
112         size += 5;
113
114         /* Fill the mapi_request structure */
115         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
116         mapi_request->mapi_len = size + sizeof (uint32_t) * 2;
117         mapi_request->length = size;
118         mapi_request->mapi_req = mapi_req;
119         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 2);
120         mapi_request->handles[0] = mapi_object_get_handle(obj_store);
121         mapi_request->handles[1] = 0xffffffff;
122
123         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
124         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
125         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
126         retval = mapi_response->mapi_repl->error_code;
127         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
128
129         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
130
131         /* Set object session and handle */
132         mapi_object_set_session(obj_message, session);
133         mapi_object_set_handle(obj_message, mapi_response->handles[1]);
134         mapi_object_set_logon_id(obj_message, logon_id);
135
136         /* Store OpenMessage reply data */
137         reply = &mapi_response->mapi_repl->u.mapi_OpenMessage;
138
139         message = talloc_zero((TALLOC_CTX *)session, mapi_object_message_t);
140
141         tstring = get_TypedString(&reply->SubjectPrefix);
142         if (tstring) {
143                 message->SubjectPrefix = talloc_strdup((TALLOC_CTX *)message, tstring);
144         }
145
146         tstring = get_TypedString(&reply->NormalizedSubject);
147         if (tstring) {
148                 message->NormalizedSubject = talloc_strdup((TALLOC_CTX *)message, tstring);
149         }
150         
151
152         message->cValues = reply->RecipientColumns.cValues;
153         message->SRowSet.cRows = reply->RowCount;
154         message->SRowSet.aRow = talloc_array((TALLOC_CTX *)message, struct SRow, reply->RowCount + 1);
155
156         message->SPropTagArray.cValues = reply->RecipientColumns.cValues;
157         message->SPropTagArray.aulPropTag = talloc_steal(message, reply->RecipientColumns.aulPropTag);
158
159         for (i = 0; i < reply->RowCount; i++) {
160                 emsmdb_get_SRow((TALLOC_CTX *)message, mapi_ctx->lp_ctx,
161                                 &(message->SRowSet.aRow[i]), &message->SPropTagArray, 
162                                 reply->recipients[i].RecipientRow.prop_count,
163                                 &reply->recipients[i].RecipientRow.prop_values,
164                                 reply->recipients[i].RecipientRow.layout, 1);
165
166                 lpProp.ulPropTag = PR_RECIPIENT_TYPE;
167                 lpProp.value.l = reply->recipients[i].RecipClass;
168                 SRow_addprop(&(message->SRowSet.aRow[i]), lpProp);
169
170                 lpProp.ulPropTag = PR_INTERNET_CPID;
171                 lpProp.value.l = reply->recipients[i].codepage;
172                 SRow_addprop(&(message->SRowSet.aRow[i]), lpProp);
173         }
174
175         /* add SPropTagArray elements we automatically append to SRow */
176         SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_RECIPIENT_TYPE);
177         SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_INTERNET_CPID);
178
179         obj_message->private_data = (void *) message;
180
181         talloc_free(mapi_response);
182         talloc_free(mem_ctx);
183
184         return MAPI_E_SUCCESS;
185 }
186
187 /**
188    \details Retrieve the message properties for an already open message.
189
190    This function is very similar to OpenMessage, but works on an already
191    open message object.
192
193    \param obj_message the message object to retrieve the properties for.
194
195    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
196
197    \note Developers may also call GetLastError() to retrieve the last
198    MAPI error code. Possible MAPI error codes are:
199    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
200    - MAPI_E_INVALID_PARAMETER: obj_store is undefined
201    - MAPI_E_CALL_FAILED: A network problem was encountered during the
202      transaction
203
204    \sa OpenMessage
205 */
206 _PUBLIC_ enum MAPISTATUS ReloadCachedInformation(mapi_object_t *obj_message)
207 {
208         struct mapi_context                     *mapi_ctx;
209         struct mapi_request                     *mapi_request;
210         struct mapi_response                    *mapi_response;
211         struct EcDoRpc_MAPI_REQ                 *mapi_req;
212         struct ReloadCachedInformation_req      request;
213         struct ReloadCachedInformation_repl     *reply;
214         struct mapi_session                     *session;
215         mapi_object_message_t                   *message;
216         struct SPropValue                       lpProp;
217         NTSTATUS                                status;
218         enum MAPISTATUS                         retval;
219         uint32_t                                size = 0;
220         TALLOC_CTX                              *mem_ctx;
221         uint32_t                                i = 0;
222         uint8_t                                 logon_id;
223
224         /* Sanity checks */
225         OPENCHANGE_RETVAL_IF(!obj_message, MAPI_E_INVALID_PARAMETER, NULL);
226         session = mapi_object_get_session(obj_message);
227         OPENCHANGE_RETVAL_IF(!session, MAPI_E_INVALID_PARAMETER, NULL);
228
229         mapi_ctx = session->mapi_ctx;
230         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
231
232         if ((retval = mapi_object_get_logon_id(obj_message, &logon_id)) != MAPI_E_SUCCESS)
233                 return retval;
234
235         mem_ctx = talloc_named(NULL, 0, "ReloadCachedInformation");
236
237         /* Fill the ReloadCachedInformation operation */
238         request.Reserved = 0x0000;
239         size += sizeof (uint16_t);
240
241         /* Fill the MAPI_REQ request */
242         mapi_req = talloc_zero(mem_ctx, struct EcDoRpc_MAPI_REQ);
243         mapi_req->opnum = op_MAPI_ReloadCachedInformation;
244         mapi_req->logon_id = logon_id;
245         mapi_req->handle_idx = 0;
246         mapi_req->u.mapi_ReloadCachedInformation = request;
247         size += 5;
248
249         /* Fill the mapi_request structure */
250         mapi_request = talloc_zero(mem_ctx, struct mapi_request);
251         mapi_request->mapi_len = size + sizeof (uint32_t);
252         mapi_request->length = size;
253         mapi_request->mapi_req = mapi_req;
254         mapi_request->handles = talloc_array(mem_ctx, uint32_t, 1);
255         mapi_request->handles[0] = mapi_object_get_handle(obj_message);
256
257         status = emsmdb_transaction_wrapper(session, mem_ctx, mapi_request, &mapi_response);
258         OPENCHANGE_RETVAL_IF(!NT_STATUS_IS_OK(status), MAPI_E_CALL_FAILED, mem_ctx);
259         OPENCHANGE_RETVAL_IF(!mapi_response->mapi_repl, MAPI_E_CALL_FAILED, mem_ctx);
260         retval = mapi_response->mapi_repl->error_code;
261
262         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
263
264         OPENCHANGE_CHECK_NOTIFICATION(session, mapi_response);
265
266         /* Store ReloadCachedInformation reply data */
267         reply = &mapi_response->mapi_repl->u.mapi_ReloadCachedInformation;
268
269         message = talloc_zero((TALLOC_CTX *)session, mapi_object_message_t);
270         message->cValues = reply->RecipientColumns.cValues;
271         message->SRowSet.cRows = reply->RowCount;
272         message->SRowSet.aRow = talloc_array((TALLOC_CTX *)message, struct SRow, reply->RowCount + 1);
273
274         message->SPropTagArray.cValues = reply->RecipientColumns.cValues;
275         message->SPropTagArray.aulPropTag = talloc_steal(message, reply->RecipientColumns.aulPropTag);
276
277         for (i = 0; i < reply->RowCount; i++) {
278                 emsmdb_get_SRow((TALLOC_CTX *)message, mapi_ctx->lp_ctx,
279                                 &(message->SRowSet.aRow[i]), &message->SPropTagArray, 
280                                 reply->RecipientRows[i].RecipientRow.prop_count,
281                                 &reply->RecipientRows[i].RecipientRow.prop_values,
282                                 reply->RecipientRows[i].RecipientRow.layout, 1);
283
284                 lpProp.ulPropTag = PR_RECIPIENT_TYPE;
285                 lpProp.value.l = reply->RecipientRows[i].RecipientType;
286                 SRow_addprop(&(message->SRowSet.aRow[i]), lpProp);
287
288                 lpProp.ulPropTag = PR_INTERNET_CPID;
289                 lpProp.value.l = reply->RecipientRows[i].CodePageId;
290                 SRow_addprop(&(message->SRowSet.aRow[i]), lpProp);
291         }
292
293         /* add SPropTagArray elements we automatically append to SRow */
294         SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_RECIPIENT_TYPE);
295         SPropTagArray_add((TALLOC_CTX *)message, &message->SPropTagArray, PR_INTERNET_CPID);
296
297         talloc_free(obj_message->private_data);
298         obj_message->private_data = (void *) message;
299
300         talloc_free(mapi_response);
301         talloc_free(mem_ctx);
302
303         errno = 0;
304         return MAPI_E_SUCCESS;
305 }