r11458: fixed our ejs smbscript interfaces to use arrays where appropriate. In
[gd/samba/.git] / source4 / scripting / ejs / mprutil.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    utility functions for manipulating mpr variables in ejs calls
5
6    Copyright (C) Andrew Tridgell 2005
7    
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 2 of the License, or
11    (at your option) any later version.
12    
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.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "lib/appweb/ejs/ejs.h"
25 #include "lib/ldb/include/ldb.h"
26
27 /*
28   return a default mpr object
29 */
30 struct MprVar mprObject(const char *name)
31 {
32         return ejsCreateObj(name && *name?name:"(NULL)", MPR_DEFAULT_HASH_SIZE);
33 }
34
35 /*
36   return a empty mpr array
37 */
38 struct MprVar mprArray(const char *name)
39 {
40         return ejsCreateArray(name && *name?name:"(NULL)", 0);
41 }
42
43 /*
44   find a mpr component, allowing for sub objects, using the '.' convention
45 */
46  NTSTATUS mprGetVar(struct MprVar **v, const char *name)
47 {
48         const char *p = strchr(name, '.');
49         char *objname;
50         NTSTATUS status;
51         if (p == NULL) {
52                 *v = mprGetProperty(*v, name, NULL);
53                 if (*v == NULL) {
54                         DEBUG(1,("mprGetVar unable to find '%s'\n", name));
55                         return NT_STATUS_INVALID_PARAMETER;
56                 }
57                 return NT_STATUS_OK;
58         }
59         objname = talloc_strndup(mprMemCtx(), name, p-name);
60         NT_STATUS_HAVE_NO_MEMORY(objname);
61         *v = mprGetProperty(*v, objname, NULL);
62         NT_STATUS_HAVE_NO_MEMORY(*v);
63         status = mprGetVar(v, p+1);
64         talloc_free(objname);
65         return status;
66 }
67
68
69 /*
70   set a mpr component, allowing for sub objects, using the '.' convention
71   destroys 'val' after setting
72 */
73  NTSTATUS mprSetVar(struct MprVar *v, const char *name, struct MprVar val)
74 {
75         const char *p = strchr(name, '.');
76         char *objname;
77         struct MprVar *v2;
78         NTSTATUS status;
79         if (p == NULL) {
80                 v2 = mprSetProperty(v, name, &val);
81                 if (v2 == NULL) {
82                         DEBUG(1,("mprSetVar unable to set '%s'\n", name));
83                         return NT_STATUS_INVALID_PARAMETER_MIX;
84                 }
85                 mprDestroyVar(&val);
86                 return NT_STATUS_OK;
87         }
88         objname = talloc_strndup(mprMemCtx(), name, p-name);
89         if (objname == NULL) {
90                 return NT_STATUS_NO_MEMORY;
91         }
92         v2 = mprGetProperty(v, objname, NULL);
93         if (v2 == NULL) {
94                 mprSetVar(v, objname, mprObject(objname));
95                 v2 = mprGetProperty(v, objname, NULL);
96         }
97         status = mprSetVar(v2, p+1, val);
98         talloc_free(objname);
99         return status;
100 }
101
102
103
104 /*
105   add an indexed array element to a property
106 */
107  void mprAddArray(struct MprVar *var, int i, struct MprVar v)
108 {
109         char idx[16];
110         mprItoa(i, idx, sizeof(idx));
111         mprSetVar(var, idx, v);
112 }
113
114 /*
115   construct a MprVar from a list
116 */
117 struct MprVar mprList(const char *name, const char **list)
118 {
119         struct MprVar var;
120         int i;
121
122         var = mprArray(name);
123         for (i=0;list && list[i];i++) {
124                 mprAddArray(&var, i, mprString(list[i]));
125         }
126         return var;
127 }
128
129 /*
130   construct a MprVar from a string, using NULL if needed
131 */
132 struct MprVar mprString(const char *s)
133 {
134         if (s == NULL) {
135                 return mprCreatePtrVar(NULL);
136         }
137         return mprCreateStringVar(s, True);
138 }
139
140 /*
141   construct a string MprVar from a lump of data
142 */
143 struct MprVar mprData(const uint8_t *p, size_t length)
144 {
145         struct MprVar var;
146         char *s = talloc_strndup(mprMemCtx(), p, length);
147         if (s == NULL) {
148                 return mprCreateUndefinedVar();
149         }
150         var = mprString(s);
151         talloc_free(s);
152         return var;
153 }
154
155 /*
156   turn a ldb_message into a ejs object variable
157 */
158 static struct MprVar mprLdbMessage(struct ldb_context *ldb, struct ldb_message *msg)
159 {
160         struct MprVar var;
161         int i;
162         /* we force some attributes to always be an array in the
163            returned structure. This makes the scripting easier, as you don't 
164            need a special case for the single value case */
165         const char *multivalued[] = { "objectClass", "memberOf", "privilege", 
166                                             "member", NULL };
167
168         var = mprObject(ldb_dn_linearize(msg, msg->dn));
169
170         for (i=0;i<msg->num_elements;i++) {
171                 struct ldb_message_element *el = &msg->elements[i];
172                 struct MprVar val;
173                 const struct ldb_attrib_handler *attr;
174                 struct ldb_val v;
175
176                 attr = ldb_attrib_handler(ldb, el->name);
177                 if (attr == NULL) {
178                         goto failed;
179                 }
180
181                 if (el->num_values == 1 &&
182                     !str_list_check_ci(multivalued, el->name)) {
183                         if (attr->ldif_write_fn(ldb, msg, &el->values[0], &v) != 0) {
184                                 goto failed;
185                         }
186                         val = mprData(v.data, v.length);
187                 } else {
188                         int j;
189                         val = mprArray(el->name);
190                         for (j=0;j<el->num_values;j++) {
191                                 if (attr->ldif_write_fn(ldb, msg, 
192                                                         &el->values[j], &v) != 0) {
193                                         goto failed;
194                                 }
195                                 mprAddArray(&val, j, mprData(v.data, v.length));
196                         }
197                 }
198                 mprSetVar(&var, el->name, val);
199         }
200
201         /* add the dn if it is not already specified */
202         if (mprGetProperty(&var, "dn", 0) == 0) {
203                 mprSetVar(&var, "dn", mprString(ldb_dn_linearize(msg, msg->dn)));
204         }
205         
206         return var;             
207 failed:
208         return mprCreateUndefinedVar();
209 }
210
211
212 /*
213   turn an array of ldb_messages into a ejs object variable
214 */
215 struct MprVar mprLdbArray(struct ldb_context *ldb, 
216                           struct ldb_message **msg, int count, const char *name)
217 {
218         struct MprVar res;
219         int i;
220
221         res = mprArray(name);
222         for (i=0;i<count;i++) {
223                 mprAddArray(&res, i, mprLdbMessage(ldb, msg[i]));
224         }
225         return res;
226 }
227
228
229 /*
230   turn a MprVar string variable into a const char *
231  */
232 const char *mprToString(const struct MprVar *v)
233 {
234         if (v->trigger) {
235                 mprReadProperty(v, 0);
236         }
237         if (!mprVarIsString(v->type)) return NULL;
238         return v->string;
239 }
240
241 /*
242   turn a MprVar integer variable into an int
243  */
244 int mprToInt(const struct MprVar *v)
245 {
246         if (v->trigger) {
247                 mprReadProperty(v, 0);
248         }
249         if (!mprVarIsNumber(v->type)) return 0;
250         return mprVarToNumber(v);
251 }
252
253 /*
254   turn a MprVar object variable into a string list
255   this assumes the object variable consists only of strings
256 */
257 const char **mprToList(TALLOC_CTX *mem_ctx, struct MprVar *v)
258 {
259         const char **list = NULL;
260         struct MprVar *el;
261
262         if (v->type != MPR_TYPE_OBJECT ||
263             v->properties == NULL) {
264                 return NULL;
265         }
266         for (el=mprGetFirstProperty(v, MPR_ENUM_DATA);
267              el;
268              el=mprGetNextProperty(v, el, MPR_ENUM_DATA)) {
269                 const char *s = mprToString(el);
270                 if (s) {
271                         list = str_list_add(list, s);
272                 }
273         }
274         talloc_steal(mem_ctx, list);
275         return list;
276 }
277
278
279 /*
280   turn a MprVar object variable into a string list
281   this assumes the object variable is an array of strings
282 */
283 const char **mprToArray(TALLOC_CTX *mem_ctx, struct MprVar *v)
284 {
285         const char **list = NULL;
286         struct MprVar *len;
287         int length, i;
288
289         len = mprGetProperty(v, "length", NULL);
290         if (len == NULL) {
291                 return NULL;
292         }
293         length = mprToInt(len);
294
295         for (i=0;i<length;i++) {
296                 char idx[16];
297                 struct MprVar *vs;
298                 mprItoa(i, idx, sizeof(idx));           
299                 vs = mprGetProperty(v, idx, NULL);
300                 if (vs == NULL || vs->type != MPR_TYPE_STRING) {
301                         talloc_free(list);
302                         return NULL;
303                 }
304                 list = str_list_add(list, mprToString(vs));
305         }
306         talloc_steal(mem_ctx, list);
307         return list;
308 }
309
310 /*
311   turn a NTSTATUS into a MprVar object with lots of funky properties
312 */
313 struct MprVar mprNTSTATUS(NTSTATUS status)
314 {
315         struct MprVar res;
316
317         res = mprObject("ntstatus");
318
319         mprSetVar(&res, "errstr", mprString(nt_errstr(status)));
320         mprSetVar(&res, "v", mprCreateIntegerVar(NT_STATUS_V(status)));
321         mprSetVar(&res, "is_ok", mprCreateBoolVar(NT_STATUS_IS_OK(status)));
322         mprSetVar(&res, "is_err", mprCreateBoolVar(NT_STATUS_IS_ERR(status)));
323
324         return res;
325 }
326
327 /*
328   create a data-blob in a mpr variable
329 */
330 struct MprVar mprDataBlob(DATA_BLOB blob)
331 {
332         struct MprVar res;
333         struct datablob *pblob = talloc(mprMemCtx(), struct datablob);
334         *pblob = data_blob_talloc(pblob, blob.data, blob.length);
335
336         res = mprObject("DATA_BLOB");
337
338         mprSetVar(&res, "size", mprCreateIntegerVar(blob.length));
339         mprSetPtrChild(&res, "blob", pblob);
340
341         return res;
342 }
343
344 /*
345   return a data blob from a mpr var created using mprDataBlob
346 */
347 struct datablob *mprToDataBlob(struct MprVar *v)
348 {
349         return talloc_get_type(mprGetPtr(v, "blob"), struct datablob);
350 }
351
352 /*
353   turn a WERROR into a MprVar object with lots of funky properties
354 */
355 struct MprVar mprWERROR(WERROR status)
356 {
357         struct MprVar res;
358
359         res = mprObject("werror");
360
361         mprSetVar(&res, "errstr", mprString(win_errstr(status)));
362         mprSetVar(&res, "v", mprCreateIntegerVar(W_ERROR_V(status)));
363         mprSetVar(&res, "is_ok", mprCreateBoolVar(W_ERROR_IS_OK(status)));
364         mprSetVar(&res, "is_err", mprCreateBoolVar(!W_ERROR_IS_OK(status)));
365
366         return res;
367 }
368
369
370 /*
371   set a pointer in a existing MprVar
372 */
373 void mprSetPtr(struct MprVar *v, const char *propname, const void *p)
374 {
375         mprSetVar(v, propname, mprCreatePtrVar(discard_const(p)));
376 }
377
378 /*
379   set a pointer in a existing MprVar, freeing it when the property goes away
380 */
381 void mprSetPtrChild(struct MprVar *v, const char *propname, const void *p)
382 {
383         mprSetVar(v, propname, mprCreatePtrVar(discard_const(p)));
384         v = mprGetProperty(v, propname, NULL);
385         v->allocatedData = 1;
386         talloc_steal(mprMemCtx(), p);
387 }
388
389 /*
390   get a pointer from a MprVar
391 */
392 void *mprGetPtr(struct MprVar *v, const char *propname)
393 {
394         struct MprVar *val;
395         val = mprGetProperty(v, propname, NULL);
396         if (val == NULL) {
397                 return NULL;
398         }
399         if (val->type != MPR_TYPE_PTR) {
400                 return NULL;
401         }
402         return val->ptr;
403 }
404
405 /*
406   set the return value then free the variable
407 */
408  void mpr_Return(int eid, struct MprVar v)
409
410         ejsSetReturnValue(eid, v);
411         mprDestroyVar(&v);
412 }
413
414 /*
415   set the return value then free the variable
416 */
417 void mpr_ReturnString(int eid, const char *s)
418
419         mpr_Return(eid, mprString(s));
420 }
421
422
423 /*
424   set a C function in a variable
425 */
426  void mprSetCFunction(struct MprVar *obj, const char *name, MprCFunction fn)
427 {
428         mprSetVar(obj, name, mprCreateCFunctionVar(fn, obj, MPR_VAR_SCRIPT_HANDLE));
429 }
430
431 /*
432   set a string C function in a variable
433 */
434  void mprSetStringCFunction(struct MprVar *obj, const char *name, MprStringCFunction fn)
435 {
436         mprSetVar(obj, name, mprCreateStringCFunctionVar(fn, obj, MPR_VAR_SCRIPT_HANDLE));
437 }
438
439 /*
440   get a pointer in the current object
441 */
442 void *mprGetThisPtr(int eid, const char *name)
443 {
444         struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0);
445         return mprGetPtr(this, name);
446 }
447
448 /*
449   set a pointer as a child of the local object
450 */
451 void mprSetThisPtr(int eid, const char *name, void *ptr)
452 {
453         struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0);
454         mprSetPtrChild(this, name, ptr);
455 }
456
457 /*
458   used by object xxx_init() routines to allow for the caller
459   to supply a pre-existing object to add properties to,
460   or create a new object. This makes inheritance easy
461 */
462 struct MprVar *mprInitObject(int eid, const char *name, int argc, struct MprVar **argv)
463 {
464         if (argc > 0 && mprVarIsObject(argv[0]->type)) {
465                 return argv[0];
466         }
467         mpr_Return(eid, mprObject(name));
468         return ejsGetReturnValue(eid);
469 }