implement adding friends

This commit is contained in:
Florian Stinglmayr 2019-07-03 22:47:12 +02:00
parent 2e563b724a
commit efce6a6543
8 changed files with 231 additions and 68 deletions

View File

@ -8,8 +8,19 @@
struct dc_account_; struct dc_account_;
typedef struct dc_account_ *dc_account_t; typedef struct dc_account_ *dc_account_t;
typedef enum {
FRIEND_STATE_NONE = 0,
/* accountt is a mutual friend
*/
FRIEND_STATE_FRIEND = 1,
/* pending account, the other side hasn't accepted yet
*/
FRIEND_STATE_PENDING = 4,
} dc_account_friend_states;
dc_account_t dc_account_new(void); dc_account_t dc_account_new(void);
dc_account_t dc_account_new2(char const *email, char const *pass); dc_account_t dc_account_new2(char const *email, char const *pass);
dc_account_t dc_account_from_fullid(char const *fullid);
void dc_account_set_email(dc_account_t a, char const *email); void dc_account_set_email(dc_account_t a, char const *email);
char const *dc_account_email(dc_account_t a); char const *dc_account_email(dc_account_t a);
@ -37,5 +48,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); 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); dc_account_t dc_account_nthfriend(dc_account_t a, size_t i);
size_t dc_account_friends_size(dc_account_t a); 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);
#endif #endif

View File

@ -65,4 +65,9 @@ bool dc_api_get_userguilds(dc_api_t api, dc_account_t login,
*/ */
bool dc_api_get_friends(dc_api_t api, dc_account_t login); bool dc_api_get_friends(dc_api_t api, dc_account_t login);
/**
* 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);
#endif #endif

View File

@ -34,6 +34,9 @@ struct dc_account_
/* friends we have /* friends we have
*/ */
GPtrArray *friends; GPtrArray *friends;
/* our own friend state
*/
int friend_state;
}; };
static void dc_account_free(dc_account_t ptr) static void dc_account_free(dc_account_t ptr)
@ -81,6 +84,38 @@ dc_account_t dc_account_new2(char const *email, char const *pass)
return ptr; return ptr;
} }
dc_account_t dc_account_from_fullid(char const *fullid)
{
return_if_true(fullid == NULL, NULL);
char *name = strdup(fullid), *discriminator = NULL;
dc_account_t acc = NULL;
return_if_true(name == NULL, NULL);
discriminator = strchr(name, '#');
if (discriminator == NULL || *discriminator == '\0') {
free(name);
return NULL;
}
*discriminator = '\0';
++discriminator;
acc = dc_account_new();
if (acc == NULL) {
free(name);
return NULL;
}
dc_account_set_username(acc, name);
dc_account_set_discriminator(acc, discriminator);
free(name);
return acc;
}
void dc_account_set_email(dc_account_t a, char const *email) void dc_account_set_email(dc_account_t a, char const *email)
{ {
return_if_true(a == NULL,); return_if_true(a == NULL,);
@ -219,3 +254,15 @@ size_t dc_account_friends_size(dc_account_t a)
return_if_true(a == NULL || a->friends == NULL, 0); return_if_true(a == NULL || a->friends == NULL, 0);
return a->friends->len; return a->friends->len;
} }
int dc_account_friend_state(dc_account_t a)
{
return_if_true(a == NULL, 0);
return a->friend_state;
}
void dc_account_set_friend_state(dc_account_t a, int state)
{
return_if_true(a == NULL,);
a->friend_state = state;
}

View File

