|
@@ -33,14 +33,31 @@ MODULE_VERSION
|
|
|
static str mi_rpc_indent = { "\t", 1 };
|
|
|
|
|
|
static const char* rpc_mi_exec_doc[2] = {
|
|
|
- "Execut MI command",
|
|
|
+ "Execute MI command",
|
|
|
0
|
|
|
};
|
|
|
|
|
|
-static void rpc_mi_exec(rpc_t* rpc, void* c);
|
|
|
+
|
|
|
+
|
|
|
+enum mi_rpc_print_mode {
|
|
|
+ MI_PRETTY_PRINT,
|
|
|
+ MI_FIFO_PRINT,
|
|
|
+ MI_DATAGRAM_PRINT,
|
|
|
+ MI_XMLRPC_PRINT
|
|
|
+};
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static void rpc_mi_pretty_exec(rpc_t* rpc, void* c);
|
|
|
+static void rpc_mi_fifo_exec(rpc_t* rpc, void* c);
|
|
|
+static void rpc_mi_dg_exec(rpc_t* rpc, void* c);
|
|
|
+static void rpc_mi_xmlrpc_exec(rpc_t* rpc, void* c);
|
|
|
|
|
|
rpc_export_t mr_rpc[] = {
|
|
|
- {"mi", rpc_mi_exec, rpc_mi_exec_doc, RET_ARRAY},
|
|
|
+ {"mi", rpc_mi_pretty_exec, rpc_mi_exec_doc, RET_ARRAY},
|
|
|
+ {"mi_fifo", rpc_mi_fifo_exec, rpc_mi_exec_doc, RET_ARRAY},
|
|
|
+ {"mi_dg", rpc_mi_dg_exec, rpc_mi_exec_doc, RET_ARRAY},
|
|
|
+ {"mi_xmlrpc", rpc_mi_xmlrpc_exec, rpc_mi_exec_doc, RET_ARRAY},
|
|
|
{0, 0, 0, 0}
|
|
|
};
|
|
|
|
|
@@ -56,6 +73,8 @@ struct module_exports exports = {
|
|
|
0 /* Child initialization function */
|
|
|
};
|
|
|
|
|
|
+
|
|
|
+
|
|
|
struct mi_root *mi_rpc_read_params(rpc_t *rpc, void *ctx)
|
|
|
{
|
|
|
struct mi_root *root;
|
|
@@ -108,63 +127,136 @@ error:
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int mi_rpc_rprint_node(rpc_t* rpc, void* ctx, struct mi_node *node,
|
|
|
- int level)
|
|
|
+
|
|
|
+
|
|
|
+/** prints a mi node using mode.
|
|
|
+ * @return 0 on success, -1 on error (line too long)
|
|
|
+ */
|
|
|
+static int mi_rpc_print_node(rpc_t* rpc, void* ctx, struct mi_node* node,
|
|
|
+ enum mi_rpc_print_mode mode, char* prefix)
|
|
|
{
|
|
|
+ static char buf[512];
|
|
|
+ char* p;
|
|
|
+ int n;
|
|
|
+ int size;
|
|
|
struct mi_attr *attr;
|
|
|
+
|
|
|
+ p=buf;
|
|
|
+ *p=0;
|
|
|
+ size=sizeof(buf);
|
|
|
+ n=snprintf(p, size, "%s%.*s:: %.*s",
|
|
|
+ prefix,
|
|
|
+ node->name.len, (node->name.s)?node->name.s:"",
|
|
|
+ node->value.len, (node->value.s)?node->value.s:"");
|
|
|
+ if (n==-1 || n >= size)
|
|
|
+ goto error_buf;
|
|
|
+ p+=n;
|
|
|
+ size-=n;
|
|
|
+ for( attr=node->attributes ; attr!=NULL ; attr=attr->next ) {
|
|
|
+ n=snprintf(p, size, " %.*s=%.*s",
|
|
|
+ attr->name.len, (attr->name.s)?attr->name.s:"",
|
|
|
+ attr->value.len, (attr->value.s)?attr->value.s:"");
|
|
|
+ if (n==-1 || n >= size)
|
|
|
+ goto error_buf;
|
|
|
+ p+=n;
|
|
|
+ size-=n;
|
|
|
+ }
|
|
|
+ if (mode!=MI_PRETTY_PRINT){
|
|
|
+ n=snprintf(p, size, "\n");
|
|
|
+ if (n==-1 || n>= size )
|
|
|
+ goto error_buf;
|
|
|
+ }
|
|
|
+ rpc->add(ctx, "s", buf);
|
|
|
+ return 0;
|
|
|
+error_buf:
|
|
|
+ ERR("line too long (extra %d chars)\n", (n>=size)?n-size+1:0);
|
|
|
+ rpc->fault(ctx, 500, "Line too long");
|
|
|
+ return -1;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static int mi_rpc_rprint_all(rpc_t* rpc, void* ctx, struct mi_node *node,
|
|
|
+ enum mi_rpc_print_mode mode, int level)
|
|
|
+{
|
|
|
char indent[32];
|
|
|
int i;
|
|
|
char *p;
|
|
|
|
|
|
- if(level*mi_rpc_indent.len>=32)
|
|
|
- {
|
|
|
- LM_ERR("too many recursive levels for indentation\n");
|
|
|
- return -1;
|
|
|
- }
|
|
|
p = indent;
|
|
|
- for(i=0; i<level; i++)
|
|
|
- {
|
|
|
- memcpy(p, mi_rpc_indent.s, mi_rpc_indent.len);
|
|
|
- p += mi_rpc_indent.len;
|
|
|
+ switch(mode){
|
|
|
+ case MI_FIFO_PRINT:
|
|
|
+ case MI_DATAGRAM_PRINT:
|
|
|
+ case MI_PRETTY_PRINT:
|
|
|
+ if(level*mi_rpc_indent.len>=32)
|
|
|
+ {
|
|
|
+ LM_ERR("too many recursive levels for indentation\n");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ for(i=0; i<level; i++)
|
|
|
+ {
|
|
|
+ memcpy(p, mi_rpc_indent.s, mi_rpc_indent.len);
|
|
|
+ p += mi_rpc_indent.len;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case MI_XMLRPC_PRINT:
|
|
|
+ /* no identation in this mode */
|
|
|
+ break;
|
|
|
}
|
|
|
*p = 0;
|
|
|
for( ; node ; node=node->next )
|
|
|
{
|
|
|
- rpc->printf(ctx, "%s+ %.*s:: %.*s",
|
|
|
- indent,
|
|
|
- node->name.len, (node->name.s)?node->name.s:"",
|
|
|
- node->value.len, (node->value.s)?node->value.s:"");
|
|
|
-
|
|
|
- for( attr=node->attributes ; attr!=NULL ; attr=attr->next ) {
|
|
|
- rpc->printf(ctx, "%s%.*s - %.*s=%.*s",
|
|
|
- indent, mi_rpc_indent.len, mi_rpc_indent.s,
|
|
|
- attr->name.len, (attr->name.s)?attr->name.s:"",
|
|
|
- attr->value.len, (attr->value.s)?attr->value.s:"");
|
|
|
- }
|
|
|
-
|
|
|
+ if (mi_rpc_print_node(rpc, ctx, node, mode, p)<0)
|
|
|
+ return -1;
|
|
|
if (node->kids) {
|
|
|
- if (mi_rpc_rprint_node(rpc, ctx, node->kids, level+1)<0)
|
|
|
+ if (mi_rpc_rprint_all(rpc, ctx, node->kids, mode, level+1)<0)
|
|
|
return -1;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int mi_rpc_print_tree(rpc_t* rpc, void* ctx, struct mi_root *tree)
|
|
|
+
|
|
|
+
|
|
|
+/** build an rpc reply from an mi tree.
|
|
|
+ * @param mode - how to build the reply: mi_fifo like, mi_datagram_like,
|
|
|
+ * mi_xmlrpc ...
|
|
|
+ * @return -1 on error, 0 on success
|
|
|
+ */
|
|
|
+static int mi_rpc_print_tree(rpc_t* rpc, void* ctx, struct mi_root *tree,
|
|
|
+ enum mi_rpc_print_mode mode)
|
|
|
{
|
|
|
- rpc->printf(ctx, "%d %.*s\n", tree->code,
|
|
|
- tree->reason.len, tree->reason.s);
|
|
|
+ switch(mode){
|
|
|
+ case MI_FIFO_PRINT:
|
|
|
+ case MI_DATAGRAM_PRINT:
|
|
|
+ /* always success, code & reason are the part of the reply */
|
|
|
+ rpc->printf(ctx, "%d %.*s\n", tree->code,
|
|
|
+ tree->reason.len, tree->reason.s);
|
|
|
+ break;
|
|
|
+ case MI_PRETTY_PRINT:
|
|
|
+ case MI_XMLRPC_PRINT:
|
|
|
+ /* don't print code & reason, use fault instead */
|
|
|
+ if (tree->code<200 || tree->code> 299) {
|
|
|
+ rpc->fault(ctx, tree->code, tree->reason.s);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
if (tree->node.kids)
|
|
|
{
|
|
|
- if (mi_rpc_rprint_node(rpc, ctx, tree->node.kids, 0)<0)
|
|
|
+ if (mi_rpc_rprint_all(rpc, ctx, tree->node.kids, mode, 0)<0)
|
|
|
return -1;
|
|
|
}
|
|
|
+ if (mode==MI_FIFO_PRINT){
|
|
|
+ /* mi fifo adds an extra "\n" at the end */
|
|
|
+ rpc->printf(ctx, "\n");
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void rpc_mi_exec(rpc_t *rpc, void *ctx)
|
|
|
+static void rpc_mi_exec(rpc_t *rpc, void *ctx, enum mi_rpc_print_mode mode)
|
|
|
{
|
|
|
str cmd;
|
|
|
struct mi_cmd *mic;
|
|
@@ -215,7 +307,7 @@ static void rpc_mi_exec(rpc_t *rpc, void *ctx)
|
|
|
|
|
|
if (mi_rpl!=MI_ROOT_ASYNC_RPL)
|
|
|
{
|
|
|
- mi_rpc_print_tree(rpc, ctx, mi_rpl);
|
|
|
+ mi_rpc_print_tree(rpc, ctx, mi_rpl, mode);
|
|
|
free_mi_tree(mi_rpl);
|
|
|
if (mi_req) free_mi_tree(mi_req);
|
|
|
return;
|
|
@@ -226,3 +318,31 @@ static void rpc_mi_exec(rpc_t *rpc, void *ctx)
|
|
|
if (mi_req) free_mi_tree(mi_req);
|
|
|
return;
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static void rpc_mi_pretty_exec(rpc_t* rpc, void* c)
|
|
|
+{
|
|
|
+ rpc_mi_exec(rpc, c, MI_PRETTY_PRINT);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static void rpc_mi_fifo_exec(rpc_t* rpc, void* c)
|
|
|
+{
|
|
|
+ rpc_mi_exec(rpc, c, MI_FIFO_PRINT);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static void rpc_mi_dg_exec(rpc_t* rpc, void* c)
|
|
|
+{
|
|
|
+ rpc_mi_exec(rpc, c, MI_DATAGRAM_PRINT);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+static void rpc_mi_xmlrpc_exec(rpc_t* rpc, void* c)
|
|
|
+{
|
|
|
+ rpc_mi_exec(rpc, c, MI_XMLRPC_PRINT);
|
|
|
+}
|