r7276: - moved static tdb function ltdb_dn_fold() into common/ so that it can be
[samba.git] / source / lib / ldb / common / ldb_utf8.c
1 /* 
2    ldb database library
3
4    Copyright (C) Andrew Tridgell  2004
5
6      ** NOTE! The following LGPL license applies to the ldb
7      ** library. This does NOT imply that all of Samba is released
8      ** under the LGPL
9    
10    This library is free software; you can redistribute it and/or
11    modify it under the terms of the GNU Lesser General Public
12    License as published by the Free Software Foundation; either
13    version 2 of the License, or (at your option) any later version.
14
15    This library is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    Lesser General Public License for more details.
19
20    You should have received a copy of the GNU Lesser General Public
21    License along with this library; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23 */
24
25 /*
26  *  Name: ldb
27  *
28  *  Component: ldb utf8 handling
29  *
30  *  Description: case folding and case comparison for UTF8 strings
31  *
32  *  Author: Andrew Tridgell
33  */
34
35 #include "includes.h"
36 #include "ldb/include/ldb.h"
37 #include "ldb/include/ldb_private.h"
38 #include <ctype.h>
39
40 /*
41   TODO:
42   a simple case folding function - will be replaced by a UTF8 aware function later
43 */
44 char *ldb_casefold(struct ldb_context *ldb, const char *s)
45 {
46         int i;
47         char *ret = talloc_strdup(ldb, s);
48         if (!s) {
49                 errno = ENOMEM;
50                 return NULL;
51         }
52         for (i=0;ret[i];i++) {
53                 ret[i] = toupper(ret[i]);
54         }
55         return ret;
56 }
57
58 /*
59   a caseless compare, optimised for 7 bit
60   TODO: doesn't yet handle UTF8
61 */
62 static int ldb_caseless_cmp(const char *s1, const char *s2)
63 {
64         int i;
65         for (i=0;s1[i] != 0;i++) {
66                 int c1 = toupper(s1[i]), c2 = toupper(s2[i]);
67                 if (c1 != c2) {
68                         return c1 - c2;
69                 }
70         }
71         return s2[i];
72 }
73
74 /*
75   compare two basedn fields
76   return 0 for match
77 */
78 int ldb_dn_cmp(const char *dn1, const char *dn2)
79 {
80         return ldb_caseless_cmp(dn1, dn2);
81 }
82
83 /*
84   compare two attributes
85   return 0 for match
86 */
87 int ldb_attr_cmp(const char *dn1, const char *dn2)
88 {
89         return ldb_caseless_cmp(dn1, dn2);
90 }
91
92
93 /*
94   casefold a dn. We need to uppercase the attribute names, and the 
95   attribute values of case insensitive attributes. We also need to remove
96   extraneous spaces between elements
97 */
98 char *ldb_dn_fold(struct ldb_module *module, const char *dn, int (*case_fold_attr_fn)(struct ldb_module * module, char * attr))
99 {
100         const char *dn_orig = dn;
101         struct ldb_context *ldb = module->ldb;
102         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
103         char *ret;
104         size_t len;
105
106         ret = talloc_strdup(tmp_ctx, "");
107         if (ret == NULL) goto failed;
108
109         while ((len = strcspn(dn, ",")) > 0) {
110                 char *p = strchr(dn, '=');
111                 char *attr, *value;
112                 int case_fold_required;
113
114                 if (p == NULL || (p-dn) > len) goto failed;
115
116                 attr = talloc_strndup(tmp_ctx, dn, p-dn);
117                 if (attr == NULL) goto failed;
118
119                 /* trim spaces from the attribute name */
120                 while (' ' == *attr) attr++;
121                 while (' ' == attr[strlen(attr)-1]) {
122                         attr[strlen(attr)-1] = 0;
123                 }
124                 if (*attr == 0) goto failed;
125
126                 value = talloc_strndup(tmp_ctx, p+1, len-(p+1-dn));
127                 if (value == NULL) goto failed;
128
129                 /* trim spaces from the value */
130                 while (' ' == *value) value++;
131                 while (' ' == value[strlen(value)-1]) {
132                         value[strlen(value)-1] = 0;
133                 }
134                 if (*value == 0) goto failed;
135
136                 case_fold_required = (* case_fold_attr_fn)(module, attr);
137
138                 attr = ldb_casefold(ldb, attr);
139                 if (attr == NULL) goto failed;
140                 talloc_steal(tmp_ctx, attr);
141
142                 if (case_fold_required) {
143                         value = ldb_casefold(ldb, value);
144                         if (value == NULL) goto failed;
145                         talloc_steal(tmp_ctx, value);
146                 }               
147
148                 if (dn[len] == ',') {
149                         ret = talloc_asprintf_append(ret, "%s=%s,", attr, value);
150                 } else {
151                         ret = talloc_asprintf_append(ret, "%s=%s", attr, value);
152                 }
153                 if (ret == NULL) goto failed;
154
155                 dn += len;
156                 if (*dn == ',') dn++;
157         }
158
159         talloc_steal(ldb, ret);
160         talloc_free(tmp_ctx);
161         return ret;
162
163 failed:
164         talloc_free(tmp_ctx);
165         return ldb_casefold(ldb, dn_orig);
166 }
167