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