diff --git a/README.md b/README.md index e468512..c13e502 100644 --- a/README.md +++ b/README.md @@ -103,17 +103,21 @@ guild names, or user names are all case sensitive. | /ack | Mark channel as read | | WIP | | /close | Close current channel view | | | | /connect | Connect as the given account | account, as named in config | | +| /dnd | Mark yourself as do not disturb | | | | /friend | List all friends | | | | /friend accept | Accept a friend request | full discord name, i.e. name#XXXX | | | /friend add | Add a friend | full discord name, i.e. name#XXXX | | | /friend list | List all friends | | | | /friend remove | Remove a friend | full discord name, i.e. name#XXXX | | | /friends | Alias for "/friend" | | | +| /idle | Mark yourself as idle | | | +| /invisible | Mark yourself as invisible | | | | /join | Join a guild channel | "guild name" "channel name" | | | /login | Alias for /connect | | | | /logout | Log current user out | | | | /markread | Alias for /ack | | WIP | | /msg | Private message a friend | full discord name, i.e. name#XXXX | | +| /online | Mark yourself as online | | | | /post | Post a message to current channel | full message to post | | | /quit | Exit, and quit | | | | /wc | Alias for /close | | | diff --git a/libdc/include/dc/api.h b/libdc/include/dc/api.h index 26edf98..79d2be9 100644 --- a/libdc/include/dc/api.h +++ b/libdc/include/dc/api.h @@ -31,6 +31,11 @@ #include #include +#define DC_API_USER_STATUS_ONLINE "online" +#define DC_API_USER_STATUS_IDLE "idle" +#define DC_API_USER_STATUS_DND "dnd" +#define DC_API_USER_STATUS_INVISIBLE "invisible" + struct dc_api_; typedef struct dc_api_ *dc_api_t; @@ -93,6 +98,14 @@ bool dc_api_get_userinfo(dc_api_t api, dc_account_t login, bool dc_api_get_userguilds(dc_api_t api, dc_account_t login, GPtrArray **guilds); +/** + * Set the online status of the currently logged in user "login". "status" must + * be one of the valid string macros defined in this header, or the function + * fails. + */ +bool dc_api_set_user_status(dc_api_t api, dc_account_t login, + char const *status); + /** * Create a 1:1 or 1:N DM channel with the given recipients. The recipients must * have their ID (snowflake) set. Returns the new channel, complete with ID, and diff --git a/libdc/src/api-user.c b/libdc/src/api-user.c index 78e3bbd..ffbbf6b 100644 --- a/libdc/src/api-user.c +++ b/libdc/src/api-user.c @@ -19,6 +19,40 @@ #include #include "internal.h" +bool dc_api_set_user_status(dc_api_t api, dc_account_t login, + char const *status) +{ + char const *url = "users/@me/settings"; + json_t *reply = NULL, *data = NULL; + bool ret = false; + + return_if_true(api == NULL || login == NULL || status == NULL, false); + + if (strcmp(status, DC_API_USER_STATUS_ONLINE) != 0 && + strcmp(status, DC_API_USER_STATUS_IDLE) != 0 && + strcmp(status, DC_API_USER_STATUS_DND) != 0 && + strcmp(status, DC_API_USER_STATUS_INVISIBLE) != 0) { + return false; + } + + data = json_object(); + goto_if_true(data == NULL, cleanup); + + json_object_set_new(data, "status", json_string(status)); + + reply = dc_api_call_sync(api, "PATCH", TOKEN(login), url, data); + goto_if_true(reply != NULL, cleanup); + + ret = true; + +cleanup: + + json_decref(reply); + json_decref(data); + + return ret; +} + bool dc_api_get_userinfo(dc_api_t api, dc_account_t login, dc_account_t user) { @@ -36,7 +70,7 @@ bool dc_api_get_userinfo(dc_api_t api, dc_account_t login, asprintf(&url, "users/%s", dc_account_id(user)); } - reply = dc_api_call_sync(api, "GET", dc_account_token(login), url, NULL); + reply = dc_api_call_sync(api, "GET", TOKEN(login), url, NULL); goto_if_true(reply == NULL, cleanup); val = json_object_get(reply, "username"); @@ -74,7 +108,7 @@ bool dc_api_get_userguilds(dc_api_t api, dc_account_t login, GPtrArray **out) 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); + reply = dc_api_call_sync(api, "GET", TOKEN(login), url, NULL); goto_if_true(reply == NULL, cleanup); goto_if_true(!json_is_array(reply), cleanup); diff --git a/libdc/src/api.c b/libdc/src/api.c index dfce721..f4906cd 100644 --- a/libdc/src/api.c +++ b/libdc/src/api.c @@ -185,7 +185,8 @@ dc_api_do(dc_api_t api, char const *verb, } if (strcmp(verb, "PUT") == 0 || - strcmp(verb, "DELETE") == 0) { + strcmp(verb, "DELETE") == 0 || + strcmp(verb, "PATCH") == 0) { curl_easy_setopt(c, CURLOPT_CUSTOMREQUEST, verb); } diff --git a/ncdc/CMakeLists.txt b/ncdc/CMakeLists.txt index 4574a26..6e72672 100644 --- a/ncdc/CMakeLists.txt +++ b/ncdc/CMakeLists.txt @@ -28,6 +28,7 @@ SET(SOURCES "src/msg.c" "src/ncdc.c" "src/post.c" + "src/status.c" "src/textview.c" "src/treeview.c" "src/util.c" diff --git a/ncdc/include/ncdc/cmds.h b/ncdc/include/ncdc/cmds.h index 94de276..b9e5c95 100644 --- a/ncdc/include/ncdc/cmds.h +++ b/ncdc/include/ncdc/cmds.h @@ -50,11 +50,15 @@ ncdc_commands_t *ncdc_find_cmd(ncdc_commands_t *cmds, wchar_t const *name); bool ncdc_cmd_ack(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); bool ncdc_cmd_close(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); +bool ncdc_cmd_dnd(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); +bool ncdc_cmd_idle(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); +bool ncdc_cmd_invisible(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); bool ncdc_cmd_join(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); bool ncdc_cmd_logout(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); +bool ncdc_cmd_online(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); bool ncdc_cmd_post(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av, wchar_t const *f); diff --git a/ncdc/include/ncdc/ncdc.h b/ncdc/include/ncdc/ncdc.h index fc60e36..9c77d06 100644 --- a/ncdc/include/ncdc/ncdc.h +++ b/ncdc/include/ncdc/ncdc.h @@ -55,6 +55,9 @@ #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) +/* NCDC_DEBUG variable */ +/*#define NCDC_DEBUG*/ + typedef enum { ncdc_colour_separator = 1, ncdc_colour_treehighlight = 2, diff --git a/ncdc/src/cmds.c b/ncdc/src/cmds.c index 4e310a5..35be31b 100644 --- a/ncdc/src/cmds.c +++ b/ncdc/src/cmds.c @@ -22,13 +22,17 @@ ncdc_commands_t cmds[] = { { L"/ack", ncdc_cmd_ack }, { L"/close", ncdc_cmd_close }, { L"/connect", ncdc_cmd_login }, + { L"/dnd", ncdc_cmd_dnd }, { L"/friend", ncdc_cmd_friends }, { L"/friends", ncdc_cmd_friends }, + { L"/idle", ncdc_cmd_idle }, + { L"/invisible",ncdc_cmd_invisible }, { L"/join", ncdc_cmd_join }, { L"/login", ncdc_cmd_login }, { L"/logout", ncdc_cmd_logout }, { L"/markread", ncdc_cmd_ack }, { L"/msg", ncdc_cmd_msg }, + { L"/online", ncdc_cmd_online }, { L"/post", ncdc_cmd_post }, { L"/quit", ncdc_cmd_quit }, { L"/wc", ncdc_cmd_close }, diff --git a/ncdc/src/mainwindow.c b/ncdc/src/mainwindow.c index 0418faa..c67fc9c 100644 --- a/ncdc/src/mainwindow.c +++ b/ncdc/src/mainwindow.c @@ -406,7 +406,7 @@ void ncdc_mainwindow_input_ready(ncdc_mainwindow_t n) } keylen = wcslen(key); -#if 0 +#ifdef NCDC_DEBUG FILE *f = fopen("keys.txt", "a+"); fwprintf(f, L"KEY: %02X %ls\n", key[0], &key[1] @@ -415,7 +415,7 @@ void ncdc_mainwindow_input_ready(ncdc_mainwindow_t n) #endif } -#if 0 +#ifdef NCDC_DEBUG FILE *f = fopen("keys.txt", "a+"); fwprintf(f, L"%X\n", i); fclose(f); diff --git a/ncdc/src/status.c b/ncdc/src/status.c new file mode 100644 index 0000000..7cb69e4 --- /dev/null +++ b/ncdc/src/status.c @@ -0,0 +1,68 @@ +/* + * Part of ncdc - a discord client for the console + * Copyright (C) 2019 Florian Stinglmayr + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +bool ncdc_cmd_idle(ncdc_mainwindow_t n, size_t ac, wchar_t **av, + wchar_t const *f) +{ + bool ret = false; + + ret = dc_api_set_user_status(dc_session_api(current_session), + dc_session_me(current_session), + DC_API_USER_STATUS_IDLE + ); + return ret; +} + +bool ncdc_cmd_online(ncdc_mainwindow_t n, size_t ac, wchar_t **av, + wchar_t const *f) +{ + bool ret = false; + + ret = dc_api_set_user_status(dc_session_api(current_session), + dc_session_me(current_session), + DC_API_USER_STATUS_ONLINE + ); + return ret; +} + +bool ncdc_cmd_invisible(ncdc_mainwindow_t n, size_t ac, wchar_t **av, + wchar_t const *f) +{ + bool ret = false; + + ret = dc_api_set_user_status(dc_session_api(current_session), + dc_session_me(current_session), + DC_API_USER_STATUS_INVISIBLE + ); + return ret; +} + +bool ncdc_cmd_dnd(ncdc_mainwindow_t n, size_t ac, wchar_t **av, + wchar_t const *f) +{ + bool ret = false; + + ret = dc_api_set_user_status(dc_session_api(current_session), + dc_session_me(current_session), + DC_API_USER_STATUS_DND + ); + return ret; +}