full friends list support, add remove, and accept
This commit is contained in:
		
							parent
							
								
									efce6a6543
								
							
						
					
					
						commit
						7f5ceff688
					
				| @ -17,6 +17,8 @@ SET(SOURCES | ||||
|   "include/dc/util.h" | ||||
|   "src/account.c" | ||||
|   "src/api.c" | ||||
|   "src/api-friends.c" | ||||
|   "src/api-util.c" | ||||
|   "src/apisync.c" | ||||
|   "src/guild.c" | ||||
|   "src/loop.c" | ||||
|  | ||||
| @ -13,14 +13,35 @@ typedef enum { | ||||
|     /* accountt is a mutual friend
 | ||||
|      */ | ||||
|     FRIEND_STATE_FRIEND = 1, | ||||
|     /* pending account, the other side hasn't accepted yet
 | ||||
|     /* pending friend request, the other side hasn't accepted yet
 | ||||
|      */ | ||||
|     FRIEND_STATE_PENDING = 4, | ||||
|     FRIEND_STATE_PENDING = 3, | ||||
| } dc_account_friend_states; | ||||
| 
 | ||||
| /**
 | ||||
|  * Represents a given account within the discord system. To start your work, | ||||
|  * you will have to create an account object, give it email and password, and | ||||
|  * call the dc_api_authenticate() with it. This gives you a login token that | ||||
|  * you can use to call other API methods (such as dc_api_get_friends()) for | ||||
|  * that account. | ||||
|  * | ||||
|  * Accounts have a few important attributes that we store: | ||||
|  *   * ID (or snowflake), a 64 bit ID of the user, that we store as a string. | ||||
|  *   * username, a string that represents the accounts user name | ||||
|  *   * discriminator, a number that differentiates users with the same name | ||||
|  *   * email, for login accounts only | ||||
|  *   * password, for login accounts only | ||||
|  *   * friend_state, if the account is someone login account's friend, we store | ||||
|  *     the relationship in this flag. See the dc_account_friend_state enum for | ||||
|  *     details. | ||||
|  * And one compound attribute: | ||||
|  *   * fullname, a combination of username and discriminator separated by the | ||||
|  *     pound sign, e.g. nola#2457 | ||||
|  */ | ||||
| 
 | ||||
| dc_account_t dc_account_new(void); | ||||
| dc_account_t dc_account_new2(char const *email, char const *pass); | ||||
| dc_account_t dc_account_from_fullid(char const *fullid); | ||||
| dc_account_t dc_account_from_fullname(char const *fullid); | ||||
| 
 | ||||
| void dc_account_set_email(dc_account_t a, char const *email); | ||||
| char const *dc_account_email(dc_account_t a); | ||||
| @ -37,7 +58,7 @@ char const *dc_account_username(dc_account_t a); | ||||
| void dc_account_set_discriminator(dc_account_t a, char const *id); | ||||
| char const *dc_account_discriminator(dc_account_t a); | ||||
| 
 | ||||
| char const *dc_account_full_username(dc_account_t a); | ||||
| char const *dc_account_fullname(dc_account_t a); | ||||
| 
 | ||||
| void dc_account_set_token(dc_account_t a, char const *token); | ||||
| char const *dc_account_token(dc_account_t a); | ||||
| @ -48,6 +69,7 @@ bool dc_account_has_token(dc_account_t a); | ||||
| void dc_account_set_friends(dc_account_t a, dc_account_t *ptr, size_t len); | ||||
| dc_account_t dc_account_nthfriend(dc_account_t a, size_t i); | ||||
| size_t dc_account_friends_size(dc_account_t a); | ||||
| 
 | ||||
| int dc_account_friend_state(dc_account_t a); | ||||
| void dc_account_set_friend_state(dc_account_t a, int state); | ||||
| 
 | ||||
|  | ||||
| @ -70,4 +70,21 @@ bool dc_api_get_friends(dc_api_t api, dc_account_t login); | ||||
|  */ | ||||
| bool dc_api_add_friend(dc_api_t api, dc_account_t login, dc_account_t friend); | ||||
| 
 | ||||
| /**
 | ||||
|  * Remove a given account as a friend to the friends list. Warning: The | ||||
|  * account ID (aka account snowflake) is required to perform this operation, | ||||
|  * so you cannot just do dc_account_from_fullname(). Suggestion: use an object | ||||
|  * from the actual friends list of the account login. | ||||
|  */ | ||||
| bool dc_api_remove_friend(dc_api_t api, dc_account_t login, | ||||
|                           dc_account_t friend); | ||||
| 
 | ||||
| /**
 | ||||
|  * Accepts someone who has sent a friend request to you, as a friend. Warning: | ||||
|  * The object "friend" requires an account ID (aka snowflake) for this method | ||||
|  * to work. You should take this object perhaps from the "login"'s friend list. | ||||
|  */ | ||||
| bool dc_api_accept_friend(dc_api_t api, dc_account_t login, | ||||
|                           dc_account_t friend); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -84,7 +84,7 @@ dc_account_t dc_account_new2(char const *email, char const *pass) | ||||
|     return ptr; | ||||
| } | ||||
| 
 | ||||