@ -349,6 +349,29 @@ error:
return NULL; 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, bool dc_api_get_userinfo(dc_api_t api, dc_account_t login,
dc_account_t user) dc_account_t user)
{ {
@ -420,6 +443,15 @@ bool dc_api_get_friends(dc_api_t api, dc_account_t login)
if (a == NULL) { if (a == NULL) {
continue; 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); g_ptr_array_add(f, a);
} }
@ -440,6 +472,36 @@ cleanup:
return ret; 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) bool dc_api_get_userguilds(dc_api_t api, dc_account_t login, GPtrArray **out)
{ {
char const *url = "users/@me/guilds"; char const *url = "users/@me/guilds";

View File

@ -1,9 +1,10 @@
#include <ncdc/cmds.h> #include <ncdc/cmds.h>
ncdc_commands_t cmds[] = { ncdc_commands_t cmds[] = {
{ L"friends", ncdc_cmd_friends }, { L"/friend", ncdc_cmd_friends },
{ L"login", ncdc_cmd_login }, { L"/friends", ncdc_cmd_friends },
{ L"quit", ncdc_cmd_quit }, { L"/login", ncdc_cmd_login },
{ L"/quit", ncdc_cmd_quit },
{ NULL, NULL } { NULL, NULL }
}; };
@ -36,7 +37,6 @@ static void *async_dispatcher(void *arg)
/* end of working orders /* end of working orders
*/ */
pthread_mutex_unlock(&mtx); pthread_mutex_unlock(&mtx);
printf("got exit\n");
return NULL; return NULL;
} else { } else {
/* call the handler /* call the handler
@ -92,15 +92,17 @@ bool ncdc_dispatch_deinit(void)
bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s) bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s)
{ {
wchar_t **tokens = NULL; wchar_t **tokens = NULL;
size_t i = 0; size_t i = 0, tokenlen = 0;
ncdc_commands_t *it = NULL; ncdc_commands_t *it = NULL;
queue_item *item = NULL; queue_item *item = NULL;
tokens = w_tokenise(s); tokens = w_tokenise(s);
return_if_true(tokens == NULL, false); return_if_true(tokens == NULL, false);
tokenlen = wcslen(tokens[0]);
for (i = 0; cmds[i].name != NULL; i++) { for (i = 0; cmds[i].name != NULL; i++) {
if (wcscmp(cmds[i].name, tokens[0]) == 0) { if (wcsncmp(cmds[i].name, tokens[0], tokenlen) == 0) {
it = cmds+i; it = cmds+i;
break; break;
} }

View File

@ -6,6 +6,7 @@ ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{ {
bool ret = false; bool ret = false;
size_t i = 0; size_t i = 0;
wchar_t c = ' ';
ret = dc_api_get_friends(api, current_account); ret = dc_api_get_friends(api, current_account);
if (!ret) { if (!ret) {
@ -16,27 +17,67 @@ ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
LOG(n, L"/FRIENDS list"); LOG(n, L"/FRIENDS list");
for (i = 0; i < dc_account_friends_size(current_account); i++) { for (i = 0; i < dc_account_friends_size(current_account); i++) {
dc_account_t acc = dc_account_nthfriend(current_account, i); dc_account_t acc = dc_account_nthfriend(current_account, i);
LOG(n, L" %s", dc_account_full_username(acc)); switch (dc_account_friend_state(acc)) {
case FRIEND_STATE_PENDING: c = 'P'; break;
default: c = ' '; break;
}
LOG(n, L"%lc %s", c, dc_account_full_username(acc));
} }
LOG(n, L"End of /FRIENDS list"); LOG(n, L"End of /FRIENDS list");
return true; return true;
} }
bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av) static bool
ncdc_cmd_friends_add(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{ {
wchar_t *subcmd = NULL; char *name = NULL;
dc_account_t friend = NULL;
bool ret = false;
if (ac <= 1) { if (ac <= 1) {
return false; return false;
} }
name = w_convert(av[1]);
return_if_true(name == NULL, false);
friend = dc_account_from_fullid(name);
if (friend == NULL) {
LOG(n, L"friends: add: invalid username given, use the full ID");
goto cleanup;
}
if (!dc_api_add_friend(api, current_account, friend)) {
LOG(n, L"friends: add: failed to add friend, Vulkan would be sad");
goto cleanup;
}
LOG(n, L"friends: add: request for friendship sent");
ret = true;
cleanup:
dc_unref(friend);
free(name);
return ret;
}
bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
{
wchar_t *subcmd = NULL;
if (current_account == NULL || if (current_account == NULL ||
!dc_account_has_token(current_account)) { !dc_account_has_token(current_account)) {
LOG(n, L"friends: not logged in"); LOG(n, L"friends: not logged in");
return false; return false;
} }
if (ac <= 1) {
return ncdc_cmd_friends_list(n, ac, av);
}
subcmd = av[1]; subcmd = av[1];
--ac; --ac;
@ -44,6 +85,8 @@ bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
if (wcscmp(subcmd, L"list") == 0) { if (wcscmp(subcmd, L"list") == 0) {
return ncdc_cmd_friends_list(n, ac, av); return ncdc_cmd_friends_list(n, ac, av);
} else if (wcscmp(subcmd, L"add") == 0) {
return ncdc_cmd_friends_add(n, ac, av);
} else { } else {
return false; return false;
} }

View File

@ -99,12 +99,12 @@ ncdc_mainwindow_callback(ncdc_input_t i, wchar_t const *s,
{ {
ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg; ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg;
if (s[0] == '/') { if (s != NULL && s[0] == '/') {
if (s[1] == '\0') { if (s[1] == '\0') {
return false; return false;
} }
return ncdc_dispatch(mainwin, s+1); return ncdc_dispatch(mainwin, s);
} }
return false; return false;

View File

@ -33,11 +33,11 @@ int aswprintf(wchar_t **buffer, wchar_t const *fmt, ...)
return sz; return sz;
} }
wchar_t* wcsndup(const wchar_t* string, size_t maxlen) wchar_t* wcsndup(wchar_t const* string, size_t maxlen)
{ {
size_t n = wcsnlen(string, maxlen) + 1; wchar_t* r = calloc(maxlen+1, sizeof(wchar_t));
wchar_t* r = calloc(n, sizeof(wchar_t)); return_if_true(r == NULL, NULL);
return r == NULL ? NULL : wmemcpy(r, string, n); return wmemcpy(r, string, maxlen);
} }
size_t w_strlenv(wchar_t **s) size_t w_strlenv(wchar_t **s)
@ -61,28 +61,56 @@ void w_strfreev(wchar_t **s)
free(s); free(s);
} }
wchar_t **w_tokenise(wchar_t const *w) wchar_t **w_tokenise(wchar_t const *str)
{ {
wchar_t const *p = NULL, *start_of_word = NULL;
wint_t c;
GPtrArray *array = g_ptr_array_new(); GPtrArray *array = g_ptr_array_new();
wchar_t const *item = w; enum states { DULL, IN_WORD, IN_STRING } state = DULL;
wchar_t *dup = NULL;
size_t len = 0, origlen = 0;
while ((dup = w_next_tok(item)) != NULL) { for (p = str; *p != '\0'; p++) {
len = origlen = wcslen(dup); c = (wint_t) *p;
switch (state) {
case DULL:
{
if (iswspace(c)) {
continue;
}
if (c == '"') {
state = IN_STRING;
start_of_word = p + 1;
continue;
}
state = IN_WORD;
start_of_word = p;
} continue;
if (*dup == '"') { case IN_STRING:
memmove(dup, dup+1, sizeof(wchar_t)*(len-1)); {
--len; if (c == '"') {
size_t len = (p - 2 - start_of_word);
wchar_t *s = wcsndup(start_of_word, len);
g_ptr_array_add(array, s);
state = DULL;
}
} continue;
case IN_WORD:
{
if (iswspace(c)) {
size_t len = (p - start_of_word);
wchar_t *s = wcsndup(start_of_word, len);
g_ptr_array_add(array, s);
state = DULL;
}
} continue;
} }
}
if (len > 0 && dup[len-1] == '"') { if (state != DULL) {
dup[len-1] = '\0'; size_t len = (p - start_of_word);
--len; wchar_t *s = wcsndup(start_of_word, len);
} g_ptr_array_add(array, s);
g_ptr_array_add(array, dup);
item += origlen;
} }
g_ptr_array_add(array, NULL); g_ptr_array_add(array, NULL);
@ -103,40 +131,3 @@ char *w_convert(wchar_t const *w)
wcstombs(ptr, w, sz); wcstombs(ptr, w, sz);
return ptr; return ptr;
} }
wchar_t *w_next_tok(wchar_t const *w)
{
bool quotes = false;
wchar_t const *start = NULL;
/* skip first white spaces if there are any
*/
for (; *w != '\0' && iswspace(*w); w++)
;
if (*w == '\0') {
return NULL;
}
start = w;
quotes = (*w == '"');
do {
if (iswspace(*w) && !quotes) {
--w;
break;
}
if (*w == '"' && *(w-1) != '\\' && quotes) {
break;
}
if (*w == '\0') {
break;
}
++w;
} while (1);
return wcsndup(start, (w - start));
}