static int command_userlogcleanup(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd) { struct log_data* ldata = (struct log_data*) plugin->ptr; struct cbuffer* buf = cbuf_create(128); struct plugin_command_arg_data* arg = (struct plugin_command_arg_data*) list_get_first(cmd->args); int days = arg->data.integer; int rc = sql_execute(ldata, null_callback, NULL, "DELETE FROM userlog WHERE time < DATETIME('NOW', 'localtime', '-%d days');", days); if (rc > 0) cbuf_append_format(buf, "*** %s: Cleaned log entries older than %d days.", cmd->prefix, days); else cbuf_append_format(buf, "*** %s: Unable to clean log table.", cmd->prefix); plugin->hub.send_message(plugin, user, cbuf_get(buf)); cbuf_destroy(buf); sql_execute(ldata, null_callback, NULL, "VACUUM;"); return 0; }
/*! Generic xml netconf clicon rpc * Want to go over to use netconf directly between client and server,... * @param[in] h clicon handle * @param[in] xml XML netconf tree * @param[out] xret Return XML netconf tree, error or OK * @param[out] sp Socket pointer for notification, otherwise NULL * @code * cxobj *xret = NULL; * int s; * if (clicon_rpc_netconf_xml(h, x, &xret, &s) < 0) * err; * xml_free(xret); * @endcode * @see clicon_rpc_netconf xml as string instead of tree */ int clicon_rpc_netconf_xml(clicon_handle h, cxobj *xml, cxobj **xret, int *sp) { int retval = -1; cbuf *cb = NULL; if ((cb = cbuf_new()) == NULL){ clicon_err(OE_XML, errno, "cbuf_new"); goto done; } if (clicon_xml2cbuf(cb, xml, 0, 0) < 0) goto done; if (clicon_rpc_netconf(h, cbuf_get(cb), xret, sp) < 0) goto done; retval = 0; done: if (cb) cbuf_free(cb); return retval; }
/** * The callback function for handling the !history command. */ static int command_history(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd) { struct cbuffer* buf; struct chat_history_data* data = (struct chat_history_data*) plugin->ptr; struct plugin_command_arg_data* arg = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_integer); int maxlines; if (!list_size(data->chat_history)) return command_status(plugin, user, cmd, cbuf_create_const("No messages.")); if (arg) maxlines = arg->data.integer; else maxlines = data->history_default; buf = cbuf_create(MAX_HISTORY_SIZE); cbuf_append_format(buf, "*** %s: Chat History:\n", cmd->prefix); get_messages(data, maxlines, buf); plugin->hub.send_message(plugin, user, cbuf_get(buf)); cbuf_destroy(buf); return 0; }
static int command_releaseadd(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd) { struct extras_data* extrasdata = (struct extras_data*) plugin->ptr; struct cbuffer* buf = cbuf_create(128); struct plugin_command_arg_data* arg1 = (struct plugin_command_arg_data*) list_get_first(cmd->args); struct plugin_command_arg_data* arg2 = (struct plugin_command_arg_data*) list_get_next(cmd->args); char* tth = strdup(sql_escape_string(arg1->data.string)); char* title = strdup(sql_escape_string(arg2->data.string)); int rc = sql_execute(extrasdata, null_callback, NULL, "INSERT INTO releases (id, title, tth) VALUES(NULL, '%s', '%s');", title, tth); if (rc > 0) cbuf_append_format(buf, "*** %s: Added \"%s\" to releases.", cmd->prefix, title); else cbuf_append_format(buf, "*** %s: Unable to add \"%s\" to releases.", cmd->prefix, title); plugin->hub.send_message(plugin, user, cbuf_get(buf)); cbuf_destroy(buf); hub_free(tth); hub_free(title); return 0; }
static int command_userlog(struct plugin_handle* plugin, struct plugin_user* user, struct plugin_command* cmd) { struct log_data* ldata = (struct log_data*) plugin->ptr; struct cbuffer* buf = cbuf_create(128); size_t argnum = list_size(cmd->args); struct plugin_command_arg_data* arg1 = NULL; struct plugin_command_arg_data* arg2 = NULL; struct plugin_command_arg_data* arg3 = NULL; if (argnum == 3) { arg1 = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_integer); arg2 = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_string); arg3 = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_string); } else { if (argnum == 2) { cbuf_append_format(buf, "*** %s: Missing search pattern.", cmd->prefix); plugin->hub.send_message(plugin, user, cbuf_get(buf)); cbuf_destroy(buf); return 0; } if (argnum == 1) arg1 = plugin->hub.command_arg_next(plugin, cmd, plugin_cmd_arg_type_integer); } int lines = arg1 ? arg1->data.integer : 20; char* column = arg2 ? arg2->data.string : ""; char* search = arg3 ? arg3->data.string : ""; size_t column_len = strlen(column); size_t search_len = strlen(search); char query[1024]; sqlite3_stmt *res; int error = 0; const char *tail; size_t count = 0; if (lines > 200) lines = 200; if (search_len && column_len) { if(!check_column(column)) { cbuf_append_format(buf, "*** %s: Invalid column. Valid columns are: nick, cid, addr, credentials, useragent, message, all.", cmd->prefix); plugin->hub.send_message(plugin, user, cbuf_get(buf)); cbuf_destroy(buf); return 0; } if (strcmp(column, "all") == 0) { sprintf(query, "SELECT * FROM userlog WHERE nick LIKE '%%%s%%' OR cid LIKE '%%%s%%' OR credentials LIKE '%%%s%%' OR useragent LIKE '%%%s%%' OR addr LIKE '%%%s%%' OR message LIKE '%%%s%%' ORDER BY time DESC LIMIT %d;", search, search, search, search, search, search, lines); cbuf_append_format(buf, "*** %s: Search_ing for \"%s\" in all columns.", cmd->prefix, search); } else { sprintf(query, "SELECT * FROM userlog WHERE %s LIKE '%%%s%%' ORDER BY time DESC LIMIT %d;", column, search, lines); cbuf_append_format(buf, "*** %s: Searching for \"%s\" in column \"%s\".", cmd->prefix, search, column); } } else { sprintf(query, "SELECT * FROM userlog ORDER BY time DESC LIMIT %d;", lines); cbuf_append_format(buf, "*** %s: ", cmd->prefix); } error = sqlite3_prepare_v2(ldata->db, query, strlen(query), &res, &tail); while (sqlite3_step(res) == SQLITE_ROW) { cbuf_append_format(buf, "\n[%s] %s, %s [%s] [%s] \"%s\" - %s", (char*) sqlite3_column_text(res, 6), (char*) sqlite3_column_text(res, 1), (char*) sqlite3_column_text(res, 0), (char*) sqlite3_column_text(res, 3), (char*) sqlite3_column_text(res, 2), (char*) sqlite3_column_text(res, 4), (char*) sqlite3_column_text(res, 5)); count++; } if (error || count == 0) { if (search_len && column_len) cbuf_append(buf, "\n"); cbuf_append(buf, "No log entries found."); } else cbuf_append_format(buf, "\n\n%zd entr%s shown", count, count != 1 ? "ies" : "y"); sqlite3_finalize(res); plugin->hub.send_message(plugin, user, cbuf_get(buf)); cbuf_destroy(buf); return 0; }
int main(void) { CircBuf *cbuf; unsigned long val, val2; unsigned long vals[32]; unsigned char c, c2; unsigned char s[10]; int i, j; cbuf = cbuf_new(sizeof(val), 32); assert(cbuf != NULL); assert(cbuf->size == (sizeof(val) * 32)); assert(cbuf_unread(cbuf) == 0); assert(cbuf_unwritten(cbuf) == 31); val = 0xaaaaaaaa; cbuf_put(cbuf, &val, 1); /* * Note: unread() + unwritten() should always equal 31 * (one less than the size of the buffer) */ assert(cbuf_unread(cbuf) == 1); assert(cbuf_unwritten(cbuf) == 30); cbuf_peek(cbuf, 0, &val2, 1); assert(val2 == val); assert(cbuf_unread(cbuf) == 1); assert(cbuf_unwritten(cbuf) == 30); val = 0xdeadbeef; cbuf_put(cbuf, &val, 1); assert(cbuf_unread(cbuf) == 2); assert(cbuf_unwritten(cbuf) == 29); val2 = 0; cbuf_get(cbuf, &val2, 1); assert(val2 == 0xaaaaaaaa); assert(cbuf_unread(cbuf) == 1); assert(cbuf_unwritten(cbuf) == 30); val = 0xdeadbabe; cbuf_put(cbuf, &val, 1); val = 0x12345678; cbuf_put(cbuf, &val, 1); /* Write 10 elements */ for (i = 0; i < 10; i++) vals[i] = i; cbuf_put(cbuf, vals, 10); assert(cbuf_unread(cbuf) == 13); assert(cbuf_unwritten(cbuf) == 18); val2 = 0; cbuf_get(cbuf, &val2, 1); assert(val2 == 0xdeadbeef); cbuf_get(cbuf, &val2, 1); assert(val2 == 0xdeadbabe); /* * Now let's try writing across the boundary.. we've written * a total of 14 elements so far. So let's write 18 now * to make sure we're overwriting the first things we wrote. */ for (i = 0; i < 18; i++) vals[i] = 0xFFFF0000 | i; cbuf_put(cbuf, vals, 18); assert(cbuf_unread(cbuf) == 29); assert(cbuf_unwritten(cbuf) == 2); cbuf_get(cbuf, &val2, 1); assert(val2 == 0x12345678); cbuf_get(cbuf, vals, 10); for (i = 0; i < 10; i++) assert(vals[i] == i); assert(cbuf_unread(cbuf) == 18); assert(cbuf_unwritten(cbuf) == 13); /* Now read across boundary */ cbuf_get(cbuf, vals, 18); for (i = 0; i < 18; i++) assert(vals[i] == (0xFFFF0000 | i)); assert(cbuf_unread(cbuf) == 0); assert(cbuf_unwritten(cbuf) == 31); /* One more boundary test, writing 1 element at a time */ for (i = 0; i < 31; i++) { val = (0xaaaa0000 | i); cbuf_put(cbuf, &val, 1); } assert(cbuf_unread(cbuf) == 31); assert(cbuf_unwritten(cbuf) == 0); for (i = 0; i < 31; i++) { cbuf_get(cbuf, &val, 1); assert(val == (0xaaaa0000 | i)); } assert(cbuf_unread(cbuf) == 0); assert(cbuf_unwritten(cbuf) == 31); cbuf_destroy(cbuf); /* Test with character elements instead of longs */ cbuf = cbuf_new(sizeof(c), 10); assert(cbuf != NULL); assert(cbuf->size == (sizeof(c) * 10)); assert(cbuf_unread(cbuf) == 0); assert(cbuf_unwritten(cbuf) == 9); c = '@'; cbuf_put(cbuf, &c, 1); assert(cbuf_unread(cbuf) == 1); assert(cbuf_unwritten(cbuf) == 8); cbuf_peek(cbuf, 0, &c2, 1); assert(c2 == c); assert(cbuf_unread(cbuf) == 1); assert(cbuf_unwritten(cbuf) == 8); c = 'a'; cbuf_put(cbuf, &c, 1); assert(cbuf_unread(cbuf) == 2); assert(cbuf_unwritten(cbuf) == 7); c2 = '\0'; cbuf_get(cbuf, &c2, 1); assert(c2 == '@'); assert(cbuf_unread(cbuf) == 1); assert(cbuf_unwritten(cbuf) == 8); c = 'b'; cbuf_put(cbuf, &c, 1); c = '#'; cbuf_put(cbuf, &c, 1); cbuf_get(cbuf, &c, 1); assert(c == 'a'); cbuf_get(cbuf, &c, 1); assert(c == 'b'); assert(cbuf_unread(cbuf) == 1); assert(cbuf_unwritten(cbuf) == 8); /* Write 8 elements */ for (i = 0; i < 8; i++) s[i] = (unsigned char) i; cbuf_put(cbuf, s, 8); assert(cbuf_unwritten(cbuf) == 0); assert(cbuf_unread(cbuf) == 9); c = '\0'; cbuf_get(cbuf, &c, 1); assert(c == '#'); for (i = 0; i < 8; i++) s[i] = '0'; cbuf_get(cbuf, s, 8); for (i = 0; i < 8; i++) assert(s[i] == (unsigned char) i); assert(cbuf_unread(cbuf) == 0); assert(cbuf_unwritten(cbuf) == 9); cbuf_destroy(cbuf); printf("Unit test PASSED\n"); return 0; }
/*! Load a configuration file to candidate database * Utility function used by cligen spec file * @param[in] h CLICON handle * @param[in] cvv Vector of variables (where <varname> is found) * @param[in] argv A string: "<varname> (merge|replace)" * <varname> is name of a variable occuring in "cvv" containing filename * @note that "filename" is local on client filesystem not backend. * @note file is assumed to have a dummy top-tag, eg <clicon></clicon> * @code * # cligen spec * load file <name2:string>, load_config_file("name2","merge"); * @endcode * @see save_config_file */ int load_config_file(clicon_handle h, cvec *cvv, cvec *argv) { int ret = -1; struct stat st; char *filename = NULL; int replace; cg_var *cv; char *opstr; char *varstr; int fd = -1; cxobj *xt = NULL; cxobj *x; cbuf *cbxml; if (cvec_len(argv) != 2){ if (cvec_len(argv)==1) clicon_err(OE_PLUGIN, 0, "Got single argument:\"%s\". Expected \"<varname>,<op>\"", cv_string_get(cvec_i(argv,0))); else clicon_err(OE_PLUGIN, 0, "Got %d arguments. Expected: <varname>,<op>", cvec_len(argv)); goto done; } varstr = cv_string_get(cvec_i(argv, 0)); opstr = cv_string_get(cvec_i(argv, 1)); if (strcmp(opstr, "merge") == 0) replace = 0; else if (strcmp(opstr, "replace") == 0) replace = 1; else{ clicon_err(OE_PLUGIN, 0, "No such op: %s, expected merge or replace", opstr); goto done; } if ((cv = cvec_find(cvv, varstr)) == NULL){ clicon_err(OE_PLUGIN, 0, "No such var name: %s", varstr); goto done; } filename = cv_string_get(cv); if (stat(filename, &st) < 0){ clicon_err(OE_UNIX, 0, "load_config: stat(%s): %s", filename, strerror(errno)); goto done; } /* Open and parse local file into xml */ if ((fd = open(filename, O_RDONLY)) < 0){ clicon_err(OE_UNIX, errno, "open(%s)", filename); goto done; } if (xml_parse_file(fd, "</clicon>", NULL, &xt) < 0) goto done; if (xt == NULL) goto done; if ((cbxml = cbuf_new()) == NULL) goto done; x = NULL; while ((x = xml_child_each(xt, x, -1)) != NULL) { /* Ensure top-level is "config", maybe this is too rough? */ xml_name_set(x, "config"); if (clicon_xml2cbuf(cbxml, x, 0, 0) < 0) goto done; } if (clicon_rpc_edit_config(h, "candidate", replace?OP_REPLACE:OP_MERGE, cbuf_get(cbxml)) < 0) goto done; cbuf_free(cbxml); // } ret = 0; done: if (xt) xml_free(xt); if (fd != -1) close(fd); return ret; }
/*! Modify xml datastore from a callback using xml key format strings * @param[in] h Clicon handle * @param[in] cvv Vector of cli string and instantiated variables * @param[in] argv Vector. First element xml key format string, eg "/aaa/%s" * @param[in] op Operation to perform on database * Cvv will contain first the complete cli string, and then a set of optional * instantiated variables. * Example: * cvv[0] = "set interfaces interface eth0 type bgp" * cvv[1] = "eth0" * cvv[2] = "bgp" * argv[0] = "/interfaces/interface/%s/type" * op: OP_MERGE * @see cli_callback_generate where arg is generated */ static int cli_dbxml(clicon_handle h, cvec *cvv, cvec *argv, enum operation_type op) { int retval = -1; char *str = NULL; char *api_path_fmt; /* xml key format */ char *api_path = NULL; /* xml key */ cg_var *cval; int len; cg_var *arg; cbuf *cb = NULL; yang_stmt *yspec; cxobj *xbot = NULL; /* xpath, NULL if datastore */ yang_stmt *y = NULL; /* yang spec of xpath */ cxobj *xtop = NULL; /* xpath root */ cxobj *xa; /* attribute */ cxobj *xb; /* body */ if (cvec_len(argv) != 1){ clicon_err(OE_PLUGIN, 0, "Requires one element to be xml key format string"); goto done; } if ((yspec = clicon_dbspec_yang(h)) == NULL){ clicon_err(OE_FATAL, 0, "No DB_SPEC"); goto done; } arg = cvec_i(argv, 0); api_path_fmt = cv_string_get(arg); if (api_path_fmt2api_path(api_path_fmt, cvv, &api_path) < 0) goto done; /* Create config top-of-tree */ if ((xtop = xml_new("config", NULL, NULL)) == NULL) goto done; xbot = xtop; if (api_path && api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, &y) < 1) goto done; if ((xa = xml_new("operation", xbot, NULL)) == NULL) goto done; xml_type_set(xa, CX_ATTR); if (xml_value_set(xa, xml_operation2str(op)) < 0) goto done; if (yang_keyword_get(y) != Y_LIST && yang_keyword_get(y) != Y_LEAF_LIST){ len = cvec_len(cvv); if (len > 1){ cval = cvec_i(cvv, len-1); if ((str = cv2str_dup(cval)) == NULL){ clicon_err(OE_UNIX, errno, "cv2str_dup"); goto done; } if ((xb = xml_new("body", xbot, NULL)) == NULL) goto done; xml_type_set(xb, CX_BODY); if (xml_value_set(xb, str) < 0) goto done; } } if ((cb = cbuf_new()) == NULL){ clicon_err(OE_XML, errno, "cbuf_new"); goto done; } if (clicon_xml2cbuf(cb, xtop, 0, 0) < 0) goto done; if (clicon_rpc_edit_config(h, "candidate", OP_NONE, cbuf_get(cb)) < 0) goto done; if (clicon_autocommit(h)) { if (clicon_rpc_commit(h) < 0) goto done; } retval = 0; done: if (cb) cbuf_free(cb); if (str) free(str); if (api_path) free(api_path); if (xtop) xml_free(xtop); return retval; }
/*! Copy one configuration object to antother * * Works for objects that are items ina yang list with a keyname, eg as: * list sender{ * key name; * leaf name{... * * @param[in] h CLICON handle * @param[in] cvv Vector of variables from CLIgen command-line * @param[in] argv Vector: <db>, <xpath>, <field>, <fromvar>, <tovar> * Explanation of argv fields: * db: Database name, eg candidate|tmp|startup * xpath: XPATH expression with exactly two %s pointing to field and from name * field: Name of list key, eg name * fromvar:Name of variable containing name of object to copy from (given by xpath) * tovar: Name of variable containing name of object to copy to. * @code * cli spec: * copy snd <n1:string> to <n2:string>, cli_copy_config("candidate", "/sender[%s='%s']", "from", "n1", "n2"); * cli command: * copy snd from to to * @endcode */ int cli_copy_config(clicon_handle h, cvec *cvv, cvec *argv) { int retval = -1; char *db; cxobj *x1 = NULL; cxobj *x2 = NULL; cxobj *x; char *xpath; int i; int j; cbuf *cb = NULL; char *keyname; char *fromvar; cg_var *fromcv; char *fromname = NULL; char *tovar; cg_var *tocv; char *toname; cxobj *xerr; if (cvec_len(argv) != 5){ clicon_err(OE_PLUGIN, 0, "Requires four elements: <db> <xpath> <keyname> <from> <to>"); goto done; } /* First argv argument: Database */ db = cv_string_get(cvec_i(argv, 0)); /* Second argv argument: xpath */ xpath = cv_string_get(cvec_i(argv, 1)); /* Third argv argument: name of keyname */ keyname = cv_string_get(cvec_i(argv, 2)); /* Fourth argv argument: from variable */ fromvar = cv_string_get(cvec_i(argv, 3)); /* Fifth argv argument: to variable */ tovar = cv_string_get(cvec_i(argv, 4)); /* Get from variable -> cv -> from name */ if ((fromcv = cvec_find(cvv, fromvar)) == NULL){ clicon_err(OE_PLUGIN, 0, "fromvar '%s' not found in cligen var list", fromvar); goto done; } /* Get from name from cv */ fromname = cv_string_get(fromcv); /* Create xpath */ if ((cb = cbuf_new()) == NULL){ clicon_err(OE_PLUGIN, errno, "cbuf_new"); goto done; } /* Sanity check that xpath contains exactly two %s, ie [%s='%s'] */ j = 0; for (i=0; i<strlen(xpath); i++){ if (xpath[i] == '%') j++; } if (j != 2){ clicon_err(OE_PLUGIN, 0, "xpath '%s' does not have two '%%'", xpath); goto done; } cprintf(cb, xpath, keyname, fromname); /* Get from object configuration and store in x1 */ if (clicon_rpc_get_config(h, db, cbuf_get(cb), &x1) < 0) goto done; if ((xerr = xpath_first(x1, "/rpc-error")) != NULL){ clicon_rpc_generate_error("Get configuration", xerr); goto done; } /* Get to variable -> cv -> to name */ if ((tocv = cvec_find(cvv, tovar)) == NULL){ clicon_err(OE_PLUGIN, 0, "tovar '%s' not found in cligen var list", tovar); goto done; } toname = cv_string_get(tocv); /* Create copy xml tree x2 */ if ((x2 = xml_new("new", NULL, NULL)) == NULL) goto done; if (xml_copy(x1, x2) < 0) goto done; xml_name_set(x2, "config"); cprintf(cb, "/%s", keyname); if ((x = xpath_first(x2, "%s", cbuf_get(cb))) == NULL){ clicon_err(OE_PLUGIN, 0, "Field %s not found in copy tree", keyname); goto done; } x = xml_find(x, "body"); xml_value_set(x, toname); /* resuse cb */ cbuf_reset(cb); /* create xml copy tree and merge it with database configuration */ clicon_xml2cbuf(cb, x2, 0, 0); if (clicon_rpc_edit_config(h, db, OP_MERGE, cbuf_get(cb)) < 0) goto done; retval = 0; done: if (cb) cbuf_free(cb); if (x1 != NULL) xml_free(x1); if (x2 != NULL) xml_free(x2); return retval; }