implement adding friends
This commit is contained in:
parent
2e563b724a
commit
efce6a6543
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
105
ncdc/src/util.c
105
ncdc/src/util.c
@ -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));
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user