server: intialize aux_header buffer to null if the data is missing.
[tridge/openchange.git] / branches / plugfest / testprogs / check_fasttransfer.c
1 /*
2    Test fast transfer operations and parser
3
4    OpenChange Project
5
6    Copyright (C) Brad Hards <bradh@openchange.org> 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "libmapi/libmapi.h"
23 #include "mapiproxy/libmapistore/mapistore.h"
24 #include "mapiproxy/libmapistore/mapistore_errors.h"
25
26 #include <samba/popt.h>
27 #include <ldb.h>
28 #include <talloc.h>
29
30 #include <inttypes.h>
31
32 static void popt_openchange_version_callback(poptContext con,
33                                              enum poptCallbackReason reason,
34                                              const struct poptOption *opt,
35                                              const char *arg,
36                                              const void *data)
37 {
38         switch (opt->val) {
39         case 'V':
40                 printf("Version %s\n", OPENCHANGE_VERSION_STRING);
41                 exit (0);
42         }
43 }
44
45 struct poptOption popt_openchange_version[] = {
46         { NULL, '\0', POPT_ARG_CALLBACK, (void *)popt_openchange_version_callback, '\0', NULL, NULL },
47         { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version ", NULL },
48         POPT_TABLEEND
49 };
50
51 #define POPT_OPENCHANGE_VERSION { NULL, 0, POPT_ARG_INCLUDE_TABLE, popt_openchange_version, 0, "Common openchange options:", NULL },
52 #define DEFAULT_PROFDB  "%s/.openchange/profiles.ldb"
53
54 /* These callbacks are for deserialising the fast transfer stream to a mapistore instance */
55 struct parent_fid {
56         struct parent_fid       *prev;
57         struct parent_fid       *next;
58         uint64_t                fid;
59 };
60
61 struct mapistore_output_ctx {
62         struct mapistore_context        *mstore_ctx;
63         uint32_t                        mapistore_context_id;
64         uint64_t                        root_fid;
65         struct parent_fid               *parent_fids; /* stack */
66         uint64_t                        current_id;
67         uint8_t                         current_output_type;
68         struct SRow                     *proplist; /* the properties on the "current" object */
69 };
70
71 static enum MAPISTATUS mapistore_marker(uint32_t marker, void *priv)
72 {
73         struct mapistore_output_ctx *mapistore = priv;
74
75         if (mapistore->proplist) {
76                 struct parent_fid *it;
77                 printf("parent_fids: ");
78                 for (it = mapistore->parent_fids; it->next; it = it->next) {
79                         printf("0x%016"PRIx64",", it->fid);
80                 }
81                 printf("\n");
82                 if (mapistore->current_id == mapistore->root_fid) {
83                         /* This is the top level folder */
84                         mapistore_setprops(mapistore->mstore_ctx, mapistore->mapistore_context_id,
85                                            mapistore->root_fid, mapistore->current_output_type,
86                                            mapistore->proplist);
87                 } else if (mapistore->current_output_type == MAPISTORE_FOLDER) {
88                         struct parent_fid *element = talloc_zero(mapistore->mstore_ctx, struct parent_fid);
89                         mapistore_mkdir(mapistore->mstore_ctx, mapistore->mapistore_context_id,
90                                         mapistore->parent_fids->fid, mapistore->current_id,
91                                         mapistore->proplist);
92                         element->fid = mapistore->current_id;
93                         DLIST_ADD(mapistore->parent_fids, element);
94                 } else {
95                         mapistore_createmessage(mapistore->mstore_ctx, mapistore->mapistore_context_id,
96                                                 mapistore->parent_fids->fid, mapistore->current_id);
97                         mapistore_setprops(mapistore->mstore_ctx, mapistore->mapistore_context_id,
98                                            mapistore->current_id, mapistore->current_output_type,
99                                            mapistore->proplist);
100                         mapistore_savechangesmessage(mapistore->mstore_ctx, mapistore->mapistore_context_id,
101                                                      mapistore->current_id, 0);
102                 }
103                 talloc_free(mapistore->proplist);
104                 mapistore->proplist = 0;
105                 (mapistore->current_id)++;
106         }
107
108         switch (marker) {
109         case PR_START_TOP_FLD:
110         {
111                 /* start collecting properties */
112                 struct SPropValue one_prop;
113                 struct parent_fid *element = talloc_zero(mapistore->mstore_ctx, struct parent_fid);
114                 mapistore->proplist = talloc_zero(mapistore->mstore_ctx, struct SRow);
115                 one_prop.ulPropTag = PR_FID;
116                 one_prop.dwAlignPad = 0;
117                 one_prop.value.d = mapistore->root_fid;
118                 SRow_addprop(mapistore->proplist, one_prop);
119                 one_prop.ulPropTag = PR_FOLDER_TYPE;
120                 one_prop.value.l = MAPISTORE_FOLDER;
121                 SRow_addprop(mapistore->proplist, one_prop);
122                 mapistore->current_id = mapistore->root_fid;
123                 mapistore->parent_fids = talloc_zero(mapistore->mstore_ctx, struct parent_fid);
124                 element->fid = mapistore->current_id;
125                 DLIST_ADD(mapistore->parent_fids, element);
126                 mapistore->current_output_type = MAPISTORE_FOLDER;
127                 break;
128         }
129         case PR_START_SUB_FLD:
130                 mapistore->proplist = talloc_zero(mapistore->mstore_ctx, struct SRow);
131                 mapistore->current_output_type = MAPISTORE_FOLDER;
132                 break;
133         case PR_START_MESSAGE:
134                 mapistore->proplist = talloc_zero(mapistore->mstore_ctx, struct SRow);
135                 mapistore->current_output_type = MAPISTORE_MESSAGE;
136                 break;
137         case PR_START_FAI_MSG:
138         case PR_START_RECIP:
139         case PR_START_EMBED:
140         case PR_NEW_ATTACH:
141                 break;
142         case PR_END_FOLDER:
143                 DLIST_REMOVE(mapistore->parent_fids, mapistore->parent_fids);
144                 break;
145         case PR_END_MESSAGE:
146         case PR_END_RECIP:
147         case PR_END_ATTACH:
148         case PR_END_EMBED:
149                 break;
150         default:
151                 printf("***unhandled *** TODO: Marker: %s (0x%08x)\n", get_proptag_name(marker), marker);
152         }
153         return MAPI_E_SUCCESS;
154 }
155
156 static enum MAPISTATUS mapistore_delprop(uint32_t proptag, void *priv)
157 {
158         printf("TODO: DelProps: 0x%08x (%s)\n", proptag, get_proptag_name(proptag));
159         return MAPI_E_SUCCESS;
160 }
161
162 static enum MAPISTATUS mapistore_namedprop(uint32_t proptag, struct MAPINAMEID nameid, void *priv)
163 {
164         TALLOC_CTX *mem_ctx;
165         // struct mapistore_output_ctx *mapistore = priv;
166         mem_ctx = talloc_init("process_namedprop");
167         printf("TODO: Named Property: 0x%08x has GUID %s and ", proptag, GUID_string(mem_ctx, &(nameid.lpguid)));
168         if (nameid.ulKind == MNID_ID) {
169                 printf("dispId 0x%08x\n", nameid.kind.lid);
170         } else if (nameid.ulKind == MNID_STRING) {
171                 printf("name %s\n", nameid.kind.lpwstr.Name);
172         }
173         talloc_free(mem_ctx);
174         return MAPI_E_SUCCESS;
175 }
176
177 static enum MAPISTATUS mapistore_property(struct SPropValue prop, void *priv)
178 {
179         struct mapistore_output_ctx *mapistore = priv;
180         SRow_addprop(mapistore->proplist, prop);
181         return MAPI_E_SUCCESS;
182 }
183
184 /* These callbacks are for the "dump-data" mode, so they don't do much */
185
186 static enum MAPISTATUS dump_marker(uint32_t marker, void *priv)
187 {
188         printf("Marker: %s (0x%08x)\n", get_proptag_name(marker), marker);
189         return MAPI_E_SUCCESS;
190 }
191
192 static enum MAPISTATUS dump_delprop(uint32_t proptag, void *priv)
193 {
194         printf("DelProps: 0x%08x (%s)\n", proptag, get_proptag_name(proptag));
195         return MAPI_E_SUCCESS;
196 }
197
198 static enum MAPISTATUS dump_namedprop(uint32_t proptag, struct MAPINAMEID nameid, void *priv)
199 {
200         TALLOC_CTX *mem_ctx;
201         mem_ctx = talloc_init("process_namedprop");
202         printf("Named Property: 0x%08x has GUID %s and ", proptag, GUID_string(mem_ctx, &(nameid.lpguid)));
203         if (nameid.ulKind == MNID_ID) {
204                 printf("dispId 0x%08x\n", nameid.kind.lid);
205         } else if (nameid.ulKind == MNID_STRING) {
206                 printf("name %s\n", nameid.kind.lpwstr.Name);
207         }
208         talloc_free(mem_ctx);
209         return MAPI_E_SUCCESS;
210 }
211
212 static enum MAPISTATUS dump_property(struct SPropValue prop, void *priv)
213 {
214         mapidump_SPropValue(prop, "\t");
215         return MAPI_E_SUCCESS;
216 }
217
218 int main(int argc, const char *argv[])
219 {
220         TALLOC_CTX                      *mem_ctx;
221         enum MAPISTATUS                 retval;
222         struct mapi_context             *mapi_ctx;
223         struct mapi_session             *session = NULL;
224         struct mapi_profile             *profile;
225         mapi_object_t                   obj_store;
226         mapi_object_t                   obj_folder;
227         mapi_object_t                   obj_fx_context;
228         mapi_id_t                       id_folder;
229
230         uint16_t                        progressCount;
231         uint16_t                        totalStepCount;
232         int                             transfers = 0;
233         enum TransferStatus             fxTransferStatus;
234         DATA_BLOB                       transferdata;
235         struct fx_parser_context        *parser;
236         struct mapistore_output_ctx     output_ctx;
237         poptContext                     pc;
238         int                             opt;
239         const char                      *opt_profdb = NULL;
240         char                            *opt_profname = NULL;
241         const char                      *opt_password = NULL;
242         uint32_t                        opt_maxsize = 0;
243         const char                      *opt_mapistore = NULL;
244         bool                            opt_showprogress = false;
245         bool                            opt_dumpdata = false;
246         const char                      *opt_debug = NULL;
247
248         enum {OPT_PROFILE_DB=1000, OPT_PROFILE, OPT_PASSWORD, OPT_MAXDATA, OPT_SHOWPROGRESS, OPT_MAPISTORE, OPT_DEBUG, OPT_DUMPDATA};
249
250         struct poptOption long_options[] = {
251                 POPT_AUTOHELP
252                 {"database", 'f', POPT_ARG_STRING, NULL, OPT_PROFILE_DB, "set the profile database path", "PATH"},
253                 {"profile", 'p', POPT_ARG_STRING, NULL, OPT_PROFILE, "set the profile name", "PROFILE"},
254                 {"password", 'P', POPT_ARG_STRING, NULL, OPT_PASSWORD, "set the profile password", "PASSWORD"},
255                 {"maxdata", 0, POPT_ARG_INT, NULL, OPT_MAXDATA, "the maximum transfer data size", "SIZE"},
256                 {"showprogress", 0, POPT_ARG_NONE, NULL, OPT_SHOWPROGRESS, "enable progress display", NULL},
257                 {"mapistore", 0, POPT_ARG_STRING, NULL, OPT_MAPISTORE, "serialise to mapistore", "FILESYSTEM_PATH"},
258                 {"debuglevel", 'd', POPT_ARG_STRING, NULL, OPT_DEBUG, "set the debug level", "LEVEL"},
259                 {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMPDATA, "dump the transfer data", NULL},
260                 POPT_OPENCHANGE_VERSION
261                 { NULL, 0, POPT_ARG_NONE, NULL, 0, NULL, NULL }
262         };
263
264         mem_ctx = talloc_named(NULL, 0, "check_fasttransfer");
265
266         pc = poptGetContext("check_fasttransfer", argc, argv, long_options, 0);
267
268         while ((opt = poptGetNextOpt(pc)) != -1) {
269                 switch (opt) {
270                 case OPT_PROFILE_DB:
271                         opt_profdb = poptGetOptArg(pc);
272                         break;
273                 case OPT_PROFILE:
274                         opt_profname = talloc_strdup(mem_ctx, (char *)poptGetOptArg(pc));
275                         break;
276                 case OPT_PASSWORD:
277                         opt_password = poptGetOptArg(pc);
278                         break;
279                 case OPT_MAXDATA:
280                         opt_maxsize = *poptGetOptArg(pc);
281                         break;
282                 case OPT_SHOWPROGRESS:
283                         opt_showprogress = true;
284                         break;
285                 case OPT_MAPISTORE:
286                         opt_mapistore = poptGetOptArg(pc);
287                         break;
288                 case OPT_DEBUG:
289                         opt_debug = poptGetOptArg(pc);
290                         break;
291                 case OPT_DUMPDATA:
292                         opt_dumpdata = true;
293                         break;
294                 }
295         }
296
297         /**
298          * Sanity checks
299          */
300
301         if (!opt_profdb) {
302                 opt_profdb = talloc_asprintf(mem_ctx, DEFAULT_PROFDB, getenv("HOME"));
303         }
304
305         /**
306          * Initialize MAPI subsystem
307          */
308
309         retval = MAPIInitialize(&mapi_ctx, opt_profdb);
310         if (retval != MAPI_E_SUCCESS) {
311                 mapi_errstr("MAPIInitialize", retval);
312                 exit (1);
313         }
314
315         /* debug options */
316         SetMAPIDumpData(mapi_ctx, opt_dumpdata);
317
318         if (opt_debug) {
319                 SetMAPIDebugLevel(mapi_ctx, atoi(opt_debug));
320         }
321
322         /* if no profile is supplied use the default one */
323         if (!opt_profname) {
324                 retval = GetDefaultProfile(mapi_ctx, &opt_profname);
325                 if (retval != MAPI_E_SUCCESS) {
326                         printf("No profile specified and no default profile found\n");
327                         exit (1);
328                 }
329         }
330
331         retval = MapiLogonEx(mapi_ctx, &session, opt_profname, opt_password);
332         talloc_free(opt_profname);
333         if (retval != MAPI_E_SUCCESS) {
334                 mapi_errstr("MapiLogonEx", retval);
335                 exit (1);
336         }
337         profile = session->profile;
338
339         /* Open the default message store */
340         mapi_object_init(&obj_store);
341         mapi_object_init(&obj_folder);
342         /* mapi_object_init(&obj_table); */
343         mapi_object_init(&obj_fx_context);
344
345         retval = OpenMsgStore(session, &obj_store);
346         if (retval != MAPI_E_SUCCESS) {
347                 mapi_errstr("OpenMsgStore", retval);
348                 exit (1);
349         }
350
351         /* Open the top level folder */
352         retval = GetDefaultFolder(&obj_store, &id_folder, olFolderTopInformationStore);
353         if (retval != MAPI_E_SUCCESS) {
354                 mapi_errstr("GetReceiveFolder", retval);
355                 exit (1);
356         }
357
358         retval = OpenFolder(&obj_store, id_folder, &obj_folder);
359         if (retval != MAPI_E_SUCCESS) {
360                 mapi_errstr("OpenFolder", retval);
361                 exit (1);
362         }
363
364         retval = FXCopyFolder(&obj_folder, FastTransferCopyFolder_CopySubfolders, FastTransfer_Unicode, &obj_fx_context);
365         if (retval != MAPI_E_SUCCESS) {
366                 mapi_errstr("FXCopyFolder", retval);
367                 exit (1);
368         }
369
370         if (opt_mapistore) {
371                 char *root_folder;
372                 // TODO: check the path is valid / exists / can be opened, etc.
373                 // TODO: maybe allow a URI instead of path.
374                 output_ctx.root_fid = 0x0000000000010001;
375                 output_ctx.current_id = output_ctx.root_fid;
376                 root_folder = talloc_asprintf(mem_ctx, "fsocpf://%s/0x%016"PRIx64, opt_mapistore, output_ctx.root_fid);
377                 parser = fxparser_init(mem_ctx, &output_ctx);
378                 retval = mapistore_set_mapping_path(opt_mapistore);
379                 if (retval != MAPISTORE_SUCCESS) {
380                         mapi_errstr("mapistore_set_mapping_path", retval);
381                         exit (1);
382                 }
383
384                 output_ctx.mstore_ctx = mapistore_init(mem_ctx, NULL);
385                 if (!(output_ctx.mstore_ctx)) {
386                         mapi_errstr("mapistore_init", retval);
387                         exit (1);
388                 }
389
390                 retval = mapistore_add_context(output_ctx.mstore_ctx, root_folder, &(output_ctx.mapistore_context_id));
391                 if (retval != MAPISTORE_SUCCESS) {
392                         DEBUG(0, ("%s\n", mapistore_errstr(retval)));
393                         exit (1);
394                 }
395                 
396                 output_ctx.proplist = 0;
397
398                 fxparser_set_marker_callback(parser, mapistore_marker);
399                 fxparser_set_delprop_callback(parser, mapistore_delprop);
400                 fxparser_set_namedprop_callback(parser, mapistore_namedprop);
401                 fxparser_set_property_callback(parser, mapistore_property);
402         } else if (opt_dumpdata) {
403                 parser = fxparser_init(mem_ctx, NULL);
404                 fxparser_set_marker_callback(parser, dump_marker);
405                 fxparser_set_delprop_callback(parser, dump_delprop);
406                 fxparser_set_namedprop_callback(parser, dump_namedprop);
407                 fxparser_set_property_callback(parser, dump_property);
408         } else {
409                 parser = fxparser_init(mem_ctx, NULL);
410         }
411
412         do {
413                 retval = FXGetBuffer(&obj_fx_context, opt_maxsize, &fxTransferStatus, &progressCount, &totalStepCount, &transferdata);
414                 transfers++;
415                 if (retval != MAPI_E_SUCCESS) {
416                         mapi_errstr("FXGetBuffer", retval);
417                         exit (1);
418                 }
419
420                 if (opt_showprogress) {
421                         printf("progress: (%d/%d)\n", progressCount, totalStepCount);
422                         printf("status: 0x%04x\n", fxTransferStatus);
423                 }
424
425                 fxparser_parse(parser, &transferdata);
426         } while ((fxTransferStatus == TransferStatus_Partial) || (fxTransferStatus == TransferStatus_NoRoom));
427
428         printf("total transfers: %i\n", transfers);
429
430         if (opt_mapistore) {
431                 retval = mapistore_del_context(output_ctx.mstore_ctx, output_ctx.mapistore_context_id);
432                 if (retval != MAPISTORE_SUCCESS) {
433                         mapi_errstr("mapistore_del_context", retval);
434                         exit (1);
435                 }
436
437                 retval = mapistore_release(output_ctx.mstore_ctx);
438                 if (retval != MAPISTORE_SUCCESS) {
439                         mapi_errstr("mapistore_release", retval);
440                         exit (1);
441                 }
442         }
443
444         talloc_free(parser);
445
446         mapi_object_release(&obj_fx_context);
447
448         mapi_object_release(&obj_folder);
449         mapi_object_release(&obj_store);
450         MAPIUninitialize(mapi_ctx);
451
452         talloc_free(mem_ctx);
453
454         return 0;
455 }