Allow for arbitrary extra manifest fields on broadcast messages

This commit is contained in:
Jeremy Lakeman 2016-08-24 16:33:39 +09:30
parent e13b9c3c94
commit 6a0b7a1da6
7 changed files with 160 additions and 115 deletions

105
meshmb.c
View File

@ -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;
}
*/

View File

@ -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);

View File

@ -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);

View File

@ -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
View File

@ -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,

View File

@ -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,

View File

@ -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;