implement message sending to channels

This commit is contained in:
Florian Stinglmayr 2019-07-12 11:53:32 +02:00
parent 0c9432c269
commit b8fa202ce3
18 changed files with 219 additions and 28 deletions

View File

@ -90,6 +90,12 @@ bool dc_api_create_channel(dc_api_t api, dc_account_t login,
*/
bool dc_api_get_messages(dc_api_t api, dc_account_t login, dc_channel_t c);
/**
* post a message to the given channel
*/
bool dc_api_post_message(dc_api_t api, dc_account_t login,
dc_channel_t c, dc_message_t m);
/**
* Fetch a list of friends of the login account "login". The friends are stored
* within the login object.

View File

@ -10,6 +10,7 @@ struct dc_message_;
typedef struct dc_message_ *dc_message_t;
dc_message_t dc_message_new(void);
dc_message_t dc_message_new_content(char const *s, int len);
dc_message_t dc_message_from_json(json_t *j);
json_t *dc_message_to_json(dc_message_t m);

View File

@ -52,6 +52,12 @@ bool dc_session_has_token(dc_session_t s);
*/
dc_account_t dc_session_me(dc_session_t s);
/**
* Return the API handle in use by the session. Do not unref the reference
* and if you need it for something else, dc_ref() it yourself.
*/
dc_api_t dc_session_api(dc_session_t s);
/**
* access to the internal account cache
*/

View File

@ -2,6 +2,36 @@
#include "internal.h"
bool dc_api_post_message(dc_api_t api, dc_account_t login,
dc_channel_t c, dc_message_t m)
{
bool ret = false;
char *url = NULL;
json_t *j = NULL, *reply = NULL;
return_if_true(api == NULL || login == NULL || m == NULL, false);
return_if_true(dc_message_content(m) == NULL, false);
asprintf(&url, "channels/%s/messages", dc_channel_id(c));
goto_if_true(url == NULL, cleanup);
j = dc_message_to_json(m);
goto_if_true(j == NULL, cleanup);
reply = dc_api_call_sync(api, "POST", TOKEN(login), url, j);
goto_if_true(reply != NULL, cleanup);
ret = true;
cleanup:
free(url);
json_decref(j);
json_decref(reply);
return ret;
}
bool dc_api_get_messages(dc_api_t api, dc_account_t login, dc_channel_t c)
{
bool ret = false;

View File

@ -40,6 +40,24 @@ dc_message_t dc_message_new(void)
return dc_ref(m);
}
dc_message_t dc_message_new_content(char const *s, int len)
{
dc_message_t m = dc_message_new();
return_if_true(m == NULL, NULL);
if (len < 0) {
len = strlen(s);
}
m->content = strndup(s, len);
if (m->content == NULL) {
dc_unref(m);
return NULL;
}
return m;
}
dc_message_t dc_message_from_json(json_t *j)
{
dc_message_t m = NULL;

View File

@ -227,6 +227,12 @@ bool dc_session_has_token(dc_session_t s)
return dc_account_has_token(s->login);
}
dc_api_t dc_session_api(dc_session_t s)
{
return_if_true(s == NULL, NULL);
return s->api;
}
dc_account_t dc_session_me(dc_session_t s)
{
return_if_true(s == NULL, NULL);

View File

@ -23,6 +23,7 @@ SET(SOURCES
"src/mainwindow.c"
"src/msg.c"
"src/ncdc.c"
"src/post.c"
"src/textview.c"
"src/util.c"
)

View File

@ -4,8 +4,14 @@
#include <ncdc/ncdc.h>
#include <ncdc/mainwindow.h>
/**
* n .. the main window handle
* ac,av .. the full string parsed up along white spaces
* f .. the full string, without the /command bit
*/
typedef bool (*ncdc_command_t)(ncdc_mainwindow_t n,
size_t argc, wchar_t **argv);
size_t argc, wchar_t **argv,
wchar_t const *f);
typedef struct {
wchar_t const *name;
@ -24,10 +30,11 @@ bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s);
*/
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_logout(ncdc_mainwindow_t n, size_t ac, wchar_t **av);
bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av);
bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av);
bool ncdc_cmd_friends(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_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);
#endif

View File

