serval-dna/meshms_cli.c

241 lines
8.6 KiB
C
Raw Normal View History

2016-06-29 02:07:38 +00:00
#include <inttypes.h>
#include "serval_types.h"
#include "dataformats.h"
#include "cli.h"
#include "keyring.h"
2016-06-29 02:07:38 +00:00
#include "meshms.h"
#include "log.h"
#include "debug.h"
#include "instance.h"
#include "conf.h"
#include "commandline.h"
2016-09-20 04:03:19 +00:00
#include "str.h"
#include "numeric_str.h"
2016-06-29 02:07:38 +00:00
Switch to feature-driven linking This introduces a new way of linking Serval executables and dynamic libraries from static libraries like libservald.a -- called "feature-driven" linking. The Makefile now links servald and serval-tests from libservald.a, rather than from an explicit list of object (.o) files. Thanks to the section-based method for registering functions such as HTTP handlers, CLI commands and MDP handlers, these object files had become "stand-alone" and hence were no longer included in the link because there was no unresolved reference that required them to be linked in. The new "feature.h" provides the DECLARE_FEATURE(name) macro that each stand-alone source file uses to declare the named feature(s) it provides. Each executable can call the USE_FEATURE(name) macro in any of its explicitly-linked source files to cause the corresponding object(s) to be included in the link, eg, servald_features.c. The DEFINE_BINDING() macro has been extended so that every individual MDP binding is given a feature name based on its port number macro, eg, "mdp_binding_MDP_PORT_ECHO". Some features have been factored into their own separate source files so they can be omitted or included in a build independently of each other: - the MDP bindings for MDP_PORT_DNALOOKUP, MDP_PORT_ECHO, MDP_PORT_TRACE, MDP_PORT_KEYMAPREQUEST, MDP_PORT_RHIZOME_xxx, MDP_PORT_PROBE, MDP_PORT_STUN, MDP_PORT_STUNREQ - the CLI "log" and "echo" commands - the CLI "rhizome direct" command The JNI source files are only compiled if the <jni.h> header is present, otherwise they are omitted from libservald.so.
2016-10-13 02:58:23 +00:00
DEFINE_FEATURE(cli_meshms);
2016-06-29 02:07:38 +00:00
// output the list of existing conversations for a given local identity
DEFINE_CMD(app_meshms_conversations, 0,
"List MeshMS threads that include <sid>",
"meshms","list","conversations" KEYRING_PIN_OPTIONS, "[--include-message]", "<sid>","[<offset>]","[<count>]");
2016-06-29 02:07:38 +00:00
static int app_meshms_conversations(const struct cli_parsed *parsed, struct cli_context *context)
{
const char *sidhex, *offset_str, *count_str;
if (cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, "") == -1
|| cli_arg(parsed, "offset", &offset_str, NULL, "0")==-1
|| cli_arg(parsed, "count", &count_str, NULL, "-1")==-1)
return -1;
int include_message = cli_arg(parsed, "--include-message", NULL, NULL, NULL) == 0;
2016-06-29 02:07:38 +00:00
sid_t sid;
struct meshms_conversations *conv = NULL;
enum meshms_status status = MESHMS_STATUS_ERROR;
fromhex(sid.binary, sidhex, sizeof(sid.binary));
int offset=atoi(offset_str);
int count=atoi(count_str);
if (create_serval_instance_dir() == -1)
goto end;
assert(keyring == NULL);
2016-06-29 02:07:38 +00:00
if (!(keyring = keyring_open_instance_cli(parsed)))
goto end;
if (rhizome_opendb() == -1)
goto end;
if (meshms_failed(status = meshms_conversations_list(NULL, &sid, &conv)))
2016-06-29 02:07:38 +00:00
goto end;
const char *names[]={
"_id","recipient","read", "last_message", "read_offset", "message"
2016-06-29 02:07:38 +00:00
};
cli_start_table(context, include_message? NELS(names) : NELS(names) - 1, names);
2016-06-29 02:07:38 +00:00
int rows = 0;
if (conv) {
struct meshms_conversation_iterator it;
for (meshms_conversation_iterator_start(&it, conv);
it.current && (count < 0 || rows < offset + count);
meshms_conversation_iterator_advance(&it), ++rows
) {
if (rows >= offset) {
cli_put_long(context, rows, ":");
cli_put_hexvalue(context, it.current->them.binary, sizeof(it.current->them), ":");
cli_put_string(context, it.current->metadata.read_offset < it.current->metadata.their_last_message ? "unread":"", ":");
cli_put_long(context, it.current->metadata.their_last_message, ":");
cli_put_long(context, it.current->metadata.read_offset, include_message?":":"\n");
if (include_message){
int output = 0;
if (it.current->metadata.their_last_message && it.current->their_ply.found){
struct message_ply_read reader;
bzero(&reader, sizeof reader);
if (message_ply_read_open(&reader, &it.current->their_ply.bundle_id, NULL) == 0){
reader.read.offset = it.current->metadata.their_last_message;
if (message_ply_read_prev(&reader)==0){
cli_put_string(context, (const char *)reader.record, "\n");
output = 1;
}
message_ply_read_close(&reader);
}
}
if (!output)
cli_put_string(context, "", "\n");
}
2016-06-29 02:07:38 +00:00
}
}
}
cli_end_table(context, rows);
2016-06-29 02:07:38 +00:00
status=MESHMS_STATUS_OK;
end:
if (conv)
meshms_free_conversations(conv);
return status;
}
DEFINE_CMD(app_meshms_send_message, 0,
"Send a MeshMS message from <sender_sid> to <recipient_sid>",
"meshms","send","message" KEYRING_PIN_OPTIONS, "<sender_sid>", "<recipient_sid>", "<payload>");
static int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
{
const char *my_sidhex, *their_sidhex, *message;
if (cli_arg(parsed, "sender_sid", &my_sidhex, str_is_subscriber_id, "") == -1
|| cli_arg(parsed, "recipient_sid", &their_sidhex, str_is_subscriber_id, "") == -1
|| cli_arg(parsed, "payload", &message, NULL, "") == -1)
return -1;
2016-08-15 07:49:34 +00:00
sid_t my_sid, their_sid;
if (str_to_sid_t(&my_sid, my_sidhex) == -1)
return WHY("Invalid sender SID");
if (str_to_sid_t(&their_sid, their_sidhex) == -1)
return WHY("Invalid recipient SID");
2016-06-29 02:07:38 +00:00
if (create_serval_instance_dir() == -1)
return -1;
assert(keyring == NULL);
2016-06-29 02:07:38 +00:00
if (!(keyring = keyring_open_instance_cli(parsed)))
return -1;
if (rhizome_opendb() == -1)
2016-06-29 02:07:38 +00:00
return -1;
// include terminating NUL
enum meshms_status status = meshms_send_message(&my_sid, &their_sid, message, strlen(message) + 1);
return meshms_failed(status) ? status : 0;
}
DEFINE_CMD(app_meshms_list_messages, 0,
"List MeshMS messages between <sender_sid> and <recipient_sid>",
"meshms","list","messages" KEYRING_PIN_OPTIONS, "<sender_sid>","<recipient_sid>");
static int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context *context)
{
const char *my_sidhex, *their_sidhex;
if (cli_arg(parsed, "sender_sid", &my_sidhex, str_is_subscriber_id, "") == -1
|| cli_arg(parsed, "recipient_sid", &their_sidhex, str_is_subscriber_id, "") == -1)
return -1;
if (create_serval_instance_dir() == -1)
return -1;
assert(keyring == NULL);
2016-06-29 02:07:38 +00:00
if (!(keyring = keyring_open_instance_cli(parsed)))
return -1;
if (rhizome_opendb() == -1)
2016-06-29 02:07:38 +00:00
return -1;
sid_t my_sid, their_sid;
if (str_to_sid_t(&my_sid, my_sidhex) == -1)
2016-06-29 02:07:38 +00:00
return WHY("invalid sender SID");
if (str_to_sid_t(&their_sid, their_sidhex) == -1)
2016-06-29 02:07:38 +00:00
return WHY("invalid recipient SID");
struct meshms_message_iterator iter;
enum meshms_status status;
if (meshms_failed(status = meshms_message_iterator_open(&iter, &my_sid, &their_sid)))
2016-06-29 02:07:38 +00:00
return status;
const char *names[]={
"_id","my_offset","their_offset","age","type","message"
2016-06-29 02:07:38 +00:00
};
cli_start_table(context, NELS(names), names);
2016-06-29 02:07:38 +00:00
bool_t marked_delivered = 0;
bool_t marked_read = 0;
time_s_t now = gettime();
int id = 0;
while ((status = meshms_message_iterator_prev(&iter)) == MESHMS_STATUS_UPDATED) {
switch (iter.type) {
case MESSAGE_SENT:
if (iter.delivered && !marked_delivered){
cli_put_long(context, id++, ":");
cli_put_long(context, iter.my_offset, ":");
cli_put_long(context, iter.metadata.their_last_ack_offset, ":");
cli_put_long(context, iter.timestamp ? (long)(now - iter.timestamp):(long)-1, ":");
2016-06-29 02:07:38 +00:00
cli_put_string(context, "ACK", ":");
cli_put_string(context, "delivered", "\n");
marked_delivered = 1;
}
// TODO new message format here
cli_put_long(context, id++, ":");
cli_put_long(context, iter.my_offset, ":");
cli_put_long(context, iter.their_offset, ":");
cli_put_long(context, iter.timestamp ? (long)(now - iter.timestamp):(long)-1, ":");
2016-06-29 02:07:38 +00:00
cli_put_string(context, ">", ":");
cli_put_string(context, iter.text, "\n");
break;
case ACK_RECEIVED:
break;
case MESSAGE_RECEIVED:
if (iter.read && !marked_read) {
cli_put_long(context, id++, ":");
cli_put_long(context, iter.metadata.read_offset, ":");
cli_put_long(context, 0, ":");
cli_put_long(context, iter.timestamp ? (long)(now - iter.timestamp):(long)-1, ":");
2016-06-29 02:07:38 +00:00
cli_put_string(context, "MARK", ":");
cli_put_string(context, "read", "\n");
marked_read = 1;
}
// TODO new message format here
cli_put_long(context, id++, ":");
cli_put_long(context, iter.my_offset, ":");
cli_put_long(context, iter.their_offset, ":");
cli_put_long(context, iter.timestamp ? (long)(now - iter.timestamp):(long)-1, ":");
2016-06-29 02:07:38 +00:00
cli_put_string(context, "<", ":");
cli_put_string(context, iter.text, "\n");
break;
}
}
if (!meshms_failed(status))
cli_end_table(context, id);
2016-06-29 02:07:38 +00:00
meshms_message_iterator_close(&iter);
return status;
}
DEFINE_CMD(app_meshms_mark_read, 0,
"Mark incoming messages from this recipient as read.",
"meshms","read","messages" KEYRING_PIN_OPTIONS, "<sender_sid>", "[<recipient_sid>]", "[<offset>]");
static int app_meshms_mark_read(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
{
const char *my_sidhex, *their_sidhex, *offset_str;
if (cli_arg(parsed, "sender_sid", &my_sidhex, str_is_subscriber_id, "") == -1
|| cli_arg(parsed, "recipient_sid", &their_sidhex, str_is_subscriber_id, NULL) == -1
|| cli_arg(parsed, "offset", &offset_str, str_is_uint64_decimal, NULL)==-1)
return -1;
if (create_serval_instance_dir() == -1)
return -1;
assert(keyring == NULL);
2016-06-29 02:07:38 +00:00
if (!(keyring = keyring_open_instance_cli(parsed)))
return -1;
if (rhizome_opendb() == -1)
return -1;
2016-06-29 02:07:38 +00:00
sid_t my_sid, their_sid;
if (str_to_sid_t(&my_sid, my_sidhex) == -1)
return WHYF("my_sidhex=%s", my_sidhex);
if (their_sidhex && str_to_sid_t(&their_sid, their_sidhex) == -1)
return WHYF("their_sidhex=%s", their_sidhex);
2016-06-29 02:07:38 +00:00
uint64_t offset = UINT64_MAX;
if (offset_str) {
if (!their_sidhex)
return WHY("missing recipient_sid");
if (!str_to_uint64(offset_str, 10, &offset, NULL))
return WHYF("offset_str=%s", offset_str);
2016-06-29 02:07:38 +00:00
}
enum meshms_status status = meshms_mark_read(&my_sid, their_sidhex ? &their_sid : NULL, offset);
return (status == MESHMS_STATUS_UPDATED) ? MESHMS_STATUS_OK : status;
2016-06-29 02:07:38 +00:00
}