3ef24cdde1a66a60fde6cdc5e12d644ba71fcda4
[jelmer/openchange.git] / libmapi / IProfAdmin.c
1 /*
2    OpenChange MAPI implementation.
3
4    Copyright (C) Julien Kerihuel 2007-2011.
5    Copyright (C) Fabien Le Mentec 2007.
6
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.
11    
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.
16    
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/>.
19  */
20
21 #include "libmapi/libmapi.h"
22 #include "libmapi/libmapi_private.h"
23 #include <credentials.h>
24 #include <ldb_errors.h>
25 #include <ldb.h>
26
27 /**
28    \file IProfAdmin.c
29
30    \brief MAPI Profiles interface
31  */
32
33 /*
34  * Private functions
35  */
36
37 /**
38  * Load a MAPI profile into a mapi_profile struct
39  */
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)
44 {
45         int                     ret;
46         enum ldb_scope          scope = LDB_SCOPE_SUBTREE;
47         struct ldb_result       *res;
48         struct ldb_message      *msg;
49         const char * const      attrs[] = { "*", NULL };
50
51         /* fills in profile name */
52         profile->profname = talloc_strdup(mem_ctx, profname);
53         if (!profile->profname) return MAPI_E_NOT_ENOUGH_RESOURCES;
54
55         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profile->profname);
56         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
57
58         /* profile not found */
59         if (!res->count) return MAPI_E_NOT_FOUND;
60         /* more than one profile */
61         if (res->count > 1) return MAPI_E_COLLISION;
62
63         /* fills in profile with query result */
64         msg = res->msgs[0];
65
66         profile->username = ldb_msg_find_attr_as_string(msg, "username", NULL);
67         profile->password = password ? password : ldb_msg_find_attr_as_string(msg, "password", "");
68         profile->workstation = ldb_msg_find_attr_as_string(msg, "workstation", NULL);
69         profile->realm = ldb_msg_find_attr_as_string(msg, "realm", NULL);
70         profile->domain = ldb_msg_find_attr_as_string(msg, "domain", NULL);
71         profile->mailbox = ldb_msg_find_attr_as_string(msg, "EmailAddress", NULL);
72         profile->homemdb = ldb_msg_find_attr_as_string(msg, "HomeMDB", NULL);
73         profile->localaddr = ldb_msg_find_attr_as_string(msg, "localaddress", NULL);
74         profile->server = ldb_msg_find_attr_as_string(msg, "binding", NULL);
75         profile->seal = ldb_msg_find_attr_as_bool(msg, "seal", false);
76         profile->org = ldb_msg_find_attr_as_string(msg, "Organization", NULL);
77         profile->ou = ldb_msg_find_attr_as_string(msg, "OrganizationUnit", NULL);
78         profile->codepage = ldb_msg_find_attr_as_int(msg, "codepage", 0);
79         profile->language = ldb_msg_find_attr_as_int(msg, "language", 0);
80         profile->method = ldb_msg_find_attr_as_int(msg, "method", 0);
81         profile->exchange_version = ldb_msg_find_attr_as_int(msg, "exchange_version", 0);
82
83         if (!profile->password) return MAPI_E_INVALID_PARAMETER;
84
85         return MAPI_E_SUCCESS;
86 }
87
88 /**
89  * Remove the "default" attribute from whichever profile is currently the default profile
90  */
91 static enum MAPISTATUS ldb_clear_default_profile(struct mapi_context *mapi_ctx,
92                                                  TALLOC_CTX *mem_ctx)
93 {
94         enum ldb_scope          scope = LDB_SCOPE_SUBTREE;
95         struct ldb_context      *ldb_ctx;
96         struct ldb_dn           *basedn;
97         struct ldb_message      *msg;
98         struct ldb_result       *res;
99         const char              *attrs[] = { "PR_DEFAULT_PROFILE", NULL };
100         int                     ret;
101         uint32_t                i;
102
103         ldb_ctx = mapi_ctx->ldb_ctx;
104
105         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
106         ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, scope, attrs, "(cn=*)");
107         
108         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
109         if (!res->count) return MAPI_E_NOT_FOUND;
110
111         for (i = 0; i < res->count; i++) {
112                 struct ldb_message              *message;
113
114                 msg = res->msgs[i];
115                 if (msg->num_elements == 1) {
116                         message = talloc_steal(mem_ctx, msg);
117                         message->elements[0].flags = LDB_FLAG_MOD_DELETE;
118
119                         ret = ldb_modify(ldb_ctx, message);
120                         talloc_free(message);
121                 }
122         }
123         
124         return MAPI_E_SUCCESS;
125 }
126
127 /**
128  * Test if the password is correct
129  */
130 static enum MAPISTATUS ldb_test_password(struct mapi_context *mapi_ctx,
131                                          TALLOC_CTX *mem_ctx, 
132                                          const char *profile, 
133                                          const char *password)
134 {
135         enum ldb_scope          scope = LDB_SCOPE_DEFAULT;
136         struct ldb_context      *ldb_ctx;
137         struct ldb_message      *msg;
138         struct ldb_result       *res;
139         const char              *attrs[] = {"cn", "password", NULL };
140         const char              *ldb_password;
141         int                     ret;
142
143         ldb_ctx = mapi_ctx->ldb_ctx;
144         
145         ret = ldb_search(ldb_ctx, mem_ctx, &res, NULL, scope, attrs, 
146                                          "(cn=%s)(cn=Profiles)", profile);
147
148         if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
149         if (!res->count) return MAPI_E_NOT_FOUND;
150         
151         msg = res->msgs[0];
152         
153         ldb_password = ldb_msg_find_attr_as_string(msg, "password", NULL);
154         if (!ldb_password) return MAPI_E_NO_SUPPORT;
155         if (strncmp(password, ldb_password, strlen(password))) return MAPI_E_LOGON_FAILED;
156         
157         return MAPI_E_SUCCESS;
158 }
159
160
161 /**
162  * Add a profile to the database with default fields
163  */
164 static enum MAPISTATUS ldb_create_profile(TALLOC_CTX *mem_ctx,
165                                           struct ldb_context *ldb_ctx,
166                                           const char *profname)
167 {
168         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
169         struct ldb_message              msg;
170         struct ldb_message_element      el[2];
171         struct ldb_val                  vals[2][1];
172         struct ldb_result               *res;
173         struct ldb_dn                   *basedn;
174         char                            *dn;
175         int                             ret;
176         const char * const              attrs[] = { "*", NULL };
177
178         /* Sanity check */
179         if (profname == NULL) 
180                 return MAPI_E_BAD_VALUE;
181
182         /* Does the profile already exists? */
183         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), 
184                                          scope, attrs, "(cn=%s)(cn=Profiles)", profname);
185         if (ret == LDB_SUCCESS && res && res->msgs) return MAPI_E_NO_ACCESS;
186
187         /*
188          * We now prepare the entry for transaction
189          */
190         
191         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
192         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
193         talloc_free(dn);
194         if (!ldb_dn_validate(basedn)) return MAPI_E_BAD_VALUE;
195
196         msg.dn = ldb_dn_copy(mem_ctx, basedn);
197         msg.num_elements = 2;
198         msg.elements = el;
199
200         el[0].flags = 0;
201         el[0].name = talloc_strdup(mem_ctx, "cn");
202         el[0].num_values = 1;
203         el[0].values = vals[0];
204         vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, profname);
205         vals[0][0].length = strlen(profname);
206
207         el[1].flags = 0;
208         el[1].name = talloc_strdup(mem_ctx, "name");
209         el[1].num_values = 1;
210         el[1].values = vals[1];
211         vals[1][0].data = (uint8_t *)talloc_strdup(mem_ctx, profname);
212         vals[1][0].length = strlen(profname);
213
214         ret = ldb_add(ldb_ctx, &msg);
215
216         if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
217
218         return MAPI_E_SUCCESS;
219 }
220
221 /*
222  * delete the current profile
223  */
224 static enum MAPISTATUS ldb_delete_profile(TALLOC_CTX *mem_ctx,
225                                           struct ldb_context *ldb_ctx,
226                                           const char *profname)
227 {
228         enum ldb_scope          scope = LDB_SCOPE_SUBTREE;
229         struct ldb_result       *res;
230         const char * const      attrs[] = { "*", NULL };
231         int                     ret;
232
233         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
234         if (!res->msgs) return MAPI_E_NOT_FOUND;
235
236         ret = ldb_delete(ldb_ctx, res->msgs[0]->dn);
237         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
238         
239         return MAPI_E_SUCCESS;
240 }
241
242
243 /**
244    \details Copy the MAPI profile
245
246    \param mem_ctx pointer to the memory context
247    \param ldb_ctx pointer to the LDB context
248    \param profname_src pointer to the source profile name
249    \param profname_dest pointer to the destination profile name
250  */
251 static enum MAPISTATUS ldb_copy_profile(TALLOC_CTX *mem_ctx,
252                                         struct ldb_context *ldb_ctx,
253                                         const char *profname_src,
254                                         const char *profname_dest)
255 {
256         int                             ret;
257         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
258         struct ldb_result               *res;
259         struct ldb_result               *res_dest;
260         struct ldb_message              *msg;
261         const char * const              attrs[] = { "*", NULL };
262         uint32_t                        i;
263         char                            *dn;
264         struct ldb_message_element      *el;
265         struct ldb_dn                   *basedn;
266
267         /* Step 1. Load the source profile */
268         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs,
269                          "(cn=%s)(cn=Profiles)", profname_src);
270         /* profile not found */
271         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
272         /* more than one profile */
273         if (res->count > 1) return MAPI_E_COLLISION;
274
275         /* fills in profile with query result */
276         msg = res->msgs[0];
277
278         /* Step 2. Encure the desintation profile doesn't exist */
279         ret = ldb_search(ldb_ctx, mem_ctx, &res_dest, ldb_get_default_basedn(ldb_ctx), scope, attrs,
280                          "(cn=%s)(cn=Profiles)", profname_dest);
281         /* If profile exists or there is more than one */
282         if (ret == LDB_SUCCESS && res_dest->count) return MAPI_E_COLLISION;
283
284         /* Step 3. Customize destination profile */
285         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname_dest);
286         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
287         talloc_free(dn);
288         if (!ldb_dn_validate(basedn)) return MAPI_E_BAD_VALUE;
289         msg->dn = ldb_dn_copy(mem_ctx, basedn);
290
291         /* Change cn */
292         el = msg->elements;
293         for (i = 0; i < msg->num_elements; i++) {
294                 if (el[i].name && !strcmp(el[i].name, "cn")) {
295                         el[i].values[0].data = (uint8_t *)talloc_strdup(mem_ctx, profname_dest);
296                         el[i].values[0].length = strlen(profname_dest);
297                 }
298         }
299
300         /* Step 4. Copy the profile */
301         ret = ldb_add(ldb_ctx, msg);
302         /* talloc_free(basedn); */
303         
304         if (ret != LDB_SUCCESS) return MAPI_E_NO_SUPPORT;
305
306         return MAPI_E_SUCCESS;
307 }
308
309
310 /**
311    \details Rename a profile
312
313    \param mem_ctx pointer on the memory context
314    \param old_profname the old profile name string
315    \param new_profname the new profile name string
316
317    \return MAPI_E_SUCCESS on success otherwise MAPI error.
318  */
319 static enum MAPISTATUS ldb_rename_profile(struct mapi_context *mapi_ctx,
320                                           TALLOC_CTX *mem_ctx, 
321                                           const char *old_profname,
322                                           const char *new_profname)
323 {
324         int                     ret;
325         struct ldb_context      *ldb_ctx;
326         struct ldb_dn           *old_dn;
327         struct ldb_dn           *new_dn;
328         char                    *dn;
329
330         /* Sanity checks */
331         OPENCHANGE_RETVAL_IF(!old_profname, MAPI_E_INVALID_PARAMETER, NULL);
332         OPENCHANGE_RETVAL_IF(!new_profname, MAPI_E_INVALID_PARAMETER, NULL);
333
334         ldb_ctx = mapi_ctx->ldb_ctx;
335
336         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", old_profname);
337         old_dn = ldb_dn_new(mem_ctx, ldb_ctx, dn);
338         talloc_free(dn);
339
340         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", new_profname);
341         new_dn = ldb_dn_new(mem_ctx, ldb_ctx, dn);
342         talloc_free(dn);
343
344         ret = ldb_rename(ldb_ctx, old_dn, new_dn);
345         OPENCHANGE_RETVAL_IF(ret, MAPI_E_CORRUPT_STORE, NULL);
346
347         return MAPI_E_SUCCESS;
348 }
349
350
351 /*
352  * Public interface
353  */
354
355 /**
356    \details Add an attribute to the profile
357
358    \param mapi_ctx pointer to the MAPI context
359    \param profile pointer to the profile name
360    \param attr the name of the atribute
361    \param value the value of the attribute
362  */
363 _PUBLIC_ enum MAPISTATUS mapi_profile_add_string_attr(struct mapi_context *mapi_ctx,
364                                                       const char *profile, 
365                                                       const char *attr, 
366                                                       const char *value)
367 {
368         TALLOC_CTX                      *mem_ctx;
369         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
370         struct ldb_message              msg;
371         struct ldb_message_element      el[1];
372         struct ldb_val                  vals[1][1];
373         struct ldb_result               *res;
374         struct ldb_context              *ldb_ctx;
375         struct ldb_dn                   *basedn;
376         char                            *dn;
377         int                             ret;
378         const char * const              attrs[] = { "*", NULL };
379
380         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
381         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
382         OPENCHANGE_RETVAL_IF(!profile, MAPI_E_BAD_VALUE, NULL);
383         OPENCHANGE_RETVAL_IF(!value, MAPI_E_INVALID_PARAMETER, NULL);
384
385         mem_ctx = talloc_named(NULL, 0, "mapi_profile_add_string_attr");
386         ldb_ctx = mapi_ctx->ldb_ctx;
387
388         /* Retrieve the profile from the database */
389         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profile);
390         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
391
392         /* Preparing for the transaction */
393         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profile);
394         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
395         talloc_free(dn);
396         OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
397
398         msg.dn = ldb_dn_copy(mem_ctx, basedn);
399         msg.num_elements = 1;
400         msg.elements = el;
401
402         el[0].flags = LDB_FLAG_MOD_ADD;
403         el[0].name = talloc_strdup(mem_ctx, attr);
404         el[0].num_values = 1;
405         el[0].values = vals[0];
406         vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
407         vals[0][0].length = strlen(value);
408
409         ret = ldb_modify(ldb_ctx, &msg);
410         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
411         
412         talloc_free(mem_ctx);
413         return MAPI_E_SUCCESS;
414 }
415
416 /**
417    \details Modify an attribute
418
419    \param mapi_ctx pointer to the MAPI context
420    \param profname the name of the profile
421    \param attr the name of the attribute
422    \param value the value of the attribute
423  */
424 _PUBLIC_ enum MAPISTATUS mapi_profile_modify_string_attr(struct mapi_context *mapi_ctx,
425                                                          const char *profname, 
426                                                          const char *attr, 
427                                                          const char *value)
428 {
429         TALLOC_CTX                      *mem_ctx;
430         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
431         struct ldb_message              msg;
432         struct ldb_message_element      el[1];
433         struct ldb_val                  vals[1][1];
434         struct ldb_result               *res;
435         struct ldb_context              *ldb_ctx;
436         struct ldb_dn                   *basedn;
437         char                            *dn;
438         int                             ret;
439         const char * const              attrs[] = { "*", NULL };
440
441         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
442         OPENCHANGE_RETVAL_IF(!profname, MAPI_E_BAD_VALUE, NULL);
443
444         ldb_ctx = mapi_ctx->ldb_ctx;
445         mem_ctx = talloc_named(NULL, 0, "mapi_profile_modify_string_attr");
446
447         /* Retrieve the profile from the database */
448         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
449         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
450
451         /* Preparing for the transaction */
452         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
453         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
454         talloc_free(dn);
455         OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
456
457         msg.dn = ldb_dn_copy(mem_ctx, basedn);
458         msg.num_elements = 1;
459         msg.elements = el;
460
461         el[0].flags = LDB_FLAG_MOD_REPLACE;
462         el[0].name = talloc_strdup(mem_ctx, attr);
463         el[0].num_values = 1;
464         el[0].values = vals[0];
465         vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
466         vals[0][0].length = strlen(value);
467
468         ret = ldb_modify(ldb_ctx, &msg);
469         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
470
471         talloc_free(mem_ctx);
472         
473         return MAPI_E_SUCCESS;
474 }
475
476 /**
477    \details Delete an attribute
478
479    \param mapi_ctx pointer to the MAPI context
480    \param profname the name of the profile
481    \param attr the name of the attribute
482    \param value the value of the attribute
483
484    
485  */
486 _PUBLIC_ enum MAPISTATUS mapi_profile_delete_string_attr(struct mapi_context *mapi_ctx,
487                                                          const char *profname, 
488                                                          const char *attr, 
489                                                          const char *value)
490 {
491         TALLOC_CTX                      *mem_ctx;
492         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
493         struct ldb_message              msg;
494         struct ldb_message_element      el[1];
495         struct ldb_val                  vals[1][1];
496         struct ldb_result               *res;
497         struct ldb_context              *ldb_ctx;
498         struct ldb_dn                   *basedn;
499         char                            *dn;
500         int                             ret;
501         const char * const              attrs[] = { "*", NULL };
502
503         /* Saniy checks */
504         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
505         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
506         OPENCHANGE_RETVAL_IF(!profname, MAPI_E_BAD_VALUE, NULL);
507
508         ldb_ctx = mapi_ctx->ldb_ctx;
509         mem_ctx = talloc_named(NULL, 0, "mapi_profile_delete_string_attr");
510
511         /* Retrieve the profile from the database */
512         ret = ldb_search(ldb_ctx, mem_ctx, &res, ldb_get_default_basedn(ldb_ctx), scope, attrs, "(cn=%s)(cn=Profiles)", profname);
513         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_BAD_VALUE, mem_ctx);
514
515         /* Preparing for the transaction */
516         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profname);
517         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, dn);
518         talloc_free(dn);
519         OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, mem_ctx);
520
521         msg.dn = ldb_dn_copy(mem_ctx, basedn);
522         msg.num_elements = 1;
523         msg.elements = el;
524
525         el[0].flags = LDB_FLAG_MOD_DELETE;
526         el[0].name = talloc_strdup(mem_ctx, attr);
527         el[0].num_values = 1;
528         el[0].values = vals[0];
529         vals[0][0].data = (uint8_t *)talloc_strdup(mem_ctx, value);
530         vals[0][0].length = strlen(value);
531
532         ret = ldb_modify(ldb_ctx, &msg);
533         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_SUPPORT, mem_ctx);
534
535         talloc_free(mem_ctx);
536         
537         return MAPI_E_SUCCESS;
538 }
539
540 /*
541  * Private function which opens the profile store
542  * Should only be called within MAPIInitialize
543  */
544 enum MAPISTATUS OpenProfileStore(TALLOC_CTX *mem_ctx, struct ldb_context **ldb_ctx, 
545                                  const char *profiledb)
546 {
547         int                     ret;
548         struct ldb_context      *tmp_ctx;
549         struct tevent_context   *ev;
550         
551         *ldb_ctx = 0;
552         
553         /* store path */
554         if (!profiledb) return MAPI_E_NOT_FOUND;
555
556         ev = tevent_context_init(mem_ctx);
557         if (!ev) return MAPI_E_NOT_ENOUGH_RESOURCES;
558
559         /* connect to the store */
560         tmp_ctx = ldb_init(mem_ctx, ev);
561         if (!tmp_ctx) return MAPI_E_NOT_ENOUGH_RESOURCES;
562
563         ret = ldb_connect(tmp_ctx, profiledb, 0, NULL);
564         if (ret != LDB_SUCCESS) return MAPI_E_NOT_FOUND;
565
566         *ldb_ctx = tmp_ctx;
567         return MAPI_E_SUCCESS;
568 }
569
570
571 /**
572    \details Get default ldif_path
573
574    This function returns the path for the default LDIF files.
575
576    \sa CreateProfileStore
577 */
578 _PUBLIC_ const char *mapi_profile_get_ldif_path(void)
579 {
580         return DEFAULT_LDIF;
581 }
582
583
584 /**
585    \details Create a profile database
586    
587    This function creates a new profile database, including doing an
588    initial setup.
589
590    \param profiledb the absolute path to the profile database intended
591    to be created
592    \param ldif_path the absolute path to the LDIF information to use
593    for initial setup.
594
595    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
596  
597    \note Developers may also call GetLastError() to retrieve the last
598    MAPI error code. Possible MAPI error codes are:
599    - MAPI_E_CALL_FAILED: profiledb or ldif_path is not set
600    - MAPI_E_NOT_ENOUGH_RESOURCES: ldb subsystem initialization failed
601    - MAPI_E_NO_ACCESS: connection or ldif add failed
602
603    \sa GetLastError, mapi_profile_get_ldif_path
604 */
605 _PUBLIC_ enum MAPISTATUS CreateProfileStore(const char *profiledb, const char *ldif_path)
606 {
607         int                     ret;
608         TALLOC_CTX              *mem_ctx;
609         struct ldb_context      *ldb_ctx;
610         struct ldb_ldif         *ldif;
611         char                    *url = NULL;
612         char                    *filename = NULL;
613         FILE                    *f;
614         struct tevent_context   *ev;
615
616         OPENCHANGE_RETVAL_IF(!profiledb, MAPI_E_CALL_FAILED, NULL);
617         OPENCHANGE_RETVAL_IF(!ldif_path, MAPI_E_CALL_FAILED, NULL);
618
619         mem_ctx = talloc_named(NULL, 0, "CreateProfileStore");
620
621         ev = tevent_context_init(mem_ctx);
622         OPENCHANGE_RETVAL_IF(!ev, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
623
624         ldb_ctx = ldb_init(mem_ctx, ev);
625         OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_ENOUGH_RESOURCES, mem_ctx);
626
627         url = talloc_asprintf(mem_ctx, "tdb://%s", profiledb);
628         ret = ldb_connect(ldb_ctx, url, 0, 0);
629         talloc_free(url);
630         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_ACCESS, mem_ctx);
631
632         filename = talloc_asprintf(mem_ctx, "%s/oc_profiles_init.ldif", ldif_path);
633         f = fopen(filename, "r");
634         OPENCHANGE_RETVAL_IF(!f, MAPI_E_NO_ACCESS, mem_ctx);
635         talloc_free(filename);
636
637         while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
638                 struct ldb_message *normalized_msg;
639                 ret = ldb_msg_normalize(ldb_ctx, mem_ctx, ldif->msg, &normalized_msg);
640                 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_ACCESS, mem_ctx);
641                 ret = ldb_add(ldb_ctx, normalized_msg);
642                 if (ret != LDB_SUCCESS) {
643                         fclose(f);
644                         OPENCHANGE_RETVAL_ERR(MAPI_E_NO_ACCESS, mem_ctx);
645                 }
646                 ldb_ldif_read_free(ldb_ctx, ldif);
647                 talloc_free(normalized_msg);
648         }
649         fclose(f);
650
651         filename = talloc_asprintf(mem_ctx, "%s/oc_profiles_schema.ldif", ldif_path);
652         f = fopen(filename, "r");
653         OPENCHANGE_RETVAL_IF(!f, MAPI_E_NO_ACCESS, mem_ctx);
654
655         talloc_free(filename);
656         while ((ldif = ldb_ldif_read_file(ldb_ctx, f))) {
657                 struct ldb_message *normalized_msg;
658                 ret = ldb_msg_normalize(ldb_ctx, mem_ctx, ldif->msg, &normalized_msg);
659                 OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NO_ACCESS, mem_ctx);
660                 ret = ldb_add(ldb_ctx, normalized_msg);
661                 if (ret != LDB_SUCCESS) {
662                         fclose(f);
663                         OPENCHANGE_RETVAL_ERR(MAPI_E_NO_ACCESS, mem_ctx);
664                 }
665
666                 ldb_ldif_read_free(ldb_ctx, ldif);
667                 talloc_free(normalized_msg);
668         }
669         fclose(f);
670
671         talloc_free(mem_ctx);
672
673         return MAPI_E_SUCCESS;
674 }
675
676
677 /**
678    \details Load a profile from the database
679
680    This function opens a named profile from the database, and fills
681    the mapi_profile structure with common profile information.
682
683    \param mapi_ctx pointer to the MAPI context
684    \param profile the resulting profile
685    \param profname the name of the profile to open
686    \param password the password to use with the profile
687
688    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
689
690    \note Developers may also call GetLastError() to retrieve the last
691    MAPI error code. Possible MAPI error codes are:
692    - MAPI_E_NOT_ENOUGH_RESOURCES: ldb subsystem initialization failed
693    - MAPI_E_NOT_FOUND: the profile was not found in the profile
694      database
695    - MAPI_E_COLLISION: profname matched more than one entry
696
697    \sa MAPIInitialize, GetLastError
698 */
699 _PUBLIC_ enum MAPISTATUS OpenProfile(struct mapi_context *mapi_ctx,
700                                      struct mapi_profile *profile, 
701                                      const char *profname, 
702                                      const char *password)
703 {
704         TALLOC_CTX      *mem_ctx;
705         enum MAPISTATUS retval;
706
707         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
708         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
709
710         mem_ctx = (TALLOC_CTX *) mapi_ctx;
711         
712         /* find the profile in ldb store */
713         retval = ldb_load_profile(mem_ctx, mapi_ctx->ldb_ctx, profile, profname, password);
714
715         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
716
717         return MAPI_E_SUCCESS;  
718 }
719
720 /**
721    \details Load a MAPI Profile and sets its credentials
722
723    This function loads a named MAPI profile and sets the MAPI session
724    credentials.
725
726    \param mapi_ctx pointer to the MAPI context
727    \param profile pointer to the MAPI profile
728
729    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
730
731    \note Developers may also call GetLastError() to retrieve the last
732    MAPI error code. Possible MAPI error codes are:
733    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
734    - MAPI_E_INVALID_PARAMETER: The profile parameter is not
735      initialized
736    - MAPI_E_NOT_ENOUGH_RESOURCES: MAPI subsystem failed to allocate
737      the necessary resources to perform the operation
738
739    \sa OpenProfile, GetLastError
740  */
741 _PUBLIC_ enum MAPISTATUS LoadProfile(struct mapi_context *mapi_ctx, 
742                                      struct mapi_profile *profile)
743 {
744         TALLOC_CTX *mem_ctx;
745
746         /* Sanity checks */
747         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
748         OPENCHANGE_RETVAL_IF(!mapi_ctx->session, MAPI_E_NOT_INITIALIZED, NULL);
749         OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
750
751         mem_ctx = (TALLOC_CTX *) mapi_ctx->session;
752
753         profile->credentials = cli_credentials_init(mem_ctx);
754         OPENCHANGE_RETVAL_IF(!profile->credentials, MAPI_E_NOT_ENOUGH_RESOURCES, NULL);
755         cli_credentials_set_username(profile->credentials, profile->username, CRED_SPECIFIED);
756         cli_credentials_set_password(profile->credentials, profile->password, CRED_SPECIFIED);
757         cli_credentials_set_workstation(profile->credentials, profile->workstation, CRED_SPECIFIED);
758         cli_credentials_set_realm(profile->credentials, profile->realm, CRED_SPECIFIED);
759         cli_credentials_set_domain(profile->credentials, profile->domain, CRED_SPECIFIED);
760
761         return MAPI_E_SUCCESS;
762 }
763
764 /**
765    \details Release a profile
766
767    This function releases the credentials associated with the profile.
768
769    \param profile the profile to release.
770
771    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
772
773    \note Developers may also call GetLastError() to retrieve the last
774    MAPI error code. Possible MAPI error codes are:
775    - MAPI_E_INVALID_PARAMETER: The profile parameter was not set or
776      not valid
777  */
778 _PUBLIC_ enum MAPISTATUS ShutDown(struct mapi_profile *profile)
779 {
780         OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
781
782         if (profile->credentials) 
783                 talloc_free(profile->credentials);
784         return MAPI_E_SUCCESS;
785 }
786
787
788 /**
789    \details Create a profile in the MAPI profile database
790
791    This function creates a profile named \a profile in the MAPI profile
792    database and sets the specified username in that profile.
793
794    This function may also set the password. If the flags include
795    OC_PROFILE_NOPASSWORD then the password will not be set. Otherwise,
796    the specified password argument will also be saved to the profile.
797
798    \param mapi_ctx pointer to the MAPI context
799    \param profile the name of the profile
800    \param username the username of the profile
801    \param password the password for the profile (if used)
802    \param flag the union of the flags. 
803
804    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
805
806    \note Developers may also call GetLastError() to retrieve the last
807    MAPI error code. Possible MAPI error codes are:
808    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
809      initialized. The MAPI subsystem must be initialized (using
810      MAPIInitialize) prior to creating a profile.
811    - MAPI_E_NOT_ENOUGH_RESOURCES: MAPI subsystem failed to allocate
812      the necessary resources to operate properly
813    - MAPI_E_NO_SUPPORT: An error was encountered while setting the
814      MAPI profile attributes in the database.
815
816    \note profile information (including the password, if saved to the
817    profile) is stored unencrypted.
818
819    \sa DeleteProfile, SetDefaultProfile, GetDefaultProfile,
820    ChangeProfilePassword, GetProfileTable, ProcessNetworkProfile,
821    GetLastError
822  */
823 _PUBLIC_ enum MAPISTATUS CreateProfile(struct mapi_context *mapi_ctx,
824                                        const char *profile, 
825                                        const char *username,
826                                        const char *password, 
827                                        uint32_t flag)
828 {
829         enum MAPISTATUS retval;
830         TALLOC_CTX      *mem_ctx;
831
832         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
833         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
834
835         mem_ctx = talloc_named(NULL, 0, "CreateProfile");
836         retval = ldb_create_profile(mem_ctx, mapi_ctx->ldb_ctx, profile);
837         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
838
839         retval = mapi_profile_add_string_attr(mapi_ctx, profile, "username", username);
840         if (flag != OC_PROFILE_NOPASSWORD) {
841                 retval = mapi_profile_add_string_attr(mapi_ctx, profile, "password", password);
842         }
843         talloc_free(mem_ctx);
844
845         return retval;
846 }
847
848
849 /**
850    \details Delete a profile from the MAPI profile database
851
852    \param mapi_ctx pointer to the MAPI context
853    \param profile the name of the profile to delete
854
855    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
856
857    \note Developers may also call GetLastError() to retrieve the last
858    MAPI error code. Possible MAPI error codes are:
859    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
860      initialized. The MAPI subsystem must be initialized (using
861      MAPIInitialize) prior to creating a profile.
862    - MAPI_E_NOT_FOUND: The profile was not found in the database.
863
864    \sa CreateProfile, ChangeProfilePassword, GetProfileTable,
865    GetProfileAttr, ProcessNetworkProfile, GetLastError
866 */
867 _PUBLIC_ enum MAPISTATUS DeleteProfile(struct mapi_context *mapi_ctx,
868                                        const char *profile)
869 {
870         TALLOC_CTX      *mem_ctx;
871         enum MAPISTATUS retval;
872
873         /* Sanity checks */
874         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
875         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
876
877         mem_ctx = talloc_named(NULL, 0, "DeleteProfile");
878         retval = ldb_delete_profile(mem_ctx, mapi_ctx->ldb_ctx, profile);
879         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
880         talloc_free(mem_ctx);
881
882         return retval;
883 }
884
885
886 /**
887    \details Change the profile password of an existing MAPI profile
888
889    \param mapi_ctx pointer to the MAPI context
890    \param profile the name of the profile to have its password changed
891    \param old_password the old password
892    \param password the new password
893
894    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
895
896    \note Developers may also call GetLastError() to retrieve the last
897    MAPI error code. Possible MAPI error codes are:
898    - MAPI_E_INVALID_PARAMETER: One of the following argument was not
899      set: profile, old_password, password
900    - MAPI_E_NOT_FOUND: The profile was not found in the database
901
902    \sa CreateProfile, GetProfileTable, GetProfileAttr,
903    ProcessNetworkProfile, GetLastError
904  */
905 _PUBLIC_ enum MAPISTATUS ChangeProfilePassword(struct mapi_context *mapi_ctx,
906                                                const char *profile, 
907                                                const char *old_password,
908                                                const char *password)
909 {
910         TALLOC_CTX              *mem_ctx;
911         enum MAPISTATUS         retval;
912
913         /* Sanity checks */
914         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
915         OPENCHANGE_RETVAL_IF(!profile || !old_password || 
916                              !password, MAPI_E_INVALID_PARAMETER, NULL);
917
918         mem_ctx = talloc_named(NULL, 0, "ChangeProfilePassword");
919
920         retval = ldb_test_password(mapi_ctx, mem_ctx, profile, password);
921         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
922
923         retval = mapi_profile_modify_string_attr(mapi_ctx, profile, "password", password);
924         
925         talloc_free(mem_ctx);
926         return retval;
927 }
928
929 /**
930    \details Copy a profile
931
932    \param mapi_ctx pointer to the MAPI context
933    \param profile_src the source profile to copy from
934    \param profile_dst the destination profile to copy to
935
936    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
937  */
938 _PUBLIC_ enum MAPISTATUS CopyProfile(struct mapi_context *mapi_ctx,
939                                      const char *profile_src,
940                                      const char *profile_dst)
941 {
942         TALLOC_CTX      *mem_ctx;
943         enum MAPISTATUS retval;
944
945         /* Sanity checks */
946         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
947         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
948         OPENCHANGE_RETVAL_IF(!profile_src, MAPI_E_INVALID_PARAMETER, NULL);
949         OPENCHANGE_RETVAL_IF(!profile_dst, MAPI_E_INVALID_PARAMETER, NULL);
950
951         mem_ctx = talloc_named(NULL, 0, "CopyProfile");
952
953         retval = ldb_copy_profile(mem_ctx, mapi_ctx->ldb_ctx, profile_src, profile_dst);
954         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
955
956         talloc_free(mem_ctx);
957         return retval;
958 }
959
960
961 /**
962    \details Duplicate an existing profile.
963
964    The username specified in parameter is used to customize the new
965    profile. This function should only be used in environments where
966    users are within the same administrative group, storage group,
967    server etc. Otherwise this will create an invalid profile and may
968    cause unpredictable results.
969
970    \param mapi_ctx pointer to the MAPI context
971    \param profile_src the source profile to duplicate from
972    \param profile_dst the destination profile to duplicate to
973    \param username the username to replace within the destination
974    profile
975
976    \return MAPI_E_SUCCESS on success, otherwise MAPI error
977  */
978 _PUBLIC_ enum MAPISTATUS DuplicateProfile(struct mapi_context *mapi_ctx,
979                                           const char *profile_src,
980                                           const char *profile_dst,
981                                           const char *username)
982 {
983         TALLOC_CTX              *mem_ctx;
984         enum MAPISTATUS         retval;
985         char                    *username_src = NULL;
986         char                    *EmailAddress = NULL;
987         char                    *ProxyAddress = NULL;
988         struct mapi_profile     profile;
989         char                    **attr_tmp = NULL;
990         char                    *tmp = NULL;
991         char                    *attr;
992         uint32_t                count = 0;
993
994         /* Sanity checks */
995         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
996         OPENCHANGE_RETVAL_IF(!profile_src, MAPI_E_INVALID_PARAMETER, NULL);
997         OPENCHANGE_RETVAL_IF(!profile_dst, MAPI_E_INVALID_PARAMETER, NULL);
998         OPENCHANGE_RETVAL_IF(!username, MAPI_E_INVALID_PARAMETER, NULL);
999
1000         /* Step 1. Copy the profile */
1001         retval = CopyProfile(mapi_ctx, profile_src, profile_dst);
1002         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1003
1004         /* retrieve username, EmailAddress and ProxyAddress */
1005         retval = OpenProfile(mapi_ctx, &profile, profile_src, NULL);
1006         OPENCHANGE_RETVAL_IF(retval, MAPI_E_NOT_FOUND, NULL);
1007
1008         mem_ctx = talloc_named(NULL, 0, "DuplicateProfile");
1009
1010         retval = GetProfileAttr(&profile, "username", &count, &attr_tmp);
1011         OPENCHANGE_RETVAL_IF(retval || !count, MAPI_E_NOT_FOUND, mem_ctx);
1012         username_src = talloc_strdup(mem_ctx, attr_tmp[0]);
1013         talloc_free(attr_tmp[0]);
1014
1015         retval = GetProfileAttr(&profile, "EmailAddress", &count, &attr_tmp);
1016         OPENCHANGE_RETVAL_IF(retval || !count, MAPI_E_NOT_FOUND, mem_ctx);
1017         EmailAddress = talloc_strdup(mem_ctx, attr_tmp[0]);
1018         talloc_free(attr_tmp[0]);
1019
1020         retval = GetProfileAttr(&profile, "ProxyAddress", &count, &attr_tmp);
1021         OPENCHANGE_RETVAL_IF(retval, MAPI_E_NOT_FOUND, mem_ctx);
1022         ProxyAddress = talloc_strdup(mem_ctx, attr_tmp[0]);
1023         talloc_free(attr_tmp[0]);
1024
1025         /* Change EmailAddress */
1026         {
1027                 int     i;
1028
1029                 tmp = NULL;
1030                 for (i = strlen(EmailAddress); i > 0; i--) {
1031                         if (EmailAddress[i] == '=') {
1032                                 tmp = talloc_strndup(mem_ctx, EmailAddress, i + 1);
1033                                 break;
1034                         }
1035                 }
1036                 OPENCHANGE_RETVAL_IF(!tmp, MAPI_E_INVALID_PARAMETER, mem_ctx);
1037
1038                 attr = talloc_asprintf(mem_ctx, "%s%s", tmp, username);
1039                 talloc_free(tmp);
1040                 mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "EmailAddress", attr);
1041                 talloc_free(attr);
1042         }
1043
1044         /* Change ProxyAddress */
1045         {
1046                 tmp = strstr(ProxyAddress, username_src);
1047                 attr = talloc_strndup(mem_ctx, ProxyAddress, strlen(ProxyAddress) - strlen(tmp));
1048                 tmp += strlen(username_src);
1049                 attr = talloc_asprintf_append(attr, "%s%s", username, tmp);
1050                 mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "ProxyAddress", attr);
1051                 talloc_free(attr);
1052         }
1053
1054         /* Step 2. Change parameters but cn (already changed) */
1055         mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "name", profile_dst);
1056         mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "username", username);
1057         mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "DisplayName", username);
1058         mapi_profile_modify_string_attr(mapi_ctx, profile_dst, "Account", username);
1059
1060         talloc_free(mem_ctx);
1061
1062         return MAPI_E_SUCCESS;
1063 }
1064
1065 /**
1066    \details Rename a profile
1067
1068    \param mapi_ctx pointer to the MAPI context
1069    \param old_profile old profile name
1070    \param profile new profile name
1071
1072    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1073  */
1074 _PUBLIC_ enum MAPISTATUS RenameProfile(struct mapi_context *mapi_ctx,
1075                                        const char *old_profile, 
1076                                        const char *profile)
1077 {
1078         TALLOC_CTX              *mem_ctx;
1079         enum MAPISTATUS         retval;
1080         struct SRowSet          proftable;
1081         struct SPropValue       *lpProp;
1082         struct ldb_message      *msg = NULL;
1083         bool                    found = false;
1084         char                    *dn = NULL;
1085         int                     ret;
1086         uint32_t                i;
1087
1088         /* Sanity checks */
1089         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1090         OPENCHANGE_RETVAL_IF(!old_profile, MAPI_E_INVALID_PARAMETER, NULL);
1091         OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
1092
1093         mem_ctx = mapi_ctx->mem_ctx;
1094
1095         retval = GetProfileTable(mapi_ctx, &proftable);
1096         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1097
1098         /* Step 1. Check if old profile exists */
1099         for (found = false, i = 0; i < proftable.cRows; i++) {
1100                 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DISPLAY_NAME);
1101                 if (lpProp && !strcmp(lpProp->value.lpszA, old_profile)) {
1102                         found = true;
1103                 }
1104         }
1105         OPENCHANGE_RETVAL_IF(found == false, MAPI_E_NOT_FOUND, proftable.aRow);
1106
1107         /* Step 2. Check if new profile already exists */
1108         for (found = false, i = 0; i < proftable.cRows; i++) {
1109                 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DISPLAY_NAME);
1110                 if (lpProp && !strcmp(lpProp->value.lpszA, profile)) {
1111                         found = true;
1112                 }
1113         }
1114         talloc_free(proftable.aRow);
1115         OPENCHANGE_RETVAL_IF(found == true, MAPI_E_INVALID_PARAMETER, NULL);
1116
1117         /* Step 3. Rename the profile */
1118         retval = ldb_rename_profile(mapi_ctx, mem_ctx, old_profile, profile);
1119         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1120
1121         /* Step 4. Change name and cn */
1122         msg = ldb_msg_new(mem_ctx);
1123         dn = talloc_asprintf(mem_ctx, "CN=%s,CN=Profiles", profile);
1124         msg->dn = ldb_dn_new(mem_ctx, mapi_ctx->ldb_ctx, dn);
1125         talloc_free(dn);
1126
1127         ret = ldb_msg_add_string(msg, "cn", profile);
1128         ret = ldb_msg_add_string(msg, "name", profile);
1129         for (i = 0; i < msg->num_elements; i++) {
1130                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
1131         }
1132
1133         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_CORRUPT_STORE, NULL);
1134         ret = ldb_modify(mapi_ctx->ldb_ctx, msg);
1135         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_CORRUPT_STORE, NULL);
1136
1137         return MAPI_E_SUCCESS;
1138 }
1139
1140
1141 /**
1142    \details Set a default profile for the database
1143
1144    \param mapi_ctx pointer to the MAPI context
1145    \param profname the name of the profile to make the default profile
1146
1147    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1148
1149    \note Developers may also call GetLastError() to retrieve the last
1150    MAPI error code. Possible MAPI error codes are:
1151    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1152    - MAPI_E_INVALID_PARAMETER: The profile parameter was not set
1153      properly.
1154    - MAPI_E_NOT_FOUND: The profile was not found in the database
1155
1156    \sa GetDefaultProfile, GetProfileTable, GetLastError
1157  */
1158 _PUBLIC_ enum MAPISTATUS SetDefaultProfile(struct mapi_context *mapi_ctx,
1159                                            const char *profname)
1160 {
1161         TALLOC_CTX              *mem_ctx;
1162         struct mapi_profile     profile;
1163         enum MAPISTATUS         retval;
1164
1165         /* Sanity checks */
1166         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1167         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1168         OPENCHANGE_RETVAL_IF(!profname, MAPI_E_INVALID_PARAMETER, NULL);
1169
1170         mem_ctx = talloc_named(NULL, 0, "SetDefaultProfile");
1171
1172         /* open profile */
1173         retval = ldb_load_profile(mem_ctx, mapi_ctx->ldb_ctx, &profile, profname, NULL);
1174         OPENCHANGE_RETVAL_IF(retval && retval != MAPI_E_INVALID_PARAMETER, retval, mem_ctx);
1175
1176         /* search any previous default profile and unset it */
1177         retval = ldb_clear_default_profile(mapi_ctx, mem_ctx);
1178
1179         /* set profname as the default profile */
1180         retval = mapi_profile_modify_string_attr(mapi_ctx, profname, "PR_DEFAULT_PROFILE", "1");
1181
1182         talloc_free(mem_ctx);
1183
1184         return retval;
1185 }
1186
1187
1188 /**
1189    \details Get the default profile from the database
1190
1191    \param mapi_ctx pointer to the MAPI context
1192    \param profname the result of the function (name of the default
1193    profile)
1194
1195    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1196
1197    \note Developers may also call GetLastError() to retrieve the last
1198    MAPI error code. Possible MAPI error codes are:
1199    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1200    - MAPI_E_NOT_FOUND: The profile was not found in the database
1201
1202    \note On success GetDefaultProfile profname string is allocated. It
1203    is up to the developer to free it when not needed anymore.
1204
1205    \sa SetDefaultProfile, GetProfileTable, GetLastError
1206 */
1207 _PUBLIC_ enum MAPISTATUS GetDefaultProfile(struct mapi_context *mapi_ctx,
1208                                            char **profname)
1209 {
1210         enum MAPISTATUS         retval;
1211         struct SRowSet          proftable;
1212         struct SPropValue       *lpProp;
1213         uint32_t                i;
1214         
1215
1216         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1217         
1218         retval = GetProfileTable(mapi_ctx, &proftable);
1219         OPENCHANGE_RETVAL_IF(retval, retval, NULL);
1220
1221         for (i = 0; i < proftable.cRows; i++) {
1222                 lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DEFAULT_PROFILE);
1223                 if (lpProp && (lpProp->value.l == 1)) {
1224                         lpProp = get_SPropValue_SRow(&(proftable.aRow[i]), PR_DISPLAY_NAME);
1225                         if (lpProp) {
1226                           *profname = talloc_strdup(mapi_ctx->mem_ctx, lpProp->value.lpszA);
1227                                 talloc_free(proftable.aRow);
1228                                 return MAPI_E_SUCCESS;
1229                         }
1230                 }
1231         }
1232         
1233         OPENCHANGE_RETVAL_ERR(MAPI_E_NOT_FOUND, proftable.aRow);
1234 }
1235
1236
1237 /**
1238    \details Retrieve the profile table
1239
1240    This function retrieves the profile table. Two fields are returned:
1241    - PR_DISPLAY_NAME: The profile name stored as a UTF8 string
1242    - PR_DEFAULT_PROFILE: Whether the profile is the default one(1) or
1243      not(0), stored as an integer
1244
1245    \param mapi_ctx pointer to the MAPI context  
1246    \param proftable the result of the call
1247
1248    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1249
1250    \note Developers may also call GetLastError() to retrieve the last
1251    MAPI error code. Possible MAPI error codes are:
1252    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1253    - MAPI_E_NOT_FOUND: The profile was not found in the database
1254
1255    \sa SetDefaultProfile, GetLastError
1256  */
1257 _PUBLIC_ enum MAPISTATUS GetProfileTable(struct mapi_context *mapi_ctx,
1258                                          struct SRowSet *proftable)
1259 {
1260         TALLOC_CTX                      *mem_ctx;
1261         enum ldb_scope                  scope = LDB_SCOPE_SUBTREE;
1262         struct ldb_context              *ldb_ctx;
1263         struct ldb_result               *res;
1264         struct ldb_message              *msg;
1265         struct ldb_dn                   *basedn;
1266         const char                      *attrs[] = {"cn", "PR_DEFAULT_PROFILE", NULL};
1267         int                             ret;
1268         uint32_t                        count;
1269
1270         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1271
1272         ldb_ctx = mapi_ctx->ldb_ctx;
1273         mem_ctx = talloc_autofree_context();
1274
1275         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1276         ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, scope, attrs, "(cn=*)");
1277         talloc_free(basedn);
1278         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1279
1280         /* Allocate Arow */
1281         proftable->cRows = res->count;
1282         proftable->aRow = talloc_array(mapi_ctx->mem_ctx, struct SRow, res->count);
1283
1284         /* Build Arow array */
1285         for (count = 0; count < res->count; count++) {
1286                 msg = res->msgs[count];
1287                 
1288                 proftable->aRow[count].lpProps = talloc_array((TALLOC_CTX *)proftable->aRow, struct SPropValue, 2);
1289                 proftable->aRow[count].cValues = 2;
1290
1291                 proftable->aRow[count].lpProps[0].ulPropTag = PR_DISPLAY_NAME;
1292                 proftable->aRow[count].lpProps[0].value.lpszA = talloc_strdup((TALLOC_CTX *)proftable->aRow, 
1293                                                                               ldb_msg_find_attr_as_string(msg, "cn", NULL));
1294                                                                               
1295                 proftable->aRow[count].lpProps[1].ulPropTag = PR_DEFAULT_PROFILE;
1296                 proftable->aRow[count].lpProps[1].value.l = ldb_msg_find_attr_as_int(msg, "PR_DEFAULT_PROFILE", 0);
1297         }
1298
1299         talloc_free(res);
1300
1301         return MAPI_E_SUCCESS;
1302 }
1303
1304
1305 /**
1306    \details Retrieve attribute values from a profile
1307
1308    This function retrieves all the attribute values from the given
1309    profile.  The number of results is stored in \a count and values
1310    are stored in an allocated string array in the \a value parameter
1311    that needs to be free'd using MAPIFreeBuffer().
1312    
1313    \param profile the name of the profile to retrieve attributes from
1314    \param attribute the attribute(s) to search for
1315    \param count the number of results
1316    \param value the resulting values
1317    
1318    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1319
1320    \note Developers may also call GetLastError() to retrieve the last
1321    MAPI error code. Possible MAPI error codes are:
1322    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized
1323    - MAPI_E_INVALID_PARAMETER: Either profile or attribute was not set
1324      properly
1325    - MAPI_E_NOT_FOUND: The profile was not found in the database
1326
1327    \sa SetDefaultProfile, GetDefaultProfile, MAPIFreeBuffer,
1328    GetProfileTable, GetLastError
1329 */
1330 _PUBLIC_ enum MAPISTATUS GetProfileAttr(struct mapi_profile *profile, 
1331                                         const char *attribute, 
1332                                         unsigned int *count,
1333                                         char ***value)
1334 {
1335         TALLOC_CTX                      *mem_ctx;
1336         struct mapi_context             *mapi_ctx;
1337         struct ldb_context              *ldb_ctx;
1338         struct ldb_result               *res;
1339         struct ldb_message              *msg;
1340         struct ldb_message_element      *ldb_element;
1341         struct ldb_dn                   *basedn;
1342         const char                      *attrs[] = {"*", NULL};
1343         int                             ret;
1344         uint32_t                        i;
1345
1346         /* Sanity checks */
1347         OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
1348         OPENCHANGE_RETVAL_IF(!attribute, MAPI_E_INVALID_PARAMETER, NULL);
1349
1350         mapi_ctx = profile->mapi_ctx;
1351         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1352         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1353
1354         mem_ctx = (TALLOC_CTX *)mapi_ctx->ldb_ctx;
1355         ldb_ctx = mapi_ctx->ldb_ctx;
1356
1357         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1358
1359         ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "(cn=%s)", profile->profname);
1360         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1361
1362         msg = res->msgs[0];
1363         ldb_element = ldb_msg_find_element(msg, attribute);
1364         if (!ldb_element) {
1365                 DEBUG(3, ("ldb_msg_find_element: NULL\n"));
1366                 return MAPI_E_NOT_FOUND;
1367         }
1368
1369         *count = ldb_element[0].num_values;
1370         value[0] = talloc_array(mem_ctx, char *, *count);
1371
1372         if (*count == 1) {
1373                 value[0][0] = talloc_strdup(value[0], 
1374                                                 ldb_msg_find_attr_as_string(msg, attribute, NULL));
1375         } else {
1376                 for (i = 0; i < *count; i++) {
1377                         value[0][i] = talloc_strdup(mem_ctx, (char *)ldb_element->values[i].data);
1378                 }
1379         }
1380
1381         return MAPI_E_SUCCESS;
1382 }
1383
1384 /**
1385    \details Search the value of an attribute within a given profile
1386
1387    \param profile pointer to the MAPI profile
1388    \param attribute pointer to the attribute name
1389    \param value pointer to the attribute value
1390
1391    \return MAPI_E_SUCCESS on success, otherwise MAPI error
1392  */
1393 _PUBLIC_ enum MAPISTATUS FindProfileAttr(struct mapi_profile *profile, 
1394                                          const char *attribute, 
1395                                          const char *value)
1396 {
1397         TALLOC_CTX                      *mem_ctx;
1398         struct mapi_context             *mapi_ctx;
1399         struct ldb_context              *ldb_ctx;
1400         struct ldb_result               *res;
1401         struct ldb_message              *msg;
1402         struct ldb_message_element      *ldb_element;
1403         struct ldb_val                  val;
1404         struct ldb_dn                   *basedn;
1405         const char                      *attrs[] = {"*", NULL};
1406         int                             ret;
1407
1408         OPENCHANGE_RETVAL_IF(!profile, MAPI_E_INVALID_PARAMETER, NULL);
1409         OPENCHANGE_RETVAL_IF(!attribute, MAPI_E_INVALID_PARAMETER, NULL);
1410         OPENCHANGE_RETVAL_IF(!value, MAPI_E_INVALID_PARAMETER, NULL);
1411
1412         mapi_ctx = profile->mapi_ctx;
1413         OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1414         OPENCHANGE_RETVAL_IF(!mapi_ctx->ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1415
1416         mem_ctx = (TALLOC_CTX *)mapi_ctx->ldb_ctx;
1417         ldb_ctx = mapi_ctx->ldb_ctx;
1418
1419         basedn = ldb_dn_new(ldb_ctx, ldb_ctx, "CN=Profiles");
1420
1421         ret = ldb_search(ldb_ctx, mem_ctx, &res, basedn, LDB_SCOPE_SUBTREE, attrs, "(CN=%s)", profile->profname);
1422         OPENCHANGE_RETVAL_IF(ret != LDB_SUCCESS, MAPI_E_NOT_FOUND, NULL);
1423         OPENCHANGE_RETVAL_IF(!res->count, MAPI_E_NOT_FOUND, NULL);
1424
1425         msg = res->msgs[0];
1426         ldb_element = ldb_msg_find_element(msg, attribute);
1427         OPENCHANGE_RETVAL_IF(!ldb_element, MAPI_E_NOT_FOUND, NULL);
1428
1429         val.data = (uint8_t *)talloc_strdup(mem_ctx, value);
1430         val.length = strlen(value);
1431         OPENCHANGE_RETVAL_IF(!ldb_msg_find_val(ldb_element, &val), MAPI_E_NOT_FOUND, NULL);
1432
1433         return MAPI_E_SUCCESS;
1434 }
1435
1436 /**
1437    Create the profile 
1438  */
1439
1440 static bool set_profile_attribute(struct mapi_context *mapi_ctx,
1441                                   const char *profname, 
1442                                   struct SRowSet rowset, 
1443                                   uint32_t index, 
1444                                   uint32_t property, 
1445                                   const char *attr)
1446 {
1447         struct SPropValue       *lpProp;
1448         enum MAPISTATUS         ret;
1449
1450         lpProp = get_SPropValue_SRow(&(rowset.aRow[index]), property);
1451
1452         if (!lpProp) {
1453                 DEBUG(3, ("MAPI Property %s not set\n", attr));
1454                 return true;
1455         }
1456
1457         ret = mapi_profile_add_string_attr(mapi_ctx, profname, attr, lpProp->value.lpszA);
1458
1459         if (ret != MAPI_E_SUCCESS) {
1460                 DEBUG(3, ("Problem adding attribute %s in profile %s\n", attr, profname));
1461                 return false;
1462         }
1463         return true;
1464 }
1465
1466 static bool set_profile_mvstr_attribute(struct mapi_context *mapi_ctx,
1467                                         const char *profname, 
1468                                         struct SRowSet rowset,
1469                                         uint32_t index, 
1470                                         uint32_t property, 
1471                                         const char *attr)
1472 {
1473         struct SPropValue       *lpProp;
1474         enum MAPISTATUS         ret;
1475         uint32_t                i;
1476
1477         lpProp = get_SPropValue_SRow(&(rowset.aRow[index]), property);
1478
1479         if (!lpProp) {
1480                 DEBUG(3, ("MAPI Property %s not set\n", attr));
1481                 return true;
1482         }
1483
1484         for (i = 0; i < lpProp->value.MVszA.cValues; i++) {
1485                 ret = mapi_profile_add_string_attr(mapi_ctx, profname, attr, lpProp->value.MVszA.lppszA[i]);
1486                 if (ret != MAPI_E_SUCCESS) {
1487                         DEBUG(3, ("Problem adding attribute %s in profile %s\n", attr, profname));
1488                         return false;
1489                 }
1490         }
1491         return true;
1492 }
1493
1494
1495 /**
1496    \details Process a full and automated MAPI profile creation
1497
1498    This function process a full and automated MAPI profile creation
1499    using the \a username pattern passed as a parameter. The functions
1500    takes a callback parameter which will be called when the username
1501    checked matches several usernames. Private data needed by the
1502    callback can be supplied using the private_data pointer.
1503
1504    \code
1505    typedef int (*mapi_callback_t) callback(struct SRowSet *, void *private_data);
1506    \endcode
1507    
1508    The callback returns the SRow element index within the SRowSet
1509    structure.  If the user cancels the operation the callback return
1510    value should be SRowSet->cRows or more.
1511
1512    \param session the session context
1513    \param username the username for the network profile
1514    \param callback function pointer callback function
1515    \param private_data context data that will be provided to the callback
1516
1517    \return MAPI_E_SUCCESS on success, otherwise MAPI error.
1518
1519    \note Developers may also call GetLastError() to retrieve the last
1520    MAPI error code. Possible MAPI error codes are:
1521
1522    - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been
1523      initialized. The MAPI subsystem must be initialized (using
1524      MAPIInitialize) prior to creating a profile.
1525    - MAPI_E_END_OF_SESSION: The NSPI session has not been initialized
1526    - MAPI_E_CANCEL_USER: The user has aborted the operation
1527    - MAPI_E_INVALID_PARAMETER: The profile parameter was not set
1528      properly.
1529    - MAPI_E_NOT_FOUND: One of the mandatory field was not found during
1530      the profile creation process.
1531
1532    \sa OpenProfileStore, MAPILogonProvider, GetLastError
1533 */
1534 _PUBLIC_ enum MAPISTATUS ProcessNetworkProfile(struct mapi_session *session, 
1535                                                const char *username,
1536                                                mapi_profile_callback_t callback, 
1537                                                const void *private_data)
1538 {
1539         TALLOC_CTX              *mem_ctx;
1540         enum MAPISTATUS         retval;
1541         struct mapi_context     *mapi_ctx;
1542         struct nspi_context     *nspi;
1543         struct SPropTagArray    *SPropTagArray = NULL;
1544         struct Restriction_r    Filter;
1545         struct SRowSet          *SRowSet;
1546         struct SPropValue       *lpProp = NULL;
1547         struct SPropTagArray    *MIds = NULL;
1548         struct SPropTagArray    MIds2;
1549         struct SPropTagArray    *MId_server = NULL;
1550         struct StringsArray_r   pNames;
1551         const char              *profname;
1552         uint32_t                instance_key = 0;
1553         uint32_t                index = 0;
1554
1555         OPENCHANGE_RETVAL_IF(!session, MAPI_E_NOT_INITIALIZED, NULL);
1556         OPENCHANGE_RETVAL_IF(!session->nspi->ctx, MAPI_E_END_OF_SESSION, NULL);
1557         OPENCHANGE_RETVAL_IF(!session->mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL);
1558
1559         mapi_ctx = session->mapi_ctx;
1560
1561         mem_ctx = talloc_named(NULL, 0, "ProcessNetworkProfile");
1562         nspi = (struct nspi_context *) session->nspi->ctx;
1563         profname = session->profile->profname;
1564         index = 0;
1565
1566         SRowSet = talloc_zero(mem_ctx, struct SRowSet);
1567         retval = nspi_GetSpecialTable(nspi, mem_ctx, 0x0, &SRowSet);
1568         MAPIFreeBuffer(SRowSet);
1569         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1570
1571         SPropTagArray = set_SPropTagArray(mem_ctx, 0xc,
1572                                           PR_DISPLAY_NAME,
1573                                           PR_OFFICE_TELEPHONE_NUMBER,
1574                                           PR_OFFICE_LOCATION,
1575                                           PR_TITLE,
1576                                           PR_COMPANY_NAME,
1577                                           PR_ACCOUNT,
1578                                           PR_ADDRTYPE,
1579                                           PR_ENTRYID,
1580                                           PR_OBJECT_TYPE,
1581                                           PR_DISPLAY_TYPE,
1582                                           PR_INSTANCE_KEY,
1583                                           PR_EMAIL_ADDRESS
1584                                           );
1585
1586         /* Retrieve the username to match */
1587         if (!username) {
1588                 username = cli_credentials_get_username(nspi->cred);
1589                 OPENCHANGE_RETVAL_IF(!username, MAPI_E_INVALID_PARAMETER, mem_ctx);
1590         }
1591
1592         /* Build the restriction we want for NspiGetMatches */
1593         lpProp = talloc_zero(mem_ctx, struct SPropValue);
1594         lpProp->ulPropTag = PR_ANR_UNICODE;
1595         lpProp->dwAlignPad = 0;
1596         lpProp->value.lpszW = username;
1597
1598         Filter.rt = (enum RestrictionType_r)RES_PROPERTY;
1599         Filter.res.resProperty.relop = RES_PROPERTY;
1600         Filter.res.resProperty.ulPropTag = PR_ANR_UNICODE;
1601         Filter.res.resProperty.lpProp = lpProp;
1602
1603         SRowSet = talloc_zero(mem_ctx, struct SRowSet);
1604         MIds = talloc_zero(mem_ctx, struct SPropTagArray);
1605         retval = nspi_GetMatches(nspi, mem_ctx, SPropTagArray, &Filter, &SRowSet, &MIds);
1606         MAPIFreeBuffer(SPropTagArray);
1607         MAPIFreeBuffer(lpProp);
1608         if (retval != MAPI_E_SUCCESS) {
1609                 MAPIFreeBuffer(MIds);
1610                 MAPIFreeBuffer(SRowSet);
1611                 talloc_free(mem_ctx);
1612                 return retval;
1613         }
1614
1615         /* if there's no match */
1616         OPENCHANGE_RETVAL_IF(!SRowSet, MAPI_E_NOT_FOUND, mem_ctx);
1617         OPENCHANGE_RETVAL_IF(!SRowSet->cRows, MAPI_E_NOT_FOUND, mem_ctx);
1618         OPENCHANGE_RETVAL_IF(!MIds, MAPI_E_NOT_FOUND, mem_ctx);
1619
1620         /* if SRowSet count is superior than 1 an callback is specified, call it */
1621         if (SRowSet->cRows > 1 && callback) {
1622                 index = callback(SRowSet, private_data);
1623                 OPENCHANGE_RETVAL_IF((index >= SRowSet->cRows), MAPI_E_USER_CANCEL, mem_ctx);
1624                 instance_key = MIds->aulPropTag[index];
1625         } else {
1626                 instance_key = MIds->aulPropTag[0];
1627         }
1628         MAPIFreeBuffer(MIds);
1629         
1630         MIds2.cValues = 0x1;
1631         MIds2.aulPropTag = (enum MAPITAGS *) &instance_key;
1632
1633         set_profile_attribute(mapi_ctx, profname, *SRowSet, index, PR_EMAIL_ADDRESS, "EmailAddress");
1634         set_profile_attribute(mapi_ctx, profname, *SRowSet, index, PR_DISPLAY_NAME, "DisplayName");
1635         set_profile_attribute(mapi_ctx, profname, *SRowSet, index, PR_ACCOUNT, "Account");
1636         set_profile_attribute(mapi_ctx, profname, *SRowSet, index, PR_ADDRTYPE, "AddrType");
1637
1638         SPropTagArray = set_SPropTagArray(mem_ctx, 0x7,
1639                                           PR_DISPLAY_NAME,
1640                                           PR_EMAIL_ADDRESS,
1641                                           PR_DISPLAY_TYPE,
1642                                           PR_EMS_AB_HOME_MDB,
1643                                           PR_ATTACH_NUM,
1644                                           PR_PROFILE_HOME_SERVER_ADDRS,
1645                                           PR_EMS_AB_PROXY_ADDRESSES
1646                                           );
1647
1648         nspi->pStat->CurrentRec = 0x0;
1649         nspi->pStat->Delta = 0x0;
1650         nspi->pStat->NumPos = 0x0;
1651         nspi->pStat->TotalRecs = 0x1;
1652
1653         MAPIFreeBuffer(SRowSet);
1654         SRowSet = talloc(mem_ctx, struct SRowSet);
1655         retval = nspi_QueryRows(nspi, mem_ctx, SPropTagArray, &MIds2, 1, &SRowSet);
1656         MAPIFreeBuffer(SPropTagArray);
1657         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1658
1659         lpProp = get_SPropValue_SRowSet(SRowSet, PR_EMS_AB_HOME_MDB);
1660         OPENCHANGE_RETVAL_IF(!lpProp, MAPI_E_NOT_FOUND, mem_ctx);
1661
1662         nspi->org = x500_get_dn_element(mem_ctx, lpProp->value.lpszA, ORG);
1663         nspi->org_unit = x500_get_dn_element(mem_ctx, lpProp->value.lpszA, ORG_UNIT);
1664         
1665         OPENCHANGE_RETVAL_IF(!nspi->org_unit, MAPI_E_INVALID_PARAMETER, mem_ctx);
1666         OPENCHANGE_RETVAL_IF(!nspi->org, MAPI_E_INVALID_PARAMETER, mem_ctx);
1667
1668         retval = mapi_profile_add_string_attr(mapi_ctx, profname, "Organization", nspi->org);
1669         retval = mapi_profile_add_string_attr(mapi_ctx, profname, "OrganizationUnit", nspi->org_unit);
1670
1671         nspi->servername = x500_get_servername(lpProp->value.lpszA);
1672         mapi_profile_add_string_attr(mapi_ctx, profname, "ServerName", nspi->servername);
1673         set_profile_attribute(mapi_ctx, profname, *SRowSet, 0, PR_EMS_AB_HOME_MDB, "HomeMDB");
1674         set_profile_mvstr_attribute(mapi_ctx, profname, *SRowSet, 0, PR_EMS_AB_PROXY_ADDRESSES, "ProxyAddress");
1675
1676         pNames.Count = 0x1;
1677         pNames.Strings = (const char **) talloc_array(mem_ctx, char **, 1);
1678         pNames.Strings[0] = (const char *) talloc_asprintf(mem_ctx, SERVER_DN, 
1679                                                            nspi->org, nspi->org_unit, 
1680                                                            nspi->servername);
1681         MId_server = talloc_zero(mem_ctx, struct SPropTagArray);
1682         retval = nspi_DNToMId(nspi, mem_ctx, &pNames, &MId_server);
1683         MAPIFreeBuffer((char *)pNames.Strings[0]);
1684         MAPIFreeBuffer((char **)pNames.Strings);
1685         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1686
1687         MAPIFreeBuffer(SRowSet);
1688         SRowSet = talloc_zero(mem_ctx, struct SRowSet);
1689         SPropTagArray = set_SPropTagArray(mem_ctx, 0x1, PR_EMS_AB_NETWORK_ADDRESS);
1690         retval = nspi_GetProps(nspi, mem_ctx, SPropTagArray, MId_server, &SRowSet);
1691         MAPIFreeBuffer(SPropTagArray);
1692         MAPIFreeBuffer(MId_server);
1693         OPENCHANGE_RETVAL_IF(retval, retval, mem_ctx);
1694
1695         set_profile_mvstr_attribute(mapi_ctx, profname, *SRowSet, 0, PR_EMS_AB_NETWORK_ADDRESS, "NetworkAddress");
1696         MAPIFreeBuffer(SRowSet);
1697         talloc_free(mem_ctx);
1698
1699         return MAPI_E_SUCCESS;
1700 }