diff --git a/.envrc b/.envrc index d474ea8..f2874d4 100644 --- a/.envrc +++ b/.envrc @@ -50,6 +50,7 @@ use_guix() libstrophe # Dep (strophe) libgcrypt # Dep (gcrypt) libsignal-protocol-c # Dep (libsignal) + lmdb # Dep (lmdb) rnp # Dep (rnpgp) ) @@ -63,5 +64,6 @@ use guix \ --with-debug-info=weechat\ --with-debug-info=libstrophe\ --with-debug-info=libsignal-protocol-c\ + --with-debug-info=lmdb\ --with-debug-info=rnp\ clang:extra gdb diff --git a/Makefile b/Makefile index 60f4fe1..1e89f09 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ FIND=find INCLUDES=-Ilibstrophe $(shell xml2-config --cflags) $(shell pkg-config --cflags librnp-0) $(shell pkg-config --cflags libsignal-protocol-c) CFLAGS+=$(DBGCFLAGS) -fno-omit-frame-pointer -fPIC -std=gnu99 -gdwarf-4 -Wall -Wextra -Werror-implicit-function-declaration -Wno-missing-field-initializers -D_XOPEN_SOURCE=700 $(INCLUDES) LDFLAGS+=$(DBGLDFLAGS) -shared -g $(DBGCFLAGS) -LDLIBS=-lstrophe -lpthread $(shell xml2-config --libs) $(shell pkg-config --libs librnp-0) $(shell pkg-config --libs libsignal-protocol-c) -lgcrypt +LDLIBS=-lstrophe -lpthread $(shell xml2-config --libs) $(shell pkg-config --libs librnp-0) $(shell pkg-config --libs libsignal-protocol-c) -lgcrypt -llmdb PREFIX ?= /usr/local LIBDIR ?= $(PREFIX)/lib diff --git a/README.org b/README.org index 1a2959e..d4815c5 100644 --- a/README.org +++ b/README.org @@ -116,14 +116,16 @@ * [X] [#B] Leaves * [X] [#B] Tracking * [X] [#B] Set/show topic - * [-] OMEMO (libsignal-protocol-c / axc) + * [-] OMEMO (libsignal-protocol-c) * [-] Presence * [X] Disco * [X] Disco response - * [-] Key Generation / storage (secured_data?) + * [-] Key Generation / storage (lmdb) * [X] Generation - * [X] Storage - * [ ] Announce + * [?] Storage + * [-] Announce + * [X] Device ID + * [ ] Bundles * [ ] Messages * [ ] [#C] MUC PMs * [X] [#A] Send typing notifications diff --git a/account.c b/account.c index 3e4a213..ab4464c 100644 --- a/account.c +++ b/account.c @@ -507,7 +507,7 @@ void account__disconnect(struct t_account *account, int reconnect) account__set_lag(account); */ // lag based on xmpp ping - account->disconnected = 1; + account->disconnected = !reconnect; /* send signal "account_disconnected" with account name */ (void) weechat_hook_signal_send("xmpp_account_disconnected", @@ -572,8 +572,6 @@ void account__close_connection(struct t_account *account) int account__connect(struct t_account *account) { - account->disconnected = 0; - if (!account->buffer) { if (!account__create_buffer(account)) @@ -587,7 +585,7 @@ int account__connect(struct t_account *account) connection__connect(account, &account->connection, account_jid(account), account_password(account), account_tls(account)); - (void) weechat_hook_signal_send("xmpp_account_connected", + (void) weechat_hook_signal_send("xmpp_account_connecting", WEECHAT_HOOK_SIGNAL_STRING, account->name); return account->is_connected; @@ -608,6 +606,7 @@ int account__timer_cb(const void *pointer, void *data, int remaining_calls) && (xmpp_conn_is_connecting(ptr_account->connection) || xmpp_conn_is_connected(ptr_account->connection))) connection__process(ptr_account->context, ptr_account->connection, 10); + else if (ptr_account->disconnected); else if (ptr_account->reconnect_start > 0 && ptr_account->reconnect_start < time(NULL)) { diff --git a/buffer.c b/buffer.c index 25fa3f6..3d5ed3e 100644 --- a/buffer.c +++ b/buffer.c @@ -155,7 +155,7 @@ int buffer__close_cb(const void *pointer, void *data, { if (ptr_account) { - if (!ptr_account->disconnected) + if (ptr_account->is_connected) { account__disconnect(ptr_account, 0); } @@ -167,7 +167,7 @@ int buffer__close_cb(const void *pointer, void *data, { if (ptr_account && ptr_channel) { - if (!ptr_account->disconnected) + if (ptr_account->is_connected) { channel__free(ptr_account, ptr_channel); } @@ -177,7 +177,7 @@ int buffer__close_cb(const void *pointer, void *data, { if (ptr_account && ptr_channel) { - if (!ptr_account->disconnected) + if (ptr_account->is_connected) { channel__free(ptr_account, ptr_channel); } diff --git a/channel.c b/channel.c index 4932079..a60b21f 100644 --- a/channel.c +++ b/channel.c @@ -211,12 +211,28 @@ void channel__add_nicklist_groups(struct t_account *account, ptr_buffer = channel ? channel->buffer : account->buffer; - snprintf(str_group, sizeof(str_group), "%03d|%s", - 000, "+"); + snprintf(str_group, sizeof(str_group), "%03d|%s", 000, "~"); weechat_nicklist_add_group(ptr_buffer, NULL, str_group, "weechat.color.nicklist_group", 1); - snprintf(str_group, sizeof(str_group), "%03d|%s", - 999, "..."); + snprintf(str_group, sizeof(str_group), "%03d|%s", 001, "&"); + weechat_nicklist_add_group(ptr_buffer, NULL, str_group, + "weechat.color.nicklist_group", 1); + snprintf(str_group, sizeof(str_group), "%03d|%s", 002, "@"); + weechat_nicklist_add_group(ptr_buffer, NULL, str_group, + "weechat.color.nicklist_group", 1); + snprintf(str_group, sizeof(str_group), "%03d|%s", 003, "%"); + weechat_nicklist_add_group(ptr_buffer, NULL, str_group, + "weechat.color.nicklist_group", 1); + snprintf(str_group, sizeof(str_group), "%03d|%s", 004, "+"); + weechat_nicklist_add_group(ptr_buffer, NULL, str_group, + "weechat.color.nicklist_group", 1); + snprintf(str_group, sizeof(str_group), "%03d|%s", 005, "?"); + weechat_nicklist_add_group(ptr_buffer, NULL, str_group, + "weechat.color.nicklist_group", 1); + snprintf(str_group, sizeof(str_group), "%03d|%s", 006, "!"); + weechat_nicklist_add_group(ptr_buffer, NULL, str_group, + "weechat.color.nicklist_group", 1); + snprintf(str_group, sizeof(str_group), "%03d|%s", 999, "..."); weechat_nicklist_add_group(ptr_buffer, NULL, str_group, "weechat.color.nicklist_group", 1); } @@ -290,6 +306,8 @@ struct t_channel *channel__new(struct t_account *account, account->channels = new_channel; account->last_channel = new_channel; + channel__add_nicklist_groups(account, new_channel); + if (type != CHANNEL_TYPE_MUC) { time_t start = time(NULL); @@ -818,15 +836,14 @@ void channel__update_topic(struct t_channel *channel, struct t_channel_member *channel__add_member(struct t_account *account, struct t_channel *channel, - const char *id, const char *client, - const char *status) + const char *id, const char *client) { struct t_channel_member *member; struct t_user *user; user = user__search(account, id); - if (weechat_strcasecmp(user->id, channel->id) == 0 + if (user && weechat_strcasecmp(user->id, channel->id) == 0 && channel->type == CHANNEL_TYPE_MUC) { weechat_printf_date_tags(channel->buffer, 0, "log2", "%sMUC: %s", @@ -835,19 +852,24 @@ struct t_channel_member *channel__add_member(struct t_account *account, return NULL; } - member = malloc(sizeof(struct t_channel_member)); - member->id = strdup(id); + if (!(member = channel__member_search(channel, id))) + { + member = malloc(sizeof(struct t_channel_member)); + member->id = strdup(id); - member->role = NULL; - member->affiliation = NULL; + member->role = NULL; + member->affiliation = NULL; - member->prev_member = channel->last_member; - member->next_member = NULL; - if (channel->last_member) - (channel->last_member)->next_member = member; - else - channel->members = member; - channel->last_member = member; + member->prev_member = channel->last_member; + member->next_member = NULL; + if (channel->last_member) + (channel->last_member)->next_member = member; + else + channel->members = member; + channel->last_member = member; + } + else if (user) + user__nicklist_remove(account, channel, user); if (user) user__nicklist_add(account, channel, user); @@ -856,28 +878,45 @@ struct t_channel_member *channel__add_member(struct t_account *account, char *jid_resource = xmpp_jid_resource(account->context, user->id); if (weechat_strcasecmp(jid_bare, channel->id) == 0 && channel->type == CHANNEL_TYPE_MUC) - weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,enter,log4", "%s%s %s%s%s %sentered%s %s %s%s%s", + weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,enter,log4", "%s%s%s%s%s %s%s%s%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s", weechat_prefix("join"), user__as_prefix_raw(account, jid_resource), - client ? "(" : "", client, client ? ")" : "", + client ? " (" : "", + client ? client : "", + client ? ")" : "", + user->profile.status ? "is " : "", weechat_color("irc.color.message_join"), + user->profile.status ? user->profile.status : "entered", weechat_color("reset"), channel->id, - status ? "[" : "", - status ? status : "", - status ? "]" : ""); + user->profile.status_text ? " [" : "", + user->profile.status_text ? user->profile.status_text : "", + user->profile.status_text ? "]" : "", + weechat_color("yellow"), " as ", weechat_color("reset"), + user->profile.affiliation ? user->profile.affiliation : "", + user->profile.affiliation ? " " : "", + user->profile.role, + user->profile.pgp_id ? weechat_color("gray") : "", + user->profile.pgp_id ? " with PGP:" : "", + user->profile.pgp_id ? user->profile.pgp_id : "", + user->profile.pgp_id ? weechat_color("reset") : ""); else - weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,enter,log4", "%s%s (%s) %sentered%s %s %s%s%s", + weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,enter,log4", "%s%s (%s) %s%s%s%s %s%s%s%s%s%s%s%s", weechat_prefix("join"), - user__as_prefix_raw(account, - xmpp_jid_bare(account->context, user->id)), - xmpp_jid_resource(account->context, user->id), + jid_resource ? user__as_prefix_raw(account, jid_bare) : "You", + jid_resource ? jid_resource : user__as_prefix_raw(account, jid_bare), + user->profile.status ? "is " : "", weechat_color("irc.color.message_join"), + user->profile.status ? user->profile.status : "entered", weechat_color("reset"), channel->id, - status ? "[" : "", - status ? status : "", - status ? "]" : ""); + user->profile.status_text ? " [" : "", + user->profile.status_text ? user->profile.status_text : "", + user->profile.status_text ? "]" : "", + user->profile.pgp_id ? weechat_color("gray") : "", + user->profile.pgp_id ? " with PGP:" : "", + user->profile.pgp_id ? user->profile.pgp_id : "", + user->profile.pgp_id ? weechat_color("reset") : ""); return member; } @@ -900,56 +939,16 @@ struct t_channel_member *channel__member_search(struct t_channel *channel, return NULL; } -int channel__set_member_role(struct t_account *account, - struct t_channel *channel, - const char *id, const char *role) -{ - struct t_channel_member *member; - struct t_user *user; - - user = user__search(account, id); - if (!user) - return 0; - - member = channel__member_search(channel, id); - if (!member) - return 0; - - member->role = strdup(role); - - return 1; -} - -int channel__set_member_affiliation(struct t_account *account, - struct t_channel *channel, - const char *id, const char *affiliation) -{ - struct t_channel_member *member; - struct t_user *user; - - user = user__search(account, id); - if (!user) - return 0; - - member = channel__member_search(channel, id); - if (!member) - return 0; - - member->affiliation = strdup(affiliation); - - return 1; -} - struct t_channel_member *channel__remove_member(struct t_account *account, struct t_channel *channel, - const char *id, const char *status) + const char *id, const char *reason) { struct t_channel_member *member; struct t_user *user; user = user__search(account, id); - //if (user) - // user__nicklist_remove(account, channel, user); + if (user) + user__nicklist_remove(account, channel, user); member = channel__member_search(channel, id); if (member) @@ -965,9 +964,9 @@ struct t_channel_member *channel__remove_member(struct t_account *account, weechat_color("irc.color.message_quit"), weechat_color("reset"), channel->id, - status ? "[" : "", - status ? status : "", - status ? "]" : ""); + reason ? "[" : "", + reason ? reason : "", + reason ? "]" : ""); else weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,leave,log4", "%s%s (%s) %sleft%s %s %s%s%s", weechat_prefix("quit"), @@ -976,9 +975,9 @@ struct t_channel_member *channel__remove_member(struct t_account *account, weechat_color("irc.color.message_quit"), weechat_color("reset"), channel->id, - status ? "[" : "", - status ? status : "", - status ? "]" : ""); + reason ? "[" : "", + reason ? reason : "", + reason ? "]" : ""); return member; } diff --git a/channel.h b/channel.h index 52d799d..c336ee2 100644 --- a/channel.h +++ b/channel.h @@ -170,20 +170,14 @@ void channel__update_purpose(struct t_channel *channel, struct t_channel_member *channel__add_member(struct t_account *account, struct t_channel *channel, - const char *id, const char *client, - const char *status); + const char *id, const char *client); -int channel__set_member_role(struct t_account *account, - struct t_channel *channel, - const char *id, const char *role); - -int channel__set_member_affiliation(struct t_account *account, - struct t_channel *channel, - const char *id, const char *affiliation); +struct t_channel_member *channel__member_search(struct t_channel *channel, + const char *id); struct t_channel_member *channel__remove_member(struct t_account *account, struct t_channel *channel, - const char *id, const char *status); + const char *id, const char *reason); void channel__send_message(struct t_account *account, struct t_channel *channel, const char *to, const char *body); diff --git a/command.c b/command.c index 2b60858..84c90ed 100644 --- a/command.c +++ b/command.c @@ -6,11 +6,11 @@ #include #include #include +#include #include #include "plugin.h" //#include "oauth.h" -//#include "teaminfo.h" #include "account.h" #include "user.h" #include "channel.h" @@ -18,6 +18,9 @@ #include "message.h" #include "command.h" +#define MAM_DEFAULT_DAYS 2 +#define STR(X) #X + void command__display_account(struct t_account *account) { int num_channels, num_pv; @@ -147,7 +150,7 @@ void command__add_account(const char *name, const char *jid, const char *passwor account_option_set(account, ACCOUNT_OPTION_NICKNAME, strdup(xmpp_jid_node(account->context, jid))); - weechat_printf ( + weechat_printf( NULL, _("%s: account %s%s%s %s(%s%s%s)%s added"), WEECHAT_XMPP_PLUGIN_NAME, @@ -161,10 +164,12 @@ void command__add_account(const char *name, const char *jid, const char *passwor weechat_color("reset")); } -void command__account_add(int argc, char **argv) +void command__account_add(struct t_gui_buffer *buffer, int argc, char **argv) { char *name, *jid = NULL, *password = NULL; + (void) buffer; + switch (argc) { case 5: @@ -202,11 +207,12 @@ int command__connect_account(struct t_account *account) return 1; } -int command__account_connect(int argc, char **argv) +int command__account_connect(struct t_gui_buffer *buffer, int argc, char **argv) { int i, nb_connect, connect_ok; struct t_account *ptr_account; + (void) buffer; (void) argc; (void) argv; @@ -257,7 +263,7 @@ int command__disconnect_account(struct t_account *account) return 1; } -int command__account_disconnect(int argc, char **argv) +int command__account_disconnect(struct t_gui_buffer *buffer, int argc, char **argv) { int i, nb_disconnect, disconnect_ok; struct t_account *ptr_account; @@ -268,6 +274,20 @@ int command__account_disconnect(int argc, char **argv) disconnect_ok = 1; nb_disconnect = 0; + if (argc < 2) + { + struct t_channel *ptr_channel; + + buffer__get_account_and_channel(buffer, &ptr_account, &ptr_channel); + + if (ptr_account) + { + if (!command__disconnect_account(ptr_account)) + { + disconnect_ok = 0; + } + } + } for (i = 2; i < argc; i++) { nb_disconnect++; @@ -292,14 +312,16 @@ int command__account_disconnect(int argc, char **argv) return (disconnect_ok) ? WEECHAT_RC_OK : WEECHAT_RC_ERROR; } -int command__account_reconnect(int argc, char **argv) +int command__account_reconnect(struct t_gui_buffer *buffer, int argc, char **argv) { - command__account_disconnect(argc, argv); - return command__account_connect(argc, argv); + command__account_disconnect(buffer, argc, argv); + return command__account_connect(buffer, argc, argv); } -void command__account_delete(int argc, char **argv) +void command__account_delete(struct t_gui_buffer *buffer, int argc, char **argv) { + (void) buffer; + struct t_account *account; char *account_name; @@ -337,7 +359,7 @@ void command__account_delete(int argc, char **argv) account_name = strdup(account->name); account__free(account); - weechat_printf ( + weechat_printf( NULL, _("%s: account %s%s%s has been deleted"), WEECHAT_XMPP_PLUGIN_NAME, @@ -349,8 +371,8 @@ void command__account_delete(int argc, char **argv) } int command__account(const void *pointer, void *data, - struct t_gui_buffer *buffer, int argc, - char **argv, char **argv_eol) + struct t_gui_buffer *buffer, int argc, + char **argv, char **argv_eol) { (void) pointer; @@ -367,31 +389,31 @@ int command__account(const void *pointer, void *data, { if (weechat_strcasecmp(argv[1], "add") == 0) { - command__account_add(argc, argv); + command__account_add(buffer, argc, argv); return WEECHAT_RC_OK; } if (weechat_strcasecmp(argv[1], "connect") == 0) { - command__account_connect(argc, argv); + command__account_connect(buffer, argc, argv); return WEECHAT_RC_OK; } if (weechat_strcasecmp(argv[1], "disconnect") == 0) { - command__account_disconnect(argc, argv); + command__account_disconnect(buffer, argc, argv); return WEECHAT_RC_OK; } if (weechat_strcasecmp(argv[1], "reconnect") == 0) { - command__account_reconnect(argc, argv); + command__account_reconnect(buffer, argc, argv); return WEECHAT_RC_OK; } if (weechat_strcasecmp(argv[1], "delete") == 0) { - command__account_delete(argc, argv); + command__account_delete(buffer, argc, argv); return WEECHAT_RC_OK; } @@ -478,6 +500,33 @@ int command__enter(const void *pointer, void *data, } weechat_string_free_split(jids); } + else + { + const char *buffer_jid = weechat_buffer_get_string(buffer, "localvar_channel"); + + pres_jid = xmpp_jid_new( + ptr_account->context, + xmpp_jid_node(ptr_account->context, buffer_jid), + xmpp_jid_domain(ptr_account->context, buffer_jid), + weechat_buffer_get_string(buffer, "localvar_nick")); + + ptr_channel = channel__search(ptr_account, buffer_jid); + if (!ptr_channel) + ptr_channel = channel__new(ptr_account, CHANNEL_TYPE_MUC, buffer_jid, buffer_jid); + + pres = xmpp_presence_new(ptr_account->context); + xmpp_stanza_set_to(pres, pres_jid); + xmpp_stanza_set_from(pres, account_jid(ptr_account)); + + xmpp_stanza_t *pres__x = xmpp_stanza_new(ptr_account->context); + xmpp_stanza_set_name(pres__x, "x"); + xmpp_stanza_set_ns(pres__x, "http://jabber.org/protocol/muc"); + xmpp_stanza_add_child(pres, pres__x); + xmpp_stanza_release(pres__x); + + xmpp_send(ptr_account->connection, pres); + xmpp_stanza_release(pres); + } return WEECHAT_RC_OK; } @@ -564,7 +613,7 @@ int command__msg(const void *pointer, void *data, if (!ptr_channel) { - weechat_printf ( + weechat_printf( ptr_account->buffer, _("%s%s: \"%s\" command can not be executed on a account buffer"), weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, "msg"); @@ -619,7 +668,7 @@ int command__me(const void *pointer, void *data, if (!ptr_channel) { - weechat_printf ( + weechat_printf( ptr_account->buffer, _("%s%s: \"%s\" command can not be executed on a account buffer"), weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, "me"); @@ -656,6 +705,58 @@ int command__me(const void *pointer, void *data, return WEECHAT_RC_OK; } +int command__mam(const void *pointer, void *data, + struct t_gui_buffer *buffer, int argc, + char **argv, char **argv_eol) +{ + struct t_account *ptr_account = NULL; + struct t_channel *ptr_channel = NULL; + int days; + + (void) pointer; + (void) data; + (void) argv_eol; + + buffer__get_account_and_channel(buffer, &ptr_account, &ptr_channel); + + if (!ptr_account) + return WEECHAT_RC_ERROR; + + if (!ptr_channel) + { + weechat_printf( + ptr_account->buffer, + _("%s%s: \"%s\" command can not be executed on a account buffer"), + weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, "mam"); + return WEECHAT_RC_OK; + } + + time_t start = time(NULL); + struct tm *ago = gmtime(&start); + if (argc > 1) + { + errno = 0; + days = strtol(argv[1], NULL, 10); + + if (errno == 0) + ago->tm_mday -= days; + else + { + weechat_printf( + ptr_channel->buffer, + _("%s%s: \"%s\" is not a valid number of %s for %s"), + weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, "days", "mam"); + ago->tm_mday -= MAM_DEFAULT_DAYS; + } + } + else + ago->tm_mday -= MAM_DEFAULT_DAYS; + start = mktime(ago); + channel__fetch_mam(ptr_account, ptr_channel, &start, NULL); + + return WEECHAT_RC_OK; +} + int command__pgp(const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) @@ -675,10 +776,10 @@ int command__pgp(const void *pointer, void *data, if (!ptr_channel) { - weechat_printf ( + weechat_printf( ptr_account->buffer, _("%s%s: \"%s\" command can not be executed on a account buffer"), - weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, "me"); + weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, "pgp"); return WEECHAT_RC_OK; } @@ -797,6 +898,15 @@ void command__init() if (!hook) weechat_printf(NULL, "Failed to setup command /me"); + hook = weechat_hook_command( + "mam", + N_("retrieve mam messages for the current channel"), + N_("[days]"), + N_("days: number of days to fetch (default: " STR(MAM_DEFAULT_DAYS) ")"), + NULL, &command__mam, NULL, NULL); + if (!hook) + weechat_printf(NULL, "Failed to setup command /mam"); + hook = weechat_hook_command( "pgp", N_("set the target pgp key for the current channel"), diff --git a/connection.c b/connection.c index 4125951..afb0683 100644 --- a/connection.c +++ b/connection.c @@ -86,9 +86,9 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void struct t_account *account = (struct t_account *)userdata; struct t_user *user; struct t_channel *channel; - xmpp_stanza_t *iq__x_signed, *iq__x_muc_user, *iq__x__item, *iq__c, *iq__status; + xmpp_stanza_t *iq__x_signed, *iq__x_muc_user, *show, *iq__x__item, *iq__c, *iq__status; const char *from, *from_bare, *from_res, *type, *role = NULL, *affiliation = NULL, *jid = NULL; - const char *certificate = NULL, *node = NULL, *ver = NULL; + const char *show__text = NULL, *certificate = NULL, *node = NULL, *ver = NULL; char *clientid = NULL, *status; from = xmpp_stanza_get_from(stanza); @@ -97,30 +97,21 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void from_bare = xmpp_jid_bare(account->context, from); from_res = xmpp_jid_resource(account->context, from); type = xmpp_stanza_get_type(stanza); + show = xmpp_stanza_get_child_by_name(stanza, "show"); + show__text = show ? xmpp_stanza_get_text(show) : NULL; iq__x_signed = xmpp_stanza_get_child_by_name_and_ns( stanza, "x", "jabber:x:signed"); if (iq__x_signed) { certificate = xmpp_stanza_get_text(iq__x_signed); } - iq__x_muc_user = xmpp_stanza_get_child_by_name_and_ns( - stanza, "x", "http://jabber.org/protocol/muc#user"); - if (iq__x_muc_user) - { - iq__x__item = xmpp_stanza_get_child_by_name(iq__x_muc_user, "item"); - role = xmpp_stanza_get_attribute(iq__x__item, "role"); - affiliation = xmpp_stanza_get_attribute(iq__x__item, "affiliation"); - jid = xmpp_stanza_get_attribute(iq__x__item, "jid"); - } iq__c = xmpp_stanza_get_child_by_name_and_ns( stanza, "c", "http://jabber.org/protocol/caps"); if (iq__c) { node = xmpp_stanza_get_attribute(iq__c, "node"); ver = xmpp_stanza_get_attribute(iq__c, "ver"); - if (jid) - clientid = strdup(jid); - else if (node && ver) + if (node && ver) { int len = strlen(node)+1+strlen(ver); clientid = malloc(sizeof(char)*len); @@ -129,36 +120,76 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void } iq__status = xmpp_stanza_get_child_by_name(stanza, "status"); status = iq__status ? xmpp_stanza_get_text(iq__status) : NULL; + iq__x_muc_user = xmpp_stanza_get_child_by_name_and_ns( + stanza, "x", "http://jabber.org/protocol/muc#user"); channel = channel__search(account, from_bare); if (weechat_strcasecmp(type, "unavailable") && !iq__x_muc_user && !channel) channel = channel__new(account, CHANNEL_TYPE_PM, from_bare, from_bare); - if (certificate && channel) + + if (iq__x_muc_user) + for (iq__x__item = xmpp_stanza_get_children(iq__x_muc_user); + iq__x__item; iq__x__item = xmpp_stanza_get_next(iq__x__item)) { - if (channel->type != CHANNEL_TYPE_MUC) - channel->pgp_id = pgp__verify(channel->buffer, account->pgp, certificate); - weechat_printf(channel->buffer, "[PGP]\t%sKey %s from %s", - weechat_color("gray"), channel->pgp_id, from); - } + if (weechat_strcasecmp(xmpp_stanza_get_name(iq__x__item), "item") != 0) + continue; - user = user__search(account, from); - if (!user) - user = user__new(account, from, - channel && weechat_strcasecmp(from_bare, channel->id) == 0 - ? from_res : from); + role = xmpp_stanza_get_attribute(iq__x__item, "role"); + affiliation = xmpp_stanza_get_attribute(iq__x__item, "affiliation"); + jid = xmpp_stanza_get_attribute(iq__x__item, "jid"); - if (!iq__x_muc_user && channel) - { - channel__add_member(account, channel, from, clientid, status); + user = user__search(account, from); + if (!user) + user = user__new(account, from, + channel && weechat_strcasecmp(from_bare, channel->id) == 0 + ? from_res : from); + user->profile.status_text = status ? strdup(status) : NULL; + user->profile.status = show ? strdup(show__text) : NULL; + user->is_away = show ? weechat_strcasecmp(show__text, "away") == 0 : 0; + user->profile.role = role ? strdup(role) : NULL; + user->profile.affiliation = affiliation && strcmp(affiliation, "none") != 0 + ? strdup(affiliation) : NULL; + if (certificate && channel) + { + user->profile.pgp_id = pgp__verify(channel->buffer, account->pgp, certificate); + if (channel->type != CHANNEL_TYPE_MUC) + channel->pgp_id = user->profile.pgp_id; + } + + if (channel) + { + if (weechat_strcasecmp(role, "none") == 0) + channel__remove_member(account, channel, from, status); + else + channel__add_member(account, channel, from, jid ? jid : clientid); + } } - else if (channel) + else { - channel__set_member_role(account, channel, from, role); - channel__set_member_affiliation(account, channel, from, affiliation); - if (weechat_strcasecmp(role, "none") == 0) - channel__remove_member(account, channel, from, status); - else - channel__add_member(account, channel, from, clientid, status); + user = user__search(account, from); + if (!user) + user = user__new(account, from, + channel && weechat_strcasecmp(from_bare, channel->id) == 0 + ? from_res : from); + user->profile.status_text = status ? strdup(status) : NULL; + user->profile.status = show ? strdup(show__text) : NULL; + user->profile.role = role ? strdup(role) : NULL; + user->profile.affiliation = affiliation && strcmp(affiliation, "none") != 0 + ? strdup(affiliation) : NULL; + if (certificate && channel) + { + user->profile.pgp_id = pgp__verify(channel->buffer, account->pgp, certificate); + if (channel->type != CHANNEL_TYPE_MUC) + channel->pgp_id = user->profile.pgp_id; + } + + if (channel) + { + if (weechat_strcasecmp(type, "unavailable") == 0) + channel__remove_member(account, channel, from, status); + else + channel__add_member(account, channel, from, clientid); + } } if (clientid) @@ -219,8 +250,7 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void * channel__add_typing(channel, user); weechat_printf(channel->buffer, "...\t%s%s typing", weechat_color("gray"), - weechat_strcasecmp(from_bare, channel->id) == 0 - ? nick : from); + channel->type == CHANNEL_TYPE_MUC ? nick : from); } sent = xmpp_stanza_get_child_by_name_and_ns( @@ -819,19 +849,21 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd { list = xmpp_stanza_get_child_by_name_and_ns( item, "list", "eu.siacs.conversations.axolotl"); - if (list) + if (list && account->omemo) { account__free_device_all(account); - struct t_account_device *dev = malloc(sizeof(struct t_account_device)); + struct t_account_device *dev; char id[64] = {0}; + int i = 0; + + dev = malloc(sizeof(struct t_account_device)); dev->id = account->omemo->device_id; snprintf(id, sizeof(id), "%d", dev->id); dev->name = strdup(id); account__add_device(account, dev); - int i = 0; children = malloc(sizeof(xmpp_stanza_t *) * 128); children[i++] = stanza__iq_pubsub_publish_item_list_device( account->context, NULL, with_noop(dev->name)); @@ -1005,6 +1037,8 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status, if (status == XMPP_CONN_CONNECT) { + account->disconnected = 0; + xmpp_stanza_t *pres, *pres__c, *pres__status, *pres__status__text, *pres__x, *pres__x__text, **children; char cap_hash[28+1] = {0}; @@ -1113,45 +1147,10 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status, xmpp_send(conn, children[0]); xmpp_stanza_release(children[0]); - struct t_hashtable *variables = weechat_hashtable_new (8, - WEECHAT_HASHTABLE_STRING, - WEECHAT_HASHTABLE_STRING, - NULL, NULL); - weechat_hashtable_set(variables, "account", account->name); - char *device_r = weechat_string_eval_expression( - "${sec.data.xmpp_device_${account}}", - NULL, variables, NULL); - char *device_w = device_r; - char *account_r = weechat_string_eval_expression( - "${sec.data.xmpp_identity_${account}}", - NULL, variables, NULL); - char *account_w = account_r; - weechat_hashtable_free(variables); - - omemo__init(account->buffer, &account->omemo, &device_w, &account_w); - - if (weechat_strcasecmp(device_w, device_r) != 0) - { - char **command = weechat_string_dyn_alloc(256); - weechat_string_dyn_concat(command, "/secure set ", -1); - weechat_string_dyn_concat(command, "xmpp_device_", -1); - weechat_string_dyn_concat(command, account->name, -1); - weechat_string_dyn_concat(command, " ", -1); - weechat_string_dyn_concat(command, device_w, -1); - weechat_command(account->buffer, *command); - weechat_string_dyn_free(command, 1); - } - if (weechat_strcasecmp(account_w, account_r) != 0) - { - char **command = weechat_string_dyn_alloc(256); - weechat_string_dyn_concat(command, "/secure set ", -1); - weechat_string_dyn_concat(command, "xmpp_identity_", -1); - weechat_string_dyn_concat(command, account->name, -1); - weechat_string_dyn_concat(command, " ", -1); - weechat_string_dyn_concat(command, account_w, -1); - weechat_command(account->buffer, *command); - weechat_string_dyn_free(command, 1); - } + omemo__init(account->buffer, &account->omemo, account->name); + + (void) weechat_hook_signal_send("xmpp_account_connected", + WEECHAT_HOOK_SIGNAL_STRING, account->name); } else { diff --git a/omemo.c b/omemo.c index 17983b7..63134cc 100644 --- a/omemo.c +++ b/omemo.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -90,19 +91,19 @@ signal_protocol_address* signal_protocol_address_new(const char* name, int32_t d return address; } -int signal_randomize(uint8_t *data, size_t len) { +int cp_randomize(uint8_t *data, size_t len) { gcry_randomize(data, len, GCRY_STRONG_RANDOM); return SG_SUCCESS; } -int signal_random_generator(uint8_t *data, size_t len, void *user_data) { +int cp_random_generator(uint8_t *data, size_t len, void *user_data) { (void) user_data; gcry_randomize(data, len, GCRY_STRONG_RANDOM); return SG_SUCCESS; } -int signal_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data) { +int cp_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_len, void *user_data) { (void) user_data; gcry_mac_hd_t* ctx = malloc(sizeof(gcry_mac_hd_t)); @@ -123,7 +124,7 @@ int signal_hmac_sha256_init(void **hmac_context, const uint8_t *key, size_t key_ return SG_SUCCESS; } -int signal_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data) { +int cp_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t data_len, void *user_data) { (void) user_data; gcry_mac_hd_t* ctx = hmac_context; @@ -133,7 +134,7 @@ int signal_hmac_sha256_update(void *hmac_context, const uint8_t *data, size_t da return SG_SUCCESS; } -int signal_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data) { +int cp_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *user_data) { (void) user_data; size_t len = gcry_mac_get_algo_maclen(GCRY_MAC_HMAC_SHA256); @@ -150,7 +151,7 @@ int signal_hmac_sha256_final(void *hmac_context, signal_buffer **output, void *u return SG_SUCCESS; } -void signal_hmac_sha256_cleanup(void *hmac_context, void *user_data) { +void cp_hmac_sha256_cleanup(void *hmac_context, void *user_data) { (void) user_data; gcry_mac_hd_t* ctx = hmac_context; @@ -160,7 +161,7 @@ void signal_hmac_sha256_cleanup(void *hmac_context, void *user_data) { } } -int signal_sha512_digest_init(void **digest_context, void *user_data) { +int cp_sha512_digest_init(void **digest_context, void *user_data) { (void) user_data; gcry_md_hd_t* ctx = malloc(sizeof(gcry_mac_hd_t)); @@ -176,7 +177,7 @@ int signal_sha512_digest_init(void **digest_context, void *user_data) { return SG_SUCCESS; } -int signal_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data) { +int cp_sha512_digest_update(void *digest_context, const uint8_t *data, size_t data_len, void *user_data) { (void) user_data; gcry_md_hd_t* ctx = digest_context; @@ -186,7 +187,7 @@ int signal_sha512_digest_update(void *digest_context, const uint8_t *data, size_ return SG_SUCCESS; } -int signal_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data) { +int cp_sha512_digest_final(void *digest_context, signal_buffer **output, void *user_data) { (void) user_data; size_t len = gcry_md_get_algo_dlen(GCRY_MD_SHA512); @@ -206,7 +207,7 @@ int signal_sha512_digest_final(void *digest_context, signal_buffer **output, voi return SG_SUCCESS; } -void signal_sha512_digest_cleanup(void *digest_context, void *user_data) { +void cp_sha512_digest_cleanup(void *digest_context, void *user_data) { (void) user_data; gcry_md_hd_t* ctx = digest_context; @@ -243,7 +244,7 @@ int aes_cipher(int cipher, size_t key_len, int* algo, int* mode) { return SG_SUCCESS; } -int signal_encrypt(signal_buffer **output, +int cp_encrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, @@ -320,7 +321,7 @@ no_error: return SG_SUCCESS; } -int signal_decrypt(signal_buffer **output, +int cp_decrypt(signal_buffer **output, int cipher, const uint8_t *key, size_t key_len, const uint8_t *iv, size_t iv_len, @@ -415,63 +416,131 @@ void omemo__log_emit_weechat(int level, const char *message, size_t len, void *u log_level_name[level], len, message); } -int omemo__signal_init(struct t_gui_buffer *buffer, struct t_omemo *omemo) +int iks_get_identity_key_pair(signal_buffer **public_data, signal_buffer **private_data, void *user_data) { - signal_context *global_context; + (void) public_data; + (void) private_data; + (void) user_data; + // Get the local client's identity key pair +} + +int iks_get_local_registration_id(void *user_data, uint32_t *registration_id) +{ + (void) user_data; + (void) registration_id; + // Return the local client's registration ID +} + +int iks_save_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) +{ + (void) address; + (void) key_data; + (void) key_len; + (void) user_data; + // Save a remote client's identity key +} + +int iks_is_trusted_identity(const signal_protocol_address *address, uint8_t *key_data, size_t key_len, void *user_data) +{ + (void) address; + (void) key_data; + (void) key_len; + (void) user_data; + // Verify a remote client's identity key +} + +void iks_destroy_func(void *user_data) +{ + (void) user_data; + // Function called to perform cleanup when the data store context is being destroyed +} + + +void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo, + const char *account_name) +{ + struct t_omemo *new_omemo; gcry_check_version(NULL); - signal_context_create(&global_context, buffer); - signal_context_set_log_function(global_context, &omemo__log_emit_weechat); - - struct signal_crypto_provider provider = { - .random_func = &signal_random_generator, - .hmac_sha256_init_func = &signal_hmac_sha256_init, - .hmac_sha256_update_func = &signal_hmac_sha256_update, - .hmac_sha256_final_func = &signal_hmac_sha256_final, - .hmac_sha256_cleanup_func = &signal_hmac_sha256_cleanup, - .sha512_digest_init_func = &signal_sha512_digest_init, - .sha512_digest_update_func = &signal_sha512_digest_update, - .sha512_digest_final_func = &signal_sha512_digest_final, - .sha512_digest_cleanup_func = &signal_sha512_digest_cleanup, - .encrypt_func = &signal_encrypt, - .decrypt_func = &signal_decrypt, + new_omemo = calloc(1, sizeof(**omemo)); + + signal_context_create(&new_omemo->context, buffer); + signal_context_set_log_function(new_omemo->context, &omemo__log_emit_weechat); + + mdb_env_create(&new_omemo->db.env); + mdb_env_set_maxdbs(new_omemo->db.env, 50); + mdb_env_set_mapsize(new_omemo->db.env, (size_t)1048576 * 100000); // 1MB * 100000 + char *path = weechat_string_eval_expression("${weechat_data_dir}/xmpp.omemo.db", + NULL, NULL, NULL); + if (mdb_env_open(new_omemo->db.env, path, MDB_NOSUBDIR, 0664) != 0) + { + return; + } + free(path); + + MDB_txn *parentTransaction = NULL; + MDB_txn *transaction; + if (mdb_txn_begin(new_omemo->db.env, parentTransaction, 0 ? MDB_RDONLY : 0, &transaction)) { + //Error + } + + if (0) { + mdb_txn_abort(transaction); + } else { + mdb_txn_commit(transaction); + } + + if (mdb_dbi_open(transaction, "databasename", MDB_DUPSORT | MDB_CREATE, new_omemo->db.dbi)) { + //Error + } + + struct signal_crypto_provider crypto_provider = { + .random_func = &cp_random_generator, + .hmac_sha256_init_func = &cp_hmac_sha256_init, + .hmac_sha256_update_func = &cp_hmac_sha256_update, + .hmac_sha256_final_func = &cp_hmac_sha256_final, + .hmac_sha256_cleanup_func = &cp_hmac_sha256_cleanup, + .sha512_digest_init_func = &cp_sha512_digest_init, + .sha512_digest_update_func = &cp_sha512_digest_update, + .sha512_digest_final_func = &cp_sha512_digest_final, + .sha512_digest_cleanup_func = &cp_sha512_digest_cleanup, + .encrypt_func = &cp_encrypt, + .decrypt_func = &cp_decrypt, .user_data = buffer, }; - signal_context_set_crypto_provider(global_context, &provider); - signal_context_set_locking_functions(global_context, &lock_function, &unlock_function); + signal_context_set_crypto_provider(new_omemo->context, &crypto_provider); + signal_context_set_locking_functions(new_omemo->context, &lock_function, &unlock_function); signal_protocol_key_helper_pre_key_list_node *pre_keys_head; session_signed_pre_key *signed_pre_key; int start_id = 0; time_t timestamp = time(NULL); - signal_protocol_key_helper_generate_identity_key_pair(&omemo->identity, global_context); - signal_protocol_key_helper_generate_registration_id(&omemo->device_id, 0, global_context); - signal_protocol_key_helper_generate_pre_keys(&pre_keys_head, start_id, 100, global_context); - signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, omemo->identity, 5, timestamp, global_context); + if (new_omemo->identity) + 0; + else + signal_protocol_key_helper_generate_identity_key_pair(&new_omemo->identity, new_omemo->context); + signal_protocol_key_helper_generate_registration_id(&new_omemo->device_id, 0, new_omemo->context); + signal_protocol_key_helper_generate_pre_keys(&pre_keys_head, start_id, 100, new_omemo->context); + signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, new_omemo->identity, 5, timestamp, new_omemo->context); /* Store pre keys in the pre key store. */ /* Store signed pre key in the signed pre key store. */ - omemo->context = global_context; - - return SG_SUCCESS; -} - -void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo, - char **device, char **identity) -{ - struct t_omemo *new_omemo; - - new_omemo = calloc(1, sizeof(**omemo)); - - omemo__deserialize(new_omemo, *device, *identity, strlen(*identity)); + signal_protocol_store_context_create(&new_omemo->store_context, new_omemo->context); - omemo__signal_init(buffer, new_omemo); + struct signal_protocol_identity_key_store identity_key_store = { + .get_identity_key_pair = &iks_get_identity_key_pair, + .get_local_registration_id = &iks_get_local_registration_id, + .save_identity = &iks_save_identity, + .is_trusted_identity = &iks_is_trusted_identity, + .destroy_func = &iks_destroy_func, + .user_data = account_name, + }; - omemo__serialize(new_omemo, device, identity, NULL); + signal_protocol_store_context_set_identity_key_store(new_omemo->store_context, &identity_key_store); *omemo = new_omemo; } diff --git a/omemo.h b/omemo.h index db6d4b1..5a28254 100644 --- a/omemo.h +++ b/omemo.h @@ -10,6 +10,12 @@ extern const char *OMEMO_ADVICE; struct t_omemo { struct signal_context *context; + struct signal_protocol_store_context *store_context; + + struct { + struct MDB_env *env; + struct MDB_dbi *dbi; + } db; struct ratchet_identity_key_pair *identity; @@ -17,7 +23,7 @@ struct t_omemo }; void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo, - char **device, char **identity); + const char *account_name); void omemo__serialize(struct t_omemo *omemo, char **device, char **identity, size_t *identity_len); diff --git a/pgp.c b/pgp.c index a879e81..9d4aed0 100644 --- a/pgp.c +++ b/pgp.c @@ -75,20 +75,20 @@ char *pgp__encrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *t if ((ret = rnp_input_from_memory(&input, (uint8_t *)message, strlen(message), false)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to create input object: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to create input object: %s\n", weechat_prefix("error"), reason); goto encrypt_finish; } if ((ret = rnp_output_to_memory(&output, 0)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to create output object: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to create output object: %s\n", weechat_prefix("error"), reason); goto encrypt_finish; } /* create encryption operation */ if ((ret = rnp_op_encrypt_create(&encrypt, pgp->context, input, output)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to create encrypt operation: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to create encrypt operation: %s\n", weechat_prefix("error"), reason); goto encrypt_finish; } @@ -103,13 +103,13 @@ char *pgp__encrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *t /* locate recipient's key and add it to the operation context. */ if ((ret = rnp_locate_key(pgp->context, "keyid", target, &key)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to locate recipient key: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to locate recipient key: %s\n", weechat_prefix("error"), reason); goto encrypt_finish; } if ((ret = rnp_op_encrypt_add_recipient(encrypt, key)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to add recipient: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to add recipient: %s\n", weechat_prefix("error"), reason); goto encrypt_finish; } rnp_key_handle_destroy(key); @@ -118,7 +118,7 @@ char *pgp__encrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *t /* execute encryption operation */ if ((ret = rnp_op_encrypt_execute(encrypt)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tencryption failed: %s\n", reason); + weechat_printf(buffer, "%spgp: encryption failed: %s\n", weechat_prefix("error"), reason); goto encrypt_finish; } @@ -156,19 +156,19 @@ char *pgp__decrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *c * message */ if ((ret = rnp_input_from_memory(&input, buf, buf_len, false)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to create input object: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to create input object: %s\n", weechat_prefix("error"), reason); goto decrypt_finish; } if ((ret = rnp_output_to_memory(&output, 0)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to create output object: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to create output object: %s\n", weechat_prefix("error"), reason); goto decrypt_finish; } if ((ret = rnp_decrypt(pgp->context, input, output)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tpublic-key decryption failed: %s\n", reason); + weechat_printf(buffer, "%spgp: public-key decryption failed: %s\n", weechat_prefix("error"), reason); goto decrypt_finish; } free(buf); @@ -204,19 +204,19 @@ char *pgp__verify(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *ce /* create file input memory objects for the signed message and verified message */ if ((ret = rnp_input_from_memory(&input, buf, buf_len, false)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to create input object: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to create input object: %s\n", weechat_prefix("error"), reason); goto verify_finish; } if ((ret = rnp_input_from_memory(&signature, buf, buf_len, false)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to create input object: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to create input object: %s\n", weechat_prefix("error"), reason); goto verify_finish; } if ((ret = rnp_op_verify_detached_create(&verify, pgp->context, input, signature)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to create verification context: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to create verification context: %s\n", weechat_prefix("error"), reason); goto verify_finish; } @@ -226,14 +226,14 @@ char *pgp__verify(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *ce // ) != RNP_ERROR_SIGNATURE_INVALID) // if (ret != RNP_ERROR_SIGNATURE_INVALID) { // const char *reason = rnp_result_to_string(ret); - // weechat_printf(buffer, "[PGP]\tfailed to execute verification operation: %s\n", reason); + // weechat_printf(buffer, "%spgp: failed to execute verification operation: %s\n", weechat_prefix("error"), reason); // goto verify_finish; // } /* now check signatures and get some info about them */ if ((ret = rnp_op_verify_get_signature_count(verify, &sigcount)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to get signature count: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to get signature count: %s\n", weechat_prefix("error"), reason); goto verify_finish; } @@ -245,14 +245,14 @@ char *pgp__verify(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *ce if ((ret = rnp_op_verify_get_signature_at(verify, i, &sig)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to get signature %d: %s\n", (int)i, reason); + weechat_printf(buffer, "%spgp: failed to get signature %d: %s\n", weechat_prefix("error"), (int)i, reason); goto verify_finish; } if ((ret = rnp_op_verify_signature_get_key(sig, &key)) == RNP_SUCCESS) { if ((ret = rnp_key_get_keyid(key, &keyid)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to get key id %d: %s\n", (int)i, reason); + weechat_printf(buffer, "%spgp: failed to get key id %d: %s\n", weechat_prefix("error"), (int)i, reason); rnp_key_handle_destroy(key); goto verify_finish; } @@ -260,7 +260,7 @@ char *pgp__verify(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *ce if ((ret = rnp_key_get_signature_at(key, 0, &signature)) == RNP_SUCCESS) { if ((ret = rnp_signature_get_keyid(signature, &keyid)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to get key id: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to get key id: %s\n", weechat_prefix("error"), reason); rnp_key_handle_destroy(key); goto verify_finish; } @@ -269,13 +269,13 @@ char *pgp__verify(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *ce } else { if ((ret = rnp_op_verify_signature_get_handle(sig, &signature)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to get signature's %d handle: %s\n", (int)i, reason); + weechat_printf(buffer, "%spgp: failed to get signature's %d handle: %s\n", weechat_prefix("error"), (int)i, reason); goto verify_finish; } if ((ret = rnp_signature_get_keyid(signature, &keyid)) != RNP_SUCCESS) { const char *reason = rnp_result_to_string(ret); - weechat_printf(buffer, "[PGP]\tfailed to get key id: %s\n", reason); + weechat_printf(buffer, "%spgp: failed to get key id: %s\n", weechat_prefix("error"), reason); rnp_key_handle_destroy(key); goto verify_finish; } @@ -309,18 +309,18 @@ char *pgp__sign(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *sour * message */ if (rnp_input_from_memory(&input, (uint8_t *)message, strlen(message), false) != RNP_SUCCESS) { - weechat_printf(buffer, "[PGP]\tfailed to create input object\n"); + weechat_printf(buffer, "%spgp: failed to create input object\n", weechat_prefix("error")); goto sign_finish; } if (rnp_output_to_memory(&output, 0) != RNP_SUCCESS) { - weechat_printf(buffer, "[PGP]\tfailed to create output object\n"); + weechat_printf(buffer, "%spgp: failed to create output object\n", weechat_prefix("error")); goto sign_finish; } /* initialize and configure sign operation */ if (rnp_op_sign_detached_create(&sign, pgp->context, input, output) != RNP_SUCCESS) { - weechat_printf(buffer, "[PGP]\tfailed to create sign operation\n"); + weechat_printf(buffer, "%spgp: failed to create sign operation\n", weechat_prefix("error")); goto sign_finish; } @@ -338,12 +338,12 @@ char *pgp__sign(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *sour /* now add signatures. First locate the signing key, then add and setup signature */ if (rnp_locate_key(pgp->context, "keyid", source, &key) != RNP_SUCCESS) { - weechat_printf(buffer, "[PGP]\tfailed to locate signing key: %s\n", source); + weechat_printf(buffer, "%spgp: failed to locate signing key: %s\n", weechat_prefix("error"), source); goto sign_finish; } if (rnp_op_sign_add_signature(sign, key, NULL) != RNP_SUCCESS) { - weechat_printf(buffer, "[PGP]\tfailed to add signature for key: %s\n", source); + weechat_printf(buffer, "%spgp: failed to add signature for key: %s\n", weechat_prefix("error"), source); goto sign_finish; } @@ -352,7 +352,7 @@ char *pgp__sign(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *sour /* finally do signing */ if (rnp_op_sign_execute(sign) != RNP_SUCCESS) { - weechat_printf(buffer, "[PGP]\tfailed to sign with key: %s\n", source); + weechat_printf(buffer, "%spgp: failed to sign with key: %s\n", weechat_prefix("error"), source); goto sign_finish; } diff --git a/user.c b/user.c index 50abe1c..5d9ed62 100644 --- a/user.c +++ b/user.c @@ -53,18 +53,18 @@ const char *user__as_prefix(struct t_account *account, } struct t_user *user__bot_search(struct t_account *account, - const char *bot_id) + const char *pgp_id) { struct t_user *ptr_user; - if (!account || !bot_id) + if (!account || !pgp_id) return NULL; for (ptr_user = account->users; ptr_user; ptr_user = ptr_user->next_user) { - if (ptr_user->profile.bot_id && - weechat_strcasecmp(ptr_user->profile.bot_id, bot_id) == 0) + if (ptr_user->profile.pgp_id && + weechat_strcasecmp(ptr_user->profile.pgp_id, pgp_id) == 0) return ptr_user; } @@ -102,15 +102,28 @@ void user__nicklist_add(struct t_account *account, ptr_buffer = channel ? channel->buffer : account->buffer; - ptr_group = weechat_nicklist_search_group(ptr_buffer, NULL, - user->is_away ? - "+" : "..."); + char *group = "..."; + if (weechat_strcasecmp(user->profile.affiliation, "outcast") == 0) + group = "!"; + if (weechat_strcasecmp(user->profile.role, "visitor") == 0) + group = "?"; + if (weechat_strcasecmp(user->profile.role, "participant") == 0) + group = "+"; + if (weechat_strcasecmp(user->profile.affiliation, "member") == 0) + group = "%"; + if (weechat_strcasecmp(user->profile.role, "moderator") == 0) + group = "@"; + if (weechat_strcasecmp(user->profile.affiliation, "admin") == 0) + group = "&"; + if (weechat_strcasecmp(user->profile.affiliation, "owner") == 0) + group = "~"; + ptr_group = weechat_nicklist_search_group(ptr_buffer, NULL, group); weechat_nicklist_add_nick(ptr_buffer, ptr_group, name, user->is_away ? "weechat.color.nicklist_away" : user__get_colour_for_nicklist(user), - user->is_away ? "+" : "", + group, "bar_fg", 1); } @@ -119,7 +132,7 @@ void user__nicklist_remove(struct t_account *account, struct t_channel *channel, struct t_user *user) { - struct t_gui_nick_group *ptr_group; + struct t_gui_nick *ptr_nick; struct t_gui_buffer *ptr_buffer; char *name = user->profile.display_name; if (channel && weechat_strcasecmp(xmpp_jid_bare(account->context, name), @@ -128,11 +141,8 @@ void user__nicklist_remove(struct t_account *account, ptr_buffer = channel ? channel->buffer : account->buffer; - ptr_group = weechat_nicklist_search_group(ptr_buffer, NULL, - user->is_away ? - "+" : "..."); - weechat_nicklist_remove_nick(ptr_buffer, - weechat_nicklist_search_nick(ptr_buffer, ptr_group, name)); + if ((ptr_nick = weechat_nicklist_search_nick(ptr_buffer, NULL, name))) + weechat_nicklist_remove_nick(ptr_buffer, ptr_nick); } struct t_user *user__new(struct t_account *account, @@ -173,14 +183,14 @@ struct t_user *user__new(struct t_account *account, new_user->profile.avatar_hash = NULL; new_user->profile.status_text = NULL; - new_user->profile.status_emoji = NULL; + new_user->profile.status = NULL; new_user->profile.real_name = NULL; new_user->profile.display_name = display_name ? strdup(display_name) : strdup(""); - new_user->profile.real_name_normalized = NULL; + new_user->profile.affiliation = NULL; new_user->profile.email = NULL; - new_user->profile.team = NULL; - new_user->profile.bot_id = NULL; + new_user->profile.role = NULL; + new_user->profile.pgp_id = NULL; new_user->updated = 0; new_user->is_away = 0; @@ -220,18 +230,18 @@ void user__free(struct t_account *account, free(user->profile.avatar_hash); if (user->profile.status_text) free(user->profile.status_text); - if (user->profile.status_emoji) - free(user->profile.status_emoji); + if (user->profile.status) + free(user->profile.status); if (user->profile.real_name) free(user->profile.real_name); if (user->profile.display_name) free(user->profile.display_name); - if (user->profile.real_name_normalized) - free(user->profile.real_name_normalized); + if (user->profile.affiliation) + free(user->profile.affiliation); if (user->profile.email) free(user->profile.email); - if (user->profile.team) - free(user->profile.team); + if (user->profile.role) + free(user->profile.role); free(user); diff --git a/user.h b/user.h index 30c6440..74c3654 100644 --- a/user.h +++ b/user.h @@ -9,13 +9,13 @@ struct t_user_profile { char *avatar_hash; char *status_text; - char *status_emoji; + char *status; char *real_name; char *display_name; - char *real_name_normalized; char *email; - char *team; - char *bot_id; + char *role; + char *affiliation; + char *pgp_id; }; struct t_user @@ -41,9 +41,6 @@ const char *user__as_prefix(struct t_account *account, struct t_user *user, const char *name); -struct t_user *user__bot_search(struct t_account *account, - const char *bot_id); - struct t_user *user__search(struct t_account *account, const char *id);