rc_api_user.c (9655B)
1 #include "rc_api_user.h" 2 #include "rc_api_common.h" 3 4 #include "../rc_version.h" 5 6 #include <string.h> 7 8 /* --- Login --- */ 9 10 int rc_api_init_login_request(rc_api_request_t* request, const rc_api_login_request_t* api_params) { 11 rc_api_url_builder_t builder; 12 13 rc_api_url_build_dorequest_url(request); 14 15 if (!api_params->username || !*api_params->username) 16 return RC_INVALID_STATE; 17 18 rc_url_builder_init(&builder, &request->buffer, 48); 19 rc_url_builder_append_str_param(&builder, "r", "login2"); 20 rc_url_builder_append_str_param(&builder, "u", api_params->username); 21 22 if (api_params->password && api_params->password[0]) 23 rc_url_builder_append_str_param(&builder, "p", api_params->password); 24 else if (api_params->api_token && api_params->api_token[0]) 25 rc_url_builder_append_str_param(&builder, "t", api_params->api_token); 26 else 27 return RC_INVALID_STATE; 28 29 request->post_data = rc_url_builder_finalize(&builder); 30 request->content_type = RC_CONTENT_TYPE_URLENCODED; 31 32 return builder.result; 33 } 34 35 int rc_api_process_login_response(rc_api_login_response_t* response, const char* server_response) { 36 rc_api_server_response_t response_obj; 37 38 memset(&response_obj, 0, sizeof(response_obj)); 39 response_obj.body = server_response; 40 response_obj.body_length = rc_json_get_object_string_length(server_response); 41 42 return rc_api_process_login_server_response(response, &response_obj); 43 } 44 45 int rc_api_process_login_server_response(rc_api_login_response_t* response, const rc_api_server_response_t* server_response) { 46 int result; 47 rc_json_field_t fields[] = { 48 RC_JSON_NEW_FIELD("Success"), 49 RC_JSON_NEW_FIELD("Error"), 50 RC_JSON_NEW_FIELD("Code"), 51 RC_JSON_NEW_FIELD("User"), 52 RC_JSON_NEW_FIELD("Token"), 53 RC_JSON_NEW_FIELD("Score"), 54 RC_JSON_NEW_FIELD("SoftcoreScore"), 55 RC_JSON_NEW_FIELD("Messages"), 56 RC_JSON_NEW_FIELD("DisplayName") 57 }; 58 59 memset(response, 0, sizeof(*response)); 60 rc_buffer_init(&response->response.buffer); 61 62 result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0])); 63 if (result != RC_OK || !response->response.succeeded) 64 return result; 65 66 if (!rc_json_get_required_string(&response->username, &response->response, &fields[3], "User")) 67 return RC_MISSING_VALUE; 68 if (!rc_json_get_required_string(&response->api_token, &response->response, &fields[4], "Token")) 69 return RC_MISSING_VALUE; 70 71 rc_json_get_optional_unum(&response->score, &fields[5], "Score", 0); 72 rc_json_get_optional_unum(&response->score_softcore, &fields[6], "SoftcoreScore", 0); 73 rc_json_get_optional_unum(&response->num_unread_messages, &fields[7], "Messages", 0); 74 75 rc_json_get_optional_string(&response->display_name, &response->response, &fields[8], "DisplayName", response->username); 76 77 return RC_OK; 78 } 79 80 void rc_api_destroy_login_response(rc_api_login_response_t* response) { 81 rc_buffer_destroy(&response->response.buffer); 82 } 83 84 /* --- Start Session --- */ 85 86 int rc_api_init_start_session_request(rc_api_request_t* request, const rc_api_start_session_request_t* api_params) { 87 rc_api_url_builder_t builder; 88 89 rc_api_url_build_dorequest_url(request); 90 91 if (api_params->game_id == 0) 92 return RC_INVALID_STATE; 93 94 rc_url_builder_init(&builder, &request->buffer, 48); 95 if (rc_api_url_build_dorequest(&builder, "startsession", api_params->username, api_params->api_token)) { 96 rc_url_builder_append_unum_param(&builder, "g", api_params->game_id); 97 98 if (api_params->game_hash && *api_params->game_hash) { 99 rc_url_builder_append_unum_param(&builder, "h", api_params->hardcore); 100 rc_url_builder_append_str_param(&builder, "m", api_params->game_hash); 101 } 102 103 rc_url_builder_append_str_param(&builder, "l", RCHEEVOS_VERSION_STRING); 104 105 request->post_data = rc_url_builder_finalize(&builder); 106 request->content_type = RC_CONTENT_TYPE_URLENCODED; 107 } 108 109 return builder.result; 110 } 111 112 int rc_api_process_start_session_response(rc_api_start_session_response_t* response, const char* server_response) { 113 rc_api_server_response_t response_obj; 114 115 memset(&response_obj, 0, sizeof(response_obj)); 116 response_obj.body = server_response; 117 response_obj.body_length = rc_json_get_object_string_length(server_response); 118 119 return rc_api_process_start_session_server_response(response, &response_obj); 120 } 121 122 int rc_api_process_start_session_server_response(rc_api_start_session_response_t* response, const rc_api_server_response_t* server_response) { 123 rc_api_unlock_entry_t* unlock; 124 rc_json_field_t array_field; 125 rc_json_iterator_t iterator; 126 uint32_t timet; 127 int result; 128 129 rc_json_field_t fields[] = { 130 RC_JSON_NEW_FIELD("Success"), 131 RC_JSON_NEW_FIELD("Error"), 132 RC_JSON_NEW_FIELD("Unlocks"), 133 RC_JSON_NEW_FIELD("HardcoreUnlocks"), 134 RC_JSON_NEW_FIELD("ServerNow") 135 }; 136 137 rc_json_field_t unlock_entry_fields[] = { 138 RC_JSON_NEW_FIELD("ID"), 139 RC_JSON_NEW_FIELD("When") 140 }; 141 142 memset(response, 0, sizeof(*response)); 143 rc_buffer_init(&response->response.buffer); 144 145 result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0])); 146 if (result != RC_OK || !response->response.succeeded) 147 return result; 148 149 if (rc_json_get_optional_array(&response->num_unlocks, &array_field, &fields[2], "Unlocks") && response->num_unlocks) { 150 response->unlocks = (rc_api_unlock_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_unlocks * sizeof(rc_api_unlock_entry_t)); 151 if (!response->unlocks) 152 return RC_OUT_OF_MEMORY; 153 154 memset(&iterator, 0, sizeof(iterator)); 155 iterator.json = array_field.value_start; 156 iterator.end = array_field.value_end; 157 158 unlock = response->unlocks; 159 while (rc_json_get_array_entry_object(unlock_entry_fields, sizeof(unlock_entry_fields) / sizeof(unlock_entry_fields[0]), &iterator)) { 160 if (!rc_json_get_required_unum(&unlock->achievement_id, &response->response, &unlock_entry_fields[0], "ID")) 161 return RC_MISSING_VALUE; 162 if (!rc_json_get_required_unum(&timet, &response->response, &unlock_entry_fields[1], "When")) 163 return RC_MISSING_VALUE; 164 unlock->when = (time_t)timet; 165 166 ++unlock; 167 } 168 } 169 170 if (rc_json_get_optional_array(&response->num_hardcore_unlocks, &array_field, &fields[3], "HardcoreUnlocks") && response->num_hardcore_unlocks) { 171 response->hardcore_unlocks = (rc_api_unlock_entry_t*)rc_buffer_alloc(&response->response.buffer, response->num_hardcore_unlocks * sizeof(rc_api_unlock_entry_t)); 172 if (!response->hardcore_unlocks) 173 return RC_OUT_OF_MEMORY; 174 175 memset(&iterator, 0, sizeof(iterator)); 176 iterator.json = array_field.value_start; 177 iterator.end = array_field.value_end; 178 179 unlock = response->hardcore_unlocks; 180 while (rc_json_get_array_entry_object(unlock_entry_fields, sizeof(unlock_entry_fields) / sizeof(unlock_entry_fields[0]), &iterator)) { 181 if (!rc_json_get_required_unum(&unlock->achievement_id, &response->response, &unlock_entry_fields[0], "ID")) 182 return RC_MISSING_VALUE; 183 if (!rc_json_get_required_unum(&timet, &response->response, &unlock_entry_fields[1], "When")) 184 return RC_MISSING_VALUE; 185 unlock->when = (time_t)timet; 186 187 ++unlock; 188 } 189 } 190 191 rc_json_get_optional_unum(&timet, &fields[4], "ServerNow", 0); 192 response->server_now = (time_t)timet; 193 194 return RC_OK; 195 } 196 197 void rc_api_destroy_start_session_response(rc_api_start_session_response_t* response) { 198 rc_buffer_destroy(&response->response.buffer); 199 } 200 201 /* --- Fetch User Unlocks --- */ 202 203 int rc_api_init_fetch_user_unlocks_request(rc_api_request_t* request, const rc_api_fetch_user_unlocks_request_t* api_params) { 204 rc_api_url_builder_t builder; 205 206 rc_api_url_build_dorequest_url(request); 207 208 rc_url_builder_init(&builder, &request->buffer, 48); 209 if (rc_api_url_build_dorequest(&builder, "unlocks", api_params->username, api_params->api_token)) { 210 rc_url_builder_append_unum_param(&builder, "g", api_params->game_id); 211 rc_url_builder_append_unum_param(&builder, "h", api_params->hardcore ? 1 : 0); 212 request->post_data = rc_url_builder_finalize(&builder); 213 request->content_type = RC_CONTENT_TYPE_URLENCODED; 214 } 215 216 return builder.result; 217 } 218 219 int rc_api_process_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response, const char* server_response) { 220 rc_api_server_response_t response_obj; 221 222 memset(&response_obj, 0, sizeof(response_obj)); 223 response_obj.body = server_response; 224 response_obj.body_length = rc_json_get_object_string_length(server_response); 225 226 return rc_api_process_fetch_user_unlocks_server_response(response, &response_obj); 227 } 228 229 int rc_api_process_fetch_user_unlocks_server_response(rc_api_fetch_user_unlocks_response_t* response, const rc_api_server_response_t* server_response) { 230 int result; 231 rc_json_field_t fields[] = { 232 RC_JSON_NEW_FIELD("Success"), 233 RC_JSON_NEW_FIELD("Error"), 234 RC_JSON_NEW_FIELD("UserUnlocks") 235 /* unused fields 236 RC_JSON_NEW_FIELD("GameID"), 237 RC_JSON_NEW_FIELD("HardcoreMode") 238 * unused fields */ 239 }; 240 241 memset(response, 0, sizeof(*response)); 242 rc_buffer_init(&response->response.buffer); 243 244 result = rc_json_parse_server_response(&response->response, server_response, fields, sizeof(fields) / sizeof(fields[0])); 245 if (result != RC_OK || !response->response.succeeded) 246 return result; 247 248 result = rc_json_get_required_unum_array(&response->achievement_ids, &response->num_achievement_ids, &response->response, &fields[2], "UserUnlocks"); 249 return result; 250 } 251 252 void rc_api_destroy_fetch_user_unlocks_response(rc_api_fetch_user_unlocks_response_t* response) { 253 rc_buffer_destroy(&response->response.buffer); 254 }