| dc_account_t dc_account_from_fullid(char const *fullid) | ||||
| dc_account_t dc_account_from_fullname(char const *fullid) | ||||
| { | ||||
|     return_if_true(fullid == NULL, NULL); | ||||
| 
 | ||||
| @ -226,7 +226,7 @@ char const *dc_account_discriminator(dc_account_t a) | ||||
|     return a->discriminator; | ||||
| } | ||||
| 
 | ||||
| char const *dc_account_full_username(dc_account_t a) | ||||
| char const *dc_account_fullname(dc_account_t a) | ||||
| { | ||||
|     return_if_true(a == NULL, NULL); | ||||
|     return a->full; | ||||
|  | ||||
							
								
								
									
										150
									
								
								libdc/src/api-friends.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								libdc/src/api-friends.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,150 @@ | ||||
| #include <dc/api.h> | ||||
| 
 | ||||
| #include "internal.h" | ||||
| 
 | ||||
| bool dc_api_get_friends(dc_api_t api, dc_account_t login) | ||||
| { | ||||
|     char const *url = "users/@me/relationships"; | ||||
|     json_t *reply = NULL, *c = NULL, *val = NULL; | ||||
|     bool ret = false; | ||||
|     size_t i = 0; | ||||
|     GPtrArray *f = g_ptr_array_new_with_free_func((GDestroyNotify)dc_unref); | ||||
| 
 | ||||
|     return_if_true(api == NULL, false); | ||||
|     return_if_true(login == NULL, false); | ||||
| 
 | ||||
|     reply = dc_api_call_sync(api, "GET", dc_account_token(login), url, NULL); | ||||
|     goto_if_true(reply == NULL, cleanup); | ||||
| 
 | ||||
|     goto_if_true(!json_is_array(reply), cleanup); | ||||
| 
 | ||||
|     json_array_foreach(reply, i, c) { | ||||
|         /* the return is an array of objects, with a "user" member
 | ||||
|          * type 1 is probably a friend | ||||
|          */ | ||||
|         val = json_object_get(c, "user"); | ||||
|         if (val == NULL) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         dc_account_t a = dc_api_account_from_json(val); | ||||
|         if (a == NULL) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         /* read the type also known as "typ"
 | ||||
|          */ | ||||
|         val = json_object_get(c, "type"); | ||||
|         if (val != NULL && json_is_integer(val)) { | ||||
|             int state = json_integer_value(val); | ||||
|             dc_account_set_friend_state(a, state); | ||||
|         } | ||||
| 
 | ||||
|         g_ptr_array_add(f, a); | ||||
|     } | ||||
| 
 | ||||
|     if (f->len == 0) { | ||||
|         /* me_irl :-(
 | ||||
|          */ | ||||
|     } | ||||
| 
 | ||||
|     dc_account_set_friends(login, (dc_account_t*)f->pdata, f->len); | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     g_ptr_array_free(f, FALSE); | ||||
|     json_decref(reply); | ||||
|     reply = NULL; | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool dc_api_remove_friend(dc_api_t api, dc_account_t login, dc_account_t friend) | ||||
| { | ||||
|     char *url = NULL; | ||||
|     json_t *reply = NULL, *post = NULL; | ||||
|     bool ret = false; | ||||
| 
 | ||||
|     return_if_true(api == NULL, false); | ||||
|     return_if_true(login == NULL || friend == NULL, false); | ||||
|     return_if_true(dc_account_id(friend) == NULL, false); | ||||
| 
 | ||||
|     asprintf(&url, "users/@me/relationships/%s", dc_account_id(friend)); | ||||
| 
 | ||||
|     post = dc_api_account_to_json(friend); | ||||
|     return_if_true(post == NULL, false); | ||||
| 
 | ||||
|     reply = dc_api_call_sync(api, "DELETE", dc_account_token(login), url, post); | ||||
|     /* if no data comes back, then the whole thing was a success
 | ||||
|      */ | ||||
|     goto_if_true(reply != NULL, cleanup); | ||||
| 
 | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     free(url); | ||||
|     json_decref(post); | ||||
|     json_decref(reply); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool dc_api_accept_friend(dc_api_t api, dc_account_t login, dc_account_t friend) | ||||
| { | ||||
|     char *url = NULL; | ||||
|     json_t *reply = NULL, *post = NULL; | ||||
|     bool ret = false; | ||||
| 
 | ||||
|     return_if_true(api == NULL, false); | ||||
|     return_if_true(login == NULL || friend == NULL, false); | ||||
|     return_if_true(dc_account_id(friend) == NULL, false); | ||||
| 
 | ||||
|     asprintf(&url, "users/@me/relationships/%s", dc_account_id(friend)); | ||||
| 
 | ||||
|     post = dc_api_account_to_json(friend); | ||||
|     return_if_true(post == NULL, false); | ||||
| 
 | ||||
|     reply = dc_api_call_sync(api, "PUT", dc_account_token(login), url, post); | ||||
|     /* no data = successful
 | ||||
|      */ | ||||
|     goto_if_true(reply != NULL, cleanup); | ||||
| 
 | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     free(url); | ||||
|     json_decref(post); | ||||
|     json_decref(reply); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool dc_api_add_friend(dc_api_t api, dc_account_t login, dc_account_t friend) | ||||
| { | ||||
|     char const *url = "users/@me/relationships"; | ||||
|     json_t *reply = NULL, *post = NULL; | ||||
|     bool ret = false; | ||||
| 
 | ||||
|     return_if_true(api == NULL, false); | ||||
|     return_if_true(login == NULL, false); | ||||
| 
 | ||||
|     post = dc_api_account_to_json(friend); | ||||
|     return_if_true(post == NULL, false); | ||||
| 
 | ||||
|     reply = dc_api_call_sync(api, "POST", dc_account_token(login), url, post); | ||||
|     /* apparently if no data comes back, then the whole thing was a success
 | ||||
|      */ | ||||
|     goto_if_true(reply != NULL, cleanup); | ||||
| 
 | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     json_decref(post); | ||||
|     json_decref(reply); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
							
								
								
									
										53
									
								
								libdc/src/api-util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								libdc/src/api-util.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,53 @@ | ||||
| #include <dc/api.h> | ||||
| 
 | ||||
| #include "internal.h" | ||||
| 
 | ||||
| dc_account_t dc_api_account_from_json(json_t *j) | ||||
| { | ||||
|     dc_account_t user = dc_account_new(); | ||||
|     json_t *val = NULL; | ||||
| 
 | ||||
|     goto_if_true(!json_is_object(j), error); | ||||
| 
 | ||||
|     val = json_object_get(j, "username"); | ||||
|     goto_if_true(val == NULL || !json_is_string(val), error); | ||||
|     dc_account_set_username(user, json_string_value(val)); | ||||
| 
 | ||||
|     val = json_object_get(j, "discriminator"); | ||||
|     goto_if_true(val == NULL || !json_is_string(val), error); | ||||
|     dc_account_set_discriminator(user, json_string_value(val)); | ||||
| 
 | ||||
|     val = json_object_get(j, "id"); | ||||
|     goto_if_true(val == NULL || !json_is_string(val), error); | ||||
|     dc_account_set_id(user, json_string_value(val)); | ||||
| 
 | ||||
|     return user; | ||||
| 
 | ||||
| error: | ||||
| 
 | ||||
|     dc_unref(user); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| json_t *dc_api_account_to_json(dc_account_t a) | ||||
| { | ||||
|     json_t *j = NULL; | ||||
| 
 | ||||
|     return_if_true(a == NULL, NULL); | ||||
|     return_if_true(dc_account_username(a) == NULL || | ||||
|                    dc_account_discriminator(a) == NULL, | ||||
|                    NULL | ||||
|         ); | ||||
| 
 | ||||
|     j = json_object(); | ||||
|     return_if_true(j == NULL, NULL); | ||||
| 
 | ||||
|     json_object_set_new(j, "username", | ||||
|                         json_string(dc_account_username(a)) | ||||
|         ); | ||||
|     json_object_set_new(j, "discriminator", | ||||
|                         json_string(dc_account_discriminator(a)) | ||||
|         ); | ||||
| 
 | ||||
|     return j; | ||||
| } | ||||
							
								
								
									
										138
									
								
								libdc/src/api.c
									
									
									
									
									
								
							
							
						
						
									
										138
									
								
								libdc/src/api.c
									
									
									
									
									
								
							| @ -322,56 +322,6 @@ cleanup: | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static dc_account_t dc_api_account_from_json(json_t *j) | ||||
| { | ||||
|     dc_account_t user = dc_account_new(); | ||||
|     json_t *val = NULL; | ||||
| 
 | ||||
|     goto_if_true(!json_is_object(j), error); | ||||
| 
 | ||||
|     val = json_object_get(j, "username"); | ||||
|     goto_if_true(val == NULL || !json_is_string(val), error); | ||||
|     dc_account_set_username(user, json_string_value(val)); | ||||
| 
 | ||||
|     val = json_object_get(j, "discriminator"); | ||||
|     goto_if_true(val == NULL || !json_is_string(val), error); | ||||
|     dc_account_set_discriminator(user, json_string_value(val)); | ||||
| 
 | ||||
|     val = json_object_get(j, "id"); | ||||
|     goto_if_true(val == NULL || !json_is_string(val), error); | ||||
|     dc_account_set_id(user, json_string_value(val)); | ||||
| 
 | ||||
|     return user; | ||||
| 
 | ||||
| error: | ||||
| 
 | ||||
|     dc_unref(user); | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| static json_t *dc_api_user_to_json(dc_account_t a) | ||||
| { | ||||
|     json_t *j = NULL; | ||||
| 
 | ||||
|     return_if_true(a == NULL, NULL); | ||||
|     return_if_true(dc_account_username(a) == NULL || | ||||
|                    dc_account_discriminator(a) == NULL, | ||||
|                    NULL | ||||
|         ); | ||||
| 
 | ||||
|     j = json_object(); | ||||
|     return_if_true(j == NULL, NULL); | ||||
| 
 | ||||
|     json_object_set_new(j, "username", | ||||
|                         json_string(dc_account_username(a)) | ||||
|         ); | ||||
|     json_object_set_new(j, "discriminator", | ||||
|                         json_string(dc_account_discriminator(a)) | ||||
|         ); | ||||
| 
 | ||||
|     return j; | ||||
| } | ||||
| 
 | ||||
| bool dc_api_get_userinfo(dc_api_t api, dc_account_t login, | ||||
|                          dc_account_t user) | ||||
| { | ||||
| @ -414,94 +364,6 @@ cleanup: | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool dc_api_get_friends(dc_api_t api, dc_account_t login) | ||||
| { | ||||
|     char const *url = "users/@me/relationships"; | ||||
|     json_t *reply = NULL, *c = NULL, *val = NULL; | ||||
|     bool ret = false; | ||||
|     size_t i = 0; | ||||
|     GPtrArray *f = g_ptr_array_new_with_free_func((GDestroyNotify)dc_unref); | ||||
| 
 | ||||
|     return_if_true(api == NULL, false); | ||||
|     return_if_true(login == NULL, false); | ||||
| 
 | ||||
|     reply = dc_api_call_sync(api, "GET", dc_account_token(login), url, NULL); | ||||
|     goto_if_true(reply == NULL, cleanup); | ||||
| 
 | ||||
|     goto_if_true(!json_is_array(reply), cleanup); | ||||
| 
 | ||||
|     json_array_foreach(reply, i, c) { | ||||
|         /* the return is an array of objects, with a "user" member
 | ||||
|          * type 1 is probably a friend | ||||
|          */ | ||||
|         val = json_object_get(c, "user"); | ||||
|         if (val == NULL) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         dc_account_t a = dc_api_account_from_json(val); | ||||
|         if (a == NULL) { | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         /* read the type also known as "typ"
 | ||||
|          */ | ||||
|         val = json_object_get(c, "type"); | ||||
|         if (val != NULL && json_is_integer(val)) { | ||||
|             int state = json_integer_value(val); | ||||
|             dc_account_set_friend_state(a, state); | ||||
|         } | ||||
| 
 | ||||
|         g_ptr_array_add(f, a); | ||||
|     } | ||||
| 
 | ||||
|     if (f->len == 0) { | ||||
|         /* me_irl :-(
 | ||||
|          */ | ||||
|     } | ||||
| 
 | ||||
|     dc_account_set_friends(login, (dc_account_t*)f->pdata, f->len); | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     g_ptr_array_free(f, FALSE); | ||||
|     json_decref(reply); | ||||
|     reply = NULL; | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Add a given account as a friend to the friends list | ||||
|  */ | ||||
| bool dc_api_add_friend(dc_api_t api, dc_account_t login, dc_account_t friend) | ||||
| { | ||||
|     char const *url = "users/@me/relationships"; | ||||
|     json_t *reply = NULL, *post = NULL; | ||||
|     bool ret = false; | ||||
| 
 | ||||
|     return_if_true(api == NULL, false); | ||||
|     return_if_true(login == NULL, false); | ||||
| 
 | ||||
|     post = dc_api_user_to_json(friend); | ||||
|     return_if_true(post == NULL, false); | ||||
| 
 | ||||
|     reply = dc_api_call_sync(api, "POST", dc_account_token(login), url, post); | ||||
|     /* apparently if no data comes back, then the whole thing was a success
 | ||||
|      */ | ||||
|     goto_if_true(reply != NULL, cleanup); | ||||
| 
 | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     json_decref(post); | ||||
|     json_decref(reply); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| bool dc_api_get_userguilds(dc_api_t api, dc_account_t login, GPtrArray **out) | ||||
| { | ||||
|     char const *url = "users/@me/guilds"; | ||||
|  | ||||
| @ -22,10 +22,18 @@ | ||||
| #include <event2/thread.h> | ||||
| 
 | ||||
| #include <dc/util.h> | ||||
| #include <dc/refable.h> | ||||
| #include <dc/account.h> | ||||
| 
 | ||||
| //#define DEBUG
 | ||||
| 
 | ||||
| #define return_if_true(v,r) do { if (v) return r; } while(0) | ||||
| #define goto_if_true(v,l) do { if (v) goto l; } while(0) | ||||
| 
 | ||||
| /* These are internal helper methods, their ABI, and API stability
 | ||||
|  * is not garuanteed. So please beware | ||||
|  */ | ||||
| json_t *dc_api_account_to_json(dc_account_t a); | ||||
| dc_account_t dc_api_account_from_json(json_t *j); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -19,6 +19,11 @@ bool ncdc_dispatch_deinit(void); | ||||
| 
 | ||||
| bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s); | ||||
| 
 | ||||
| /* find a given command in a list of commands, helpful if your command has
 | ||||
|  * sub commands. for example usage see the friends command | ||||
|  */ | ||||
| ncdc_commands_t *ncdc_find_cmd(ncdc_commands_t *cmds, wchar_t const *name); | ||||
| 
 | ||||
| bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av); | ||||
| bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av); | ||||
| bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av); | ||||
|  | ||||
| @ -89,26 +89,29 @@ bool ncdc_dispatch_deinit(void) | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| ncdc_commands_t *ncdc_find_cmd(ncdc_commands_t *cmds, wchar_t const *name) | ||||
| { | ||||
|     ncdc_commands_t *it = NULL; | ||||
| 
 | ||||
|     for (it = cmds; it->name != NULL; it++) { | ||||
|         if (wcscmp(it->name, name) == 0) { | ||||
|             return it; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return NULL; | ||||
| } | ||||
| 
 | ||||
| bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s) | ||||
| { | ||||
|     wchar_t **tokens = NULL; | ||||
|     size_t i = 0, tokenlen = 0; | ||||
|     ncdc_commands_t *it = NULL; | ||||
|     queue_item *item = NULL; | ||||
| 
 | ||||
|     tokens = w_tokenise(s); | ||||
|     return_if_true(tokens == NULL, false); | ||||
| 
 | ||||
|     tokenlen = wcslen(tokens[0]); | ||||
| 
 | ||||
|     for (i = 0; cmds[i].name != NULL; i++) { | ||||
|         if (wcsncmp(cmds[i].name, tokens[0], tokenlen) == 0) { | ||||
|             it = cmds+i; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (it == NULL) { | ||||
|     if ((it = ncdc_find_cmd(cmds, tokens[0])) == NULL) { | ||||
|         /* no such command
 | ||||
|          */ | ||||
|         LOG(n, L"error: no such command \"%ls\"", tokens[0]); | ||||
|  | ||||
| @ -6,7 +6,7 @@ ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| { | ||||
|     bool ret = false; | ||||
|     size_t i = 0; | ||||
|     wchar_t c = ' '; | ||||
|     char c = ' '; | ||||
| 
 | ||||
|     ret = dc_api_get_friends(api, current_account); | ||||
|     if (!ret) { | ||||
| @ -21,7 +21,7 @@ ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
|         case FRIEND_STATE_PENDING: c = 'P'; break; | ||||
|         default: c = ' '; break; | ||||
|         } | ||||
|         LOG(n, L"%lc %s", c, dc_account_full_username(acc)); | ||||
|         LOG(n, L" %c %s", c, dc_account_fullname(acc)); | ||||
|     } | ||||
|     LOG(n, L"End of /FRIENDS list"); | ||||
| 
 | ||||
| @ -42,7 +42,7 @@ ncdc_cmd_friends_add(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
|     name = w_convert(av[1]); | ||||
|     return_if_true(name == NULL, false); | ||||
| 
 | ||||
|     friend = dc_account_from_fullid(name); | ||||
|     friend = dc_account_from_fullname(name); | ||||
|     if (friend == NULL) { | ||||
|         LOG(n, L"friends: add: invalid username given, use the full ID"); | ||||
|         goto cleanup; | ||||
| @ -53,7 +53,7 @@ ncdc_cmd_friends_add(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     LOG(n, L"friends: add: request for friendship sent"); | ||||
|     LOG(n, L"friends: add: request for friendship sent to %s", name); | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| @ -64,9 +64,105 @@ cleanup: | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| ncdc_cmd_friends_remove(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| { | ||||
|     char *name = NULL; | ||||
|     dc_account_t friend = NULL; | ||||
|     bool ret = false; | ||||
|     size_t i = 0; | ||||
| 
 | ||||
|     if (ac <= 1) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     name = w_convert(av[1]); | ||||
|     return_if_true(name == NULL, false); | ||||
| 
 | ||||
|     for (i = 0; i < dc_account_friends_size(current_account); i++) { | ||||
|         dc_account_t cur = dc_account_nthfriend(current_account, i); | ||||
|         if (strcmp(dc_account_fullname(cur), name) == 0) { | ||||
|             friend = cur; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (friend == NULL) { | ||||
|         LOG(n, L"friends: remove: no such friend in friend's list"); | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     if (!dc_api_remove_friend(api, current_account, friend)) { | ||||
|         LOG(n, L"friends: remove: failed to remove friend"); | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     LOG(n, L"friends: remove: friend %s removed", name); | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     free(name); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static bool | ||||
| ncdc_cmd_friends_accept(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| { | ||||
|     char *name = NULL; | ||||
|     dc_account_t friend = NULL; | ||||
|     bool ret = false; | ||||
|     size_t i = 0; | ||||
| 
 | ||||
|     if (ac <= 1) { | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     name = w_convert(av[1]); | ||||
|     return_if_true(name == NULL, false); | ||||
| 
 | ||||
|     for (i = 0; i < dc_account_friends_size(current_account); i++) { | ||||
|         dc_account_t cur = dc_account_nthfriend(current_account, i); | ||||
|         if (strcmp(dc_account_fullname(cur), name) == 0 && | ||||
|             dc_account_friend_state(cur) == FRIEND_STATE_PENDING) { | ||||
|             friend = cur; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if (friend == NULL) { | ||||
|         LOG(n, L"friends: accept: no such pending friend on the list"); | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     if (!dc_api_accept_friend(api, current_account, friend)) { | ||||
|         LOG(n, L"friends: accept: failed to accept friend"); | ||||
|         goto cleanup; | ||||
|     } | ||||
| 
 | ||||
|     LOG(n, L"friends: accept: friend %s accepted", name); | ||||
|     ret = true; | ||||
| 
 | ||||
| cleanup: | ||||
| 
 | ||||
|     free(name); | ||||
| 
 | ||||
|     return ret; | ||||
| } | ||||
| 
 | ||||
| static ncdc_commands_t subcmds[] = { | ||||
|     { L"accept", ncdc_cmd_friends_accept }, | ||||
|     { L"add",    ncdc_cmd_friends_add }, | ||||
|     { L"list",   ncdc_cmd_friends_list }, | ||||
|     { L"remove", ncdc_cmd_friends_remove }, | ||||
|     { NULL,     NULL } | ||||
| }; | ||||
| 
 | ||||
| bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
| { | ||||
|     wchar_t *subcmd = NULL; | ||||
|     ncdc_commands_t *it = NULL; | ||||
| 
 | ||||
|     if (current_account == NULL || | ||||
|         !dc_account_has_token(current_account)) { | ||||
| @ -83,13 +179,10 @@ bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av) | ||||
|     --ac; | ||||
|     ++av; | ||||
| 
 | ||||
|     if (wcscmp(subcmd, L"list") == 0) { | ||||
|         return ncdc_cmd_friends_list(n, ac, av); | ||||
|     } else if (wcscmp(subcmd, L"add") == 0) { | ||||
|         return ncdc_cmd_friends_add(n, ac, av); | ||||
|     } else { | ||||
|     if ((it = ncdc_find_cmd(subcmds, subcmd)) == NULL) { | ||||
|         LOG(n, L"friends: no such subcommand \"%ls\"", subcmd); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     return true; | ||||
|     return it->handler(n, ac, av); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user