mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-07 11:08:36 +00:00
Allow for arbitrary extra manifest fields on broadcast messages
This commit is contained in:
parent
e13b9c3c94
commit
6a0b7a1da6
105
meshmb.c
105
meshmb.c
@ -8,17 +8,9 @@
|
||||
#include "commandline.h"
|
||||
#include "overlay_buffer.h"
|
||||
|
||||
/*
|
||||
DEFINE_CMD(app_meshmb_news, 0,
|
||||
"",
|
||||
"meshmb", "news" KEYRING_PIN_OPTIONS, "<sid>");
|
||||
static int app_meshmb_news(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
static int meshmb_send(keyring_identity *id, const char *message, size_t message_len,
|
||||
unsigned nassignments, const struct rhizome_manifest_field_assignment *assignments){
|
||||
|
||||
static int meshmb_send(keyring_identity *id, const char *message, size_t message_len){
|
||||
struct message_ply ply;
|
||||
bzero(&ply, sizeof ply);
|
||||
|
||||
@ -30,15 +22,16 @@ static int meshmb_send(keyring_identity *id, const char *message, size_t message
|
||||
message_ply_append_timestamp(b);
|
||||
assert(!ob_overrun(b));
|
||||
|
||||
int ret = message_ply_append(id, RHIZOME_SERVICE_MESHMB, NULL, &ply, b);
|
||||
// TODO add id card details to manifest
|
||||
int ret = message_ply_append(id, RHIZOME_SERVICE_MESHMB, NULL, &ply, b, nassignments, assignments);
|
||||
ob_free(b);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DEFINE_CMD(app_meshmb_send, 0,
|
||||
"",
|
||||
"meshmb", "send" KEYRING_PIN_OPTIONS, "<id>", "<message>");
|
||||
"Append a public broadcast message to your feed",
|
||||
"meshmb", "send" KEYRING_PIN_OPTIONS, "<id>", "<message>", "...");
|
||||
static int app_meshmb_send(const struct cli_parsed *parsed, struct cli_context *UNUSED(context))
|
||||
{
|
||||
const char *idhex, *message;
|
||||
@ -46,6 +39,14 @@ static int app_meshmb_send(const struct cli_parsed *parsed, struct cli_context *
|
||||
|| cli_arg(parsed, "message", &message, NULL, "") == -1)
|
||||
return -1;
|
||||
|
||||
unsigned nfields = (parsed->varargi == -1) ? 0 : parsed->argc - (unsigned)parsed->varargi;
|
||||
struct rhizome_manifest_field_assignment fields[nfields];
|
||||
if (nfields) {
|
||||
assert(parsed->varargi >= 0);
|
||||
if (rhizome_parse_field_assignments(fields, nfields, parsed->args + parsed->varargi)==-1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
identity_t identity;
|
||||
if (str_to_identity_t(&identity, idhex) == -1)
|
||||
return WHY("Invalid identity");
|
||||
@ -65,41 +66,15 @@ static int app_meshmb_send(const struct cli_parsed *parsed, struct cli_context *
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret = meshmb_send(id, message, strlen(message)+1);
|
||||
ret = meshmb_send(id, message, strlen(message)+1, nfields, fields);
|
||||
end:
|
||||
keyring_free(keyring);
|
||||
keyring = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
DEFINE_CMD(app_meshmb_list, 0,
|
||||
"",
|
||||
"meshmb", "list", "following|blocked" KEYRING_PIN_OPTIONS, "--last-message", "<sid>");
|
||||
static int app_meshmb_list(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_CMD(app_meshmb_follow, 0,
|
||||
"",
|
||||
"meshmb", "follow|ignore|block" KEYRING_PIN_OPTIONS, "<sid>", "<id>");
|
||||
static int app_meshmb_follow(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_CMD(app_meshmb_find, 0,
|
||||
"",
|
||||
"meshmb", "find", "[<search>]");
|
||||
static int app_meshmb_find(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
DEFINE_CMD(app_meshmb_read, 0,
|
||||
"",
|
||||
"Read a broadcast message feed.",
|
||||
"meshmb", "read", "<id>");
|
||||
static int app_meshmb_read(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
@ -163,3 +138,51 @@ static int app_meshmb_read(const struct cli_parsed *parsed, struct cli_context *
|
||||
message_ply_read_close(&read);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
DEFINE_CMD(app_meshmb_find, 0,
|
||||
"Browse available broadcast message feeds",
|
||||
"meshmb", "find", "[<search>]");
|
||||
static int app_meshmb_find(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
|
||||
// Ensure the Rhizome database exists and is open
|
||||
if (create_serval_instance_dir() == -1)
|
||||
return -1;
|
||||
if (rhizome_opendb() == -1)
|
||||
return -1;
|
||||
|
||||
sqlite_retry_state retry = SQLITE_RETRY_STATE_DEFAULT;
|
||||
sqlite3_stmt *statement = sqlite_prepare(&retry,
|
||||
"SELECT ROWID, MANIFEST FROM MANIFESTS WHERE SERVICE = '"RHIZOME_SERVICE_MESHMB"' ORDER BY ROWID DESC;");
|
||||
while (sqlite_step_retry(&retry, statement) == SQLITE_ROW) {
|
||||
}
|
||||
|
||||
//TODO hide feeds that have been blocked
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_CMD(app_meshmb_follow, 0,
|
||||
"",
|
||||
"meshmb", "follow|ignore|block" KEYRING_PIN_OPTIONS, "<id>", "<peer>");
|
||||
static int app_meshmb_follow(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_CMD(app_meshmb_list, 0,
|
||||
"",
|
||||
"meshmb", "list", "following|blocked" KEYRING_PIN_OPTIONS, "--last-message", "<id>");
|
||||
static int app_meshmb_list(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_CMD(app_meshmb_news, 0,
|
||||
"",
|
||||
"meshmb", "news" KEYRING_PIN_OPTIONS, "<sid>");
|
||||
static int app_meshmb_news(const struct cli_parsed *parsed, struct cli_context *context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
*/
|
4
meshms.c
4
meshms.c
@ -322,7 +322,7 @@ static enum meshms_status update_conversation(const keyring_identity *id, struct
|
||||
message_ply_append_timestamp(b);
|
||||
assert(!ob_overrun(b));
|
||||
|
||||
if (message_ply_append(id, RHIZOME_SERVICE_MESHMS2, &conv->them, &conv->my_ply, b)!=0){
|
||||
if (message_ply_append(id, RHIZOME_SERVICE_MESHMS2, &conv->them, &conv->my_ply, b, 0, NULL)!=0){
|
||||
status = MESHMS_STATUS_ERROR;
|
||||
}else{
|
||||
conv->metadata.my_last_ack = conv->metadata.their_last_message;
|
||||
@ -933,7 +933,7 @@ enum meshms_status meshms_send_message(const sid_t *sender, const sid_t *recipie
|
||||
|
||||
assert(!ob_overrun(b));
|
||||
|
||||
if (message_ply_append(id, RHIZOME_SERVICE_MESHMS2, recipient, &c->my_ply, b)==0){
|
||||
if (message_ply_append(id, RHIZOME_SERVICE_MESHMS2, recipient, &c->my_ply, b, 0, NULL)==0){
|
||||
if (ack)
|
||||
c->metadata.my_last_ack = c->metadata.their_last_message;
|
||||
c->metadata.my_size += ob_position(b);
|
||||
|
@ -64,7 +64,8 @@ static int message_ply_fill_manifest(const keyring_identity *id, const sid_t *re
|
||||
return ret;
|
||||
}
|
||||
|
||||
int message_ply_append(const keyring_identity *id, const char *service, const sid_t *recipient, struct message_ply *ply, struct overlay_buffer *b)
|
||||
int message_ply_append(const keyring_identity *id, const char *service, const sid_t *recipient, struct message_ply *ply, struct overlay_buffer *b,
|
||||
unsigned nassignments, const struct rhizome_manifest_field_assignment *assignments)
|
||||
{
|
||||
rhizome_manifest *mout = NULL;
|
||||
rhizome_manifest *m = rhizome_new_manifest();
|
||||
@ -86,6 +87,14 @@ int message_ply_append(const keyring_identity *id, const char *service, const si
|
||||
}
|
||||
}
|
||||
|
||||
struct rhizome_bundle_result result = rhizome_apply_assignments(m, nassignments, assignments);
|
||||
if (result.status != RHIZOME_BUNDLE_STATUS_NEW){
|
||||
WARNF("Cannot create message ply manifest: %s", alloca_rhizome_bundle_result(result));
|
||||
rhizome_bundle_result_free(&result);
|
||||
goto end;
|
||||
}
|
||||
rhizome_bundle_result_free(&result);
|
||||
|
||||
if (!ply->found){
|
||||
rhizome_manifest_set_service(m, service);
|
||||
if (ply->known_bid)
|
||||
@ -98,7 +107,7 @@ int message_ply_append(const keyring_identity *id, const char *service, const si
|
||||
if (pstatus != RHIZOME_PAYLOAD_STATUS_NEW)
|
||||
goto end;
|
||||
|
||||
struct rhizome_bundle_result result = rhizome_manifest_finalise(m, &mout, 1);
|
||||
result = rhizome_manifest_finalise(m, &mout, 1);
|
||||
if (result.status != RHIZOME_BUNDLE_STATUS_NEW){
|
||||
WARNF("Cannot create message ply manifest: %s", alloca_rhizome_bundle_result(result));
|
||||
rhizome_bundle_result_free(&result);
|
||||
|
@ -43,6 +43,7 @@ void message_ply_read_rewind(struct message_ply_read *ply);
|
||||
void message_ply_append_ack(struct overlay_buffer *b, uint64_t message_offset, uint64_t previous_ack_offset);
|
||||
void message_ply_append_timestamp(struct overlay_buffer *b);
|
||||
void message_ply_append_message(struct overlay_buffer *b, const char *message, size_t message_len);
|
||||
int message_ply_append(const struct keyring_identity *id, const char *service, const sid_t *recipient, struct message_ply *ply, struct overlay_buffer *b);
|
||||
int message_ply_append(const struct keyring_identity *id, const char *service, const sid_t *recipient, struct message_ply *ply, struct overlay_buffer *b,
|
||||
unsigned nassignments, const struct rhizome_manifest_field_assignment *assignments);
|
||||
|
||||
#endif
|
120
rhizome.c
120
rhizome.c
@ -97,6 +97,78 @@ int rhizome_fetch_delay_ms()
|
||||
return config.rhizome.fetch_delay_ms;
|
||||
}
|
||||
|
||||
int rhizome_parse_field_assignments(struct rhizome_manifest_field_assignment *fields, unsigned argc, const char *const *args)
|
||||
{
|
||||
unsigned i;
|
||||
for (i = 0; i < argc; ++i) {
|
||||
struct rhizome_manifest_field_assignment *field = &fields[i];
|
||||
const char *arg = args[i];
|
||||
size_t arglen = strlen(arg);
|
||||
const char *eq;
|
||||
if (arglen > 0 && arg[0] == '!') {
|
||||
field->label = arg + 1;
|
||||
field->labellen = arglen - 1;
|
||||
field->value = NULL;
|
||||
} else if ((eq = strchr(arg, '='))) {
|
||||
field->label = arg;
|
||||
field->labellen = eq - arg;
|
||||
field->value = eq + 1;
|
||||
field->valuelen = (arg + arglen) - field->value;
|
||||
} else
|
||||
return WHYF("invalid manifest field argument: %s", alloca_str_toprint(arg));
|
||||
if (!rhizome_manifest_field_label_is_valid(field->label, field->labellen))
|
||||
return WHYF("invalid manifest field label: %s", alloca_toprint(-1, field->label, field->labellen));
|
||||
if (field->value && !rhizome_manifest_field_value_is_valid(field->value, field->valuelen))
|
||||
return WHYF("invalid manifest field value: %s", alloca_toprint(-1, field->value, field->valuelen));
|
||||
}
|
||||
return argc;
|
||||
}
|
||||
|
||||
struct rhizome_bundle_result rhizome_apply_assignments(rhizome_manifest *m,
|
||||
unsigned nassignments, const struct rhizome_manifest_field_assignment *assignments)
|
||||
{
|
||||
// Apply the field assignments, overriding the existing manifest fields.
|
||||
unsigned i;
|
||||
for (i = 0; i != nassignments; ++i) {
|
||||
const struct rhizome_manifest_field_assignment *asg = &assignments[i];
|
||||
rhizome_manifest_remove_field(m, asg->label, asg->labellen);
|
||||
if (asg->value) {
|
||||
const char *label = alloca_strndup(asg->label, asg->labellen);
|
||||
enum rhizome_manifest_parse_status status = rhizome_manifest_parse_field(m, asg->label, asg->labellen, asg->value, asg->valuelen);
|
||||
switch (status) {
|
||||
case RHIZOME_MANIFEST_ERROR:
|
||||
return rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_ERROR,
|
||||
"Error updating manifest field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
case RHIZOME_MANIFEST_OK:
|
||||
break;
|
||||
case RHIZOME_MANIFEST_SYNTAX_ERROR:
|
||||
return rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest syntax error: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
case RHIZOME_MANIFEST_DUPLICATE_FIELD:
|
||||
// We already deleted the field, so if this happens, its a logic bug.
|
||||
FATALF("Duplicate field should not occur: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
case RHIZOME_MANIFEST_INVALID:
|
||||
return rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest invalid field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
case RHIZOME_MANIFEST_MALFORMED:
|
||||
return rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest malformed field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
case RHIZOME_MANIFEST_OVERFLOW:
|
||||
return rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Too many fields in manifest at: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
default:
|
||||
FATALF("status = %d", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
return rhizome_bundle_result(RHIZOME_BUNDLE_STATUS_NEW);
|
||||
}
|
||||
|
||||
/* Create a manifest structure to accompany adding a file to Rhizome or appending to a journal.
|
||||
* This function is used by all application-facing APIs (eg, CLI, RESTful HTTP). It differs from
|
||||
* the import operation in that if the caller does not supply a complete, signed manifest then this
|
||||
@ -247,51 +319,9 @@ struct rhizome_bundle_result rhizome_manifest_add_file(int appending,
|
||||
}
|
||||
// Apply the field assignments, overriding the existing manifest fields.
|
||||
if (nassignments) {
|
||||
unsigned i;
|
||||
for (i = 0; i != nassignments; ++i) {
|
||||
const struct rhizome_manifest_field_assignment *asg = &assignments[i];
|
||||
rhizome_manifest_remove_field(new_manifest, asg->label, asg->labellen);
|
||||
if (asg->value) {
|
||||
const char *label = alloca_strndup(asg->label, asg->labellen);
|
||||
enum rhizome_manifest_parse_status status = rhizome_manifest_parse_field(new_manifest, asg->label, asg->labellen, asg->value, asg->valuelen);
|
||||
int status_ok = 0;
|
||||
switch (status) {
|
||||
case RHIZOME_MANIFEST_ERROR:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_ERROR,
|
||||
"Error updating manifest field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_OK:
|
||||
status_ok = 1;
|
||||
break;
|
||||
case RHIZOME_MANIFEST_SYNTAX_ERROR:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest syntax error: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_DUPLICATE_FIELD:
|
||||
// We already deleted the field, so if this happens, its a logic bug.
|
||||
FATALF("Duplicate field should not occur: %s=%s", label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
case RHIZOME_MANIFEST_INVALID:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest invalid field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_MALFORMED:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Manifest malformed field: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
case RHIZOME_MANIFEST_OVERFLOW:
|
||||
result = rhizome_bundle_result_sprintf(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
"Too many fields in manifest at: %s=%s",
|
||||
label, alloca_toprint(-1, asg->value, asg->valuelen));
|
||||
goto error;
|
||||
}
|
||||
if (!status_ok)
|
||||
FATALF("status = %d", status);
|
||||
}
|
||||
}
|
||||
result = rhizome_apply_assignments(new_manifest, nassignments, assignments);
|
||||
if (result.status != RHIZOME_BUNDLE_STATUS_NEW)
|
||||
goto error;
|
||||
}
|
||||
if (appending && !new_manifest->is_journal) {
|
||||
result = rhizome_bundle_result_static(RHIZOME_BUNDLE_STATUS_INVALID,
|
||||
|
@ -475,6 +475,10 @@ rhizome_manifest *_rhizome_new_manifest(struct __sourceloc);
|
||||
int rhizome_store_manifest(rhizome_manifest *m);
|
||||
int rhizome_store_file(rhizome_manifest *m,const unsigned char *key);
|
||||
|
||||
int rhizome_parse_field_assignments(struct rhizome_manifest_field_assignment *fields, unsigned argc, const char *const *args);
|
||||
struct rhizome_bundle_result rhizome_apply_assignments(rhizome_manifest *m,
|
||||
unsigned nassignments, const struct rhizome_manifest_field_assignment *assignments);
|
||||
|
||||
struct rhizome_bundle_result rhizome_manifest_add_file(int appending,
|
||||
rhizome_manifest *m,
|
||||
rhizome_manifest **mout,
|
||||
|
@ -178,30 +178,8 @@ static int app_rhizome_add_file(const struct cli_parsed *parsed, struct cli_cont
|
||||
struct rhizome_manifest_field_assignment fields[nfields];
|
||||
if (nfields) {
|
||||
assert(parsed->varargi >= 0);
|
||||
unsigned i;
|
||||
for (i = 0; i < nfields; ++i) {
|
||||
struct rhizome_manifest_field_assignment *field = &fields[i];
|
||||
unsigned n = (unsigned)parsed->varargi + i;
|
||||
assert(n < parsed->argc);
|
||||
const char *arg = parsed->args[n];
|
||||
size_t arglen = strlen(arg);
|
||||
const char *eq;
|
||||
if (arglen > 0 && arg[0] == '!') {
|
||||
field->label = arg + 1;
|
||||
field->labellen = arglen - 1;
|
||||
field->value = NULL;
|
||||
} else if ((eq = strchr(arg, '='))) {
|
||||
field->label = arg;
|
||||
field->labellen = eq - arg;
|
||||
field->value = eq + 1;
|
||||
field->valuelen = (arg + arglen) - field->value;
|
||||
} else
|
||||
return WHYF("invalid manifest field argument: %s", alloca_str_toprint(arg));
|
||||
if (!rhizome_manifest_field_label_is_valid(field->label, field->labellen))
|
||||
return WHYF("invalid manifest field label: %s", alloca_toprint(-1, field->label, field->labellen));
|
||||
if (field->value && !rhizome_manifest_field_value_is_valid(field->value, field->valuelen))
|
||||
return WHYF("invalid manifest field value: %s", alloca_toprint(-1, field->value, field->valuelen));
|
||||
}
|
||||
if (rhizome_parse_field_assignments(fields, nfields, parsed->args + parsed->varargi)==-1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
int appending = strcasecmp(parsed->args[1], "journal")==0;
|
||||
|
Loading…
x
Reference in New Issue
Block a user