You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
234 lines
6.5 KiB
C
234 lines
6.5 KiB
C
#include "model/account.h"
|
|
|
|
// Submodules
|
|
#include "util/format.h"
|
|
#include "ffdb/trie.h"
|
|
#include "collections/array.h"
|
|
#include "ap/object.h"
|
|
|
|
// Model
|
|
#include "model/server.h"
|
|
#include "model/status.h"
|
|
#include "model/activity.h"
|
|
#include "model/outbox_envelope.h"
|
|
|
|
// Standard Library
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
|
|
void account_deliver_activity( struct account* a, struct ap_object* act, struct outbox_envelope_list* oel )
|
|
{
|
|
if( a->defunct ) {
|
|
printf( "Account %s id defunct, not delivering activity\n", a->account_url );
|
|
return;
|
|
}
|
|
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 && a->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;
|
|
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_object* act, struct outbox_envelope_list* oel )
|
|
{
|
|
printf( "Delivering activity %s to followers of account %s\n", act->id, a->account_url );
|
|
struct {
|
|
char** items;
|
|
int count;
|
|
} keys;
|
|
memset( &keys, 0, sizeof(keys) );
|
|
|
|
char filename[512];
|
|
snprintf( filename, sizeof(filename), "data/accounts/%d/followers", a->id );
|
|
|
|
// TODO: handle shared inbox delivery
|
|
int pages = (a->followers_count+31) / 32;
|
|
printf( "\tpages = %d, followers = %d\n", pages, a->followers_count );
|
|
for( int i = 0; i < pages; ++i ) {
|
|
keys.count = 0;
|
|
ffdb_trie_list( filename, i * 32, 32, &keys, NULL );
|
|
printf( "keys.count = %d\n", keys.count );
|
|
for( int j = 0; j < keys.count; ++j ) {
|
|
int account_id = atoi(keys.items[j]);
|
|
free(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, oel );
|
|
account_free(follower_account);
|
|
}
|
|
}
|
|
free(keys.items);
|
|
}
|
|
|
|
void account_create( struct account* a, struct status* s )
|
|
{
|
|
struct ap_object* note = activity_create_Note(s);
|
|
struct ap_object* create = activity_create_Create(note);
|
|
activity_save(create);
|
|
|
|
// Link status to activity
|
|
s->activity_id = create->local_id;
|
|
status_save(s);
|
|
|
|
// Add to owner timeline, public timeline and home timelines
|
|
status_add_to_timeline( s, a->id );
|
|
status_add_to_timeline( s, public_timeline_id );
|
|
status_add_to_timeline( s, home_timeline_id );
|
|
//status_add_post_to_timeline( s, federated_timeline_id );
|
|
|
|
//account_deliver_activity_to_followers( a, create, &oel );
|
|
activity_deliver( create );
|
|
|
|
ap_object_free(create);
|
|
ap_object_free(note);
|
|
}
|
|
|
|
struct status* account_announce( struct account* a, struct status* original_post, struct status* local_repost, struct ap_object* act )
|
|
{
|
|
if( !local_repost ) {
|
|
local_repost = status_new_repost( original_post, a );
|
|
|
|
// Flag the status as reposted
|
|
original_post->reposted_status_id = local_repost->id;
|
|
status_save(original_post);
|
|
|
|
// Add repost to timelines
|
|
status_add_to_timeline( local_repost, a->id );
|
|
if( a->id == owner_account_id ) {
|
|
status_add_to_timeline( local_repost, home_timeline_id );
|
|
}
|
|
status_add_to_timeline( local_repost, public_timeline_id );
|
|
}
|
|
|
|
if( !act ) {
|
|
act = ap_object_new();
|
|
activity_allocate_local_id(act);
|
|
act->id = aformat( "https://%s/activity/%d", g_server->domain, act->local_id );
|
|
act->published = time(NULL);
|
|
act->type = ap_Announce;
|
|
act->object.tag = apaot_ref;
|
|
act->object.ref = strdup(original_post->url);
|
|
act->actor = strdup(a->account_url);
|
|
|
|
// Create To: list
|
|
char* str = strdup("https://www.w3.org/ns/activitystreams#Public");
|
|
array_append( &act->to, sizeof(str), &str );
|
|
|
|
str = aformat("https://%s/owner/followers", g_server->domain );
|
|
array_append( &act->to, sizeof(str), &str );
|
|
|
|
struct account* origin_post_account = account_from_id(original_post->account_id);
|
|
str = strdup(origin_post_account->account_url);
|
|
array_append( &act->to, sizeof(str), &str );
|
|
account_free(origin_post_account);
|
|
}
|
|
|
|
activity_deliver( act );
|
|
|
|
// Link status to activity
|
|
local_repost->activity_id = act->local_id;
|
|
status_save(local_repost);
|
|
|
|
status_add_repost( original_post, local_repost );
|
|
status_save(original_post);
|
|
|
|
goto cleanup;
|
|
cleanup:
|
|
ap_object_free(act);
|
|
|
|
return local_repost;
|
|
}
|
|
|
|
void account_follow( struct account* a, struct account* to_follow )
|
|
{
|
|
char filename[512];
|
|
char key[32];
|
|
char value[32];
|
|
|
|
// Federate Follow Activity
|
|
int act_id = activity_follow( a, to_follow );
|
|
|
|
// Update following list
|
|
account_add_follower( to_follow, a );
|
|
|
|
// Record the activity so it an Undo can be issued in the future
|
|
mkdir( format(filename,sizeof(filename),"data/accounts/%d/follow-activities", a->id), 0755 );
|
|
ffdb_trie_set(filename, format(key,32,"%d", to_follow->id ), format(value,32,"%d", act_id ) );
|
|
|
|
// Save account data
|
|
account_save(a);
|
|
account_save(to_follow);
|
|
}
|
|
|
|
void account_unfollow( struct account* a, struct account* to_unfollow )
|
|
{
|
|
char index[512];
|
|
char key[32];
|
|
|
|
// Make sure the account to unfollow has previously been followed
|
|
char* res = ffdb_trie_get(
|
|
format(index,512,"data/accounts/%d/follow-activities", a->id),
|
|
format(key,32,"%d", to_unfollow->id)
|
|
);
|
|
if( !res ) {
|
|
printf( "Unable to find activity to undo follow\n" );
|
|
printf( "%s is trying to unfollow %s\n", a->account_url, to_unfollow->account_url );
|
|
return;
|
|
}
|
|
|
|
// Lookup the Activity used to federate following this account
|
|
struct ap_object* act = activity_from_local_id( atoi(res) );
|
|
free(res);
|
|
|
|
// Federate Undo Activity
|
|
activity_undo(act,to_unfollow->id);
|
|
ap_object_free(act);
|
|
|
|
// Update following list
|
|
account_remove_follower( to_unfollow, a );
|
|
|
|
// Save account data
|
|
account_save(a);
|
|
}
|
|
|
|
void account_update( struct account* a )
|
|
{
|
|
struct ap_object* act;
|
|
act = malloc(sizeof(*act));
|
|
memset(act,0,sizeof(*act));
|
|
|
|
activity_allocate_local_id(act);
|
|
act->id = aformat( "https://%s/activity/%d", g_server->domain, act->id );
|
|
act->type = ap_Update;
|
|
act->actor = strdup(a->account_url);
|
|
|
|
act->object.tag = apaot_activity;
|
|
act->object.ptr = account_activity_pub(a);
|
|
|
|
char* str = aformat("https://%s/owner/followers", g_server->domain );
|
|
array_append( &act->to, sizeof(str), &str );
|
|
|
|
activity_deliver( act );
|
|
|
|
activity_save(act);
|
|
ap_object_free(act);
|
|
}
|
|
|