2 Test fast transfer operations and parser
6 Copyright (C) Brad Hards <bradh@openchange.org> 2010
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.
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.
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/>.
22 #include "libmapi/libmapi.h"
23 #include "mapiproxy/libmapistore/mapistore.h"
24 #include "mapiproxy/libmapistore/mapistore_errors.h"
26 #include <samba/popt.h>
32 static void popt_openchange_version_callback(poptContext con,
33 enum poptCallbackReason reason,
34 const struct poptOption *opt,
40 printf("Version %s\n", OPENCHANGE_VERSION_STRING);
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 },
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"
54 /* These callbacks are for deserialising the fast transfer stream to a mapistore instance */
56 struct parent_fid *prev;
57 struct parent_fid *next;
61 struct mapistore_output_ctx {
62 struct mapistore_context *mstore_ctx;
63 uint32_t mapistore_context_id;
65 struct parent_fid *parent_fids; /* stack */
67 uint8_t current_output_type;
68 struct SRow *proplist; /* the properties on the "current" object */
71 static enum MAPISTATUS mapistore_marker(uint32_t marker, void *priv)
73 struct mapistore_output_ctx *mapistore = priv;
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);
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,
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,
92 element->fid = mapistore->current_id;
93 DLIST_ADD(mapistore->parent_fids, element);
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,
100 mapistore_savechangesmessage(mapistore->mstore_ctx, mapistore->mapistore_context_id,
101 mapistore->current_id, 0);
103 talloc_free(mapistore->proplist);
104 mapistore->proplist = 0;
105 (mapistore->current_id)++;
109 case PR_START_TOP_FLD:
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;
129 case PR_START_SUB_FLD:
130 mapistore->proplist = talloc_zero(mapistore->mstore_ctx, struct SRow);
131 mapistore->current_output_type = MAPISTORE_FOLDER;
133 case PR_START_MESSAGE:
134 mapistore->proplist = talloc_zero(mapistore->mstore_ctx, struct SRow);
135 mapistore->current_output_type = MAPISTORE_MESSAGE;
137 case PR_START_FAI_MSG:
143 DLIST_REMOVE(mapistore->parent_fids, mapistore->parent_fids);
151 printf("***unhandled *** TODO: Marker: %s (0x%08x)\n", get_proptag_name(marker), marker);
153 return MAPI_E_SUCCESS;
156 static enum MAPISTATUS mapistore_delprop(uint32_t proptag, void *priv)
158 printf("TODO: DelProps: 0x%08x (%s)\n", proptag, get_proptag_name(proptag));
159 return MAPI_E_SUCCESS;
162 static enum MAPISTATUS mapistore_namedprop(uint32_t proptag, struct MAPINAMEID nameid, void *priv)
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);
173 talloc_free(mem_ctx);
174 return MAPI_E_SUCCESS;
177 static enum MAPISTATUS mapistore_property(struct SPropValue prop, void *priv)
179 struct mapistore_output_ctx *mapistore = priv;
180 SRow_addprop(mapistore->proplist, prop);
181 return MAPI_E_SUCCESS;
184 /* These callbacks are for the "dump-data" mode, so they don't do much */
186 static enum MAPISTATUS dump_marker(uint32_t marker, void *priv)
188 printf("Marker: %s (0x%08x)\n", get_proptag_name(marker), marker);
189 return MAPI_E_SUCCESS;
192 static enum MAPISTATUS dump_delprop(uint32_t proptag, void *priv)
194 printf("DelProps: 0x%08x (%s)\n", proptag, get_proptag_name(proptag));
195 return MAPI_E_SUCCESS;
198 static enum MAPISTATUS dump_namedprop(uint32_t proptag, struct MAPINAMEID nameid, void *priv)
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);
208 talloc_free(mem_ctx);
209 return MAPI_E_SUCCESS;
212 static enum MAPISTATUS dump_property(struct SPropValue prop, void *priv)
214 mapidump_SPropValue(prop, "\t");
215 return MAPI_E_SUCCESS;
218 int main(int argc, const char *argv[])
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;
230 uint16_t progressCount;
231 uint16_t totalStepCount;
233 enum TransferStatus fxTransferStatus;
234 DATA_BLOB transferdata;
235 struct fx_parser_context *parser;
236 struct mapistore_output_ctx output_ctx;
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;
248 enum {OPT_PROFILE_DB=1000, OPT_PROFILE, OPT_PASSWORD, OPT_MAXDATA, OPT_SHOWPROGRESS, OPT_MAPISTORE, OPT_DEBUG, OPT_DUMPDATA};
250 struct poptOption long_options[] = {
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 }
264 mem_ctx = talloc_named(NULL, 0, "check_fasttransfer");
266 pc = poptGetContext("check_fasttransfer", argc, argv, long_options, 0);
268 while ((opt = poptGetNextOpt(pc)) != -1) {
271 opt_profdb = poptGetOptArg(pc);
274 opt_profname = talloc_strdup(mem_ctx, (char *)poptGetOptArg(pc));
277 opt_password = poptGetOptArg(pc);
280 opt_maxsize = *poptGetOptArg(pc);
282 case OPT_SHOWPROGRESS:
283 opt_showprogress = true;
286 opt_mapistore = poptGetOptArg(pc);
289 opt_debug = poptGetOptArg(pc);
302 opt_profdb = talloc_asprintf(mem_ctx, DEFAULT_PROFDB, getenv("HOME"));
306 * Initialize MAPI subsystem
309 retval = MAPIInitialize(&mapi_ctx, opt_profdb);
310 if (retval != MAPI_E_SUCCESS) {
311 mapi_errstr("MAPIInitialize", retval);
316 SetMAPIDumpData(mapi_ctx, opt_dumpdata);
319 SetMAPIDebugLevel(mapi_ctx, atoi(opt_debug));
322 /* if no profile is supplied use the default one */
324 retval = GetDefaultProfile(mapi_ctx, &opt_profname);
325 if (retval != MAPI_E_SUCCESS) {
326 printf("No profile specified and no default profile found\n");
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);
337 profile = session->profile;
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);
345 retval = OpenMsgStore(session, &obj_store);
346 if (retval != MAPI_E_SUCCESS) {
347 mapi_errstr("OpenMsgStore", retval);
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);
358 retval = OpenFolder(&obj_store, id_folder, &obj_folder);
359 if (retval != MAPI_E_SUCCESS) {
360 mapi_errstr("OpenFolder", retval);
364 retval = FXCopyFolder(&obj_folder, FastTransferCopyFolder_CopySubfolders, FastTransfer_Unicode, &obj_fx_context);
365 if (retval != MAPI_E_SUCCESS) {
366 mapi_errstr("FXCopyFolder", retval);
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);
384 output_ctx.mstore_ctx = mapistore_init(mem_ctx, NULL);
385 if (!(output_ctx.mstore_ctx)) {
386 mapi_errstr("mapistore_init", retval);
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)));
396 output_ctx.proplist = 0;
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);
409 parser = fxparser_init(mem_ctx, NULL);
413 retval = FXGetBuffer(&obj_fx_context, opt_maxsize, &fxTransferStatus, &progressCount, &totalStepCount, &transferdata);
415 if (retval != MAPI_E_SUCCESS) {
416 mapi_errstr("FXGetBuffer", retval);
420 if (opt_showprogress) {
421 printf("progress: (%d/%d)\n", progressCount, totalStepCount);
422 printf("status: 0x%04x\n", fxTransferStatus);
425 fxparser_parse(parser, &transferdata);
426 } while ((fxTransferStatus == TransferStatus_Partial) || (fxTransferStatus == TransferStatus_NoRoom));
428 printf("total transfers: %i\n", transfers);
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);
437 retval = mapistore_release(output_ctx.mstore_ctx);
438 if (retval != MAPISTORE_SUCCESS) {
439 mapi_errstr("mapistore_release", retval);
446 mapi_object_release(&obj_fx_context);
448 mapi_object_release(&obj_folder);
449 mapi_object_release(&obj_store);
450 MAPIUninitialize(mapi_ctx);
452 talloc_free(mem_ctx);