pump up version number and update changelog
[profile/ivi/pulseaudio-module-murphy-ivi.git] / murphy / scripting.c
1 /*
2  * Module-murphy-ivi -- PulseAudio module for providing audio routing support
3  * Copyright (c) 2012, Intel Corporation.
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms and conditions of the GNU Lesser General Public License,
7  * version 2.1, as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.
12  * See the GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
17  * MA 02110-1301 USA.
18  *
19  */
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdarg.h>
23 #include <ctype.h>
24 #include <errno.h>
25
26 #include <pulsecore/pulsecore-config.h>
27 #include <pulsecore/core-util.h>
28
29 #include <murphy/common/macros.h>
30 #include <murphy/common/mm.h>
31 #include <murphy/core/lua-utils/object.h>
32 #include <murphy/core/lua-utils/funcbridge.h>
33 #include <murphy/core/lua-utils/strarray.h>
34 #include <murphy/core/lua-utils/funcbridge.h>
35 #include <murphy/domain-control/client.h>
36 #include <murphy/resource/data-types.h>
37 #include <murphy/resource/protocol.h>
38
39 #include "scripting.h"
40 #include "zone.h"
41 #include "node.h"
42 #include "router.h"
43 #include "volume.h"
44 #include "murphyif.h"
45 #include "murphy-config.h"
46
47 #define IMPORT_CLASS       MRP_LUA_CLASS(mdb, import)
48 #define NODE_CLASS         MRP_LUA_CLASS(node, instance)
49 #define ZONE_CLASS         MRP_LUA_CLASS_SIMPLE(zone)
50 #define RESOURCE_CLASS     MRP_LUA_CLASS_SIMPLE(audio_resource)
51 #define RTGROUP_CLASS      MRP_LUA_CLASS_SIMPLE(routing_group)
52 #define APPLICATION_CLASS  MRP_LUA_CLASS_SIMPLE(application_class)
53 #define VOLLIM_CLASS       MRP_LUA_CLASS_SIMPLE(volume_limit)
54
55 #define ARRAY_CLASSID      MRP_LUA_CLASSID_ROOT "mdb_array"
56
57 #define USERDATA           "murphy_ivi_userdata"
58
59 #undef  MRP_LUA_ENTER
60 #define MRP_LUA_ENTER                                           \
61     pa_log_debug("%s() enter", __FUNCTION__)
62
63 #undef  MRP_LUA_LEAVE
64 #define MRP_LUA_LEAVE(_v)                                       \
65     do {                                                        \
66         pa_log_debug("%s() leave (%d)", __FUNCTION__, (_v));    \
67         return (_v);                                            \
68     } while (0)
69
70 #undef  MRP_LUA_LEAVE_NOARG
71 #define MRP_LUA_LEAVE_NOARG                                     \
72     pa_log_debug("%s() leave", __FUNCTION__)
73
74 typedef void (*update_func_t)(struct userdata *);
75
76 struct pa_scripting {
77     lua_State *L;
78     bool configured;
79 };
80
81 struct scripting_import {
82     struct userdata    *userdata;
83     const char         *table;
84     mrp_lua_strarray_t *columns;
85     const char         *condition;
86     pa_value           *values;
87     mrp_funcbridge_t   *update;
88 };
89
90 struct scripting_node {
91     struct userdata    *userdata;
92     const char         *id;
93     mir_node           *node;
94 };
95
96 typedef struct {
97     const char         *recording;
98     const char         *playback;
99 } resource_name_t;
100
101 typedef struct {
102     const char         *prop;
103     mrp_attr_t          def;
104 } attribute_t;
105
106
107 struct scripting_zone {
108     struct userdata    *userdata;
109     const char         *name;
110     uint32_t            index;
111 };
112
113 struct scripting_resource {
114     struct userdata    *userdata;
115     resource_name_t    *name;
116     attribute_t        *attributes;
117 };
118
119 struct scripting_rtgroup {
120     struct userdata    *userdata;
121     mir_rtgroup        *rtg;
122     mir_direction       type;
123     mrp_funcbridge_t   *accept;
124     mrp_funcbridge_t   *compare;
125 };
126
127 typedef struct {
128     const char        **input;
129     const char        **output;
130 } route_t;
131
132 typedef struct {
133     const char         *name;
134     bool                needres;
135     const char         *role;
136     pa_nodeset_resdef   resource;
137 } map_t;
138
139 struct scripting_apclass {
140     struct userdata    *userdata;
141     const char         *name;
142     const char         *class;
143     mir_node_type       type;
144     int                 priority;
145     route_t            *route;
146     map_t              *roles;
147     map_t              *binaries;
148     struct {
149         bool resource;
150     }                   needs;
151 };
152
153 typedef enum {
154     vollim_class = 1,
155     vollim_generic,
156     vollim_maximum
157 } vollim_type;
158
159 typedef struct {
160     size_t      nint;
161     int        *ints;
162 } intarray_t;
163
164 typedef struct {
165     bool   mallocd;
166     double     *value;
167 } limit_data_t;
168
169 struct scripting_vollim {
170     struct userdata  *userdata;
171     const char       *name;
172     vollim_type       type;
173     intarray_t       *classes;
174     limit_data_t     *limit;
175     mrp_funcbridge_t *calculate;
176     char              args[0];
177 };
178
179 typedef struct {
180     const char *name;
181     int value;
182 } const_def_t;
183
184 typedef struct {
185     const char *name;
186     const char *sign;
187     mrp_funcbridge_cfunc_t func;
188     void *data;
189 } funcbridge_def_t;
190
191 typedef enum {
192     NAME = 1,
193     TYPE,
194     ZONE,
195     CLASS,
196     INPUT,
197     LIMIT,
198     ROUTE,
199     ROLES,
200     TABLE,
201     ACCEPT,
202     MAXROW,
203     OUTPUT,
204     TABLES,
205     UPDATE,
206     COMPARE,
207     COLUMNS,
208     PRIVACY,
209     BINARIES,
210     CHANNELS,
211     LOCATION,
212     PRIORITY,
213     AVAILABLE,
214     CALCULATE,
215     CONDITION,
216     DIRECTION,
217     IMPLEMENT,
218     NODE_TYPE,
219     ATTRIBUTES,
220     AUTORELEASE,
221     DESCRIPTION,
222 } field_t;
223
224 static int  import_create(lua_State *);
225 static int  import_getfield(lua_State *);
226 static int  import_setfield(lua_State *);
227 static int  import_tostring(lua_State *);
228 static void import_destroy(void *);
229
230 static int  import_link(lua_State *);
231
232 static void import_data_changed(struct userdata *, const char *,
233                                 int, mrp_domctl_value_t **);
234 static bool update_bridge(lua_State *, void *, const char *,
235                           mrp_funcbridge_value_t *, char *,
236                           mrp_funcbridge_value_t *);
237
238 static void array_class_create(lua_State *);
239 static pa_value *array_create(lua_State *, int, mrp_lua_strarray_t *);
240 static int  array_getfield(lua_State *);
241 static int  array_setfield(lua_State *);
242 static int  array_getlength(lua_State *);
243
244 #if 0
245 static void array_destroy(void *);
246 #endif
247
248 static int  node_create(lua_State *);
249 static int  node_getfield(lua_State *);
250 static int  node_setfield(lua_State *);
251 static int  node_tostring(lua_State *);
252 static void node_destroy(void *);
253
254 static int  zone_create(lua_State *);
255 static int  zone_getfield(lua_State *);
256 static int  zone_setfield(lua_State *);
257 static void zone_destroy(void *);
258
259 static int  resource_create(lua_State *);
260 static int  resource_getfield(lua_State *);
261 static int  resource_setfield(lua_State *);
262 static void resource_destroy(void *);
263
264 static int  rtgroup_create(lua_State *);
265 static int  rtgroup_getfield(lua_State *);
266 static int  rtgroup_setfield(lua_State *);
267 static int  rtgroup_tostring(lua_State *);
268 static void rtgroup_destroy(void *);
269
270 static bool rtgroup_accept(struct userdata *, mir_rtgroup *, mir_node *);
271 static int  rtgroup_compare(struct userdata *, mir_rtgroup *,
272                             mir_node *, mir_node *);
273
274 static bool accept_bridge(lua_State *, void *, const char *,
275                           mrp_funcbridge_value_t *, char *,
276                           mrp_funcbridge_value_t *);
277 static bool compare_bridge(lua_State *, void *, const char *,
278                            mrp_funcbridge_value_t *, char *,
279                            mrp_funcbridge_value_t *);
280 static bool change_bridge(lua_State *, void *, const char *,
281                            mrp_funcbridge_value_t *, char *,
282                            mrp_funcbridge_value_t *);
283
284 static int  apclass_create(lua_State *);
285 static int  apclass_getfield(lua_State *);
286 static int  apclass_setfield(lua_State *);
287 static int  apclass_tostring(lua_State *);
288 static void apclass_destroy(void *);
289
290 static route_t *route_check(lua_State *, int);
291 static int route_push(lua_State *, route_t *);
292 static void route_destroy(route_t *);
293
294 static int  vollim_create(lua_State *);
295 static int  vollim_getfield(lua_State *);
296 static int  vollim_setfield(lua_State *);
297 static int  vollim_tostring(lua_State *);
298 static void vollim_destroy(void *);
299
300 static double vollim_calculate(struct userdata *, int, mir_node *, uint32_t, void *);
301 static bool calculate_bridge(lua_State *, void *, const char *,
302                              mrp_funcbridge_value_t *, char *,
303                              mrp_funcbridge_value_t *);
304
305 static limit_data_t *limit_data_check(lua_State *, int);
306
307 #if 0
308 static int limit_data_push(lua_State *, limit_data_t *);
309 #endif
310
311 static void limit_data_destroy(limit_data_t *);
312
313 static intarray_t *intarray_check(lua_State *, int, int, int);
314 static int intarray_push(lua_State *, intarray_t *);
315 static void intarray_destroy(intarray_t *);
316
317 static resource_name_t *resource_names_check(lua_State *, int);
318 static void resource_names_destroy(resource_name_t *);
319
320 static attribute_t *attributes_check(lua_State *, int);
321 static void attributes_destroy(attribute_t *);
322
323 static map_t *map_check(lua_State *, int);
324 static int map_push(lua_State *, map_t *);
325 static void map_destroy(map_t *);
326
327 static field_t field_check(lua_State *, int, const char **);
328 static field_t field_name_to_type(const char *, size_t);
329 static int make_id(char *buf, size_t len, const char *fmt, ...);
330
331 static void setup_murphy_interface(struct userdata *);
332 static char *comma_separated_list(mrp_lua_strarray_t *, char *, int);
333
334 static bool define_constants(lua_State *);
335 static bool register_methods(lua_State *);
336
337 static void *alloc(void *, void *, size_t, size_t);
338 static int panic(lua_State *);
339
340
341 MRP_LUA_METHOD_LIST_TABLE (
342     import_methods,           /* methodlist name */
343     MRP_LUA_METHOD_CONSTRUCTOR  (import_create)
344     MRP_LUA_METHOD        (link, import_link  )
345 );
346
347 MRP_LUA_METHOD_LIST_TABLE (
348     node_methods,             /* methodlist name */
349     MRP_LUA_METHOD_CONSTRUCTOR  (node_create)
350 );
351
352
353 MRP_LUA_METHOD_LIST_TABLE (
354     import_overrides,        /* methodlist_name */
355     MRP_LUA_OVERRIDE_CALL       (import_create)
356     MRP_LUA_OVERRIDE_GETFIELD   (import_getfield)
357     MRP_LUA_OVERRIDE_SETFIELD   (import_setfield)
358     MRP_LUA_OVERRIDE_STRINGIFY  (import_tostring)
359 );
360
361 MRP_LUA_METHOD_LIST_TABLE (
362     array_overrides,         /* methodlist_name */
363     MRP_LUA_OVERRIDE_GETFIELD   (array_getfield)
364     MRP_LUA_OVERRIDE_SETFIELD   (array_setfield)
365     MRP_LUA_OVERRIDE_GETLENGTH  (array_getlength)
366 );
367
368 MRP_LUA_METHOD_LIST_TABLE (
369     node_overrides,           /* methodlist name */
370     MRP_LUA_OVERRIDE_CALL       (node_create)
371     MRP_LUA_OVERRIDE_GETFIELD   (node_getfield)
372     MRP_LUA_OVERRIDE_SETFIELD   (node_setfield)
373     MRP_LUA_OVERRIDE_STRINGIFY  (node_tostring)
374 );
375
376
377 MRP_LUA_CLASS_DEF (
378    mdb,                         /* class name */
379    import,                      /* constructor name */
380    scripting_import,            /* userdata type */
381    import_destroy,              /* userdata destructor */
382    import_methods,              /* class methods */
383    import_overrides             /* override methods */
384 );
385
386 MRP_LUA_CLASS_DEF (
387    node,                        /* class name */
388    instance,                    /* constructor name */
389    scripting_node,              /* userdata type */
390    node_destroy,                /* userdata destructor */
391    node_methods,                /* class methods */
392    node_overrides               /* override methods */
393 );
394
395 MRP_LUA_CLASS_DEF_SIMPLE (
396    zone,                         /* class name */
397    scripting_zone,               /* userdata type */
398    zone_destroy,                 /* userdata destructor */
399    MRP_LUA_METHOD_LIST (         /* methods */
400       MRP_LUA_METHOD_CONSTRUCTOR  (zone_create)
401    ),
402    MRP_LUA_METHOD_LIST (         /* overrides */
403       MRP_LUA_OVERRIDE_CALL       (zone_create)
404       MRP_LUA_OVERRIDE_GETFIELD   (zone_getfield)
405       MRP_LUA_OVERRIDE_SETFIELD   (zone_setfield)
406    )
407 );
408
409 MRP_LUA_CLASS_DEF_SIMPLE (
410    audio_resource,               /* class name */
411    scripting_resource,           /* userdata type */
412    resource_destroy,             /* userdata destructor */
413    MRP_LUA_METHOD_LIST (         /* methods */
414       MRP_LUA_METHOD_CONSTRUCTOR  (resource_create)
415    ),
416    MRP_LUA_METHOD_LIST (         /* overrides */
417       MRP_LUA_OVERRIDE_CALL       (resource_create)
418       MRP_LUA_OVERRIDE_GETFIELD   (resource_getfield)
419       MRP_LUA_OVERRIDE_SETFIELD   (resource_setfield)
420    )
421 );
422
423 MRP_LUA_CLASS_DEF_SIMPLE (
424    routing_group,                /* class name */
425    scripting_rtgroup,            /* userdata type */
426    rtgroup_destroy,              /* userdata destructor */
427    MRP_LUA_METHOD_LIST (         /* methods */
428       MRP_LUA_METHOD_CONSTRUCTOR  (rtgroup_create)
429    ),
430    MRP_LUA_METHOD_LIST (         /* overrides */
431       MRP_LUA_OVERRIDE_CALL       (rtgroup_create)
432       MRP_LUA_OVERRIDE_GETFIELD   (rtgroup_getfield)
433       MRP_LUA_OVERRIDE_SETFIELD   (rtgroup_setfield)
434       MRP_LUA_OVERRIDE_STRINGIFY  (rtgroup_tostring)
435    )
436 );
437
438 MRP_LUA_CLASS_DEF_SIMPLE (
439    application_class,            /* class name */
440    scripting_apclass,            /* userdata type */
441    apclass_destroy,              /* userdata destructor */
442    MRP_LUA_METHOD_LIST (         /* methods */
443       MRP_LUA_METHOD_CONSTRUCTOR  (apclass_create)
444    ),
445    MRP_LUA_METHOD_LIST (        /* overrides */
446       MRP_LUA_OVERRIDE_CALL       (apclass_create)
447       MRP_LUA_OVERRIDE_GETFIELD   (apclass_getfield)
448       MRP_LUA_OVERRIDE_SETFIELD   (apclass_setfield)
449       MRP_LUA_OVERRIDE_STRINGIFY  (apclass_tostring)
450    )
451 );
452
453 MRP_LUA_CLASS_DEF_SIMPLE (
454    volume_limit,                 /* class name */
455    scripting_vollim,             /* userdata type */
456    vollim_destroy,               /* userdata destructor */
457    MRP_LUA_METHOD_LIST (         /* methods */
458       MRP_LUA_METHOD_CONSTRUCTOR  (vollim_create)
459    ),
460    MRP_LUA_METHOD_LIST (        /* overrides */
461       MRP_LUA_OVERRIDE_CALL       (vollim_create)
462       MRP_LUA_OVERRIDE_GETFIELD   (vollim_getfield)
463       MRP_LUA_OVERRIDE_SETFIELD   (vollim_setfield)
464       MRP_LUA_OVERRIDE_STRINGIFY  (vollim_tostring)
465    )
466 );
467
468
469 pa_scripting *pa_scripting_init(struct userdata *u)
470 {
471     pa_scripting *scripting;
472     lua_State *L;
473
474     pa_assert(u);
475
476     scripting = pa_xnew0(pa_scripting, 1);
477
478     if (!(L = lua_newstate(alloc, u)))
479         pa_log("failed to initialize Lua");
480     else {
481         lua_atpanic(L, &panic);
482         luaL_openlibs(L);
483
484         mrp_create_funcbridge_class(L);
485         mrp_lua_create_object_class(L, IMPORT_CLASS);
486         mrp_lua_create_object_class(L, NODE_CLASS);
487         mrp_lua_create_object_class(L, ZONE_CLASS);
488         mrp_lua_create_object_class(L, RESOURCE_CLASS);
489         mrp_lua_create_object_class(L, RTGROUP_CLASS);
490         mrp_lua_create_object_class(L, APPLICATION_CLASS);
491         mrp_lua_create_object_class(L, VOLLIM_CLASS);
492
493         array_class_create(L);
494
495         define_constants(L);
496         register_methods(L);
497
498         lua_pushlightuserdata(L, u);
499         lua_setglobal(L, USERDATA);
500
501         scripting->L = L;
502         scripting->configured = false;
503     }
504
505     return scripting;
506 }
507
508 void pa_scripting_done(struct userdata *u)
509 {
510     pa_scripting *scripting;
511
512     if (u && (scripting = u->scripting)) {
513         pa_xfree(scripting);
514         u->scripting = NULL;
515     }
516 }
517
518 bool pa_scripting_dofile(struct userdata *u, const char *file)
519 {
520     pa_scripting *scripting;
521     lua_State *L;
522     bool success;
523
524     pa_assert(u);
525     pa_assert(file);
526
527     pa_assert_se((scripting = u->scripting));
528     pa_assert_se((L = scripting->L));
529
530     if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) {
531         success = false;
532         pa_log("%s", lua_tostring(L, -1));
533         lua_pop(L, 1);
534     }
535     else {
536         success =true;
537         scripting->configured = true;
538         setup_murphy_interface(u);
539         pa_zoneset_update_module_property(u);
540     }
541
542     return success;
543 }
544
545 static int import_create(lua_State *L)
546 {
547     struct userdata *u = NULL;
548     pa_scripting *scripting;
549     size_t fldnamlen;
550     const char *fldnam;
551     scripting_import *imp;
552     const char *table = NULL;
553     mrp_lua_strarray_t *columns = NULL;
554     const char *condition = NULL;
555     int maxrow = 0;
556     mrp_funcbridge_t *update = NULL;
557     int maxcol;
558     pa_value **rows;
559     pa_value **cols;
560     int i,j;
561     int top;
562
563     MRP_LUA_ENTER;
564
565     top = lua_gettop(L);
566
567     lua_getglobal(L, USERDATA);
568     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
569         luaL_error(L, "missing or invalid global '" USERDATA "'");
570
571     pa_assert_se((scripting = u->scripting));
572
573     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
574
575         switch (field_name_to_type(fldnam, fldnamlen)) {
576         case TABLE:      table = luaL_checkstring(L, -1);                break;
577         case COLUMNS:    columns = mrp_lua_check_strarray(L, -1);        break;
578         case CONDITION:  condition = luaL_checkstring(L, -1);            break;
579         case MAXROW:     maxrow = luaL_checkint(L, -1);                  break;
580         case UPDATE:     update = mrp_funcbridge_create_luafunc(L, -1);  break;
581         default:         luaL_error(L, "bad field '%s'", fldnam);        break;
582         }
583
584     } /* MRP_LUA_FOREACH_FIELD */
585
586     lua_settop(L, top);
587
588     if (!table)
589         luaL_error(L, "missing table field");
590     if (!columns)
591         luaL_error(L, "missing columns field");
592     if (maxrow < 1 || maxrow >= MQI_QUERY_RESULT_MAX)
593         luaL_error(L, "missing or invalid maxrow field");
594     if (!update)
595         luaL_error(L, "missing update function");
596
597     maxcol = (int)columns->nstring;
598
599     if (maxcol >= MQI_COLUMN_MAX)
600         luaL_error(L, "too many columns (max %d allowed)", MQI_COLUMN_MAX);
601
602     if (scripting->configured)
603         luaL_error(L, "refuse to import '%s' after configuration phase",table);
604
605     imp = (scripting_import *)mrp_lua_create_object(L, IMPORT_CLASS, table,0);
606
607     imp->userdata = u;
608     imp->table = pa_xstrdup(table);
609     imp->columns = columns;
610     imp->condition = condition;
611     imp->values = array_create(L, maxrow, NULL);
612     imp->update = update;
613
614     for (i = 0, rows = imp->values->value.array;  i < maxrow;   i++) {
615         cols = (rows[i] = array_create(L, (int)maxcol, columns))->value.array;
616         lua_rawseti(L, -3, i+1); /* we add this to the import */
617         for (j = 0;  j < maxcol;  j++)
618             cols[j] = pa_xnew0(pa_value, 1);
619     }
620
621     lua_rawseti(L, -2, MQI_QUERY_RESULT_MAX);
622
623     MRP_LUA_LEAVE(1);
624 }
625
626 static int import_getfield(lua_State *L)
627 {
628     scripting_import *imp;
629     pa_value *values;
630     int colidx;
631     field_t fld;
632
633     MRP_LUA_ENTER;
634
635     if (!(imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1)))
636         lua_pushnil(L);
637     else {
638         pa_assert_se((values = imp->values));
639
640         if (lua_type(L, 2) == LUA_TNUMBER) {
641             colidx = lua_tointeger(L, 2);
642
643             if (colidx < 1 || colidx > -values->type)
644                 lua_pushnil(L);
645             else
646                 lua_rawgeti(L, 1, colidx);
647         }
648         else {
649             fld = field_check(L, 2, NULL);
650             lua_pop(L, 1);
651
652             switch (fld) {
653             case TABLE:       lua_pushstring(L, imp->table);             break;
654             case COLUMNS:     mrp_lua_push_strarray(L, imp->columns);    break;
655             case CONDITION:   lua_pushstring(L, imp->condition);         break;
656             case MAXROW:      lua_pushinteger(L, -imp->values->type);    break;
657             default:          lua_pushnil(L);                            break;
658             }
659         }
660     }
661
662     MRP_LUA_LEAVE(1);
663 }
664
665 static int import_setfield(lua_State *L)
666 {
667     const char *f;
668
669     MRP_LUA_ENTER;
670
671     f = luaL_checkstring(L, 2);
672     luaL_error(L, "attempt to set '%s' field of read-only mdb.import", f);
673
674     MRP_LUA_LEAVE(0);
675 }
676
677 static int import_tostring(lua_State *L)
678 {
679     scripting_import *imp;
680
681     MRP_LUA_ENTER;
682
683     imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
684
685     lua_pushstring(L, imp->table);
686
687     MRP_LUA_LEAVE(1);
688 }
689
690 static void import_destroy(void *data)
691 {
692     scripting_import *imp = (scripting_import *)data;
693
694     MRP_LUA_ENTER;
695
696     pa_xfree((void *)imp->table);
697     mrp_lua_free_strarray(imp->columns);
698     pa_xfree((void *)imp->condition);
699
700     MRP_LUA_LEAVE_NOARG;
701 }
702
703 static int import_link(lua_State *L)
704 {
705     scripting_import *imp;
706     mrp_lua_strarray_t *columns;
707     pa_value *values;
708     const char *colnam;
709     int rowidx;
710     size_t colidx;
711     pa_value *row;
712     pa_value *col;
713
714     MRP_LUA_ENTER;
715
716     imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
717     rowidx = luaL_checkint(L, 2) - 1;
718     colnam = luaL_checkstring(L, 3);
719
720     pa_assert(imp);
721     pa_assert_se((columns = imp->columns));
722
723     col = NULL;
724
725     if (rowidx >= 0 && rowidx < -imp->values->type) {
726         for (colidx = 0;   colidx < columns->nstring;   colidx++) {
727             if (!strcmp(colnam, columns->strings[colidx])) {
728                 pa_assert_se((values = imp->values));
729                 pa_assert_se((row = values->value.array[rowidx]));
730                 pa_assert(colidx < (size_t)-row->type);
731                 pa_assert_se((col = row->value.array[colidx]));
732                 break;
733             }
734         }
735     }
736
737     if(col)
738         pa_log_debug("userdata: type:%d", col->type);
739
740     lua_pushlightuserdata(L, col);
741
742     MRP_LUA_LEAVE(1);
743 }
744
745 static void import_data_changed(struct userdata *u,
746                                 const char *table,
747                                 int nrow,
748                                 mrp_domctl_value_t **mval)
749 {
750     static mrp_domctl_value_t empty;
751
752     pa_scripting *scripting;
753     lua_State *L;
754     scripting_import *imp;
755     mrp_domctl_value_t *mrow;
756     mrp_domctl_value_t *mcol;
757     pa_value *ptval, *prval, *pcval;
758     pa_value **prow;
759     pa_value **pcol;
760     int maxcol;
761     int maxrow;
762     mrp_funcbridge_value_t arg;
763     mrp_funcbridge_value_t ret;
764     char t;
765     int i,j;
766
767     pa_assert(u);
768     pa_assert(table);
769     pa_assert(mval || nrow == 0);
770     pa_assert_se((scripting = u->scripting));
771     pa_assert_se((L = scripting->L));
772
773     pa_log_debug("table '%s' data changed: got %d rows", table, nrow);
774
775     mrp_lua_get_class_table(L, IMPORT_CLASS);
776
777     if (!lua_istable(L, -1)){
778         luaL_error(L, "internal error: failed to find '%s' table",
779                    (IMPORT_CLASS)->constructor);
780     }
781
782     lua_pushstring(L, table);
783     lua_rawget(L, -2);
784
785     if (!(imp = mrp_lua_to_object(L, IMPORT_CLASS, -1)))
786         pa_log("can't find import '%s'", table);
787     else {
788         pa_assert(!strcmp(table, imp->table));
789         pa_assert(imp->columns);
790         pa_assert(imp->update);
791         pa_assert_se((ptval = imp->values));
792         pa_assert_se((prow = ptval->value.array));
793
794         maxrow = -ptval->type;
795         maxcol = (int)imp->columns->nstring;
796
797         pa_assert(maxrow >= 0);
798         pa_assert(nrow <= maxrow);
799
800         pa_log_debug("import '%s' found", imp->table);
801
802         for (i = 0; i < maxrow;  i++) {
803             pa_assert_se((prval = prow[i]));
804             pa_assert_se((pcol = prval->value.array));
805             pa_assert(prval->type < 0);
806             pa_assert(maxcol == -prval->type);
807
808             mrow = (i < nrow) ? mval[i] : NULL;
809
810             for (j = 0;  j < maxcol;  j++) {
811                 pcval = pcol[j];
812                 mcol = mrow ? mrow + j : &empty;
813
814                 switch (mcol->type) {
815                 case MRP_DOMCTL_STRING:
816                     pa_assert(!pcval->type || pcval->type == pa_value_string);
817                     pa_xfree((void *)pcval->value.string);
818                     pcval->type = pa_value_string;
819                     pcval->value.string = pa_xstrdup(mcol->str);
820                     break;
821                 case MRP_DOMCTL_INTEGER:
822                     pa_assert(!pcval->type || pcval->type == pa_value_integer);
823                     pcval->type = pa_value_integer;
824                     pcval->value.integer = mcol->s32;
825                     break;
826                 case MRP_DOMCTL_UNSIGNED:
827                     pa_assert(!pcval->type || pcval->type == pa_value_unsignd);
828                     pcval->type = pa_value_unsignd;
829                     pcval->value.unsignd = mcol->u32;
830                     break;
831                 case MRP_DOMCTL_DOUBLE:
832                     pa_assert(!pcval->type || pcval->type ==pa_value_floating);
833                     pcval->type = pa_value_floating;
834                     pcval->value.floating = mcol->dbl;
835                     break;
836                 default:
837                     if (pcval->type == pa_value_string)
838                         pa_xfree((void *)pcval->value.string);
839                     memset(pcval, 0, sizeof(pa_value));
840                     break;
841                 }
842             }
843         }
844
845         arg.pointer = imp;
846
847         if (!mrp_funcbridge_call_from_c(L, imp->update, "o", &arg, &t, &ret)) {
848             pa_log("failed to call %s:update method (%s)",
849                    imp->table, ret.string);
850             pa_xfree((void *)ret.string);
851         }
852     }
853
854     lua_pop(L, 2);
855 }
856
857
858 static bool update_bridge(lua_State *L, void *data, const char *signature,
859                           mrp_funcbridge_value_t *args,
860                           char *ret_type, mrp_funcbridge_value_t *ret_val)
861 {
862     update_func_t update;
863     scripting_import *imp;
864     struct userdata *u;
865     bool success;
866
867     (void)L;
868
869     pa_assert(signature);
870     pa_assert(args);
871     pa_assert(ret_type);
872     pa_assert(ret_val);
873
874     pa_assert_se((update = (update_func_t)data));
875
876     if (strcmp(signature, "o"))
877         success = false;
878     else {
879         pa_assert_se((imp = args[0].pointer));
880         pa_assert_se((u = imp->userdata));
881
882         success = true;
883         *ret_type = MRP_FUNCBRIDGE_NO_DATA;
884         memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
885         update(u);
886     }
887
888     return success;
889 }
890
891
892
893 static void array_class_create(lua_State *L)
894 {
895     /* create a metatable for row's */
896     luaL_newmetatable(L, ARRAY_CLASSID);
897     lua_pushliteral(L, "__index");
898     lua_pushvalue(L, -2);
899     lua_settable(L, -3);        /* metatable.__index = metatable */
900     luaL_openlib(L, NULL, array_overrides, 0);
901 }
902
903
904 static pa_value *array_create(lua_State *L, int dimension,
905                               mrp_lua_strarray_t *names)
906 {
907     pa_value  *value;
908     pa_value **array;
909
910     pa_assert(L);
911     pa_assert(dimension >= 0);
912     pa_assert(dimension < MQI_QUERY_RESULT_MAX);
913
914     array = pa_xnew0(pa_value *, (size_t)(dimension + 1));
915     value = lua_newuserdata(L, sizeof(pa_value));
916     value->type = -dimension;
917     value->value.array = array;
918
919     array[dimension] = (pa_value *)names;
920
921     luaL_getmetatable(L, ARRAY_CLASSID);
922     lua_setmetatable(L, -2);
923
924     return value;
925 }
926
927 static int array_getfield(lua_State *L)
928 {
929     pa_value *arr, *value;
930     int dimension;
931     int key_type;
932     const char *key;
933     mrp_lua_strarray_t *names;
934     int idx;
935     int i;
936
937     MRP_LUA_ENTER;
938
939     pa_assert(L);
940
941     arr = (pa_value *)luaL_checkudata(L, 1, ARRAY_CLASSID);
942
943     pa_assert(arr->type < 0);
944
945     dimension = -arr->type;
946     key_type = lua_type(L, 2);
947
948     switch (key_type) {
949     case LUA_TNUMBER:
950         idx = lua_tointeger(L, 2) - 1;
951         break;
952     case LUA_TSTRING:
953         idx = -1;
954         if ((names = (mrp_lua_strarray_t *)arr->value.array[dimension])) {
955             pa_assert(dimension == (int)names->nstring);
956             key = lua_tostring(L, 2);
957             pa_assert(key);
958             for (i = 0;  i < dimension;  i++) {
959                 if (!strcmp(key, names->strings[i])) {
960                     idx = i;
961                     break;
962                 }
963             }
964         }
965         break;
966     default:
967         idx = -1;
968         break;
969     }
970
971
972     if (idx < 0 || idx >= dimension || !(value = arr->value.array[idx]))
973         lua_pushnil(L);
974     else if (value->type < 0)
975         lua_rawgeti(L, 1, 1 - value->type);
976     else {
977         switch (value->type) {
978         case pa_value_string:   lua_pushstring(L, value->value.string);   break;
979         case pa_value_integer:  lua_pushinteger(L, value->value.integer); break;
980         case pa_value_unsignd:  lua_pushinteger(L, (int)(value->value.unsignd)); break;
981         case pa_value_floating: lua_pushnumber(L, value->value.floating); break;
982         default:                lua_pushnil(L);                     break;
983         }
984     }
985
986     MRP_LUA_LEAVE(1);
987 }
988
989 static int array_setfield(lua_State *L)
990 {
991     MRP_LUA_ENTER;
992
993     pa_assert(L);
994
995     luaL_error(L, "attempt to write to a read-only object");
996
997     MRP_LUA_LEAVE(0);
998 }
999
1000 static int array_getlength(lua_State *L)
1001 {
1002     MRP_LUA_ENTER;
1003
1004     pa_assert(L);
1005
1006     MRP_LUA_LEAVE(1);
1007 }
1008
1009 #if 0
1010 static void array_destroy(void *data)
1011 {
1012     pa_value *value = (pa_value *)data;
1013
1014     MRP_LUA_ENTER;
1015
1016     if (value) {
1017         pa_assert(value->type < 0);
1018         pa_xfree(value->value.array);
1019     }
1020
1021     MRP_LUA_LEAVE_NOARG;
1022 }
1023 #endif
1024
1025 scripting_node *pa_scripting_node_create(struct userdata *u, mir_node *node)
1026 {
1027     pa_scripting *scripting;
1028     lua_State *L;
1029     scripting_node *sn;
1030     char id[256];
1031
1032     pa_assert(u);
1033     pa_assert(node);
1034     pa_assert(node->amname);
1035
1036     pa_assert_se((scripting = u->scripting));
1037     pa_assert_se((L = scripting->L));
1038
1039     make_id(id, sizeof(id), "%s_%d", node->amname, node->index);
1040
1041     if ((sn = (scripting_node *)mrp_lua_create_object(L, NODE_CLASS, id,0))) {
1042         sn->userdata = u;
1043         sn->id = pa_xstrdup(id);
1044         sn->node = node;
1045     }
1046
1047     return sn;
1048 }
1049
1050 void pa_scripting_node_destroy(struct userdata *u, mir_node *node)
1051 {
1052     pa_scripting *scripting;
1053     lua_State *L;
1054     scripting_node *sn;
1055
1056     MRP_LUA_ENTER;
1057
1058     pa_assert(u);
1059     pa_assert(node);
1060
1061     pa_assert_se((scripting = u->scripting));
1062     pa_assert_se((L = scripting->L));
1063
1064     if ((sn = node->scripting)) {
1065         mrp_lua_destroy_object(L, sn->id,0, sn);
1066         sn->node = NULL;
1067         node->scripting = NULL;
1068     }
1069
1070     MRP_LUA_LEAVE_NOARG;
1071 }
1072
1073 static int node_create(lua_State *L)
1074 {
1075     MRP_LUA_ENTER;
1076
1077     lua_pushnil(L);
1078
1079     MRP_LUA_LEAVE(1);
1080 }
1081
1082 static int node_getfield(lua_State *L)
1083 {
1084     scripting_node *sn;
1085     mir_node *node;
1086     field_t fld;
1087
1088     MRP_LUA_ENTER;
1089
1090     fld = field_check(L, 2, NULL);
1091     lua_pop(L, 1);
1092
1093     if (!(sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1)))
1094         lua_pushnil(L);
1095     else {
1096         pa_assert_se((node = sn->node));
1097
1098         switch (fld) {
1099         case NAME:           lua_pushstring(L, node->amname);           break;
1100         case DESCRIPTION:    lua_pushstring(L, node->amdescr);          break;
1101         case DIRECTION:      lua_pushinteger(L, node->direction);       break;
1102         case IMPLEMENT:      lua_pushinteger(L, node->implement);       break;
1103         case CHANNELS:       lua_pushinteger(L, (int)(node->channels)); break;
1104         case LOCATION:       lua_pushinteger(L, node->location);        break;
1105         case PRIVACY:        lua_pushinteger(L, node->privacy);         break;
1106         case ZONE:           lua_pushstring(L, node->zone);             break;
1107         case TYPE:           lua_pushinteger(L, node->type);            break;
1108         case AVAILABLE:      lua_pushboolean(L, node->available);       break;
1109         default:             lua_pushnil(L);                            break;
1110         }
1111     }
1112
1113     MRP_LUA_LEAVE(1);
1114 }
1115
1116 static int node_setfield(lua_State *L)
1117 {
1118     const char *f;
1119
1120     MRP_LUA_ENTER;
1121
1122     f = luaL_checkstring(L, 2);
1123     luaL_error(L, "attempt to set '%s' field of read-only node", f);
1124
1125     MRP_LUA_LEAVE(0);
1126 }
1127
1128 static int node_tostring(lua_State *L)
1129 {
1130     scripting_node *sn;
1131
1132     MRP_LUA_ENTER;
1133
1134     sn = (scripting_node *)mrp_lua_check_object(L, NODE_CLASS, 1);
1135
1136     lua_pushstring(L, (sn && sn->id) ? sn->id : "<unknown node>");
1137
1138     MRP_LUA_LEAVE(1);
1139 }
1140
1141 static void node_destroy(void *data)
1142 {
1143     scripting_node *sn = (scripting_node *)data;
1144     mir_node *node;
1145
1146     MRP_LUA_ENTER;
1147
1148     if ((node = sn->node) && sn == node->scripting)
1149         node->scripting = NULL;
1150
1151     pa_xfree((void *)sn->id);
1152
1153     MRP_LUA_LEAVE_NOARG;
1154 }
1155
1156
1157 static int zone_create(lua_State *L)
1158 {
1159     static uint32_t index;
1160
1161     struct userdata *u;
1162     size_t fldnamlen;
1163     const char *fldnam;
1164     scripting_zone *zone;
1165     const char *name = NULL;
1166     /* attribute_t *attributes = NULL; */
1167
1168     MRP_LUA_ENTER;
1169
1170     lua_getglobal(L, USERDATA);
1171     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1172         luaL_error(L, "missing or invalid global '" USERDATA "'");
1173     lua_pop(L, 1);
1174
1175
1176     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1177
1178         switch (field_name_to_type(fldnam, fldnamlen)) {
1179         case NAME:         name = luaL_checkstring(L, -1);           break;
1180             /* case ATTRIBUTES:   attributes = attributes_check(L, -1);     break; */
1181         default:           luaL_error(L, "bad field '%s'", fldnam);  break;
1182         }
1183
1184     } /* MRP_LUA_FOREACH_FIELD */
1185
1186     if (!name)
1187         luaL_error(L, "missing or invalid name field");
1188
1189     if (pa_zoneset_add_zone(u, name, index+1))
1190         luaL_error(L, "attempt to define zone '%s' multiple times", name);
1191
1192     zone = (scripting_zone *)mrp_lua_create_object(L, ZONE_CLASS, name, 0);
1193
1194     zone->userdata = u;
1195     zone->name = pa_xstrdup(name);
1196     zone->index = ++index;
1197
1198
1199     MRP_LUA_LEAVE(1);
1200 }
1201
1202 static int zone_getfield(lua_State *L)
1203 {
1204     scripting_zone *zone;
1205     field_t fld;
1206
1207     MRP_LUA_ENTER;
1208
1209     fld = field_check(L, 2, NULL);
1210     lua_pop(L, 1);
1211
1212     if (!(zone = (scripting_zone *)mrp_lua_check_object(L, ZONE_CLASS, 1)))
1213         lua_pushnil(L);
1214     else {
1215         switch (fld) {
1216         case NAME:           lua_pushstring(L, zone->name);         break;
1217 #if 0
1218         case ATTRIBUTES:     lua_pushinteger(L, rtgs->type);       break;
1219 #endif
1220         default:             lua_pushnil(L);                       break;
1221         }
1222     }
1223
1224     MRP_LUA_LEAVE(1);
1225 }
1226
1227 static int zone_setfield(lua_State *L)
1228 {
1229     const char *f;
1230
1231     MRP_LUA_ENTER;
1232
1233     f = luaL_checkstring(L, 2);
1234     luaL_error(L, "attempt to set '%s' field of read-only zone", f);
1235
1236     MRP_LUA_LEAVE(0);
1237 }
1238
1239 static void zone_destroy(void *data)
1240 {
1241     scripting_zone *zone = (scripting_zone *)data;
1242
1243     MRP_LUA_ENTER;
1244
1245     pa_xfree((void *)zone->name);
1246
1247     zone->name = NULL;
1248
1249     MRP_LUA_LEAVE_NOARG;
1250 }
1251
1252
1253 static int resource_create(lua_State *L)
1254 {
1255     struct userdata *u;
1256     size_t fldnamlen;
1257     const char *fldnam;
1258     scripting_resource *res;
1259     resource_name_t *name = NULL;
1260     attribute_t *attributes = NULL;
1261     attribute_t *attr;
1262
1263     MRP_LUA_ENTER;
1264
1265     lua_getglobal(L, USERDATA);
1266     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1267         luaL_error(L, "missing or invalid global '" USERDATA "'");
1268     lua_pop(L, 1);
1269
1270
1271     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1272
1273         switch (field_name_to_type(fldnam, fldnamlen)) {
1274         case NAME:         name = resource_names_check(L, -1);       break;
1275         case ATTRIBUTES:   attributes = attributes_check(L, -1);     break;
1276         default:           luaL_error(L, "bad field '%s'", fldnam);  break;
1277         }
1278
1279     } /* MRP_LUA_FOREACH_FIELD */
1280
1281     if (!name)
1282         luaL_error(L, "missing or invalid name field");
1283
1284     pa_murphyif_add_audio_resource(u, mir_input,  name->playback);
1285     pa_murphyif_add_audio_resource(u, mir_output, name->recording);
1286
1287     if (attributes) {
1288         for (attr = attributes;   attr->prop && attr->def.name;   attr++) {
1289             switch (attr->def.type) {
1290             case mqi_string:
1291                 pa_murphyif_add_audio_attribute(u, attr->prop,
1292                                                 attr->def.name,
1293                                                 attr->def.type,
1294                                                 attr->def.value.string);
1295                 break;
1296             case mqi_integer:
1297                 pa_murphyif_add_audio_attribute(u, attr->prop,
1298                                                 attr->def.name,
1299                                                 attr->def.type,
1300                                                 attr->def.value.integer);
1301                 break;
1302             case mqi_unsignd:
1303                 pa_murphyif_add_audio_attribute(u, attr->prop,
1304                                                 attr->def.name,
1305                                                 attr->def.type,
1306                                                 attr->def.value.unsignd);
1307                 break;
1308             case mqi_floating:
1309                 pa_murphyif_add_audio_attribute(u, attr->prop,
1310                                                 attr->def.name,
1311                                                 attr->def.type,
1312                                                 attr->def.value.floating);
1313                 break;
1314             default:
1315                 luaL_error(L, "invalid audio resource attribute '%s'",
1316                            attr->def.name);
1317                 break;
1318             }
1319         }
1320     }
1321
1322     res = (scripting_resource *)mrp_lua_create_object(L, RTGROUP_CLASS,
1323                                                       "definition",0);
1324
1325     res->userdata = u;
1326     res->name = name;
1327     res->attributes = attributes;
1328
1329     MRP_LUA_LEAVE(1);
1330 }
1331
1332 static int resource_getfield(lua_State *L)
1333 {
1334     /* field_t fld; */
1335
1336     MRP_LUA_ENTER;
1337
1338     /* fld = field_check(L, 2, NULL);*/
1339     lua_pop(L, 1);
1340
1341     if (!mrp_lua_check_object(L,RESOURCE_CLASS,1))
1342         lua_pushnil(L);
1343     else {
1344 #if 0
1345         switch (fld) {
1346         case NAME:           lua_pushstring(L, rtg->name);         break;
1347         case ATTRIBUTES:     lua_pushinteger(L, rtgs->type);       break;
1348         default:             lua_pushnil(L);                       break;
1349         }
1350 #else
1351         lua_pushnil(L);
1352 #endif
1353     }
1354
1355     MRP_LUA_LEAVE(1);
1356 }
1357
1358 static int resource_setfield(lua_State *L)
1359 {
1360     const char *f;
1361
1362     MRP_LUA_ENTER;
1363
1364     f = luaL_checkstring(L, 2);
1365     luaL_error(L, "attempt to set '%s' field of read-only resource_class", f);
1366
1367     MRP_LUA_LEAVE(0);
1368 }
1369
1370 static void resource_destroy(void *data)
1371 {
1372     scripting_resource *res = (scripting_resource *)data;
1373
1374     MRP_LUA_ENTER;
1375
1376     resource_names_destroy(res->name);
1377     attributes_destroy(res->attributes);
1378
1379     res->name = NULL;
1380     res->attributes = NULL;
1381
1382     MRP_LUA_LEAVE_NOARG;
1383 }
1384
1385
1386 static int rtgroup_create(lua_State *L)
1387 {
1388     struct userdata *u;
1389     size_t fldnamlen;
1390     const char *fldnam;
1391     mir_rtgroup *rtg;
1392     scripting_rtgroup *rtgs;
1393     const char *name = NULL;
1394     mir_direction type = 0;
1395     mrp_funcbridge_t *accept = NULL;
1396     mrp_funcbridge_t *compare = NULL;
1397     char id[256];
1398
1399     MRP_LUA_ENTER;
1400
1401     lua_getglobal(L, USERDATA);
1402     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1403         luaL_error(L, "missing or invalid global '" USERDATA "'");
1404     lua_pop(L, 1);
1405
1406
1407     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1408
1409         switch (field_name_to_type(fldnam, fldnamlen)) {
1410         case NAME:      name    = luaL_checkstring(L, -1);               break;
1411         case NODE_TYPE: type    = luaL_checkint(L, -1);                  break;
1412         case ACCEPT:    accept  = mrp_funcbridge_create_luafunc(L, -1);  break;
1413         case COMPARE:   compare = mrp_funcbridge_create_luafunc(L, -1);  break;
1414         default:        luaL_error(L, "bad field '%s'", fldnam);         break;
1415         }
1416
1417     } /* MRP_LUA_FOREACH_FIELD */
1418
1419     if (!name)
1420         luaL_error(L, "missing name field");
1421     if (type != mir_input && type != mir_output)
1422         luaL_error(L, "missing or invalid node_type");
1423     if (!accept)
1424         luaL_error(L, "missing or invalid accept field");
1425     if (!compare)
1426         luaL_error(L, "missing or invalid compare field");
1427
1428     make_id(id,sizeof(id), "%s_%sput", name, (type == mir_input) ? "in":"out");
1429
1430     rtgs = (scripting_rtgroup *)mrp_lua_create_object(L, RTGROUP_CLASS, id,0);
1431
1432     rtg  = mir_router_create_rtgroup(u, type, pa_xstrdup(name),
1433                                      rtgroup_accept, rtgroup_compare);
1434     if (!rtgs || !rtg)
1435         luaL_error(L, "failed to create routing group '%s'", id);
1436
1437     rtg->scripting = rtgs;
1438
1439     rtgs->userdata = u;
1440     rtgs->rtg = rtg;
1441     rtgs->type = type;
1442     rtgs->accept = accept;
1443     rtgs->compare = compare;
1444
1445     MRP_LUA_LEAVE(1);
1446 }
1447
1448 static int rtgroup_getfield(lua_State *L)
1449 {
1450     scripting_rtgroup *rtgs;
1451     mir_rtgroup *rtg;
1452     field_t fld;
1453
1454     MRP_LUA_ENTER;
1455
1456     fld = field_check(L, 2, NULL);
1457     lua_pop(L, 1);
1458
1459     if (!(rtgs = (scripting_rtgroup *)mrp_lua_check_object(L,RTGROUP_CLASS,1)))
1460         lua_pushnil(L);
1461     else {
1462         pa_assert_se((rtg = rtgs->rtg));
1463
1464         switch (fld) {
1465         case NAME:           lua_pushstring(L, rtg->name);         break;
1466         case NODE_TYPE:      lua_pushinteger(L, rtgs->type);       break;
1467         default:             lua_pushnil(L);                       break;
1468         }
1469     }
1470
1471     MRP_LUA_LEAVE(1);
1472 }
1473
1474 static int rtgroup_setfield(lua_State *L)
1475 {
1476     const char *f;
1477
1478     MRP_LUA_ENTER;
1479
1480     f = luaL_checkstring(L, 2);
1481     luaL_error(L, "attempt to set '%s' field of read-only routing_group", f);
1482
1483     MRP_LUA_LEAVE(0);
1484 }
1485
1486 static int rtgroup_tostring(lua_State *L)
1487 {
1488     scripting_rtgroup *rtgs;
1489     mir_rtgroup *rtg;
1490
1491     MRP_LUA_ENTER;
1492
1493     rtgs = (scripting_rtgroup *)mrp_lua_check_object(L, RTGROUP_CLASS, 1);
1494     pa_assert_se((rtg = rtgs->rtg));
1495
1496     lua_pushstring(L, rtg->name);
1497
1498     MRP_LUA_LEAVE(1);
1499 }
1500
1501 static void rtgroup_destroy(void *data)
1502 {
1503     scripting_rtgroup *rtgs = (scripting_rtgroup *)data;
1504     mir_rtgroup *rtg;
1505
1506     MRP_LUA_ENTER;
1507
1508     pa_assert_se((rtg = rtgs->rtg));
1509     pa_assert(rtgs == rtg->scripting);
1510
1511     rtg->scripting = NULL;
1512
1513     MRP_LUA_LEAVE_NOARG;
1514 }
1515
1516
1517 static bool rtgroup_accept(struct userdata *u,
1518                                 mir_rtgroup *rtg,
1519                                 mir_node *node)
1520 {
1521     pa_scripting *scripting;
1522     lua_State *L;
1523     scripting_rtgroup *rtgs;
1524     mrp_funcbridge_value_t  args[2];
1525     char rt;
1526     mrp_funcbridge_value_t  rv;
1527     bool accept;
1528
1529     pa_assert(u);
1530     pa_assert_se((scripting = u->scripting));
1531     pa_assert_se((L = scripting->L));
1532     pa_assert(rtg);
1533     pa_assert_se((rtgs = rtg->scripting));
1534     pa_assert(u == rtgs->userdata);
1535     pa_assert(rtgs->accept);
1536     pa_assert(node);
1537
1538     accept = false;
1539
1540     if ((rtgs = rtg->scripting) && node->scripting) {
1541
1542         args[0].pointer = rtgs;
1543         args[1].pointer = node->scripting;
1544
1545         if (!mrp_funcbridge_call_from_c(L, rtgs->accept, "oo",args, &rt,&rv)) {
1546             if (rt != MRP_FUNCBRIDGE_STRING)
1547                 pa_log("call to accept function failed");
1548             else {
1549                 pa_log("call to accept function failed: %s", rv.string);
1550                 mrp_free((void *)rv.string);
1551             }
1552         }
1553         else {
1554             if (rt != MRP_FUNCBRIDGE_BOOLEAN)
1555                 pa_log("accept function returned invalid type");
1556             else
1557                 accept = rv.boolean;
1558         }
1559     }
1560
1561     return accept;
1562 }
1563
1564 static int rtgroup_compare(struct userdata *u,
1565                            mir_rtgroup *rtg,
1566                            mir_node *node1,
1567                            mir_node *node2)
1568 {
1569     pa_scripting *scripting;
1570     lua_State *L;
1571     scripting_rtgroup *rtgs;
1572     mrp_funcbridge_value_t  args[3];
1573     char rt;
1574     mrp_funcbridge_value_t  rv;
1575     int result;
1576
1577     pa_assert(u);
1578     pa_assert_se((scripting = u->scripting));
1579     pa_assert_se((L = scripting->L));
1580     pa_assert(rtg);
1581     pa_assert_se((rtgs = rtg->scripting));
1582     pa_assert(u == rtgs->userdata);
1583     pa_assert(rtgs->compare);
1584     pa_assert(node1);
1585     pa_assert(node2);
1586
1587     result = -1;
1588
1589     if ((rtgs = rtg->scripting) && node1->scripting && node2->scripting) {
1590
1591         args[0].pointer = rtgs;
1592         args[1].pointer = node1->scripting;
1593         args[2].pointer = node2->scripting;
1594
1595         if (!mrp_funcbridge_call_from_c(L, rtgs->compare, "ooo",args, &rt,&rv))
1596             pa_log("failed to call compare function");
1597         else {
1598             if (rt != MRP_FUNCBRIDGE_FLOATING)
1599                 pa_log("compare function returned invalid type");
1600             else
1601                 result = (int)(rv.floating);
1602         }
1603     }
1604
1605     return result;
1606 }
1607
1608
1609 static bool accept_bridge(lua_State *L, void *data,
1610                           const char *signature, mrp_funcbridge_value_t *args,
1611                           char *ret_type, mrp_funcbridge_value_t *ret_val)
1612 {
1613     mir_rtgroup_accept_t accept;
1614     scripting_rtgroup *rtgs;
1615     scripting_node *ns;
1616     struct userdata *u;
1617     mir_rtgroup *rtg;
1618     mir_node *node;
1619     bool success;
1620
1621     (void)L;
1622
1623     pa_assert(signature);
1624     pa_assert(args);
1625     pa_assert(ret_type);
1626     pa_assert(ret_val);
1627
1628     pa_assert((accept = (mir_rtgroup_accept_t)data));
1629
1630     if (strcmp(signature, "oo"))
1631         success = false;
1632     else {
1633         pa_assert_se((rtgs = args[0].pointer));
1634         pa_assert_se((u = rtgs->userdata));
1635         pa_assert_se((ns = args[1].pointer));
1636
1637         if (!(rtg = rtgs->rtg) || !(node = ns->node))
1638             success = false;
1639         else {
1640             success = true;
1641             *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1642             ret_val->boolean = accept(u, rtg, node);
1643         }
1644     }
1645
1646     return success;
1647 }
1648
1649
1650 static bool compare_bridge(lua_State *L, void *data,
1651                            const char *signature, mrp_funcbridge_value_t *args,
1652                            char *ret_type, mrp_funcbridge_value_t *ret_val)
1653 {
1654     mir_rtgroup_compare_t compare;
1655     scripting_rtgroup *rtgs;
1656     scripting_node *ns1, *ns2;
1657     struct userdata *u;
1658     mir_rtgroup *rtg;
1659     mir_node *node1, *node2;
1660     bool success;
1661
1662     (void)L;
1663
1664     pa_assert(signature);
1665     pa_assert(args);
1666     pa_assert(ret_type);
1667     pa_assert(ret_val);
1668
1669     pa_assert_se((compare = (mir_rtgroup_compare_t)data));
1670
1671     if (strcmp(signature, "ooo"))
1672         success = false;
1673     else {
1674         pa_assert_se((rtgs = args[0].pointer));
1675         pa_assert_se((u = rtgs->userdata));
1676         pa_assert_se((ns1 = args[1].pointer));
1677         pa_assert_se((ns2 = args[2].pointer));
1678
1679
1680         if (!(rtg = rtgs->rtg) || !(node1 = ns1->node) || !(node2 = ns2->node))
1681             success = false;
1682         else {
1683             success = true;
1684             *ret_type = MRP_FUNCBRIDGE_FLOATING;
1685             ret_val->floating = compare(u, rtg, node1, node2);
1686         }
1687     }
1688
1689     return success;
1690 }
1691
1692
1693 static bool change_bridge(lua_State *L, void *data,
1694                           const char *signature, mrp_funcbridge_value_t *args,
1695                           char *ret_type, mrp_funcbridge_value_t *ret_val)
1696 {
1697     mir_change_value_t change;
1698     scripting_import *imp;
1699     struct userdata *u;
1700     bool success;
1701     const char *s = "default";
1702
1703     (void)L;
1704
1705     pa_assert(signature);
1706     pa_assert(args);
1707     pa_assert(ret_type);
1708     pa_assert(ret_val);
1709
1710     pa_assert_se((change = (mir_change_value_t)data));
1711
1712     if (strcmp(signature, "o"))
1713         success = false;
1714     else {
1715         pa_assert_se((imp = args[0].pointer));
1716         pa_assert_se((u = imp->userdata));
1717
1718         /* FIXME: is this how it is supposed to be done?! */
1719
1720         if (imp->values && imp->values->value.array && imp->values->value.array[0] &&
1721             imp->values->value.array[0]->value.array &&
1722               imp->values->value.array[0]->value.array[0] &&
1723               imp->values->value.array[0]->value.array[0]->type == pa_value_string)
1724             pa_assert_se((s = imp->values->value.array[0]->value.array[0]->value.string));
1725
1726         success = true;
1727         *ret_type = MRP_FUNCBRIDGE_NO_DATA;
1728         memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
1729         change(u, s);
1730     }
1731
1732     return success;
1733 }
1734
1735
1736 static int apclass_create(lua_State *L)
1737 {
1738     struct userdata *u;
1739     size_t fldnamlen;
1740     const char *fldnam;
1741     scripting_apclass *ac;
1742     char name[256];
1743     const char *class = NULL;
1744     mir_node_type type = -1;
1745     int priority = -1;
1746     route_t *route = NULL;
1747     map_t *roles = NULL;
1748     map_t *binaries = NULL;
1749     pa_nodeset_resdef *resdef;
1750     map_t *r, *b;
1751     size_t i;
1752     const char *n;
1753     bool ir, or;
1754
1755     MRP_LUA_ENTER;
1756
1757     lua_getglobal(L, USERDATA);
1758     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1759         luaL_error(L, "missing or invalid global '" USERDATA "'");
1760     lua_pop(L, 1);
1761
1762
1763     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1764
1765         switch (field_name_to_type(fldnam, fldnamlen)) {
1766         case CLASS:       class = luaL_checkstring(L, -1);             break;
1767         case NODE_TYPE:   type = luaL_checkint(L, -1);                 break;
1768         case PRIORITY:    priority = luaL_checkint(L, -1);             break;
1769         case ROUTE:       route = route_check(L, -1);                  break;
1770         case ROLES:       roles = map_check(L, -1);                    break;
1771         case BINARIES:    binaries = map_check(L, -1);                 break;
1772         default:          luaL_error(L, "bad field '%s'", fldnam);     break;
1773         }
1774
1775     } /* MRP_LUA_FOREACH_FIELD */
1776
1777     if (type < mir_application_class_begin ||
1778         type >= mir_application_class_end    )
1779         luaL_error(L, "missing or invalid node_type %d", type);
1780     if (priority < 0)
1781         luaL_error(L, "missing or invalid priority field");
1782     if (!route)
1783         luaL_error(L, "missing or invalid route field");
1784     if (!roles && !binaries)
1785         luaL_error(L, "missing roles or binaries");
1786
1787     make_id(name, sizeof(name), "%s", mir_node_type_str(type));
1788
1789     mir_router_assign_class_priority(u, type, priority);
1790
1791     ir = or = true;
1792
1793     if (route->input) {
1794         for (i = 0;  i < MRP_ZONE_MAX;  i++) {
1795             if ((n = route->input[i]))
1796                 ir &= mir_router_assign_class_to_rtgroup(u,type,i,mir_input,n);
1797         }
1798     }
1799
1800     if (route->output) {
1801         for (i = 0;  i < MRP_ZONE_MAX;  i++) {
1802             if ((n = route->output[i]))
1803                 or &= mir_router_assign_class_to_rtgroup(u,type,i,mir_output,n);
1804         }
1805     }
1806
1807     ac = (scripting_apclass *)mrp_lua_create_object(L, APPLICATION_CLASS,
1808                                                     name, 0);
1809
1810     if (!ir || !or || !ac)
1811         luaL_error(L, "failed to create application class '%s'", name);
1812
1813     ac->userdata = u;
1814     ac->name = pa_xstrdup(name);
1815     ac->class = class ? pa_xstrdup(class) : NULL;
1816     ac->type = type;
1817     ac->priority = priority;
1818     ac->route = route;
1819     ac->roles = roles;
1820     ac->binaries = binaries;
1821
1822     if (class) {
1823         if (pa_nodeset_add_class(u, type, class)) {
1824             luaL_error(L, "node type '%s' is defined multiple times",
1825                        mir_node_type_str(type));
1826         }
1827     }
1828
1829     if (roles) {
1830         for (r = roles;  r->name;  r++) {
1831             resdef = r->needres ? &r->resource : NULL;
1832
1833             if (r->role && strcmp(r->role, r->name)) {
1834                 luaL_error(L, "conflicting roles in role definition '%s' (%s)",
1835                            r->name, r->role);
1836             }
1837
1838             if (pa_nodeset_add_role(u, r->name, type, resdef)) {
1839                 luaL_error(L, "role '%s' is added to mutiple application "
1840                            "classes", r->name);
1841             }
1842         }
1843     }
1844
1845     if (binaries) {
1846         for (b = binaries;  b->name;  b++) {
1847             resdef = b->needres ? &b->resource : NULL;
1848
1849             if (pa_nodeset_add_binary(u, b->name, type, b->role, resdef)) {
1850                 luaL_error(L, "binary '%s' is added to multiple application "
1851                            "classes", b->name);
1852             }
1853         }
1854     }
1855
1856     MRP_LUA_LEAVE(1);
1857 }
1858
1859 static int apclass_getfield(lua_State *L)
1860 {
1861     scripting_apclass *ac;
1862     field_t fld;
1863
1864     MRP_LUA_ENTER;
1865
1866     fld = field_check(L, 2, NULL);
1867     lua_pop(L, 1);
1868
1869     if (!(ac=(scripting_apclass *)mrp_lua_check_object(L,APPLICATION_CLASS,1)))
1870         lua_pushnil(L);
1871     else {
1872         switch (fld) {
1873         case NAME:           lua_pushstring(L, ac->name);          break;
1874         case NODE_TYPE:      lua_pushinteger(L, ac->type);         break;
1875         case PRIORITY:       lua_pushinteger(L, ac->priority);     break;
1876         case ROUTE:          route_push(L, ac->route);             break;
1877         case ROLES:          map_push(L, ac->roles);               break;
1878         case BINARIES:       map_push(L, ac->binaries);            break;
1879         default:             lua_pushnil(L);                       break;
1880         }
1881     }
1882
1883     MRP_LUA_LEAVE(1);
1884 }
1885
1886 static int apclass_setfield(lua_State *L)
1887 {
1888     const char *f;
1889
1890     MRP_LUA_ENTER;
1891
1892     f = luaL_checkstring(L, 2);
1893     luaL_error(L,"attempt to set '%s' field of read-only application class",f);
1894
1895     MRP_LUA_LEAVE(0);
1896 }
1897
1898 static int apclass_tostring(lua_State *L)
1899 {
1900     scripting_apclass *ac;
1901
1902     MRP_LUA_ENTER;
1903
1904     ac = (scripting_apclass *)mrp_lua_check_object(L, APPLICATION_CLASS, 1);
1905
1906     lua_pushstring(L, ac->name);
1907
1908     MRP_LUA_LEAVE(1);
1909 }
1910
1911 static void apclass_destroy(void *data)
1912 {
1913     scripting_apclass *ac = (scripting_apclass *)data;
1914     struct userdata *u;
1915     map_t *r, *b;
1916
1917     MRP_LUA_ENTER;
1918
1919     pa_assert(ac);
1920     pa_assert_se((u = ac->userdata));
1921
1922     route_destroy(ac->route);
1923     ac->route = NULL;
1924
1925     pa_xfree((void *)ac->name);
1926     ac->name = NULL;
1927
1928     pa_nodeset_delete_class(u, ac->type);
1929     pa_xfree((void *)ac->class);
1930     ac->class = NULL;
1931
1932     if (ac->roles) {
1933         for (r = ac->roles;  r->name;  r++)
1934             pa_nodeset_delete_role(u, r->name);
1935
1936         map_destroy(ac->roles);
1937         ac->roles = NULL;
1938     }
1939
1940     if (ac->binaries) {
1941         for (b = ac->binaries;  b->name;  b++)
1942             pa_nodeset_delete_binary(u, b->name);
1943
1944         map_destroy(ac->binaries);
1945         ac->binaries = NULL;
1946     }
1947
1948     MRP_LUA_LEAVE_NOARG;
1949 }
1950
1951 static const char **route_definition_check(lua_State *L, int idx)
1952 {
1953     size_t zonelen;
1954     const char *zonenam;
1955     scripting_zone *zone;
1956     scripting_rtgroup *rtgs;
1957     mir_rtgroup *rtg;
1958     const char **defs;
1959     const char *rtgnam;
1960     int ndef;
1961
1962     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1963
1964     luaL_checktype(L, idx, LUA_TTABLE);
1965
1966     defs = pa_xnew0(const char *, MRP_ZONE_MAX);
1967     ndef = 0;
1968
1969     MRP_LUA_FOREACH_FIELD(L, idx, zonenam, zonelen) {
1970         if (!zonenam[0])
1971             luaL_error(L, "invalid route definition");
1972
1973         mrp_lua_find_object(L, ZONE_CLASS, zonenam);
1974
1975         if (!(zone = mrp_lua_check_object(L, NULL, -1)))
1976             luaL_error(L, "can't find zone '%s'", zonenam);
1977
1978         lua_pop(L, 1);
1979
1980         if (zone->index >= MRP_ZONE_MAX)
1981             luaL_error(L, "Internal error: zone index overflow");
1982
1983         switch (lua_type(L, -1)) {
1984         case LUA_TSTRING:
1985             rtgnam = lua_tostring(L, -1);
1986             break;
1987         case LUA_TTABLE:
1988             rtgs = (scripting_rtgroup*)mrp_lua_check_object(L,RTGROUP_CLASS,-1);
1989             if (!rtgs || !(rtg = rtgs->rtg))
1990                 rtgnam = NULL;
1991             else
1992                 rtgnam = rtg->name;
1993             break;
1994         default:
1995             rtgnam = NULL;
1996             break;
1997         }
1998
1999         if (!rtgnam)
2000             luaL_error(L, "missing or invalid routing group");
2001
2002         defs[zone->index] = pa_xstrdup(rtgnam);
2003         ndef++;
2004     }
2005
2006     if (!ndef)
2007         luaL_error(L, "empty definition");
2008
2009     return defs;
2010 }
2011
2012 static int route_definition_push(lua_State *L, const char **defs)
2013 {
2014     int i;
2015
2016     lua_createtable(L, MRP_ZONE_MAX, 0);
2017
2018     for (i = 0;  i < MRP_ZONE_MAX;  i++) {
2019     }
2020
2021     return 1;
2022 }
2023
2024
2025 #if 0
2026 static void route_definition_free(const char **defs)
2027 {
2028     int i;
2029
2030     if (defs) {
2031         for (i = 0;  i < MRP_ZONE_MAX;  i++)
2032             pa_xfree((void *)defs[i]);
2033         pa_xfree((void *)defs);
2034     }
2035 }
2036 #endif
2037
2038 static route_t *route_check(lua_State *L, int idx)
2039 {
2040     size_t fldnamlen;
2041     const char *fldnam;
2042     route_t *rt;
2043     const char **input = NULL;
2044     const char **output = NULL;
2045
2046     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2047
2048     luaL_checktype(L, idx, LUA_TTABLE);
2049
2050     MRP_LUA_FOREACH_FIELD(L, idx, fldnam, fldnamlen) {
2051         switch (field_name_to_type(fldnam, fldnamlen)) {
2052         case        INPUT:  input  = route_definition_check(L, -1);      break;
2053         case        OUTPUT: output = route_definition_check(L, -1);      break;
2054         default:    luaL_error(L, "invalid field '%s'", fldnam);         break;
2055         }
2056     } /* MRP_LUA_FOREACH_FIELD */
2057
2058     if (!input && !output)
2059         luaL_error(L, "neither input nor output routing group were specified");
2060
2061     rt = pa_xmalloc(sizeof(route_t));
2062     rt->input  = input;
2063     rt->output = output;
2064
2065     return rt;
2066 }
2067
2068 static int route_push(lua_State *L, route_t *rt)
2069 {
2070     if (!rt || (!rt->input && !rt->output))
2071         lua_pushnil(L);
2072     else {
2073         lua_createtable(L, 0, 2);
2074
2075         if (rt->input) {
2076             lua_pushstring(L, "input");
2077             route_definition_push(L, rt->input);
2078             lua_settable(L, -3);
2079         }
2080
2081         if (rt->output) {
2082             lua_pushstring(L, "output");
2083             route_definition_push(L, rt->output);
2084             lua_settable(L, -3);
2085         }
2086     }
2087
2088     return 1;
2089 }
2090
2091 static void route_destroy(route_t *rt)
2092 {
2093     if (rt) {
2094         pa_xfree((void *)rt->input);
2095         pa_xfree((void *)rt->output);
2096         pa_xfree((void *)rt);
2097     }
2098 }
2099
2100
2101 static int vollim_create(lua_State *L)
2102 {
2103     static int min = mir_application_class_begin;
2104     static int max = mir_application_class_end;
2105
2106     struct userdata *u;
2107     size_t fldnamlen;
2108     const char *fldnam;
2109     scripting_vollim *vlim;
2110     const char *name = NULL;
2111     vollim_type type = 0;
2112     limit_data_t *limit = NULL;
2113     mrp_funcbridge_t *calculate = NULL;
2114     intarray_t *classes = NULL;
2115     bool suppress = false;
2116     bool correct = false;
2117     size_t arglgh = 0;
2118     int i;
2119     int class;
2120     uint32_t mask, clmask;
2121     char id[256];
2122
2123     MRP_LUA_ENTER;
2124
2125     lua_getglobal(L, USERDATA);
2126     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
2127         luaL_error(L, "missing or invalid global '" USERDATA "'");
2128     lua_pop(L, 1);
2129
2130
2131     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
2132
2133         switch (field_name_to_type(fldnam, fldnamlen)) {
2134         case NAME:      name      = luaL_checkstring(L, -1);             break;
2135         case TYPE:      type      = luaL_checkint(L, -1);                break;
2136         case NODE_TYPE: classes = intarray_check(L, -1, min, max);       break;
2137         case LIMIT:     limit     = limit_data_check(L, -1);             break;
2138         case CALCULATE: calculate = mrp_funcbridge_create_luafunc(L,-1); break;
2139         default:        luaL_error(L, "bad field '%s'", fldnam);         break;
2140         }
2141
2142     } /* MRP_LUA_FOREACH_FIELD */
2143
2144     if (!name)
2145         luaL_error(L, "missing name field");
2146     if (type != vollim_class && type != vollim_generic && type != vollim_maximum)
2147         luaL_error(L, "missing or invalid type");
2148     if ((type == vollim_class || type == vollim_maximum) && !classes)
2149         luaL_error(L, "missing or invalid node_type for class/maximum limit");
2150     if (type == vollim_generic && classes)
2151         luaL_error(L, "can't specify node_type for generic volume limit");
2152     if (!limit)
2153         luaL_error(L, "missing or invalid limit");
2154     if (type != vollim_maximum && !calculate)
2155         luaL_error(L, "missing calculate field");
2156     if (type != vollim_maximum) {
2157         if (calculate->type == MRP_C_FUNCTION) {
2158             if (strcmp(calculate->c.signature, "odod"))
2159                 luaL_error(L,"invalid calculate field (mismatching signature)");
2160             if (calculate->c.data == mir_volume_suppress) {
2161                 if (type != vollim_class)
2162                     luaL_error(L, "attempt to make generic volume supression");
2163                 suppress = true;
2164                 arglgh = sizeof(mir_volume_suppress_arg);
2165             }
2166             else if (calculate->c.data == mir_volume_correction) {
2167                 if (type != vollim_generic) {
2168                     luaL_error(L, "attempt to make class based volume"
2169                                "correction");
2170                 }
2171                 correct = true;
2172                 arglgh = sizeof(double *);
2173             }
2174             else {
2175                 luaL_error(L, "invalid builtin.method for calculate");
2176             }
2177         }
2178         else {
2179             switch (type) {
2180             case vollim_class:
2181                 suppress = true;
2182                 arglgh = sizeof(mir_volume_suppress_arg);
2183                 break;
2184             case vollim_generic:
2185                 correct = true;
2186                 arglgh = sizeof(double *);
2187                 break;
2188             default:
2189                 break;
2190             }
2191         }
2192     }
2193
2194     make_id(id, sizeof(id), "%s", name);
2195
2196     (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2197     vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2198     (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2199
2200     vlim->userdata = u;
2201     vlim->name = pa_xstrdup(name);
2202     vlim->type = type;
2203     vlim->classes = classes;
2204     vlim->limit = limit;
2205     vlim->calculate = calculate;
2206
2207     if (suppress) {
2208         mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)(void *)vlim->args;
2209         size_t size = sizeof(int) * classes->nint;
2210         size_t n = mir_application_class_end - mir_application_class_begin;
2211
2212         for (i = 0, clmask = 0;   i < (int)(classes->nint);   i++) {
2213             class = classes->ints[i];
2214
2215             if (class <= mir_application_class_begin ||
2216                 class >  mir_application_class_end     )
2217             {
2218                 pa_log("invalid triggering class id %d", class);
2219                 clmask = 0;
2220                 classes->nint = n = 0;
2221                 break;
2222             }
2223
2224             mask = ((uint32_t)1) << (class - mir_application_class_begin);
2225
2226             if (!(clmask & mask) && n > 0)
2227                 n--;
2228
2229             clmask |= mask;
2230         }
2231
2232         args->attenuation = limit->value;
2233         args->trigger.nclass = classes->nint;
2234         args->trigger.classes = pa_xmalloc(size);
2235         args->trigger.clmask = clmask;
2236
2237         memcpy(args->trigger.classes, classes->ints, size);
2238
2239         if (n > classes->nint)
2240             classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2241         classes->nint = n;
2242
2243         for (i = mir_application_class_begin, n = 0;
2244              i < mir_application_class_end;
2245              i++)
2246         {
2247             if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2248                 classes->ints[n++] = i;
2249         }
2250     }
2251     else if (correct) {
2252         /* *(double **)vlim->args = limit->value; */
2253
2254         memcpy(vlim->args, &limit->value, sizeof(limit->value));
2255     }
2256
2257     switch (type) {
2258     case vollim_generic:
2259         mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2260         break;
2261     case vollim_class:
2262         for (i = 0;  i < (int)(classes->nint);  i++) {
2263             mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2264                                        vlim->args);
2265         }
2266         break;
2267     case vollim_maximum:
2268         mir_volume_add_maximum_limit(u, *(vlim->limit->value),
2269                                      classes->nint, classes->ints);
2270         break;
2271     default:
2272         break;
2273     }
2274
2275     MRP_LUA_LEAVE(1);
2276 }
2277
2278 static int vollim_getfield(lua_State *L)
2279 {
2280     scripting_vollim *vlim;
2281     field_t fld;
2282
2283     MRP_LUA_ENTER;
2284
2285     fld = field_check(L, 2, NULL);
2286     lua_pop(L, 1);
2287
2288     if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2289         lua_pushnil(L);
2290     else {
2291         switch (fld) {
2292         case NAME:         lua_pushstring(L, vlim->name);           break;
2293         case TYPE:         lua_pushinteger(L, vlim->type);          break;
2294         case NODE_TYPE:    intarray_push(L, vlim->classes);         break;
2295         case LIMIT:        lua_pushnumber(L, *vlim->limit->value);  break;
2296         default:           lua_pushnil(L);                          break;
2297         }
2298     }
2299
2300     MRP_LUA_LEAVE(1);
2301 }
2302
2303 static int vollim_setfield(lua_State *L)
2304 {
2305     const char *f;
2306
2307     MRP_LUA_ENTER;
2308
2309     f = luaL_checkstring(L, 2);
2310     luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2311
2312     MRP_LUA_LEAVE(0);
2313 }
2314
2315 static int vollim_tostring(lua_State *L)
2316 {
2317     scripting_vollim *vlim;
2318
2319     MRP_LUA_ENTER;
2320
2321     vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2322
2323     lua_pushstring(L, vlim->name);
2324
2325     MRP_LUA_LEAVE(1);
2326 }
2327
2328 static void vollim_destroy(void *data)
2329 {
2330     scripting_vollim *vlim = (scripting_vollim *)data;
2331
2332     MRP_LUA_ENTER;
2333
2334     pa_xfree((void *)vlim->name);
2335     intarray_destroy(vlim->classes);
2336     limit_data_destroy(vlim->limit);
2337
2338     MRP_LUA_LEAVE_NOARG;
2339 }
2340
2341
2342 static double vollim_calculate(struct userdata *u, int class,
2343                                mir_node *node, uint32_t mask, void *data)
2344 {
2345     static int offset = ((scripting_vollim *)0)->args - (char *)0;
2346
2347     pa_scripting *scripting;
2348     lua_State *L;
2349     scripting_vollim *vlim;
2350     mrp_funcbridge_value_t args[4];
2351     char rt;
2352     mrp_funcbridge_value_t  rv;
2353     double limit;
2354
2355     pa_assert(u);
2356     pa_assert_se((scripting = u->scripting));
2357     pa_assert_se((L = scripting->L));
2358     pa_assert(!class || (class >= mir_application_class_begin &&
2359                          class <  mir_application_class_end)     );
2360     pa_assert(node);
2361
2362     vlim = (scripting_vollim *)(void*)((char *)data - offset);
2363
2364     pa_assert(u == vlim->userdata);
2365
2366     limit = -90.0;
2367
2368     if (node->scripting) {
2369
2370         args[0].pointer = vlim;
2371         args[1].integer = class;
2372         args[2].pointer = node->scripting;
2373         args[3].integer = (int32_t)mask;
2374
2375         if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odod",args,&rt,&rv))
2376             pa_log("failed to call calculate function");
2377         else {
2378             if (rt != MRP_FUNCBRIDGE_FLOATING)
2379                 pa_log("accept function returned invalid type");
2380             else
2381                 limit = rv.floating;
2382         }
2383     }
2384
2385     return limit;
2386 }
2387
2388 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2389                              mrp_funcbridge_value_t *args,
2390                              char *ret_type, mrp_funcbridge_value_t *ret_val)
2391 {
2392     mir_volume_func_t calculate;
2393     scripting_vollim *vlim;
2394     scripting_node *ns;
2395     struct userdata *u;
2396     int class;
2397     mir_node *node;
2398     uint32_t mask;
2399     bool success;
2400
2401     (void)L;
2402
2403     pa_assert(signature);
2404     pa_assert(args);
2405     pa_assert(ret_type);
2406     pa_assert(ret_val);
2407
2408     pa_assert_se((calculate = (mir_volume_func_t)data));
2409
2410     if (strcmp(signature, "odod"))
2411         success = false;
2412     else {
2413         pa_assert_se((vlim = args[0].pointer));
2414         pa_assert_se((u = vlim->userdata));
2415         pa_assert_se((ns = args[2].pointer));
2416
2417         class = args[1].integer;
2418         mask = (uint32_t)args[3].integer;
2419
2420         pa_assert(!class || (class >= mir_application_class_begin &&
2421                              class <  mir_application_class_end));
2422
2423         if (!(node = ns->node))
2424             success = false;
2425         else {
2426             success = true;
2427             *ret_type = MRP_FUNCBRIDGE_FLOATING;
2428             /* TODO: check the vollim type vs. c function */
2429             ret_val->floating = calculate(u, class, node, mask, vlim->args);
2430         }
2431     }
2432
2433     return success;
2434 }
2435
2436 static limit_data_t *limit_data_check(lua_State *L, int idx)
2437 {
2438     static double nolimit = 0.0;
2439
2440     limit_data_t *ld = NULL;
2441     double value;
2442     pa_value *v;
2443
2444     switch (lua_type(L, idx)) {
2445     case LUA_TNUMBER:
2446         if ((value = lua_tonumber(L, idx)) > 0.0)
2447             luaL_error(L, "volume limit is in dB and can't be positive");
2448         else {
2449             ld = pa_xnew0(limit_data_t, 1);
2450             ld->mallocd = true;
2451             ld->value = pa_xnew0(double, 1);
2452             *ld->value = value;
2453         }
2454         break;
2455     case LUA_TLIGHTUSERDATA:
2456         if (!(v = lua_touserdata(L, idx)) || v->type < 0)
2457             luaL_error(L, "broken link for volume limit value");
2458         else {
2459             ld = pa_xnew0(limit_data_t, 1);
2460             ld->mallocd = false;
2461             ld->value = &v->value.floating;
2462         }
2463         break;
2464     default:
2465         ld = pa_xnew0(limit_data_t, 1);
2466         ld->mallocd = false;
2467         ld->value = &nolimit;
2468         break;
2469     }
2470
2471     return ld;
2472 }
2473
2474 #if 0
2475 static int limit_data_push(lua_State *L, limit_data_t *ld)
2476 {
2477     if (ld)
2478         lua_pushnumber(L, *ld->value);
2479     else
2480         lua_pushnil;
2481
2482     return 1;
2483 }
2484 #endif
2485
2486 static void limit_data_destroy(limit_data_t *ld)
2487 {
2488     if (ld) {
2489         if (ld->mallocd)
2490             pa_xfree(ld->value);
2491         pa_xfree(ld);
2492     }
2493 }
2494
2495
2496 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2497 {
2498     int len;
2499     size_t size;
2500     intarray_t *arr;
2501     int val;
2502     int i;
2503
2504     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2505
2506     luaL_checktype(L, idx, LUA_TTABLE);
2507
2508     if ((len = luaL_getn(L, idx)) < 1)
2509         arr = NULL;
2510     else {
2511         size = sizeof(intarray_t) + sizeof(int) * (size_t)len;
2512         arr  = pa_xmalloc0(sizeof(intarray_t));
2513
2514         arr->nint = (size_t)len;
2515         arr->ints = pa_xmalloc0(size);
2516
2517         for (i = 0;  i < len;  i++) {
2518             lua_pushnumber(L, (int)(i+1));
2519             lua_gettable(L, idx);
2520
2521             val = luaL_checkint(L, -1);
2522
2523             lua_pop(L, 1);
2524
2525             if (val < min || val >= max)
2526                 luaL_error(L, "array [%u]: out of range value (%d)", i, val);
2527
2528             arr->ints[i] = val;
2529         }
2530     }
2531
2532     return arr;
2533 }
2534
2535 static int intarray_push(lua_State *L, intarray_t *arr)
2536 {
2537     size_t i;
2538
2539     if (!arr)
2540         lua_pushnil(L);
2541     else {
2542         lua_createtable(L, (int)(arr->nint), 0);
2543
2544         for (i = 0;  i < arr->nint;  i++) {
2545             lua_pushinteger(L, (int)(i+1));
2546             lua_pushinteger(L, arr->ints[i]);
2547             lua_settable(L, -3);
2548         }
2549     }
2550
2551     return 1;
2552 }
2553
2554 static void intarray_destroy(intarray_t *arr)
2555 {
2556     if (arr) {
2557         pa_xfree(arr->ints);
2558         pa_xfree(arr);
2559     }
2560 }
2561
2562 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2563 {
2564     resource_name_t *name;
2565     size_t fldnamlen;
2566     const char *fldnam;
2567     const char *value;
2568
2569     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2570
2571     luaL_checktype(L, tbl, LUA_TTABLE);
2572
2573     name = pa_xnew0(resource_name_t, 1);
2574
2575     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2576         value = luaL_checkstring(L, -1);
2577
2578         if (!strcmp(fldnam, "recording"))
2579             name->recording = pa_xstrdup(value);
2580         else if (!strcmp(fldnam, "playback"))
2581             name->playback = pa_xstrdup(value);
2582         else {
2583             luaL_error(L, "invalid field '%s' in resource name definition",
2584                        fldnam);
2585         }
2586     }
2587
2588     return name;
2589 }
2590
2591 static void resource_names_destroy(resource_name_t *name)
2592 {
2593     if (name) {
2594         pa_xfree((void *)name->recording);
2595         pa_xfree((void *)name->playback);
2596         pa_xfree(name);
2597     }
2598 }
2599
2600 static attribute_t *attributes_check(lua_State *L, int tbl)
2601 {
2602     int def;
2603     size_t fldnamlen;
2604     const char *fldnam;
2605     attribute_t *attr, *attrs = NULL;
2606     size_t nattr = 0;
2607     mrp_attr_value_t *v;
2608     int i, len;
2609
2610     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2611
2612     luaL_checktype(L, tbl, LUA_TTABLE);
2613
2614     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2615         if (!fldnam[0])
2616             luaL_error(L, "invalid attribute definition");
2617
2618         attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2619         memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2620
2621         attr = attrs + nattr++;
2622         v = &attr->def.value;
2623         def = lua_gettop(L);
2624
2625         attr->def.name = pa_xstrdup(fldnam);
2626
2627         if ((len = luaL_getn(L, def)) != 3)
2628             luaL_error(L, "invalid attribute definition '%s'", fldnam);
2629
2630         for (i = 0;  i < len;  i++) {
2631             lua_pushnumber(L, (int)(i+1));
2632             lua_gettable(L, def);
2633
2634             switch (i) {
2635             case 0:  attr->prop = pa_xstrdup(luaL_checkstring(L,-1));    break;
2636             case 1:  attr->def.type = luaL_checkint(L,-1);               break;
2637             case 2:
2638                 switch (attr->def.type) {
2639                 case mqi_string:   v->string = luaL_checkstring(L,-1);   break;
2640                 case mqi_integer:  v->integer = luaL_checkint(L,-1);     break;
2641                 case mqi_unsignd:  v->integer = luaL_checkint(L,-1);     break;
2642                 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2643                 default:           memset(v, 0, sizeof(*v));             break;
2644                 }
2645             }
2646
2647             lua_pop(L, 1);
2648         }
2649
2650         if (!attr->prop)
2651             luaL_error(L, "missing property name definition from '%s'",fldnam);
2652         if (attr->def.type != mqi_string  && attr->def.type != mqi_integer &&
2653             attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2654         {
2655             luaL_error(L, "invalid attribute type %d for '%s'",
2656                        attr->def.type, fldnam);
2657         }
2658         if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2659             luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2660                        attr->def.value.integer, fldnam);
2661         }
2662     }
2663
2664     return attrs;
2665 }
2666
2667 static void attributes_destroy(attribute_t *attrs)
2668 {
2669     attribute_t *attr;
2670
2671     if (attrs) {
2672         for (attr = attrs;  attr->prop && attr->def.name;  attr++) {
2673             pa_xfree((void *)attr->prop);
2674             pa_xfree((void *)attr->def.name);
2675             if (attr->def.type == mqi_string)
2676                 pa_xfree((void *)attr->def.value.string);
2677         }
2678         pa_xfree(attrs);
2679     }
2680 }
2681
2682 static map_t *map_check(lua_State *L, int tbl)
2683 {
2684     int def;
2685     size_t namlen;
2686     const char *name;
2687     const char *option;
2688     map_t *m, *map = NULL;
2689     size_t n = 0;
2690     int i, len;
2691     int priority;
2692     pa_nodeset_resdef *rd;
2693
2694     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2695
2696     luaL_checktype(L, tbl, LUA_TTABLE);
2697
2698     MRP_LUA_FOREACH_FIELD(L, tbl, name, namlen) {
2699         if (!name[0])
2700             luaL_error(L, "invalid role or binary definition");
2701
2702         map = pa_xrealloc(map, sizeof(map_t) * (n + 2));
2703         memset(map + n, 0, sizeof(map_t) * 2);
2704
2705         m = map + n++;
2706         def = lua_gettop(L);
2707
2708         m->name = pa_xstrdup(name);
2709
2710         switch (lua_type(L, -1)) {
2711
2712         case LUA_TNUMBER:
2713             m->needres = false;
2714             break;
2715
2716         case LUA_TSTRING:
2717             m->needres = false;
2718             m->role = mrp_strdup(lua_tostring(L, def));
2719             break;
2720
2721         case LUA_TTABLE:
2722             m->needres = true;
2723
2724             if ((len = luaL_getn(L, def)) < 1)
2725                 luaL_error(L, "invalid resource definition '%s'", name);
2726
2727             for (i = 1;  i < len+1;  i++) {
2728                 lua_pushnumber(L, (int)i);
2729                 lua_gettable(L, def);
2730
2731                 if (i == 1) {
2732                     priority = luaL_checkint(L, -1);
2733
2734                     if (priority < 0 || priority > 7) {
2735                         luaL_error(L, "invalid priority %d for '%s'",
2736                                    priority, name);
2737                     }
2738
2739                     m->resource.priority = (uint32_t)priority;
2740                 }
2741                 else {
2742                     option = luaL_checkstring(L, -1);
2743                     rd = &m->resource;
2744
2745                     if (pa_streq(option, "autorelease"))
2746                         rd->flags.rset |= RESPROTO_RSETFLAG_AUTORELEASE;
2747                     else if (pa_streq(option, "mandatory"))
2748                         rd->flags.audio |= RESPROTO_RESFLAG_MANDATORY;
2749                     else if (pa_streq(option, "shared"))
2750                         rd->flags.audio |= RESPROTO_RESFLAG_SHARED;
2751                     else if (!pa_streq(option, "optional") &&
2752                              !pa_streq(option, "exclusive") )
2753                     {
2754                         if (!m->role)
2755                             m->role = pa_xstrdup(option);
2756                         else {
2757                             luaL_error(L, "multiple role definition '%s','%s'",
2758                                        m->role, option);
2759                         }
2760                     }
2761                 }
2762
2763                 lua_pop(L, 1);
2764             }
2765
2766             break;
2767
2768         default:
2769             luaL_error(L, "invalid resource specification. "
2770                        "Should be either 'no_resource' or a table");
2771             break;
2772         }
2773     } /* FOREACH_FIELD */
2774
2775     return map;
2776 }
2777
2778 static int map_push(lua_State *L, map_t *map)
2779 {
2780     map_t *m;
2781
2782     if (!map)
2783         lua_pushnil(L);
2784     else {
2785         lua_newtable(L);
2786
2787         for (m = map;  m->name;  m++) {
2788             if (!m->needres) {
2789                 if (m->role)
2790                     lua_pushstring(L, m->role);
2791                 else
2792                     lua_pushnumber(L, 0);
2793             }
2794             else {
2795                 lua_newtable(L);
2796                 lua_pushinteger(L, (int)(m->resource.priority));
2797                 if (m->role)
2798                     lua_pushstring(L, m->role);
2799                 if (m->resource.flags.rset & RESPROTO_RSETFLAG_AUTORELEASE)
2800                     lua_pushstring(L, "autorelease");
2801                 if (m->resource.flags.audio & RESPROTO_RESFLAG_MANDATORY)
2802                     lua_pushstring(L, "mandatory");
2803                 else
2804                     lua_pushstring(L, "optional");
2805                 if (m->resource.flags.audio & RESPROTO_RESFLAG_SHARED)
2806                     lua_pushstring(L, "shared");
2807                 else
2808                     lua_pushstring(L, "exclusive");
2809             }
2810             lua_setfield(L, -2, m->name);
2811         }
2812     }
2813
2814     return 1;
2815 }
2816
2817 static void map_destroy(map_t *map)
2818 {
2819     map_t *m;
2820
2821     if (map) {
2822         for (m = map;  m->name;  m++) {
2823             pa_xfree((void *)m->name);
2824             pa_xfree((void *)m->role);
2825         }
2826         pa_xfree(map);
2827     }
2828 }
2829
2830
2831 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
2832 {
2833     const char *fldnam;
2834     size_t fldnamlen;
2835     field_t fldtyp;
2836
2837     if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
2838         fldtyp = 0;
2839     else
2840         fldtyp = field_name_to_type(fldnam, fldnamlen);
2841
2842     if (ret_fldnam)
2843         *ret_fldnam = fldnam;
2844
2845     return fldtyp;
2846 }
2847
2848 static field_t field_name_to_type(const char *name, size_t len)
2849 {
2850     switch (len) {
2851
2852     case 4:
2853         switch (name[0]) {
2854         case 'n':
2855             if (!strcmp(name, "name"))
2856                 return NAME;
2857             break;
2858         case 't':
2859             if (!strcmp(name, "type"))
2860                 return TYPE;
2861             break;
2862         case 'z':
2863             if (!strcmp(name, "zone"))
2864                 return ZONE;
2865             break;
2866         default:
2867             break;
2868         }
2869         break;
2870
2871     case 5:
2872         switch (name[0]) {
2873         case 'c':
2874             if (!strcmp(name, "class"))
2875                 return CLASS;
2876             break;
2877         case 'i':
2878             if (!strcmp(name, "input"))
2879                 return INPUT;
2880             break;
2881         case 'l':
2882             if (!strcmp(name, "limit"))
2883                 return LIMIT;
2884             break;
2885         case 'r':
2886             if (!strcmp(name, "route"))
2887                 return ROUTE;
2888             if (!strcmp(name, "roles"))
2889                 return ROLES;
2890             break;
2891         case 't':
2892             if (!strcmp(name, "table"))
2893                 return TABLE;
2894             break;
2895         default:
2896             break;
2897         }
2898         break;
2899
2900     case 6:
2901         switch (name[0]) {
2902         case 'a':
2903             if (!strcmp(name, "accept"))
2904                 return ACCEPT;
2905             break;
2906         case 'm':
2907             if (!strcmp(name, "maxrow"))
2908                 return MAXROW;
2909             break;
2910         case 'o':
2911             if (!strcmp(name, "output"))
2912                 return OUTPUT;
2913             break;
2914         case 't':
2915             if (!strcmp(name, "tables"))
2916                 return TABLES;
2917             break;
2918         case 'u':
2919             if (!strcmp(name, "update"))
2920                 return UPDATE;
2921             break;
2922         default:
2923             break;
2924         }
2925         break;
2926
2927     case 7:
2928         switch (name[0]) {
2929         case 'c':
2930             if (!strcmp(name, "compare"))
2931                 return COMPARE;
2932             if (!strcmp(name, "columns"))
2933                 return COLUMNS;
2934             break;
2935         case 'p':
2936             if (!strcmp(name, "privacy"))
2937                 return PRIVACY;
2938             break;
2939         default:
2940             break;
2941         }
2942         break;
2943
2944     case 8:
2945         switch (name[0]) {
2946         case 'b':
2947             if (!strcmp(name, "binaries"))
2948                 return BINARIES;
2949             break;
2950         case 'c':
2951             if (!strcmp(name, "channels"))
2952                 return CHANNELS;
2953             break;
2954         case 'l':
2955             if (!strcmp(name, "location"))
2956                 return LOCATION;
2957             break;
2958         case 'p':
2959             if (!strcmp(name, "priority"))
2960                 return PRIORITY;
2961             break;
2962         default:
2963             break;
2964         }
2965         break;
2966
2967     case 9:
2968         switch (name[0]) {
2969         case 'a':
2970             if (!strcmp(name, "available"))
2971                 return AVAILABLE;
2972             break;
2973         case 'c':
2974             if (!strcmp(name, "calculate"))
2975                 return CALCULATE;
2976             if (!strcmp(name, "condition"))
2977                 return CONDITION;
2978             break;
2979         case 'd':
2980             if (!strcmp(name, "direction"))
2981                 return DIRECTION;
2982             break;
2983         case 'i':
2984             if (!strcmp(name, "implement"))
2985                 return IMPLEMENT;
2986             break;
2987         case 'n':
2988             if (!strcmp(name, "node_type"))
2989                 return NODE_TYPE;
2990             break;
2991         default:
2992             break;
2993         }
2994         break;
2995
2996     case 10:
2997         if (!strcmp(name, "attributes"))
2998             return ATTRIBUTES;
2999         break;
3000
3001     case 11:
3002         if (!strcmp(name, "autorelease"))
3003             return AUTORELEASE;
3004         if (!strcmp(name, "description"))
3005             return DESCRIPTION;
3006         break;
3007
3008     default:
3009         break;
3010     }
3011
3012     return 0;
3013 }
3014
3015 static int make_id(char *buf, size_t len, const char *fmt, ...)
3016 {
3017     va_list ap;
3018     int l;
3019     char *p, c;
3020
3021     va_start(ap, fmt);
3022     l = vsnprintf(buf, len, fmt, ap);
3023     va_end(ap);
3024
3025     for (p = buf;  (c = *p);  p++) {
3026         if (isalpha(c))
3027             c = (char)tolower(c);
3028         else if (!isdigit(c))
3029             c = '_';
3030         *p = c;
3031     }
3032
3033     return l;
3034 }
3035
3036
3037 static void setup_murphy_interface(struct userdata *u)
3038 {
3039     pa_scripting *scripting;
3040     scripting_import *imp;
3041     const char *key;
3042     lua_State *L;
3043     int class;
3044     bool need_domainctl;
3045     char buf[8192];
3046     const char *columns;
3047     int top;
3048     pa_value *values;
3049
3050     MRP_LUA_ENTER;
3051
3052     pa_assert(u);
3053     pa_assert_se((scripting = u->scripting));
3054     pa_assert_se((L = scripting->L));
3055
3056     top = lua_gettop(L);
3057
3058     mrp_lua_get_class_table(L, IMPORT_CLASS);
3059     class = lua_gettop(L);
3060
3061     if (!lua_istable(L, class)){
3062         luaL_error(L, "internal error: failed to find '%s' table",
3063                    (IMPORT_CLASS)->constructor);
3064     }
3065
3066     need_domainctl = false;
3067
3068     lua_pushnil(L);
3069     while (lua_next(L, class)) {
3070         if (lua_isstring(L, -2)) {
3071             if ((imp = mrp_lua_to_object(L, IMPORT_CLASS, -1))) {
3072                 key = lua_tostring(L, -2);
3073
3074                 pa_assert(!strcmp(key, imp->table));
3075                 pa_assert_se((values = imp->values));
3076
3077                 pa_log_debug("adding import '%s'", imp->table);
3078
3079                 need_domainctl = true;
3080                 columns = comma_separated_list(imp->columns, buf,sizeof(buf));
3081
3082                 pa_murphyif_add_watch(u, imp->table, columns, imp->condition,
3083                                       -values->type);
3084             }
3085         }
3086         lua_pop(L, 1);
3087     }
3088
3089     if (need_domainctl)
3090         pa_murphyif_setup_domainctl(u, import_data_changed);
3091
3092     lua_settop(L, top);
3093
3094     MRP_LUA_LEAVE_NOARG;
3095 }
3096
3097
3098 static char *comma_separated_list(mrp_lua_strarray_t *arr, char *buf, int len)
3099 {
3100     char *p, *e;
3101     size_t i;
3102
3103     pa_assert(arr);
3104     pa_assert(buf);
3105     pa_assert(len > 0);
3106
3107     for (i = 0, e = (p = buf) + len;   i < arr->nstring && p < e;    i++)
3108         p += snprintf(p, (size_t)(e-p), "%s%s", (p == buf ? "" : ","), arr->strings[i]);
3109
3110     return (p < e) ? buf : NULL;
3111 }
3112
3113
3114 static bool define_constants(lua_State *L)
3115 {
3116     static const_def_t mdb_const[] = {
3117         { "string"           , mqi_string           },
3118         { "integer"          , mqi_integer          },
3119         { "unsigned"         , mqi_unsignd          },
3120         { "floating"         , mqi_floating         },
3121         {       NULL         ,         0            }
3122     };
3123
3124     static const_def_t node_const[] = {
3125         { "input"            , mir_input            },
3126         { "output"           , mir_output           },
3127         { "device"           , mir_device           },
3128         { "stream"           , mir_stream           },
3129         { "internal"         , mir_internal         },
3130         { "external"         , mir_external         },
3131         { "radio"            , mir_radio            },
3132         { "player"           , mir_player           },
3133         { "navigator"        , mir_navigator        },
3134         { "game"             , mir_game             },
3135         { "browser"          , mir_browser          },
3136         { "camera"           , mir_camera           },
3137         { "phone"            , mir_phone            },
3138         { "alert"            , mir_alert            },
3139         { "event"            , mir_event            },
3140         { "system"           , mir_system           },
3141         { "speakers"         , mir_speakers         },
3142         { "microphone"       , mir_microphone       },
3143         { "jack"             , mir_jack             },
3144         { "spdif"            , mir_spdif            },
3145         { "hdmi"             , mir_hdmi             },
3146         { "wired_headset"    , mir_wired_headset    },
3147         { "wired_headphone"  , mir_wired_headphone  },
3148         { "usb_headset"      , mir_usb_headset      },
3149         { "usb_headphone"    , mir_usb_headphone    },
3150         { "bluetooth_sco"    , mir_bluetooth_sco    },
3151         { "bluetooth_a2dp"   , mir_bluetooth_a2dp   },
3152         { "bluetooth_carkit" , mir_bluetooth_carkit },
3153         { "bluetooth_source" , mir_bluetooth_source },
3154         { "bluetooth_sink"   , mir_bluetooth_sink   },
3155         {       NULL         ,         0            }
3156     };
3157
3158     static const_def_t vollim_const[] = {
3159         { "class"            , vollim_class         },
3160         { "generic"          , vollim_generic       },
3161         { "maximum"          , vollim_maximum       },
3162         {       NULL         ,         0            }
3163     };
3164
3165     const_def_t *cd;
3166     bool success = true;
3167
3168
3169     lua_getglobal(L, "mdb");
3170
3171     if (!lua_istable(L, -1))
3172         success = false;
3173     else {
3174         for (cd = mdb_const;   cd->name;   cd++) {
3175             lua_pushstring(L, cd->name);
3176             lua_pushinteger(L, cd->value);
3177             lua_rawset(L, -3);
3178         }
3179         lua_pop(L, 1);
3180     }
3181
3182
3183
3184     lua_getglobal(L, "node");
3185
3186     if (!lua_istable(L, -1))
3187         success = false;
3188     else {
3189         for (cd = node_const;   cd->name;   cd++) {
3190             lua_pushstring(L, cd->name);
3191             lua_pushinteger(L, cd->value);
3192             lua_rawset(L, -3);
3193         }
3194         lua_pop(L, 1);
3195     }
3196
3197
3198     lua_getglobal(L, "volume_limit");
3199
3200     if (!lua_istable(L, -1))
3201         success = false;
3202     else {
3203         for (cd = vollim_const;   cd->name;   cd++) {
3204             lua_pushstring(L, cd->name);
3205             lua_pushinteger(L, cd->value);
3206             lua_rawset(L, -3);
3207         }
3208         lua_pop(L, 1);
3209     }
3210
3211     lua_pushnumber(L, 0);
3212     lua_setglobal(L, "no_resource");
3213
3214     return success;
3215 }
3216
3217
3218 static bool register_methods(lua_State *L)
3219 {
3220     static funcbridge_def_t funcbridge_defs[] = {
3221         {"make_routes"    ,"o"   , update_bridge   ,mir_router_make_routing   },
3222         {"make_volumes"   ,"o"   , update_bridge   ,mir_volume_make_limiting  },
3223         {"accept_default" ,"oo"  , accept_bridge   ,mir_router_default_accept },
3224         {"compare_default","ooo" , compare_bridge  ,mir_router_default_compare},
3225         {"accept_phone"   ,"oo"  , accept_bridge   ,mir_router_phone_accept   },
3226         {"compare_phone"  ,"ooo" , compare_bridge  ,mir_router_phone_compare  },
3227         {"volume_supress" ,"odod", calculate_bridge,mir_volume_suppress       },
3228         {"volume_correct" ,"odod", calculate_bridge,mir_volume_correction     },
3229         {"change_volume_context","o",change_bridge, mir_volume_change_context },
3230         {       NULL      , NULL,      NULL       ,         NULL              }
3231     };
3232
3233     funcbridge_def_t *d;
3234     bool success = true;
3235
3236     for (d = funcbridge_defs;   d->name;    d++) {
3237         if (!mrp_funcbridge_create_cfunc(L,d->name,d->sign,d->func,d->data)) {
3238             pa_log("%s: failed to register builtin function '%s'",
3239                    __FILE__, d->name);
3240             success = false;
3241         }
3242     }
3243
3244     return success;
3245 }
3246
3247
3248
3249 static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize)
3250 {
3251     void *mem;
3252
3253     (void)ud;
3254     (void)osize;
3255
3256     if (nsize)
3257         mem = pa_xrealloc(ptr, nsize);
3258     else {
3259         mem = NULL;
3260         pa_xfree(ptr);
3261     }
3262
3263     return mem;
3264 }
3265
3266 static int panic(lua_State *L)
3267 {
3268     (void)L;
3269
3270     pa_log("PANIC: unprotected error in call to Lua API (%s)",
3271            lua_tostring(L,-1));
3272
3273     return 0;
3274 }
3275
3276
3277 /*
3278  * Local Variables:
3279  * c-basic-offset: 4
3280  * indent-tabs-mode: nil
3281  * End:
3282  *
3283  */