#include "mastodon_api.h" #include "http_server/http_request.h" #include #include #include #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, ¬e, 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; }