diff --git a/pretty_json.rb b/pretty_json.rb new file mode 100755 index 0000000..fc131e8 --- /dev/null +++ b/pretty_json.rb @@ -0,0 +1,8 @@ +#!/usr/bin/ruby + +require 'json' + +data = JSON.parse( STDIN.read ) +puts JSON.pretty_generate(data, { + :indent => "\t" +}) diff --git a/src/controller/api/accounts.c b/src/controller/api/accounts.c index 401e1b3..263c212 100644 --- a/src/controller/api/accounts.c +++ b/src/controller/api/accounts.c @@ -171,7 +171,7 @@ bool route_api_account( struct http_request* req ) int count; } accounts; - account_list_followers( a, 0, 32, &accounts ); + account_list_followers( a, 0, 100, &accounts ); struct json_writer jw = { .f = http_request_get_response_body( req ), @@ -191,7 +191,7 @@ bool route_api_account( struct http_request* req ) int count; } accounts; - account_list_following( a, 0, 32, &accounts ); + account_list_following( a, 0, 100, &accounts ); struct json_writer jw = { .f = http_request_get_response_body( req ), diff --git a/src/controller/api/status.c b/src/controller/api/status.c index 95259a1..079f3ba 100644 --- a/src/controller/api/status.c +++ b/src/controller/api/status.c @@ -9,6 +9,7 @@ #include "model/status/react.h" #include "model/account.h" #include "model/ap/activity.h" +#include "model/ap/outbox_envelope.h" #include "view/api/Account.h" @@ -171,12 +172,16 @@ bool handle_post( struct http_request* req, struct account* a ) struct ap_activity* create = ap_activity_create_Create(note); ap_activity_save(create); - account_deliver_activity_to_followers( a, create ); + struct outbox_envelope_list oel; + memset(&oel,0,sizeof(oel)); + account_deliver_activity_to_followers( a, create, &oel ); + printf( "Delivering to %d inboxes\n", oel.count ); + outbox_envelope_list_save(&oel); + outbox_envelope_list_free_composite(&oel); ap_activity_free(create); ap_activity_free(note); - http_request_send_headers( req, 200, "application/json", true ); FILE* f = http_request_get_response_body(req); api_status_write_as_json(s,f); @@ -200,6 +205,10 @@ bool handle_repost( struct http_request* req, struct status* s ) struct account* owner = account_from_id(owner_account_id); struct status* repost = status_new_repost( s, owner ); + // Flag the status as reposted + s->reposted_status_id = repost->id; + status_save(s); + // Add repost to timelines status_add_to_timeline( repost, owner->id ); status_add_to_timeline( repost, home_timeline_id ); diff --git a/src/controller/outbox.c b/src/controller/outbox.c index ecc89e6..cc6e385 100644 --- a/src/controller/outbox.c +++ b/src/controller/outbox.c @@ -67,8 +67,13 @@ static bool process_envelope( struct outbox_envelope* env ) postdata[size] = '\0'; printf( "post: %s\n", postdata ); + const char* inbox = to_account->inbox; + if( env->shared_inbox ) { + inbox = env->shared_inbox; + } + struct http_signature hs; - if( !http_signature_make( to_account->inbox, keys, &hs ) ) { + if( !http_signature_make( inbox, keys, &hs/*, postdata */ ) ) { printf( "! Failed to make HTTP signature\n" ); goto failed; } @@ -85,10 +90,10 @@ static bool process_envelope( struct outbox_envelope* env ) char user_agent[512]; snprintf( user_agent, sizeof(user_agent), "User-Agent: curl (Apogee/0.1; +https://%s/)", g_server_name ); - printf( "Performing post to %s\n", to_account->inbox ); + printf( "Performing post to %s\n", inbox ); long status_code = -1; const void* request[] = { - HTTP_REQ_URL, to_account->inbox, + HTTP_REQ_URL, inbox, HTTP_REQ_HEADER, user_agent, HTTP_REQ_HEADER, date_header, HTTP_REQ_HEADER, sign_header, @@ -143,7 +148,7 @@ discard: goto cleanup; } -static bool process_one() +static bool process_pending() { int head = fs_list_get("data/outbox/HEAD"); int tail = fs_list_get("data/outbox/TAIL"); @@ -165,6 +170,7 @@ static bool process_one() } outbox_envelope_free(env); } + fflush(stdout); } return result; @@ -175,7 +181,7 @@ void process_outbox() { while( !terminate ) { bool activity = false; - activity |= process_one(); + activity |= process_pending(); //activity |= cleanup_outbox(); if( !activity ) { diff --git a/src/ffdb b/src/ffdb index f631295..7100619 160000 --- a/src/ffdb +++ b/src/ffdb @@ -1 +1 @@ -Subproject commit f63129506085ac418d9ad9a4dd3845fad07fa604 +Subproject commit 71006190b8e05366e355455174bcf2308805686c diff --git a/src/model/account.c b/src/model/account.c index eeae8f8..bbe7a61 100644 --- a/src/model/account.c +++ b/src/model/account.c @@ -69,6 +69,7 @@ static struct json_object_field account_layout[] = { JSON_FIELD_ARRAY_OF_STRINGS( aliases, false ), JSON_FIELD_ENUM( account_type, account_types_enum, true ), JSON_FIELD_STRING( inbox, false ), + JSON_FIELD_STRING( shared_inbox, false ), JSON_FIELD_STRING( note, false ), { .key = "followers", @@ -257,6 +258,9 @@ bool account_sync_from_activity_pub( unsigned int account_id ) a->account_type = at_remote_activity_pub; a->account_url = strdup(ap->url); a->inbox = strdup(ap->inbox); + if( ap->shared_inbox ) { + a->shared_inbox = strdup(ap->shared_inbox); + } if( 0 == strncmp( ap->id, "https://", 8 ) ) { char* server_name = strdup(&ap->id[8]); @@ -381,6 +385,7 @@ void account_free( struct account* a ) free(a->handle); free(a->server); free(a->inbox); + free(a->shared_inbox); free(a->display_name); free(a->account_url); free(a->avatar.url); @@ -506,8 +511,15 @@ void account_announce( struct account* a, struct status* s ) str = strdup(origin_post_account->account_url); array_append( &act->to, sizeof(str), &str ); - account_deliver_activity_to_followers( a, act ); - account_deliver_activity( origin_post_account, act ); + struct outbox_envelope_list oel; + memset(&oel,0,sizeof(oel)); + + account_deliver_activity_to_followers( a, act, &oel ); + account_deliver_activity( origin_post_account, act, &oel ); + + printf( "Delivering to %s inboxes\n", oel.count ); + outbox_envelope_list_save(&oel); + outbox_envelope_list_free_composite(&oel); ap_activity_save(act); ap_activity_write_to_FILE( act, stdout ); @@ -517,17 +529,31 @@ cleanup: ap_activity_free(act); } -void account_deliver_activity( struct account* a, struct ap_activity* act ) +void account_deliver_activity( struct account* a, struct ap_activity* act, struct outbox_envelope_list* oel ) { printf( "Delivering activity %s to account %s\n", act->id, a->account_url ); + if( a->shared_inbox ) { + // Check if the sh + for( int i = 0; i < oel->count; ++i ) { + struct outbox_envelope* e = oel->items[i]; + if( e->shared_inbox && 0 == strcmp(e->shared_inbox,a->shared_inbox) ) { + printf( "\tUsing shared inbox %s already in delivery list\n", a->shared_inbox ); + // This account will get the message delivered thru the shared inbox + return; + } + } + } + struct outbox_envelope* env = outbox_envelope_new(); - env->activity_id = act->local_id; - env->account_id = a->id; - outbox_envelope_save(env); - outbox_envelope_free(env); + env->activity_id = act->local_id; + if( a->shared_inbox ) { + env->shared_inbox = strdup(a->shared_inbox); + } + env->account_id = a->id; + array_append( oel, sizeof(env), &env ); } -void account_deliver_activity_to_followers( struct account* a, struct ap_activity* act ) +void account_deliver_activity_to_followers( struct account* a, struct ap_activity* act, struct outbox_envelope_list* oel ) { printf( "Delivering activity %s to followers of account %s\n", act->id, a->account_url ); struct { @@ -550,7 +576,7 @@ void account_deliver_activity_to_followers( struct account* a, struct ap_activit int account_id = atoi(keys.items[j]); printf( "account_id = %d\n", account_id ); struct account* follower_account = account_from_id(account_id); - account_deliver_activity( follower_account, act ); + account_deliver_activity( follower_account, act, oel ); account_free(follower_account); } } diff --git a/src/model/account.h b/src/model/account.h index 83a073b..dbfa8ac 100644 --- a/src/model/account.h +++ b/src/model/account.h @@ -31,6 +31,7 @@ struct account int account_type; char* account_url; char* inbox; + char* shared_inbox; struct { char* url; @@ -46,6 +47,7 @@ struct account int following_count; int status_count; int follow_activity; + bool follow_confirmed; char* note; @@ -72,8 +74,11 @@ bool account_sync_from_activity( struct account* a, struct ap_activity* act ); struct ap_account; struct ap_account* account_activity_pub_data( struct account* a ); -void account_deliver_activity( struct account* a, struct ap_activity* act ); -void account_deliver_activity_to_followers( struct account* a, struct ap_activity* act ); +struct outbox_envelope; +struct outbox_envelope_list; + +void account_deliver_activity( struct account* a, struct ap_activity* act, struct outbox_envelope_list* oel ); +void account_deliver_activity_to_followers( struct account* a, struct ap_activity* act, struct outbox_envelope_list* oel ); struct crypto_keys* account_get_public_key( struct account* a, const char* key_name ); struct crypto_keys* account_get_private_key( struct account* a ); diff --git a/src/model/ap/account.c b/src/model/ap/account.c index f36a14d..b64863c 100644 --- a/src/model/ap/account.c +++ b/src/model/ap/account.c @@ -47,6 +47,14 @@ static struct json_object_field image_layout[] = { }; #define OBJ_TYPE struct ap_account +static struct json_object_field endpoints_layout[] = { + { + .key = "sharedInbox", + .offset = offsetof(OBJ_TYPE,shared_inbox), + .required = false, + .type = &json_field_string, + }, +}; static struct json_object_field ap_account_layout[] = { JSON_FIELD_STRING( id, true ), JSON_FIELD_ENUM( type, ap_account_type_enum, true ), @@ -65,6 +73,13 @@ static struct json_object_field ap_account_layout[] = { .type = &json_field_object_composite, .composite_layout = public_key_layout }, + { + .key = "endpoints", + .offset = 0, + .required = false, + .type = &json_field_object_composite, + .composite_layout = endpoints_layout, + }, JSON_FIELD_BOOL( discoverable, false ), { .key = "icon", @@ -118,7 +133,8 @@ void ap_account_free( struct ap_account* acc ) } void ap_account_debug_dump( struct ap_account* acc ) { - FILE* f = stdout; - #include "src/model/ap/account.debug_dump.txt.inc" + json_write_object_layout_to_FILE( stdout, "\t", ap_account_layout, acc ); + //FILE* f = stdout; + //#include "src/model/ap/account.debug_dump.txt.inc" } diff --git a/src/model/ap/account.h b/src/model/ap/account.h index 9f0e192..cc982f1 100644 --- a/src/model/ap/account.h +++ b/src/model/ap/account.h @@ -23,6 +23,7 @@ struct ap_account char* name; char* preferredUsername; char* inbox; + char* shared_inbox; char* outbox; char* featured; diff --git a/src/model/ap/outbox_envelope.c b/src/model/ap/outbox_envelope.c index df78483..8f2ea3d 100644 --- a/src/model/ap/outbox_envelope.c +++ b/src/model/ap/outbox_envelope.c @@ -10,7 +10,7 @@ #define OBJ_TYPE struct outbox_envelope static struct json_object_field layout[] = { - JSON_FIELD_BOOL( use_shared_inbox, false ), + JSON_FIELD_STRING( shared_inbox, false ), JSON_FIELD_BOOL( sent, false ), JSON_FIELD_INTEGER( retries, false ), JSON_FIELD_DATETIME( retry_after, false ), @@ -42,6 +42,8 @@ struct outbox_envelope* outbox_envelope_new() } void outbox_envelope_free( struct outbox_envelope* env ) { + if( !env ) { return; } + free(env->shared_inbox); free(env); } @@ -92,3 +94,18 @@ void outbox_envelope_delete( struct outbox_envelope* env ) outbox_envelope_free(env); } +void outbox_envelope_list_save( struct outbox_envelope_list* oel ) +{ + for( int i = 0; i < oel->count; ++i ) { + outbox_envelope_save(oel->items[i]); + } +} +void outbox_envelope_list_free_composite( struct outbox_envelope_list* oel ) +{ + for( int i = 0; i < oel->count; ++i ) { + free(oel->items[i]); + } + free(oel->items); +} + + diff --git a/src/model/ap/outbox_envelope.h b/src/model/ap/outbox_envelope.h index c9d4cad..de2790d 100644 --- a/src/model/ap/outbox_envelope.h +++ b/src/model/ap/outbox_envelope.h @@ -8,7 +8,7 @@ struct outbox_envelope int id; int activity_id; int account_id; - bool use_shared_inbox; + char* shared_inbox; bool sent; time_t retry_after; int retries; @@ -23,4 +23,12 @@ void outbox_envelope_save( struct outbox_envelope* env ); //struct outbox_envelope* outbox_envelope_load_next(); void outbox_envelope_delete( struct outbox_envelope* env ); +struct outbox_envelope_list +{ + struct outbox_envelope** items; + int count; +}; + +void outbox_envelope_list_save( struct outbox_envelope_list* oel ); +void outbox_envelope_list_free_composite( struct outbox_envelope_list* oel ); diff --git a/src/model/status.c b/src/model/status.c index 5569ade..10c72b3 100644 --- a/src/model/status.c +++ b/src/model/status.c @@ -38,6 +38,7 @@ static struct json_object_field status_layout[] = { JSON_FIELD_INTEGER( in_reply_to, false ), JSON_FIELD_INTEGER( repost_id, false ), JSON_FIELD_INTEGER( root_status_id, false ), + JSON_FIELD_INTEGER( reposted_status_id, false ), JSON_FIELD_ARRAY_OF_STRINGS( media, false ), JSON_FIELD_ARRAY_OF_TYPE( reacts, false, status_react_type ), @@ -250,6 +251,7 @@ struct status* status_fetch_from_uri( const char* uri ) memset(s,0,sizeof(*s)); s->remote = true; + s->account_id = -1; s->stub = true; s->published = time(NULL); s->url = strdup(uri); diff --git a/src/model/status.h b/src/model/status.h index 6086e54..bad982a 100644 --- a/src/model/status.h +++ b/src/model/status.h @@ -24,6 +24,7 @@ struct status int in_reply_to; int repost_id; int root_status_id; + int reposted_status_id; // if this post was reposted, this will be the id of that status struct { char** items;