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.

335 lines
8.8 KiB
C

#define _GNU_SOURCE
#include "activity.h"
// Submodules
#include "format.h"
#include "ffdb/fs_list.h"
#include "collections/array.h"
#include "ap/object.h"
// Model
#include "model/server.h"
#include "model/account.h"
#include "model/status.h"
#include "model/emoji.h"
#include "model/media.h"
#include "model/outbox_envelope.h"
// Standard Library
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
void activity_allocate_local_id( struct ap_object* obj )
{
int id = fs_list_get("data/activities/HEAD") + 1;
fs_list_set( "data/activities/HEAD", id );
obj->local_id = id;
}
void activity_save( struct ap_object* act )
{
char filename[512];
snprintf( filename, sizeof(filename), "data/activities/%d.json", act->local_id );
json_write_object_layout_to_file( filename, "\t", ap_object_layout, act );
}
struct ap_object* activity_from_local_id( int id )
{
struct ap_object* act = ap_activity_new();
char filename[512];
snprintf( filename, sizeof(filename), "data/activities/%d.json", id );
if( !json_read_object_layout_from_file( filename, ap_object_layout, act ) ) {
ap_object_free(act);
return NULL;
}
return act;
}
struct ap_object* activity_create_Accept( struct ap_object* act )
{
struct ap_object* accept = malloc(sizeof(struct ap_activity));
memset(accept,0,sizeof(*accept));
activity_allocate_local_id(accept);
asprintf( &accept->id,"https://%s/activity/%d", g_server->domain, accept->id );
accept->type = ap_Accept;
asprintf( &accept->actor, "https://%s/owner/actor", g_server->domain );
char* new_act_actor = strdup(act->actor);
array_append( &accept->to, sizeof(char*), &new_act_actor );
accept->object.tag = apaot_activity;
accept->object.ptr = ap_activity_dup(act);
return accept;
}
void activity_accept( struct ap_object* act, int deliver_to_account_id )
{
struct ap_object* accept = activity_create_Accept(act);
activity_save(accept);
struct outbox_envelope* env = outbox_envelope_new();
env->activity_id = accept->local_id;
env->account_id = deliver_to_account_id;
outbox_envelope_save( env );
outbox_envelope_free( env );
ap_object_free(accept);
}
struct ap_object* activity_create_EmojiReact( struct status* s, const char* react )
{
if( !*react ) {
return NULL;
}
struct account* a = account_from_id( s->account_id );
struct ap_object* act = ap_activity_new();
activity_allocate_local_id(act);
act->id = aformat( "https://%s/activity/%d", g_server->domain, act->local_id );
act->actor = aformat( "https://%s/owner/actor", g_server->domain );
act->type = pleroma_EmojiReact;
act->content.content = safe_strdup(react);
act->published = time(NULL);
act->object.tag = apaot_ref;
act->object.ref = strdup( s->url );
char* to = aformat( "%s/followers", a->account_url );
array_append( &act->to, sizeof(to), &to );
char* cc = strdup( "https://www.w3.org/ns/activitystreams#Public" );
array_append( &act->cc, sizeof(cc), &cc );
cc = strdup( a->account_url );
array_append( &act->cc, sizeof(cc), &cc );
account_free(a);
return act;
}
void activity_react( struct status* s, const char* react )
{
struct ap_object* act = activity_create_EmojiReact(s,react);
if( !act ) { return; }
activity_save(act);
struct outbox_envelope* env = outbox_envelope_new();
env->activity_id = act->local_id;
env->account_id = s->account_id;
outbox_envelope_save( env );
outbox_envelope_free( env );
ap_object_free(act);
}
struct ap_object* activity_create_Follow( struct account* follower, struct account* following )
{
struct ap_object* act = ap_activity_new();
activity_allocate_local_id(act);
act->id = aformat( "https://%s/activity/%d", g_server->domain, act->local_id );
act->actor = strdup( follower->account_url );
act->type = ap_Follow;
act->published = time(NULL);
act->object.tag = apaot_ref;
act->state = strdup("pending");
act->object.ref = strdup( following->account_url );
char* to = strdup(following->account_url);
array_append( &act->to, sizeof(to), &to );
return act;
}
int activity_follow( struct account* follower, struct account* following )
{
int res = -1;
struct ap_object* act = activity_create_Follow( follower, following );
if( !act ) { goto failed; }
activity_save(act);
res = act->local_id;
struct outbox_envelope* env = outbox_envelope_new();
if( !env ) { goto failed; }
env->activity_id = act->local_id;
env->account_id = following->id;
outbox_envelope_save( env );
outbox_envelope_free( env );
cleanup:
ap_object_free(act);
return res;
failed:
res = -1;
goto cleanup;
}
struct ap_object* activity_create_Undo( struct ap_activity* act_to_undo )
{
struct ap_object* act = ap_activity_new();
activity_allocate_local_id(act);
act->id = aformat( "https://%s/activity/%d", g_server->domain, act->local_id );
act->actor = strdup( act_to_undo->actor );
act->type = ap_Undo;
act->published = time(NULL);
act->object.tag = apaot_activity;
act->object.ptr = ap_activity_dup(act_to_undo);
char* to = strdup(act_to_undo->object.ref);
array_append( &act->to, sizeof(to), &to );
return act;
}
void activity_undo( struct ap_object* act, int deliver_to_account_id )
{
struct ap_object* undo_act = activity_create_Undo( act );
if( !undo_act ) { goto failed; }
activity_save(undo_act);
/*
printf( "act=" );
ap_activity_write_to_FILE( act, stdout );
printf( "\nundo_act=");
ap_activity_write_to_FILE( undo_act, stdout );
printf( "\n" );
*/
struct outbox_envelope* env = outbox_envelope_new();
if( !env ) { goto failed; }
env->activity_id = undo_act->local_id;
env->account_id = deliver_to_account_id;
outbox_envelope_save( env );
outbox_envelope_free( env );
cleanup:
ap_object_free(undo_act);
return;
failed:
goto cleanup;
}
struct ap_object* activity_create_Like( struct status* s )
{
return NULL;
}
int activity_like( struct status* s )
{
printf( "TODO: like\n" );
return -1;
}
struct ap_object* activity_create_Note( struct status* s )
{
struct ap_object* act = ap_activity_new();
act->id = aformat( "https://%s/note/%d", g_server->domain, s->id );
act->type = ap_Note;
act->published = s->published;
act->source.content = strdup(s->source);
act->content.content = strdup(status_render_source(s));
if( s->in_reply_to ) {
struct status* s_in_reply_to = status_from_id( s->in_reply_to );
act->in_reply_to = strdup( s_in_reply_to->url );
status_free(s_in_reply_to);
}
/* set account related parameters */ {
struct account* a = account_from_id( s->account_id );
act->actor = strdup( a->account_url );
act->attributed_to = strdup( a->account_url );
account_free(a);
}
char* str = strdup("https://www.w3.org/ns/activitystreams#Public");
array_append( &act->to, sizeof(str), &str );
for( int i = 0; i < s->media.count; ++i ) {
struct media* m = media_from_local_uri( s->media.items[i] );
if( m ) {
struct ap_attachment* att;
att = malloc(sizeof(*att));
memset(att,0,sizeof(*att));
att->type = ap_Document;
att->url = strdup(s->media.items[i]);
att->mediaType = strdup(m->content_type);
att->name = strdup("");
array_append( &act->attachments, sizeof(att), &att );
}
media_free(m);
}
for( int i = 0; i < s->emoji.count; ++i ) {
struct emoji* e = s->emoji.items[i];
struct ap_activity_tag* tag;
tag = malloc(sizeof(*tag));
memset(tag,0,sizeof(*tag));
tag->type = aptag_emoji;
tag->icon.url = strdup(e->url);
tag->id = strdup(e->url);
tag->icon.type = ap_Image;
tag->name = aformat(":%s:", e->shortcode );
array_append( &act->tags, sizeof(tag), &tag );
}
str = aformat( "https://%s/owner/followers", g_server->domain );
array_append( &act->cc, sizeof(str), &str );
for( int i = 0; i < s->mentions.count; ++i ) {
struct account* mentioned = account_from_id( s->mentions.items[i] );
str = strdup(mentioned->account_url);
array_append( &act->to, sizeof(str), &str );
struct ap_activity_tag* tag;
tag = malloc(sizeof(*tag));
memset(tag,0,sizeof(*tag));
tag->type = aptag_mention;
tag->href = strdup(mentioned->account_url);
tag->name = aformat( "%s@%s", mentioned->handle, mentioned->server );
array_append( &act->tags, sizeof(tag), &tag );
account_free(mentioned);
}
return act;
}
struct ap_object* activity_create_Create( struct ap_activity* object )
{
struct ap_object* act = ap_activity_new();
activity_allocate_local_id(act);
act->type = ap_Create;
act->id = aformat( "https://%s/activity/%d", g_server->domain, act->local_id );
act->object.tag = apaot_activity;
act->object.ptr = ap_activity_dup(object);
act->actor = strdup( object->actor );
act->published = object->published;
char* str;
for( int i = 0; i < object->to.count; ++i ) {
str = strdup( object->to.items[i] );
array_append( &act->to, sizeof(str), &str );
}
for( int i = 0; i < object->cc.count; ++i ) {
str = strdup( object->cc.items[i] );
array_append( &act->cc, sizeof(str), &str );
}
return act;
}
void activity_deliver( struct ap_object* obj )
{
// TODO: handle delivery
}