Continue s/ap_activity/ap_object/, remove ap_account and use ap_object instead, move actor/attribtuedTo fixup code to controller/inbox.c

master
teknomunk 1 year ago
parent 1a18b603f5
commit 1c1df8270c

@ -35,7 +35,7 @@ bool route_ap_note( struct http_request* req )
http_request_send_headers( req, 200, "application/ld+json", true );
FILE* f = http_request_get_response_body( req );
ap_activity_write_to_FILE( act, f );
ap_object_write_to_FILE( act, f );
fflush(f);
ap_object_free(act);
@ -56,7 +56,7 @@ bool route_ap_outbox( struct http_request* req )
http_request_send_headers( req, 200, "application/ld+json", true );
FILE* f = http_request_get_response_body( req );
ap_activity_write_to_FILE( outbox, f );
ap_object_write_to_FILE( outbox, f );
fflush(f);
ap_object_free(outbox);
@ -70,7 +70,7 @@ bool route_ap_outbox( struct http_request* req )
http_request_send_headers( req, 200, "application/ld+json", true );
FILE* f = http_request_get_response_body( req );
ap_activity_write_to_FILE( outbox_page, f );
ap_object_write_to_FILE( outbox_page, f );
fflush(f);
ap_object_free(outbox_page);

@ -154,7 +154,7 @@ static bool handle_command_test( struct cli_request* req )
struct account* owner_account = account_from_id( owner_account_id );
struct ap_object* obj = account_ap_actor( owner_account );
ap_activity_write_to_FILE( obj, stdout );
ap_object_write_to_FILE( obj, stdout );
printf( "\n" );
ap_object_free(obj);

