Split apart application-specific AcitivytPub code and generic ap_object code, rename ap_object type enumeration values, start work to ingest external Activities
parent
c5445ca9a5
commit
f2a61e0b71
@ -0,0 +1,58 @@
|
||||
#include "follow.h"
|
||||
|
||||
#include "model/ap/object.h"
|
||||
|
||||
#include "model/activity.h"
|
||||
#include "model/account.h"
|
||||
#include "model/server.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
bool route_follow( struct ap_object* act )
|
||||
{
|
||||
struct account* follower = NULL;
|
||||
bool res = false;
|
||||
struct ap_object* accept = NULL;
|
||||
|
||||
const char* target = act->object.ref;
|
||||
struct account* a = account_from_uri( target );
|
||||
|
||||
// Don't process follows for remote users
|
||||
if( !a || 0 != strcmp( a->server, g_server->domain ) ) {
|
||||
printf( "Unfollow not targeted at local account. Discarding.\n" );
|
||||
goto success;
|
||||
}
|
||||
|
||||
// Get account for the follower
|
||||
follower = account_from_uri( act->actor );
|
||||
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;
|
||||
}
|
||||
|
||||
// Add the follower
|
||||
account_add_follower( a, follower );
|
||||
|
||||
// Create Accept activity
|
||||
activity_accept( act, follower->id );
|
||||
|
||||
success:
|
||||
res = true;
|
||||
goto cleanup;
|
||||
cleanup:
|
||||
account_free(a);
|
||||
account_free(follower);
|
||||
|
||||
return res;
|
||||
failed:
|
||||
res = false;
|
||||
goto cleanup;
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct ap_object;
|
||||
|
||||
bool route_follow( struct ap_object* act );
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit f887e970303d2602ef9cdf9a51756fc46631964d
|
||||
Subproject commit 7eb2ff95d464fba91d7ba4e496aa37a80cbec1de
|
@ -0,0 +1,332 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "activity.h"
|
||||
|
||||
#include "format.h"
|
||||
#include "ffdb/fs_list.h"
|
||||
#include "collections/array.h"
|
||||
// TODO: change to submodule
|
||||
#include "model/ap/object.h"
|
||||
|
||||
#include "model/server.h"
|
||||
#include "model/account.h"
|
||||
#include "model/status.h"
|
||||
#include "model/emoji.h"
|
||||
#include "model/media.h"
|
||||
#include "model/ap/outbox_envelope.h"
|
||||
|
||||
#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
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
struct ap_object;
|
||||
struct status;
|
||||
struct account;
|
||||
|
||||
// Database management
|
||||
struct ap_object* activity_from_local_id( int id );
|
||||
void activity_save( struct ap_object* o );
|
||||
void activity_allocate_local_id( struct ap_object* obj );
|
||||
|
||||
// creation
|
||||
struct ap_object* activity_create_Accept( struct ap_object* act );
|
||||
struct ap_object* activity_create_EmojiReact( struct status* s, const char* react );
|
||||
struct ap_object* activity_create_Undo( struct ap_object* act );
|
||||
struct ap_object* activity_create_Like( struct status* s );
|
||||
struct ap_object* activity_create_Note( struct status* s );
|
||||
struct ap_object* activity_create_Create( struct ap_object* act );
|
||||
struct ap_object* activity_create_Accept( struct ap_object* act );
|
||||
|
||||
// Actions
|
||||
void activity_react( struct status* s, const char* react );
|
||||
int activity_follow( struct account* follower, struct account* following );
|
||||
void activity_unfollow( struct account* follower, struct account* to_unfollow );
|
||||
void activity_undo( struct ap_object* act, int deliver_to_account_id );
|
||||
int activity_like( struct status* s );
|
||||
void activity_accept( struct ap_object* act, int deliver_to_account_id );
|
||||
|
||||
void activity_deliver( struct ap_object* obj );
|
||||
|
@ -0,0 +1,256 @@
|
||||
#pragma once
|
||||
|
||||
#include "json/layout.h"
|
||||
|
||||
#include "activity/context.h"
|
||||
#include "activity/tag.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
// Reference: https://www.w3.org/TR/activitystreams-vocabulary/
|
||||
// TODO: rename this to ap_object, as this is really an Object base and not an Activity base
|
||||
struct ap_object;
|
||||
#define ap_activity ap_object
|
||||
|
||||
struct ap_activity_source
|
||||
{
|
||||
char* mime_type;
|
||||
char* content;
|
||||
|
||||
// TODO: add map;
|
||||
};
|
||||
|
||||
enum ap_signature_type
|
||||
{
|
||||
apst_rsa_signature_2017 = 1,
|
||||
};
|
||||
|
||||
struct ap_signature
|
||||
{
|
||||
int type;
|
||||
char* creator;
|
||||
time_t created;
|
||||
char* value;
|
||||
};
|
||||
|
||||
enum ap_object_type
|
||||
{
|
||||
// Activity Types
|
||||
ap_Undo = 1,
|
||||
ap_Follow = 2,
|
||||
ap_Delete = 3,
|
||||
ap_Accept = 4,
|
||||
ap_Create = 5,
|
||||
ap_TentativeAccept = 6,
|
||||
ap_Add = 7,
|
||||
ap_Arrive = 8,
|
||||
ap_Ignore = 9,
|
||||
ap_Join = 10,
|
||||
ap_Leave = 11,
|
||||
ap_Like = 12,
|
||||
ap_Offer = 13,
|
||||
ap_Invite = 14,
|
||||
ap_Reject = 15,
|
||||
ap_TentativeReject = 16,
|
||||
ap_Remove = 17,
|
||||
ap_Update = 18,
|
||||
ap_View = 19,
|
||||
ap_Listen = 20,
|
||||
ap_Read = 21,
|
||||
ap_Move = 22,
|
||||
ap_Travel = 23,
|
||||
ap_Announce = 24,
|
||||
ap_Block = 25,
|
||||
ap_Flag = 26,
|
||||
ap_Dislike = 27,
|
||||
|
||||
// Object Types
|
||||
ap_Note = 100,
|
||||
ap_Question = 101,
|
||||
ap_Article = 102,
|
||||
ap_Audio = 103,
|
||||
ap_Document = 104,
|
||||
ap_Event = 105,
|
||||
ap_Image = 106,
|
||||
ap_Page = 107,
|
||||
ap_Place = 108,
|
||||
ap_Profile = 109,
|
||||
ap_Relationship = 110,
|
||||
ap_Tombstone = 111,
|
||||
ap_Video = 112,
|
||||
|
||||
// Actor Types
|
||||
ap_Person = 200,
|
||||
ap_Service = 201,
|
||||
ap_Application = 202,
|
||||
ap_Group = 203,
|
||||
ap_Organization = 204,
|
||||
|
||||
// Collection Types
|
||||
ap_OrderedCollection = 301,
|
||||
ap_OrderedCollectionPage = 302,
|
||||
ap_Collection = 303,
|
||||
ap_CollectionPage = 304,
|
||||
|
||||
/// Pleroma Types
|
||||
pleroma_EmojiReact = 28,
|
||||
|
||||
/// Musicbox Types
|
||||
mb_Track = 501,
|
||||
mb_Album = 502,
|
||||
|
||||
/// Forge Types (https://forgefed.org/vocabulary.html)
|
||||
forge_Grant = 601,
|
||||
forge_Push = 602,
|
||||
forge_Repository = 603,
|
||||
forge_TicketTracker = 604,
|
||||
forge_PatchTracker = 605,
|
||||
forge_Project = 606,
|
||||
forge_Team = 607,
|
||||
forge_Branch = 608,
|
||||
forge_Commit = 609,
|
||||
forge_TicketDependency = 610,
|
||||
forge_Ticket = 611,
|
||||
|
||||
/// Schema.org types
|
||||
schema_PropertyValue = 401, // https://schema.org/PropertyValue
|
||||
};
|
||||
extern struct json_enum ap_object_type_enum[];
|
||||
|
||||
enum ap_activity_object_type {
|
||||
apaot_ref = 1,
|
||||
apaot_activity = 2,
|
||||
apaot_object = 2,
|
||||
};
|
||||
|
||||
struct ap_attachment
|
||||
{
|
||||
int type;
|
||||
char* mediaType;
|
||||
char* name;
|
||||
char* url;
|
||||
char* value;
|
||||
};
|
||||
void ap_attachment_free( struct ap_attachment* a );
|
||||
extern struct json_field_type ap_attachment_type;
|
||||
|
||||
struct ap_object_ptr_or_ref
|
||||
{
|
||||
int tag;
|
||||
union {
|
||||
char* ref;
|
||||
struct ap_object* ptr;
|
||||
};
|
||||
};
|
||||
struct ap_public_key
|
||||
{
|
||||
char* id;
|
||||
char* owner;
|
||||
char* public_key;
|
||||
};
|
||||
void ap_object_ptr_or_ref_free( struct ap_object_ptr_or_ref* oor );
|
||||
void ap_object_ptr_or_ref_free_composite( struct ap_object_ptr_or_ref* oor );
|
||||
|
||||
struct ap_object
|
||||
{
|
||||
struct ap_activity_context ap_context;
|
||||
|
||||
char* id;
|
||||
char* actor;
|
||||
char* name;
|
||||
int local_id;
|
||||
int type;
|
||||
|
||||
// Actor-specific fields
|
||||
char* inbox;
|
||||
char* outbox;
|
||||
char* preferred_username;
|
||||
char* url;
|
||||
struct {
|
||||
char* shared_inbox;
|
||||
} endpoints;
|
||||
char* featured;
|
||||
char* followers;
|
||||
char* following;
|
||||
struct {
|
||||
bool show;
|
||||
bool accepts_chat_messages;
|
||||
} capabilities;
|
||||
char* avatar;
|
||||
char* banner;
|
||||
bool discoverable;
|
||||
bool manually_approves_followers;
|
||||
struct ap_public_key* public_key;
|
||||
|
||||
char* context;
|
||||
int context_id;
|
||||
|
||||
bool direct_message;
|
||||
|
||||
char* attributed_to;
|
||||
char* target;
|
||||
char* in_reply_to;
|
||||
|
||||
struct ap_activity_source content;
|
||||
|
||||
char* conversation;
|
||||
time_t published;
|
||||
struct ap_activity_source source;
|
||||
|
||||
char* summary;
|
||||
|
||||
bool sensitive;
|
||||
|
||||
struct {
|
||||
struct ap_activity_tag** items;
|
||||
int count;
|
||||
} tags;
|
||||
|
||||
struct {
|
||||
struct ap_attachment** items;
|
||||
int count;
|
||||
} attachments;
|
||||
|
||||
struct {
|
||||
char** items;
|
||||
int count;
|
||||
} also_known_as;
|
||||
|
||||
struct {
|
||||
struct ap_object_ptr_or_ref* items;
|
||||
int count;
|
||||
} collection_items;
|
||||
|
||||
struct {
|
||||
char** items;
|
||||
int count;
|
||||
} to, cc, bcc;
|
||||
|
||||
struct ap_object_ptr_or_ref object;
|
||||
|
||||
char* state;
|
||||
|
||||
int has_signature;
|
||||
struct ap_signature signature;
|
||||
|
||||
// Collection fields
|
||||
struct ap_object_ptr_or_ref first;
|
||||
char* next;
|
||||
char* prev;
|
||||
char* part_of;
|
||||
int total_items;
|
||||
};
|
||||
|
||||
struct json_object_field;
|
||||
extern struct json_field_type ap_object_type;
|
||||
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_object_from_FILE( FILE* f );
|
||||
struct ap_object* ap_object_from_file( const char* filename );
|
||||
void ap_object_free( struct ap_object* o );
|
||||
void ap_activity_free_composite( struct ap_object* o );
|
||||
|
||||
void ap_object_write_to_FILE( struct ap_object* o, FILE* f );
|
||||
|
Loading…
Reference in new issue