r8635: make object inheritance with the builtin objects easy by allowing
[kai/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:"(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 struct MprVar mprLdbMessage(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(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                 if (el->num_values == 1 &&
170                     !str_list_check_ci(multivalued, el->name)) {
171                         val = mprData(el->values[0].data, el->values[0].length);
172                 } else {
173                         int j;
174                         val = mprObject(el->name);
175                         for (j=0;j<el->num_values;j++) {
176                                 mprAddArray(&val, j, 
177                                             mprData(el->values[j].data, 
178                                                     el->values[j].length));
179                         }
180                 }
181                 mprSetVar(&var, el->name, val);
182         }
183
184         /* add the dn if it is not already specified */
185         if (mprGetProperty(&var, "dn", 0) == 0) {
186                 mprSetVar(&var, "dn", mprString(msg->dn));
187         }
188         
189         return var;             
190 }
191
192
193 /*
194   turn an array of ldb_messages into a ejs object variable
195 */
196 struct MprVar mprLdbArray(struct ldb_message **msg, int count, const char *name)
197 {
198         struct MprVar res;
199         int i;
200
201         res = mprObject(name);
202         for (i=0;i<count;i++) {
203                 mprAddArray(&res, i, mprLdbMessage(msg[i]));
204         }
205         if (i==0) {
206                 mprSetVar(&res, "length", mprCreateIntegerVar(0));
207         }
208         return res;
209 }
210
211
212 /*
213   turn a MprVar string variable into a const char *
214  */
215 const char *mprToString(const struct MprVar *v)
216 {
217         if (!mprVarIsString(v->type)) return NULL;
218         return v->string;
219 }
220
221 /*
222   turn a MprVar integer variable into an int
223  */
224 int mprToInt(const struct MprVar *v)
225 {
226         if (!mprVarIsNumber(v->type)) return 0;
227         return mprVarToNumber(v);
228 }
229
230 /*
231   turn a MprVar object variable into a string list
232   this assumes the object variable consists only of strings
233 */
234 const char **mprToList(TALLOC_CTX *mem_ctx, struct MprVar *v)
235 {
236         const char **list = NULL;
237         struct MprVar *el;
238
239         if (v->type != MPR_TYPE_OBJECT ||
240             v->properties == NULL) {
241                 return NULL;
242         }
243         for (el=mprGetFirstProperty(v, MPR_ENUM_DATA);
244              el;
245              el=mprGetNextProperty(v, el, MPR_ENUM_DATA)) {
246                 const char *s = mprToString(el);
247                 if (s) {
248                         list = str_list_add(list, s);
249                 }
250         }
251         talloc_steal(mem_ctx, list);
252         return list;
253 }
254
255
256 /*
257   turn a MprVar object variable into a string list
258   this assumes the object variable is an array of strings
259 */
260 const char **mprToArray(TALLOC_CTX *mem_ctx, struct MprVar *v)
261 {
262         const char **list = NULL;
263         struct MprVar *len;
264         int length, i;
265
266         len = mprGetProperty(v, "length", NULL);
267         if (len == NULL) {
268                 return NULL;
269         }
270         length = mprToInt(len);
271
272         for (i=0;i<length;i++) {
273                 char idx[16];
274                 struct MprVar *vs;
275                 mprItoa(i, idx, sizeof(idx));           
276                 vs = mprGetProperty(v, idx, NULL);
277                 if (vs == NULL || vs->type != MPR_TYPE_STRING) {
278                         talloc_free(list);
279                         return NULL;
280                 }
281                 list = str_list_add(list, mprToString(vs));
282         }
283         talloc_steal(mem_ctx, list);
284         return list;
285 }
286
287 /*
288   turn a NTSTATUS into a MprVar object with lots of funky properties
289 */
290 struct MprVar mprNTSTATUS(NTSTATUS status)
291 {
292         struct MprVar res;
293
294         res = mprObject("ntstatus");
295
296         mprSetVar(&res, "errstr", mprString(nt_errstr(status)));
297         mprSetVar(&res, "v", mprCreateIntegerVar(NT_STATUS_V(status)));
298         mprSetVar(&res, "is_ok", mprCreateBoolVar(NT_STATUS_IS_OK(status)));
299         mprSetVar(&res, "is_err", mprCreateBoolVar(NT_STATUS_IS_ERR(status)));
300
301         return res;
302 }
303
304 /*
305   turn a WERROR into a MprVar object with lots of funky properties
306 */
307 struct MprVar mprWERROR(WERROR status)
308 {
309         struct MprVar res;
310
311         res = mprObject("werror");
312
313         mprSetVar(&res, "errstr", mprString(win_errstr(status)));
314         mprSetVar(&res, "v", mprCreateIntegerVar(W_ERROR_V(status)));
315         mprSetVar(&res, "is_ok", mprCreateBoolVar(W_ERROR_IS_OK(status)));
316         mprSetVar(&res, "is_err", mprCreateBoolVar(!W_ERROR_IS_OK(status)));
317
318         return res;
319 }
320
321
322 /*
323   set a pointer in a existing MprVar
324 */
325 void mprSetPtr(struct MprVar *v, const char *propname, const void *p)
326 {
327         mprSetVar(v, propname, mprCreatePtrVar(discard_const(p)));
328 }
329
330 /*
331   set a pointer in a existing MprVar, making it a child of the property
332 */
333 void mprSetPtrChild(struct MprVar *v, const char *propname, const void *p)
334 {
335         mprSetVar(v, propname, mprCreatePtrVar(discard_const(p)));
336         talloc_steal(mprGetProperty(v, propname, NULL), p);
337 }
338
339 /*
340   get a pointer from a MprVar
341 */
342 void *mprGetPtr(struct MprVar *v, const char *propname)
343 {
344         struct MprVar *val;
345         val = mprGetProperty(v, propname, NULL);
346         if (val == NULL) {
347                 return NULL;
348         }
349         if (val->type != MPR_TYPE_PTR) {
350                 return NULL;
351         }
352         return val->ptr;
353 }
354
355 /*
356   set the return value then free the variable
357 */
358  void mpr_Return(int eid, struct MprVar v)
359
360         ejsSetReturnValue(eid, v);
361         mprDestroyVar(&v);
362 }
363
364 /*
365   set the return value then free the variable
366 */
367 void mpr_ReturnString(int eid, const char *s)
368
369         mpr_Return(eid, mprString(s));
370 }
371
372
373 /*
374   set a C function in a variable
375 */
376  void mprSetCFunction(struct MprVar *obj, const char *name, MprCFunction fn)
377 {
378         mprSetVar(obj, name, mprCreateCFunctionVar(fn, obj, MPR_VAR_SCRIPT_HANDLE));
379 }
380
381 /*
382   set a string C function in a variable
383 */
384  void mprSetStringCFunction(struct MprVar *obj, const char *name, MprStringCFunction fn)
385 {
386         mprSetVar(obj, name, mprCreateStringCFunctionVar(fn, obj, MPR_VAR_SCRIPT_HANDLE));
387 }
388
389 /*
390   get a poiner in the current object
391 */
392 void *mprGetThisPtr(int eid, const char *name)
393 {
394         struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0);
395         return mprGetPtr(this, name);
396 }
397
398 /*
399   set a pointer as a child of the local object
400 */
401 void mprSetThisPtr(int eid, const char *name, void *ptr)
402 {
403         struct MprVar *this = mprGetProperty(ejsGetLocalObject(eid), "this", 0);
404         mprSetPtrChild(this, name, ptr);
405 }
406
407 /*
408   used by object xxx_init() routines to allow for the caller
409   to supply a pre-existing object to add properties to,
410   or create a new object. This makes inheritance easy
411 */
412 struct MprVar *mprInitObject(int eid, const char *name, int argc, struct MprVar **argv)
413 {
414         if (argc > 0 && mprVarIsObject(argv[0]->type)) {
415                 return argv[0];
416         }
417         mpr_Return(eid, mprObject(name));
418         return ejsGetReturnValue(eid);
419 }