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.

281 lines
6.7 KiB
C

#include "mastodon_api.h"
#include "http_server/http_request.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "form.h"
#include "json/json.h"
#include "model/client_app.h"
#include "model/status.h"
#include "model/account.h"
#include "model/notification.h"
bool handle_mastodon_api_apps( struct http_request* req )
{
FILE* data = http_request_get_request_data( req );
struct form_parser* fp = form_pull_parser_new( data );
if( !fp ) { return false; }
char* client_name = NULL;
char* redirect_uris = NULL;
char* key;
while( key = form_pull_parser_read_key( fp ) ) {
if( 0 == strcmp( "client_name", key ) ) {
client_name = strdup( form_pull_parser_read_value(fp) );
} else if( 0 == strcmp( "redirect_uris", key ) ) {
redirect_uris = strdup( form_pull_parser_read_value(fp) );
} else {
printf( "key: %s\n", key );
printf( "value: %s\n", form_pull_parser_read_value(fp) );
}
}
form_pull_parser_release(fp);
struct client_app* app = client_app_new( client_name );
http_request_send_headers( req, 200, "application/json", true );
FILE* f = http_request_get_response_body( req );
#define RENDER
#include "controller/mastodon_api/apps.json.inc"
#undef RENDER
free(client_name);
free(redirect_uris);
return true;
}
bool check_bearer_token( struct http_request* req )
{
// Check bearer token
const char* auth_token = http_request_get_header( req, "Authorization" );
if( !auth_token ) { return false; }
if( 0 != strncmp( auth_token, "Bearer ", 7 ) ) { return false; }
char* client_id = strndup( &auth_token[7], 32 );
struct client_app* app = client_app_from_id( client_id );
free(client_id);
if( !app ) { return false; }
if( 0 != strcmp( &auth_token[7], app->access_token ) ) { return false; }
client_app_free(app);
return true;
}
void show_status( struct http_request* req, struct status* s )
{
http_request_send_headers( req, 200, "application/json", true );
FILE* f = http_request_get_response_body( req );
status_write_as_json(s,f);
}
void show_status_context( struct http_request* req, struct status* s )
{
http_request_send_headers( req, 200, "application/json", true );
FILE* f = http_request_get_response_body( req );
fprintf( f, "{\"ancestors\":[],\"descendants\":[]}" );
}
void show_statuses( struct http_request* req, struct status* ss, int count )
{
http_request_send_headers( req, 200, "application/json", true );
FILE* f = http_request_get_response_body( req );
fprintf( f, "[" );
for( int i = 0; i < count; ++i ) {
if( i > 0 ) {
fprintf( f, "," );
}
status_write_as_json(&ss[i],f);
}
fprintf( f, "]" );
}
void show_notifications( struct http_request* req, struct notification* ns, int count )
{
http_request_send_headers( req, 200, "application/json", true );
FILE* f = http_request_get_response_body( req );
fprintf( f, "[" );
for( int i = 0; i < count; ++i ) {
if( i > 0 ) {
fprintf( f, "," );
}
notification_write_as_json(&ns[i],f);
}
fprintf( f, "]" );
}
bool handle_timeline( struct http_request* req, const char* which )
{
// "GET /api/v1/timelines/home?with_muted=true&limit=31"
bool with_muted = false;
unsigned int limit = 100;
struct status s = {
.id = 1,
.account_id = 1,
};
show_statuses( req, &s, 1 );
return true;
}
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 );
account_write_as_json(a,f);
return true;
}
bool handle_post( struct http_request* req, struct account* a )
{
printf( "TODO: new post" );
FILE* data = http_request_get_request_data( req );
struct json_pull_parser* jpp = json_pull_parser_new( data );
if( !jpp ) { return false; }
int save;
if( !json_pull_parser_begin_object( jpp, &save ) ) { return false; }
struct status s;
bool sensitive = false;
char* key;
while( key = json_pull_parser_read_object_key(jpp) ) {
if( 0 == strcmp(key,"media_ids") ) {
json_pull_parser_read_value(jpp);
} else if( 0 == strcmp(key,"sensitive") ) {
json_pull_parser_read_bool(jpp,&sensitive);
} else if( 0 == strcmp(key,"status") ) {
json_pull_parser_read_string(jpp);
} else if( 0 == strcmp(key,"visibility") ) {
json_pull_parser_read_string(jpp);
} else if( 0 == strcmp(key,"spoiler_text") ) {
json_pull_parser_read_string(jpp);
}
}
free(key);
if( !json_pull_parser_end_object(jpp, &save ) ) {
return false;
}
// {"media_ids":[],"sensitive":false,"status":"Test","visibility":"public","spoiler_text":""}
char ch;
while( (ch = fgetc(data)) != EOF ) {
printf( "%c", ch );
}
return false;
}
bool route_mastodon_api( struct http_request* req )
{
if( http_request_route( req, "apps" ) ) {
if( http_request_route_method( req, "POST" ) ) {
return handle_mastodon_api_apps(req);
}
}
if( http_request_route( req, "timelines/public" ) ) {
show_statuses( req, NULL, 0 );
return true;
}
/*
if( !check_bearer_token(req) ) { return false; }
printf( "authorization still valid\n" );
//*/
struct account* owner = account_from_id(0);
if( http_request_route( req, "notifications" ) ) {
struct notification note = {
.account_id = 1,
.status_id = 1,
};
show_notifications( req, &note, 1 );
return true;
}
if( http_request_route( req, "statuses" ) ) {
if( http_request_route( req, "/" ) ) {
char* id_str = http_request_route_get_dir_or_file(req);
if( !id_str || !*id_str ) { return false; }
int id = -1;
sscanf( id_str, "%d", &id );
free(id_str);
if( id == -1 ) { return false; }
struct status* s = status_from_id(id);
if( http_request_route( req, "context" ) ) {
show_status_context( req, s );
} else {
show_status( req, s );
}
return true;
} else if( http_request_route_method( req, "POST" ) ) {
return handle_post(req, owner);
}
}
if( http_request_route( req, "timelines/home" ) ) {
return handle_timeline( req, "home" );
} else if( http_request_route( req, "accounts/" ) ) {
if( http_request_route( req, "verify_credentials" ) ) {
return true;
} else if( http_request_route( req, "statuses" ) ) {
show_statuses( req, NULL, 0 );
return true;
}
char* id_str = http_request_route_get_dir_or_file(req);
int id = -1;
printf( "id_str = %s\n", id_str );
if( !id_str ) { return false; }
if( !*id_str ) {
id = 0;
return handle_mastodon_api_show_account( req, owner );
} else {
sscanf( id_str, "%d", &id );
free( id_str );
if( id == -1 ) {
printf( "Invalid id\n" );
return false;
}
}
struct account* a = account_from_id( id );
if( !a ) { return false; }
if( http_request_route( req, "statuses" ) ) {
printf( "TODO: statuses\n" );
show_statuses( req, NULL, 0 );
return true;
} else {
return handle_mastodon_api_show_account( req, a );
}
}
return false;
}