/* * Secure X Message Passing Library v2 implementation. * (c) Askele Group 2013-2015 * (c) Alexander Vdolainen 2013-2015 * * libsxmp is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * libsxmp is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see ."; * */ #include #include #include #include #include #include #include #include #include #include static long __cmp_int(const void *a, const void *b) { return *(int *)a - *(int *)b; } static long __cmp_cstr(const void *a, const void *b) { return strcmp((char *)a, (char *)b); } int sxmp_rpclist_init(usrtc_t *tree) { usrtc_init(tree, USRTC_REDBLACK, MAX_RPC_LIST, __cmp_int); return 0; } int sxmp_rpclist_add(usrtc_t *tree, int type, const char *description, const char *version) { rpc_typed_list_t *nlist = NULL; sxl_rpclist_t *rpc_list = NULL; usrtc_t *rtree = NULL; usrtc_node_t *node = NULL; int r = ENOMEM; /* check for existing one */ node = usrtc_lookup(tree, &type); if(node) return EEXIST; /* allocate all */ if(!(nlist = malloc(sizeof(rpc_typed_list_t)))) goto __fail; else memset(nlist, 0, sizeof(rpc_typed_list_t)); if(!(rpc_list = malloc(sizeof(sxl_rpclist_t)))) goto __fail; else memset(rpc_list, 0, sizeof(sxl_rpclist_t)); if(!(rtree = malloc(sizeof(usrtc_t)))) goto __fail; /* version and description */ if(!(nlist->description = strdup(description))) goto __fail_a; if(version) { /* in case of existing version */ if(!(rpc_list->opt_version = strdup(version))) goto __fail_a; } /* initialize all */ nlist->type_id = type; nlist->rpc_list = rpc_list; rpc_list->rpc_tree = rtree; usrtc_node_init(&(nlist->lnode), nlist); usrtc_init(rtree, USRTC_SPLAY, MAX_RPC_LIST, __cmp_cstr); node = &(nlist->lnode); /* insert it */ usrtc_insert(tree, node, &(nlist->type_id)); return 0; __fail_a: if(nlist->description) free(nlist->description); if(rpc_list->opt_version) free(rpc_list->opt_version); __fail: if(nlist) free(nlist); if(rpc_list) free(rpc_list); if(rtree) free(rtree); return r; } int sxmp_rpclist_add_function(usrtc_t *tree, int type, const char *fu_name, int (*rpcf)(void *, sexp_t *)) { usrtc_node_t *node; rpc_typed_list_t *tlist; sxl_rpclist_t *rlist; sxl_rpc_t *rentry = NULL; if(*fu_name == '!') return EINVAL; /* reserve such names for ither purposes */ node = usrtc_lookup(tree, &type); if(!node) return ENOENT; else tlist = (rpc_typed_list_t *)usrtc_node_getdata(node); rlist = tlist->rpc_list; /* get rpc list */ /* ok, we don't allow dupes */ node = usrtc_lookup(rlist->rpc_tree, fu_name); if(node) return EEXIST; if(!(rentry = malloc(sizeof(sxl_rpc_t)))) return ENOMEM; else if(!(rentry->name = strdup(fu_name))) { free(rentry); return ENOMEM; } /* init */ usrtc_node_init(&(rentry->node), rentry); rentry->rpcf = rpcf; node = &(rentry->node); usrtc_insert(rlist->rpc_tree, node, rentry->name); /* insert it */ return 0; } int sxmp_rpclist_filter(usrtc_t *source, usrtc_t **dest, int flag, int *filter) { int r = 0, *f = filter, i; usrtc_t *destination = NULL; usrtc_node_t *node; rpc_typed_list_t *tlist, *tlist_filter; if(!filter) return EINVAL; if(!(destination = malloc(sizeof(usrtc_t)))) return ENOMEM; else usrtc_init(destination, USRTC_REDBLACK, MAX_RPC_LIST, __cmp_int); switch(flag) { case SXMP_FILTER_EXC: for(node = usrtc_first(source); ; node = usrtc_next(source, node)) { tlist = (rpc_typed_list_t *)usrtc_node_getdata(node); r = ENOENT; for(i = *f; i != SXMP_FILTER_END; f++, i = *f) { if(tlist->type_id == i) { r = 0; break; } } if(r) { /* we should clone it */ if(!(tlist_filter = malloc(sizeof(rpc_typed_list_t)))) continue; /* skip */ else { tlist_filter->type_id = tlist->type_id; tlist_filter->description = tlist->description; tlist_filter->rpc_list = tlist->rpc_list; usrtc_node_init(&(tlist_filter->lnode), tlist_filter); usrtc_insert(destination, &(tlist_filter->lnode), &(tlist_filter->type_id)); } } if(node == usrtc_last(source)) break; } r = 0; break; case SXMP_FILTER_INC: for(i = *f; i != SXMP_FILTER_END; f++, i = *f) { node = usrtc_lookup(source, &i); if(!node) continue; /* skip it at all */ else tlist = (rpc_typed_list_t *)usrtc_node_getdata(node); /* clone tlist */ if(!(tlist_filter = malloc(sizeof(rpc_typed_list_t)))) continue; /* skip */ else { tlist_filter->type_id = tlist->type_id; tlist_filter->description = tlist->description; tlist_filter->rpc_list = tlist->rpc_list; usrtc_node_init(&(tlist_filter->lnode), tlist_filter); usrtc_insert(destination, &(tlist_filter->lnode), &(tlist_filter->type_id)); } } break; default: r = EINVAL; goto __fail; } if(!usrtc_count(destination)) { /* we have an empty list */ r = EINVAL; goto __fail; } *dest = destination; return 0; __fail: if(destination) free(destination); return r; }