"Fossies" - the Fresh Open Source Software Archive 
Member "evolution-mapi-3.46.1/src/libexchangemapi/e-mapi-fast-transfer.c" (2 Dec 2022, 17108 Bytes) of package /linux/misc/evolution-mapi-3.46.1.tar.xz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "e-mapi-fast-transfer.c" see the
Fossies "Dox" file reference documentation.
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * This program is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with the program; if not, see <http://www.gnu.org/licenses/>
15 *
16 *
17 * Authors:
18 * Milan Crha <mcrha@redhat.com>
19 *
20 * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
21 *
22 */
23
24 #include "evolution-mapi-config.h"
25
26 #include "e-mapi-connection.h"
27 #include "e-mapi-debug.h"
28
29 #include "e-mapi-fast-transfer.h"
30
31 #ifndef HAVE_FAST_TRANSFER_TAGS_2_1
32 #define StartMessage PidTagStartMessage
33 #define EndMessage PidTagEndMessage
34 #define StartRecip PidTagStartRecip
35 #define EndToRecip PidTagEndToRecip
36 #define NewAttach PidTagNewAttach
37 #define EndAttach PidTagEndAttach
38 #define StartEmbed PidTagStartEmbed
39 #define EndEmbed PidTagEndEmbed
40 #endif
41
42 struct _EMapiFXParserClosure;
43 typedef struct _EMapiFXParserClosure EMapiFXParserClosure;
44
45 struct _EMapiFXParserClosure {
46 EMapiConnection *conn;
47 TALLOC_CTX *mem_ctx;
48 TransferObjectCB cb;
49 gpointer cb_user_data;
50 GCancellable *cancellable;
51 GError **perror;
52
53 uint32_t next_proptag_is_nameid;
54 uint32_t next_nameid_proptag;
55 guint32 object_index;
56 guint32 objects_total;
57
58 /* in what section it is now */
59 uint32_t marker;
60 /* where to store read properties */
61 struct mapi_SPropValue_array *current_properties;
62 TALLOC_CTX *current_streamed_mem_ctx;
63 EMapiStreamedProp **current_streamed_properties;
64 guint32 *current_streamed_properties_count;
65
66 /* what object is currently read (can be embeded object or the below object */
67 EMapiObject *current_object;
68
69 /* main object properties */
70 EMapiObject *object;
71 };
72
73 static void
74 e_mapi_object_finish_read (EMapiObject *object)
75 {
76 EMapiRecipient *rprev, *rtail, *rnext;
77 EMapiAttachment *aprev, *atail, *anext;
78
79 if (!object)
80 return;
81
82 /* reverse order of recipients and attachments */
83 rprev = NULL;
84 for (rtail = object->recipients; rtail; rtail = rnext) {
85 rnext = rtail->next;
86 rtail->next = rprev;
87 rprev = rtail;
88 }
89 object->recipients = rprev;
90
91 aprev = NULL;
92 for (atail = object->attachments; atail; atail = anext) {
93 anext = atail->next;
94 atail->next = aprev;
95 aprev = atail;
96 }
97 object->attachments = aprev;
98 }
99
100 static gboolean
101 process_parsed_object (EMapiFXParserClosure *data)
102 {
103 g_return_val_if_fail (data != NULL, FALSE);
104 g_return_val_if_fail (data->conn != NULL, FALSE);
105 g_return_val_if_fail (data->cb != NULL, FALSE);
106 g_return_val_if_fail (data->object != NULL, FALSE);
107
108 return data->cb (data->conn, data->mem_ctx, data->object, data->object_index, data->objects_total, data->cb_user_data, data->cancellable, data->perror);
109 }
110
111 static enum MAPISTATUS
112 parse_marker_cb (uint32_t marker, void *closure)
113 {
114 EMapiFXParserClosure *data = closure;
115 gboolean stop = FALSE;
116
117 /* g_print ("\tMarker: %s (0x%08x)\n", get_proptag_name (marker), marker); */
118 switch (marker) {
119 case StartMessage:
120 if (data->object) {
121 g_debug ("%s: StartMessage: out of order, previous object not finished yet", G_STRFUNC);
122 e_mapi_object_finish_read (data->object);
123 stop = !process_parsed_object (data);
124 e_mapi_object_free (data->object);
125 data->object = NULL;
126 data->current_object = NULL;
127 data->current_properties = NULL;
128 data->current_streamed_mem_ctx = NULL;
129 data->current_streamed_properties = NULL;
130 data->current_streamed_properties_count = NULL;
131 }
132
133 if (stop)
134 return MAPI_E_USER_CANCEL;
135
136 /* new object parsing */
137 data->object_index++;
138 data->object = e_mapi_object_new (data->mem_ctx);
139 data->current_object = data->object;
140 data->current_properties = &data->object->properties;
141 data->current_streamed_mem_ctx = data->object;
142 data->current_streamed_properties = &data->object->streamed_properties;
143 data->current_streamed_properties_count = &data->object->streamed_properties_count;
144 data->marker = marker;
145 break;
146 case EndMessage:
147 if (!data->object) {
148 g_debug ("%s: EndMessage no object started", G_STRFUNC);
149 } else {
150 e_mapi_object_finish_read (data->object);
151 stop = !process_parsed_object (data);
152
153 e_mapi_object_free (data->object);
154 data->object = NULL;
155 data->current_object = NULL;
156 data->current_properties = NULL;
157 data->current_streamed_mem_ctx = NULL;
158 data->current_streamed_properties = NULL;
159 data->current_streamed_properties_count = NULL;
160
161 if (stop)
162 return MAPI_E_USER_CANCEL;
163 }
164 data->marker = 0;
165 break;
166 case StartRecip:
167 if (!data->current_object) {
168 g_debug ("%s: StartRecip no object started", G_STRFUNC);
169 } else {
170 EMapiRecipient *recipient;
171
172 recipient = e_mapi_recipient_new (data->mem_ctx);
173
174 /* they are stored in reverse order, but reverted before passing to a caller */
175 recipient->next = data->current_object->recipients;
176 data->current_object->recipients = recipient;
177
178 data->current_properties = &recipient->properties;
179 data->current_streamed_mem_ctx = NULL;
180 data->current_streamed_properties = NULL;
181 data->current_streamed_properties_count = NULL;
182 }
183 data->marker = marker;
184 break;
185 case EndToRecip:
186 data->current_properties = NULL;
187 data->current_streamed_mem_ctx = NULL;
188 data->current_streamed_properties = NULL;
189 data->current_streamed_properties_count = NULL;
190 data->marker = 0;
191 break;
192 case NewAttach:
193 if (!data->current_object) {
194 g_debug ("%s: NewAttach no object started", G_STRFUNC);
195 } else {
196 EMapiAttachment *attachment;
197
198 attachment = e_mapi_attachment_new (data->mem_ctx);
199
200 /* they are stored in reverse order, but reverted before passing to a caller */
201 attachment->next = data->current_object->attachments;
202 data->current_object->attachments = attachment;
203
204 data->current_properties = &attachment->properties;
205 data->current_streamed_mem_ctx = attachment;
206 data->current_streamed_properties = &attachment->streamed_properties;
207 data->current_streamed_properties_count = &attachment->streamed_properties_count;
208 }
209 data->marker = marker;
210 break;
211 case EndAttach:
212 data->current_properties = NULL;
213 data->current_streamed_mem_ctx = NULL;
214 data->current_streamed_properties = NULL;
215 data->current_streamed_properties_count = NULL;
216 data->marker = 0;
217 break;
218 case StartEmbed:
219 if (!data->current_object) {
220 g_debug ("%s: StartEmbed no object started", G_STRFUNC);
221 } else if (!data->current_object->attachments) {
222 g_debug ("%s: StartEmbed no attachment started", G_STRFUNC);
223 } else if (data->current_object->attachments->embedded_object) {
224 g_debug ("%s: StartEmbed attachment has embedded object already", G_STRFUNC);
225 } else {
226 EMapiObject *object;
227
228 object = e_mapi_object_new (data->mem_ctx);
229
230 object->parent = data->current_object;
231 data->current_object->attachments->embedded_object = object;
232 data->current_object = object;
233 data->current_properties = &object->properties;
234 data->current_streamed_mem_ctx = object;
235 data->current_streamed_properties = &object->streamed_properties;
236 data->current_streamed_properties_count = &object->streamed_properties_count;
237 }
238 data->marker = marker;
239 break;
240 case EndEmbed:
241 if (!data->current_object) {
242 g_debug ("%s: EndEmbed no object started", G_STRFUNC);
243 } else if (!data->current_object->parent) {
244 g_debug ("%s: EndEmbed no parent object", G_STRFUNC);
245 } else {
246 e_mapi_object_finish_read (data->current_object);
247 data->current_object = data->current_object->parent;
248 data->current_properties = NULL;
249 data->current_streamed_mem_ctx = NULL;
250 data->current_streamed_properties = NULL;
251 data->current_streamed_properties_count = NULL;
252 }
253 data->marker = 0;
254 break;
255 default:
256 data->marker = marker;
257 break;
258 }
259
260 return MAPI_E_SUCCESS;
261 }
262
263 static enum MAPISTATUS
264 parse_delprop_cb (uint32_t proptag, void *closure)
265 {
266 return MAPI_E_SUCCESS;
267 }
268
269 static enum MAPISTATUS
270 parse_namedprop_cb (uint32_t proptag, struct MAPINAMEID nameid, void *closure)
271 {
272 /* the next property is a named property, but cannot make it proptag, thus left it for later */
273 EMapiFXParserClosure *data = closure;
274 uint32_t lid = MAPI_E_RESERVED;
275 char *guid;
276
277 guid = GUID_string (data->mem_ctx, &(nameid.lpguid));
278
279 if (nameid.ulKind == MNID_ID) {
280 if (mapi_nameid_lid_lookup_canonical (nameid.kind.lid, guid, &lid) != MAPI_E_SUCCESS)
281 lid = MAPI_E_RESERVED;
282 } else if (nameid.ulKind == MNID_STRING) {
283 if (mapi_nameid_string_lookup_canonical (nameid.kind.lpwstr.Name, guid, &lid) != MAPI_E_SUCCESS)
284 lid = MAPI_E_RESERVED;
285 }
286
287 talloc_free (guid);
288
289 if (lid != MAPI_E_RESERVED && (lid & 0xFFFF) == (proptag & 0xFFFF)) {
290 data->next_proptag_is_nameid = proptag;
291 data->next_nameid_proptag = lid;
292 }
293
294 return MAPI_E_SUCCESS;
295 }
296
297 static enum MAPISTATUS
298 parse_property_cb (struct SPropValue prop, void *closure)
299 {
300 EMapiFXParserClosure *data = closure;
301
302 if (data->next_proptag_is_nameid == prop.ulPropTag) {
303 prop.ulPropTag = data->next_nameid_proptag;
304 }
305
306 data->next_proptag_is_nameid = MAPI_E_RESERVED;
307 data->next_nameid_proptag = MAPI_E_RESERVED;
308
309 if (!data->current_properties) {
310 if (data->marker)
311 g_debug ("%s: Property received out of order under marker %s", G_STRFUNC, get_proptag_name (data->marker));
312 return MAPI_E_SUCCESS;
313 }
314
315 switch (prop.ulPropTag & 0xFFFF) {
316 case PT_BINARY:
317 if (data->current_streamed_properties && data->current_streamed_properties_count &&
318 prop.value.bin.cb > 65535) {
319 guint32 index;
320
321 (*data->current_streamed_properties) = talloc_realloc (data->current_streamed_mem_ctx,
322 (*data->current_streamed_properties),
323 EMapiStreamedProp,
324 (*data->current_streamed_properties_count) + 1);
325 index = (*data->current_streamed_properties_count);
326 (*data->current_streamed_properties_count)++;
327 (*data->current_streamed_properties)[index].proptag = prop.ulPropTag;
328 (*data->current_streamed_properties)[index].cb = prop.value.bin.cb;
329 (*data->current_streamed_properties)[index].lpb = prop.value.bin.lpb;
330 break;
331 } else if (prop.value.bin.cb > 65535) {
332 g_debug ("%s: PT_BINARY property 0x%X larger than 64KB (%d), will be truncated", G_STRFUNC, prop.ulPropTag, prop.value.bin.cb);
333 }
334 /* falls through */
335 case PT_BOOLEAN:
336 case PT_I2:
337 case PT_LONG:
338 case PT_DOUBLE:
339 case PT_I8:
340 case PT_STRING8:
341 case PT_UNICODE:
342 case PT_SYSTIME:
343 case PT_ERROR:
344 case PT_CLSID:
345 case PT_SVREID:
346 case PT_MV_STRING8:
347 case PT_MV_UNICODE:
348 case PT_MV_BINARY:
349 case PT_MV_LONG:
350 data->current_properties->cValues++;
351 data->current_properties->lpProps = talloc_realloc (data->mem_ctx,
352 data->current_properties->lpProps,
353 struct mapi_SPropValue,
354 data->current_properties->cValues + 1);
355 cast_mapi_SPropValue (data->mem_ctx, &data->current_properties->lpProps[data->current_properties->cValues - 1], &prop);
356 data->current_properties->lpProps[data->current_properties->cValues].ulPropTag = 0;
357 break;
358 default:
359 /* skip all of other type */
360 break;
361 }
362
363 return MAPI_E_SUCCESS;
364 }
365
366 static enum MAPISTATUS
367 e_mapi_fast_transfer_internal (EMapiConnection *conn,
368 TALLOC_CTX *mem_ctx,
369 TransferObjectCB cb,
370 gpointer cb_user_data,
371 gint objects_total,
372 gboolean expect_start_message,
373 mapi_object_t *fasttransfer_ctx,
374 GCancellable *cancellable,
375 GError **perror)
376 {
377 enum MAPISTATUS ms;
378 enum TransferStatus transferStatus;
379 uint16_t stepCount = -1, totalCount = -1;
380 struct fx_parser_context *parser;
381 EMapiFXParserClosure data = { 0 };
382
383 data.conn = conn;
384 data.mem_ctx = talloc_new (mem_ctx);
385 data.cb = cb;
386 data.cb_user_data = cb_user_data;
387 data.cancellable = cancellable;
388 data.perror = perror;
389
390 data.next_proptag_is_nameid = MAPI_E_RESERVED;
391 data.next_nameid_proptag = MAPI_E_RESERVED;
392 data.object_index = 0;
393 data.objects_total = objects_total;
394 data.marker = 0;
395 data.current_properties = NULL;
396 data.current_streamed_mem_ctx = NULL;
397 data.current_streamed_properties = NULL;
398 data.current_streamed_properties_count = NULL;
399 data.current_object = NULL;
400 data.object = NULL;
401
402 if (!expect_start_message) {
403 data.object_index++;
404 data.object = e_mapi_object_new (data.mem_ctx);
405 data.current_object = data.object;
406 data.current_properties = &data.object->properties;
407 data.current_streamed_mem_ctx = data.object;
408 data.current_streamed_properties = &data.object->streamed_properties;
409 data.current_streamed_properties_count = &data.object->streamed_properties_count;
410 data.marker = StartMessage;
411 }
412
413 parser = fxparser_init (data.mem_ctx, &data);
414 fxparser_set_marker_callback (parser, parse_marker_cb);
415 fxparser_set_delprop_callback (parser, parse_delprop_cb);
416 fxparser_set_namedprop_callback (parser, parse_namedprop_cb);
417 fxparser_set_property_callback (parser, parse_property_cb);
418
419 do {
420 DATA_BLOB transferdata;
421
422 transferdata.data = NULL;
423
424 ms = FXGetBuffer (fasttransfer_ctx, 0, &transferStatus, &stepCount, &totalCount, &transferdata);
425 if (ms != MAPI_E_SUCCESS)
426 break;
427
428 ms = fxparser_parse (parser, &transferdata);
429 talloc_free (transferdata.data);
430 if (ms != MAPI_E_SUCCESS)
431 break;
432
433 if (g_cancellable_is_cancelled (cancellable)) {
434 ms = MAPI_E_USER_CANCEL;
435 break;
436 }
437 } while ((transferStatus == TransferStatus_Partial) || (transferStatus == TransferStatus_NoRoom));
438
439 if (data.object) {
440 e_mapi_object_finish_read (data.object);
441 if (ms == MAPI_E_SUCCESS && !process_parsed_object (&data))
442 ms = MAPI_E_USER_CANCEL;
443
444 e_mapi_object_free (data.object);
445 }
446
447 talloc_free (parser);
448 talloc_free (data.mem_ctx);
449
450 return ms;
451 }
452
453 enum MAPISTATUS
454 e_mapi_fast_transfer_objects (EMapiConnection *conn,
455 TALLOC_CTX *mem_ctx,
456 mapi_object_t *obj_folder,
457 mapi_id_array_t *ids,
458 TransferObjectCB cb,
459 gpointer cb_user_data,
460 GCancellable *cancellable,
461 GError **perror)
462 {
463 enum MAPISTATUS ms;
464 mapi_object_t fasttransfer_ctx;
465
466 mapi_object_init (&fasttransfer_ctx);
467
468 ms = FXCopyMessages (obj_folder, ids, FastTransferCopyMessage_BestBody, FastTransfer_Unicode, &fasttransfer_ctx);
469 if (ms == MAPI_E_SUCCESS)
470 ms = e_mapi_fast_transfer_internal (conn, mem_ctx, cb, cb_user_data, ids->count, TRUE, &fasttransfer_ctx, cancellable, perror);
471
472 mapi_object_release (&fasttransfer_ctx);
473
474 if (perror && !*perror && ms != MAPI_E_SUCCESS)
475 make_mapi_error (perror, G_STRFUNC, ms);
476
477 return ms;
478 }
479
480 enum MAPISTATUS
481 e_mapi_fast_transfer_object (EMapiConnection *conn,
482 TALLOC_CTX *mem_ctx,
483 mapi_object_t *object,
484 guint32 transfer_flags, /* bit or of EMapiFastTransferFlags */
485 TransferObjectCB cb,
486 gpointer cb_user_data,
487 GCancellable *cancellable,
488 GError **perror)
489 {
490 enum MAPISTATUS ms;
491 mapi_object_t fasttransfer_ctx;
492 struct SPropTagArray *excludes = NULL;
493
494 mapi_object_init (&fasttransfer_ctx);
495
496 #define add(x) { \
497 if (!excludes) \
498 excludes = set_SPropTagArray (mem_ctx, 0x1, x); \
499 else \
500 SPropTagArray_add (mem_ctx, excludes, x); \
501 }
502
503 if (!(transfer_flags & E_MAPI_FAST_TRANSFER_FLAG_ATTACHMENTS))
504 add (PidTagMessageAttachments);
505 if (!(transfer_flags & E_MAPI_FAST_TRANSFER_FLAG_RECIPIENTS))
506 add (PidTagMessageRecipients);
507
508 #undef add
509
510 if (!excludes)
511 excludes = talloc_zero (mem_ctx, struct SPropTagArray);
512
513 ms = FXCopyTo (object, 0, FastTransferCopyTo_BestBody, FastTransfer_Unicode, excludes, &fasttransfer_ctx);
514 if (ms == MAPI_E_SUCCESS)
515 ms = e_mapi_fast_transfer_internal (conn, mem_ctx, cb, cb_user_data, 1, FALSE, &fasttransfer_ctx, cancellable, perror);
516
517 mapi_object_release (&fasttransfer_ctx);
518 talloc_free (excludes);
519
520 if (perror && !*perror && ms != MAPI_E_SUCCESS)
521 make_mapi_error (perror, G_STRFUNC, ms);
522
523 return ms;
524 }
525
526 enum MAPISTATUS
527 e_mapi_fast_transfer_properties (EMapiConnection *conn,
528 TALLOC_CTX *mem_ctx,
529 mapi_object_t *object,
530 struct SPropTagArray *tags,
531 TransferObjectCB cb,
532 gpointer cb_user_data,
533 GCancellable *cancellable,
534 GError **perror)
535 {
536 enum MAPISTATUS ms;
537 mapi_object_t fasttransfer_ctx;
538
539 g_return_val_if_fail (tags != NULL, MAPI_E_INVALID_PARAMETER);
540 g_return_val_if_fail (tags->cValues > 0, MAPI_E_INVALID_PARAMETER);
541
542 mapi_object_init (&fasttransfer_ctx);
543
544 ms = FXCopyProperties (object, 0, 0, FastTransfer_Unicode, tags, &fasttransfer_ctx);
545 if (ms == MAPI_E_SUCCESS)
546 ms = e_mapi_fast_transfer_internal (conn, mem_ctx, cb, cb_user_data, 1, FALSE, &fasttransfer_ctx, cancellable, perror);
547
548 mapi_object_release (&fasttransfer_ctx);
549
550 if (perror && !*perror && ms != MAPI_E_SUCCESS)
551 make_mapi_error (perror, G_STRFUNC, ms);
552
553 return ms;
554 }