#include "accounts.h" #include "http/server/request.h" #include "json/layout.h" #include "json/json.h" #include "http/query.h" #include "model/account.h" #include "view/api/Relationship.h" #include "view/api/Account.h" #include "controller/api/timeline.h" #include #include bool get_local_account_id( struct http_request* req, int* id ) { bool result = false; char* id_str = http_request_route_get_dir_or_file(req); if( !id_str || !*id_str ) { goto failed; } if( 1 != sscanf( id_str, "%d", id ) ) { struct account* a = account_from_webfinger(id_str); if( a ) { *id = a->id; account_free(a); goto success; } goto failed; } success: result = true; cleanup: free(id_str); return result; failed: result = false; goto cleanup; } bool handle_mastodon_api_show_account( struct http_request* req, struct account* a ) { http_request_send_headers( req, 200, "application/json", true ); FILE* f = http_request_get_response_body( req ); api_Account_write(a,f,0); return true; } static bool handle_search( struct http_request* req ) { struct params_t { const char* q; int limit; bool resolve; bool following; } params; memset(¶ms,0,sizeof(params)); static struct http_query_fields fields[] = { { "q", offsetof(struct params_t,q), qf_string }, { "limit", offsetof(struct params_t,limit), qf_integer }, { "resolve", offsetof(struct params_t,resolve), qf_bool }, { "following", offsetof(struct params_t,following), qf_bool }, { NULL }, }; http_query_parse( req, fields, ¶ms ); http_request_send_headers( req, 200, "application/json", true ); FILE* f = http_request_get_response_body( req ); struct account* a = account_from_webfinger( params.q ); if( !a && params.resolve ) { printf( "TODO: perform webfinger lookup\n" ); return false; } fprintf( f, "[" ); if( a ) { api_Account_write(a,f,1); } fprintf( f, "]" ); account_free(a); return true; } // Route: /api/v1/accounts/relationships? static bool handle_relationships( struct http_request* req ) { http_request_send_headers( req, 200, "application/json", true ); struct account* owner_account = account_from_id( owner_account_id ); FILE* f = http_request_get_response_body( req ); fprintf( f, "[" ); bool first = true; for(;;) { const char* key = http_request_route_query_key(req); if( !key ) { break; } if( 0 == strcmp(key,"id[]" ) ) { } else if( 0 == strcmp(key,"id%5B%5D") ) { } else { break; } int id = atoi( http_request_route_query_value(req) ); if( id > 0 ) { struct account* a = account_from_id(id); if( !a ) { continue; } fprintf( f, first ? "\n\t" : ",\n\t" ); first = false; api_Relationship_write( owner_account, a, f, 1 ); account_free(a); } } fprintf( f, "\n]" ); account_free(owner_account); return true; } // Route: /api/v1/accounts/ bool route_api_account( struct http_request* req ) { if( http_request_route_term( req, "verify_credentials" ) || http_request_route_term( req, "update_credentials" ) ) { struct account* owner = account_from_id(0); bool res = handle_mastodon_api_show_account( req, owner ); account_free(owner); return res; } else if( http_request_route( req, "relationships?" ) ) { return handle_relationships(req); } else if( http_request_route( req, "statuses" ) ) { return handle_timeline( req, tli_owner ); } else if( http_request_route( req, "search?" ) ) { return handle_search( req ); } else if( http_request_route_term(req,"") ) { struct account* owner = account_from_id(0); bool res = handle_mastodon_api_show_account( req, owner ); account_free(owner); return res; } int id = 0; if( !get_local_account_id( req, &id ) ) { return false; } struct account* a = account_from_id( id ); if( !a ) { return false; } // Route: /api/v1/accounts/%d{id} if( http_request_route( req, "statuses" ) ) { bool res = handle_timeline( req, id ); account_free(a); return res; } else if( http_request_route( req, "followers" ) ) { struct { int* items; int count; } accounts; account_list_followers( a, 0, 100, &accounts ); struct json_writer jw = { .f = http_request_get_response_body( req ), .indentation = "\t", .indent = 0, }; http_request_send_headers( req, 200, "application/json", true ); json_write_array( &jw, &api_Account_type, &accounts ); free(accounts.items); return true; } else if( http_request_route( req, "following" ) ) { struct { int* items; int count; } accounts; account_list_following( a, 0, 100, &accounts ); struct json_writer jw = { .f = http_request_get_response_body( req ), .indentation = "\t", .indent = 0, }; http_request_send_headers( req, 200, "application/json", true ); json_write_array( &jw, &api_Account_type, &accounts ); free(accounts.items); return true; } else if( http_request_route_term( req, "follow" ) ) { struct account* owner_account = account_from_id( owner_account_id ); account_follow( owner_account, a ); account_free(owner_account); bool res = handle_mastodon_api_show_account( req, a ); account_free(a); return res; } else if( http_request_route_term( req, "unfollow" ) ) { struct account* owner_account = account_from_id( owner_account_id ); account_unfollow( owner_account, a ); account_free(owner_account); bool res = handle_mastodon_api_show_account( req, a ); account_free(a); return res; } else if( http_request_route_term( req, "" ) ) { bool res = handle_mastodon_api_show_account( req, a ); account_free(a); return res; } return false; }