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); 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 * Fetch a list of friends of the login account "login". The friends are stored
* within the login object. * within the login object.

View File

@ -10,6 +10,7 @@ struct dc_message_;
typedef struct dc_message_ *dc_message_t; typedef struct dc_message_ *dc_message_t;
dc_message_t dc_message_new(void); 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); dc_message_t dc_message_from_json(json_t *j);
json_t *dc_message_to_json(dc_message_t m); 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); 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 * access to the internal account cache
*/ */

View File

@ -2,6 +2,36 @@
#include "internal.h" #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 dc_api_get_messages(dc_api_t api, dc_account_t login, dc_channel_t c)
{ {
bool ret = false; bool ret = false;

View File

@ -40,6 +40,24 @@ dc_message_t dc_message_new(void)
return dc_ref(m); 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 dc_message_from_json(json_t *j)
{ {
dc_message_t m = NULL; 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); 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) dc_account_t dc_session_me(dc_session_t s)
{ {
return_if_true(s == NULL, NULL); return_if_true(s == NULL, NULL);

View File

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

View File

@ -4,8 +4,14 @@
#include <ncdc/ncdc.h> #include <ncdc/ncdc.h>
#include <ncdc/mainwindow.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, 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 { typedef struct {
wchar_t const *name; 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); 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_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); 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); 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); bool ncdc_cmd_msg(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); 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 #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, ...); void ncdc_mainwindow_log(ncdc_mainwindow_t w, wchar_t const *fmt, ...);
GPtrArray *ncdc_mainwindow_views(ncdc_mainwindow_t n); 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_switchview(ncdc_mainwindow_t n, int idx);
void ncdc_mainwindow_refresh(ncdc_mainwindow_t n); void ncdc_mainwindow_refresh(ncdc_mainwindow_t n);

View File

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

View File

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

View File

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

View File

@ -2,7 +2,8 @@
#include <ncdc/ncdc.h> #include <ncdc/ncdc.h>
#include <ncdc/config.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; 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) size_t len, void *arg)
{ {
ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg; ncdc_mainwindow_t mainwin = (ncdc_mainwindow_t)arg;
bool ret = false;
if (s != NULL && s[0] == '/') { if (s == NULL || s[0] == '\0') {
if (s[1] == '\0') {
return false; return false;
} }
return ncdc_dispatch(mainwin, s); 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 false; return ret;
} }
static void ncdc_mainwindow_resize(ncdc_mainwindow_t n) 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,); return_if_true(n == NULL,);
n->curview = (n->curview - 1) % n->views->len; 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/ncdc.h>
#include <ncdc/textview.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); return_if_true(ac <= 1, false);
char * target = NULL; char * target = NULL;
wchar_t *full_message = NULL; wchar_t *full_message = NULL;
char * message = NULL; char * message = NULL;
dc_message_t m = NULL;
bool ret = false; bool ret = false;
dc_channel_t c = NULL; dc_channel_t c = NULL;
ncdc_textview_t v = 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); 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; ret = true;
cleanup: cleanup:
dc_unref(c); dc_unref(c);
dc_unref(v); dc_unref(v);
dc_unref(m);
free(target); free(target);
free(full_message);
free(message); free(message);
return ret; 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 Automatically open window for 1:1 and 1:N
** TODO send v6/api/channels/$ID/ack for "I read that shit" ** TODO send v6/api/channels/$ID/ack for "I read that shit"
** TODO add timestamps from messages ** TODO add timestamps from messages
** TODO add message sending ** DONE add message sending
* Guilds [0/3] * Guilds [0/3]
** TODO Guild support code ** TODO Guild support code
** TODO Guild view on the left pane ** TODO Guild view on the left pane