2 OpenChange MAPI implementation.
4 Copyright (C) Julien Kerihuel 2007-2008.
5 Copyright (C) Fabien Le Mentec 2007.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <libmapi/libmapi.h>
22 #include <libmapi/proto_private.h>
23 #include <credentials.h>
24 #include <ldb_errors.h>
30 \brief MAPI Profiles interface
38 * Load a MAPI profile into a mapi_profile struct
40 static enum MAPISTATUS ldb_load_profile(TALLOC_CTX *mem_ctx,
41 struct ldb_context *ldb_ctx,
42 struct mapi_profile *profile,
43 const char *profname, const char *password)
46 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
47 struct ldb_result *res;
48 struct ldb_message *msg;
49 const char * const attrs[] = { "*", NULL };
51 /* fills in profile name */
52 profile->profname = talloc_strdup(mem_ctx, profname);
53 if (!profile->profname) return MAPI_E_NOT_ENOUGH_RESOURCES;
56 ldb_ctx = global_mapi_ctx->ldb_ctx;
58 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profile->profname);
59 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
61 /* profile not found */
62 if (!res->count) return MAPI_E_NOT_FOUND;
63 /* more than one profile */
64 if (res->count > 1) return MAPI_E_COLLISION;
66 /* fills in profile with query result */
69 profile->username = ldb_msg_find_attr_as_string(msg, "username", NULL);
70 profile->password = password ? password : ldb_msg_find_attr_as_string(msg, "password", "");
71 profile->workstation = ldb_msg_find_attr_as_string(msg, "workstation", NULL);
72 profile->realm = ldb_msg_find_attr_as_string(msg, "realm", NULL);
73 profile->domain = ldb_msg_find_attr_as_string(msg, "domain", NULL);
74 profile->mailbox = ldb_msg_find_attr_as_string(msg, "EmailAddress", NULL);
75 profile->homemdb = ldb_msg_find_attr_as_string(msg, "HomeMDB", NULL);
76 profile->server = ldb_msg_find_attr_as_string(msg, "binding", NULL);
77 profile->org = ldb_msg_find_attr_as_string(msg, "Organization", NULL);
78 profile->ou = ldb_msg_find_attr_as_string(msg, "OrganizationUnit", NULL);
79 profile->codepage = ldb_msg_find_attr_as_int(msg, "codepage", 0);
80 profile->language = ldb_msg_find_attr_as_int(msg, "language", 0);
81 profile->method = ldb_msg_find_attr_as_int(msg, "method", 0);
83 if (!profile->password) return MAPI_E_INVALID_PARAMETER;
85 return MAPI_E_SUCCESS;
89 * Search for and attribute within profiles
91 static enum MAPISTATUS ldb_clear_default_profile(TALLOC_CTX *mem_ctx)
93 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
94 struct ldb_context *ldb_ctx;
95 struct ldb_dn *basedn;
96 struct ldb_message *msg;
97 struct ldb_result *res;
98 const char *attrs[] = { "PR_DEFAULT_PROFILE", NULL };
102 ldb_ctx = global_mapi_ctx->ldb_ctx;
104 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
105 ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, scope, attrs, "(cn=*)");
107 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
108 if (!res->count) return MAPI_E_NOT_FOUND;
110 for (i = 0; i < res->count; i++) {
111 struct ldb_message *message;
114 if (msg->num_elements == 1) {
115 message = talloc_steal(mem_ctx, msg);
116 message->elements[0].flags = LDB_FLAG_MOD_DELETE;
118 ret = ldb_modify(ldb_ctx, message);
119 talloc_free(message);
123 return MAPI_E_SUCCESS;
127 * Test if the password is correct
129 static enum MAPISTATUS ldb_test_password(TALLOC_CTX *mem_ctx, const char *profile,
130 const char *password)
132 enum ldb_scope scope = LDB_SCOPE_DEFAULT;
133 struct ldb_context *ldb_ctx;
134 struct ldb_message *msg;
135 struct ldb_result *res;
136 const char *attrs[] = {"cn", "password", NULL };
137 const char *ldb_password;
140 ldb_ctx = global_mapi_ctx->ldb_ctx;
142 ret = ldb_search(ldb_ctx, mem_ctx, &res, NULL, scope, attrs,
143 "(cn=%s)(cn=Profiles)", profile);
145 if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
146 if (!res->count) return MAPI_E_NOT_FOUND;
150 ldb_password = ldb_msg_find_attr_as_string(msg, "password", NULL);
151 if (!ldb_password) return MAPI_E_NO_SUPPORT;
152 if (strncmp(password, ldb_password, strlen(password))) return MAPI_E_LOGON_FAILED;
154 return MAPI_E_SUCCESS;
159 * Add a profile to the database with default fields
161 static enum MAPISTATUS ldb_create_profile(TALLOC_CTX *mem_ctx,
162 struct ldb_context *ldb_ctx,
163 const char *profname)
165 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
166 struct ldb_message msg;
167 struct ldb_message_element el[2];
168 struct ldb_val vals[2][1];
169 struct ldb_result *res;
170 struct ldb_dn *basedn;
173 const char * const attrs[] = { "*", NULL };
176 if (profname == NULL)
177 return MAPI_E_BAD_VALUE;
179 /* Does the profile already exists? */
180 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx),
181 scope, attrs, "(cn=%s)(cn=Profiles)", profname);
182 if (res->msgs) return MAPI_E_NO_ACCESS;
185 * We now prepare the entry for transaction
188 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
189 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
191 if (!ldb_dn_validate(basedn)) return MAPI_E_BAD_VALUE;
193 msg.dn = ldb_dn_copy(mem_ctx, basedn);
194 msg.num_elements = 2;
198 el[0].name = talloc_strdup(mem_ctx, "cn");
199 el[0].num_values = 1;
200 el[0].values = vals[0];
201 vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, profname);
202 vals[0][0].length = strlen(profname);
205 el[1].name = talloc_strdup(mem_ctx, "name");
206 el[1].num_values = 1;
207 el[1].values = vals[1];
208 vals[1][0].data = (uint8_t *)talloc_strdup(mem_ctx, profname);
209 vals[1][0].length = strlen(profname);
211 ret = ldb_add(ldb_ctx, &msg);
213 if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
215 return MAPI_E_SUCCESS;
219 * delete the current profile
221 static enum MAPISTATUS ldb_delete_profile(TALLOC_CTX *mem_ctx,
222 struct ldb_context *ldb_ctx,
223 const char *profname)
225 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
226 struct ldb_result *res;
227 const char * const attrs[] = { "*", NULL };
230 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
231 if (!res->msgs) return MAPI_E_NOT_FOUND;
233 ret = ldb_delete(ldb_ctx, res->msgs[0]->dn);
234 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
236 return MAPI_E_SUCCESS;
244 \details Add an attribute to the profile
246 _PUBLIC_ enum MAPISTATUS mapi_profile_add_string_attr(const char *profile,
251 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
252 struct ldb_message msg;
253 struct ldb_message_element el[1];
254 struct ldb_val vals[1][1];
255 struct ldb_result *res;
256 struct ldb_context *ldb_ctx;
257 struct ldb_dn *basedn;
260 const char * const attrs[] = { "*", NULL };
262 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
263 MAPI_RETVAL_IF(!global_mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
264 MAPI_RETVAL_IF(!profile, MAPI_E_BAD_VALUE, NULL);
265 MAPI_RETVAL_IF(!value, MAPI_E_INVALID_PARAMETER, NULL);
267 mem_ctx = talloc_init("mapi_profile_add_string_attr");
268 ldb_ctx = global_mapi_ctx->ldb_ctx;
270 /* Retrieve the profile from the database */
271 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profile);
272 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
274 /* Preparing for the transaction */
275 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profile);
276 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
278 MAPI_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
280 msg.dn = ldb_dn_copy(mem_ctx, basedn);
281 msg.num_elements = 1;
284 el[0].flags = LDB_FLAG_MOD_ADD;
285 el[0].name = talloc_strdup(mem_ctx, attr);
286 el[0].num_values = 1;
287 el[0].values = vals[0];
288 vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
289 vals[0][0].length = strlen(value);
291 ret = ldb_modify(ldb_ctx, &msg);
292 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
294 talloc_free(mem_ctx);
295 return MAPI_E_SUCCESS;
299 \details Modify an attribute
301 _PUBLIC_ enum MAPISTATUS mapi_profile_modify_string_attr(const char *profname,
306 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
307 struct ldb_message msg;
308 struct ldb_message_element el[1];
309 struct ldb_val vals[1][1];
310 struct ldb_result *res;
311 struct ldb_context *ldb_ctx;
312 struct ldb_dn *basedn;
315 const char * const attrs[] = { "*", NULL };
317 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
318 MAPI_RETVAL_IF(!profname, MAPI_E_BAD_VALUE, NULL);
320 ldb_ctx = global_mapi_ctx->ldb_ctx;
321 mem_ctx = talloc_init("mapi_profile_modify_string_attr");
323 /* Retrieve the profile from the database */
324 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
325 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
327 /* Preparing for the transaction */
328 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
329 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
331 MAPI_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
333 msg.dn = ldb_dn_copy(mem_ctx, basedn);
334 msg.num_elements = 1;
337 el[0].flags = LDB_FLAG_MOD_REPLACE;
338 el[0].name = talloc_strdup(mem_ctx, attr);
339 el[0].num_values = 1;
340 el[0].values = vals[0];
341 vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
342 vals[0][0].length = strlen(value);
344 ret = ldb_modify(ldb_ctx, &msg);
345 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
347 talloc_free(mem_ctx);
349 return MAPI_E_SUCCESS;
353 \details Delete an attribute
355 _PUBLIC_ enum MAPISTATUS mapi_profile_delete_string_attr(const char *profname,
360 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
361 struct ldb_message msg;
362 struct ldb_message_element el[1];
363 struct ldb_val vals[1][1];
364 struct ldb_result *res;
365 struct ldb_context *ldb_ctx;
366 struct ldb_dn *basedn;
369 const char * const attrs[] = { "*", NULL };
371 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
372 MAPI_RETVAL_IF(!profname, MAPI_E_BAD_VALUE, NULL);
374 ldb_ctx = global_mapi_ctx->ldb_ctx;
375 mem_ctx = talloc_init("mapi_profile_delete_string_attr");
377 /* Retrieve the profile from the database */
378 ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
379 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
381 /* Preparing for the transaction */
382 dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
383 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
385 MAPI_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
387 msg.dn = ldb_dn_copy(mem_ctx, basedn);
388 msg.num_elements = 1;
391 el[0].flags = LDB_FLAG_MOD_DELETE;
392 el[0].name = talloc_strdup(mem_ctx, attr);
393 el[0].num_values = 1;
394 el[0].values = vals[0];
395 vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
396 vals[0][0].length = strlen(value);
398 ret = ldb_modify(ldb_ctx, &msg);
399 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
401 talloc_free(mem_ctx);
403 return MAPI_E_SUCCESS;
407 * Private function which opens the profile store
408 * Should only be called within MAPIInitialize
410 enum MAPISTATUS OpenProfileStore(TALLOC_CTX *mem_ctx, struct ldb_context **ldb_ctx,
411 const char *profiledb)
414 struct ldb_context *tmp_ctx;
415 struct event_context *ev;
420 if (!profiledb) return MAPI_E_NOT_FOUND;
422 ev = event_context_init(mem_ctx);
423 if (!ev) return MAPI_E_NOT_ENOUGH_RESOURCES;
425 /* connect to the store */
426 tmp_ctx = ldb_init(mem_ctx, ev);
427 if (!tmp_ctx) return MAPI_E_NOT_ENOUGH_RESOURCES;
429 ret = ldb_connect(tmp_ctx, profiledb, 0, NULL);
430 if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
433 return MAPI_E_SUCCESS;
438 \details Get default ldif_path
440 This function returns the path for the default LDIF files.
442 \sa CreateProfileStore
444 _PUBLIC_ const char *mapi_profile_get_ldif_path(void)
451 \details Create a profile database
453 This function creates a new profile database, including doing an
456 \param profiledb the absolute path to the profile database intended
458 \param ldif_path the absolute path to the LDIF information to use
461 \return MAPI_E_SUCCESS on success, otherwise -1.
463 \note Developers should call GetLastError() to retrieve the last
464 MAPI error code. Possible MAPI error codes are:
465 - MAPI_E_CALL_FAILED: profiledb or ldif_path is not set
466 - MAPI_E_NOT_ENOUGH_RESOURCES: ldb subsystem initialization failed
467 - MAPI_E_NO_ACCESS: connection or ldif add failed
469 \sa GetLastError, mapi_profile_get_ldif_path
471 _PUBLIC_ enum MAPISTATUS CreateProfileStore(const char *profiledb, const char *ldif_path)
475 struct ldb_context *ldb_ctx;
476 struct ldb_ldif *ldif;
478 char *filename = NULL;
480 struct event_context *ev;
482 MAPI_RETVAL_IF(!profiledb, MAPI_E_CALL_FAILED, NULL);
483 MAPI_RETVAL_IF(!ldif_path, MAPI_E_CALL_FAILED, NULL);
485 mem_ctx = talloc_init("CreateProfileStore");
487 ev = event_context_init(mem_ctx);
488 MAPI_RETVAL_IF(!ev, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
490 ldb_ctx = ldb_init(mem_ctx, ev);
491 MAPI_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
493 url = talloc_asprintf(mem_ctx, "tdb://%s", profiledb);
494 ret = ldb_connect(ldb_ctx, url, 0, 0);
496 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_ACCESS, mem_ctx);
498 filename = talloc_asprintf(mem_ctx, "%s/oc_profiles_init.ldif", ldif_path);
499 f = fopen(filename, "r");
500 MAPI_RETVAL_IF(!f, MAPI_E_NO_ACCESS, mem_ctx);
501 talloc_free(filename);
503 while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
504 ldif->msg = ldb_msg_canonicalize(ldb_ctx, ldif->msg);
505 ret = ldb_add(ldb_ctx, ldif->msg);
506 if (ret != LDB_SUCCESS) {
508 MAPI_RETVAL_IF("ldb_ldif_read_file", MAPI_E_NO_ACCESS, mem_ctx);
510 ldb_ldif_read_free(ldb_ctx, ldif);
514 filename = talloc_asprintf(mem_ctx, "%s/oc_profiles_schema.ldif", ldif_path);
515 f = fopen(filename, "r");
516 MAPI_RETVAL_IF(!f, MAPI_E_NO_ACCESS, mem_ctx);
518 talloc_free(filename);
519 while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
520 ldif->msg = ldb_msg_canonicalize(ldb_ctx, ldif->msg);
521 ret = ldb_add(ldb_ctx, ldif->msg);
522 if (ret != LDB_SUCCESS) {
524 MAPI_RETVAL_IF("ldb_ldif_read_file", MAPI_E_NO_ACCESS, mem_ctx);
527 ldb_ldif_read_free(ldb_ctx, ldif);
531 talloc_free(mem_ctx);
533 return MAPI_E_SUCCESS;
538 \details Load a profile from the database
540 This function opens a named profile from the database, and fills
541 the mapi_profile structure with common profile information.
543 \param profile the resulting profile
544 \param profname the name of the profile to open
545 \param password the password to use with the profile
547 \return MAPI_E_SUCCESS on success, otherwise -1.
549 \note Developers should call GetLastError() to retrieve the last
550 MAPI error code. Possible MAPI error codes are:
551 - MAPI_E_NOT_ENOUGH_RESOURCES: ldb subsystem initialization failed
552 - MAPI_E_NOT_FOUND: the profile was not found in the profile
554 - MAPI_E_COLLISION: profname matched more than one entry
556 \sa MAPIInitialize, GetLastError
558 _PUBLIC_ enum MAPISTATUS OpenProfile(struct mapi_profile *profile, const char *profname, const char *password)
561 enum MAPISTATUS retval;
563 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
565 mem_ctx = (TALLOC_CTX *) global_mapi_ctx->session;
567 /* find the profile in ldb store */
568 retval = ldb_load_profile(mem_ctx, global_mapi_ctx->ldb_ctx, profile, profname, password);
570 MAPI_RETVAL_IF(retval, retval, NULL);
572 return MAPI_E_SUCCESS;
576 \details Load a MAPI Profile and sets its credentials
578 This function loads a named MAPI profile and sets the MAPI session
581 \return MAPI_E_SUCCESS on success, otherwise -1.
583 \note Developers should call GetLastError() to retrieve the last
584 MAPI error code. Possible MAPI error codes are:
585 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
586 - MAPI_E_INVALID_PARAMETER: The profile parameter is not
588 - MAPI_E_NOT_ENOUGH_RESOURCES: MAPI subsystem failed to allocate
589 the necessary resources to perform the operation
591 \sa OpenProfile, GetLastError
593 _PUBLIC_ enum MAPISTATUS LoadProfile(struct mapi_profile *profile)
597 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
598 MAPI_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
600 mem_ctx = (TALLOC_CTX *) global_mapi_ctx->session;
602 profile->credentials = cli_credentials_init(mem_ctx);
603 MAPI_RETVAL_IF(!profile->credentials, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
604 cli_credentials_set_username(profile->credentials, profile->username, CRED_SPECIFIED);
605 cli_credentials_set_password(profile->credentials, profile->password, CRED_SPECIFIED);
606 cli_credentials_set_workstation(profile->credentials, profile->workstation, CRED_SPECIFIED);
607 cli_credentials_set_realm(profile->credentials, profile->realm, CRED_SPECIFIED);
608 cli_credentials_set_domain(profile->credentials, profile->domain, CRED_SPECIFIED);
610 return MAPI_E_SUCCESS;
614 \details Release a profile
616 This function releases the credentials associated with the profile.
618 \param profile the profile to release.
620 \return MAPI_E_SUCCESS on success, otherwise -1.
622 \note Developers should call GetLastError() to retrieve the last
623 MAPI error code. Possible MAPI error codes are:
624 - MAPI_E_INVALID_PARAMETER: The profile parameter was not set or
627 _PUBLIC_ enum MAPISTATUS ShutDown(struct mapi_profile *profile)
629 MAPI_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
631 if (profile->credentials)
632 talloc_free(profile->credentials);
633 return MAPI_E_SUCCESS;
638 \details Create a profile in the MAPI profile database
640 This function creates a profile named \a profile in the MAPI profile
641 database and sets the specified username in that profile.
643 This function may also set the password. If the flags include
644 OC_PROFILE_NOPASSWORD then the password will not be set. Otherwise,
645 the specified password argument will also be saved to the profile.
647 \param profile the name of the profile
648 \param username the username of the profile
649 \param password the password for the profile (if used)
650 \param flag the union of the flags.
652 \return MAPI_E_SUCCESS on success, otherwise -1.
654 \note Developers should call GetLastError() to retrieve the last
655 MAPI error code. Possible MAPI error codes are:
656 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
657 initialized. The MAPI subsystem must be initialized (using
658 MAPIInitialize) prior to creating a profile.
659 - MAPI_E_NOT_ENOUGH_RESOURCES: MAPI subsystem failed to allocate
660 the necessary resources to operate properly
661 - MAPI_E_NO_SUPPORT: An error was encountered while setting the
662 MAPI profile attributes in the database.
664 \note profile information (including the password, if saved to the
665 profile) is stored unencrypted.
667 \sa DeleteProfile, SetDefaultProfile, GetDefaultProfile,
668 ChangeProfilePassword, GetProfileTable, ProcessNetworkProfile,
671 _PUBLIC_ enum MAPISTATUS CreateProfile(const char *profile, const char *username,
672 const char *password, uint32_t flag)
674 enum MAPISTATUS retval;
677 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
679 mem_ctx = talloc_init("CreateProfile");
680 retval = ldb_create_profile(mem_ctx, global_mapi_ctx->ldb_ctx, profile);
681 MAPI_RETVAL_IF(retval, retval, mem_ctx);
683 retval = mapi_profile_add_string_attr(profile, "username", username);
684 if (flag != OC_PROFILE_NOPASSWORD) {
685 retval = mapi_profile_add_string_attr(profile, "password", password);
687 talloc_free(mem_ctx);
694 \details Delete a profile from the MAPI profile database
696 \param profile the name of the profile to delete
698 \return MAPI_E_SUCCESS on success, otherwise -1.
700 \note Developers should call GetLastError() to retrieve the last
701 MAPI error code. Possible MAPI error codes are:
702 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
703 initialized. The MAPI subsystem must be initialized (using
704 MAPIInitialize) prior to creating a profile.
705 - MAPI_E_NOT_FOUND: The profile was not found in the database.
707 \sa CreateProfile, ChangeProfilePassword, GetProfileTable,
708 GetProfileAttr, ProcessNetworkProfile, GetLastError
710 _PUBLIC_ enum MAPISTATUS DeleteProfile(const char *profile)
713 enum MAPISTATUS retval;
715 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
717 mem_ctx = talloc_init("DeleteProfile");
718 retval = ldb_delete_profile(mem_ctx, global_mapi_ctx->ldb_ctx, profile);
719 MAPI_RETVAL_IF(retval, retval, mem_ctx);
720 talloc_free(mem_ctx);
727 \details Change the profile password of an existing MAPI profile
729 \param profile the name of the profile to have its password changed
730 \param old_password the old password
731 \param password the new password
733 \return MAPI_E_SUCCESS on success, otherwise -1.
735 \note Developers should call GetLastError() to retrieve the last
736 MAPI error code. Possible MAPI error codes are:
737 - MAPI_E_INVALID_PARAMETER: One of the following argument was not
738 set: profile, old_password, password
739 - MAPI_E_NOT_FOUND: The profile was not found in the database
741 \sa CreateProfile, GetProfileTable, GetProfileAttr,
742 ProcessNetworkProfile, GetLastError
744 _PUBLIC_ enum MAPISTATUS ChangeProfilePassword(const char *profile,
745 const char *old_password,
746 const char *password)
749 enum MAPISTATUS retval;
751 if (!profile || !old_password | !password) return MAPI_E_INVALID_PARAMETER;
753 mem_ctx = talloc_init("ChangeProfilePassword");
755 retval = ldb_test_password(mem_ctx, profile, password);
756 MAPI_RETVAL_IF(retval, retval, mem_ctx);
758 retval = mapi_profile_modify_string_attr(profile, "password", password);
760 talloc_free(mem_ctx);
767 _PUBLIC_ enum MAPISTATUS CopyProfile(const char *old_profile,
768 const char *password,
774 return MAPI_E_SUCCESS;
775 /* return MAPI_E_LOGON_FAILED => auth failure */
776 /* return MAPI_E_ACCESS_DENIED => the new profile already exists */
777 /* return MAPI_E_NOT_FOUND => old profile doesn't exist */
783 _PUBLIC_ enum MAPISTATUS RenameProfile(const char *old_profile,
784 const char *password,
790 return MAPI_E_SUCCESS;
791 /* return MAPI_E_LOGON_FAILED => auth failure*/
796 \details Set a default profile for the database
798 \param profname the name of the profile to make the default profile
800 \return MAPI_E_SUCCESS on success, otherwise -1.
802 \note Developers should call GetLastError() to retrieve the last
803 MAPI error code. Possible MAPI error codes are:
804 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
805 - MAPI_E_INVALID_PARAMETER: The profile parameter was not set
807 - MAPI_E_NOT_FOUND: The profile was not found in the database
809 \sa GetDefaultProfile, GetProfileTable, GetLastError
811 _PUBLIC_ enum MAPISTATUS SetDefaultProfile(const char *profname)
814 struct mapi_profile profile;
815 enum MAPISTATUS retval;
817 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
818 MAPI_RETVAL_IF(!profname, MAPI_E_INVALID_PARAMETER, NULL);
820 mem_ctx = talloc_init("SetDefaultProfile");
823 retval = ldb_load_profile(mem_ctx, global_mapi_ctx->ldb_ctx, &profile, profname, NULL);
824 MAPI_RETVAL_IF(retval && retval != MAPI_E_INVALID_PARAMETER, retval, mem_ctx);
826 /* search any previous default profile and unset it */
827 retval = ldb_clear_default_profile(mem_ctx);
829 /* set profname as the default profile */
830 retval = mapi_profile_modify_string_attr(profname, "PR_DEFAULT_PROFILE", "1");
832 talloc_free(mem_ctx);
839 \details Get the default profile from the database
841 \param profname the result of the function (name of the default
844 \return MAPI_E_SUCCESS on success, otherwise -1.
846 \note Developers should call GetLastError() to retrieve the last
847 MAPI error code. Possible MAPI error codes are:
848 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
849 - MAPI_E_NOT_FOUND: The profile was not found in the database
851 \sa SetDefaultProfile, GetProfileTable, GetLastError
853 _PUBLIC_ enum MAPISTATUS GetDefaultProfile(const char **profname)
855 enum MAPISTATUS retval;
856 struct SRowSet proftable;
857 struct SPropValue *lpProp;
861 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
863 retval = GetProfileTable(&proftable);
865 for (i = 0; i < proftable.cRows; i++) {
866 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DEFAULT_PROFILE);
867 if (lpProp && (lpProp->value.l == 1)) {
868 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DISPLAY_NAME);
870 *profname = lpProp->value.lpszA;
871 talloc_free(proftable.aRow);
872 return MAPI_E_SUCCESS;
877 MAPI_RETVAL_IF("GetDefaultProfile", MAPI_E_NOT_FOUND, proftable.aRow);
881 \details Retrieve a pointer on the mapi_profile structure used in
884 _PUBLIC_ enum MAPISTATUS GetProfilePtr(struct mapi_profile *profile)
886 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
888 profile = global_mapi_ctx->session->profile;
890 return MAPI_E_SUCCESS;
895 \details Retrieve the profile table
897 This function retrieves the profile table. Two fields are returned:
898 - PR_DISPLAY_NAME: The profile name stored as a UTF8 string
899 - PR_DEFAULT_PROFILE: Whether the profile is the default one(1) or
900 not(0), stored as an integer
902 \param proftable the result of the call
904 \return MAPI_E_SUCCESS on success, otherwise -1.
906 \note Developers should call GetLastError() to retrieve the last
907 MAPI error code. Possible MAPI error codes are:
908 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
909 - MAPI_E_NOT_FOUND: The profile was not found in the database
911 \sa SetDefaultProfile, GetProfileTable, GetLastError
913 _PUBLIC_ enum MAPISTATUS GetProfileTable(struct SRowSet *proftable)
916 enum ldb_scope scope = LDB_SCOPE_SUBTREE;
917 struct ldb_context *ldb_ctx;
918 struct ldb_result *res;
919 struct ldb_message *msg;
920 struct ldb_dn *basedn;
921 const char *attrs[] = {"cn", "PR_DEFAULT_PROFILE", NULL};
925 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
927 ldb_ctx = global_mapi_ctx->ldb_ctx;
928 mem_ctx = (TALLOC_CTX *)ldb_ctx;
930 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
931 ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, scope, attrs, "(cn=*)");
932 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
935 proftable->cRows = res->count;
936 proftable->aRow = talloc_array(mem_ctx, struct SRow, res->count);
938 /* Build Arow array */
939 for (count = 0; count < res->count; count++) {
940 msg = res->msgs[count];
942 proftable->aRow[count].lpProps = talloc_array(mem_ctx, struct SPropValue, 2);
943 proftable->aRow[count].cValues = 2;
945 proftable->aRow[count].lpProps[0].ulPropTag = PR_DISPLAY_NAME;
946 proftable->aRow[count].lpProps[0].value.lpszA = ldb_msg_find_attr_as_string(msg, "cn", NULL);
948 proftable->aRow[count].lpProps[1].ulPropTag = PR_DEFAULT_PROFILE;
949 proftable->aRow[count].lpProps[1].value.l = ldb_msg_find_attr_as_int(msg, "PR_DEFAULT_PROFILE", 0);
952 return MAPI_E_SUCCESS;
957 \details Retrieve attribute values from a profile
959 This function retrieves all the attribute values from the given
960 profile. The number of results is stored in \a count and values
961 are stored in an allocated string array in the \a value parameter
962 that needs to be free'd using MAPIFreeBuffer().
964 \param profile the name of the profile to retrieve attributes from
965 \param attribute the attribute(s) to search for
966 \param count the number of results
967 \param value the resulting values
969 \return MAPI_E_SUCCESS on success, otherwise -1.
971 \note Developers should call GetLastError() to retrieve the last
972 MAPI error code. Possible MAPI error codes are:
973 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
974 - MAPI_E_INVALID_PARAMETER: Either profile or attribute was not set
976 - MAPI_E_NOT_FOUND: The profile was not found in the database
978 \sa SetDefaultProfile, GetDefaultProfile, MAPIFreeBuffer,
979 GetProfileTable, GetLastError
981 _PUBLIC_ enum MAPISTATUS GetProfileAttr(struct mapi_profile *profile,
982 const char *attribute,
987 struct ldb_context *ldb_ctx;
988 struct ldb_result *res;
989 struct ldb_message *msg;
990 struct ldb_message_element *ldb_element;
991 struct ldb_dn *basedn;
992 const char *attrs[] = {"*", NULL};
996 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
997 MAPI_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
998 MAPI_RETVAL_IF(!attribute, MAPI_E_INVALID_PARAMETER, NULL);
1000 mem_ctx = (TALLOC_CTX *)global_mapi_ctx->ldb_ctx;
1001 ldb_ctx = global_mapi_ctx->ldb_ctx;
1003 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1005 ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "(cn=%s)", profile->profname);
1006 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1009 ldb_element = ldb_msg_find_element(msg, attribute);
1011 DEBUG(3, ("ldb_msg_find_element: NULL\n"));
1012 return MAPI_E_NOT_FOUND;
1015 *count = ldb_element[0].num_values;
1016 value[0] = talloc_array(mem_ctx, char *, *count);
1019 value[0][0] = talloc_strdup(value[0],
1020 ldb_msg_find_attr_as_string(msg, attribute, NULL));
1022 for (i = 0; i < *count; i++) {
1023 value[0][i] = talloc_strdup(mem_ctx, (char *)ldb_element->values[i].data);
1027 return MAPI_E_SUCCESS;
1031 \details Search the value of an attribute within a given profile
1033 _PUBLIC_ enum MAPISTATUS FindProfileAttr(struct mapi_profile *profile, const char *attribute, const char *value)
1035 TALLOC_CTX *mem_ctx;
1036 struct ldb_context *ldb_ctx;
1037 struct ldb_result *res;
1038 struct ldb_message *msg;
1039 struct ldb_message_element *ldb_element;
1041 struct ldb_dn *basedn;
1042 const char *attrs[] = {"*", NULL};
1045 MAPI_RETVAL_IF(!global_mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1046 MAPI_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
1047 MAPI_RETVAL_IF(!attribute, MAPI_E_INVALID_PARAMETER, NULL);
1048 MAPI_RETVAL_IF(!value, MAPI_E_INVALID_PARAMETER, NULL);
1050 mem_ctx = (TALLOC_CTX *)global_mapi_ctx->ldb_ctx;
1051 ldb_ctx = global_mapi_ctx->ldb_ctx;
1053 basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1055 ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "(CN=%s)", profile->profname);
1056 MAPI_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1057 MAPI_RETVAL_IF(!res->count, MAPI_E_NOT_FOUND, NULL);
1060 ldb_element = ldb_msg_find_element(msg, attribute);
1061 MAPI_RETVAL_IF(!ldb_element, MAPI_E_NOT_FOUND, NULL);
1063 val.data = (uint8_t *)talloc_strdup(mem_ctx, value);
1064 val.length = strlen(value);
1065 MAPI_RETVAL_IF(!ldb_msg_find_val(ldb_element, &val), MAPI_E_NOT_FOUND, NULL);
1067 return MAPI_E_SUCCESS;
1074 static bool set_profile_attribute(const char *profname, struct SRowSet rowset,
1075 uint32_t index, uint32_t property, const char *attr)
1077 struct SPropValue *lpProp;
1078 enum MAPISTATUS ret;
1080 lpProp = get_SPropValue_SRow(&(rowset.aRow[index]), property);
1083 DEBUG(3, ("MAPI Property %s not set\n", attr));
1087 ret = mapi_profile_add_string_attr(profname, attr, lpProp->value.lpszA);
1089 if (ret != MAPI_E_SUCCESS) {
1090 DEBUG(3, ("Problem adding attribute %s in profile %s\n", attr, profname));
1096 static bool set_profile_mvstr_attribute(const char *profname, struct SRowSet rowset,
1097 uint32_t index, uint32_t property, const char *attr)
1099 struct SPropValue *lpProp;
1100 enum MAPISTATUS ret;
1103 lpProp = get_SPropValue_SRow(&(rowset.aRow[index]), property);
1106 DEBUG(3, ("MAPI Property %s not set\n", attr));
1110 for (i = 0; i < lpProp->value.MVszA.cValues; i++) {
1111 ret = mapi_profile_add_string_attr(profname, attr, lpProp->value.MVszA.lppszA[i]);
1112 if (ret != MAPI_E_SUCCESS) {
1113 DEBUG(3, ("Problem adding attribute %s in profile %s\n", attr, profname));
1122 \details Process a full and automated MAPI profile creation
1124 This function process a full and automated MAPI profile creation
1125 using the \a username pattern passed as a parameter. The functions
1126 takes a callback parameter which will be called when the username
1127 checked matches several usernames. Private data needed by the
1128 callback can be supplied using the private_data pointer.
1131 typedef int (*mapi_callback_t) callback(struct SRowSet *, void *private_data);
1134 The callback returns the SRow element index within the SRowSet
1135 structure. If the user cancels the operation the callback return
1136 value should be SRowSet->cRows or more.
1138 \param session the session context
1139 \param username the username for the network profile
1140 \param callback function pointer callback function
1141 \param private_data context data that will be provided to the callback
1143 \return MAPI_E_SUCCESS on success, otherwise -1.
1145 \note Developers should call GetLastError() to retrieve the last
1146 MAPI error code. Possible MAPI error codes are:
1148 - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
1149 initialized. The MAPI subsystem must be initialized (using
1150 MAPIInitialize) prior to creating a profile.
1151 - MAPI_E_END_OF_SESSION: The NSPI session has not been initialized
1152 - MAPI_E_CANCEL_USER: The user has aborted the operation
1153 - MAPI_E_INVALID_PARAMETER: The profile parameter was not set
1155 - MAPI_E_NOT_FOUND: One of the mandatory field was not found during
1156 the profile creation process.
1158 \sa OpenProfileStore, MAPILogonProvider, GetLastError
1160 _PUBLIC_ enum MAPISTATUS ProcessNetworkProfile(struct mapi_session *session, const char *username,
1161 mapi_profile_callback_t callback, const void *private_data)
1163 enum MAPISTATUS retval;
1164 struct nspi_context *nspi;
1165 struct SPropTagArray *SPropTagArray = NULL;
1166 struct Restriction_r Filter;
1167 struct SRowSet *SRowSet;
1168 struct SPropValue *lpProp = NULL;
1169 struct SPropTagArray *MIds = NULL;
1170 struct SPropTagArray MIds2;
1171 struct SPropTagArray *MId_server = NULL;
1172 struct StringsArray_r pNames;
1173 const char *profname;
1174 uint32_t instance_key = 0;
1177 MAPI_RETVAL_IF(!session, MAPI_E_NOT_INITIALIZED, NULL);
1178 MAPI_RETVAL_IF(!session->nspi->ctx, MAPI_E_END_OF_SESSION, NULL);
1180 nspi = (struct nspi_context *) session->nspi->ctx;
1181 profname = session->profile->profname;
1184 SRowSet = talloc_zero(nspi->mem_ctx, struct SRowSet);
1185 retval = nspi_GetSpecialTable(nspi, 0x0, &SRowSet);
1186 MAPIFreeBuffer(SRowSet);
1187 if (retval != MAPI_E_SUCCESS) return retval;
1189 SPropTagArray = set_SPropTagArray(nspi->mem_ctx, 0xc,
1191 PR_OFFICE_TELEPHONE_NUMBER,
1204 /* Retrieve the username to match */
1206 username = cli_credentials_get_username(nspi->cred);
1207 MAPI_RETVAL_IF(!username, MAPI_E_INVALID_PARAMETER, NULL);
1210 /* Build the restriction we want for NspiGetMatches */
1211 lpProp = talloc_zero(nspi->mem_ctx, struct SPropValue);
1212 lpProp->ulPropTag = PR_ANR_UNICODE;
1213 lpProp->dwAlignPad = 0;
1214 lpProp->value.lpszW = username;
1216 Filter.rt = RES_PROPERTY;
1217 Filter.res.resProperty.relop = RES_PROPERTY;
1218 Filter.res.resProperty.ulPropTag = PR_ANR_UNICODE;
1219 Filter.res.resProperty.lpProp = lpProp;
1221 SRowSet = talloc_zero(nspi->mem_ctx, struct SRowSet);
1222 MIds = talloc_zero(nspi->mem_ctx, struct SPropTagArray);
1223 retval = nspi_GetMatches(nspi, SPropTagArray, &Filter, &SRowSet, &MIds);
1224 MAPIFreeBuffer(SPropTagArray);
1225 MAPIFreeBuffer(lpProp);
1226 if (retval != MAPI_E_SUCCESS) {
1227 MAPIFreeBuffer(MIds);
1228 MAPIFreeBuffer(SRowSet);
1232 /* if there's no match */
1233 MAPI_RETVAL_IF(!SRowSet, MAPI_E_NOT_FOUND, NULL);
1234 MAPI_RETVAL_IF(!SRowSet->cRows, MAPI_E_NOT_FOUND, NULL);
1235 MAPI_RETVAL_IF(!MIds, MAPI_E_NOT_FOUND, NULL);
1237 /* if SRowSet count is superior than 1 an callback is specified, call it */
1238 if (SRowSet->cRows > 1 && callback) {
1239 index = callback(SRowSet, private_data);
1240 MAPI_RETVAL_IF((index >= SRowSet->cRows), MAPI_E_USER_CANCEL, NULL);
1241 instance_key = MIds->aulPropTag[index];
1243 instance_key = MIds->aulPropTag[0];
1245 MAPIFreeBuffer(MIds);
1247 MIds2.cValues = 0x1;
1248 MIds2.aulPropTag = &instance_key;
1250 set_profile_attribute(profname, *SRowSet, index, PR_EMAIL_ADDRESS, "EmailAddress");
1251 set_profile_attribute(profname, *SRowSet, index, PR_DISPLAY_NAME, "DisplayName");
1252 set_profile_attribute(profname, *SRowSet, index, PR_ACCOUNT, "Account");
1253 set_profile_attribute(profname, *SRowSet, index, PR_ADDRTYPE, "AddrType");
1255 SPropTagArray = set_SPropTagArray(nspi->mem_ctx, 0x7,
1261 PR_PROFILE_HOME_SERVER_ADDRS,
1262 PR_EMS_AB_PROXY_ADDRESSES
1265 nspi->pStat->CurrentRec = 0x0;
1266 nspi->pStat->Delta = 0x0;
1267 nspi->pStat->NumPos = 0x0;
1268 nspi->pStat->TotalRecs = 0x1;
1270 MAPIFreeBuffer(SRowSet);
1271 SRowSet = talloc(nspi->mem_ctx, struct SRowSet);
1272 retval = nspi_QueryRows(nspi, SPropTagArray, &MIds2, 1, &SRowSet);
1273 MAPIFreeBuffer(SPropTagArray);
1274 if (retval != MAPI_E_SUCCESS) return retval;
1276 lpProp = get_SPropValue_SRowSet(SRowSet, PR_EMS_AB_HOME_MDB);
1277 MAPI_RETVAL_IF(!lpProp, MAPI_E_NOT_FOUND, NULL);
1279 nspi->org = x500_get_dn_element(nspi->mem_ctx, lpProp->value.lpszA, ORG);
1280 nspi->org_unit = x500_get_dn_element(nspi->mem_ctx, lpProp->value.lpszA, ORG_UNIT);
1282 MAPI_RETVAL_IF(!nspi->org_unit, MAPI_E_INVALID_PARAMETER, NULL);
1283 MAPI_RETVAL_IF(!nspi->org, MAPI_E_INVALID_PARAMETER, NULL);
1285 retval = mapi_profile_add_string_attr(profname, "Organization", nspi->org);
1286 retval = mapi_profile_add_string_attr(profname, "OrganizationUnit", nspi->org_unit);
1288 nspi->servername = x500_get_servername(lpProp->value.lpszA);
1289 mapi_profile_add_string_attr(profname, "ServerName", nspi->servername);
1290 set_profile_attribute(profname, *SRowSet, 0, PR_EMS_AB_HOME_MDB, "HomeMDB");
1291 set_profile_mvstr_attribute(profname, *SRowSet, 0, PR_EMS_AB_PROXY_ADDRESSES, "ProxyAddress");
1292 MAPIFreeBuffer(SRowSet);
1295 pNames.Strings = (const char **) talloc_array(nspi->mem_ctx, char **, 1);
1296 pNames.Strings[0] = (const char *) talloc_asprintf(nspi->mem_ctx, SERVER_DN,
1297 nspi->org, nspi->org_unit,
1299 MId_server = talloc_zero(nspi->mem_ctx, struct SPropTagArray);
1300 retval = nspi_DNToMId(nspi, &pNames, &MId_server);
1301 MAPIFreeBuffer((char *)pNames.Strings[0]);
1302 MAPIFreeBuffer((char **)pNames.Strings);
1303 if (retval != MAPI_E_SUCCESS) return retval;
1305 SRowSet = talloc_zero(nspi->mem_ctx, struct SRowSet);
1306 SPropTagArray = set_SPropTagArray(nspi->mem_ctx, 0x1, PR_EMS_AB_NETWORK_ADDRESS);
1307 retval = nspi_GetProps(nspi, SPropTagArray, MId_server, &SRowSet);
1308 MAPIFreeBuffer(SPropTagArray);
1309 MAPIFreeBuffer(MId_server);
1310 if (retval != MAPI_E_SUCCESS) {
1311 MAPIFreeBuffer(SRowSet);
1315 set_profile_mvstr_attribute(profname, *SRowSet, 0, PR_EMS_AB_NETWORK_ADDRESS, "NetworkAddress");
1316 MAPIFreeBuffer(SRowSet);
1318 return MAPI_E_SUCCESS;