librpc/wsp: adjust the wsp property api to additionally use a csv file
[Samba.git] / librpc / wsp / wsp_util.c
blobd2bebc3b92d067a84ef380cff891c51fba3116ed
1 /*
2 * Unix SMB/CIFS implementation.
4 * Window Search Service
6 * Copyright (c) Noel Power
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "librpc/wsp/wsp_util.h"
23 #include "librpc/gen_ndr/wsp.h"
24 #include "librpc/gen_ndr/ndr_wsp.h"
25 #include "lib/util/strv_util.h"
26 #include "lib/util/strv.h"
27 #include "lib/util/util_str_hex.h"
28 #include "source3/param/param_proto.h"
29 #include "lib/util/dlinklist.h"
31 #define BUFFER_SIZE 1024000
32 struct guidtopropmap_holder
34 struct guidtopropmap *guidtopropmaploc;
37 struct full_propset_info_list {
38 struct full_propset_info_list *prev, *next;
39 struct full_propset_info info;
42 struct guidtopropmap {
43 struct guidtopropmap *prev, *next;
44 struct GUID guid;
45 struct full_propset_info_list *propset;
48 static struct guidtopropmap *find_guid_props(
49 struct guidtopropmap_holder *holder,
50 const struct GUID *guid)
52 struct guidtopropmap *mapitem;
53 for (mapitem = holder->guidtopropmaploc; mapitem; mapitem = mapitem->next) {
54 if (GUID_equal(guid, &mapitem->guid)) {
55 return mapitem;
58 return NULL;
61 static bool getbool(char *str)
63 char *cpy = talloc_strdup(NULL, str);
64 bool result;
66 trim_string(cpy, " ", " ");
67 if (strequal("TRUE", cpy)) {
68 result = true;
69 } else {
70 result = false;
72 TALLOC_FREE(cpy);
73 return result;
76 struct {
77 const char* typename;
78 uint16_t type;
79 } vtype_map[] = {
80 {"GUID", VT_CLSID},
81 {"String", VT_LPWSTR},
82 {"BString", VT_BSTR},
83 {"Double", VT_R8},
84 {"Buffer", VT_BLOB_OBJECT},
85 {"Byte", VT_UI1},
86 {"UInt64", VT_UI8},
87 {"Int64", VT_I8},
88 {"UInt32", VT_UI4},
89 {"Int32", VT_I4},
90 {"UInt16", VT_UI2},
91 {"Int16", VT_I2},
92 {"DateTime", VT_FILETIME},
93 {"Boolean", VT_BOOL}
96 static uint16_t getvtype(char *str, bool isvec)
98 uint16_t result = UINT16_MAX;
99 int i;
100 for (i = 0; i < ARRAY_SIZE(vtype_map); i++) {
101 if (strequal(vtype_map[i].typename, str)) {
102 result = vtype_map[i].type;
103 if (isvec) {
104 result |= VT_VECTOR;
106 break;
109 return result;
112 static bool parse_csv_line(TALLOC_CTX *ctx,
113 char **csvs, size_t num_values,
114 struct guidtopropmap_holder *propmap_holder)
116 struct guidtopropmap *mapitem = NULL;
117 struct full_propset_info_list *item = NULL;
119 char *guid_str = NULL;
120 struct GUID guid;
121 bool ok;
123 item = talloc_zero(ctx,
124 struct full_propset_info_list);
125 if (!item) {
126 return false;
129 item->info.in_inverted_index = false;
130 item->info.is_column = true;
131 item->info.can_col_be_indexed = true;
133 if (strlen(csvs[1])) {
134 guid_str = talloc_strdup(ctx, csvs[1]);
137 if (!guid_str) {
138 DBG_ERR("out of memory\n");
139 return false;
142 if (!trim_string(guid_str, "{", "}")) {
143 return false;
146 if (strlen(csvs[0])) {
147 char *tmp = talloc_strdup(item, csvs[0]);
148 trim_string(tmp, " ", " ");
149 item->info.name = tmp;
152 if (strlen(csvs[2])) {
153 item->info.id = atoi(csvs[2]);
156 if (strlen(csvs[3])) {
157 item->info.in_inverted_index = getbool(csvs[3]);
160 if (strlen(csvs[4])) {
161 item->info.is_column = getbool(csvs[4]);
164 if (strlen(csvs[5])) {
165 item->info.can_col_be_indexed = getbool(csvs[5]);
168 if (strlen(csvs[6])) {
169 bool isvec = false;
170 uint16_t type;
171 if (strlen(csvs[0])) {
172 isvec = getbool(csvs[8]);
174 type = getvtype(csvs[6], isvec);
175 if (type == UINT16_MAX) {
176 DBG_ERR("failed to parse type\n");
177 return false;
179 item->info.vtype = type;
182 ok = parse_guid_string(guid_str, &guid);
183 if (!ok) {
184 return false;
187 mapitem = find_guid_props(propmap_holder, &guid);
188 if (!mapitem) {
189 mapitem = talloc_zero(propmap_holder,
190 struct guidtopropmap);
191 if (!mapitem) {
192 return false;
194 mapitem->guid = guid;
195 DLIST_ADD_END(propmap_holder->guidtopropmaploc, mapitem);
198 talloc_steal(mapitem, item);
199 DLIST_ADD_END(mapitem->propset, item);
200 return true;
203 static bool parse_properties_line(TALLOC_CTX *ctx,
204 const char* line,
205 struct guidtopropmap_holder *propmap_holder)
207 int ret;
208 int pos;
209 char* strv = NULL;
210 char** csv_line = NULL;
211 char* t = NULL;
212 size_t len;
214 ret = strv_split(ctx,
215 &strv,
216 line,
217 ",");
219 if (ret != 0) {
220 DBG_ERR("failed to split line\n");
221 return false;
224 len = strv_count(strv);
226 if (len < 9) {
227 DBG_WARNING("skipping line as it doesn't have "
228 "enough fields\n");
229 return true;
232 csv_line = talloc_zero_array(ctx,
233 char *,
234 len);
236 if (!csv_line) {
237 DBG_ERR("out of memory\n");
238 return false;
240 for (pos = 0; pos < talloc_array_length(csv_line); pos++) {
241 t = strv_next(strv, t);
242 /* the scraped property file can have a non ascii char */
243 if (strlen(t) == 1 && *t == 0xa0) {
244 csv_line[pos] = talloc_strdup(csv_line,
245 "");
246 } else {
247 csv_line[pos] = talloc_strdup(csv_line,
250 trim_string(csv_line[pos], " ", " ");
253 if (!parse_csv_line(csv_line, csv_line, len, propmap_holder)) {
254 DBG_ERR("failed to parse line\n");
255 TALLOC_FREE(csv_line);
256 return false;
258 TALLOC_FREE(csv_line);
259 return true;
262 static bool parse_properties_csvfile(TALLOC_CTX *ctx,
263 struct guidtopropmap_holder *propmap_holder,
264 const char* filename)
266 char **lines = NULL;
267 int numlines;
268 int i;
270 if (filename == NULL || strlen(filename) == 0) {
271 return false;
274 lines = file_lines_load(filename,
275 &numlines,
276 BUFFER_SIZE,
277 ctx);
278 if (!lines) {
279 DBG_ERR("Failed to load %s\n", filename);
280 return false;
282 DBG_ERR("parsed %d lines\n", numlines);
284 for (i = 0; i < numlines; i++) {
285 TALLOC_CTX *line_ctx = talloc_init("line context");
286 if (!line_ctx) {
287 DBG_ERR("out of memory\n");
288 return false;
291 trim_string(lines[i], " ", " ");
292 if (lines[i][0] == '#') {
293 DBG_WARNING("skipping comment at line %d.\n)", i);
294 TALLOC_FREE(line_ctx);
295 continue;
298 if (!parse_properties_line(line_ctx,
299 lines[i],
300 propmap_holder)) {
301 DBG_ERR("Failed to parse line %d\n", i);
303 TALLOC_FREE(line_ctx);
305 return true;
308 static bool populate_map(struct guidtopropmap_holder *propmap_holder)
310 const char * path = NULL;
311 path = lp_wsp_property_file();
313 /* first populate the map from property file */
314 if (path) {
315 parse_properties_csvfile(propmap_holder, propmap_holder, path);
318 return true;
321 static struct guidtopropmap_holder *propmap(void)
323 static struct guidtopropmap_holder *holder = NULL;
325 if (!holder) {
326 holder = talloc_zero(NULL, struct guidtopropmap_holder);
327 if (holder) {
328 populate_map(holder);
332 return holder;
335 const struct full_propset_info *get_propset_info_with_guid(
336 const char *prop_name,
337 struct GUID *propset_guid)
339 const struct full_propset_info *result = NULL;
340 struct guidtopropmap_holder *holder = NULL;
341 struct guidtopropmap *mapitem = NULL;
343 size_t i;
344 const struct full_guid_propset *guid_propset = NULL;
346 /* search builtin props first */
347 for (i = 0; full_propertyset[i].prop_info != NULL; i++) {
348 const struct full_propset_info *item = NULL;
349 guid_propset = &full_propertyset[i];
350 item = guid_propset->prop_info;
351 while (item->id) {
352 if (strequal(prop_name, item->name)) {
353 *propset_guid = guid_propset->guid;
354 result = item;
355 break;
357 item++;
359 if (result) {
360 break;
364 if (result) {
365 return result;
368 /* if we didn't find a match in builtin props try the extra props */
369 holder = propmap();
370 for (mapitem = holder->guidtopropmaploc; mapitem;
371 mapitem = mapitem->next) {
372 struct full_propset_info_list *propitem;
373 for (propitem = mapitem->propset; propitem;
374 propitem = propitem->next) {
375 if (strequal(prop_name, propitem->info.name)) {
376 *propset_guid = mapitem->guid;
377 result = &propitem->info;
378 break;
382 return result;
385 const struct full_propset_info *get_prop_info(const char *prop_name)
387 const struct full_propset_info *result = NULL;
388 struct GUID guid;
389 result = get_propset_info_with_guid(prop_name, &guid);
390 return result;
393 char *prop_from_fullprop(TALLOC_CTX *ctx, struct wsp_cfullpropspec *fullprop)
395 size_t i;
396 char *result = NULL;
397 const struct full_propset_info *item = NULL;
398 const struct full_propset_info_list *prop_item = NULL;
399 bool search_by_id = (fullprop->ulkind == PRSPEC_PROPID);
400 struct guidtopropmap_holder *holder = NULL;
401 struct guidtopropmap *mapitem = NULL;
403 /* check builtin properties */
404 for (i = 0; full_propertyset[i].prop_info != NULL; i++) {
405 /* find propset */
406 if (GUID_equal(&fullprop->guidpropset,
407 &full_propertyset[i].guid)) {
408 item = full_propertyset[i].prop_info;
409 break;
412 if (item) {
413 while (item->id) {
414 if (search_by_id) {
415 if( fullprop->name_or_id.prspec == item->id) {
416 result = talloc_strdup(ctx, item->name);
417 break;
419 } else if (strcmp(item->name,
420 fullprop->name_or_id.propname.vstring)
421 == 0) {
422 result = talloc_strdup(ctx, item->name);
423 break;
425 item++;
429 /* not found, search the extra props */
430 if (!result) {
431 holder = propmap();
433 for (mapitem = holder->guidtopropmaploc; mapitem;
434 mapitem = mapitem->next) {
435 if (GUID_equal(&fullprop->guidpropset,
436 &mapitem->guid)) {
437 prop_item = mapitem->propset;
438 break;
442 for (;prop_item; prop_item = prop_item->next) {
443 if (search_by_id) {
444 if(fullprop->name_or_id.prspec ==
445 prop_item->info.id) {
446 result = talloc_strdup(ctx,
447 prop_item->info.name);
448 break;
450 } else if (strcmp(prop_item->info.name,
451 fullprop->name_or_id.propname.vstring) == 0) {
452 result = talloc_strdup(ctx,
453 prop_item->info.name);
454 break;
459 if (!result) {
460 result = GUID_string(ctx, &fullprop->guidpropset);
462 if (search_by_id) {
463 result = talloc_asprintf(result, "%s/%d", result,
464 fullprop->name_or_id.prspec);
465 } else {
466 result = talloc_asprintf(result, "%s/%s", result,
467 fullprop->name_or_id.propname.vstring);
470 return result;
473 struct wsp_cfullpropspec *get_full_prop(struct wsp_crestriction *restriction)
475 struct wsp_cfullpropspec *result;
476 switch (restriction->ultype) {
477 case RTPROPERTY:
478 result = &restriction->restriction.cpropertyrestriction.property;
479 break;
480 case RTCONTENT:
481 result = &restriction->restriction.ccontentrestriction.property;
482 break;
483 case RTNATLANGUAGE:
484 result = &restriction->restriction.cnatlanguagerestriction.property;
485 break;
486 default:
487 result = NULL;
488 break;
490 return result;