@ -13,10 +13,8 @@
#include "model/account.h"
#include "model/notification.h"
#include "model/ap/activity.h"
#include "model/ap/account.h"
#include "model/ap/inbox_envelope.h"
#include "model/crypto/http_sign.h"
//#include "model/timeline.h"
// Stdlib
#include <stdio.h>
@ -42,11 +40,11 @@ bool route_inbox( struct http_request* req )
return true;
}
static bool route_follow( struct ap_activity* act )
static bool route_follow( struct ap_object* act )
{
struct account* follower = NULL;
bool res = false;
struct ap_activity* accept = NULL;
struct ap_object* accept = NULL;
const char* target = act->object.ref;
struct account* a = account_from_uri( target );
@ -62,6 +60,10 @@ static bool route_follow( struct ap_activity* act )
if( !follower ) {
follower = account_fetch_from_uri( act->actor );
}
if( follower->id == owner_account_id ) {
// Something went wrong, bail
goto failed;
}
if( !follower ) {
printf( "Unable to fetch account for %s\n", act->actor );
goto failed;
@ -75,6 +77,7 @@ static bool route_follow( struct ap_activity* act )
success:
res = true;
goto cleanup;
cleanup:
account_free(a);
account_free(follower);
@ -85,7 +88,7 @@ failed:
goto cleanup;
}
static bool route_undo_Announce( struct ap_activity* act )
static bool route_undo_Announce( struct ap_object* act )
{
struct status* s = NULL;
@ -97,7 +100,7 @@ static bool route_undo_Announce( struct ap_activity* act )
status_free(s);
return true;
}
static bool route_undo_Like( struct ap_activity* act )
static bool route_undo_Like( struct ap_object* act )
{
struct status* s = NULL;
s = status_from_uri( act->object.ptr->id );
@ -107,7 +110,7 @@ static bool route_undo_Like( struct ap_activity* act )
return false;
}
static bool route_undo_activity( struct ap_activity* act )
static bool route_undo_activity( struct ap_object* act )
{
if( act->object.tag != apaot_activity ) {
printf( "Can't undo reference activities, discarding...\n" );
@ -133,7 +136,7 @@ static bool route_undo_activity( struct ap_activity* act )
enum {
error_lookup_failed = 1,
};
static struct status* lookup_object_status( struct ap_activity* act, int* error )
static struct status* lookup_object_status( struct ap_object* act, int* error )
{
struct status* s = NULL;
@ -175,7 +178,7 @@ static struct status* lookup_object_status( struct ap_activity* act, int* error
return NULL;
}
static struct account* lookup_actor_account( struct ap_activity* act )
static struct account* lookup_actor_account( struct ap_object* act )
{
struct account* a = account_from_uri( act->actor );
if( a ) { return a; }
@ -184,7 +187,7 @@ static struct account* lookup_actor_account( struct ap_activity* act )
return a;
}
static bool route_like( struct ap_activity* act )
static bool route_like( struct ap_object* act )
{
struct status* s = NULL;
struct account* liker = NULL;
@ -211,7 +214,7 @@ failed:
goto cleanup;
}
static bool route_emoji_react( struct ap_activity* act )
static bool route_emoji_react( struct ap_object* act )
{
struct status* s = NULL;
struct account* reactor = NULL;
@ -234,7 +237,7 @@ failed:
goto cleanup;
}
static bool route_update_Person( struct ap_activity* act )
static bool route_update_Person( struct ap_object* act )
{
bool result = false;
struct account* a = account_fetch_from_uri( act->object.ptr->id );
@ -253,7 +256,7 @@ failed:
goto cleanup;
}
static bool route_update( struct ap_activity* act )
static bool route_update( struct ap_object* act )
{
struct status* s = NULL;
@ -287,7 +290,7 @@ static bool route_update( struct ap_activity* act )
return true;
}
static bool route_move( struct ap_activity* act )
static bool route_move( struct ap_object* act )
{
bool result = false;
struct account* a = NULL;
@ -312,6 +315,7 @@ is_alias:
discard:
result = true;
goto cleanup;
cleanup:
account_free(a);
return result;
@ -416,6 +420,7 @@ check_is_follower:
discard:
result = true;
goto cleanup;
cleanup:
account_free(actor_account);
account_free(owner_account);
@ -426,7 +431,7 @@ failed:
goto cleanup;
}
static bool route_block( struct ap_activity* act )
static bool route_block( struct ap_object* act )
{
bool result = false;
struct account* actor_account = NULL;
@ -456,17 +461,17 @@ failed:
goto cleanup;
}
static bool route_accept( struct ap_activity* act )
static bool route_accept( struct ap_object* act )
{
// TODO: actually handle accepts
// In particular, this needs to change a follow request to a following accepted
return true;
}
bool route_activity( struct ap_activity* act )
bool route_activity( struct ap_object* act )
{
printf( "Handling %s\n", act->id );
ap_activity_write_to_FILE( act, stdout );
ap_object_write_to_FILE( act, stdout );
switch( act->type ) {
case apat_undo: return route_undo_activity(act);
@ -490,7 +495,7 @@ bool route_activity( struct ap_activity* act )
static bool process_one()
{
// Items requiring cleanup
struct ap_activity* act = NULL;
struct ap_object* act = NULL;
struct ap_envelope* env = NULL;
bool result = false;
@ -508,15 +513,24 @@ static bool process_one()
bool step_tail = false;
if( !env ) {
printf( "Failed to parse envelope+activity for data/inbox/%d.json\n", id );
printf( "! Failed to parse envelope+activity for data/inbox/%d.json\n", id );
goto failed;
}
// Load activity
FILE* f = fmemopen( env->body, strlen(env->body), "r" );
act = ap_activity_from_FILE(f);
act = ap_object_from_FILE(f);
if( !act ) { goto failed; }
// Sanitize actor
if( !act->actor ) {
if( !act->attributed_to ) {
printf( "! activity does not have actor or attributedTo property, can't process\n" );
goto discard;
}
act->actor = strdup(act->attributed_to);
}
// Discard delete requests
if( act->type == apat_delete ) {
goto discard;

@ -1,7 +1,6 @@
#include "../inbox.h"
#include "model/account.h"
#include "model/ap/account.h"
#include "model/ap/activity.h"
#include "model/status.h"
@ -12,7 +11,7 @@ bool route_add( struct ap_activity* act )
bool result = false;
struct status* s = NULL;
struct account* a = NULL;
struct ap_account* apa = NULL;
struct ap_object* apa = NULL;
// Make sure this is to pin a status
a = account_from_uri_or_fetch( act->actor );
@ -20,7 +19,7 @@ bool route_add( struct ap_activity* act )
printf( "Don't have account...\n" );
goto failed;
} // Don't have ActivityPub account data, try again later
apa = account_activity_pub_data(a);
apa = account_activity_pub(a);
if( 0 != strcmp( apa->featured, act->target ) ) {
printf( "Not adding to featured...\n" );
printf( "apa->featured = %s\n", apa->featured );
@ -40,7 +39,7 @@ bool route_add( struct ap_activity* act )
result = true;
cleanup:
status_free(s);
ap_account_free(apa);
ap_object_free(apa);
account_free(a);
return result;
failed:

@ -60,7 +60,7 @@ static bool process_envelope( struct outbox_envelope* env )
size_t size;
{
FILE* f2 = open_memstream( &postdata, &size );
ap_activity_write_to_FILE( act, f2 );
ap_object_write_to_FILE( act, f2 );
fclose(f2);
}

@ -32,7 +32,7 @@ static bool handle_followers( struct http_request* req )
http_request_send_headers( req, 200, "application/activity+json", true );
FILE* f = http_request_get_response_body(req);
ap_activity_write_to_FILE( obj, f );
ap_object_write_to_FILE( obj, f );
ap_object_free(obj);
} else if( http_request_route( req, "/page-" ) ) {
printf( "/page-\n" );
@ -47,7 +47,7 @@ static bool handle_followers( struct http_request* req )
http_request_send_headers( req, 200, "application/activity+json", true );
FILE* f = http_request_get_response_body(req);
ap_activity_write_to_FILE( obj, f );
ap_object_write_to_FILE( obj, f );
ap_object_free(obj);
}
@ -73,7 +73,7 @@ static bool handle_following( struct http_request* req )
http_request_send_headers( req, 200, "application/activity+json", true );
FILE* f = http_request_get_response_body(req);
ap_activity_write_to_FILE( obj, f );
ap_object_write_to_FILE( obj, f );
ap_object_free(obj);
} else if( http_request_route( req, "/page-" ) ) {
printf( "/page-\n" );
@ -88,7 +88,7 @@ static bool handle_following( struct http_request* req )
http_request_send_headers( req, 200, "application/activity+json", true );
FILE* f = http_request_get_response_body(req);
ap_activity_write_to_FILE( obj, f );
ap_object_write_to_FILE( obj, f );
ap_object_free(obj);
}
@ -113,7 +113,7 @@ static bool handle_owner_actor( struct http_request* req )
FILE* f = http_request_get_response_body(req);
struct ap_object* obj = account_ap_actor( owner_account );
ap_activity_write_to_FILE( obj, f );
ap_object_write_to_FILE( obj, f );
ap_object_free(obj);
account_free( owner_account );

@ -5,7 +5,6 @@
#include "collections/array.h"
#include "model/account.h"
#include "model/ap/account.h"
#include "model/ap/activity.h"
#include "model/ap/activity/rsa_signature_2017.h"
#include "model/ap/outbox_envelope.h"

@ -1 +1 @@
Subproject commit d1ca725373342a37aecaa56f88c463057807e613
Subproject commit 36c3fb214952ab71a0f3ee7c235a78c19c2ac5a8

@ -14,7 +14,6 @@
#include "model/server.h"
#include "model/status.h"
#include "model/ap/activity.h"
#include "model/ap/account.h"
#include "model/crypto/keys.h"
#include "model/notification.h"

@ -99,7 +99,6 @@ void account_list_followers( struct account* a, int offset, int limit, void* id_
void account_list_following( struct account* a, int offset, int limit, void* id_array );
// Activity pub data
struct ap_account* account_activity_pub_data( struct account* a ); // TODO: convert this to struct ap_object*
struct ap_object* account_activity_pub( struct account* a );
struct ap_object* account_ap_actor( struct account* a );
struct ap_object* account_ap_outbox( struct account* a );

@ -7,22 +7,17 @@
#include "model/server.h"
#include "model/status.h"
#include "model/ap/activity.h"
#include "model/ap/account.h"
#include <stdlib.h>
#include <string.h>
// TODO: convert this to struct ap_object*
struct ap_account* account_activity_pub_data( struct account* a )
struct ap_object* account_activity_pub( struct account* a )
{
// Pass thru remote activity pub actor data if present
char filename[512];
return ap_account_from_file(
format( filename, 512, "data/accounts/%d/ap.json", a->id )
);
}
struct ap_object* obj = ap_object_from_file( format( filename, 512, "data/accounts/%d/ap.json", a->id ) );
if( obj ) { return obj; }
struct ap_object* account_activity_pub( struct account* a )
{
return account_ap_actor(a);
}

@ -6,7 +6,6 @@
// Model
#include "model/ap/activity.h"
#include "model/ap/account.h"
// Standard Library
#include <string.h>
@ -14,41 +13,48 @@
bool account_sync_from_activity_pub( unsigned int account_id )
{
bool result = false;
char filename[512];
struct ap_account* ap = ap_account_from_file(
format( filename, 512, "data/accounts/%d/ap.json", account_id )
);
snprintf( filename, 512, "data/accounts/%d/ap.json", account_id );
printf( "ap_object_from_file( %s )\n", filename );
struct ap_object* obj = ap_object_from_file(filename);
printf( "obj = "); ap_object_write_to_FILE(obj,stdout);
printf( "\n" );
struct account* a = malloc(sizeof(struct account));
memset(a,0,sizeof(*a));
a->id = account_id;
if( !ap ) {
if( !obj ) {
printf( "? Failed to sync account %d from %s, creating stub\n", account_id, filename );
return false;
goto failed;
}
printf( "ap = " ); ap_account_debug_dump(ap);
a->handle = strdup(ap->preferredUsername);
if( ap->name ) {
a->display_name = strdup(ap->name);
a->handle = strdup(obj->preferred_username);
if( obj->name ) {
a->display_name = strdup(obj->name);
} else {
a->display_name = strdup(ap->preferredUsername);
a->display_name = strdup(obj->preferred_username);
}
if( ap->avatar ) {
a->avatar.url = strdup(ap->avatar);
a->avatar.static_url = strdup(ap->avatar);
if( obj->avatar ) {
a->avatar.url = strdup(obj->avatar);
a->avatar.static_url = strdup(obj->avatar);
}
a->bot = ( ap->type != apacct_Person );
if( obj->banner ) {
a->banner = strdup(obj->banner);
}
a->bot = ( obj->type != apot_person );
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);
a->account_url = strdup(obj->url);
a->inbox = strdup(obj->inbox);
if( obj->endpoints.shared_inbox ) {
a->shared_inbox = strdup(obj->endpoints.shared_inbox);
}
if( 0 == strncmp( ap->id, "https://", 8 ) ) {
char* server_name = strdup(&ap->id[8]);
if( 0 == strncmp( obj->id, "https://", 8 ) ) {
char* server_name = strdup(&obj->id[8]);
char* discard;
strtok_r(server_name,"/",&discard);
@ -56,7 +62,7 @@ bool account_sync_from_activity_pub( unsigned int account_id )
}
// Extract out the public key
char* id = strdup(ap->public_key.id);
char* id = strdup(obj->public_key->id);
char* key_id = NULL;
strtok_r( id, "#", &key_id );
FILE* key_pem = fopen( format(filename,sizeof(filename),"data/accounts/%d/%s.pem", a->id, key_id), "w" );
@ -64,7 +70,7 @@ bool account_sync_from_activity_pub( unsigned int account_id )
printf( "Unable to save public key to %s\n", filename );
} else {
printf( "Writing public key to %s\n", filename );
fprintf( key_pem, "%s", ap->public_key.pem );
fprintf( key_pem, "%s", obj->public_key->public_key );
fclose(key_pem);
}
free(id);
@ -72,10 +78,18 @@ bool account_sync_from_activity_pub( unsigned int account_id )
account_save(a);
account_index_webfinger(a);
ap_account_free(ap);
goto succeeded;
succeeded:
result = true;
goto cleanup;
cleanup:
ap_object_free(obj);
account_free(a);
return true;
return result;
failed:
result = false;
goto cleanup;
}
bool account_sync_from_activity( struct account* a, struct ap_object* act )

@ -133,7 +133,7 @@ void account_announce( struct account* a, struct status* original_post, struct s
outbox_envelope_list_free_composite(&oel);
ap_activity_save(act);
ap_activity_write_to_FILE( act, stdout );
ap_object_write_to_FILE( act, stdout );
// Link status to activity
local_repost->activity_id = act->local_id;

@ -1,150 +0,0 @@
#include "account.h"
#include "json/json.h"
#include "json/layout.h"
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
static struct json_enum ap_account_type_enum[] = {
{ "Person", apacct_Person },
{ NULL, 0 },
};
#define OBJ_TYPE struct ap_crypto_key
static struct json_object_field public_key_layout[] = {
JSON_FIELD_STRING( id, true ),
JSON_FIELD_STRING( owner, true ),
{
.key = "publicKeyPem",
.offset = offsetof(struct ap_crypto_key,pem),
.required = true,
.type = &json_field_string
},
JSON_FIELD_END,
};
#undef OBJ_TYPE
static struct json_object_field icon_layout[] = {
{
.key = "url",
.offset = offsetof(struct ap_account,avatar),
.required = true,
.type = &json_field_string
},
JSON_FIELD_END,
};
static struct json_object_field image_layout[] = {
{
.key = "url",
.offset = offsetof(struct ap_account,banner),
.required = true,
.type = &json_field_string
},
JSON_FIELD_END,
};
#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,
},
JSON_FIELD_END,
};
static struct json_object_field ap_account_layout[] = {
JSON_FIELD_STRING( id, true ),
JSON_FIELD_ENUM( type, ap_account_type_enum, true ),
JSON_FIELD_STRING( url, true ),
JSON_FIELD_STRING( name, false ),
JSON_FIELD_STRING( preferredUsername, true ),
JSON_FIELD_STRING( inbox, true ),
JSON_FIELD_STRING( summary, true ),
JSON_FIELD_STRING( featured, false ),
JSON_FIELD_STRING( followers, false ),
JSON_FIELD_STRING( following, false ),
{
.key = "publicKey",
.offset = offsetof(struct ap_account,public_key),
.required = false,
.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",
.offset = 0,
.required = false,
.type = &json_field_object_composite,
.composite_layout = icon_layout
},
{
.key = "image",
.offset = 0,
.required = false,
.type = &json_field_object_composite,
.composite_layout = image_layout
},
JSON_FIELD_END,
};
#undef OBJ_TYPE
struct ap_account* ap_account_from_file( const char* filename )
{
struct ap_account* acc = malloc(sizeof(struct ap_account));
memset(acc,0,sizeof(struct ap_account));
if( !json_read_object_layout_from_file( filename, ap_account_layout, acc ) ) {
ap_account_free(acc);
return NULL;
}
return acc;
}
void ap_account_free( struct ap_account* acc )
{
if( !acc ) { return; }
free(acc->id);
free(acc->url);
free(acc->name);
free(acc->preferredUsername);
free(acc->inbox);
free(acc->shared_inbox);
free(acc->outbox);
free(acc->featured);
free(acc->followers);
free(acc->following);
free(acc->avatar);
free(acc->banner);
free(acc->summary);
free(acc->public_key.id);
free(acc->public_key.owner);
free(acc->public_key.pem);
free(acc);
}
void ap_account_debug_dump( struct ap_account* acc )
{
json_write_object_layout_to_FILE( stdout, "\t", ap_account_layout, acc );
//FILE* f = stdout;
//#include "src/model/ap/account.debug_dump.txt.inc"
}

@ -1,27 +0,0 @@
%p{acc} = {
.id = %s{acc->id},
.type = %d{acc->type},
.url = %s{acc->url},
.name = %s{acc->name},
.preferredUsername = %s{acc->preferredUsername},
.inbox = %s{acc->inbox},
.outbox = %s{acc->outbox},
.featured = %s{acc->featured},
.followers = %s{acc->followers},
.following = %s{acc->following},
.avatar = %s{acc->avatar},
.banner = %s{acc->banner},
.summary = %s{acc->summary},
.discoverable = %c{ acc->discoverable ? 'T' : 'F' },
.public_key = {
.id = %s{acc->public_key.id},
.owner = %s{acc->public_key.owner},
.pem = %s{acc->public_key.pem}
}
}

@ -1,47 +0,0 @@
#pragma once
#include <stdbool.h>
enum ap_account_type
{
apacct_Person = 1,
};
struct ap_crypto_key
{
char* id;
char* owner;
char* pem;
};
struct ap_account
{
char* id;
int type;
char* url;
char* name;
char* preferredUsername;
char* inbox;
char* shared_inbox;
char* outbox;
char* featured;
char* followers;
char* following;
char* avatar;
char* banner;
char* summary;
bool discoverable;
struct ap_crypto_key public_key;
};
struct ap_account* ap_account_from_file( const char* filename );
void ap_account_free( struct ap_account* acc );
void ap_account_debug_dump( struct ap_account* acc );

@ -228,12 +228,13 @@ extern struct json_object_field ap_object_layout[];
struct ap_object* ap_activity_new();
struct ap_object* ap_activity_dup( struct ap_object* o );
struct ap_object* ap_activity_from_FILE( FILE* f );
struct ap_object* ap_object_from_FILE( FILE* f );
struct ap_object* ap_object_from_file( const char* filename );
struct ap_object* ap_activity_from_local_id( int id );
void ap_object_free( struct ap_object* o );
void ap_activity_free_composite( struct ap_object* o );
void ap_activity_write_to_FILE( struct ap_object* o, FILE* f );
void ap_object_write_to_FILE( struct ap_object* o, FILE* f );
void ap_activity_save( struct ap_object* o );
struct ap_object* ap_activity_create_accept( struct ap_object* act );

@ -313,7 +313,7 @@ struct json_object_field ap_object_layout[] = {
JSON_FIELD_TYPE_OBJECT_LAYOUT_WITH_DEFAULTS( ap_object );
struct ap_object* ap_activity_from_FILE( FILE* f )
struct ap_object* ap_object_from_FILE( FILE* f )
{
struct ap_object* act = malloc(sizeof(struct ap_object));
memset(act,0,sizeof(*act));
@ -323,25 +323,29 @@ struct ap_object* ap_activity_from_FILE( FILE* f )
return NULL;
}
if( !act->actor ) {
if( !act->attributed_to ) {
ap_object_free(act);
return NULL;
}
act->actor = strdup(act->attributed_to);
}
return act;
}
struct ap_object* ap_object_from_file( const char* filename )
{
FILE* f = fopen(filename,"r");
if( !f ) { return NULL; }
struct ap_object* obj = ap_object_from_FILE(f);
return obj;
}
void ap_activity_write_to_FILE( struct ap_object* act, FILE* f )
void ap_object_write_to_FILE( struct ap_object* obj, FILE* f )
{
struct json_writer jw = {
.f = f,
.indentation = "\t",
.indent = 0,
};
json_write_pretty_object_layout( &jw, ap_object_layout, act );
if( !obj ) {
fprintf( f, "null" );
return;
}
json_write_pretty_object_layout( &jw, ap_object_layout, obj );
}
void ap_activity_save( struct ap_object* act )
{

@ -202,10 +202,10 @@ void status_add_repost( struct status* s, struct status* repost )
{
// TODO: implement
}
bool status_sync_from_activity_pub( struct status* s, struct ap_activity* act )
bool status_sync_from_activity_pub( struct status* s, struct ap_object* act )
{
printf( "Syncing status from activity %s\n", act->id );
ap_activity_write_to_FILE( act, stdout );
ap_object_write_to_FILE( act, stdout );
bool result = false;
struct account* a = account_from_uri_or_fetch(act->actor);
if( !a ) {
@ -326,7 +326,7 @@ bool pull_remote_file( const char* filename, const char* uri )
bool status_sync_from_uri( struct status* s, const char* uri )
{
struct ap_activity* act = NULL;
struct ap_object* act = NULL;
FILE* f = NULL;
bool result = false;
@ -341,7 +341,7 @@ bool status_sync_from_uri( struct status* s, const char* uri )
}
// Load the activity and sync status
act = ap_activity_from_FILE(f); f = NULL;
act = ap_object_from_FILE(f); f = NULL;
if( !act ) { goto failed; }
if( !status_sync_from_activity_pub(s,act) ) { goto failed; }

Loading…
Cancel
Save