From 6a0b7a1da67c0fdce2da8f60c3fbdeba5033c044 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 24 Aug 2016 16:33:39 +0930 Subject: [PATCH] Allow for arbitrary extra manifest fields on broadcast messages --- meshmb.c | 105 ++++++++++++++++++++++++++----------------- meshms.c | 4 +- message_ply.c | 13 +++++- message_ply.h | 3 +- rhizome.c | 120 +++++++++++++++++++++++++++++++------------------- rhizome.h | 4 ++ rhizome_cli.c | 26 +---------- 7 files changed, 160 insertions(+), 115 deletions(-) diff --git a/meshmb.c b/meshmb.c index 80bd7fab..dfa81bc2 100644 --- a/meshmb.c +++ b/meshmb.c @@ -8,17 +8,9 @@ #include "commandline.h" #include "overlay_buffer.h" -/* -DEFINE_CMD(app_meshmb_news, 0, - "", - "meshmb", "news" KEYRING_PIN_OPTIONS, ""); -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, "", ""); + "Append a public broadcast message to your feed", + "meshmb", "send" KEYRING_PIN_OPTIONS, "", "", "..."); 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", ""); -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, "", ""); -static int app_meshmb_follow(const struct cli_parsed *parsed, struct cli_context *context) -{ - return 0; -} - -DEFINE_CMD(app_meshmb_find, 0, - "", - "meshmb", "find", "[]"); -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", ""); 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", "[]"); +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, "", ""); +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", ""); +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, ""); +static int app_meshmb_news(const struct cli_parsed *parsed, struct cli_context *context) +{ + return 0; +} +*/ \ No newline at end of file diff --git a/meshms.c b/meshms.c index 1271d312..9e2a713e 100644 --- a/meshms.c +++ b/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); diff --git a/message_ply.c b/message_ply.c index f2bee3a5..1d7a9b2f 100644 --- a/message_ply.c +++ b/message_ply.c @@ -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); diff --git a/message_ply.h b/message_ply.h index 9efccc96..d228b7b8 100644 --- a/message_ply.h +++ b/message_ply.h @@ -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 \ No newline at end of file diff --git a/rhizome.c b/rhizome.c index 5eb97972..fe952f1c 100644 --- a/rhizome.c +++ b/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, diff --git a/rhizome.h b/rhizome.h index 0e8950aa..f2d88dc5 100644 --- a/rhizome.h +++ b/rhizome.h @@ -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, diff --git a/rhizome_cli.c b/rhizome_cli.c index 21baf4d5..0f6ad2bd 100644 --- a/rhizome_cli.c +++ b/rhizome_cli.c @@ -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;