murphyif: Free the connect timer when unloading
[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
180 typedef struct {
181     const char *name;
182     int value;
183 } const_def_t;
184
185 typedef struct {
186     const char *name;
187     const char *sign;
188     mrp_funcbridge_cfunc_t func;
189     void *data;
190 } funcbridge_def_t;
191
192 typedef enum {
193     NAME = 1,
194     TYPE,
195     ZONE,
196     CLASS,
197     INPUT,
198     LIMIT,
199     ROUTE,
200     ROLES,
201     TABLE,
202     ACCEPT,
203     MAXROW,
204     OUTPUT,
205     TABLES,
206     UPDATE,
207     COMPARE,
208     COLUMNS,
209     PRIVACY,
210     BINARIES,
211     CHANNELS,
212     LOCATION,
213     PRIORITY,
214     AVAILABLE,
215     CALCULATE,
216     CONDITION,
217     DIRECTION,
218     IMPLEMENT,
219     NODE_TYPE,
220     ATTRIBUTES,
221     AUTORELEASE,
222     DESCRIPTION,
223 } field_t;
224
225 static int  import_create(lua_State *);
226 static int  import_getfield(lua_State *);
227 static int  import_setfield(lua_State *);
228 static int  import_tostring(lua_State *);
229 static void import_destroy(void *);
230
231 static int  import_link(lua_State *);
232
233 static void import_data_changed(struct userdata *, const char *,
234                                 int, mrp_domctl_value_t **);
235 static bool update_bridge(lua_State *, void *, const char *,
236                           mrp_funcbridge_value_t *, char *,
237                           mrp_funcbridge_value_t *);
238
239 static void array_class_create(lua_State *);
240 static pa_value *array_create(lua_State *, int, mrp_lua_strarray_t *);
241 static int  array_getfield(lua_State *);
242 static int  array_setfield(lua_State *);
243 static int  array_getlength(lua_State *);
244
245 #if 0
246 static void array_destroy(void *);
247 #endif
248
249 static int  node_create(lua_State *);
250 static int  node_getfield(lua_State *);
251 static int  node_setfield(lua_State *);
252 static int  node_tostring(lua_State *);
253 static void node_destroy(void *);
254
255 static int  zone_create(lua_State *);
256 static int  zone_getfield(lua_State *);
257 static int  zone_setfield(lua_State *);
258 static void zone_destroy(void *);
259
260 static int  resource_create(lua_State *);
261 static int  resource_getfield(lua_State *);
262 static int  resource_setfield(lua_State *);
263 static void resource_destroy(void *);
264
265 static int  rtgroup_create(lua_State *);
266 static int  rtgroup_getfield(lua_State *);
267 static int  rtgroup_setfield(lua_State *);
268 static int  rtgroup_tostring(lua_State *);
269 static void rtgroup_destroy(void *);
270
271 static bool rtgroup_accept(struct userdata *, mir_rtgroup *, mir_node *);
272 static int  rtgroup_compare(struct userdata *, mir_rtgroup *,
273                             mir_node *, mir_node *);
274
275 static bool accept_bridge(lua_State *, void *, const char *,
276                           mrp_funcbridge_value_t *, char *,
277                           mrp_funcbridge_value_t *);
278 static bool compare_bridge(lua_State *, void *, const char *,
279                            mrp_funcbridge_value_t *, char *,
280                            mrp_funcbridge_value_t *);
281 static bool change_bridge(lua_State *, void *, const char *,
282                            mrp_funcbridge_value_t *, char *,
283                            mrp_funcbridge_value_t *);
284
285 static int  apclass_create(lua_State *);
286 static int  apclass_getfield(lua_State *);
287 static int  apclass_setfield(lua_State *);
288 static int  apclass_tostring(lua_State *);
289 static void apclass_destroy(void *);
290
291 static route_t *route_check(lua_State *, int);
292 static int route_push(lua_State *, route_t *);
293 static void route_destroy(route_t *);
294
295 static int  vollim_create(lua_State *);
296 static int  vollim_getfield(lua_State *);
297 static int  vollim_setfield(lua_State *);
298 static int  vollim_tostring(lua_State *);
299 static void vollim_destroy(void *);
300
301 static double vollim_calculate(struct userdata *, int, mir_node *, void *);
302 static bool calculate_bridge(lua_State *, void *, const char *,
303                              mrp_funcbridge_value_t *, char *,
304                              mrp_funcbridge_value_t *);
305
306 static limit_data_t *limit_data_check(lua_State *, int);
307
308 #if 0
309 static int limit_data_push(lua_State *, limit_data_t *);
310 #endif
311
312 static void limit_data_destroy(limit_data_t *);
313
314 static intarray_t *intarray_check(lua_State *, int, int, int);
315 static int intarray_push(lua_State *, intarray_t *);
316 static void intarray_destroy(intarray_t *);
317
318 static resource_name_t *resource_names_check(lua_State *, int);
319 static void resource_names_destroy(resource_name_t *);
320
321 static attribute_t *attributes_check(lua_State *, int);
322 static void attributes_destroy(attribute_t *);
323
324 static map_t *map_check(lua_State *, int);
325 static int map_push(lua_State *, map_t *);
326 static void map_destroy(map_t *);
327
328 static field_t field_check(lua_State *, int, const char **);
329 static field_t field_name_to_type(const char *, size_t);
330 static int make_id(char *buf, size_t len, const char *fmt, ...);
331
332 static void setup_murphy_interface(struct userdata *);
333 static char *comma_separated_list(mrp_lua_strarray_t *, char *, int);
334
335 static bool define_constants(lua_State *);
336 static bool register_methods(lua_State *);
337
338 static void *alloc(void *, void *, size_t, size_t);
339 static int panic(lua_State *);
340
341
342 MRP_LUA_METHOD_LIST_TABLE (
343     import_methods,           /* methodlist name */
344     MRP_LUA_METHOD_CONSTRUCTOR  (import_create)
345     MRP_LUA_METHOD        (link, import_link  )
346 );
347
348 MRP_LUA_METHOD_LIST_TABLE (
349     node_methods,             /* methodlist name */
350     MRP_LUA_METHOD_CONSTRUCTOR  (node_create)
351 );
352
353
354 MRP_LUA_METHOD_LIST_TABLE (
355     import_overrides,        /* methodlist_name */
356     MRP_LUA_OVERRIDE_CALL       (import_create)
357     MRP_LUA_OVERRIDE_GETFIELD   (import_getfield)
358     MRP_LUA_OVERRIDE_SETFIELD   (import_setfield)
359     MRP_LUA_OVERRIDE_STRINGIFY  (import_tostring)
360 );
361
362 MRP_LUA_METHOD_LIST_TABLE (
363     array_overrides,         /* methodlist_name */
364     MRP_LUA_OVERRIDE_GETFIELD   (array_getfield)
365     MRP_LUA_OVERRIDE_SETFIELD   (array_setfield)
366     MRP_LUA_OVERRIDE_GETLENGTH  (array_getlength)
367 );
368
369 MRP_LUA_METHOD_LIST_TABLE (
370     node_overrides,           /* methodlist name */
371     MRP_LUA_OVERRIDE_CALL       (node_create)
372     MRP_LUA_OVERRIDE_GETFIELD   (node_getfield)
373     MRP_LUA_OVERRIDE_SETFIELD   (node_setfield)
374     MRP_LUA_OVERRIDE_STRINGIFY  (node_tostring)
375 );
376
377
378 MRP_LUA_CLASS_DEF (
379    mdb,                         /* class name */
380    import,                      /* constructor name */
381    scripting_import,            /* userdata type */
382    import_destroy,              /* userdata destructor */
383    import_methods,              /* class methods */
384    import_overrides             /* override methods */
385 );
386
387 MRP_LUA_CLASS_DEF (
388    node,                        /* class name */
389    instance,                    /* constructor name */
390    scripting_node,              /* userdata type */
391    node_destroy,                /* userdata destructor */
392    node_methods,                /* class methods */
393    node_overrides               /* override methods */
394 );
395
396 MRP_LUA_CLASS_DEF_SIMPLE (
397    zone,                         /* class name */
398    scripting_zone,               /* userdata type */
399    zone_destroy,                 /* userdata destructor */
400    MRP_LUA_METHOD_LIST (         /* methods */
401       MRP_LUA_METHOD_CONSTRUCTOR  (zone_create)
402    ),
403    MRP_LUA_METHOD_LIST (         /* overrides */
404       MRP_LUA_OVERRIDE_CALL       (zone_create)
405       MRP_LUA_OVERRIDE_GETFIELD   (zone_getfield)
406       MRP_LUA_OVERRIDE_SETFIELD   (zone_setfield)
407    )
408 );
409
410 MRP_LUA_CLASS_DEF_SIMPLE (
411    audio_resource,               /* class name */
412    scripting_resource,           /* userdata type */
413    resource_destroy,             /* userdata destructor */
414    MRP_LUA_METHOD_LIST (         /* methods */
415       MRP_LUA_METHOD_CONSTRUCTOR  (resource_create)
416    ),
417    MRP_LUA_METHOD_LIST (         /* overrides */
418       MRP_LUA_OVERRIDE_CALL       (resource_create)
419       MRP_LUA_OVERRIDE_GETFIELD   (resource_getfield)
420       MRP_LUA_OVERRIDE_SETFIELD   (resource_setfield)
421    )
422 );
423
424 MRP_LUA_CLASS_DEF_SIMPLE (
425    routing_group,                /* class name */
426    scripting_rtgroup,            /* userdata type */
427    rtgroup_destroy,              /* userdata destructor */
428    MRP_LUA_METHOD_LIST (         /* methods */
429       MRP_LUA_METHOD_CONSTRUCTOR  (rtgroup_create)
430    ),
431    MRP_LUA_METHOD_LIST (         /* overrides */
432       MRP_LUA_OVERRIDE_CALL       (rtgroup_create)
433       MRP_LUA_OVERRIDE_GETFIELD   (rtgroup_getfield)
434       MRP_LUA_OVERRIDE_SETFIELD   (rtgroup_setfield)
435       MRP_LUA_OVERRIDE_STRINGIFY  (rtgroup_tostring)
436    )
437 );
438
439 MRP_LUA_CLASS_DEF_SIMPLE (
440    application_class,            /* class name */
441    scripting_apclass,            /* userdata type */
442    apclass_destroy,              /* userdata destructor */
443    MRP_LUA_METHOD_LIST (         /* methods */
444       MRP_LUA_METHOD_CONSTRUCTOR  (apclass_create)
445    ),
446    MRP_LUA_METHOD_LIST (        /* overrides */
447       MRP_LUA_OVERRIDE_CALL       (apclass_create)
448       MRP_LUA_OVERRIDE_GETFIELD   (apclass_getfield)
449       MRP_LUA_OVERRIDE_SETFIELD   (apclass_setfield)
450       MRP_LUA_OVERRIDE_STRINGIFY  (apclass_tostring)
451    )
452 );
453
454 MRP_LUA_CLASS_DEF_SIMPLE (
455    volume_limit,                 /* class name */
456    scripting_vollim,             /* userdata type */
457    vollim_destroy,               /* userdata destructor */
458    MRP_LUA_METHOD_LIST (         /* methods */
459       MRP_LUA_METHOD_CONSTRUCTOR  (vollim_create)
460    ),
461    MRP_LUA_METHOD_LIST (        /* overrides */
462       MRP_LUA_OVERRIDE_CALL       (vollim_create)
463       MRP_LUA_OVERRIDE_GETFIELD   (vollim_getfield)
464       MRP_LUA_OVERRIDE_SETFIELD   (vollim_setfield)
465       MRP_LUA_OVERRIDE_STRINGIFY  (vollim_tostring)
466    )
467 );
468
469
470 pa_scripting *pa_scripting_init(struct userdata *u)
471 {
472     pa_scripting *scripting;
473     lua_State *L;
474
475     pa_assert(u);
476
477     scripting = pa_xnew0(pa_scripting, 1);
478
479     if (!(L = lua_newstate(alloc, u)))
480         pa_log("failed to initialize Lua");
481     else {
482         lua_atpanic(L, &panic);
483         luaL_openlibs(L);
484
485         mrp_create_funcbridge_class(L);
486         mrp_lua_create_object_class(L, IMPORT_CLASS);
487         mrp_lua_create_object_class(L, NODE_CLASS);
488         mrp_lua_create_object_class(L, ZONE_CLASS);
489         mrp_lua_create_object_class(L, RESOURCE_CLASS);
490         mrp_lua_create_object_class(L, RTGROUP_CLASS);
491         mrp_lua_create_object_class(L, APPLICATION_CLASS);
492         mrp_lua_create_object_class(L, VOLLIM_CLASS);
493
494         array_class_create(L);
495
496         define_constants(L);
497         register_methods(L);
498
499         lua_pushlightuserdata(L, u);
500         lua_setglobal(L, USERDATA);
501
502         scripting->L = L;
503         scripting->configured = false;
504     }
505
506     return scripting;
507 }
508
509 void pa_scripting_done(struct userdata *u)
510 {
511     pa_scripting *scripting;
512
513     if (u && (scripting = u->scripting)) {
514         pa_xfree(scripting);
515         u->scripting = NULL;
516     }
517 }
518
519 bool pa_scripting_dofile(struct userdata *u, const char *file)
520 {
521     pa_scripting *scripting;
522     lua_State *L;
523     bool success;
524
525     pa_assert(u);
526     pa_assert(file);
527
528     pa_assert_se((scripting = u->scripting));
529     pa_assert_se((L = scripting->L));
530
531     if (luaL_loadfile(L, file) || lua_pcall(L, 0, 0, 0)) {
532         success = false;
533         pa_log("%s", lua_tostring(L, -1));
534         lua_pop(L, 1);
535     }
536     else {
537         success =true;
538         scripting->configured = true;
539         setup_murphy_interface(u);
540         pa_zoneset_update_module_property(u);
541     }
542
543     return success;
544 }
545
546 static int import_create(lua_State *L)
547 {
548     struct userdata *u;
549     pa_scripting *scripting;
550     size_t fldnamlen;
551     const char *fldnam;
552     scripting_import *imp;
553     const char *table = NULL;
554     mrp_lua_strarray_t *columns = NULL;
555     const char *condition = NULL;
556     int maxrow = 0;
557     mrp_funcbridge_t *update = NULL;
558     size_t maxcol;
559     pa_value **rows;
560     pa_value **cols;
561     int i,j;
562     int top;
563
564     MRP_LUA_ENTER;
565
566     top = lua_gettop(L);
567
568     lua_getglobal(L, USERDATA);
569     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
570         luaL_error(L, "missing or invalid global '" USERDATA "'");
571
572     pa_assert_se((scripting = u->scripting));
573
574     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
575
576         switch (field_name_to_type(fldnam, fldnamlen)) {
577         case TABLE:      table = luaL_checkstring(L, -1);                break;
578         case COLUMNS:    columns = mrp_lua_check_strarray(L, -1);        break;
579         case CONDITION:  condition = luaL_checkstring(L, -1);            break;
580         case MAXROW:     maxrow = luaL_checkint(L, -1);                  break;
581         case UPDATE:     update = mrp_funcbridge_create_luafunc(L, -1);  break;
582         default:         luaL_error(L, "bad field '%s'", fldnam);        break;
583         }
584
585     } /* MRP_LUA_FOREACH_FIELD */
586
587     lua_settop(L, top);
588
589     if (!table)
590         luaL_error(L, "missing table field");
591     if (!columns)
592         luaL_error(L, "missing columns field");
593     if (maxrow < 1 || maxrow >= MQI_QUERY_RESULT_MAX)
594         luaL_error(L, "missing or invalid maxrow field");
595     if (!update)
596         luaL_error(L, "missing update function");
597
598     maxcol = columns->nstring;
599
600     if (maxcol >= MQI_COLUMN_MAX)
601         luaL_error(L, "too many columns (max %d allowed)", MQI_COLUMN_MAX);
602
603     if (scripting->configured)
604         luaL_error(L, "refuse to import '%s' after configuration phase",table);
605
606     imp = (scripting_import *)mrp_lua_create_object(L, IMPORT_CLASS, table,0);
607
608     imp->userdata = u;
609     imp->table = pa_xstrdup(table);
610     imp->columns = columns;
611     imp->condition = condition;
612     imp->values = array_create(L, maxrow, NULL);
613     imp->update = update;
614
615     for (i = 0, rows = imp->values->array;  i < maxrow;   i++) {
616         cols = (rows[i] = array_create(L, maxcol, columns))->array;
617         lua_rawseti(L, -3, i+1); /* we add this to the import */
618         for (j = 0;  j < maxcol;  j++)
619             cols[j] = pa_xnew0(pa_value, 1);
620     }
621
622     lua_rawseti(L, -2, MQI_QUERY_RESULT_MAX);
623
624     MRP_LUA_LEAVE(1);
625 }
626
627 static int import_getfield(lua_State *L)
628 {
629     scripting_import *imp;
630     pa_value *values;
631     int colidx;
632     field_t fld;
633
634     MRP_LUA_ENTER;
635
636     if (!(imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1)))
637         lua_pushnil(L);
638     else {
639         pa_assert_se((values = imp->values));
640
641         if (lua_type(L, 2) == LUA_TNUMBER) {
642             colidx = lua_tointeger(L, 2);
643
644             if (colidx < 1 || colidx > -values->type)
645                 lua_pushnil(L);
646             else
647                 lua_rawgeti(L, 1, colidx);
648         }
649         else {
650             fld = field_check(L, 2, NULL);
651             lua_pop(L, 1);
652
653             switch (fld) {
654             case TABLE:       lua_pushstring(L, imp->table);             break;
655             case COLUMNS:     mrp_lua_push_strarray(L, imp->columns);    break;
656             case CONDITION:   lua_pushstring(L, imp->condition);         break;
657             case MAXROW:      lua_pushinteger(L, -imp->values->type);    break;
658             default:          lua_pushnil(L);                            break;
659             }
660         }
661     }
662
663     MRP_LUA_LEAVE(1);
664 }
665
666 static int import_setfield(lua_State *L)
667 {
668     const char *f;
669
670     MRP_LUA_ENTER;
671
672     f = luaL_checkstring(L, 2);
673     luaL_error(L, "attempt to set '%s' field of read-only mdb.import", f);
674
675     MRP_LUA_LEAVE(0);
676 }
677
678 static int import_tostring(lua_State *L)
679 {
680     scripting_import *imp;
681
682     MRP_LUA_ENTER;
683
684     imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
685
686     lua_pushstring(L, imp->table);
687
688     MRP_LUA_LEAVE(1);
689 }
690
691 static void import_destroy(void *data)
692 {
693     scripting_import *imp = (scripting_import *)data;
694
695     MRP_LUA_ENTER;
696
697     pa_xfree((void *)imp->table);
698     mrp_lua_free_strarray(imp->columns);
699     pa_xfree((void *)imp->condition);
700
701     MRP_LUA_LEAVE_NOARG;
702 }
703
704 static int import_link(lua_State *L)
705 {
706     scripting_import *imp;
707     mrp_lua_strarray_t *columns;
708     pa_value *values;
709     const char *colnam;
710     int rowidx;
711     size_t colidx;
712     pa_value *row;
713     pa_value *col;
714
715     MRP_LUA_ENTER;
716
717     imp = (scripting_import *)mrp_lua_check_object(L, IMPORT_CLASS, 1);
718     rowidx = luaL_checkint(L, 2) - 1;
719     colnam = luaL_checkstring(L, 3);
720
721     pa_assert(imp);
722     pa_assert_se((columns = imp->columns));
723
724     col = NULL;
725
726     if (rowidx >= 0 && rowidx < -imp->values->type) {
727         for (colidx = 0;   colidx < columns->nstring;   colidx++) {
728             if (!strcmp(colnam, columns->strings[colidx])) {
729                 pa_assert_se((values = imp->values));
730                 pa_assert_se((row = values->array[rowidx]));
731                 pa_assert(colidx < (size_t)-row->type);
732                 pa_assert_se((col = row->array[colidx]));
733                 break;
734             }
735         }
736     }
737
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->array));
793
794         maxrow = -ptval->type;
795         maxcol = 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->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->string);
818                     pcval->type = pa_value_string;
819                     pcval->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->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->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->floating = mcol->dbl;
835                     break;
836                 default:
837                     if (pcval->type == pa_value_string)
838                         pa_xfree((void *)pcval->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 *, dimension + 1);
915     value = lua_newuserdata(L, sizeof(pa_value));
916     value->type = -dimension;
917     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     size_t 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->array[dimension])) {
955             pa_assert(dimension == 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->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->string);   break;
979         case pa_value_integer:  lua_pushinteger(L, value->integer); break;
980         case pa_value_unsignd:  lua_pushinteger(L, value->unsignd); break;
981         case pa_value_floating: lua_pushnumber(L, 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->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, 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     mir_rtgroup *rtg;
1259     scripting_resource *res;
1260     resource_name_t *name = NULL;
1261     attribute_t *attributes = NULL;
1262     attribute_t *attr;
1263
1264     MRP_LUA_ENTER;
1265
1266     lua_getglobal(L, USERDATA);
1267     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1268         luaL_error(L, "missing or invalid global '" USERDATA "'");
1269     lua_pop(L, 1);
1270
1271
1272     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1273
1274         switch (field_name_to_type(fldnam, fldnamlen)) {
1275         case NAME:         name = resource_names_check(L, -1);       break;
1276         case ATTRIBUTES:   attributes = attributes_check(L, -1);     break;
1277         default:           luaL_error(L, "bad field '%s'", fldnam);  break;
1278         }
1279
1280     } /* MRP_LUA_FOREACH_FIELD */
1281
1282     if (!name)
1283         luaL_error(L, "missing or invalid name field");
1284
1285     pa_murphyif_add_audio_resource(u, mir_input,  name->playback);
1286     pa_murphyif_add_audio_resource(u, mir_output, name->recording);
1287
1288     if (attributes) {
1289         for (attr = attributes;   attr->prop && attr->def.name;   attr++) {
1290             switch (attr->def.type) {
1291             case mqi_string:
1292                 pa_murphyif_add_audio_attribute(u, attr->prop,
1293                                                 attr->def.name,
1294                                                 attr->def.type,
1295                                                 attr->def.value.string);
1296                 break;
1297             case mqi_integer:
1298                 pa_murphyif_add_audio_attribute(u, attr->prop,
1299                                                 attr->def.name,
1300                                                 attr->def.type,
1301                                                 attr->def.value.integer);
1302                 break;
1303             case mqi_unsignd:
1304                 pa_murphyif_add_audio_attribute(u, attr->prop,
1305                                                 attr->def.name,
1306                                                 attr->def.type,
1307                                                 attr->def.value.unsignd);
1308                 break;
1309             case mqi_floating:
1310                 pa_murphyif_add_audio_attribute(u, attr->prop,
1311                                                 attr->def.name,
1312                                                 attr->def.type,
1313                                                 attr->def.value.floating);
1314                 break;
1315             default:
1316                 luaL_error(L, "invalid audio resource attribute '%s'",
1317                            attr->def.name);
1318                 break;
1319             }
1320         }
1321     }
1322
1323     res = (scripting_resource *)mrp_lua_create_object(L, RTGROUP_CLASS,
1324                                                       "definition",0);
1325
1326     res->userdata = u;
1327     res->name = name;
1328     res->attributes = attributes;
1329
1330     MRP_LUA_LEAVE(1);
1331 }
1332
1333 static int resource_getfield(lua_State *L)
1334 {
1335     scripting_resource *res;
1336     field_t fld;
1337
1338     MRP_LUA_ENTER;
1339
1340     fld = field_check(L, 2, NULL);
1341     lua_pop(L, 1);
1342
1343     if (!(res = (scripting_resource*)mrp_lua_check_object(L,RESOURCE_CLASS,1)))
1344         lua_pushnil(L);
1345     else {
1346 #if 0
1347         switch (fld) {
1348         case NAME:           lua_pushstring(L, rtg->name);         break;
1349         case ATTRIBUTES:     lua_pushinteger(L, rtgs->type);       break;
1350         default:             lua_pushnil(L);                       break;
1351         }
1352 #else
1353         lua_pushnil(L);
1354 #endif
1355     }
1356
1357     MRP_LUA_LEAVE(1);
1358 }
1359
1360 static int resource_setfield(lua_State *L)
1361 {
1362     const char *f;
1363
1364     MRP_LUA_ENTER;
1365
1366     f = luaL_checkstring(L, 2);
1367     luaL_error(L, "attempt to set '%s' field of read-only resource_class", f);
1368
1369     MRP_LUA_LEAVE(0);
1370 }
1371
1372 static void resource_destroy(void *data)
1373 {
1374     scripting_resource *res = (scripting_resource *)data;
1375
1376     MRP_LUA_ENTER;
1377
1378     resource_names_destroy(res->name);
1379     attributes_destroy(res->attributes);
1380
1381     res->name = NULL;
1382     res->attributes = NULL;
1383
1384     MRP_LUA_LEAVE_NOARG;
1385 }
1386
1387
1388 static int rtgroup_create(lua_State *L)
1389 {
1390     struct userdata *u;
1391     size_t fldnamlen;
1392     const char *fldnam;
1393     mir_rtgroup *rtg;
1394     scripting_rtgroup *rtgs;
1395     const char *name = NULL;
1396     mir_direction type = 0;
1397     mrp_funcbridge_t *accept = NULL;
1398     mrp_funcbridge_t *compare = NULL;
1399     char id[256];
1400
1401     MRP_LUA_ENTER;
1402
1403     lua_getglobal(L, USERDATA);
1404     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1405         luaL_error(L, "missing or invalid global '" USERDATA "'");
1406     lua_pop(L, 1);
1407
1408
1409     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1410
1411         switch (field_name_to_type(fldnam, fldnamlen)) {
1412         case NAME:      name    = luaL_checkstring(L, -1);               break;
1413         case NODE_TYPE: type    = luaL_checkint(L, -1);                  break;
1414         case ACCEPT:    accept  = mrp_funcbridge_create_luafunc(L, -1);  break;
1415         case COMPARE:   compare = mrp_funcbridge_create_luafunc(L, -1);  break;
1416         default:        luaL_error(L, "bad field '%s'", fldnam);         break;
1417         }
1418
1419     } /* MRP_LUA_FOREACH_FIELD */
1420
1421     if (!name)
1422         luaL_error(L, "missing name field");
1423     if (type != mir_input && type != mir_output)
1424         luaL_error(L, "missing or invalid node_type");
1425     if (!accept)
1426         luaL_error(L, "missing or invalid accept field");
1427     if (!compare)
1428         luaL_error(L, "missing or invalid compare field");
1429
1430     make_id(id,sizeof(id), "%s_%sput", name, (type == mir_input) ? "in":"out");
1431
1432     rtgs = (scripting_rtgroup *)mrp_lua_create_object(L, RTGROUP_CLASS, id,0);
1433
1434     rtg  = mir_router_create_rtgroup(u, type, pa_xstrdup(name),
1435                                      rtgroup_accept, rtgroup_compare);
1436     if (!rtgs || !rtg)
1437         luaL_error(L, "failed to create routing group '%s'", id);
1438
1439     rtg->scripting = rtgs;
1440
1441     rtgs->userdata = u;
1442     rtgs->rtg = rtg;
1443     rtgs->type = type;
1444     rtgs->accept = accept;
1445     rtgs->compare = compare;
1446
1447     MRP_LUA_LEAVE(1);
1448 }
1449
1450 static int rtgroup_getfield(lua_State *L)
1451 {
1452     scripting_rtgroup *rtgs;
1453     mir_rtgroup *rtg;
1454     field_t fld;
1455
1456     MRP_LUA_ENTER;
1457
1458     fld = field_check(L, 2, NULL);
1459     lua_pop(L, 1);
1460
1461     if (!(rtgs = (scripting_rtgroup *)mrp_lua_check_object(L,RTGROUP_CLASS,1)))
1462         lua_pushnil(L);
1463     else {
1464         pa_assert_se((rtg = rtgs->rtg));
1465
1466         switch (fld) {
1467         case NAME:           lua_pushstring(L, rtg->name);         break;
1468         case NODE_TYPE:      lua_pushinteger(L, rtgs->type);       break;
1469         default:             lua_pushnil(L);                       break;
1470         }
1471     }
1472
1473     MRP_LUA_LEAVE(1);
1474 }
1475
1476 static int rtgroup_setfield(lua_State *L)
1477 {
1478     const char *f;
1479
1480     MRP_LUA_ENTER;
1481
1482     f = luaL_checkstring(L, 2);
1483     luaL_error(L, "attempt to set '%s' field of read-only routing_group", f);
1484
1485     MRP_LUA_LEAVE(0);
1486 }
1487
1488 static int rtgroup_tostring(lua_State *L)
1489 {
1490     scripting_rtgroup *rtgs;
1491     mir_rtgroup *rtg;
1492
1493     MRP_LUA_ENTER;
1494
1495     rtgs = (scripting_rtgroup *)mrp_lua_check_object(L, RTGROUP_CLASS, 1);
1496     pa_assert_se((rtg = rtgs->rtg));
1497
1498     lua_pushstring(L, rtg->name);
1499
1500     MRP_LUA_LEAVE(1);
1501 }
1502
1503 static void rtgroup_destroy(void *data)
1504 {
1505     scripting_rtgroup *rtgs = (scripting_rtgroup *)data;
1506     mir_rtgroup *rtg;
1507
1508     MRP_LUA_ENTER;
1509
1510     pa_assert_se((rtg = rtgs->rtg));
1511     pa_assert(rtgs == rtg->scripting);
1512
1513     rtg->scripting = NULL;
1514
1515     MRP_LUA_LEAVE_NOARG;
1516 }
1517
1518
1519 static bool rtgroup_accept(struct userdata *u,
1520                                 mir_rtgroup *rtg,
1521                                 mir_node *node)
1522 {
1523     pa_scripting *scripting;
1524     lua_State *L;
1525     scripting_rtgroup *rtgs;
1526     mrp_funcbridge_value_t  args[2];
1527     char rt;
1528     mrp_funcbridge_value_t  rv;
1529     bool accept;
1530
1531     pa_assert(u);
1532     pa_assert_se((scripting = u->scripting));
1533     pa_assert_se((L = scripting->L));
1534     pa_assert(rtg);
1535     pa_assert_se((rtgs = rtg->scripting));
1536     pa_assert(u == rtgs->userdata);
1537     pa_assert(rtgs->accept);
1538     pa_assert(node);
1539
1540     accept = false;
1541
1542     if ((rtgs = rtg->scripting) && node->scripting) {
1543
1544         args[0].pointer = rtgs;
1545         args[1].pointer = node->scripting;
1546
1547         if (!mrp_funcbridge_call_from_c(L, rtgs->accept, "oo",args, &rt,&rv)) {
1548             if (rt != MRP_FUNCBRIDGE_STRING)
1549                 pa_log("call to accept function failed");
1550             else {
1551                 pa_log("call to accept function failed: %s", rv.string);
1552                 mrp_free((void *)rv.string);
1553             }
1554         }
1555         else {
1556             if (rt != MRP_FUNCBRIDGE_BOOLEAN)
1557                 pa_log("accept function returned invalid type");
1558             else
1559                 accept = rv.boolean;
1560         }
1561     }
1562
1563     return accept;
1564 }
1565
1566 static int rtgroup_compare(struct userdata *u,
1567                            mir_rtgroup *rtg,
1568                            mir_node *node1,
1569                            mir_node *node2)
1570 {
1571     pa_scripting *scripting;
1572     lua_State *L;
1573     scripting_rtgroup *rtgs;
1574     mrp_funcbridge_value_t  args[3];
1575     char rt;
1576     mrp_funcbridge_value_t  rv;
1577     int result;
1578
1579     pa_assert(u);
1580     pa_assert_se((scripting = u->scripting));
1581     pa_assert_se((L = scripting->L));
1582     pa_assert(rtg);
1583     pa_assert_se((rtgs = rtg->scripting));
1584     pa_assert(u == rtgs->userdata);
1585     pa_assert(rtgs->compare);
1586     pa_assert(node1);
1587     pa_assert(node2);
1588
1589     result = -1;
1590
1591     if ((rtgs = rtg->scripting) && node1->scripting && node2->scripting) {
1592
1593         args[0].pointer = rtgs;
1594         args[1].pointer = node1->scripting;
1595         args[2].pointer = node2->scripting;
1596
1597         if (!mrp_funcbridge_call_from_c(L, rtgs->compare, "ooo",args, &rt,&rv))
1598             pa_log("failed to call compare function");
1599         else {
1600             if (rt != MRP_FUNCBRIDGE_FLOATING)
1601                 pa_log("compare function returned invalid type");
1602             else
1603                 result = rv.floating;
1604         }
1605     }
1606
1607     return result;
1608 }
1609
1610
1611 static bool accept_bridge(lua_State *L, void *data,
1612                           const char *signature, mrp_funcbridge_value_t *args,
1613                           char *ret_type, mrp_funcbridge_value_t *ret_val)
1614 {
1615     mir_rtgroup_accept_t accept;
1616     scripting_rtgroup *rtgs;
1617     scripting_node *ns;
1618     struct userdata *u;
1619     mir_rtgroup *rtg;
1620     mir_node *node;
1621     bool success;
1622
1623     (void)L;
1624
1625     pa_assert(signature);
1626     pa_assert(args);
1627     pa_assert(ret_type);
1628     pa_assert(ret_val);
1629
1630     pa_assert_se((accept = (mir_rtgroup_accept_t)data));
1631
1632     if (strcmp(signature, "oo"))
1633         success = false;
1634     else {
1635         pa_assert_se((rtgs = args[0].pointer));
1636         pa_assert_se((u = rtgs->userdata));
1637         pa_assert_se((ns = args[1].pointer));
1638
1639         if (!(rtg = rtgs->rtg) || !(node = ns->node))
1640             success = false;
1641         else {
1642             success = true;
1643             *ret_type = MRP_FUNCBRIDGE_BOOLEAN;
1644             ret_val->boolean = accept(u, rtg, node);
1645         }
1646     }
1647
1648     return success;
1649 }
1650
1651
1652 static bool compare_bridge(lua_State *L, void *data,
1653                            const char *signature, mrp_funcbridge_value_t *args,
1654                            char *ret_type, mrp_funcbridge_value_t *ret_val)
1655 {
1656     mir_rtgroup_compare_t compare;
1657     scripting_rtgroup *rtgs;
1658     scripting_node *ns1, *ns2;
1659     struct userdata *u;
1660     mir_rtgroup *rtg;
1661     mir_node *node1, *node2;
1662     bool success;
1663
1664     (void)L;
1665
1666     pa_assert(signature);
1667     pa_assert(args);
1668     pa_assert(ret_type);
1669     pa_assert(ret_val);
1670
1671     pa_assert_se((compare = (mir_rtgroup_compare_t)data));
1672
1673     if (strcmp(signature, "ooo"))
1674         success = false;
1675     else {
1676         pa_assert_se((rtgs = args[0].pointer));
1677         pa_assert_se((u = rtgs->userdata));
1678         pa_assert_se((ns1 = args[1].pointer));
1679         pa_assert_se((ns2 = args[2].pointer));
1680
1681
1682         if (!(rtg = rtgs->rtg) || !(node1 = ns1->node) || !(node2 = ns2->node))
1683             success = false;
1684         else {
1685             success = true;
1686             *ret_type = MRP_FUNCBRIDGE_FLOATING;
1687             ret_val->floating = compare(u, rtg, node1, node2);
1688         }
1689     }
1690
1691     return success;
1692 }
1693
1694
1695 static bool change_bridge(lua_State *L, void *data,
1696                           const char *signature, mrp_funcbridge_value_t *args,
1697                           char *ret_type, mrp_funcbridge_value_t *ret_val)
1698 {
1699     mir_change_value_t change;
1700     scripting_import *imp;
1701     struct userdata *u;
1702     bool success;
1703     const char *s = "default";
1704
1705     (void)L;
1706
1707     pa_assert(signature);
1708     pa_assert(args);
1709     pa_assert(ret_type);
1710     pa_assert(ret_val);
1711
1712     pa_assert_se((change = (mir_change_value_t)data));
1713
1714     if (strcmp(signature, "o"))
1715         success = false;
1716     else {
1717         pa_assert_se((imp = args[0].pointer));
1718         pa_assert_se((u = imp->userdata));
1719
1720         /* FIXME: is this how it is supposed to be done?! */
1721
1722         if (imp->values && imp->values->array && imp->values->array[0] &&
1723               imp->values->array[0]->array &&
1724               imp->values->array[0]->array[0] &&
1725               imp->values->array[0]->array[0]->type == pa_value_string)
1726             pa_assert_se((s = imp->values->array[0]->array[0]->string));
1727
1728         success = true;
1729         *ret_type = MRP_FUNCBRIDGE_NO_DATA;
1730         memset(ret_val, 0, sizeof(mrp_funcbridge_value_t));
1731         change(u, s);
1732     }
1733
1734     return success;
1735 }
1736
1737
1738 static int apclass_create(lua_State *L)
1739 {
1740     struct userdata *u;
1741     size_t fldnamlen;
1742     const char *fldnam;
1743     scripting_apclass *ac;
1744     char name[256];
1745     const char *class = NULL;
1746     mir_node_type type = -1;
1747     int priority = -1;
1748     route_t *route = NULL;
1749     map_t *roles = NULL;
1750     map_t *binaries = NULL;
1751     bool needs_resource = false;
1752     pa_nodeset_resdef *resdef;
1753     map_t *r, *b;
1754     size_t i;
1755     const char *n;
1756     bool ir, or;
1757
1758     MRP_LUA_ENTER;
1759
1760     lua_getglobal(L, USERDATA);
1761     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
1762         luaL_error(L, "missing or invalid global '" USERDATA "'");
1763     lua_pop(L, 1);
1764
1765
1766     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1767
1768         switch (field_name_to_type(fldnam, fldnamlen)) {
1769         case CLASS:       class = luaL_checkstring(L, -1);             break;
1770         case NODE_TYPE:   type = luaL_checkint(L, -1);                 break;
1771         case PRIORITY:    priority = luaL_checkint(L, -1);             break;
1772         case ROUTE:       route = route_check(L, -1);                  break;
1773         case ROLES:       roles = map_check(L, -1);                    break;
1774         case BINARIES:    binaries = map_check(L, -1);                 break;
1775         default:          luaL_error(L, "bad field '%s'", fldnam);     break;
1776         }
1777
1778     } /* MRP_LUA_FOREACH_FIELD */
1779
1780     if (type < mir_application_class_begin ||
1781         type >= mir_application_class_end    )
1782         luaL_error(L, "missing or invalid node_type %d", type);
1783     if (priority < 0)
1784         luaL_error(L, "missing or invalid priority field");
1785     if (!route)
1786         luaL_error(L, "missing or invalid route field");
1787     if (!roles && !binaries)
1788         luaL_error(L, "missing roles or binaries");
1789
1790     make_id(name, sizeof(name), "%s", mir_node_type_str(type));
1791
1792     mir_router_assign_class_priority(u, type, priority);
1793
1794     ir = or = true;
1795
1796     if (route->input) {
1797         for (i = 0;  i < MRP_ZONE_MAX;  i++) {
1798             if ((n = route->input[i]))
1799                 ir &= mir_router_assign_class_to_rtgroup(u,type,i,mir_input,n);
1800         }
1801     }
1802
1803     if (route->output) {
1804         for (i = 0;  i < MRP_ZONE_MAX;  i++) {
1805             if ((n = route->output[i]))
1806                 or &= mir_router_assign_class_to_rtgroup(u,type,i,mir_output,n);
1807         }
1808     }
1809
1810     ac = (scripting_apclass *)mrp_lua_create_object(L, APPLICATION_CLASS,
1811                                                     name, 0);
1812
1813     if (!ir || !or || !ac)
1814         luaL_error(L, "failed to create application class '%s'", name);
1815
1816     ac->userdata = u;
1817     ac->name = pa_xstrdup(name);
1818     ac->class = class ? pa_xstrdup(class) : NULL;
1819     ac->type = type;
1820     ac->priority = priority;
1821     ac->route = route;
1822     ac->roles = roles;
1823     ac->binaries = binaries;
1824
1825     if (class) {
1826         if (pa_nodeset_add_class(u, type, class)) {
1827             luaL_error(L, "node type '%s' is defined multiple times",
1828                        mir_node_type_str(type));
1829         }
1830     }
1831
1832     if (roles) {
1833         for (r = roles;  r->name;  r++) {
1834             resdef = r->needres ? &r->resource : NULL;
1835
1836             if (r->role && strcmp(r->role, r->name)) {
1837                 luaL_error(L, "conflicting roles in role definition '%s' (%s)",
1838                            r->name, r->role);
1839             }
1840
1841             if (pa_nodeset_add_role(u, r->name, type, resdef)) {
1842                 luaL_error(L, "role '%s' is added to mutiple application "
1843                            "classes", r->name);
1844             }
1845         }
1846     }
1847
1848     if (binaries) {
1849         for (b = binaries;  b->name;  b++) {
1850             resdef = b->needres ? &b->resource : NULL;
1851
1852             if (pa_nodeset_add_binary(u, b->name, type, b->role, resdef)) {
1853                 luaL_error(L, "binary '%s' is added to multiple application "
1854                            "classes", b->name);
1855             }
1856         }
1857     }
1858
1859     MRP_LUA_LEAVE(1);
1860 }
1861
1862 static int apclass_getfield(lua_State *L)
1863 {
1864     scripting_apclass *ac;
1865     field_t fld;
1866
1867     MRP_LUA_ENTER;
1868
1869     fld = field_check(L, 2, NULL);
1870     lua_pop(L, 1);
1871
1872     if (!(ac=(scripting_apclass *)mrp_lua_check_object(L,APPLICATION_CLASS,1)))
1873         lua_pushnil(L);
1874     else {
1875         switch (fld) {
1876         case NAME:           lua_pushstring(L, ac->name);          break;
1877         case NODE_TYPE:      lua_pushinteger(L, ac->type);         break;
1878         case PRIORITY:       lua_pushinteger(L, ac->priority);     break;
1879         case ROUTE:          route_push(L, ac->route);             break;
1880         case ROLES:          map_push(L, ac->roles);               break;
1881         case BINARIES:       map_push(L, ac->binaries);            break;
1882         default:             lua_pushnil(L);                       break;
1883         }
1884     }
1885
1886     MRP_LUA_LEAVE(1);
1887 }
1888
1889 static int apclass_setfield(lua_State *L)
1890 {
1891     const char *f;
1892
1893     MRP_LUA_ENTER;
1894
1895     f = luaL_checkstring(L, 2);
1896     luaL_error(L,"attempt to set '%s' field of read-only application class",f);
1897
1898     MRP_LUA_LEAVE(0);
1899 }
1900
1901 static int apclass_tostring(lua_State *L)
1902 {
1903     scripting_apclass *ac;
1904
1905     MRP_LUA_ENTER;
1906
1907     ac = (scripting_apclass *)mrp_lua_check_object(L, APPLICATION_CLASS, 1);
1908
1909     lua_pushstring(L, ac->name);
1910
1911     MRP_LUA_LEAVE(1);
1912 }
1913
1914 static void apclass_destroy(void *data)
1915 {
1916     scripting_apclass *ac = (scripting_apclass *)data;
1917     struct userdata *u;
1918     map_t *r, *b;
1919     size_t i;
1920
1921     MRP_LUA_ENTER;
1922
1923     pa_assert(ac);
1924     pa_assert_se((u = ac->userdata));
1925
1926     route_destroy(ac->route);
1927     ac->route = NULL;
1928
1929     pa_xfree((void *)ac->name);
1930     ac->name = NULL;
1931
1932     pa_nodeset_delete_class(u, ac->type);
1933     pa_xfree((void *)ac->class);
1934     ac->class = NULL;
1935
1936     if (ac->roles) {
1937         for (r = ac->roles;  r->name;  r++)
1938             pa_nodeset_delete_role(u, r->name);
1939
1940         map_destroy(ac->roles);
1941         ac->roles = NULL;
1942     }
1943
1944     if (ac->binaries) {
1945         for (b = ac->binaries;  b->name;  b++)
1946             pa_nodeset_delete_binary(u, b->name);
1947
1948         map_destroy(ac->binaries);
1949         ac->binaries = NULL;
1950     }
1951
1952     MRP_LUA_LEAVE_NOARG;
1953 }
1954
1955 static const char **route_definition_check(lua_State *L, int idx)
1956 {
1957     size_t zonelen;
1958     const char *zonenam;
1959     scripting_zone *zone;
1960     scripting_rtgroup *rtgs;
1961     mir_rtgroup *rtg;
1962     const char **defs;
1963     const char *rtgnam;
1964     int ndef;
1965
1966     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
1967
1968     luaL_checktype(L, idx, LUA_TTABLE);
1969
1970     defs = pa_xnew0(const char *, MRP_ZONE_MAX);
1971     ndef = 0;
1972
1973     MRP_LUA_FOREACH_FIELD(L, idx, zonenam, zonelen) {
1974         if (!zonenam[0])
1975             luaL_error(L, "invalid route definition");
1976
1977         mrp_lua_find_object(L, ZONE_CLASS, zonenam);
1978
1979         if (!(zone = mrp_lua_check_object(L, NULL, -1)))
1980             luaL_error(L, "can't find zone '%s'", zonenam);
1981
1982         lua_pop(L, 1);
1983
1984         if (zone->index >= MRP_ZONE_MAX)
1985             luaL_error(L, "Internal error: zone index overflow");
1986
1987         switch (lua_type(L, -1)) {
1988         case LUA_TSTRING:
1989             rtgnam = lua_tostring(L, -1);
1990             break;
1991         case LUA_TTABLE:
1992             rtgs = (scripting_rtgroup*)mrp_lua_check_object(L,RTGROUP_CLASS,-1);
1993             if (!rtgs || !(rtg = rtgs->rtg))
1994                 rtgnam = NULL;
1995             else
1996                 rtgnam = rtg->name;
1997             break;
1998         default:
1999             rtgnam = NULL;
2000             break;
2001         }
2002
2003         if (!rtgnam)
2004             luaL_error(L, "missing or invalid routing group");
2005
2006         defs[zone->index] = pa_xstrdup(rtgnam);
2007         ndef++;
2008     }
2009
2010     if (!ndef)
2011         luaL_error(L, "empty definition");
2012
2013     return defs;
2014 }
2015
2016 static int route_definition_push(lua_State *L, const char **defs)
2017 {
2018     int i;
2019
2020     lua_createtable(L, MRP_ZONE_MAX, 0);
2021
2022     for (i = 0;  i < MRP_ZONE_MAX;  i++) {
2023     }
2024
2025     return 1;
2026 }
2027
2028
2029 static void route_definition_free(const char **defs)
2030 {
2031     int i;
2032
2033     if (defs) {
2034         for (i = 0;  i < MRP_ZONE_MAX;  i++)
2035             pa_xfree((void *)defs[i]);
2036         pa_xfree((void *)defs);
2037     }
2038 }
2039
2040
2041 static route_t *route_check(lua_State *L, int idx)
2042 {
2043     size_t fldnamlen;
2044     const char *fldnam;
2045     route_t *rt;
2046     const char **input = NULL;
2047     const char **output = NULL;
2048
2049     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2050
2051     luaL_checktype(L, idx, LUA_TTABLE);
2052
2053     MRP_LUA_FOREACH_FIELD(L, idx, fldnam, fldnamlen) {
2054         switch (field_name_to_type(fldnam, fldnamlen)) {
2055         case        INPUT:  input  = route_definition_check(L, -1);      break;
2056         case        OUTPUT: output = route_definition_check(L, -1);      break;
2057         default:    luaL_error(L, "invalid field '%s'", fldnam);         break;
2058         }
2059     } /* MRP_LUA_FOREACH_FIELD */
2060
2061     if (!input && !output)
2062         luaL_error(L, "neither input nor output routing group were specified");
2063
2064     rt = pa_xmalloc(sizeof(route_t));
2065     rt->input  = input;
2066     rt->output = output;
2067
2068     return rt;
2069 }
2070
2071 static int route_push(lua_State *L, route_t *rt)
2072 {
2073     if (!rt || (!rt->input && !rt->output))
2074         lua_pushnil(L);
2075     else {
2076         lua_createtable(L, 0, 2);
2077
2078         if (rt->input) {
2079             lua_pushstring(L, "input");
2080             route_definition_push(L, rt->input);
2081             lua_settable(L, -3);
2082         }
2083
2084         if (rt->output) {
2085             lua_pushstring(L, "output");
2086             route_definition_push(L, rt->output);
2087             lua_settable(L, -3);
2088         }
2089     }
2090
2091     return 1;
2092 }
2093
2094 static void route_destroy(route_t *rt)
2095 {
2096     if (rt) {
2097         pa_xfree((void *)rt->input);
2098         pa_xfree((void *)rt->output);
2099         pa_xfree((void *)rt);
2100     }
2101 }
2102
2103
2104 static int vollim_create(lua_State *L)
2105 {
2106     static int min = mir_application_class_begin;
2107     static int max = mir_application_class_end;
2108
2109     struct userdata *u;
2110     size_t fldnamlen;
2111     const char *fldnam;
2112     scripting_vollim *vlim;
2113     const char *name = NULL;
2114     vollim_type type = 0;
2115     limit_data_t *limit = NULL;
2116     mrp_funcbridge_t *calculate = NULL;
2117     intarray_t *classes = NULL;
2118     bool suppress = false;
2119     bool correct = false;
2120     size_t arglgh = 0;
2121     size_t i;
2122     int class;
2123     uint32_t mask, clmask;
2124     char id[256];
2125
2126     MRP_LUA_ENTER;
2127
2128     lua_getglobal(L, USERDATA);
2129     if (!lua_islightuserdata(L, -1) || !(u = lua_touserdata(L, -1)))
2130         luaL_error(L, "missing or invalid global '" USERDATA "'");
2131     lua_pop(L, 1);
2132
2133
2134     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
2135
2136         switch (field_name_to_type(fldnam, fldnamlen)) {
2137         case NAME:      name      = luaL_checkstring(L, -1);             break;
2138         case TYPE:      type      = luaL_checkint(L, -1);                break;
2139         case NODE_TYPE: classes = intarray_check(L, -1, min, max);       break;
2140         case LIMIT:     limit     = limit_data_check(L, -1);             break;
2141         case CALCULATE: calculate = mrp_funcbridge_create_luafunc(L,-1); break;
2142         default:        luaL_error(L, "bad field '%s'", fldnam);         break;
2143         }
2144
2145     } /* MRP_LUA_FOREACH_FIELD */
2146
2147     if (!name)
2148         luaL_error(L, "missing name field");
2149     if (type != vollim_class && type != vollim_generic && type != vollim_maximum)
2150         luaL_error(L, "missing or invalid type");
2151     if ((type == vollim_class || type == vollim_maximum) && !classes)
2152         luaL_error(L, "missing or invalid node_type for class/maximum limit");
2153     if (type == vollim_generic && classes)
2154         luaL_error(L, "can't specify node_type for generic volume limit");
2155     if (!limit)
2156         luaL_error(L, "missing or invalid limit");
2157     if (type != vollim_maximum && !calculate)
2158         luaL_error(L, "missing calculate field");
2159     if (type != vollim_maximum) {
2160         if (calculate->type == MRP_C_FUNCTION) {
2161             if (strcmp(calculate->c.signature, "odo"))
2162                 luaL_error(L,"invalid calculate field (mismatching signature)");
2163             if (calculate->c.data == mir_volume_suppress) {
2164                 if (type != vollim_class)
2165                     luaL_error(L, "attempt to make generic volume supression");
2166                 suppress = true;
2167                 arglgh = sizeof(mir_volume_suppress_arg);
2168             }
2169             else if (calculate->c.data == mir_volume_correction) {
2170                 if (type != vollim_generic) {
2171                     luaL_error(L, "attempt to make class based volume"
2172                                "correction");
2173                 }
2174                 correct = true;
2175                 arglgh = sizeof(double *);
2176             }
2177             else {
2178                 luaL_error(L, "invalid builtin.method for calculate");
2179             }
2180         }
2181         else {
2182             switch (type) {
2183             case vollim_class:
2184                 suppress = true;
2185                 arglgh = sizeof(mir_volume_suppress_arg);
2186                 break;
2187             case vollim_generic:
2188                 correct = true;
2189                 arglgh = sizeof(double *);
2190                 break;
2191             default:
2192                 break;
2193             }
2194         }
2195     }
2196
2197     make_id(id, sizeof(id), "%s", name);
2198
2199     (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim) + arglgh;
2200     vlim = (scripting_vollim *)mrp_lua_create_object(L, VOLLIM_CLASS, id,0);
2201     (VOLLIM_CLASS)->userdata_size = sizeof(scripting_vollim);
2202
2203     vlim->userdata = u;
2204     vlim->name = pa_xstrdup(name);
2205     vlim->type = type;
2206     vlim->classes = classes;
2207     vlim->limit = limit;
2208     vlim->calculate = calculate;
2209
2210     if (suppress) {
2211         mir_volume_suppress_arg *args = (mir_volume_suppress_arg *)vlim->args;
2212         size_t size = sizeof(int) * classes->nint;
2213         size_t n = mir_application_class_end - mir_application_class_begin;
2214
2215         for (i = 0, clmask = 0;   i < classes->nint;   i++) {
2216             class = classes->ints[i];
2217
2218             if (class <= mir_application_class_begin ||
2219                 class >  mir_application_class_end     )
2220             {
2221                 pa_log("invalid triggering class id %d", class);
2222                 clmask = 0;
2223                 classes->nint = n = 0;
2224                 break;
2225             }
2226
2227             mask = ((uint32_t)1) << (class - mir_application_class_begin);
2228
2229             if (!(clmask & mask) && n > 0)
2230                 n--;
2231
2232             clmask |= mask;
2233         }
2234
2235         args->attenuation = limit->value;
2236         args->trigger.nclass = classes->nint;
2237         args->trigger.classes = pa_xmalloc(size);
2238         args->trigger.clmask = clmask;
2239
2240         memcpy(args->trigger.classes, classes->ints, size);
2241
2242         if (n > classes->nint)
2243             classes->ints = pa_xrealloc(classes->ints, sizeof(int) * n);
2244         classes->nint = n;
2245
2246         for (i = mir_application_class_begin, n = 0;
2247              i < mir_application_class_end;
2248              i++)
2249         {
2250             if (!(clmask & (((uint32_t)1) << (i-mir_application_class_begin))))
2251                 classes->ints[n++] = i;
2252         }
2253     }
2254     else if (correct) {
2255         /* *(double **)vlim->args = limit->value; */
2256
2257         memcpy(vlim->args, &limit->value, sizeof(limit->value));
2258     }
2259
2260     switch (type) {
2261     case vollim_generic:
2262         mir_volume_add_generic_limit(u, vollim_calculate, vlim->args);
2263         break;
2264     case vollim_class:
2265         for (i = 0;  i < classes->nint;  i++) {
2266             mir_volume_add_class_limit(u, classes->ints[i], vollim_calculate,
2267                                        vlim->args);
2268         }
2269         break;
2270     case vollim_maximum:
2271         mir_volume_add_maximum_limit(u, *(vlim->limit->value),
2272                                      classes->nint, classes->ints);
2273         break;
2274     default:
2275         break;
2276     }
2277
2278     MRP_LUA_LEAVE(1);
2279 }
2280
2281 static int vollim_getfield(lua_State *L)
2282 {
2283     scripting_vollim *vlim;
2284     field_t fld;
2285
2286     MRP_LUA_ENTER;
2287
2288     fld = field_check(L, 2, NULL);
2289     lua_pop(L, 1);
2290
2291     if (!(vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1)))
2292         lua_pushnil(L);
2293     else {
2294         switch (fld) {
2295         case NAME:         lua_pushstring(L, vlim->name);           break;
2296         case TYPE:         lua_pushinteger(L, vlim->type);          break;
2297         case NODE_TYPE:    intarray_push(L, vlim->classes);         break;
2298         case LIMIT:        lua_pushnumber(L, *vlim->limit->value);  break;
2299         default:           lua_pushnil(L);                          break;
2300         }
2301     }
2302
2303     MRP_LUA_LEAVE(1);
2304 }
2305
2306 static int vollim_setfield(lua_State *L)
2307 {
2308     const char *f;
2309
2310     MRP_LUA_ENTER;
2311
2312     f = luaL_checkstring(L, 2);
2313     luaL_error(L, "attempt to set '%s' field of read-only volume_limit", f);
2314
2315     MRP_LUA_LEAVE(0);
2316 }
2317
2318 static int vollim_tostring(lua_State *L)
2319 {
2320     scripting_vollim *vlim;
2321
2322     MRP_LUA_ENTER;
2323
2324     vlim = (scripting_vollim *)mrp_lua_check_object(L, VOLLIM_CLASS, 1);
2325
2326     lua_pushstring(L, vlim->name);
2327
2328     MRP_LUA_LEAVE(1);
2329 }
2330
2331 static void vollim_destroy(void *data)
2332 {
2333     scripting_vollim *vlim = (scripting_vollim *)data;
2334
2335     MRP_LUA_ENTER;
2336
2337     pa_xfree((void *)vlim->name);
2338     intarray_destroy(vlim->classes);
2339     limit_data_destroy(vlim->limit);
2340
2341     MRP_LUA_LEAVE_NOARG;
2342 }
2343
2344
2345 static double vollim_calculate(struct userdata *u, int class, mir_node *node,
2346                                void *data)
2347 {
2348     static int offset = ((scripting_vollim *)0)->args - (char *)0;
2349
2350     pa_scripting *scripting;
2351     lua_State *L;
2352     scripting_vollim *vlim;
2353     mrp_funcbridge_value_t args[3];
2354     char rt;
2355     mrp_funcbridge_value_t  rv;
2356     double limit;
2357
2358     pa_assert(u);
2359     pa_assert_se((scripting = u->scripting));
2360     pa_assert_se((L = scripting->L));
2361     pa_assert(!class || (class >= mir_application_class_begin &&
2362                          class <  mir_application_class_end)     );
2363     pa_assert(node);
2364
2365     vlim = (scripting_vollim *)(data - offset);
2366
2367     pa_assert(u == vlim->userdata);
2368
2369     limit = -90.0;
2370
2371     if (node->scripting) {
2372
2373         args[0].pointer = vlim;
2374         args[1].integer = class;
2375         args[2].pointer = node->scripting;
2376
2377         if (!mrp_funcbridge_call_from_c(L,vlim->calculate,"odo",args,&rt,&rv))
2378             pa_log("failed to call calculate function");
2379         else {
2380             if (rt != MRP_FUNCBRIDGE_FLOATING)
2381                 pa_log("accept function returned invalid type");
2382             else
2383                 limit = rv.floating;
2384         }
2385     }
2386
2387     return limit;
2388 }
2389
2390 static bool calculate_bridge(lua_State *L, void *data, const char *signature,
2391                              mrp_funcbridge_value_t *args,
2392                              char *ret_type, mrp_funcbridge_value_t *ret_val)
2393 {
2394     mir_volume_func_t calculate;
2395     scripting_vollim *vlim;
2396     scripting_node *ns;
2397     struct userdata *u;
2398     int class;
2399     mir_node *node;
2400     bool success;
2401
2402     (void)L;
2403
2404     pa_assert(signature);
2405     pa_assert(args);
2406     pa_assert(ret_type);
2407     pa_assert(ret_val);
2408
2409     pa_assert_se((calculate = (mir_volume_func_t)data));
2410
2411     if (strcmp(signature, "odo"))
2412         success = false;
2413     else {
2414         pa_assert_se((vlim = args[0].pointer));
2415         pa_assert_se((u = vlim->userdata));
2416         pa_assert_se((ns = args[2].pointer));
2417
2418         class = args[1].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, 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;
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->floating;
2462         }
2463         break;
2464     default:
2465         ld->mallocd = false;
2466         ld->value = &nolimit;
2467         break;
2468     }
2469
2470     return ld;
2471 }
2472
2473 #if 0
2474 static int limit_data_push(lua_State *L, limit_data_t *ld)
2475 {
2476     if (ld)
2477         lua_pushnumber(L, *ld->value);
2478     else
2479         lua_pushnil;
2480
2481     return 1;
2482 }
2483 #endif
2484
2485 static void limit_data_destroy(limit_data_t *ld)
2486 {
2487     if (ld) {
2488         if (ld->mallocd)
2489             pa_xfree(ld->value);
2490         pa_xfree(ld);
2491     }
2492 }
2493
2494
2495 static intarray_t *intarray_check(lua_State *L, int idx, int min, int max)
2496 {
2497     size_t len;
2498     size_t size;
2499     intarray_t *arr;
2500     int val;
2501     size_t i;
2502
2503     idx = (idx < 0) ? lua_gettop(L) + idx + 1 : idx;
2504
2505     luaL_checktype(L, idx, LUA_TTABLE);
2506
2507     if ((len = luaL_getn(L, idx)) < 1)
2508         arr = NULL;
2509     else {
2510         size = sizeof(intarray_t) + sizeof(int) * len;
2511         arr  = pa_xmalloc0(sizeof(intarray_t));
2512
2513         arr->nint = len;
2514         arr->ints = pa_xmalloc0(size);
2515
2516         for (i = 0;  i < len;  i++) {
2517             lua_pushnumber(L, (int)(i+1));
2518             lua_gettable(L, idx);
2519
2520             val = luaL_checkint(L, -1);
2521
2522             lua_pop(L, 1);
2523
2524             if (val < min || val >= max)
2525                 luaL_error(L, "array [%u]: out of range value (%d)", i, val);
2526
2527             arr->ints[i] = val;
2528         }
2529     }
2530
2531     return arr;
2532 }
2533
2534 static int intarray_push(lua_State *L, intarray_t *arr)
2535 {
2536     size_t i;
2537
2538     if (!arr)
2539         lua_pushnil(L);
2540     else {
2541         lua_createtable(L, arr->nint, 0);
2542
2543         for (i = 0;  i < arr->nint;  i++) {
2544             lua_pushinteger(L, (int)(i+1));
2545             lua_pushinteger(L, arr->ints[i]);
2546             lua_settable(L, -3);
2547         }
2548     }
2549
2550     return 1;
2551 }
2552
2553 static void intarray_destroy(intarray_t *arr)
2554 {
2555     if (arr) {
2556         pa_xfree(arr->ints);
2557         pa_xfree(arr);
2558     }
2559 }
2560
2561 static resource_name_t *resource_names_check(lua_State *L, int tbl)
2562 {
2563     resource_name_t *name;
2564     size_t fldnamlen;
2565     const char *fldnam;
2566     const char *value;
2567
2568     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2569
2570     luaL_checktype(L, tbl, LUA_TTABLE);
2571
2572     name = pa_xnew0(resource_name_t, 1);
2573
2574     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2575         value = luaL_checkstring(L, -1);
2576
2577         if (!strcmp(fldnam, "recording"))
2578             name->recording = pa_xstrdup(value);
2579         else if (!strcmp(fldnam, "playback"))
2580             name->playback = pa_xstrdup(value);
2581         else {
2582             luaL_error(L, "invalid field '%s' in resource name definition",
2583                        fldnam);
2584         }
2585     }
2586
2587     return name;
2588 }
2589
2590 static void resource_names_destroy(resource_name_t *name)
2591 {
2592     if (name) {
2593         pa_xfree((void *)name->recording);
2594         pa_xfree((void *)name->playback);
2595         pa_xfree(name);
2596     }
2597 }
2598
2599 static attribute_t *attributes_check(lua_State *L, int tbl)
2600 {
2601     int def;
2602     size_t fldnamlen;
2603     const char *fldnam;
2604     attribute_t *attr, *attrs = NULL;
2605     size_t nattr = 0;
2606     mrp_attr_value_t *v;
2607     size_t i, len;
2608
2609     tbl = (tbl < 0) ? lua_gettop(L) + tbl + 1 : tbl;
2610
2611     luaL_checktype(L, tbl, LUA_TTABLE);
2612
2613     MRP_LUA_FOREACH_FIELD(L, tbl, fldnam, fldnamlen) {
2614         if (!fldnam[0])
2615             luaL_error(L, "invalid attribute definition");
2616
2617         attrs = pa_xrealloc(attrs, sizeof(attribute_t) * (nattr + 2));
2618         memset(attrs + nattr, 0, sizeof(attribute_t) * 2);
2619
2620         attr = attrs + nattr++;
2621         v = &attr->def.value;
2622         def = lua_gettop(L);
2623
2624         attr->def.name = pa_xstrdup(fldnam);
2625
2626         if ((len = luaL_getn(L, def)) != 3)
2627             luaL_error(L, "invalid attribute definition '%s'", fldnam);
2628
2629         for (i = 0;  i < len;  i++) {
2630             lua_pushnumber(L, (int)(i+1));
2631             lua_gettable(L, def);
2632
2633             switch (i) {
2634             case 0:  attr->prop = pa_xstrdup(luaL_checkstring(L,-1));    break;
2635             case 1:  attr->def.type = luaL_checkint(L,-1);               break;
2636             case 2:
2637                 switch (attr->def.type) {
2638                 case mqi_string:   v->string = luaL_checkstring(L,-1);   break;
2639                 case mqi_integer:  v->integer = luaL_checkint(L,-1);     break;
2640                 case mqi_unsignd:  v->integer = luaL_checkint(L,-1);     break;
2641                 case mqi_floating: v->floating = luaL_checknumber(L,-1); break;
2642                 default:           memset(v, 0, sizeof(*v));             break;
2643                 }
2644             }
2645
2646             lua_pop(L, 1);
2647         }
2648
2649         if (!attr->prop)
2650             luaL_error(L, "missing property name definition from '%s'",fldnam);
2651         if (attr->def.type != mqi_string  && attr->def.type != mqi_integer &&
2652             attr->def.type != mqi_unsignd && attr->def.type != mqi_floating)
2653         {
2654             luaL_error(L, "invalid attribute type %d for '%s'",
2655                        attr->def.type, fldnam);
2656         }
2657         if (attr->def.type == mqi_unsignd && attr->def.value.integer < 0) {
2658             luaL_error(L, "attempt to give negative value (%d) for field '%s'",
2659                        attr->def.value.integer, fldnam);
2660         }
2661     }
2662
2663     return attrs;
2664 }
2665
2666 static void attributes_destroy(attribute_t *attrs)
2667 {
2668     attribute_t *attr;
2669
2670     if (attrs) {
2671         for (attr = attrs;  attr->prop && attr->def.name;  attr++) {
2672             pa_xfree((void *)attr->prop);
2673             pa_xfree((void *)attr->def.name);
2674             if (attr->def.type == mqi_string)
2675                 pa_xfree((void *)attr->def.value.string);
2676         }
2677         pa_xfree(attrs);
2678     }
2679 }
2680
2681 static map_t *map_check(lua_State *L, int tbl)
2682 {
2683     int def;
2684     size_t namlen;
2685     const char *name;
2686     const char *option;
2687     const char *role;
2688     map_t *m, *map = NULL;
2689     size_t n = 0;
2690     size_t 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;  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 = 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, 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 = 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, 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" ,"odo", calculate_bridge,mir_volume_suppress       },
3228         {"volume_correct" ,"odo", 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  */