mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-02-06 11:09:13 +00:00
Add command to mark messages as read
This commit is contained in:
parent
a1caa4bf68
commit
7634e1fcfb
@ -2314,6 +2314,8 @@ struct cli_schema command_line_options[]={
|
|||||||
"List MeshMS messages between <sender_sid> and <recipient_sid>"},
|
"List MeshMS messages between <sender_sid> and <recipient_sid>"},
|
||||||
{app_meshms_send_message,{"meshms","send","message" KEYRING_PIN_OPTIONS, "<sender_sid>", "<recipient_sid>", "<payload>",NULL},0,
|
{app_meshms_send_message,{"meshms","send","message" KEYRING_PIN_OPTIONS, "<sender_sid>", "<recipient_sid>", "<payload>",NULL},0,
|
||||||
"Send a MeshMS message from <sender_sid> to <recipient_sid>"},
|
"Send a MeshMS message from <sender_sid> to <recipient_sid>"},
|
||||||
|
{app_meshms_mark_read,{"meshms","read","messages" KEYRING_PIN_OPTIONS, "<sender_sid>", "[<recipient_sid>]", "[<offset>]",NULL},0,
|
||||||
|
"Mark incoming messages from this recipient as read."},
|
||||||
{app_rhizome_append_manifest, {"rhizome", "append", "manifest", "<filepath>", "<manifestpath>", NULL}, 0,
|
{app_rhizome_append_manifest, {"rhizome", "append", "manifest", "<filepath>", "<manifestpath>", NULL}, 0,
|
||||||
"Append a manifest to the end of the file it belongs to."},
|
"Append a manifest to the end of the file it belongs to."},
|
||||||
{app_rhizome_hash_file,{"rhizome","hash","file","<filepath>",NULL}, 0,
|
{app_rhizome_hash_file,{"rhizome","hash","file","<filepath>",NULL}, 0,
|
||||||
|
147
meshms.c
147
meshms.c
@ -3,11 +3,13 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "conf.h"
|
#include "conf.h"
|
||||||
#include "crypto.h"
|
#include "crypto.h"
|
||||||
|
#include "strlcpy.h"
|
||||||
|
|
||||||
#define MESHMS_BLOCK_TYPE_ACK 0x01
|
#define MESHMS_BLOCK_TYPE_ACK 0x01
|
||||||
#define MESHMS_BLOCK_TYPE_MESSAGE 0x02
|
#define MESHMS_BLOCK_TYPE_MESSAGE 0x02
|
||||||
#define MESHMS_BLOCK_TYPE_BID_REFERENCE 0x03
|
#define MESHMS_BLOCK_TYPE_BID_REFERENCE 0x03
|
||||||
|
|
||||||
|
// the manifest details for one half of a conversation
|
||||||
struct ply{
|
struct ply{
|
||||||
char bundle_id[RHIZOME_MANIFEST_ID_STRLEN+1];
|
char bundle_id[RHIZOME_MANIFEST_ID_STRLEN+1];
|
||||||
uint64_t version;
|
uint64_t version;
|
||||||
@ -16,11 +18,16 @@ struct ply{
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct conversations{
|
struct conversations{
|
||||||
|
// binary tree
|
||||||
struct conversations *_left;
|
struct conversations *_left;
|
||||||
struct conversations *_right;
|
struct conversations *_right;
|
||||||
|
|
||||||
|
// who are we talking to?
|
||||||
char them[SID_STRLEN+1];
|
char them[SID_STRLEN+1];
|
||||||
|
|
||||||
char found_my_ply;
|
char found_my_ply;
|
||||||
struct ply my_ply;
|
struct ply my_ply;
|
||||||
|
|
||||||
char found_their_ply;
|
char found_their_ply;
|
||||||
struct ply their_ply;
|
struct ply their_ply;
|
||||||
|
|
||||||
@ -32,13 +39,19 @@ struct conversations{
|
|||||||
uint64_t their_size;
|
uint64_t their_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// cursor state for reading one half of a conversation
|
||||||
struct ply_read{
|
struct ply_read{
|
||||||
|
// rhizome payload
|
||||||
struct rhizome_read read;
|
struct rhizome_read read;
|
||||||
|
// block buffer
|
||||||
struct rhizome_read_buffer buff;
|
struct rhizome_read_buffer buff;
|
||||||
|
|
||||||
|
// details of the current record
|
||||||
uint64_t record_end_offset;
|
uint64_t record_end_offset;
|
||||||
uint16_t record_length;
|
uint16_t record_length;
|
||||||
int buffer_size;
|
int buffer_size;
|
||||||
char type;
|
char type;
|
||||||
|
// raw record data
|
||||||
unsigned char *buffer;
|
unsigned char *buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -74,6 +87,9 @@ static int get_my_conversation_bundle(const char *my_sid, rhizome_manifest *m)
|
|||||||
|
|
||||||
// always consider the content encrypted, we don't need to rely on the manifest itself.
|
// always consider the content encrypted, we don't need to rely on the manifest itself.
|
||||||
m->payloadEncryption=1;
|
m->payloadEncryption=1;
|
||||||
|
if (m->haveSecret==NEW_BUNDLE_ID){
|
||||||
|
rhizome_fill_manifest(m, NULL, NULL, NULL);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +247,7 @@ static int ply_read_next(struct ply_read *ply){
|
|||||||
DEBUGF("EOF");
|
DEBUGF("EOF");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (rhizome_read_buffered(&ply->read, &ply->buff, footer, sizeof(footer)))
|
if (rhizome_read_buffered(&ply->read, &ply->buff, footer, sizeof(footer)) < sizeof(footer))
|
||||||
return -1;
|
return -1;
|
||||||
// (rhizome_read automatically advances the offset by the number of bytes read)
|
// (rhizome_read automatically advances the offset by the number of bytes read)
|
||||||
ply->record_length=read_uint16(footer);
|
ply->record_length=read_uint16(footer);
|
||||||
@ -442,8 +458,11 @@ static int update_conversations(const char *my_sidhex, struct conversations *con
|
|||||||
|
|
||||||
// read our cached conversation list from our rhizome payload
|
// read our cached conversation list from our rhizome payload
|
||||||
static int read_known_conversations(rhizome_manifest *m, const char *their_sid_hex, struct conversations **conv){
|
static int read_known_conversations(rhizome_manifest *m, const char *their_sid_hex, struct conversations **conv){
|
||||||
if (m->haveSecret!=EXISTING_BUNDLE_ID)
|
if (m->haveSecret==NEW_BUNDLE_ID){
|
||||||
|
if (config.debug.meshms)
|
||||||
|
DEBUGF("Ignoring new bundle?");
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct rhizome_read read;
|
struct rhizome_read read;
|
||||||
bzero(&read, sizeof(read));
|
bzero(&read, sizeof(read));
|
||||||
@ -453,12 +472,14 @@ static int read_known_conversations(rhizome_manifest *m, const char *their_sid_h
|
|||||||
int ret = rhizome_open_decrypt_read(m, NULL, &read, 0);
|
int ret = rhizome_open_decrypt_read(m, NULL, &read, 0);
|
||||||
if (ret<0)
|
if (ret<0)
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
while (1){
|
while (1){
|
||||||
char them[SID_STRLEN+1];
|
char them[SID_STRLEN+1];
|
||||||
ret=rhizome_read_buffered(&read, &buff, (unsigned char *)them, sizeof(them));
|
ret=rhizome_read_buffered(&read, &buff, (unsigned char *)them, sizeof(them));
|
||||||
if (ret<=0)
|
if (ret<sizeof(them))
|
||||||
break;
|
break;
|
||||||
|
if (config.debug.meshms)
|
||||||
|
DEBUGF("Reading existing conversation for %s", them);
|
||||||
if (their_sid_hex && strcmp(them, their_sid_hex))
|
if (their_sid_hex && strcmp(them, their_sid_hex))
|
||||||
continue;
|
continue;
|
||||||
struct conversations *ptr = add_conv(conv, them);
|
struct conversations *ptr = add_conv(conv, them);
|
||||||
@ -466,7 +487,7 @@ static int read_known_conversations(rhizome_manifest *m, const char *their_sid_h
|
|||||||
return -1;
|
return -1;
|
||||||
unsigned char details[8*3];
|
unsigned char details[8*3];
|
||||||
ret=rhizome_read_buffered(&read, &buff, details, sizeof(details));
|
ret=rhizome_read_buffered(&read, &buff, details, sizeof(details));
|
||||||
if (ret<=0)
|
if (ret<sizeof(details))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ptr->their_last_message = read_uint64(details);
|
ptr->their_last_message = read_uint64(details);
|
||||||
@ -480,6 +501,8 @@ end:
|
|||||||
|
|
||||||
static int write_conversation(struct rhizome_write *write, struct conversations *conv){
|
static int write_conversation(struct rhizome_write *write, struct conversations *conv){
|
||||||
int len=0;
|
int len=0;
|
||||||
|
if (!conv)
|
||||||
|
return len;
|
||||||
{
|
{
|
||||||
unsigned char buffer[SID_STRLEN + 1 + (8*3)];
|
unsigned char buffer[SID_STRLEN + 1 + (8*3)];
|
||||||
if (write)
|
if (write)
|
||||||
@ -494,6 +517,11 @@ static int write_conversation(struct rhizome_write *write, struct conversations
|
|||||||
if (write)
|
if (write)
|
||||||
write_uint64(&buffer[len], conv->their_size);
|
write_uint64(&buffer[len], conv->their_size);
|
||||||
len+=8;
|
len+=8;
|
||||||
|
if (write){
|
||||||
|
int ret=rhizome_write_buffer(write, buffer, len);
|
||||||
|
if (ret<0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// write the two child nodes
|
// write the two child nodes
|
||||||
int ret=write_conversation(write, conv->_left);
|
int ret=write_conversation(write, conv->_left);
|
||||||
@ -508,8 +536,6 @@ static int write_conversation(struct rhizome_write *write, struct conversations
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int write_known_conversations(rhizome_manifest *m, struct conversations *conv){
|
static int write_known_conversations(rhizome_manifest *m, struct conversations *conv){
|
||||||
if (m->haveSecret!=EXISTING_BUNDLE_ID)
|
|
||||||
return 0;
|
|
||||||
rhizome_manifest *mout=NULL;
|
rhizome_manifest *mout=NULL;
|
||||||
|
|
||||||
struct rhizome_write write;
|
struct rhizome_write write;
|
||||||
@ -524,13 +550,19 @@ static int write_known_conversations(rhizome_manifest *m, struct conversations *
|
|||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
// then write it
|
// then write it
|
||||||
|
m->version++;
|
||||||
|
rhizome_manifest_set_ll(m,"version",m->version);
|
||||||
m->fileLength = len;
|
m->fileLength = len;
|
||||||
|
rhizome_manifest_set_ll(m,"filesize",m->fileLength);
|
||||||
|
|
||||||
if (rhizome_write_open_manifest(&write, m))
|
if (rhizome_write_open_manifest(&write, m))
|
||||||
goto end;
|
goto end;
|
||||||
if (write_conversation(&write, conv)<0)
|
if (write_conversation(&write, conv)<0)
|
||||||
goto end;
|
goto end;
|
||||||
if (rhizome_finish_write(&write))
|
if (rhizome_finish_write(&write))
|
||||||
goto end;
|
goto end;
|
||||||
|
strlcpy(m->fileHexHash, write.id, SHA512_DIGEST_STRING_LENGTH);
|
||||||
|
rhizome_manifest_set(m, "filehash", m->fileHexHash);
|
||||||
if (rhizome_manifest_finalise(m,&mout))
|
if (rhizome_manifest_finalise(m,&mout))
|
||||||
goto end;
|
goto end;
|
||||||
|
|
||||||
@ -580,8 +612,7 @@ static int output_conversations(struct cli_context *context, struct conversation
|
|||||||
if (count <0 || output + traverse_count < offset + count){
|
if (count <0 || output + traverse_count < offset + count){
|
||||||
if (output + traverse_count >= offset){
|
if (output + traverse_count >= offset){
|
||||||
cli_put_string(context, conv->them, ":");
|
cli_put_string(context, conv->them, ":");
|
||||||
cli_put_string(context, conv->read_offset < conv->their_last_message ? "unread":"", ":");
|
cli_put_string(context, conv->read_offset < conv->their_last_message ? "unread":"", "\n");
|
||||||
cli_put_string(context, "delivered", "\n");// TODO
|
|
||||||
}
|
}
|
||||||
traverse_count++;
|
traverse_count++;
|
||||||
}
|
}
|
||||||
@ -614,10 +645,10 @@ int app_meshms_conversations(const struct cli_parsed *parsed, struct cli_context
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
const char *names[]={
|
const char *names[]={
|
||||||
"sid","read","delivered"
|
"sid","read"
|
||||||
};
|
};
|
||||||
|
|
||||||
cli_columns(context, 3, names);
|
cli_columns(context, 2, names);
|
||||||
output_conversations(context, conv, 0, offset, count);
|
output_conversations(context, conv, 0, offset, count);
|
||||||
free_conversations(conv);
|
free_conversations(conv);
|
||||||
return 0;
|
return 0;
|
||||||
@ -679,6 +710,9 @@ int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context
|
|||||||
|
|
||||||
cli_columns(context, 5, names);
|
cli_columns(context, 5, names);
|
||||||
|
|
||||||
|
rhizome_manifest *m_ours=NULL, *m_theirs=NULL;
|
||||||
|
struct ply_read read_ours, read_theirs;
|
||||||
|
|
||||||
// if we've never sent a message, (or acked theirs), there is nothing to show
|
// if we've never sent a message, (or acked theirs), there is nothing to show
|
||||||
if (!conv->found_my_ply){
|
if (!conv->found_my_ply){
|
||||||
ret=0;
|
ret=0;
|
||||||
@ -686,13 +720,11 @@ int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start reading messages from both ply's in reverse order
|
// start reading messages from both ply's in reverse order
|
||||||
rhizome_manifest *m_ours=NULL, *m_theirs=NULL;
|
|
||||||
struct ply_read read_ours, read_theirs;
|
|
||||||
bzero(&read_ours, sizeof(read_ours));
|
bzero(&read_ours, sizeof(read_ours));
|
||||||
bzero(&read_theirs, sizeof(read_theirs));
|
bzero(&read_theirs, sizeof(read_theirs));
|
||||||
|
|
||||||
if (conv->found_my_ply){
|
if (conv->found_my_ply){
|
||||||
rhizome_manifest *m_ours = rhizome_new_manifest();
|
m_ours = rhizome_new_manifest();
|
||||||
if (!m_ours)
|
if (!m_ours)
|
||||||
goto end;
|
goto end;
|
||||||
if (ply_read_open(&read_ours, conv->my_ply.bundle_id, m_ours))
|
if (ply_read_open(&read_ours, conv->my_ply.bundle_id, m_ours))
|
||||||
@ -717,11 +749,10 @@ int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context
|
|||||||
DEBUGF("Found their last ack @%"PRId64, their_last_ack);
|
DEBUGF("Found their last ack @%"PRId64, their_last_ack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int id=0;
|
int id=0;
|
||||||
while(ply_read_next(&read_ours)==0){
|
while(ply_read_next(&read_ours)==0){
|
||||||
if (config.debug.meshms)
|
if (config.debug.meshms)
|
||||||
DEBUGF("%"PRId64", found %d", read_ours.read.offset, read_ours.type);
|
DEBUGF("Offset %"PRId64", type %d, read_offset %"PRId64, read_ours.read.offset, read_ours.type, conv->read_offset);
|
||||||
switch(read_ours.type){
|
switch(read_ours.type){
|
||||||
case MESHMS_BLOCK_TYPE_ACK:
|
case MESHMS_BLOCK_TYPE_ACK:
|
||||||
// read their message list, and insert all messages that are included in the ack range
|
// read their message list, and insert all messages that are included in the ack range
|
||||||
@ -746,7 +777,7 @@ int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context
|
|||||||
if (read_theirs.read.offset < end_range)
|
if (read_theirs.read.offset < end_range)
|
||||||
break;
|
break;
|
||||||
cli_put_long(context, id++, ":");
|
cli_put_long(context, id++, ":");
|
||||||
cli_put_long(context, read_theirs.read.offset, ":");
|
cli_put_long(context, read_theirs.record_end_offset, ":");
|
||||||
cli_put_string(context, their_sidhex, ":");
|
cli_put_string(context, their_sidhex, ":");
|
||||||
cli_put_string(context, read_theirs.record_end_offset <= conv->read_offset?"":"unread", ":");
|
cli_put_string(context, read_theirs.record_end_offset <= conv->read_offset?"":"unread", ":");
|
||||||
cli_put_string(context, (char *)read_theirs.buffer, "\n");
|
cli_put_string(context, (char *)read_theirs.buffer, "\n");
|
||||||
@ -756,7 +787,7 @@ int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context
|
|||||||
case MESHMS_BLOCK_TYPE_MESSAGE:
|
case MESHMS_BLOCK_TYPE_MESSAGE:
|
||||||
// TODO new message format here
|
// TODO new message format here
|
||||||
cli_put_long(context, id++, ":");
|
cli_put_long(context, id++, ":");
|
||||||
cli_put_long(context, read_ours.read.offset, ":");
|
cli_put_long(context, read_ours.record_end_offset, ":");
|
||||||
cli_put_string(context, my_sidhex, ":");
|
cli_put_string(context, my_sidhex, ":");
|
||||||
cli_put_string(context, their_last_ack >= read_ours.record_end_offset ? "delivered":"", ":");
|
cli_put_string(context, their_last_ack >= read_ours.record_end_offset ? "delivered":"", ":");
|
||||||
cli_put_string(context, (char *)read_ours.buffer, "\n");
|
cli_put_string(context, (char *)read_ours.buffer, "\n");
|
||||||
@ -776,4 +807,84 @@ end:
|
|||||||
}
|
}
|
||||||
free_conversations(conv);
|
free_conversations(conv);
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mark_read(struct conversations *conv, const char *their_sid, const char *offset_str){
|
||||||
|
int ret=0;
|
||||||
|
if (conv){
|
||||||
|
int cmp = their_sid?strcmp(conv->them, their_sid):0;
|
||||||
|
if (!their_sid || cmp<0){
|
||||||
|
ret+=mark_read(conv->_left, their_sid, offset_str);
|
||||||
|
}
|
||||||
|
if (!their_sid || cmp==0){
|
||||||
|
// update read offset
|
||||||
|
// - never rewind
|
||||||
|
// - never past their last message
|
||||||
|
uint64_t offset = conv->their_last_message;
|
||||||
|
if (offset_str){
|
||||||
|
uint64_t x = atol(offset_str);
|
||||||
|
if (x<offset)
|
||||||
|
offset=x;
|
||||||
|
}
|
||||||
|
if (offset > conv->read_offset){
|
||||||
|
if (config.debug.meshms)
|
||||||
|
DEBUGF("Moving read marker for %s, from %"PRId64" to %"PRId64, conv->them, conv->read_offset, offset);
|
||||||
|
conv->read_offset = offset;
|
||||||
|
ret++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!their_sid || cmp>0){
|
||||||
|
ret+=mark_read(conv->_right, their_sid, offset_str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int app_meshms_mark_read(const struct cli_parsed *parsed, struct cli_context *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, NULL, NULL)==-1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (create_serval_instance_dir() == -1)
|
||||||
|
return -1;
|
||||||
|
if (!(keyring = keyring_open_instance_cli(parsed)))
|
||||||
|
return -1;
|
||||||
|
if (rhizome_opendb() == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int ret=-1;
|
||||||
|
struct conversations *conv=NULL;
|
||||||
|
rhizome_manifest *m = rhizome_new_manifest();
|
||||||
|
if (!m)
|
||||||
|
goto end;
|
||||||
|
if (get_my_conversation_bundle(my_sidhex, m))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
// read all conversations, so we can write them again
|
||||||
|
if (read_known_conversations(m, NULL, &conv))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
// read the full list of conversations from the database too
|
||||||
|
if (get_database_conversations(my_sidhex, my_sidhex, &conv))
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
// check if any incoming conversations need to be acked or have new messages and update the read offset
|
||||||
|
int changed = update_conversations(my_sidhex, conv);
|
||||||
|
if (mark_read(conv, their_sidhex, offset_str))
|
||||||
|
changed =1;
|
||||||
|
if (changed){
|
||||||
|
// save the conversation list
|
||||||
|
if (write_known_conversations(m, conv))
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret=0;
|
||||||
|
|
||||||
|
end:
|
||||||
|
if (m)
|
||||||
|
rhizome_manifest_free(m);
|
||||||
|
free_conversations(conv);
|
||||||
|
return ret;
|
||||||
}
|
}
|
@ -759,20 +759,22 @@ int rhizome_fill_manifest(rhizome_manifest *m, const char *filepath, const sid_t
|
|||||||
rhizome_manifest_set_ll(m,"version",m->version);
|
rhizome_manifest_set_ll(m,"version",m->version);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *id = rhizome_manifest_get(m, "id", NULL, 0);
|
if (!m->haveSecret){
|
||||||
if (id == NULL) {
|
const char *id = rhizome_manifest_get(m, "id", NULL, 0);
|
||||||
if (config.debug.rhizome) DEBUG("creating new bundle");
|
if (id == NULL) {
|
||||||
if (rhizome_manifest_bind_id(m) == -1) {
|
if (config.debug.rhizome) DEBUG("creating new bundle");
|
||||||
return WHY("Could not bind manifest to an ID");
|
if (rhizome_manifest_bind_id(m) == -1) {
|
||||||
|
return WHY("Could not bind manifest to an ID");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (config.debug.rhizome) DEBUGF("modifying existing bundle bid=%s", id);
|
||||||
|
|
||||||
|
// Modifying an existing bundle. Make sure we can find the bundle secret.
|
||||||
|
if (rhizome_extract_privatekey_required(m, bsk))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
// TODO assert that new version > old version?
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (config.debug.rhizome) DEBUGF("modifying existing bundle bid=%s", id);
|
|
||||||
|
|
||||||
// Modifying an existing bundle. Make sure we can find the bundle secret.
|
|
||||||
if (rhizome_extract_privatekey_required(m, bsk))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
// TODO assert that new version > old version?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int crypt = rhizome_manifest_get_ll(m,"crypt");
|
int crypt = rhizome_manifest_get_ll(m,"crypt");
|
||||||
|
@ -80,7 +80,8 @@ int rhizome_get_bundle_from_seed(rhizome_manifest *m, const char *seed)
|
|||||||
m->haveSecret=(ret==0)?EXISTING_BUNDLE_ID:NEW_BUNDLE_ID;
|
m->haveSecret=(ret==0)?EXISTING_BUNDLE_ID:NEW_BUNDLE_ID;
|
||||||
bcopy(key.Public, m->cryptoSignPublic, sizeof(m->cryptoSignPublic));
|
bcopy(key.Public, m->cryptoSignPublic, sizeof(m->cryptoSignPublic));
|
||||||
bcopy(key.Private, m->cryptoSignSecret, sizeof(m->cryptoSignSecret));
|
bcopy(key.Private, m->cryptoSignSecret, sizeof(m->cryptoSignSecret));
|
||||||
|
if (ret>0)
|
||||||
|
rhizome_manifest_set(m, "id", alloca_tohex_bid(m->cryptoSignPublic));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -588,7 +588,7 @@ static int rhizome_write_derive_key(rhizome_manifest *m, rhizome_bk_t *bsk, stru
|
|||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (config.debug.rhizome)
|
if (config.debug.rhizome)
|
||||||
DEBUGF("Encrypting payload contents");
|
DEBUGF("Encrypting payload contents for %s, %"PRId64, alloca_tohex_bid(m->cryptoSignPublic), m->version);
|
||||||
|
|
||||||
write->crypt=1;
|
write->crypt=1;
|
||||||
write->tail = m->journalTail;
|
write->tail = m->journalTail;
|
||||||
@ -747,7 +747,13 @@ int rhizome_read(struct rhizome_read *read_state, unsigned char *buffer, int buf
|
|||||||
/* Read len bytes from read->offset into data, using *buffer to cache any reads */
|
/* Read len bytes from read->offset into data, using *buffer to cache any reads */
|
||||||
int rhizome_read_buffered(struct rhizome_read *read, struct rhizome_read_buffer *buffer, unsigned char *data, int len)
|
int rhizome_read_buffered(struct rhizome_read *read, struct rhizome_read_buffer *buffer, unsigned char *data, int len)
|
||||||
{
|
{
|
||||||
|
int bytes_copied=0;
|
||||||
|
|
||||||
while (len>0){
|
while (len>0){
|
||||||
|
// make sure we only attempt to read data that actually exists
|
||||||
|
if (read->length !=-1 && read->offset + len > read->length)
|
||||||
|
len = read->length - read->offset;
|
||||||
|
|
||||||
// if we can supply either the beginning or end of the data from cache, do that first.
|
// if we can supply either the beginning or end of the data from cache, do that first.
|
||||||
uint64_t ofs=read->offset - buffer->offset;
|
uint64_t ofs=read->offset - buffer->offset;
|
||||||
if (ofs>=0 && ofs<=buffer->len){
|
if (ofs>=0 && ofs<=buffer->len){
|
||||||
@ -760,6 +766,7 @@ int rhizome_read_buffered(struct rhizome_read *read, struct rhizome_read_buffer
|
|||||||
data+=size;
|
data+=size;
|
||||||
len-=size;
|
len-=size;
|
||||||
read->offset+=size;
|
read->offset+=size;
|
||||||
|
bytes_copied+=size;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -773,6 +780,7 @@ int rhizome_read_buffered(struct rhizome_read *read, struct rhizome_read_buffer
|
|||||||
// copy into the end of the data buffer
|
// copy into the end of the data buffer
|
||||||
bcopy(buffer->data + ofs - size, data + len - size, size);
|
bcopy(buffer->data + ofs - size, data + len - size, size);
|
||||||
len-=size;
|
len-=size;
|
||||||
|
bytes_copied+=size;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -786,7 +794,7 @@ int rhizome_read_buffered(struct rhizome_read *read, struct rhizome_read_buffer
|
|||||||
if (buffer->len<=0)
|
if (buffer->len<=0)
|
||||||
return buffer->len;
|
return buffer->len;
|
||||||
}
|
}
|
||||||
return 0;
|
return bytes_copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rhizome_read_close(struct rhizome_read *read)
|
int rhizome_read_close(struct rhizome_read *read)
|
||||||
@ -842,7 +850,7 @@ static int read_derive_key(rhizome_manifest *m, rhizome_bk_t *bsk, struct rhizom
|
|||||||
return WHY("Unable to decrypt bundle, valid key not found");
|
return WHY("Unable to decrypt bundle, valid key not found");
|
||||||
}
|
}
|
||||||
if (config.debug.rhizome)
|
if (config.debug.rhizome)
|
||||||
DEBUGF("Decrypting file contents");
|
DEBUGF("Decrypting payload contents for %s, %"PRId64, alloca_tohex_bid(m->cryptoSignPublic), m->version);
|
||||||
|
|
||||||
read_state->tail = m->journalTail;
|
read_state->tail = m->journalTail;
|
||||||
bcopy(m->payloadKey, read_state->key, sizeof(read_state->key));
|
bcopy(m->payloadKey, read_state->key, sizeof(read_state->key));
|
||||||
|
1
serval.h
1
serval.h
@ -673,6 +673,7 @@ int app_vomp_console(const struct cli_parsed *parsed, struct cli_context *contex
|
|||||||
int app_meshms_conversations(const struct cli_parsed *parsed, struct cli_context *context);
|
int app_meshms_conversations(const struct cli_parsed *parsed, struct cli_context *context);
|
||||||
int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context *context);
|
int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context *context);
|
||||||
int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context *context);
|
int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context *context);
|
||||||
|
int app_meshms_mark_read(const struct cli_parsed *parsed, struct cli_context *context);
|
||||||
|
|
||||||
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax);
|
||||||
|
|
||||||
|
67
tests/meshms
67
tests/meshms
@ -28,13 +28,14 @@ teardown() {
|
|||||||
assert_no_servald_processes
|
assert_no_servald_processes
|
||||||
}
|
}
|
||||||
|
|
||||||
doc_MessageDelivery="Send messages and ack them in a 2 party conversation"
|
doc_MessageDelivery="Send messages, ack and read them in a 2 party conversation"
|
||||||
setup_MessageDelivery() {
|
setup_MessageDelivery() {
|
||||||
setup_servald
|
setup_servald
|
||||||
set_instance +A
|
set_instance +A
|
||||||
create_identities 2
|
create_identities 2
|
||||||
executeOk_servald config \
|
executeOk_servald config \
|
||||||
set debug.meshms on \
|
set debug.meshms on \
|
||||||
|
set debug.rhizome on \
|
||||||
set log.console.level debug
|
set log.console.level debug
|
||||||
}
|
}
|
||||||
test_MessageDelivery() {
|
test_MessageDelivery() {
|
||||||
@ -58,10 +59,26 @@ test_MessageDelivery() {
|
|||||||
# 4. list the messages from the receivers point of view (which ACKs them)
|
# 4. list the messages from the receivers point of view (which ACKs them)
|
||||||
executeOk_servald meshms list messages $SIDA2 $SIDA1
|
executeOk_servald meshms list messages $SIDA2 $SIDA1
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
assertStdoutGrep --stdout --matches=1 ":How are you\$"
|
assertStdoutGrep --stdout --matches=1 "^0:19:$SIDA1:unread:How are you\$"
|
||||||
assertStdoutGrep --stdout --matches=1 ":Hi\$"
|
assertStdoutGrep --stdout --matches=1 "^1:5:$SIDA1:unread:Hi\$"
|
||||||
assertStdoutLineCount '==' 4
|
assertStdoutLineCount '==' 4
|
||||||
# 5. list messages from the senders point of view after they have been delivered
|
# 5. mark the first message as read
|
||||||
|
executeOk_servald meshms read messages $SIDA2 $SIDA1 5
|
||||||
|
tfw_cat --stdout --stderr
|
||||||
|
executeOk_servald meshms list messages $SIDA2 $SIDA1
|
||||||
|
tfw_cat --stdout --stderr
|
||||||
|
assertStdoutGrep --stdout --matches=1 ":unread:How are you\$"
|
||||||
|
assertStdoutGrep --stdout --matches=1 "::Hi\$"
|
||||||
|
assertStdoutLineCount '==' 4
|
||||||
|
# 6. mark all messages as read
|
||||||
|
executeOk_servald meshms read messages $SIDA2
|
||||||
|
tfw_cat --stdout --stderr
|
||||||
|
executeOk_servald meshms list messages $SIDA2 $SIDA1
|
||||||
|
tfw_cat --stdout --stderr
|
||||||
|
assertStdoutGrep --stdout --matches=1 "::How are you\$"
|
||||||
|
assertStdoutGrep --stdout --matches=1 "::Hi\$"
|
||||||
|
assertStdoutLineCount '==' 4
|
||||||
|
# 7. list messages from the senders point of view after they have been delivered
|
||||||
executeOk_servald meshms list messages $SIDA1 $SIDA2
|
executeOk_servald meshms list messages $SIDA1 $SIDA2
|
||||||
tfw_cat --stdout --stderr
|
tfw_cat --stdout --stderr
|
||||||
assertStdoutGrep --stdout --matches=1 ":delivered:How are you\$"
|
assertStdoutGrep --stdout --matches=1 ":delivered:How are you\$"
|
||||||
@ -81,29 +98,33 @@ setup_MessageThreading() {
|
|||||||
executeOk_servald meshms send message $SIDB $SIDA "Never mind"
|
executeOk_servald meshms send message $SIDB $SIDA "Never mind"
|
||||||
start_servald_instances +A +B
|
start_servald_instances +A +B
|
||||||
}
|
}
|
||||||
test_MessageThreading() {
|
|
||||||
#TODO wait for bundle to arrive
|
|
||||||
sleep 3
|
|
||||||
|
|
||||||
|
has_unread_messages() {
|
||||||
|
executeOk_servald meshms list conversations $1
|
||||||
|
if ! grep ":unread\$" $_tfw_tmp/stdout; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
test_MessageThreading() {
|
||||||
set_instance +B
|
set_instance +B
|
||||||
|
wait_until has_unread_messages $SIDB
|
||||||
executeOk_servald meshms list messages $SIDB $SIDA
|
executeOk_servald meshms list messages $SIDB $SIDA
|
||||||
tfw_cat --stdout
|
tfw_cat --stdout
|
||||||
assertStdoutGrep --stdout --matches=1 "^0:24:$SIDA:unread:Still waiting\$"
|
assertStdoutGrep --stdout --matches=1 "^0:40:$SIDA:unread:Still waiting\$"
|
||||||
assertStdoutGrep --stdout --matches=1 "^1:0:$SIDA:unread:Hello can you hear me\$"
|
assertStdoutGrep --stdout --matches=1 "^1:24:$SIDA:unread:Hello can you hear me\$"
|
||||||
assertStdoutGrep --stdout --matches=1 "^2:41:$SIDB::Never mind\$"
|
assertStdoutGrep --stdout --matches=1 "^2:54:$SIDB::Never mind\$"
|
||||||
assertStdoutGrep --stdout --matches=1 "^3:0:$SIDB::Help Im trapped in a test case factory\$"
|
assertStdoutGrep --stdout --matches=1 "^3:41:$SIDB::Help Im trapped in a test case factory\$"
|
||||||
assertStdoutLineCount '==' 6
|
assertStdoutLineCount '==' 6
|
||||||
|
|
||||||
#TODO wait for bundle to arrive
|
|
||||||
sleep 3
|
|
||||||
|
|
||||||
set_instance +A
|
set_instance +A
|
||||||
|
wait_until has_unread_messages $SIDA
|
||||||
executeOk_servald meshms list messages $SIDA $SIDB
|
executeOk_servald meshms list messages $SIDA $SIDB
|
||||||
tfw_cat --stdout
|
tfw_cat --stdout
|
||||||
assertStdoutGrep --stdout --matches=1 "^0:41:$SIDB:unread:Never mind\$"
|
assertStdoutGrep --stdout --matches=1 "^0:54:$SIDB:unread:Never mind\$"
|
||||||
assertStdoutGrep --stdout --matches=1 "^1:0:$SIDB:unread:Help Im trapped in a test case factory\$"
|
assertStdoutGrep --stdout --matches=1 "^1:41:$SIDB:unread:Help Im trapped in a test case factory\$"
|
||||||
assertStdoutGrep --stdout --matches=1 "^2:24:$SIDA:delivered:Still waiting\$"
|
assertStdoutGrep --stdout --matches=1 "^2:40:$SIDA:delivered:Still waiting\$"
|
||||||
assertStdoutGrep --stdout --matches=1 "^3:0:$SIDA:delivered:Hello can you hear me\$"
|
assertStdoutGrep --stdout --matches=1 "^3:24:$SIDA:delivered:Hello can you hear me\$"
|
||||||
assertStdoutLineCount '==' 6
|
assertStdoutLineCount '==' 6
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,11 +146,11 @@ setup_listConversations() {
|
|||||||
test_listConversations() {
|
test_listConversations() {
|
||||||
executeOk_servald meshms list conversations $SIDA1
|
executeOk_servald meshms list conversations $SIDA1
|
||||||
tfw_cat --stdout
|
tfw_cat --stdout
|
||||||
assertStdoutIs --stderr --line=1 -e '3\n'
|
assertStdoutIs --stderr --line=1 -e '2\n'
|
||||||
assertStdoutIs --stderr --line=2 -e 'sid:read:delivered\n'
|
assertStdoutIs --stderr --line=2 -e 'sid:read\n'
|
||||||
assertStdoutGrep --stderr --matches=1 "^$SIDA2::delivered\$"
|
assertStdoutGrep --stderr --matches=1 "^$SIDA2:\$"
|
||||||
assertStdoutGrep --stderr --matches=1 "^$SIDA3:unread:delivered\$"
|
assertStdoutGrep --stderr --matches=1 "^$SIDA3:unread\$"
|
||||||
assertStdoutGrep --stderr --matches=1 "^$SIDA4:unread:delivered\$"
|
assertStdoutGrep --stderr --matches=1 "^$SIDA4:unread\$"
|
||||||
assertStdoutLineCount '==' 5
|
assertStdoutLineCount '==' 5
|
||||||
executeOk_servald meshms list conversations $SIDA1 1
|
executeOk_servald meshms list conversations $SIDA1 1
|
||||||
assertStdoutLineCount '==' 4
|
assertStdoutLineCount '==' 4
|
||||||
|
Loading…
x
Reference in New Issue
Block a user