@ -15,6 +15,7 @@ ncdc_mainwindow_t ncdc_mainwindow_new(void);
void ncdc_mainwindow_log(ncdc_mainwindow_t w, wchar_t const *fmt, ...);
GPtrArray *ncdc_mainwindow_views(ncdc_mainwindow_t n);
dc_channel_t ncdc_mainwindow_current_channel(ncdc_mainwindow_t n);
void ncdc_mainwindow_switchview(ncdc_mainwindow_t n, int idx);
void ncdc_mainwindow_refresh(ncdc_mainwindow_t n);

View File

@ -6,6 +6,7 @@
#include <stdbool.h>
#include <string.h>
#include <wctype.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/stat.h>

View File

@ -6,6 +6,7 @@ ncdc_commands_t cmds[] = {
{ L"/login", ncdc_cmd_login },
{ L"/logout", ncdc_cmd_logout },
{ L"/msg", ncdc_cmd_msg },
{ L"/post", ncdc_cmd_post },
{ L"/quit", ncdc_cmd_quit },
{ NULL, NULL }
};
@ -17,6 +18,7 @@ static pthread_cond_t cnd;
typedef struct {
ncdc_commands_t *cmd;
wchar_t *f;
size_t ac;
wchar_t **av;
ncdc_mainwindow_t mainwindow;
@ -43,9 +45,12 @@ static void *async_dispatcher(void *arg)
} else {
/* call the handler
*/
item->cmd->handler(item->mainwindow, item->ac, item->av);
item->cmd->handler(item->mainwindow, item->ac,
item->av, item->f
);
w_strfreev(item->av);
free(item->f);
free(item);
}
}
@ -109,6 +114,8 @@ bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s)
wchar_t **tokens = NULL;
ncdc_commands_t *it = NULL;
queue_item *item = NULL;
wchar_t *f = NULL;
size_t len = 0, cmdlen = 0;
tokens = w_tokenise(s);
return_if_true(tokens == NULL, false);
@ -121,12 +128,21 @@ bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s)
return false;
}
/* make a complete string without the /command part
*/
len = wcslen(s);
cmdlen = wcslen(it->name);
f = wcsdup(s);
return_if_true(f == NULL, false);
memmove(f, f+cmdlen, len-cmdlen);
item = calloc(1, sizeof(queue_item));
item->ac = w_strlenv(tokens);
item->av = tokens;
item->cmd = it;
item->mainwindow = n;
item->f = f;
pthread_mutex_lock(&mtx);
g_queue_push_tail(queue, item);
@ -136,7 +152,8 @@ bool ncdc_dispatch(ncdc_mainwindow_t n, wchar_t const *s)
return true;
}
bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
bool ncdc_cmd_quit(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *f)
{
exit_main();
return true;

View File

@ -2,7 +2,8 @@
#include <ncdc/ncdc.h>
static bool
ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *f)
{
size_t i = 0;
char c = ' ';
@ -23,7 +24,8 @@ ncdc_cmd_friends_list(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)
ncdc_cmd_friends_add(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *f)
{
char *name = NULL;
dc_account_t friend = NULL;
@ -60,7 +62,8 @@ cleanup:
}
static bool
ncdc_cmd_friends_remove(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
ncdc_cmd_friends_remove(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *f)
{
char *name = NULL;
dc_account_t friend = NULL;
@ -104,7 +107,8 @@ cleanup:
}
static bool
ncdc_cmd_friends_accept(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
ncdc_cmd_friends_accept(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *f)
{
char *name = NULL;
dc_account_t friend = NULL;
@ -156,7 +160,8 @@ static ncdc_commands_t subcmds[] = {
{ NULL, NULL }
};
bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *f)
{
wchar_t *subcmd = NULL;
ncdc_commands_t *it = NULL;
@ -167,7 +172,7 @@ bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
}
if (ac <= 1) {
return ncdc_cmd_friends_list(n, ac, av);
return ncdc_cmd_friends_list(n, ac, av, f);
}
subcmd = av[1];
@ -180,5 +185,5 @@ bool ncdc_cmd_friends(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
return false;
}
return it->handler(n, ac, av);
return it->handler(n, ac, av, f);
}

View File

@ -2,7 +2,8 @@
#include <ncdc/ncdc.h>
#include <ncdc/config.h>
bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *f)
{
char *arg = NULL;
bool ret = false;

View File

@ -2,7 +2,8 @@
#include <ncdc/ncdc.h>
#include <ncdc/config.h>
bool ncdc_cmd_logout(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
bool ncdc_cmd_logout(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *f)
{
bool ret = false;

View File

@ -110,16 +110,25 @@ ncdc_mainwindow_callback(ncdc_input_t i, wchar_t const *s,
size_t len, void *arg)
{
ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg;
bool ret = false;
if (s != NULL && s[0] == '/') {
if (s[1] == '\0') {
return false;
}
return ncdc_dispatch(mainwin, s);
if (s == NULL || s[0] == '\0') {
return false;
}
return false;
if (s[0] == '/') {
ret = ncdc_dispatch(mainwin, s);
} else {
wchar_t *post = calloc(wcslen(s)+6, sizeof(wchar_t));
wcscat(post, L"/post ");
wcscat(post, s);
ret = ncdc_dispatch(mainwin, post);
free(post);
}
return ret;
}
static void ncdc_mainwindow_resize(ncdc_mainwindow_t n)
@ -331,3 +340,13 @@ void ncdc_mainwindow_leftview(ncdc_mainwindow_t n)
return_if_true(n == NULL,);
n->curview = (n->curview - 1) % n->views->len;
}
dc_channel_t ncdc_mainwindow_current_channel(ncdc_mainwindow_t n)
{
return_if_true(n == NULL, NULL);
ncdc_textview_t view = g_ptr_array_index(n->views, n->curview);
/* can't post to the log channel, that's for internal use only
*/
return_if_true(view == n->log, NULL);
return ncdc_textview_channel(view);
}

View File

@ -2,13 +2,15 @@
#include <ncdc/ncdc.h>
#include <ncdc/textview.h>
bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac,
wchar_t **av, wchar_t const *fullmsg)
{
return_if_true(ac <= 1, false);
char * target = NULL;
wchar_t *full_message = NULL;
char * message = NULL;
dc_message_t m = NULL;
bool ret = false;
dc_channel_t c = NULL;
ncdc_textview_t v = NULL;
@ -64,15 +66,34 @@ bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av)
ncdc_mainwindow_switchview(n, ncdc_mainwindow_views(n)->len-1);
}
if (ac > 2) {
/* also post the rest of the content as a message to the channel
*/
full_message = wcsstr(fullmsg, av[2]);
goto_if_true(full_message == NULL, cleanup);
message = w_convert(full_message);
goto_if_true(message == NULL, cleanup);
m = dc_message_new_content(message, -1);
goto_if_true(m == NULL, cleanup);
ret = dc_api_post_message(
dc_session_api(current_session),
dc_session_me(current_session),
c, m
);
}
ret = true;
cleanup:
dc_unref(c);
dc_unref(v);
dc_unref(m);
free(target);
free(full_message);
free(message);
return ret;

50
ncdc/src/post.c Normal file
View File

@ -0,0 +1,50 @@
#include <ncdc/cmds.h>
#include <ncdc/ncdc.h>
bool ncdc_cmd_post(ncdc_mainwindow_t n, size_t ac, wchar_t **av,
wchar_t const *f)
{
char *str = NULL;
bool ret = false;
dc_message_t m = NULL;
dc_channel_t chan = NULL;
size_t i = 0;
if (!is_logged_in()) {
return false;
}
chan = ncdc_mainwindow_current_channel(n);
goto_if_true(chan == NULL, cleanup);
/* the API only uses multi-byte strings, so convert from wchar_t
*/
str = w_convert(f);
goto_if_true(str == NULL, cleanup);
/* trim string at least on the left
*/
for (i = 0; isspace(str[i]) && str[i] != '\0'; i++)
;
goto_if_true (str[i] == '\0', cleanup);
memmove(str, str+i, strlen(str)+1-i);
m = dc_message_new_content(str, -1);
goto_if_true(m == NULL, cleanup);
ret = dc_api_post_message(
dc_session_api(current_session),
dc_session_me(current_session),
chan, m
);
goto_if_true(ret == false, cleanup);
ret = true;
cleanup:
dc_unref(m);
free(str);
return ret;
}

View File

@ -1,8 +1,8 @@
* Channels [0/4]
* Channels [1/4]
** TODO Automatically open window for 1:1 and 1:N
** TODO send v6/api/channels/$ID/ack for "I read that shit"
** TODO add timestamps from messages
** TODO add message sending
** DONE add message sending
* Guilds [0/3]
** TODO Guild support code
** TODO Guild view on the left pane