Rewrite command-line parser

Now supports optional args followed by non-optional.
This commit is contained in:
Andrew Bettison 2013-02-12 18:00:37 +10:30
parent 46513bf192
commit fcb6600cd6
9 changed files with 399 additions and 275 deletions

166
cli.c

@ -5,77 +5,103 @@
#include "serval.h"
#include "rhizome.h"
int cli_usage(const struct command_line_option *options) {
int cli_usage(const struct command_line_option *commands) {
printf("Usage:\n");
int i,j;
for(i=0;options[i].function;i++) {
for(j=0;options[i].words[j];j++)
printf(" %s",options[i].words[j]);
printf("\n %s\n",options[i].description);
for(i=0;commands[i].function;i++) {
for(j=0;commands[i].words[j];j++)
printf(" %s",commands[i].words[j]);
printf("\n %s\n",commands[i].description);
}
return 0;
}
int cli_parse(const int argc, const char *const *args, const struct command_line_option *options)
static const char * parsed_add_label_arg(struct parsed_command *parsed, const char *label, unsigned labellen, unsigned argi)
{
int ambiguous=0;
int cli_call=-1;
int i;
for(i=0;options[i].function;i++)
{
int j;
if (parsed->labelc >= NELS(parsed->labelv))
return "too many labeled args";
parsed->labelv[parsed->labelc].label = label;
parsed->labelv[parsed->labelc].len = labellen;
parsed->labelv[parsed->labelc].argi = argi;
++parsed->labelc;
return NULL;
}
int cli_parse(const int argc, const char *const *args, const struct command_line_option *commands, struct parsed_command *parsed)
{
int ambiguous = 0;
int matched_cmd = -1;
int cmd;
for (cmd = 0; commands[cmd].function; ++cmd) {
struct parsed_command cmdpa;
memset(&cmdpa, 0, sizeof cmdpa);
cmdpa.command = &commands[cmd];
cmdpa.args = args;
cmdpa.argc = argc;
cmdpa.labelc = 0;
cmdpa.varargi = -1;
const char *problem = NULL;
const char *word = NULL;
int optional = 0;
int mandatory = 0;
for (j = 0; (word = options[i].words[j]); ++j) {
int arg, opt;
for (arg = 0, opt = 0; !problem && (word = commands[cmd].words[opt]); ++opt) {
int wordlen = strlen(word);
if (optional < 0) {
WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" not allowed after \"...\"", i, j, word);
break;
}
else if (!( (wordlen > 2 && word[0] == '<' && word[wordlen-1] == '>')
|| (wordlen > 4 && word[0] == '[' && word[1] == '<' && word[wordlen-2] == '>' && word[wordlen-1] == ']')
|| (wordlen > 0)
)) {
WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" is malformed", i, j, word);
break;
} else if (word[0] == '<') {
++mandatory;
if (optional) {
WHYF("Internal error: command_line_options[%d].word[%d]=\"%s\" should be optional", i, j, word);
break;
}
} else if (word[0] == '[') {
++optional;
if (cmdpa.varargi != -1)
problem = "more words not allowed after \"...\"";
else if (wordlen > 4 && word[0] == '[' && word[1] == '<' && word[wordlen-2] == '>' && word[wordlen-1] == ']') {
// "[<label>]" consumes one argument if available, records it with label "label".
if (arg < argc)
problem = parsed_add_label_arg(&cmdpa, &word[2], wordlen - 4, arg++);
} else if (wordlen > 2 && word[0] == '[' && word[wordlen-1] == ']') {
// "[word]" consumes one argument if it exactly matches "word", records it with label
// "word".
const char *endp = NULL;
if (arg < argc && strncase_startswith(word + 1, wordlen - 2, args[arg], &endp) && endp == word + wordlen - 1)
problem = parsed_add_label_arg(&cmdpa, &word[1], wordlen - 2, arg++);
} else if (wordlen == 3 && word[0] == '.' && word[1] == '.' && word[2] == '.') {
optional = -1;
} else {
++mandatory;
if (j < argc && strcasecmp(word, args[j])) // literal words don't match
// "..." consumes all remaining arguments.
cmdpa.varargi = arg;
arg = argc;
} else if (wordlen > 2 && word[0] == '<' && word[wordlen-1] == '>') {
// "<label>" consumes exactly one argument, records it with label "label".
if (arg < argc)
problem = parsed_add_label_arg(&cmdpa, &word[1], wordlen - 2, arg++);
else
break;
}
} else if (wordlen > 0) {
const char *endp = NULL;
// "word" consumes exactly one argument which must exactly match "word".
if (arg < argc && strncase_startswith(word, wordlen, args[arg], &endp) && endp == word + wordlen)
++arg;
else
break;
} else
problem = "malformed";
}
if (!word && argc >= mandatory && (optional < 0 || argc <= mandatory + optional)) {
if (problem)
return WHYF("Internal error: commands[%d].word[%d]=\"%s\" - %s", cmd, opt - 1, word, problem);
if (!word && arg == argc) {
/* A match! We got through the command definition with no internal errors and all literal
args matched and we have a proper number of args. If we have multiple matches, then note
that the call is ambiguous. */
if (cli_call>=0) ambiguous++;
if (ambiguous==1) {
if (matched_cmd >= 0)
++ambiguous;
if (ambiguous == 1) {
WHY("Ambiguous command line call:");
WHY_argv(" ", argc, args);
WHY("Matches the following known command line calls:");
WHY_argv(" ", argc, options[cli_call].words);
WHY_argv(" ", argc, commands[matched_cmd].words);
}
if (ambiguous)
WHY_argv(" ", argc, options[i].words);
cli_call=i;
WHY_argv(" ", argc, commands[cmd].words);
matched_cmd = cmd;
*parsed = cmdpa;
}
}
/* Don't process ambiguous calls */
if (ambiguous) return -1;
if (ambiguous)
return -1;
/* Complain if we found no matching calls */
if (cli_call<0) {
if (matched_cmd < 0) {
if (argc) {
WHY("Unknown command line call:");
WHY_argv(" ", argc, args);
@ -83,35 +109,43 @@ int cli_parse(const int argc, const char *const *args, const struct command_line
INFO("Use \"help\" command to see a list of valid commands");
return -1;
}
return cli_call;
return matched_cmd;
}
int cli_invoke(const struct command_line_option *option, const int argc, const char *const *args, void *context)
void _debug_parsed(struct __sourceloc __whence, const struct parsed_command *parsed)
{
DEBUG_argv("command", parsed->argc, parsed->args);
strbuf b = strbuf_alloca(1024);
int i;
for (i = 0; i < parsed->labelc; ++i) {
const struct labelv *lab = &parsed->labelv[i];
strbuf_sprintf(b, " %s=%d", alloca_toprint(-1, lab->label, lab->len), lab->argi);
}
if (parsed->varargi >= 0)
strbuf_sprintf(b, " varargi=%d", parsed->varargi);
DEBUGF("parsed%s", strbuf_str(b));
}
int cli_invoke(const struct parsed_command *parsed, void *context)
{
IN();
int ret=option->function(argc, args, option, context);
int ret = parsed->command->function(parsed, context);
RETURN(ret);
}
int cli_arg(int argc, const char *const *argv, const struct command_line_option *o, char *argname, const char **dst, int (*validator)(const char *arg), char *defaultvalue)
int cli_arg(const struct parsed_command *parsed, char *label, const char **dst, int (*validator)(const char *arg), char *defaultvalue)
{
int arglen = strlen(argname);
int labellen = strlen(label);
if (dst)
*dst = defaultvalue;
int i;
const char *word;
*dst = defaultvalue;
for(i = 0; (word = o->words[i]); ++i) {
int wordlen = strlen(word);
/* No need to check that the "<...>" and "[<...>]" are all intact in the command_line_option,
because that was already checked in parseCommandLine(). */
if (i < argc
&&( (wordlen == arglen + 2 && word[0] == '<' && !strncasecmp(&word[1], argname, arglen))
|| (wordlen == arglen + 4 && word[0] == '[' && !strncasecmp(&word[2], argname, arglen)))
) {
const char *value = argv[i];
for (i = 0; i < parsed->labelc; ++i) {
if (parsed->labelv[i].len == labellen && strncasecmp(label, parsed->labelv[i].label, labellen) == 0) {
const char *value = parsed->args[parsed->labelv[i].argi];
if (validator && !(*validator)(value))
return WHYF("Invalid argument %d '%s': \"%s\"", i + 1, argname, value);
*dst = value;
return WHYF("Invalid argument %d '%s': \"%s\"", i + 1, label, value);
if (dst)
*dst = value;
return 0;
}
}

61
cli.h

@ -1,21 +1,62 @@
/*
Serval command line parsing and processing.
Copyright (C) 2012,2013 Serval Project, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __SERVALD_CLI_H
#define __SERVALD_CLI_H
typedef struct command_line_option {
int (*function)(int argc, const char *const *argv, const struct command_line_option *o, void *context);
const char *words[32]; // 32 words should be plenty!
#include "log.h"
#define COMMAND_LINE_MAX_LABELS (32)
struct parsed_command;
struct command_line_option {
int (*function)(const struct parsed_command *parsed, void *context);
const char *words[COMMAND_LINE_MAX_LABELS];
unsigned long long flags;
#define CLIFLAG_NONOVERLAY (1<<0) /* Uses a legacy IPv4 DNA call instead of overlay mnetwork */
#define CLIFLAG_STANDALONE (1<<1) /* Cannot be issued to a running instance */
#define CLIFLAG_PERMISSIVE_CONFIG (1<<2) /* No error on bad configuration file */
const char *description; // describe this invocation
} command_line_option;
};
struct parsed_command {
const struct command_line_option *command;
struct labelv {
const char *label;
unsigned int len;
unsigned argi;
} labelv[COMMAND_LINE_MAX_LABELS];
unsigned labelc;
const char *const *args;
unsigned argc;
unsigned varargi;
};
int cli_usage(const command_line_option *options);
int cli_parse(const int argc, const char *const *args, const struct command_line_option *options);
int cli_invoke(const struct command_line_option *option, const int argc, const char *const *args, void *context);
int cli_arg(int argc, const char *const *argv, const command_line_option *o, char *argname, const char **dst, int (*validator)(const char *arg), char *defaultvalue);
void _debug_parsed(struct __sourceloc __whence, const struct parsed_command *parsed);
#define DEBUG_parsed(parsed) _debug_parsed(__WHENCE__, parsed)
int cli_usage(const struct command_line_option *commands);
int cli_parse(const int argc, const char *const *args, const struct command_line_option *commands, struct parsed_command *parsed);
int cli_invoke(const struct parsed_command *parsed, void *context);
int cli_arg(const struct parsed_command *parsed, char *label, const char **dst, int (*validator)(const char *arg), char *defaultvalue);
int cli_lookup_did(const char *text);
int cli_absolute_path(const char *arg);
@ -27,6 +68,4 @@ int cli_optional_bundle_crypt_key(const char *arg);
int cli_uint(const char *arg);
int cli_optional_did(const char *text);
#endif
#endif // __SERVALD_CLI_H

@ -46,7 +46,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
extern struct command_line_option command_line_options[];
int commandline_usage(int argc, const char *const *argv, const struct command_line_option *o, void *context){
int commandline_usage(const struct parsed_command *parsed, void *context)
{
printf("Serval Mesh version <version>.\n");
return cli_usage(command_line_options);
}
@ -223,12 +224,12 @@ int parseCommandLine(const char *argv0, int argc, const char *const *args)
fd_clearstats();
IN();
int result = cli_parse(argc, args, command_line_options);
struct parsed_command parsed;
int result = cli_parse(argc, args, command_line_options, &parsed);
if (result != -1) {
const struct command_line_option *option = &command_line_options[result];
// Do not run the command if the configuration does not load ok
if (((option->flags & CLIFLAG_PERMISSIVE_CONFIG) ? cf_reload_permissive() : cf_reload()) != -1)
result = cli_invoke(option, argc, args, NULL);
if (((parsed.command->flags & CLIFLAG_PERMISSIVE_CONFIG) ? cf_reload_permissive() : cf_reload()) != -1)
result = cli_invoke(&parsed, NULL);
else {
strbuf b = strbuf_alloca(160);
strbuf_append_argv(b, argc, args);
@ -478,24 +479,22 @@ void cli_flush()
fflush(stdout);
}
int app_echo(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_echo(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
int i = 1;
int escapes = 0;
if (i < argc && strcmp(argv[i], "-e") == 0) {
escapes = 1;
++i;
}
for (; i < argc; ++i) {
if (config.debug.verbose)
DEBUG_parsed(parsed);
int escapes = !cli_arg(parsed, "-e", NULL, NULL, NULL);
int i;
for (i = parsed->varargi; i < parsed->argc; ++i) {
const char *arg = parsed->args[i];
if (config.debug.verbose)
DEBUGF("echo:argv[%d]=\"%s\"", i, argv[i]);
DEBUGF("echo:argv[%d]=\"%s\"", i, arg);
if (escapes) {
unsigned char buf[strlen(argv[i])];
size_t len = str_fromprint(buf, argv[i]);
unsigned char buf[strlen(arg)];
size_t len = str_fromprint(buf, arg);
cli_write(buf, len);
} else
cli_puts(argv[i]);
cli_puts(arg);
cli_delim(NULL);
}
return 0;
@ -541,9 +540,10 @@ void lookup_send_request(unsigned char *srcsid, int srcport, unsigned char *dsts
}
}
int app_dna_lookup(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_dna_lookup(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
/* Create the instance directory if it does not yet exist */
if (create_serval_instance_dir() == -1)
@ -555,9 +555,9 @@ int app_dna_lookup(int argc, const char *const *argv, const struct command_line_
char uris[MAXREPLIES][MAXURILEN];
const char *did, *delay;
if (cli_arg(argc, argv, o, "did", &did, cli_lookup_did, "*") == -1)
if (cli_arg(parsed, "did", &did, cli_lookup_did, "*") == -1)
return -1;
if (cli_arg(argc, argv, o, "timeout", &delay, NULL, "3000") == -1)
if (cli_arg(parsed, "timeout", &delay, NULL, "3000") == -1)
return -1;
int idelay=atoi(delay);
@ -658,9 +658,10 @@ int app_dna_lookup(int argc, const char *const *argv, const struct command_line_
return 0;
}
int app_server_start(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_server_start(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
/* Process optional arguments */
int pid=-1;
int cpid=-1;
@ -701,9 +702,9 @@ int app_server_start(int argc, const char *const *argv, const struct command_lin
#endif
const char *execpath, *instancepath;
char *tmp;
int foregroundP = (argc >= 2 && !strcasecmp(argv[1], "foreground"));
if (cli_arg(argc, argv, o, "instance path", &instancepath, cli_absolute_path, NULL) == -1
|| cli_arg(argc, argv, o, "exec path", &execpath, cli_absolute_path, NULL) == -1)
int foregroundP = parsed->argc >= 2 && !strcasecmp(parsed->args[1], "foreground");
if (cli_arg(parsed, "instance path", &instancepath, cli_absolute_path, NULL) == -1
|| cli_arg(parsed, "exec path", &execpath, cli_absolute_path, NULL) == -1)
return -1;
if (instancepath != NULL)
serval_setinstancepath(instancepath);
@ -831,13 +832,14 @@ int app_server_start(int argc, const char *const *argv, const struct command_lin
return ret;
}
int app_server_stop(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_server_stop(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
int pid, tries, running;
const char *instancepath;
time_ms_t timeout;
if (cli_arg(argc, argv, o, "instance path", &instancepath, cli_absolute_path, NULL) == -1)
if (cli_arg(parsed, "instance path", &instancepath, cli_absolute_path, NULL) == -1)
return WHY("Unable to determine instance path");
if (instancepath != NULL)
serval_setinstancepath(instancepath);
@ -892,12 +894,13 @@ int app_server_stop(int argc, const char *const *argv, const struct command_line
return 0;
}
int app_server_status(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_server_status(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
int pid;
const char *instancepath;
if (cli_arg(argc, argv, o, "instance path", &instancepath, cli_absolute_path, NULL) == -1)
if (cli_arg(parsed, "instance path", &instancepath, cli_absolute_path, NULL) == -1)
return WHY("Unable to determine instance path");
if (instancepath != NULL)
serval_setinstancepath(instancepath);
@ -919,13 +922,14 @@ int app_server_status(int argc, const char *const *argv, const struct command_li
return pid > 0 ? 0 : 1;
}
int app_mdp_ping(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_mdp_ping(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *sid, *count;
if (cli_arg(argc, argv, o, "SID|broadcast", &sid, str_is_subscriber_id, "broadcast") == -1)
if (cli_arg(parsed, "SID|broadcast", &sid, str_is_subscriber_id, "broadcast") == -1)
return -1;
if (cli_arg(argc, argv, o, "count", &count, NULL, "0") == -1)
if (cli_arg(parsed, "count", &count, NULL, "0") == -1)
return -1;
// assume we wont hear any responses
@ -1066,9 +1070,10 @@ int app_mdp_ping(int argc, const char *const *argv, const struct command_line_op
return ret;
}
int app_config_schema(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_config_schema(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
if (create_serval_instance_dir() == -1)
return -1;
struct cf_om_node *root = NULL;
@ -1086,9 +1091,10 @@ int app_config_schema(int argc, const char *const *argv, const struct command_li
return 0;
}
int app_config_set(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_config_set(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
if (create_serval_instance_dir() == -1)
return -1;
// <kludge>
@ -1107,26 +1113,27 @@ int app_config_set(int argc, const char *const *argv, const struct command_line_
if (cf_om_reload() == -1)
return -1;
// </kludge>
const char *var[argc - 1];
const char *val[argc - 1];
const char *var[parsed->argc - 1];
const char *val[parsed->argc - 1];
int nvar = 0;
int i;
for (i = 1; i < argc; ++i) {
for (i = 1; i < parsed->argc; ++i) {
const char *arg = parsed->args[i];
int iv;
if (strcmp(argv[i], "set") == 0) {
if (i + 2 > argc)
return WHYF("malformed command at argv[%d]: 'set' not followed by two arguments", i);
var[nvar] = argv[iv = ++i];
val[nvar] = argv[++i];
} else if (strcmp(argv[i], "del") == 0) {
if (i + 1 > argc)
return WHYF("malformed command at argv[%d]: 'del' not followed by one argument", i);
var[nvar] = argv[iv = ++i];
if (strcmp(arg, "set") == 0) {
if (i + 2 > parsed->argc)
return WHYF("malformed command at args[%d]: 'set' not followed by two arguments", i);
var[nvar] = parsed->args[iv = ++i];
val[nvar] = parsed->args[++i];
} else if (strcmp(arg, "del") == 0) {
if (i + 1 > parsed->argc)
return WHYF("malformed command at args[%d]: 'del' not followed by one argument", i);
var[nvar] = parsed->args[iv = ++i];
val[nvar] = NULL;
} else
return WHYF("malformed command at argv[%d]: unsupported action '%s'", i, argv[i]);
return WHYF("malformed command at args[%d]: unsupported action '%s'", i, arg);
if (!is_configvarname(var[nvar]))
return WHYF("malformed command at argv[%d]: '%s' is not a valid config option name", iv, var[nvar]);
return WHYF("malformed command at args[%d]: '%s' is not a valid config option name", iv, var[nvar]);
++nvar;
}
for (i = 0; i < nvar; ++i)
@ -1139,11 +1146,12 @@ int app_config_set(int argc, const char *const *argv, const struct command_line_
return 0;
}
int app_config_get(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_config_get(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *var;
if (cli_arg(argc, argv, o, "variable", &var, is_configvarpattern, NULL) == -1)
if (cli_arg(parsed, "variable", &var, is_configvarpattern, NULL) == -1)
return -1;
if (create_serval_instance_dir() == -1)
return -1;
@ -1173,13 +1181,14 @@ int app_config_get(int argc, const char *const *argv, const struct command_line_
return 0;
}
int app_rhizome_hash_file(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_rhizome_hash_file(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
/* compute hash of file. We do this without a manifest, so it will necessarily
return the hash of the file unencrypted. */
const char *filepath;
cli_arg(argc, argv, o, "filepath", &filepath, NULL, "");
cli_arg(parsed, "filepath", &filepath, NULL, "");
char hexhash[RHIZOME_FILEHASH_STRLEN + 1];
if (rhizome_hash_file(NULL,filepath, hexhash))
return -1;
@ -1188,16 +1197,17 @@ int app_rhizome_hash_file(int argc, const char *const *argv, const struct comman
return 0;
}
int app_rhizome_add_file(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_rhizome_add_file(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *filepath, *manifestpath, *authorSidHex, *pin, *bskhex;
cli_arg(argc, argv, o, "filepath", &filepath, NULL, "");
if (cli_arg(argc, argv, o, "author_sid", &authorSidHex, cli_optional_sid, "") == -1)
cli_arg(parsed, "filepath", &filepath, NULL, "");
if (cli_arg(parsed, "author_sid", &authorSidHex, cli_optional_sid, "") == -1)
return -1;
cli_arg(argc, argv, o, "pin", &pin, NULL, "");
cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "");
if (cli_arg(argc, argv, o, "bsk", &bskhex, cli_optional_bundle_key, NULL) == -1)
cli_arg(parsed, "pin", &pin, NULL, "");
cli_arg(parsed, "manifestpath", &manifestpath, NULL, "");
if (cli_arg(parsed, "bsk", &bskhex, cli_optional_bundle_key, NULL) == -1)
return -1;
sid_t authorSid;
@ -1312,12 +1322,13 @@ int app_rhizome_add_file(int argc, const char *const *argv, const struct command
return ret;
}
int app_rhizome_import_bundle(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_rhizome_import_bundle(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *filepath, *manifestpath;
cli_arg(argc, argv, o, "filepath", &filepath, NULL, "");
cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "");
cli_arg(parsed, "filepath", &filepath, NULL, "");
cli_arg(parsed, "manifestpath", &manifestpath, NULL, "");
if (rhizome_opendb() == -1)
return -1;
@ -1366,12 +1377,13 @@ cleanup:
return status;
}
int app_rhizome_append_manifest(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_rhizome_append_manifest(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *manifestpath, *filepath;
if (cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "") == -1
|| cli_arg(argc, argv, o, "filepath", &filepath, NULL, "") == -1)
if ( cli_arg(parsed, "manifestpath", &manifestpath, NULL, "") == -1
|| cli_arg(parsed, "filepath", &filepath, NULL, "") == -1)
return -1;
rhizome_manifest *m = rhizome_new_manifest();
@ -1392,15 +1404,16 @@ int app_rhizome_append_manifest(int argc, const char *const *argv, const struct
return ret;
}
int app_rhizome_extract_bundle(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_rhizome_extract_bundle(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *manifestpath, *filepath, *manifestid, *pins, *bskhex;
if (cli_arg(argc, argv, o, "manifestid", &manifestid, cli_manifestid, "") == -1
|| cli_arg(argc, argv, o, "manifestpath", &manifestpath, NULL, "") == -1
|| cli_arg(argc, argv, o, "filepath", &filepath, NULL, "") == -1
|| cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, "") == -1
|| cli_arg(argc, argv, o, "bsk", &bskhex, cli_optional_bundle_key, NULL) == -1)
if ( cli_arg(parsed, "manifestid", &manifestid, cli_manifestid, "") == -1
|| cli_arg(parsed, "manifestpath", &manifestpath, NULL, "") == -1
|| cli_arg(parsed, "filepath", &filepath, NULL, "") == -1
|| cli_arg(parsed, "pin,pin...", &pins, NULL, "") == -1
|| cli_arg(parsed, "bsk", &bskhex, cli_optional_bundle_key, NULL) == -1)
return -1;
/* Ensure the Rhizome database exists and is open */
@ -1491,12 +1504,13 @@ int app_rhizome_extract_bundle(int argc, const char *const *argv, const struct c
return ret;
}
int app_rhizome_dump_file(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_rhizome_dump_file(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *fileid, *filepath;
if (cli_arg(argc, argv, o, "filepath", &filepath, NULL, "") == -1
|| cli_arg(argc, argv, o, "fileid", &fileid, cli_fileid, NULL) == -1)
if ( cli_arg(parsed, "filepath", &filepath, NULL, "") == -1
|| cli_arg(parsed, "fileid", &fileid, cli_fileid, NULL) == -1)
return -1;
if (create_serval_instance_dir() == -1)
@ -1519,17 +1533,18 @@ int app_rhizome_dump_file(int argc, const char *const *argv, const struct comman
return 0;
}
int app_rhizome_list(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_rhizome_list(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *pins, *service, *name, *sender_sid, *recipient_sid, *offset, *limit;
cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, "");
cli_arg(argc, argv, o, "service", &service, NULL, "");
cli_arg(argc, argv, o, "name", &name, NULL, "");
cli_arg(argc, argv, o, "sender_sid", &sender_sid, cli_optional_sid, "");
cli_arg(argc, argv, o, "recipient_sid", &recipient_sid, cli_optional_sid, "");
cli_arg(argc, argv, o, "offset", &offset, cli_uint, "0");
cli_arg(argc, argv, o, "limit", &limit, cli_uint, "0");
cli_arg(parsed, "pin,pin...", &pins, NULL, "");
cli_arg(parsed, "service", &service, NULL, "");
cli_arg(parsed, "name", &name, NULL, "");
cli_arg(parsed, "sender_sid", &sender_sid, cli_optional_sid, "");
cli_arg(parsed, "recipient_sid", &recipient_sid, cli_optional_sid, "");
cli_arg(parsed, "offset", &offset, cli_uint, "0");
cli_arg(parsed, "limit", &limit, cli_uint, "0");
/* Create the instance directory if it does not yet exist */
if (create_serval_instance_dir() == -1)
return -1;
@ -1540,21 +1555,23 @@ int app_rhizome_list(int argc, const char *const *argv, const struct command_lin
return rhizome_list_manifests(service, name, sender_sid, recipient_sid, atoi(offset), atoi(limit), 0);
}
int app_keyring_create(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_keyring_create(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *pin;
cli_arg(argc, argv, o, "pin,pin...", &pin, NULL, "");
cli_arg(parsed, "pin,pin...", &pin, NULL, "");
if (!keyring_open_with_pins(pin))
return -1;
return 0;
}
int app_keyring_list(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_keyring_list(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *pins;
cli_arg(argc, argv, o, "pin,pin...", &pins, NULL, "");
cli_arg(parsed, "pin,pin...", &pins, NULL, "");
keyring_file *k = keyring_open_with_pins(pins);
if (!k)
return -1;
@ -1577,11 +1594,12 @@ int app_keyring_list(int argc, const char *const *argv, const struct command_lin
return 0;
}
int app_keyring_add(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_keyring_add(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *pin;
cli_arg(argc, argv, o, "pin", &pin, NULL, "");
cli_arg(parsed, "pin", &pin, NULL, "");
keyring_file *k = keyring_open_with_pins("");
if (!k)
return -1;
@ -1622,14 +1640,15 @@ int app_keyring_add(int argc, const char *const *argv, const struct command_line
return 0;
}
int app_keyring_set_did(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_keyring_set_did(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *sid, *did, *pin, *name;
cli_arg(argc, argv, o, "sid", &sid, str_is_subscriber_id, "");
cli_arg(argc, argv, o, "did", &did, cli_optional_did, "");
cli_arg(argc, argv, o, "name", &name, NULL, "");
cli_arg(argc, argv, o, "pin", &pin, NULL, "");
cli_arg(parsed, "sid", &sid, str_is_subscriber_id, "");
cli_arg(parsed, "did", &did, cli_optional_did, "");
cli_arg(parsed, "name", &name, NULL, "");
cli_arg(parsed, "pin", &pin, NULL, "");
if (strlen(name)>63) return WHY("Name too long (31 char max)");
@ -1651,9 +1670,10 @@ int app_keyring_set_did(int argc, const char *const *argv, const struct command_
return 0;
}
int app_id_self(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_id_self(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
/* List my own identities */
overlay_mdp_frame a;
bzero(&a, sizeof(overlay_mdp_frame));
@ -1661,14 +1681,15 @@ int app_id_self(int argc, const char *const *argv, const struct command_line_opt
int count=0;
a.packetTypeAndFlags=MDP_GETADDRS;
if (!strcasecmp(argv[1],"self"))
const char *arg = parsed->argc >= 2 ? parsed->args[1] : "";
if (!strcasecmp(arg,"self"))
a.addrlist.mode = MDP_ADDRLIST_MODE_SELF; /* get own identities */
else if (!strcasecmp(argv[1],"allpeers"))
else if (!strcasecmp(arg,"allpeers"))
a.addrlist.mode = MDP_ADDRLIST_MODE_ALL_PEERS; /* get all known peers */
else if (!strcasecmp(argv[1],"peers"))
else if (!strcasecmp(arg,"peers"))
a.addrlist.mode = MDP_ADDRLIST_MODE_ROUTABLE_PEERS; /* get routable (reachable) peers */
else
return WHYF("unsupported arg '%s'", argv[1]);
return WHYF("unsupported arg '%s'", arg);
a.addrlist.first_sid=0;
do{
@ -1698,8 +1719,10 @@ int app_id_self(int argc, const char *const *argv, const struct command_line_opt
return 0;
}
int app_count_peers(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_count_peers(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose)
DEBUG_parsed(parsed);
overlay_mdp_frame a;
bzero(&a, sizeof(overlay_mdp_frame));
a.packetTypeAndFlags=MDP_GETADDRS;
@ -1715,9 +1738,10 @@ int app_count_peers(int argc, const char *const *argv, const struct command_line
return 0;
}
int app_crypt_test(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_crypt_test(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
unsigned char nonce[crypto_box_curve25519xsalsa20poly1305_NONCEBYTES];
unsigned char k[crypto_box_curve25519xsalsa20poly1305_BEFORENMBYTES];
@ -1878,11 +1902,12 @@ int app_crypt_test(int argc, const char *const *argv, const struct command_line_
return 0;
}
int app_node_info(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_node_info(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose) DEBUG_argv("command", argc, argv);
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *sid;
cli_arg(argc, argv, o, "sid", &sid, NULL, "");
cli_arg(parsed, "sid", &sid, NULL, "");
overlay_mdp_frame mdp;
bzero(&mdp,sizeof(mdp));
@ -1925,8 +1950,10 @@ int app_node_info(int argc, const char *const *argv, const struct command_line_o
return 0;
}
int app_route_print(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_route_print(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose)
DEBUG_parsed(parsed);
overlay_mdp_frame mdp;
bzero(&mdp,sizeof(mdp));
@ -1967,16 +1994,16 @@ int app_route_print(int argc, const char *const *argv, const struct command_line
return 0;
}
int app_reverse_lookup(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_reverse_lookup(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose)
DEBUG_parsed(parsed);
const char *sid, *delay;
if (cli_arg(argc, argv, o, "sid", &sid, str_is_subscriber_id, "") == -1)
if (cli_arg(parsed, "sid", &sid, str_is_subscriber_id, "") == -1)
return -1;
if (cli_arg(argc, argv, o, "timeout", &delay, NULL, "3000") == -1)
if (cli_arg(parsed, "timeout", &delay, NULL, "3000") == -1)
return -1;
int port=32768+(random()&0xffff);
unsigned char srcsid[SID_SIZE];
@ -2063,8 +2090,10 @@ int app_reverse_lookup(int argc, const char *const *argv, const struct command_l
return 0;
}
int app_network_scan(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_network_scan(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose)
DEBUG_parsed(parsed);
overlay_mdp_frame mdp;
bzero(&mdp,sizeof(mdp));
@ -2072,7 +2101,7 @@ int app_network_scan(int argc, const char *const *argv, const struct command_lin
struct overlay_mdp_scan *scan = (struct overlay_mdp_scan *)&mdp.raw;
const char *address;
if (cli_arg(argc, argv, o, "address", &address, NULL, NULL) == -1)
if (cli_arg(parsed, "address", &address, NULL, NULL) == -1)
return -1;
if (address){
@ -2112,7 +2141,7 @@ struct command_line_option command_line_options[]={
"Lookup the SIP/MDP address of the supplied telephone number (DID)."},
{commandline_usage,{"help",NULL},CLIFLAG_PERMISSIVE_CONFIG,
"Display command usage."},
{app_echo,{"echo","...",NULL},CLIFLAG_STANDALONE,
{app_echo,{"echo","[-e]","[--]","...",NULL},CLIFLAG_STANDALONE,
"Output the supplied string."},
{app_server_start,{"start",NULL},CLIFLAG_STANDALONE,
"Start Serval Mesh node process with instance path taken from SERVALINSTANCE_PATH environment variable."},

@ -5,6 +5,7 @@ HDRS= fifo.h \
overlay_packet.h \
rhizome.h \
serval.h \
cli.h \
str.h \
mem.h \
os.h \

@ -46,7 +46,7 @@ struct monitor_command_handler monitor_handlers[]={
{.command="", .handler=remote_print},
};
int app_monitor_cli(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_monitor_cli(const struct parsed_command *parsed, void *context)
{
struct pollfd fds[2];
struct monitor_state *state;

@ -382,23 +382,24 @@ void monitor_get_all_supported_codecs(unsigned char *codecs){
}
}
static int monitor_set(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int monitor_set(const struct parsed_command *parsed, void *context)
{
struct monitor_context *c=context;
if (strcase_startswith((char *)argv[1],"vomp",NULL)){
if (strcase_startswith(parsed->args[1],"vomp",NULL)){
c->flags|=MONITOR_VOMP;
// store the list of supported codecs against the monitor connection,
// since we need to forget about them when the client disappears.
int i;
for (i=2;i<argc;i++){
int codec = atoi(argv[i]);
for (i = 2; i < parsed->argc; ++i) {
int codec = atoi(parsed->args[i]);
if (codec>=0 && codec <=255)
set_codec_flag(codec, c->supported_codecs);
}
}else if (strcase_startswith((char *)argv[1],"rhizome", NULL))
}else if (strcase_startswith(parsed->args[1],"rhizome", NULL))
c->flags|=MONITOR_RHIZOME;
else if (strcase_startswith((char *)argv[1],"peers", NULL))
else if (strcase_startswith(parsed->args[1],"peers", NULL))
c->flags|=MONITOR_PEERS;
else if (strcase_startswith((char *)argv[1],"dnahelper", NULL))
else if (strcase_startswith(parsed->args[1],"dnahelper", NULL))
c->flags|=MONITOR_DNAHELPER;
else
return monitor_write_error(c,"Unknown monitor type");
@ -410,15 +411,16 @@ static int monitor_set(int argc, const char *const *argv, const struct command_l
return 0;
}
static int monitor_clear(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int monitor_clear(const struct parsed_command *parsed, void *context)
{
struct monitor_context *c=context;
if (strcase_startswith((char *)argv[1],"vomp",NULL))
if (strcase_startswith(parsed->args[1],"vomp",NULL))
c->flags&=~MONITOR_VOMP;
else if (strcase_startswith((char *)argv[1],"rhizome", NULL))
else if (strcase_startswith(parsed->args[1],"rhizome", NULL))
c->flags&=~MONITOR_RHIZOME;
else if (strcase_startswith((char *)argv[1],"peers", NULL))
else if (strcase_startswith(parsed->args[1],"peers", NULL))
c->flags&=~MONITOR_PEERS;
else if (strcase_startswith((char *)argv[1],"dnahelper", NULL))
else if (strcase_startswith(parsed->args[1],"dnahelper", NULL))
c->flags&=~MONITOR_DNAHELPER;
else
return monitor_write_error(c,"Unknown monitor type");
@ -430,17 +432,18 @@ static int monitor_clear(int argc, const char *const *argv, const struct command
return 0;
}
static int monitor_lookup_match(int argc, const char *const *argv, const struct command_line_option *o, void *context){
struct monitor_context *c=context;
const char *sid=argv[2];
const char *ext=argv[4];
const char *name=argc>=4?argv[5]:"";
static int monitor_lookup_match(const struct parsed_command *parsed, void *context)
{
struct monitor_context *c = context;
const char *sid = parsed->args[2];
const char *ext = parsed->args[4];
const char *name = parsed->argc >= 4 ? parsed->args[5] : "";
if (!my_subscriber)
return monitor_write_error(c,"I don't know who I am");
struct sockaddr_mdp addr={
.port = atoi(argv[3]),
.port = atoi(parsed->args[3]),
};
if (stowSid((unsigned char *)&addr.sid, 0, sid)==-1)
@ -453,69 +456,75 @@ static int monitor_lookup_match(int argc, const char *const *argv, const struct
return 0;
}
static int monitor_call(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int monitor_call(const struct parsed_command *parsed, void *context)
{
struct monitor_context *c=context;
unsigned char sid[SID_SIZE];
if (stowSid(sid, 0, argv[1]) == -1)
if (stowSid(sid, 0, parsed->args[1]) == -1)
return monitor_write_error(c,"invalid SID, so cannot place call");
if (!my_subscriber)
return monitor_write_error(c,"I don't know who I am");
struct subscriber *remote = find_subscriber(sid, SID_SIZE, 1);
vomp_dial(my_subscriber, remote, argv[2], argv[3]);
vomp_dial(my_subscriber, remote, parsed->args[2], parsed->args[3]);
return 0;
}
static int monitor_call_ring(int argc, const char *const *argv, const struct command_line_option *o, void *context){
struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16));
static int monitor_call_ring(const struct parsed_command *parsed, void *context)
{
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
if (!call)
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", argv[1]);
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", parsed->args[1]);
else
vomp_ringing(call);
return 0;
}
static int monitor_call_pickup(int argc, const char *const *argv, const struct command_line_option *o, void *context){
struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16));
static int monitor_call_pickup(const struct parsed_command *parsed, void *context)
{
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
if (!call)
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", argv[1]);
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", parsed->args[1]);
else
vomp_pickup(call);
return 0;
}
static int monitor_call_audio(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int monitor_call_audio(const struct parsed_command *parsed, void *context)
{
struct monitor_context *c=context;
struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16));
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
if (!call){
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", argv[1]);
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", parsed->args[1]);
return 0;
}
int codec_type = atoi(argv[2]);
int time = argc>=4?atoi(argv[3]):-1;
int sequence = argc>=5?atoi(argv[4]):-1;
int codec_type = atoi(parsed->args[2]);
int time = parsed->argc >=4 ? atoi(parsed->args[3]) : -1;
int sequence = parsed->argc >= 5 ? atoi(parsed->args[4]) : -1;
vomp_received_audio(call, codec_type, time, sequence, c->buffer, c->data_expected);
return 0;
}
static int monitor_call_hangup(int argc, const char *const *argv, const struct command_line_option *o, void *context){
struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16));
static int monitor_call_hangup(const struct parsed_command *parsed, void *context)
{
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
if (!call)
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", argv[1]);
monitor_tell_formatted(MONITOR_VOMP, "\nHANGUP:%s\n", parsed->args[1]);
else
vomp_hangup(call);
return 0;
}
static int monitor_call_dtmf(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int monitor_call_dtmf(const struct parsed_command *parsed, void *context)
{
struct monitor_context *c=context;
struct vomp_call_state *call=vomp_find_call_by_session(strtol(argv[1],NULL,16));
struct vomp_call_state *call=vomp_find_call_by_session(strtol(parsed->args[1],NULL,16));
if (!call)
return monitor_write_error(c,"Invalid call token");
const char *digits = argv[2];
const char *digits = parsed->args[2];
int i;
for(i=0;i<strlen(digits);i++) {
@ -552,8 +561,9 @@ int monitor_process_command(struct monitor_context *c)
char *argv[16]={NULL,};
int argc = parse_argv(c->line, ' ', argv, 16);
int res = cli_parse(argc, (const char *const*)argv, monitor_options);
if (res == -1 || cli_invoke(&monitor_options[res], argc, (const char *const*)argv, c))
struct parsed_command parsed;
int res = cli_parse(argc, (const char *const*)argv, monitor_options, &parsed);
if (res == -1 || cli_invoke(&parsed, c))
return monitor_write_error(c, "Invalid command");
return 0;
}

@ -513,25 +513,27 @@ static int rhizome_sync_with_peers(int mode, int peer_count, const struct config
return 0;
}
int app_rhizome_direct_sync(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_rhizome_direct_sync(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose)
DEBUG_parsed(parsed);
/* Attempt to connect with a remote Rhizome Direct instance,
and negotiate which BARs to synchronise. */
const char *modeName = (argc >= 3 ? argv[2] : "sync");
const char *modeName = (parsed->argc >= 3 ? parsed->args[2] : "sync");
int mode=3; /* two-way sync */
if (!strcasecmp(modeName,"push")) mode=1; /* push only */
if (!strcasecmp(modeName,"pull")) mode=2; /* pull only */
DEBUGF("sync direction = %d",mode);
if (argv[3]) {
if (parsed->args[3]) {
struct config_rhizome_peer peer;
const struct config_rhizome_peer *peers[1] = { &peer };
int result = cf_opt_rhizome_peer_from_uri(&peer, argv[3]);
int result = cf_opt_rhizome_peer_from_uri(&peer, parsed->args[3]);
if (result == CFOK)
return rhizome_sync_with_peers(mode, 1, peers);
else {
strbuf b = strbuf_alloca(128);
strbuf_cf_flag_reason(b, result);
return WHYF("Invalid peer URI %s -- %s", alloca_str_toprint(argv[3]), strbuf_str(b));
return WHYF("Invalid peer URI %s -- %s", alloca_str_toprint(parsed->args[3]), strbuf_str(b));
}
} else if (config.rhizome.direct.peer.ac == 0) {
DEBUG("No rhizome direct peers were configured or supplied");

@ -109,6 +109,7 @@ struct in_addr {
#include <ctype.h>
#include <sys/stat.h>
#include "cli.h"
#include "constants.h"
#include "mem.h"
#include "xprintf.h"
@ -656,12 +657,12 @@ int directory_registration();
int directory_service_init();
struct command_line_option;
int app_rhizome_direct_sync(int argc, const char *const *argv, const struct command_line_option *o, void *context);
int app_rhizome_direct_sync(const struct parsed_command *parsed, void *context);
#ifdef HAVE_VOIPTEST
int app_pa_phone(int argc, const char *const *argv, const struct command_line_option *o, void *context);
int app_pa_phone(const struct parsed_command *parsed, void *context);
#endif
int app_monitor_cli(int argc, const char *const *argv, const struct command_line_option *o, void *context);
int app_vomp_console(int argc, const char *const *argv, const struct command_line_option *o, void *context);
int app_monitor_cli(const struct parsed_command *parsed, void *context);
int app_vomp_console(const struct parsed_command *parsed, void *context);
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);

@ -186,19 +186,21 @@ struct monitor_command_handler console_handlers[]={
{.command="MONITORSTATUS", .handler=remote_noop},
};
static int console_dial(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int console_dial(const struct parsed_command *parsed, void *context)
{
if (call_token!=-1){
printf("Already in a call\n");
return 0;
}
const char *sid=argv[1];
const char *local=argc>=3?argv[2]:"";
const char *remote=argc>=4?argv[3]:"";
const char *sid = parsed->args[1];
const char *local = parsed->argc >= 3 ? parsed->args[2] : "";
const char *remote = parsed->argc >= 4 ? parsed->args[3] : "";
send_call(sid, local, remote);
return 0;
}
static int console_answer(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int console_answer(const struct parsed_command *parsed, void *context)
{
if (call_token==-1){
printf("No active call to answer\n");
fflush(stdout);
@ -207,7 +209,8 @@ static int console_answer(int argc, const char *const *argv, const struct comman
return 0;
}
static int console_hangup(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int console_hangup(const struct parsed_command *parsed, void *context)
{
if (call_token==-1){
printf("No call to hangup\n");
fflush(stdout);
@ -216,7 +219,8 @@ static int console_hangup(int argc, const char *const *argv, const struct comman
return 0;
}
static int console_audio(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int console_audio(const struct parsed_command *parsed, void *context)
{
if (call_token==-1){
printf("No active call\n");
fflush(stdout);
@ -225,11 +229,11 @@ static int console_audio(int argc, const char *const *argv, const struct command
static struct strbuf str_buf = STRUCT_STRBUF_EMPTY;
int i;
strbuf_init(&str_buf, buf, sizeof(buf));
for (i = 0; i < argc; ++i) {
for (i = 0; i < parsed->argc; ++i) {
if (i)
strbuf_putc(&str_buf, ' ');
if (argv[i])
strbuf_toprint_quoted(&str_buf, "\"\"", argv[i]);
if (parsed->args[i])
strbuf_toprint_quoted(&str_buf, "\"\"", parsed->args[i]);
else
strbuf_puts(&str_buf, "NULL");
}
@ -239,7 +243,7 @@ static int console_audio(int argc, const char *const *argv, const struct command
return 0;
}
static int console_usage(int argc, const char *const *argv, const struct command_line_option *o, void *context);
static int console_usage(const struct parsed_command *parsed, void *context);
struct command_line_option console_commands[]={
{console_answer,{"answer",NULL},0,"Answer an incoming phone call"},
@ -250,7 +254,8 @@ struct command_line_option console_commands[]={
{NULL},
};
static int console_usage(int argc, const char *const *argv, const struct command_line_option *o, void *context){
static int console_usage(const struct parsed_command *parsed, void *context)
{
cli_usage(console_commands);
fflush(stdout);
return 0;
@ -260,12 +265,13 @@ static void console_command(char *line){
char *argv[16];
int argc = parse_argv(line, ' ', argv, 16);
int ret = cli_parse(argc, (const char *const*)argv, console_commands);
struct parsed_command parsed;
int ret = cli_parse(argc, (const char *const*)argv, console_commands, &parsed);
if (ret == -1) {
printf("Unknown command, try help\n");
fflush(stdout);
} else {
cli_invoke(&console_commands[ret], argc, (const char *const*)argv, NULL);
cli_invoke(&parsed, NULL);
}
}
@ -306,8 +312,10 @@ static void monitor_read(struct sched_ent *alarm){
}
}
int app_vomp_console(int argc, const char *const *argv, const struct command_line_option *o, void *context)
int app_vomp_console(const struct parsed_command *parsed, void *context)
{
if (config.debug.verbose)
DEBUG_parsed(parsed);
static struct profile_total stdin_profile={
.name="read_lines",
};