diff --git a/libdc/include/dc/account.h b/libdc/include/dc/account.h index dab9024..4c3ddf7 100644 --- a/libdc/include/dc/account.h +++ b/libdc/include/dc/account.h @@ -79,9 +79,9 @@ bool dc_account_equal(dc_account_t a, dc_account_t b); */ void dc_account_set_friends(dc_account_t a, dc_account_t *ptr, size_t len); void dc_account_add_friend(dc_account_t a, dc_account_t friend); -dc_account_t dc_account_nthfriend(dc_account_t a, size_t i); +dc_account_t dc_account_nth_friend(dc_account_t a, size_t i); size_t dc_account_friends_size(dc_account_t a); -dc_account_t dc_account_findfriend(dc_account_t a, char const *fullname); +dc_account_t dc_account_find_friend(dc_account_t a, char const *fullname); int dc_account_friend_state(dc_account_t a); void dc_account_set_friend_state(dc_account_t a, int state); diff --git a/libdc/include/dc/channel.h b/libdc/include/dc/channel.h index 31a229a..9450249 100644 --- a/libdc/include/dc/channel.h +++ b/libdc/include/dc/channel.h @@ -56,11 +56,14 @@ dc_channel_type_t dc_channel_type(dc_channel_t c); void dc_channel_set_type(dc_channel_t c, dc_channel_type_t t); size_t dc_channel_recipients(dc_channel_t c); -void dc_channel_addrecipient(dc_channel_t c, dc_account_t a); -dc_account_t dc_channel_nthrecipient(dc_channel_t c, size_t i); +void dc_channel_add_recipient(dc_channel_t c, dc_account_t a); +dc_account_t dc_channel_nth_recipient(dc_channel_t c, size_t i); +bool dc_channel_has_recipient(dc_channel_t c, dc_account_t a); size_t dc_channel_messages(dc_channel_t c); -dc_message_t dc_channel_nthmessage(dc_channel_t c, size_t i); -void dc_channel_addmessages(dc_channel_t c, dc_message_t *m, size_t s); +dc_message_t dc_channel_nth_message(dc_channel_t c, size_t i); +void dc_channel_add_messages(dc_channel_t c, dc_message_t *m, size_t s); + +bool dc_channel_compare(dc_channel_t a, dc_channel_t b); #endif diff --git a/libdc/include/dc/session.h b/libdc/include/dc/session.h index fd914b3..c175892 100644 --- a/libdc/include/dc/session.h +++ b/libdc/include/dc/session.h @@ -56,12 +56,30 @@ dc_account_t dc_session_me(dc_session_t s); * access to the internal account cache */ void dc_session_add_account(dc_session_t s, dc_account_t u); +dc_account_t dc_session_account_fullname(dc_session_t s, char const *f); /** - * access to the internal channel cache + * Adds a new channel to the internal cache. */ void dc_session_add_channel(dc_session_t s, dc_channel_t u); +/** + * Creates a new channel, or returns an existing channel if a channel with + * these recipients already exists. + * Warning: You must dc_ref() the return object if you need it beyond the + * life-span of the session. + */ +dc_channel_t dc_session_make_channel(dc_session_t s, dc_account_t *r, + size_t n); + +/** + * Finds a channel object by that match the given recipients. + * Warning: You must dc_ref() the return object if you need it beyond the + * life-span of the session. + */ +dc_channel_t dc_session_channel_recipients(dc_session_t s, + dc_account_t *r, size_t sz); + /** * comparision functions for sorting, and finding */ diff --git a/libdc/src/account.c b/libdc/src/account.c index 93da004..90ba296 100644 --- a/libdc/src/account.c +++ b/libdc/src/account.c @@ -331,7 +331,7 @@ void dc_account_set_friends(dc_account_t a, dc_account_t *friends, size_t len) } } -dc_account_t dc_account_findfriend(dc_account_t a, char const *fullname) +dc_account_t dc_account_find_friend(dc_account_t a, char const *fullname) { size_t i = 0; return_if_true(a == NULL || fullname == NULL, NULL); @@ -352,7 +352,7 @@ void dc_account_add_friend(dc_account_t a, dc_account_t friend) g_ptr_array_add(a->friends, dc_ref(friend)); } -dc_account_t dc_account_nthfriend(dc_account_t a, size_t i) +dc_account_t dc_account_nth_friend(dc_account_t a, size_t i) { return_if_true(a == NULL || a->friends == NULL, NULL); return (dc_account_t)g_ptr_array_index(a->friends, i); diff --git a/libdc/src/api-channel.c b/libdc/src/api-channel.c index 5d3957f..f4fbb68 100644 --- a/libdc/src/api-channel.c +++ b/libdc/src/api-channel.c @@ -27,7 +27,7 @@ bool dc_api_get_messages(dc_api_t api, dc_account_t login, dc_channel_t c) g_ptr_array_add(msgs, m); } - dc_channel_addmessages(c, (dc_message_t*)msgs->pdata, msgs->len); + dc_channel_add_messages(c, (dc_message_t*)msgs->pdata, msgs->len); ret = true; cleanup: diff --git a/libdc/src/channel.c b/libdc/src/channel.c index 3a72801..65b8cd6 100644 --- a/libdc/src/channel.c +++ b/libdc/src/channel.c @@ -249,33 +249,42 @@ size_t dc_channel_recipients(dc_channel_t c) return c->recipients->len; } -dc_account_t dc_channel_nthrecipient(dc_channel_t c, size_t i) +dc_account_t dc_channel_nth_recipient(dc_channel_t c, size_t i) { return_if_true(c == NULL || c->recipients == NULL, NULL); return_if_true(i >= c->recipients->len, NULL); return g_ptr_array_index(c->recipients, i); } -void dc_channel_addrecipient(dc_channel_t c, dc_account_t a) +void dc_channel_add_recipient(dc_channel_t c, dc_account_t a) { return_if_true(c == NULL || a == NULL,); g_ptr_array_add(c->recipients, dc_ref(a)); } +bool dc_channel_has_recipient(dc_channel_t c, dc_account_t a) +{ + return_if_true(c == NULL || a == NULL, false); + return g_ptr_array_find_with_equal_func( + c->recipients, a, (GEqualFunc)dc_account_equal, NULL + ); +} + + size_t dc_channel_messages(dc_channel_t c) { return_if_true(c == NULL || c->messages == NULL, 0); return c->messages->len; } -dc_message_t dc_channel_nthmessage(dc_channel_t c, size_t i) +dc_message_t dc_channel_nth_message(dc_channel_t c, size_t i) { return_if_true(c == NULL || c->messages == NULL, NULL); return_if_true(i >= c->messages->len, NULL); return g_ptr_array_index(c->messages, i); } -void dc_channel_addmessages(dc_channel_t c, dc_message_t *m, size_t s) +void dc_channel_add_messages(dc_channel_t c, dc_message_t *m, size_t s) { return_if_true(c == NULL || c->messages == NULL,); return_if_true(m == NULL || s == 0,); @@ -288,3 +297,10 @@ void dc_channel_addmessages(dc_channel_t c, dc_message_t *m, size_t s) g_ptr_array_sort(c->messages, (GCompareFunc)dc_message_compare); } + +bool dc_channel_compare(dc_channel_t a, dc_channel_t b) +{ + return_if_true(a == NULL || b == NULL, false); + return_if_true(a->id == NULL || b->id == NULL, false); + return (strcmp(a->id, b->id) == 0); +} diff --git a/libdc/src/session.c b/libdc/src/session.c index 1d779ad..3456844 100644 --- a/libdc/src/session.c +++ b/libdc/src/session.c @@ -235,6 +235,25 @@ void dc_session_add_account(dc_session_t s, dc_account_t u) } } +dc_account_t dc_session_account_fullname(dc_session_t s, char const *f) +{ + return_if_true(s == NULL || f == NULL, NULL); + GHashTableIter iter; + gpointer key, value; + + /* TODO: hash table with fullname + */ + g_hash_table_iter_init(&iter, s->accounts); + while (g_hash_table_iter_next(&iter, &key, &value)) { + dc_account_t a = (dc_account_t)value; + if (strcmp(dc_account_fullname(a), f) == 0) { + return a; + } + } + + return NULL; +} + void dc_session_add_channel(dc_session_t s, dc_channel_t u) { return_if_true(s == NULL || u == NULL,); @@ -248,3 +267,63 @@ void dc_session_add_channel(dc_session_t s, dc_channel_t u) */ } } + +dc_channel_t dc_session_make_channel(dc_session_t s, dc_account_t *r, + size_t n) +{ + dc_channel_t c = NULL; + + /* check if we have the channel already with those recipients + */ + c = dc_session_channel_recipients(s, r, n); + return_if_true(c != NULL, c); + + /* no? create new one + */ + if (!dc_api_create_channel(s->api, s->login, r, n, &c)) { + return NULL; + } + + return_if_true(c == NULL, NULL); + dc_session_add_channel(s, c); + + /* unref once to match the proper ref count after dc_session_add_channel() + * BUG: if dc_session_add_channel() fails this is bad + */ + dc_unref(c); + + return c; +} + +dc_channel_t dc_session_channel_recipients(dc_session_t s, + dc_account_t *r, size_t sz) +{ + return_if_true(s == NULL || r == NULL || sz == 0, NULL); + + GHashTableIter iter; + gpointer key, value; + size_t i = 0, j = 0; + + g_hash_table_iter_init(&iter, s->channels); + while (g_hash_table_iter_next(&iter, &key, &value)) { + dc_channel_t chan = (dc_channel_t)value; + bool found = true; + + if (dc_channel_recipients(chan) != sz) { + continue; + } + + for (i = 0; i < sz; i++) { + if (!dc_channel_has_recipient(chan, r[j])) { + found = false; + break; + } + } + + if (found) { + return chan; + } + } + + return NULL; +} diff --git a/ncdc/src/friends.c b/ncdc/src/friends.c index a6e25cf..43f7859 100644 --- a/ncdc/src/friends.c +++ b/ncdc/src/friends.c @@ -10,7 +10,7 @@ ncdc_cmd_friends_list(ncdc_mainwindow_t n, size_t ac, wchar_t **av) LOG(n, L"/FRIENDS list"); 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_nth_friend(current_account, i); switch (dc_account_friend_state(acc)) { case FRIEND_STATE_PENDING: c = 'P'; break; default: c = ' '; break; @@ -76,7 +76,7 @@ ncdc_cmd_friends_remove(ncdc_mainwindow_t n, size_t ac, wchar_t **av) return_if_true(name == NULL, false); for (i = 0; i < dc_account_friends_size(current_account); i++) { - dc_account_t cur = dc_account_nthfriend(current_account, i); + dc_account_t cur = dc_account_nth_friend(current_account, i); if (strcmp(dc_account_fullname(cur), name) == 0) { friend = cur; break; @@ -120,7 +120,7 @@ ncdc_cmd_friends_accept(ncdc_mainwindow_t n, size_t ac, wchar_t **av) return_if_true(name == NULL, false); for (i = 0; i < dc_account_friends_size(current_account); i++) { - dc_account_t cur = dc_account_nthfriend(current_account, i); + dc_account_t cur = dc_account_nth_friend(current_account, i); if (strcmp(dc_account_fullname(cur), name) == 0 && dc_account_friend_state(cur) == FRIEND_STATE_PENDING) { friend = cur; diff --git a/ncdc/src/login.c b/ncdc/src/login.c index b3aed99..d61d35c 100644 --- a/ncdc/src/login.c +++ b/ncdc/src/login.c @@ -49,7 +49,7 @@ bool ncdc_cmd_login(ncdc_mainwindow_t n, size_t ac, wchar_t **av) dc_unref(current_session); current_session = dc_ref(s); - LOG(n, L"login: %ls: authentication successful", av[1]); + LOG(n, L"login: %ls: authentication successful, waiting for data...", av[1]); ret = true; cleanup: diff --git a/ncdc/src/msg.c b/ncdc/src/msg.c index 62c0616..8f32b04 100644 --- a/ncdc/src/msg.c +++ b/ncdc/src/msg.c @@ -15,7 +15,7 @@ bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av) dc_account_t current_account = NULL; size_t i = 0; - if (is_logged_in()) { + if (!is_logged_in()) { LOG(n, L"msg: not logged in"); return false; } @@ -27,40 +27,33 @@ bool ncdc_cmd_msg(ncdc_mainwindow_t n, size_t ac, wchar_t **av) /* find out if the target is a friend we can contact */ - dc_account_t f = dc_account_findfriend(current_account, target); + dc_account_t f = dc_session_account_fullname(current_session, target); if (f == NULL) { - LOG(n, L"msg: no such friend found: \"%s\"", target); + LOG(n, L"msg: no such account found: \"%s\"", target); + goto cleanup; + } + + c = dc_session_make_channel(current_session, &f, 1); + if (c == NULL) { + LOG(n, L"msg: failed to create channel for these recipients"); goto cleanup; } /* see if we have a channel already, that services that user + * if so we set v to something non-NIL and it should be good */ for (i = 0; i < ncdc_mainwindow_views(n)->len; i++) { - v = g_ptr_array_index(ncdc_mainwindow_views(n), i); - dc_channel_t chan = ncdc_textview_channel(v); + ncdc_textview_t view = g_ptr_array_index(ncdc_mainwindow_views(n), i); + dc_channel_t chan = ncdc_textview_channel(view); - if (chan != NULL && - dc_channel_type(chan) == CHANNEL_TYPE_DM_TEXT && - dc_account_equal(dc_channel_nthrecipient(chan, 1), f)) { - c = dc_ref(chan); + if (dc_channel_compare(chan, c)) { ncdc_mainwindow_switchview(n, i); + v = view; break; } } - if (c == NULL) { - /* no? create a new window and switch to it - */ - if (!dc_api_create_channel(api, current_account, &f, 1, &c)) { - LOG(n, L"msg: failed to create channel"); - goto cleanup; - } - - if (!dc_api_get_messages(api, current_account, c)) { - LOG(n, L"msg: failed to fetch messages in channel"); - goto cleanup; - } - + if (v == NULL) { v = ncdc_textview_new(); goto_if_true(v == NULL, cleanup); diff --git a/ncdc/src/textview.c b/ncdc/src/textview.c index 72507bd..dcc8476 100644 --- a/ncdc/src/textview.c +++ b/ncdc/src/textview.c @@ -54,7 +54,7 @@ static void ncdc_textview_maketitle(ncdc_textview_t v) size_t rlen = dc_channel_recipients(v->channel); for (i = 0; i < rlen; i++) { - dc_account_t r = dc_channel_nthrecipient(v->channel, i); + dc_account_t r = dc_channel_nth_recipient(v->channel, i); fwprintf(f, L"%s", dc_account_fullname(r)); if (i < (rlen-1)) { fwprintf(f, L","); @@ -201,7 +201,7 @@ ncdc_textview_render_msgs(ncdc_textview_t v, WINDOW *win, int lines, int cols) atline = lines; for (i = msgs-1; i >= 0; i--) { - dc_message_t m = dc_channel_nthmessage(v->channel, i); + dc_message_t m = dc_channel_nth_message(v->channel, i); wchar_t *s = ncdc_textview_format(m); wchar_t const *end = s, *last = NULL; size_t len = 0;