nicklist stuff

v1
Tony Olagbaiye 3 years ago
parent d566f45c6a
commit d3ffc19378
No known key found for this signature in database
GPG Key ID: 9E2FF3BDEBDFC910

@ -50,6 +50,7 @@ use_guix()
libstrophe # Dep (strophe) libstrophe # Dep (strophe)
libgcrypt # Dep (gcrypt) libgcrypt # Dep (gcrypt)
libsignal-protocol-c # Dep (libsignal) libsignal-protocol-c # Dep (libsignal)
lmdb # Dep (lmdb)
rnp # Dep (rnpgp) rnp # Dep (rnpgp)
) )
@ -63,5 +64,6 @@ use guix \
--with-debug-info=weechat\ --with-debug-info=weechat\
--with-debug-info=libstrophe\ --with-debug-info=libstrophe\
--with-debug-info=libsignal-protocol-c\ --with-debug-info=libsignal-protocol-c\
--with-debug-info=lmdb\
--with-debug-info=rnp\ --with-debug-info=rnp\
clang:extra gdb clang:extra gdb

@ -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) 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) 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) 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 PREFIX ?= /usr/local
LIBDIR ?= $(PREFIX)/lib LIBDIR ?= $(PREFIX)/lib

@ -116,14 +116,16 @@
* [X] [#B] Leaves * [X] [#B] Leaves
* [X] [#B] Tracking * [X] [#B] Tracking
* [X] [#B] Set/show topic * [X] [#B] Set/show topic
* [-] OMEMO (libsignal-protocol-c / axc) * [-] OMEMO (libsignal-protocol-c)
* [-] Presence * [-] Presence
* [X] Disco * [X] Disco
* [X] Disco response * [X] Disco response
* [-] Key Generation / storage (secured_data?) * [-] Key Generation / storage (lmdb)
* [X] Generation * [X] Generation
* [X] Storage * [?] Storage
* [ ] Announce * [-] Announce
* [X] Device ID
* [ ] Bundles
* [ ] Messages * [ ] Messages
* [ ] [#C] MUC PMs * [ ] [#C] MUC PMs
* [X] [#A] Send typing notifications * [X] [#A] Send typing notifications

@ -507,7 +507,7 @@ void account__disconnect(struct t_account *account, int reconnect)
account__set_lag(account); account__set_lag(account);
*/ // lag based on xmpp ping */ // lag based on xmpp ping
account->disconnected = 1; account->disconnected = !reconnect;
/* send signal "account_disconnected" with account name */ /* send signal "account_disconnected" with account name */
(void) weechat_hook_signal_send("xmpp_account_disconnected", (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) int account__connect(struct t_account *account)
{ {
account->disconnected = 0;
if (!account->buffer) if (!account->buffer)
{ {
if (!account__create_buffer(account)) if (!account__create_buffer(account))
@ -587,7 +585,7 @@ int account__connect(struct t_account *account)
connection__connect(account, &account->connection, account_jid(account), connection__connect(account, &account->connection, account_jid(account),
account_password(account), account_tls(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); WEECHAT_HOOK_SIGNAL_STRING, account->name);
return account->is_connected; 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_connecting(ptr_account->connection)
|| xmpp_conn_is_connected(ptr_account->connection))) || xmpp_conn_is_connected(ptr_account->connection)))
connection__process(ptr_account->context, ptr_account->connection, 10); connection__process(ptr_account->context, ptr_account->connection, 10);
else if (ptr_account->disconnected);
else if (ptr_account->reconnect_start > 0 else if (ptr_account->reconnect_start > 0
&& ptr_account->reconnect_start < time(NULL)) && ptr_account->reconnect_start < time(NULL))
{ {

@ -155,7 +155,7 @@ int buffer__close_cb(const void *pointer, void *data,
{ {
if (ptr_account) if (ptr_account)
{ {
if (!ptr_account->disconnected) if (ptr_account->is_connected)
{ {
account__disconnect(ptr_account, 0); 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 && ptr_channel)
{ {
if (!ptr_account->disconnected) if (ptr_account->is_connected)
{ {
channel__free(ptr_account, ptr_channel); 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 && ptr_channel)
{ {
if (!ptr_account->disconnected) if (ptr_account->is_connected)
{ {
channel__free(ptr_account, ptr_channel); channel__free(ptr_account, ptr_channel);
} }

@ -211,12 +211,28 @@ void channel__add_nicklist_groups(struct t_account *account,
ptr_buffer = channel ? channel->buffer : account->buffer; ptr_buffer = channel ? channel->buffer : account->buffer;
snprintf(str_group, sizeof(str_group), "%03d|%s", snprintf(str_group, sizeof(str_group), "%03d|%s", 000, "~");
000, "+");
weechat_nicklist_add_group(ptr_buffer, NULL, str_group, weechat_nicklist_add_group(ptr_buffer, NULL, str_group,
"weechat.color.nicklist_group", 1); "weechat.color.nicklist_group", 1);
snprintf(str_group, sizeof(str_group), "%03d|%s", snprintf(str_group, sizeof(str_group), "%03d|%s", 001, "&");
999, "..."); 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_nicklist_add_group(ptr_buffer, NULL, str_group,
"weechat.color.nicklist_group", 1); "weechat.color.nicklist_group", 1);
} }
@ -290,6 +306,8 @@ struct t_channel *channel__new(struct t_account *account,
account->channels = new_channel; account->channels = new_channel;
account->last_channel = new_channel; account->last_channel = new_channel;
channel__add_nicklist_groups(account, new_channel);
if (type != CHANNEL_TYPE_MUC) if (type != CHANNEL_TYPE_MUC)
{ {
time_t start = time(NULL); 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_member *channel__add_member(struct t_account *account,
struct t_channel *channel, struct t_channel *channel,
const char *id, const char *client, const char *id, const char *client)
const char *status)
{ {
struct t_channel_member *member; struct t_channel_member *member;
struct t_user *user; struct t_user *user;
user = user__search(account, id); 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) && channel->type == CHANNEL_TYPE_MUC)
{ {
weechat_printf_date_tags(channel->buffer, 0, "log2", "%sMUC: %s", weechat_printf_date_tags(channel->buffer, 0, "log2", "%sMUC: %s",
@ -835,6 +852,8 @@ struct t_channel_member *channel__add_member(struct t_account *account,
return NULL; return NULL;
} }
if (!(member = channel__member_search(channel, id)))
{
member = malloc(sizeof(struct t_channel_member)); member = malloc(sizeof(struct t_channel_member));
member->id = strdup(id); member->id = strdup(id);
@ -848,6 +867,9 @@ struct t_channel_member *channel__add_member(struct t_account *account,
else else
channel->members = member; channel->members = member;
channel->last_member = member; channel->last_member = member;
}
else if (user)
user__nicklist_remove(account, channel, user);
if (user) if (user)
user__nicklist_add(account, channel, 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); char *jid_resource = xmpp_jid_resource(account->context, user->id);
if (weechat_strcasecmp(jid_bare, channel->id) == 0 if (weechat_strcasecmp(jid_bare, channel->id) == 0
&& channel->type == CHANNEL_TYPE_MUC) && 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"), weechat_prefix("join"),
user__as_prefix_raw(account, jid_resource), user__as_prefix_raw(account, jid_resource),
client ? "(" : "", client, client ? ")" : "", client ? " (" : "",
client ? client : "",
client ? ")" : "",
user->profile.status ? "is " : "",
weechat_color("irc.color.message_join"), weechat_color("irc.color.message_join"),
user->profile.status ? user->profile.status : "entered",
weechat_color("reset"), weechat_color("reset"),
channel->id, channel->id,
status ? "[" : "", user->profile.status_text ? " [" : "",
status ? status : "", user->profile.status_text ? user->profile.status_text : "",
status ? "]" : ""); 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 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"), weechat_prefix("join"),
user__as_prefix_raw(account, jid_resource ? user__as_prefix_raw(account, jid_bare) : "You",
xmpp_jid_bare(account->context, user->id)), jid_resource ? jid_resource : user__as_prefix_raw(account, jid_bare),
xmpp_jid_resource(account->context, user->id), user->profile.status ? "is " : "",
weechat_color("irc.color.message_join"), weechat_color("irc.color.message_join"),
user->profile.status ? user->profile.status : "entered",
weechat_color("reset"), weechat_color("reset"),
channel->id, channel->id,
status ? "[" : "", user->profile.status_text ? " [" : "",
status ? status : "", user->profile.status_text ? user->profile.status_text : "",
status ? "]" : ""); 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; return member;
} }
@ -900,56 +939,16 @@ struct t_channel_member *channel__member_search(struct t_channel *channel,
return NULL; 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_member *channel__remove_member(struct t_account *account,
struct t_channel *channel, struct t_channel *channel,
const char *id, const char *status) const char *id, const char *reason)
{ {
struct t_channel_member *member; struct t_channel_member *member;
struct t_user *user; struct t_user *user;
user = user__search(account, id); user = user__search(account, id);
//if (user) if (user)
// user__nicklist_remove(account, channel, user); user__nicklist_remove(account, channel, user);
member = channel__member_search(channel, id); member = channel__member_search(channel, id);
if (member) 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("irc.color.message_quit"),
weechat_color("reset"), weechat_color("reset"),
channel->id, channel->id,
status ? "[" : "", reason ? "[" : "",
status ? status : "", reason ? reason : "",
status ? "]" : ""); reason ? "]" : "");
else else
weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,leave,log4", "%s%s (%s) %sleft%s %s %s%s%s", weechat_printf_date_tags(channel->buffer, 0, "xmpp_presence,leave,log4", "%s%s (%s) %sleft%s %s %s%s%s",
weechat_prefix("quit"), 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("irc.color.message_quit"),
weechat_color("reset"), weechat_color("reset"),
channel->id, channel->id,
status ? "[" : "", reason ? "[" : "",
status ? status : "", reason ? reason : "",
status ? "]" : ""); reason ? "]" : "");
return member; return member;
} }

@ -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_member *channel__add_member(struct t_account *account,
struct t_channel *channel, struct t_channel *channel,
const char *id, const char *client, const char *id, const char *client);
const char *status);
int channel__set_member_role(struct t_account *account, struct t_channel_member *channel__member_search(struct t_channel *channel,
struct t_channel *channel, const char *id);
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__remove_member(struct t_account *account, struct t_channel_member *channel__remove_member(struct t_account *account,
struct t_channel *channel, 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, void channel__send_message(struct t_account *account, struct t_channel *channel,
const char *to, const char *body); const char *to, const char *body);

@ -6,11 +6,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <weechat/weechat-plugin.h> #include <weechat/weechat-plugin.h>
#include "plugin.h" #include "plugin.h"
//#include "oauth.h" //#include "oauth.h"
//#include "teaminfo.h"
#include "account.h" #include "account.h"
#include "user.h" #include "user.h"
#include "channel.h" #include "channel.h"
@ -18,6 +18,9 @@
#include "message.h" #include "message.h"
#include "command.h" #include "command.h"
#define MAM_DEFAULT_DAYS 2
#define STR(X) #X
void command__display_account(struct t_account *account) void command__display_account(struct t_account *account)
{ {
int num_channels, num_pv; int num_channels, num_pv;
@ -161,10 +164,12 @@ void command__add_account(const char *name, const char *jid, const char *passwor
weechat_color("reset")); 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; char *name, *jid = NULL, *password = NULL;
(void) buffer;
switch (argc) switch (argc)
{ {
case 5: case 5:
@ -202,11 +207,12 @@ int command__connect_account(struct t_account *account)
return 1; 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; int i, nb_connect, connect_ok;
struct t_account *ptr_account; struct t_account *ptr_account;
(void) buffer;
(void) argc; (void) argc;
(void) argv; (void) argv;
@ -257,7 +263,7 @@ int command__disconnect_account(struct t_account *account)
return 1; 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; int i, nb_disconnect, disconnect_ok;
struct t_account *ptr_account; struct t_account *ptr_account;
@ -268,6 +274,20 @@ int command__account_disconnect(int argc, char **argv)
disconnect_ok = 1; disconnect_ok = 1;
nb_disconnect = 0; 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++) for (i = 2; i < argc; i++)
{ {
nb_disconnect++; nb_disconnect++;
@ -292,14 +312,16 @@ int command__account_disconnect(int argc, char **argv)
return (disconnect_ok) ? WEECHAT_RC_OK : WEECHAT_RC_ERROR; 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); command__account_disconnect(buffer, argc, argv);
return command__account_connect(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; struct t_account *account;
char *account_name; char *account_name;
@ -367,31 +389,31 @@ int command__account(const void *pointer, void *data,
{ {
if (weechat_strcasecmp(argv[1], "add") == 0) if (weechat_strcasecmp(argv[1], "add") == 0)
{ {
command__account_add(argc, argv); command__account_add(buffer, argc, argv);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
if (weechat_strcasecmp(argv[1], "connect") == 0) if (weechat_strcasecmp(argv[1], "connect") == 0)
{ {
command__account_connect(argc, argv); command__account_connect(buffer, argc, argv);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
if (weechat_strcasecmp(argv[1], "disconnect") == 0) if (weechat_strcasecmp(argv[1], "disconnect") == 0)
{ {
command__account_disconnect(argc, argv); command__account_disconnect(buffer, argc, argv);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
if (weechat_strcasecmp(argv[1], "reconnect") == 0) if (weechat_strcasecmp(argv[1], "reconnect") == 0)
{ {
command__account_reconnect(argc, argv); command__account_reconnect(buffer, argc, argv);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
if (weechat_strcasecmp(argv[1], "delete") == 0) if (weechat_strcasecmp(argv[1], "delete") == 0)
{ {
command__account_delete(argc, argv); command__account_delete(buffer, argc, argv);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
@ -478,6 +500,33 @@ int command__enter(const void *pointer, void *data,
} }
weechat_string_free_split(jids); 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; return WEECHAT_RC_OK;
} }
@ -656,6 +705,58 @@ int command__me(const void *pointer, void *data,
return WEECHAT_RC_OK; 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, int command__pgp(const void *pointer, void *data,
struct t_gui_buffer *buffer, int argc, struct t_gui_buffer *buffer, int argc,
char **argv, char **argv_eol) char **argv, char **argv_eol)
@ -678,7 +779,7 @@ int command__pgp(const void *pointer, void *data,
weechat_printf( weechat_printf(
ptr_account->buffer, ptr_account->buffer,
_("%s%s: \"%s\" command can not be executed on a 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; return WEECHAT_RC_OK;
} }
@ -797,6 +898,15 @@ void command__init()
if (!hook) if (!hook)
weechat_printf(NULL, "Failed to setup command /me"); 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( hook = weechat_hook_command(
"pgp", "pgp",
N_("set the target pgp key for the current channel"), N_("set the target pgp key for the current channel"),

@ -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_account *account = (struct t_account *)userdata;
struct t_user *user; struct t_user *user;
struct t_channel *channel; 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 *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; char *clientid = NULL, *status;
from = xmpp_stanza_get_from(stanza); 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_bare = xmpp_jid_bare(account->context, from);
from_res = xmpp_jid_resource(account->context, from); from_res = xmpp_jid_resource(account->context, from);
type = xmpp_stanza_get_type(stanza); 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( iq__x_signed = xmpp_stanza_get_child_by_name_and_ns(
stanza, "x", "jabber:x:signed"); stanza, "x", "jabber:x:signed");
if (iq__x_signed) if (iq__x_signed)
{ {
certificate = xmpp_stanza_get_text(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( iq__c = xmpp_stanza_get_child_by_name_and_ns(
stanza, "c", "http://jabber.org/protocol/caps"); stanza, "c", "http://jabber.org/protocol/caps");
if (iq__c) if (iq__c)
{ {
node = xmpp_stanza_get_attribute(iq__c, "node"); node = xmpp_stanza_get_attribute(iq__c, "node");
ver = xmpp_stanza_get_attribute(iq__c, "ver"); ver = xmpp_stanza_get_attribute(iq__c, "ver");
if (jid) if (node && ver)
clientid = strdup(jid);
else if (node && ver)
{ {
int len = strlen(node)+1+strlen(ver); int len = strlen(node)+1+strlen(ver);
clientid = malloc(sizeof(char)*len); 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"); iq__status = xmpp_stanza_get_child_by_name(stanza, "status");
status = iq__status ? xmpp_stanza_get_text(iq__status) : NULL; 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); channel = channel__search(account, from_bare);
if (weechat_strcasecmp(type, "unavailable") && !iq__x_muc_user && !channel) if (weechat_strcasecmp(type, "unavailable") && !iq__x_muc_user && !channel)
channel = channel__new(account, CHANNEL_TYPE_PM, from_bare, from_bare); channel = channel__new(account, CHANNEL_TYPE_PM, from_bare, from_bare);
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 (weechat_strcasecmp(xmpp_stanza_get_name(iq__x__item), "item") != 0)
continue;
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");
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) if (certificate && channel)
{ {
user->profile.pgp_id = pgp__verify(channel->buffer, account->pgp, certificate);
if (channel->type != CHANNEL_TYPE_MUC) if (channel->type != CHANNEL_TYPE_MUC)
channel->pgp_id = pgp__verify(channel->buffer, account->pgp, certificate); channel->pgp_id = user->profile.pgp_id;
weechat_printf(channel->buffer, "[PGP]\t%sKey %s from %s",
weechat_color("gray"), channel->pgp_id, from);
} }
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
{
user = user__search(account, from); user = user__search(account, from);
if (!user) if (!user)
user = user__new(account, from, user = user__new(account, from,
channel && weechat_strcasecmp(from_bare, channel->id) == 0 channel && weechat_strcasecmp(from_bare, channel->id) == 0
? from_res : from); ? from_res : from);
user->profile.status_text = status ? strdup(status) : NULL;
if (!iq__x_muc_user && channel) 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)
{ {
channel__add_member(account, channel, from, clientid, status); user->profile.pgp_id = pgp__verify(channel->buffer, account->pgp, certificate);
if (channel->type != CHANNEL_TYPE_MUC)
channel->pgp_id = user->profile.pgp_id;
} }
else if (channel)
if (channel)
{ {
channel__set_member_role(account, channel, from, role); if (weechat_strcasecmp(type, "unavailable") == 0)
channel__set_member_affiliation(account, channel, from, affiliation);
if (weechat_strcasecmp(role, "none") == 0)
channel__remove_member(account, channel, from, status); channel__remove_member(account, channel, from, status);
else else
channel__add_member(account, channel, from, clientid, status); channel__add_member(account, channel, from, clientid);
}
} }
if (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); channel__add_typing(channel, user);
weechat_printf(channel->buffer, "...\t%s%s typing", weechat_printf(channel->buffer, "...\t%s%s typing",
weechat_color("gray"), weechat_color("gray"),
weechat_strcasecmp(from_bare, channel->id) == 0 channel->type == CHANNEL_TYPE_MUC ? nick : from);
? nick : from);
} }
sent = xmpp_stanza_get_child_by_name_and_ns( 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( list = xmpp_stanza_get_child_by_name_and_ns(
item, "list", "eu.siacs.conversations.axolotl"); item, "list", "eu.siacs.conversations.axolotl");
if (list) if (list && account->omemo)
{ {
account__free_device_all(account); 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}; char id[64] = {0};
int i = 0;
dev = malloc(sizeof(struct t_account_device));
dev->id = account->omemo->device_id; dev->id = account->omemo->device_id;
snprintf(id, sizeof(id), "%d", dev->id); snprintf(id, sizeof(id), "%d", dev->id);
dev->name = strdup(id); dev->name = strdup(id);
account__add_device(account, dev); account__add_device(account, dev);
int i = 0;
children = malloc(sizeof(xmpp_stanza_t *) * 128); children = malloc(sizeof(xmpp_stanza_t *) * 128);
children[i++] = stanza__iq_pubsub_publish_item_list_device( children[i++] = stanza__iq_pubsub_publish_item_list_device(
account->context, NULL, with_noop(dev->name)); 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) if (status == XMPP_CONN_CONNECT)
{ {
account->disconnected = 0;
xmpp_stanza_t *pres, *pres__c, *pres__status, *pres__status__text, xmpp_stanza_t *pres, *pres__c, *pres__status, *pres__status__text,
*pres__x, *pres__x__text, **children; *pres__x, *pres__x__text, **children;
char cap_hash[28+1] = {0}; 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_send(conn, children[0]);
xmpp_stanza_release(children[0]); xmpp_stanza_release(children[0]);
struct t_hashtable *variables = weechat_hashtable_new (8, omemo__init(account->buffer, &account->omemo, account->name);
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) (void) weechat_hook_signal_send("xmpp_account_connected",
{ WEECHAT_HOOK_SIGNAL_STRING, account->name);
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);
}
} }
else else
{ {

@ -9,6 +9,7 @@
#include <gcrypt.h> #include <gcrypt.h>
#include <signal_protocol.h> #include <signal_protocol.h>
#include <key_helper.h> #include <key_helper.h>
#include <lmdb.h>
#include <strophe.h> #include <strophe.h>
#include <weechat/weechat-plugin.h> #include <weechat/weechat-plugin.h>
@ -90,19 +91,19 @@ signal_protocol_address* signal_protocol_address_new(const char* name, int32_t d
return address; 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); gcry_randomize(data, len, GCRY_STRONG_RANDOM);
return SG_SUCCESS; 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; (void) user_data;
gcry_randomize(data, len, GCRY_STRONG_RANDOM); gcry_randomize(data, len, GCRY_STRONG_RANDOM);
return SG_SUCCESS; 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; (void) user_data;
gcry_mac_hd_t* ctx = malloc(sizeof(gcry_mac_hd_t)); 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; 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; (void) user_data;
gcry_mac_hd_t* ctx = hmac_context; 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; 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; (void) user_data;
size_t len = gcry_mac_get_algo_maclen(GCRY_MAC_HMAC_SHA256); 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; 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; (void) user_data;
gcry_mac_hd_t* ctx = hmac_context; 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; (void) user_data;
gcry_md_hd_t* ctx = malloc(sizeof(gcry_mac_hd_t)); 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; 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; (void) user_data;
gcry_md_hd_t* ctx = digest_context; 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; 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; (void) user_data;
size_t len = gcry_md_get_algo_dlen(GCRY_MD_SHA512); 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; 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; (void) user_data;
gcry_md_hd_t* ctx = digest_context; 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; return SG_SUCCESS;
} }
int signal_encrypt(signal_buffer **output, int cp_encrypt(signal_buffer **output,
int cipher, int cipher,
const uint8_t *key, size_t key_len, const uint8_t *key, size_t key_len,
const uint8_t *iv, size_t iv_len, const uint8_t *iv, size_t iv_len,
@ -320,7 +321,7 @@ no_error:
return SG_SUCCESS; return SG_SUCCESS;
} }
int signal_decrypt(signal_buffer **output, int cp_decrypt(signal_buffer **output,
int cipher, int cipher,
const uint8_t *key, size_t key_len, const uint8_t *key, size_t key_len,
const uint8_t *iv, size_t iv_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); 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); gcry_check_version(NULL);
signal_context_create(&global_context, buffer); new_omemo = calloc(1, sizeof(**omemo));
signal_context_set_log_function(global_context, &omemo__log_emit_weechat);
signal_context_create(&new_omemo->context, buffer);
struct signal_crypto_provider provider = { signal_context_set_log_function(new_omemo->context, &omemo__log_emit_weechat);
.random_func = &signal_random_generator,
.hmac_sha256_init_func = &signal_hmac_sha256_init, mdb_env_create(&new_omemo->db.env);
.hmac_sha256_update_func = &signal_hmac_sha256_update, mdb_env_set_maxdbs(new_omemo->db.env, 50);
.hmac_sha256_final_func = &signal_hmac_sha256_final, mdb_env_set_mapsize(new_omemo->db.env, (size_t)1048576 * 100000); // 1MB * 100000
.hmac_sha256_cleanup_func = &signal_hmac_sha256_cleanup, char *path = weechat_string_eval_expression("${weechat_data_dir}/xmpp.omemo.db",
.sha512_digest_init_func = &signal_sha512_digest_init, NULL, NULL, NULL);
.sha512_digest_update_func = &signal_sha512_digest_update, if (mdb_env_open(new_omemo->db.env, path, MDB_NOSUBDIR, 0664) != 0)
.sha512_digest_final_func = &signal_sha512_digest_final, {
.sha512_digest_cleanup_func = &signal_sha512_digest_cleanup, return;
.encrypt_func = &signal_encrypt, }
.decrypt_func = &signal_decrypt, 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, .user_data = buffer,
}; };
signal_context_set_crypto_provider(global_context, &provider); signal_context_set_crypto_provider(new_omemo->context, &crypto_provider);
signal_context_set_locking_functions(global_context, &lock_function, &unlock_function); signal_context_set_locking_functions(new_omemo->context, &lock_function, &unlock_function);
signal_protocol_key_helper_pre_key_list_node *pre_keys_head; signal_protocol_key_helper_pre_key_list_node *pre_keys_head;
session_signed_pre_key *signed_pre_key; session_signed_pre_key *signed_pre_key;
int start_id = 0; int start_id = 0;
time_t timestamp = time(NULL); time_t timestamp = time(NULL);
signal_protocol_key_helper_generate_identity_key_pair(&omemo->identity, global_context); if (new_omemo->identity)
signal_protocol_key_helper_generate_registration_id(&omemo->device_id, 0, global_context); 0;
signal_protocol_key_helper_generate_pre_keys(&pre_keys_head, start_id, 100, global_context); else
signal_protocol_key_helper_generate_signed_pre_key(&signed_pre_key, omemo->identity, 5, timestamp, global_context); 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 pre keys in the pre key store. */
/* Store signed pre key in the signed pre key store. */ /* Store signed pre key in the signed pre key store. */
omemo->context = global_context; signal_protocol_store_context_create(&new_omemo->store_context, new_omemo->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));
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; *omemo = new_omemo;
} }

@ -10,6 +10,12 @@ extern const char *OMEMO_ADVICE;
struct t_omemo struct t_omemo
{ {
struct signal_context *context; 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; 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, 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, void omemo__serialize(struct t_omemo *omemo, char **device,
char **identity, size_t *identity_len); char **identity, size_t *identity_len);

50
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)) != if ((ret = rnp_input_from_memory(&input, (uint8_t *)message, strlen(message), false)) !=
RNP_SUCCESS) { RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto encrypt_finish;
} }
if ((ret = rnp_output_to_memory(&output, 0)) != RNP_SUCCESS) { if ((ret = rnp_output_to_memory(&output, 0)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto encrypt_finish;
} }
/* create encryption operation */ /* create encryption operation */
if ((ret = rnp_op_encrypt_create(&encrypt, pgp->context, input, output)) != RNP_SUCCESS) { if ((ret = rnp_op_encrypt_create(&encrypt, pgp->context, input, output)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; 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. */ /* locate recipient's key and add it to the operation context. */
if ((ret = rnp_locate_key(pgp->context, "keyid", target, &key)) != RNP_SUCCESS) { if ((ret = rnp_locate_key(pgp->context, "keyid", target, &key)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto encrypt_finish;
} }
if ((ret = rnp_op_encrypt_add_recipient(encrypt, key)) != RNP_SUCCESS) { if ((ret = rnp_op_encrypt_add_recipient(encrypt, key)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto encrypt_finish;
} }
rnp_key_handle_destroy(key); 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 */ /* execute encryption operation */
if ((ret = rnp_op_encrypt_execute(encrypt)) != RNP_SUCCESS) { if ((ret = rnp_op_encrypt_execute(encrypt)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto encrypt_finish;
} }
@ -156,19 +156,19 @@ char *pgp__decrypt(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *c
* message */ * message */
if ((ret = rnp_input_from_memory(&input, buf, buf_len, false)) != RNP_SUCCESS) { if ((ret = rnp_input_from_memory(&input, buf, buf_len, false)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto decrypt_finish;
} }
if ((ret = rnp_output_to_memory(&output, 0)) != RNP_SUCCESS) { if ((ret = rnp_output_to_memory(&output, 0)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto decrypt_finish;
} }
if ((ret = rnp_decrypt(pgp->context, input, output)) != RNP_SUCCESS) { if ((ret = rnp_decrypt(pgp->context, input, output)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto decrypt_finish;
} }
free(buf); 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 */ /* 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) { if ((ret = rnp_input_from_memory(&input, buf, buf_len, false)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto verify_finish;
} }
if ((ret = rnp_input_from_memory(&signature, buf, buf_len, false)) != RNP_SUCCESS) { if ((ret = rnp_input_from_memory(&signature, buf, buf_len, false)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto verify_finish;
} }
if ((ret = rnp_op_verify_detached_create(&verify, pgp->context, input, signature)) != RNP_SUCCESS) { if ((ret = rnp_op_verify_detached_create(&verify, pgp->context, input, signature)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; 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) // ) != RNP_ERROR_SIGNATURE_INVALID)
// if (ret != RNP_ERROR_SIGNATURE_INVALID) { // if (ret != RNP_ERROR_SIGNATURE_INVALID) {
// const char *reason = rnp_result_to_string(ret); // 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; // goto verify_finish;
// } // }
/* now check signatures and get some info about them */ /* now check signatures and get some info about them */
if ((ret = rnp_op_verify_get_signature_count(verify, &sigcount)) != RNP_SUCCESS) { if ((ret = rnp_op_verify_get_signature_count(verify, &sigcount)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; 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) { if ((ret = rnp_op_verify_get_signature_at(verify, i, &sig)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto verify_finish;
} }
if ((ret = rnp_op_verify_signature_get_key(sig, &key)) == RNP_SUCCESS) { if ((ret = rnp_op_verify_signature_get_key(sig, &key)) == RNP_SUCCESS) {
if ((ret = rnp_key_get_keyid(key, &keyid)) != RNP_SUCCESS) { if ((ret = rnp_key_get_keyid(key, &keyid)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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); rnp_key_handle_destroy(key);
goto verify_finish; 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_key_get_signature_at(key, 0, &signature)) == RNP_SUCCESS) {
if ((ret = rnp_signature_get_keyid(signature, &keyid)) != RNP_SUCCESS) { if ((ret = rnp_signature_get_keyid(signature, &keyid)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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); rnp_key_handle_destroy(key);
goto verify_finish; goto verify_finish;
} }
@ -269,13 +269,13 @@ char *pgp__verify(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *ce
} else { } else {
if ((ret = rnp_op_verify_signature_get_handle(sig, &signature)) != RNP_SUCCESS) { if ((ret = rnp_op_verify_signature_get_handle(sig, &signature)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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; goto verify_finish;
} }
if ((ret = rnp_signature_get_keyid(signature, &keyid)) != RNP_SUCCESS) { if ((ret = rnp_signature_get_keyid(signature, &keyid)) != RNP_SUCCESS) {
const char *reason = rnp_result_to_string(ret); 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); rnp_key_handle_destroy(key);
goto verify_finish; goto verify_finish;
} }
@ -309,18 +309,18 @@ char *pgp__sign(struct t_gui_buffer *buffer, struct t_pgp *pgp, const char *sour
* message */ * message */
if (rnp_input_from_memory(&input, (uint8_t *)message, strlen(message), false) != if (rnp_input_from_memory(&input, (uint8_t *)message, strlen(message), false) !=
RNP_SUCCESS) { 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; goto sign_finish;
} }
if (rnp_output_to_memory(&output, 0) != RNP_SUCCESS) { 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; goto sign_finish;
} }
/* initialize and configure sign operation */ /* initialize and configure sign operation */
if (rnp_op_sign_detached_create(&sign, pgp->context, input, output) != RNP_SUCCESS) { 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; 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 */ /* now add signatures. First locate the signing key, then add and setup signature */
if (rnp_locate_key(pgp->context, "keyid", source, &key) != RNP_SUCCESS) { 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; goto sign_finish;
} }
if (rnp_op_sign_add_signature(sign, key, NULL) != RNP_SUCCESS) { 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; 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 */ /* finally do signing */
if (rnp_op_sign_execute(sign) != RNP_SUCCESS) { 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; goto sign_finish;
} }

@ -53,18 +53,18 @@ const char *user__as_prefix(struct t_account *account,
} }
struct t_user *user__bot_search(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; struct t_user *ptr_user;
if (!account || !bot_id) if (!account || !pgp_id)
return NULL; return NULL;
for (ptr_user = account->users; ptr_user; for (ptr_user = account->users; ptr_user;
ptr_user = ptr_user->next_user) ptr_user = ptr_user->next_user)
{ {
if (ptr_user->profile.bot_id && if (ptr_user->profile.pgp_id &&
weechat_strcasecmp(ptr_user->profile.bot_id, bot_id) == 0) weechat_strcasecmp(ptr_user->profile.pgp_id, pgp_id) == 0)
return ptr_user; return ptr_user;
} }
@ -102,15 +102,28 @@ void user__nicklist_add(struct t_account *account,
ptr_buffer = channel ? channel->buffer : account->buffer; ptr_buffer = channel ? channel->buffer : account->buffer;
ptr_group = weechat_nicklist_search_group(ptr_buffer, NULL, char *group = "...";
user->is_away ? 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, weechat_nicklist_add_nick(ptr_buffer, ptr_group,
name, name,
user->is_away ? user->is_away ?
"weechat.color.nicklist_away" : "weechat.color.nicklist_away" :
user__get_colour_for_nicklist(user), user__get_colour_for_nicklist(user),
user->is_away ? "+" : "", group,
"bar_fg", "bar_fg",
1); 1);
} }
@ -119,7 +132,7 @@ void user__nicklist_remove(struct t_account *account,
struct t_channel *channel, struct t_channel *channel,
struct t_user *user) struct t_user *user)
{ {
struct t_gui_nick_group *ptr_group; struct t_gui_nick *ptr_nick;
struct t_gui_buffer *ptr_buffer; struct t_gui_buffer *ptr_buffer;
char *name = user->profile.display_name; char *name = user->profile.display_name;
if (channel && weechat_strcasecmp(xmpp_jid_bare(account->context, 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_buffer = channel ? channel->buffer : account->buffer;
ptr_group = weechat_nicklist_search_group(ptr_buffer, NULL, if ((ptr_nick = weechat_nicklist_search_nick(ptr_buffer, NULL, name)))
user->is_away ? weechat_nicklist_remove_nick(ptr_buffer, ptr_nick);
"+" : "...");
weechat_nicklist_remove_nick(ptr_buffer,
weechat_nicklist_search_nick(ptr_buffer, ptr_group, name));
} }
struct t_user *user__new(struct t_account *account, 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.avatar_hash = NULL;
new_user->profile.status_text = 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.real_name = NULL;
new_user->profile.display_name = display_name ? new_user->profile.display_name = display_name ?
strdup(display_name) : strdup(""); strdup(display_name) : strdup("");
new_user->profile.real_name_normalized = NULL; new_user->profile.affiliation = NULL;
new_user->profile.email = NULL; new_user->profile.email = NULL;
new_user->profile.team = NULL; new_user->profile.role = NULL;
new_user->profile.bot_id = NULL; new_user->profile.pgp_id = NULL;
new_user->updated = 0; new_user->updated = 0;
new_user->is_away = 0; new_user->is_away = 0;
@ -220,18 +230,18 @@ void user__free(struct t_account *account,
free(user->profile.avatar_hash); free(user->profile.avatar_hash);
if (user->profile.status_text) if (user->profile.status_text)
free(user->profile.status_text); free(user->profile.status_text);
if (user->profile.status_emoji) if (user->profile.status)
free(user->profile.status_emoji); free(user->profile.status);
if (user->profile.real_name) if (user->profile.real_name)
free(user->profile.real_name); free(user->profile.real_name);
if (user->profile.display_name) if (user->profile.display_name)
free(user->profile.display_name); free(user->profile.display_name);
if (user->profile.real_name_normalized) if (user->profile.affiliation)
free(user->profile.real_name_normalized); free(user->profile.affiliation);
if (user->profile.email) if (user->profile.email)
free(user->profile.email); free(user->profile.email);
if (user->profile.team) if (user->profile.role)
free(user->profile.team); free(user->profile.role);
free(user); free(user);

@ -9,13 +9,13 @@ struct t_user_profile
{ {
char *avatar_hash; char *avatar_hash;
char *status_text; char *status_text;
char *status_emoji; char *status;
char *real_name; char *real_name;
char *display_name; char *display_name;
char *real_name_normalized;
char *email; char *email;
char *team; char *role;
char *bot_id; char *affiliation;
char *pgp_id;
}; };
struct t_user struct t_user
@ -41,9 +41,6 @@ const char *user__as_prefix(struct t_account *account,
struct t_user *user, struct t_user *user,
const char *name); 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, struct t_user *user__search(struct t_account *account,
const char *id); const char *id);

Loading…
Cancel
Save