omemo progress

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

@ -30,10 +30,12 @@ use_guix()
# Miscellaneous packages. # Miscellaneous packages.
ENVIRONMENTS=( ENVIRONMENTS=(
weechat # Debug runs weechat # Debug runs
profanity # Test
) )
# Environment packages. # Environment packages.
PACKAGES=( PACKAGES=(
profanity # Test
autoconf # Deps with autoreconf autoconf # Deps with autoreconf
autoconf-archive # Deps with m4 tooling autoconf-archive # Deps with m4 tooling
automake # Deps with automake automake # Deps with automake
@ -49,10 +51,9 @@ use_guix()
libxml2 # Dep (libxml2) libxml2 # Dep (libxml2)
libstrophe # Dep (strophe) libstrophe # Dep (strophe)
libgcrypt # Dep (gcrypt) libgcrypt # Dep (gcrypt)
-l libomemo.scm #libsignal-protocol-c # Dep (libsignal)
lmdb # Dep (lmdb) lmdb # Dep (lmdb)
rnp # Dep (rnpgp) rnp # Dep (rnpgp)
glib sqlite minixml libsignal-protocol-c -l libomemo.scm # Dep (libsignal)
) )
# Thanks <https://lists.gnu.org/archive/html/guix-devel/2016-09/msg00859.html> # Thanks <https://lists.gnu.org/archive/html/guix-devel/2016-09/msg00859.html>
@ -62,9 +63,11 @@ use_guix()
} }
use guix \ use guix \
--with-debug-info=profanity\
--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=libomemo-c\
--with-debug-info=lmdb\ --with-debug-info=lmdb\
--with-debug-info=rnp\ --with-debug-info=rnp\
clang:extra gdb clang:extra gdb lmdb

@ -186,8 +186,7 @@ xmpp_stanza_t *account__get_devicelist(struct t_account *account)
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(device->name), account->context, NULL, with_noop(device->name), NULL);
with_noop("weechat"));
free(device->label); free(device->label);
free(device->name); free(device->name);
@ -207,7 +206,7 @@ xmpp_stanza_t *account__get_devicelist(struct t_account *account)
account->context, NULL, children, with_noop(node)); account->context, NULL, children, with_noop(node));
children[1] = NULL; children[1] = NULL;
children[0] = stanza__iq_pubsub_publish_item( children[0] = stanza__iq_pubsub_publish_item(
account->context, NULL, children, NULL); account->context, NULL, children, with_noop("current"));
node = "eu.siacs.conversations.axolotl.devicelist"; node = "eu.siacs.conversations.axolotl.devicelist";
children[0] = stanza__iq_pubsub_publish(account->context, children[0] = stanza__iq_pubsub_publish(account->context,
NULL, children, NULL, children,

@ -11,8 +11,8 @@
#include <weechat/weechat-plugin.h> #include <weechat/weechat-plugin.h>
#include "plugin.h" #include "plugin.h"
#include "omemo.h"
#include "account.h" #include "account.h"
#include "omemo.h"
#include "user.h" #include "user.h"
#include "channel.h" #include "channel.h"
#include "input.h" #include "input.h"
@ -24,17 +24,48 @@ const char *channel__transport_name(enum t_channel_transport transport)
{ {
switch (transport) switch (transport)
{ {
case CHANNEL_TRANSPORT_PLAINTEXT: case CHANNEL_TRANSPORT_PLAIN:
return "PLAINTEXT"; return "PLAINTEXT";
case CHANNEL_TRANSPORT_OMEMO: case CHANNEL_TRANSPORT_OMEMO:
return "OMEMO"; return "OMEMO";
case CHANNEL_TRANSPORT_PGP: case CHANNEL_TRANSPORT_PGP:
return "PGP"; return "PGP";
case CHANNEL_TRANSPORT_OTR:
return "OTR";
default: default:
return NULL; return NULL;
} }
} }
void channel__set_transport(struct t_channel *channel, enum t_channel_transport transport, int force)
{
if (force)
switch (transport)
{
case CHANNEL_TRANSPORT_PLAIN:
channel->omemo.enabled = 0;
channel->pgp.enabled = 0;
break;
case CHANNEL_TRANSPORT_OMEMO:
channel->omemo.enabled = 1;
channel->pgp.enabled = 0;
break;
case CHANNEL_TRANSPORT_PGP:
channel->omemo.enabled = 0;
channel->pgp.enabled = 1;
break;
default:
break;
}
if (channel->transport != transport)
{
channel->transport = transport;
weechat_printf_date_tags(channel->buffer, 0, NULL, "%s%sTransport: %s",
weechat_prefix("network"), weechat_color("gray"),
channel__transport_name(channel->transport));
}
}
struct t_account *channel__account(struct t_channel *channel) struct t_account *channel__account(struct t_channel *channel)
{ {
struct t_account *ptr_account; struct t_account *ptr_account;
@ -82,7 +113,7 @@ struct t_gui_buffer *channel__search_buffer(struct t_account *account,
{ {
struct t_hdata *hdata_buffer; struct t_hdata *hdata_buffer;
struct t_gui_buffer *ptr_buffer; struct t_gui_buffer *ptr_buffer;
const char *ptr_type, *ptr_account_name, *ptr_channel_name; const char *ptr_type, *ptr_account_name, *ptr_remote_jid;
hdata_buffer = weechat_hdata_get("buffer"); hdata_buffer = weechat_hdata_get("buffer");
ptr_buffer = weechat_hdata_get_list(hdata_buffer, "gui_buffers"); ptr_buffer = weechat_hdata_get_list(hdata_buffer, "gui_buffers");
@ -93,18 +124,18 @@ struct t_gui_buffer *channel__search_buffer(struct t_account *account,
{ {
ptr_type = weechat_buffer_get_string(ptr_buffer, "localvar_type"); ptr_type = weechat_buffer_get_string(ptr_buffer, "localvar_type");
ptr_account_name = weechat_buffer_get_string(ptr_buffer, ptr_account_name = weechat_buffer_get_string(ptr_buffer,
"localvar_server"); "localvar_account");
ptr_channel_name = weechat_buffer_get_string(ptr_buffer, ptr_remote_jid = weechat_buffer_get_string(ptr_buffer,
"localvar_channel"); "localvar_remote_jid");
if (ptr_type && ptr_type[0] if (ptr_type && ptr_type[0]
&& ptr_account_name && ptr_account_name[0] && ptr_account_name && ptr_account_name[0]
&& ptr_channel_name && ptr_channel_name[0] && ptr_remote_jid && ptr_remote_jid[0]
&& ( (( (type == CHANNEL_TYPE_MUC)) && ( (( (type == CHANNEL_TYPE_MUC))
&& (strcmp(ptr_type, "channel") == 0)) && (strcmp(ptr_type, "room") == 0))
|| (( (type == CHANNEL_TYPE_PM)) || (( (type == CHANNEL_TYPE_PM))
&& (strcmp(ptr_type, "private") == 0))) && (strcmp(ptr_type, "private") == 0)))
&& (strcmp(ptr_account_name, account->name) == 0) && (strcmp(ptr_account_name, account->name) == 0)
&& (weechat_strcasecmp(ptr_channel_name, name) == 0)) && (weechat_strcasecmp(ptr_remote_jid, name) == 0))
{ {
return ptr_buffer; return ptr_buffer;
} }
@ -121,13 +152,13 @@ struct t_gui_buffer *channel__create_buffer(struct t_account *account,
{ {
struct t_gui_buffer *ptr_buffer; struct t_gui_buffer *ptr_buffer;
int buffer_created; int buffer_created;
const char *short_name, *localvar_channel; const char *short_name, *localvar_remote_jid;
char buffer_name[256]; char buffer_name[1024];
buffer_created = 0; buffer_created = 0;
snprintf(buffer_name, sizeof(buffer_name), snprintf(buffer_name, sizeof(buffer_name),
"xmpp.%s.%s", account->name, name); "%s.%s", account->name, name);
ptr_buffer = channel__search_buffer(account, type, name); ptr_buffer = channel__search_buffer(account, type, name);
if (ptr_buffer) if (ptr_buffer)
@ -152,12 +183,12 @@ struct t_gui_buffer *channel__create_buffer(struct t_account *account,
} }
else else
{ {
short_name = weechat_buffer_get_string (ptr_buffer, "short_name"); short_name = weechat_buffer_get_string(ptr_buffer, "short_name");
localvar_channel = weechat_buffer_get_string(ptr_buffer, localvar_remote_jid = weechat_buffer_get_string(ptr_buffer,
"localvar_channel"); "localvar_remote_jid");
if (!short_name || if (!short_name ||
(localvar_channel && (strcmp(localvar_channel, short_name) == 0))) (localvar_remote_jid && (strcmp(localvar_remote_jid, short_name) == 0)))
{ {
weechat_buffer_set(ptr_buffer, "short_name", weechat_buffer_set(ptr_buffer, "short_name",
xmpp_jid_node(account->context, name)); xmpp_jid_node(account->context, name));
@ -167,22 +198,21 @@ struct t_gui_buffer *channel__create_buffer(struct t_account *account,
account_option_set(account, ACCOUNT_OPTION_NICKNAME, account_option_set(account, ACCOUNT_OPTION_NICKNAME,
xmpp_jid_node(account->context, account_jid(account))); xmpp_jid_node(account->context, account_jid(account)));
weechat_buffer_set(ptr_buffer, "name", name);
weechat_buffer_set(ptr_buffer, "notify", weechat_buffer_set(ptr_buffer, "notify",
(type == CHANNEL_TYPE_PM) ? "3" : "1"); (type == CHANNEL_TYPE_PM) ? "3" : "1");
weechat_buffer_set(ptr_buffer, "localvar_set_type", weechat_buffer_set(ptr_buffer, "localvar_set_type",
(type == CHANNEL_TYPE_PM) ? "private" : "channel"); (type == CHANNEL_TYPE_PM) ? "private" : "channel");
weechat_buffer_set(ptr_buffer, "localvar_set_nick", weechat_buffer_set(ptr_buffer, "localvar_set_nick",
account_nickname(account)); account_nickname(account));
weechat_buffer_set(ptr_buffer, "localvar_set_server", account->name); weechat_buffer_set(ptr_buffer, "localvar_set_account", account->name);
weechat_buffer_set(ptr_buffer, "localvar_set_channel", name); weechat_buffer_set(ptr_buffer, "localvar_set_remote_jid", name);
weechat_buffer_set(ptr_buffer, "input_multiline", "1"); weechat_buffer_set(ptr_buffer, "input_multiline", "1");
if (buffer_created) if (buffer_created)
{ {
(void) weechat_hook_signal_send ("logger_backlog", (void) weechat_hook_signal_send("logger_backlog",
WEECHAT_HOOK_SIGNAL_POINTER, WEECHAT_HOOK_SIGNAL_POINTER,
ptr_buffer); ptr_buffer);
weechat_buffer_set(ptr_buffer, "input_get_unknown_commands", "1"); weechat_buffer_set(ptr_buffer, "input_get_unknown_commands", "1");
if (type != CHANNEL_TYPE_PM) if (type != CHANNEL_TYPE_PM)
{ {
@ -275,13 +305,15 @@ struct t_channel *channel__new(struct t_account *account,
new_channel->type = type; new_channel->type = type;
new_channel->id = strdup(id); new_channel->id = strdup(id);
new_channel->name = strdup(name); new_channel->name = strdup(name);
new_channel->transport = CHANNEL_TRANSPORT_PLAINTEXT; new_channel->transport = CHANNEL_TRANSPORT_PLAIN;
new_channel->pgp_id = NULL; new_channel->omemo.enabled = type == CHANNEL_TYPE_PM ? 1 : 0;
new_channel->omemo.session = 0;
new_channel->omemo.devicelist_requests = weechat_hashtable_new(64, new_channel->omemo.devicelist_requests = weechat_hashtable_new(64,
WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER, NULL, NULL); WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER, NULL, NULL);
new_channel->omemo.bundle_requests = weechat_hashtable_new(64, new_channel->omemo.bundle_requests = weechat_hashtable_new(64,
WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER, NULL, NULL); WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER, NULL, NULL);
new_channel->pgp.enabled = 1;
new_channel->pgp.id = NULL;
new_channel->otr.enabled = 0;
new_channel->topic.value = NULL; new_channel->topic.value = NULL;
new_channel->topic.creator = NULL; new_channel->topic.creator = NULL;
@ -797,8 +829,8 @@ void channel__free(struct t_account *account,
free(channel->id); free(channel->id);
if (channel->name) if (channel->name)
free(channel->name); free(channel->name);
if (channel->pgp_id) if (channel->pgp.id)
free(channel->pgp_id); free(channel->pgp.id);
if (channel->topic.value) if (channel->topic.value)
free(channel->topic.value); free(channel->topic.value);
if (channel->topic.creator) if (channel->topic.creator)
@ -994,8 +1026,8 @@ struct t_channel_member *channel__remove_member(struct t_account *account,
return member; return member;
} }
void channel__send_message(struct t_account *account, struct t_channel *channel, int channel__send_message(struct t_account *account, struct t_channel *channel,
const char *to, const char *body) const char *to, const char *body)
{ {
channel__send_reads(account, channel); channel__send_reads(account, channel);
@ -1008,30 +1040,51 @@ void channel__send_message(struct t_account *account, struct t_channel *channel,
xmpp_stanza_set_id(message, id); xmpp_stanza_set_id(message, id);
xmpp_free(account->context, id); xmpp_free(account->context, id);
if (account->omemo && channel->omemo.session >= 0) if (account->omemo && channel->omemo.enabled)
{ {
xmpp_message_set_body(message, body); xmpp_stanza_t *encrypted = omemo__encode(account, to, body);
if (!encrypted)
if (channel->transport != CHANNEL_TRANSPORT_OMEMO)
{ {
channel->transport = CHANNEL_TRANSPORT_OMEMO; weechat_printf_date_tags(channel->buffer, 0, "notify_none", "%s%s",
weechat_printf_date_tags(channel->buffer, 0, NULL, "%s%sTransport: %s", weechat_prefix("error"), "OMEMO Error");
weechat_prefix("network"), weechat_color("gray"), channel__set_transport(channel, CHANNEL_TRANSPORT_PLAIN, 1);
channel__transport_name(channel->transport)); xmpp_stanza_release(message);
return WEECHAT_RC_ERROR;
} }
xmpp_stanza_add_child(message, encrypted);
xmpp_stanza_release(encrypted);
omemo__encode(account->omemo, to, 0, body); xmpp_stanza_t *message__encryption = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__encryption, "encryption");
xmpp_stanza_set_ns(message__encryption, "urn:xmpp:eme:0");
xmpp_stanza_set_attribute(message__encryption, "namespace",
"eu.siacs.conversations.axolotl");
xmpp_stanza_set_attribute(message__encryption, "name", "OMEMO");
xmpp_stanza_add_child(message, message__encryption);
xmpp_stanza_release(message__encryption);
xmpp_message_set_body(message, OMEMO_ADVICE);
channel__set_transport(channel, CHANNEL_TRANSPORT_OMEMO, 0);
} }
else if (channel->pgp_id) else if (channel->pgp.enabled && channel->pgp.id)
{ {
xmpp_stanza_t *message__x = xmpp_stanza_new(account->context); xmpp_stanza_t *message__x = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__x, "x"); xmpp_stanza_set_name(message__x, "x");
xmpp_stanza_set_ns(message__x, "jabber:x:encrypted"); xmpp_stanza_set_ns(message__x, "jabber:x:encrypted");
xmpp_stanza_t *message__x__text = xmpp_stanza_new(account->context); xmpp_stanza_t *message__x__text = xmpp_stanza_new(account->context);
char *ciphertext = pgp__encrypt(channel->buffer, account->pgp, account_pgp_keyid(account), channel->pgp_id, body); char *ciphertext = pgp__encrypt(channel->buffer, account->pgp, account_pgp_keyid(account), channel->pgp.id, body);
if (ciphertext) if (ciphertext)
xmpp_stanza_set_text(message__x__text, ciphertext); xmpp_stanza_set_text(message__x__text, ciphertext);
else
{
weechat_printf_date_tags(channel->buffer, 0, "notify_none", "%s%s",
weechat_prefix("error"), "PGP Error");
channel__set_transport(channel, CHANNEL_TRANSPORT_PLAIN, 1);
xmpp_stanza_release(message);
return WEECHAT_RC_ERROR;
}
free(ciphertext); free(ciphertext);
xmpp_stanza_add_child(message__x, message__x__text); xmpp_stanza_add_child(message__x, message__x__text);
@ -1050,29 +1103,17 @@ void channel__send_message(struct t_account *account, struct t_channel *channel,
xmpp_message_set_body(message, PGP_ADVICE); xmpp_message_set_body(message, PGP_ADVICE);
if (ciphertext && channel->transport != CHANNEL_TRANSPORT_PGP) channel__set_transport(channel, CHANNEL_TRANSPORT_PGP, 0);
{
channel->transport = CHANNEL_TRANSPORT_PGP;
weechat_printf_date_tags(channel->buffer, 0, NULL, "%s%sTransport: %s",
weechat_prefix("network"), weechat_color("gray"),
channel__transport_name(channel->transport));
}
} }
else else
{ {
xmpp_message_set_body(message, body); xmpp_message_set_body(message, body);
if (channel->transport != CHANNEL_TRANSPORT_PLAINTEXT) channel__set_transport(channel, CHANNEL_TRANSPORT_PLAIN, 0);
{
channel->transport = CHANNEL_TRANSPORT_PLAINTEXT;
weechat_printf_date_tags(channel->buffer, 0, NULL, "%s%sTransport: %s",
weechat_prefix("network"), weechat_color("gray"),
channel__transport_name(channel->transport));
}
} }
char *url = strstr(body, "http"); char *url = strstr(body, "http");
if (url) if (url && channel->transport == CHANNEL_TRANSPORT_PLAIN)
{ {
xmpp_stanza_t *message__x = xmpp_stanza_new(account->context); xmpp_stanza_t *message__x = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__x, "x"); xmpp_stanza_set_name(message__x, "x");
@ -1095,11 +1136,28 @@ void channel__send_message(struct t_account *account, struct t_channel *channel,
xmpp_stanza_t *message__active = xmpp_stanza_new(account->context); xmpp_stanza_t *message__active = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__active, "active"); xmpp_stanza_set_name(message__active, "active");
xmpp_stanza_set_ns(message__active, "http://jabber./org/protocol/chatstates"); xmpp_stanza_set_ns(message__active, "http://jabber.org/protocol/chatstates");
xmpp_stanza_add_child(message, message__active); xmpp_stanza_add_child(message, message__active);
xmpp_stanza_release(message__active); xmpp_stanza_release(message__active);
xmpp_stanza_t *message__request = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__request, "request");
xmpp_stanza_set_ns(message__request, "urn:xmpp:receipts");
xmpp_stanza_add_child(message, message__request);
xmpp_stanza_release(message__request);
xmpp_stanza_t *message__markable = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__markable, "markable");
xmpp_stanza_set_ns(message__markable, "urn:xmpp:chat-markers:0");
xmpp_stanza_add_child(message, message__markable);
xmpp_stanza_release(message__markable);
xmpp_stanza_t *message__store = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__store, "store");
xmpp_stanza_set_ns(message__store, "urn:xmpp:hints");
xmpp_stanza_add_child(message, message__store);
xmpp_stanza_release(message__store);
xmpp_send(account->connection, message); xmpp_send(account->connection, message);
xmpp_stanza_release(message); xmpp_stanza_release(message);
if (channel->type != CHANNEL_TYPE_MUC) if (channel->type != CHANNEL_TYPE_MUC)
@ -1108,6 +1166,8 @@ void channel__send_message(struct t_account *account, struct t_channel *channel,
"%s\t%s", "%s\t%s",
user__as_prefix_raw(account, account_jid(account)), user__as_prefix_raw(account, account_jid(account)),
body); body);
return WEECHAT_RC_OK;
} }
void channel__send_reads(struct t_account *account, struct t_channel *channel) void channel__send_reads(struct t_account *account, struct t_channel *channel)

@ -15,9 +15,11 @@ enum t_channel_type
enum t_channel_transport enum t_channel_transport
{ {
CHANNEL_TRANSPORT_PLAINTEXT, CHANNEL_TRANSPORT_PLAIN,
CHANNEL_TRANSPORT_OMEMO, CHANNEL_TRANSPORT_OMEMO,
CHANNEL_TRANSPORT_PGP, CHANNEL_TRANSPORT_PGP,
CHANNEL_TRANSPORT_OTR,
CHANNEL_TRANSPORT_OX,
}; };
struct t_channel_typing struct t_channel_typing
@ -63,12 +65,18 @@ struct t_channel
char *id; char *id;
char *name; char *name;
enum t_channel_transport transport; enum t_channel_transport transport;
char *pgp_id;
struct { struct {
int session; int enabled;
struct t_hashtable *devicelist_requests; struct t_hashtable *devicelist_requests;
struct t_hashtable *bundle_requests; struct t_hashtable *bundle_requests;
} omemo; } omemo;
struct {
int enabled;
char *id;
} pgp;
struct {
int enabled;
} otr;
struct t_channel_topic topic; struct t_channel_topic topic;
@ -97,6 +105,9 @@ struct t_channel
const char *channel__transport_name(enum t_channel_transport transport); const char *channel__transport_name(enum t_channel_transport transport);
void channel__set_transport(struct t_channel *channel,
enum t_channel_transport transport, int force);
struct t_account *channel__account(struct t_channel *channel); struct t_account *channel__account(struct t_channel *channel);
struct t_channel *channel__search(struct t_account *account, struct t_channel *channel__search(struct t_account *account,
@ -184,8 +195,8 @@ struct t_channel_member *channel__remove_member(struct t_account *account,
struct t_channel *channel, struct t_channel *channel,
const char *id, const char *reason); const char *id, const char *reason);
void channel__send_message(struct t_account *account, struct t_channel *channel, int channel__send_message(struct t_account *account, struct t_channel *channel,
const char *to, const char *body); const char *to, const char *body);
void channel__send_reads(struct t_account *account, struct t_channel *channel); void channel__send_reads(struct t_account *account, struct t_channel *channel);

@ -502,7 +502,7 @@ int command__enter(const void *pointer, void *data,
} }
else else
{ {
const char *buffer_jid = weechat_buffer_get_string(buffer, "localvar_channel"); const char *buffer_jid = weechat_buffer_get_string(buffer, "localvar_remote_jid");
pres_jid = xmpp_jid_new( pres_jid = xmpp_jid_new(
ptr_account->context, ptr_account->context,
@ -757,6 +757,41 @@ int command__mam(const void *pointer, void *data,
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
int command__omemo(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;
(void) pointer;
(void) data;
(void) argc;
(void) argv;
(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, "omemo");
return WEECHAT_RC_OK;
}
ptr_channel->omemo.enabled = 1;
ptr_channel->pgp.enabled = 0;
channel__set_transport(ptr_channel, CHANNEL_TRANSPORT_OMEMO, 0);
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)
@ -787,13 +822,48 @@ int command__pgp(const void *pointer, void *data,
{ {
keyid = argv_eol[1]; keyid = argv_eol[1];
ptr_channel->pgp_id = strdup(keyid); ptr_channel->pgp.id = strdup(keyid);
} }
else ptr_channel->omemo.enabled = 0;
ptr_channel->pgp.enabled = 1;
channel__set_transport(ptr_channel, CHANNEL_TRANSPORT_PGP, 0);
return WEECHAT_RC_OK;
}
int command__plain(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;
(void) pointer;
(void) data;
(void) argc;
(void) argv;
(void) argv_eol;
buffer__get_account_and_channel(buffer, &ptr_account, &ptr_channel);
if (!ptr_account)
return WEECHAT_RC_ERROR;
if (!ptr_channel)
{ {
ptr_channel->pgp_id = NULL; weechat_printf(
ptr_account->buffer,
_("%s%s: \"%s\" command can not be executed on a account buffer"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME, "plain");
return WEECHAT_RC_OK;
} }
ptr_channel->omemo.enabled = 0;
ptr_channel->pgp.enabled = 0;
channel__set_transport(ptr_channel, CHANNEL_TRANSPORT_PLAIN, 0);
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
@ -811,6 +881,9 @@ int command__xml(const void *pointer, void *data,
buffer__get_account_and_channel(buffer, &ptr_account, &ptr_channel); buffer__get_account_and_channel(buffer, &ptr_account, &ptr_channel);
if (!ptr_account)
return WEECHAT_RC_ERROR;
if (!ptr_account->is_connected) if (!ptr_account->is_connected)
{ {
weechat_printf(buffer, weechat_printf(buffer,
@ -822,7 +895,7 @@ int command__xml(const void *pointer, void *data,
if (argc > 1) if (argc > 1)
{ {
stanza = xmpp_stanza_new_from_string(ptr_account->context, stanza = xmpp_stanza_new_from_string(ptr_account->context,
argv_eol[0]); argv_eol[1]);
if (!stanza) if (!stanza)
return WEECHAT_RC_ERROR; return WEECHAT_RC_ERROR;
@ -907,15 +980,33 @@ void command__init()
if (!hook) if (!hook)
weechat_printf(NULL, "Failed to setup command /mam"); weechat_printf(NULL, "Failed to setup command /mam");
hook = weechat_hook_command(
"omemo",
N_("set the current buffer to use omemo encryption"),
N_(""),
N_(""),
NULL, &command__omemo, NULL, NULL);
if (!hook)
weechat_printf(NULL, "Failed to setup command /omemo");
hook = weechat_hook_command( hook = weechat_hook_command(
"pgp", "pgp",
N_("set the target pgp key for the current channel"), N_("set the current buffer to use pgp encryption (with a given target pgp key)"),
N_("<keyid>"), N_("<keyid>"),
N_("keyid: recipient keyid"), N_("keyid: recipient keyid"),
NULL, &command__pgp, NULL, NULL); NULL, &command__pgp, NULL, NULL);
if (!hook) if (!hook)
weechat_printf(NULL, "Failed to setup command /pgp"); weechat_printf(NULL, "Failed to setup command /pgp");
hook = weechat_hook_command(
"plain",
N_("set the current buffer to use no encryption"),
N_(""),
N_(""),
NULL, &command__plain, NULL, NULL);
if (!hook)
weechat_printf(NULL, "Failed to setup command /plain");
hook = weechat_hook_command( hook = weechat_hook_command(
"xml", "xml",
N_("send a raw xml stanza"), N_("send a raw xml stanza"),

@ -25,6 +25,7 @@
void connection__init() void connection__init()
{ {
srand(time(NULL));
xmpp_initialize(); xmpp_initialize();
} }
@ -87,10 +88,11 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void
struct t_user *user; struct t_user *user;
struct t_channel *channel; struct t_channel *channel;
xmpp_stanza_t *pres__x_signed, *pres__x_muc_user, *show, *idle, *pres__x__item, *pres__c, *pres__status; xmpp_stanza_t *pres__x_signed, *pres__x_muc_user, *show, *idle, *pres__x__item, *pres__c, *pres__status;
const char *from, *from_bare, *from_res, *type, *role = NULL, *affiliation = NULL, *jid = NULL; const char *to, *from, *from_bare, *from_res, *type, *role = NULL, *affiliation = NULL, *jid = NULL;
const char *show__text = NULL, *idle__since = NULL, *certificate = NULL, *node = NULL, *ver = NULL; const char *show__text = NULL, *idle__since = NULL, *certificate = NULL, *node = NULL, *ver = NULL;
char *clientid = NULL, *status; char *clientid = NULL, *status;
to = xmpp_stanza_get_to(stanza);
from = xmpp_stanza_get_from(stanza); from = xmpp_stanza_get_from(stanza);
if (from == NULL) if (from == NULL)
return 1; return 1;
@ -115,9 +117,20 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void
ver = xmpp_stanza_get_attribute(pres__c, "ver"); ver = xmpp_stanza_get_attribute(pres__c, "ver");
if (node && ver) if (node && ver)
{ {
int len = strlen(node)+1+strlen(ver); int len = strlen(node)+1+strlen(ver) + 1;
clientid = malloc(sizeof(char)*len); clientid = malloc(sizeof(char)*len);
snprintf(clientid, len, "%s#%s", node, ver); snprintf(clientid, len, "%s#%s", node, ver);
xmpp_stanza_t *children[2] = {NULL};
children[0] = stanza__iq_pubsub_items(account->context, NULL,
"eu.siacs.conversations.axolotl.devicelist");
children[0] = stanza__iq_pubsub(account->context, NULL,
children, with_noop("http://jabber.org/protocol/pubsub"));
children[0] = stanza__iq(account->context, NULL, children, NULL,
strdup("fetch2"), to ? strdup(to) : NULL, strdup(from_bare),
strdup("get"));
xmpp_send(conn, children[0]);
xmpp_stanza_release(children[0]);
} }
} }
pres__status = xmpp_stanza_get_child_by_name(stanza, "status"); pres__status = xmpp_stanza_get_child_by_name(stanza, "status");
@ -133,8 +146,60 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void
for (pres__x__item = xmpp_stanza_get_children(pres__x_muc_user); for (pres__x__item = xmpp_stanza_get_children(pres__x_muc_user);
pres__x__item; pres__x__item = xmpp_stanza_get_next(pres__x__item)) pres__x__item; pres__x__item = xmpp_stanza_get_next(pres__x__item))
{ {
if (weechat_strcasecmp(xmpp_stanza_get_name(pres__x__item), "item") != 0) const char *pres__x__item__name = xmpp_stanza_get_name(pres__x__item);
if (weechat_strcasecmp(pres__x__item__name, "item") != 0)
{
if (weechat_strcasecmp(pres__x__item__name, "status") == 0)
{
const char *pres__x__status__code = xmpp_stanza_get_attribute(
pres__x__item, "code");
switch (strtol(pres__x__status__code, NULL, 10))
{
case 100: // Non-Anonymous: [message | Entering a room]: Inform user that any occupant is allowed to see the user's full JID
weechat_buffer_set(channel->buffer, "notify", "2");
break;
case 101: // : [message (out of band) | Affiliation change]: Inform user that his or her affiliation changed while not in the room
break;
case 102: // : [message | Configuration change]: Inform occupants that room now shows unavailable members
break;
case 103: // : [message | Configuration change]: Inform occupants that room now does not show unavailable members
break;
case 104: // : [message | Configuration change]: Inform occupants that a non-privacy-related room configuration change has occurred
break;
case 110: // Self-Presence: [presence | Any room presence]: Inform user that presence refers to one of its own room occupants
break;
case 170: // Logging Active: [message or initial presence | Configuration change]: Inform occupants that room logging is now enabled
break;
case 171: // : [message | Configuration change]: Inform occupants that room logging is now disabled
break;
case 172: // : [message | Configuration change]: Inform occupants that the room is now non-anonymous
break;
case 173: // : [message | Configuration change]: Inform occupants that the room is now semi-anonymous
break;
case 174: // : [message | Configuration change]: Inform occupants that the room is now fully-anonymous
break;
case 201: // : [presence | Entering a room]: Inform user that a new room has been created
break;
case 210: // Nick Modified: [presence | Entering a room]: Inform user that the service has assigned or modified the occupant's roomnick
break;
case 301: // : [presence | Removal from room]: Inform user that he or she has been banned from the room
break;
case 303: // : [presence | Exiting a room]: Inform all occupants of new room nickname
break;
case 307: // : [presence | Removal from room]: Inform user that he or she has been kicked from the room
break;
case 321: // : [presence | Removal from room]: Inform user that he or she is being removed from the room because of an affiliation change
break;
case 322: // : [presence | Removal from room]: Inform user that he or she is being removed from the room because the room has been changed to members-only and the user is not a member
break;
case 332: // : [presence | Removal from room]: Inform user that he or she is being removed from the room because of a system shutdown
break;
default:
break;
}
}
continue; continue;
}
role = xmpp_stanza_get_attribute(pres__x__item, "role"); role = xmpp_stanza_get_attribute(pres__x__item, "role");
affiliation = xmpp_stanza_get_attribute(pres__x__item, "affiliation"); affiliation = xmpp_stanza_get_attribute(pres__x__item, "affiliation");
@ -156,7 +221,7 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void
{ {
user->profile.pgp_id = pgp__verify(channel->buffer, account->pgp, certificate); 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 = user->profile.pgp_id; channel->pgp.id = user->profile.pgp_id;
} }
if (channel) if (channel)
@ -185,7 +250,7 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void
{ {
user->profile.pgp_id = pgp__verify(channel->buffer, account->pgp, certificate); 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 = user->profile.pgp_id; channel->pgp.id = user->profile.pgp_id;
} }
if (channel) if (channel)
@ -328,8 +393,8 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
{ {
if (account->omemo) if (account->omemo)
{ {
omemo__handle_devicelist(account->omemo, from, omemo__handle_devicelist(account->omemo,
items); from ? from : account_jid(account), items);
} }
children = malloc(sizeof(*children) * (3 + 1)); children = malloc(sizeof(*children) * (3 + 1));
@ -355,9 +420,11 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
children[0] = children[0] =
stanza__iq_pubsub(account->context, NULL, children, stanza__iq_pubsub(account->context, NULL, children,
with_noop("http://jabber.org/protocol/pubsub")); with_noop("http://jabber.org/protocol/pubsub"));
char *uuid = xmpp_uuid_gen(account->context);
children[0] = children[0] =
stanza__iq(account->context, NULL, children, NULL, strdup("fetch1"), stanza__iq(account->context, NULL, children, NULL, uuid,
strdup(to), strdup(from), strdup("get")); strdup(to), strdup(from), strdup("get"));
xmpp_free(account->context, uuid);
xmpp_send(conn, children[0]); xmpp_send(conn, children[0]);
xmpp_stanza_release(children[0]); xmpp_stanza_release(children[0]);
@ -457,7 +524,7 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
"eu.siacs.conversations.axolotl"); "eu.siacs.conversations.axolotl");
if (encrypted && account->omemo) if (encrypted && account->omemo)
{ {
omemo__decode(account->omemo, from_bare, encrypted); cleartext = omemo__decode(account, from_bare, encrypted);
} }
x = xmpp_stanza_get_child_by_name_and_ns(stanza, "x", "jabber:x:encrypted"); x = xmpp_stanza_get_child_by_name_and_ns(stanza, "x", "jabber:x:encrypted");
intext = xmpp_stanza_get_text(body); intext = xmpp_stanza_get_text(body);
@ -650,9 +717,9 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
weechat_prefix("network"), weechat_color("gray"), weechat_prefix("network"), weechat_color("gray"),
channel__transport_name(channel->transport)); channel__transport_name(channel->transport));
} }
else if (!x && text == intext && channel->transport != CHANNEL_TRANSPORT_PLAINTEXT) else if (!x && text == intext && channel->transport != CHANNEL_TRANSPORT_PLAIN)
{ {
channel->transport = CHANNEL_TRANSPORT_PLAINTEXT; channel->transport = CHANNEL_TRANSPORT_PLAIN;
weechat_printf_date_tags(channel->buffer, date, NULL, "%s%sTransport: %s", weechat_printf_date_tags(channel->buffer, date, NULL, "%s%sTransport: %s",
weechat_prefix("network"), weechat_color("gray"), weechat_prefix("network"), weechat_color("gray"),
channel__transport_name(channel->transport)); channel__transport_name(channel->transport));
@ -682,232 +749,199 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
return 1; return 1;
} }
xmpp_stanza_t *connection__get_caps(xmpp_stanza_t *reply, struct t_account *account, char **hash)
{
xmpp_stanza_t *query = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(query, "query");
xmpp_stanza_set_ns(query, "http://jabber.org/protocol/disco#info");
char *client_name = weechat_string_eval_expression(
"weechat ${info:version}", NULL, NULL, NULL);
char **serial = weechat_string_dyn_alloc(256);
weechat_string_dyn_concat(serial, "client/pc//", -1);
weechat_string_dyn_concat(serial, client_name, -1);
weechat_string_dyn_concat(serial, "<", -1);
xmpp_stanza_t *identity = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(identity, "identity");
xmpp_stanza_set_attribute(identity, "category", "client");
xmpp_stanza_set_attribute(identity, "name", client_name);
free(client_name);
xmpp_stanza_set_attribute(identity, "type", "pc");
xmpp_stanza_add_child(query, identity);
xmpp_stanza_release(identity);
xmpp_stanza_t *feature = NULL;
#define FEATURE(NS) \
feature = xmpp_stanza_new(account->context); \
xmpp_stanza_set_name(feature, "feature"); \
xmpp_stanza_set_attribute(feature, "var", NS); \
xmpp_stanza_add_child(query, feature); \
xmpp_stanza_release(feature); \
weechat_string_dyn_concat(serial, NS, -1); \
weechat_string_dyn_concat(serial, "<", -1);
FEATURE("eu.siacs.conversations.axolotl.devicelist+notify");
FEATURE("http://jabber.org/protocol/caps");
FEATURE("http://jabber.org/protocol/chatstates");
FEATURE("http://jabber.org/protocol/disco#info");
FEATURE("http://jabber.org/protocol/disco#items");
FEATURE("http://jabber.org/protocol/muc");
FEATURE("http://jabber.org/protocol/nick+notify");
FEATURE("jabber:iq:version");
FEATURE("jabber:x:conference");
FEATURE("jabber:x:oob");
FEATURE("storage:bookmarks+notify");
FEATURE("urn:xmpp:avatar:metadata+notify");
FEATURE("urn:xmpp:chat-markers:0");
FEATURE("urn:xmpp:idle:1");
//FEATURE("urn:xmpp:jingle-message:0");
//FEATURE("urn:xmpp:jingle:1");
//FEATURE("urn:xmpp:jingle:apps:dtls:0");
//FEATURE("urn:xmpp:jingle:apps:file-transfer:3");
//FEATURE("urn:xmpp:jingle:apps:file-transfer:4");
//FEATURE("urn:xmpp:jingle:apps:file-transfer:5");
//FEATURE("urn:xmpp:jingle:apps:rtp:1");
//FEATURE("urn:xmpp:jingle:apps:rtp:audio");
//FEATURE("urn:xmpp:jingle:apps:rtp:video");
//FEATURE("urn:xmpp:jingle:jet-omemo:0");
//FEATURE("urn:xmpp:jingle:jet:0");
//FEATURE("urn:xmpp:jingle:transports:ibb:1");
//FEATURE("urn:xmpp:jingle:transports:ice-udp:1");
//FEATURE("urn:xmpp:jingle:transports:s5b:1");
FEATURE("urn:xmpp:message-correct:0");
FEATURE("urn:xmpp:ping");
FEATURE("urn:xmpp:receipts");
FEATURE("urn:xmpp:time");
#undef FEATURE
xmpp_stanza_t *x = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(x, "x");
xmpp_stanza_set_ns(x, "jabber:x:data");
xmpp_stanza_set_attribute(x, "type", "result");
static struct utsname osinfo;
if (uname(&osinfo) < 0)
{
*osinfo.sysname = 0;
*osinfo.release = 0;
}
xmpp_stanza_t *field, *value, *text;
// This is utter bullshit, TODO: anything but this.
#define FEATURE1(VAR, TYPE, VALUE) \
field = xmpp_stanza_new(account->context); \
xmpp_stanza_set_name(field, "field"); \
xmpp_stanza_set_attribute(field, "var", VAR); \
if(TYPE) xmpp_stanza_set_attribute(field, "type", TYPE); \
value = xmpp_stanza_new(account->context); \
xmpp_stanza_set_name(value, "value"); \
text = xmpp_stanza_new(account->context); \
xmpp_stanza_set_text(text, VALUE); \
xmpp_stanza_add_child(value, text); \
xmpp_stanza_release(text); \
xmpp_stanza_add_child(field, value); \
xmpp_stanza_release(value); \
xmpp_stanza_add_child(x, field); \
xmpp_stanza_release(field); \
if (strcmp(VAR, "FORM_TYPE") == 0) { \
weechat_string_dyn_concat(serial, VAR, -1); \
weechat_string_dyn_concat(serial, "<", -1); \
} \
weechat_string_dyn_concat(serial, VALUE, -1); \
weechat_string_dyn_concat(serial, "<", -1);
#define FEATURE2(VAR, TYPE, VALUE1, VALUE2) \
field = xmpp_stanza_new(account->context); \
xmpp_stanza_set_name(field, "field"); \
xmpp_stanza_set_attribute(field, "var", VAR); \
xmpp_stanza_set_attribute(field, "type", TYPE); \
value = xmpp_stanza_new(account->context); \
xmpp_stanza_set_name(value, "value"); \
text = xmpp_stanza_new(account->context); \
xmpp_stanza_set_text(text, VALUE1); \
xmpp_stanza_add_child(value, text); \
xmpp_stanza_release(text); \
xmpp_stanza_add_child(field, value); \
xmpp_stanza_release(value); \
value = xmpp_stanza_new(account->context); \
xmpp_stanza_set_name(value, "value"); \
text = xmpp_stanza_new(account->context); \
xmpp_stanza_set_text(text, VALUE2); \
xmpp_stanza_add_child(value, text); \
xmpp_stanza_release(text); \
xmpp_stanza_add_child(field, value); \
xmpp_stanza_release(value); \
xmpp_stanza_add_child(x, field); \
xmpp_stanza_release(field); \
weechat_string_dyn_concat(serial, VAR, -1); \
weechat_string_dyn_concat(serial, "<", -1); \
weechat_string_dyn_concat(serial, VALUE1, -1); \
weechat_string_dyn_concat(serial, "<", -1); \
weechat_string_dyn_concat(serial, VALUE2, -1); \
weechat_string_dyn_concat(serial, "<", -1);
FEATURE1("FORM_TYPE", "hidden", "urn:xmpp:dataforms:softwareinfo");
FEATURE2("ip_version", "text-multi", "ipv4", "ipv6");
FEATURE1("os", NULL, osinfo.sysname);
FEATURE1("os_version", NULL, osinfo.release);
FEATURE1("software", NULL, "weechat");
FEATURE1("software_version", NULL, weechat_info_get("version", NULL));
#undef FEATURE1
#undef FEATURE2
xmpp_stanza_add_child(query, x);
xmpp_stanza_release(x);
xmpp_stanza_set_type(reply, "result");
xmpp_stanza_add_child(reply, query);
weechat_printf(NULL, "verstr: %s", *serial);
unsigned char digest[20];
xmpp_sha1_t *sha1 = xmpp_sha1_new(account->context);
xmpp_sha1_update(sha1, (unsigned char*)*serial, strlen(*serial));
xmpp_sha1_final(sha1);
weechat_string_dyn_free(serial, 1);
xmpp_sha1_to_digest(sha1, digest);
xmpp_sha1_free(sha1);
if (hash)
{
char *cap_hash = xmpp_base64_encode(account->context, digest, 20);
*hash = strdup(cap_hash);
xmpp_free(account->context, cap_hash);
weechat_printf(NULL, "verhash: %s", *hash);
}
return reply;
}
int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata) int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{ {
struct t_account *account = (struct t_account *)userdata; struct t_account *account = (struct t_account *)userdata;
xmpp_stanza_t *reply, *query, *identity, *feature, *x, *field, *value, *text, *fin; xmpp_stanza_t *reply, *query, *text, *fin;
xmpp_stanza_t *pubsub, *items, *item, *list, *bundle, *device; xmpp_stanza_t *pubsub, *items, *item, *list, *bundle, *device;
xmpp_stanza_t *storage, *conference, *nick; xmpp_stanza_t *storage, *conference, *nick;
static struct utsname osinfo;
const char *id = xmpp_stanza_get_id(stanza); const char *id = xmpp_stanza_get_id(stanza);
const char *from = xmpp_stanza_get_from(stanza); const char *from = xmpp_stanza_get_from(stanza);
const char *to = xmpp_stanza_get_to(stanza);
query = xmpp_stanza_get_child_by_name_and_ns( query = xmpp_stanza_get_child_by_name_and_ns(
stanza, "query", "http://jabber.org/protocol/disco#info"); stanza, "query", "http://jabber.org/protocol/disco#info");
const char *type = xmpp_stanza_get_attribute(stanza, "type"); const char *type = xmpp_stanza_get_attribute(stanza, "type");
if (query && type && weechat_strcasecmp(type, "get") == 0) if (query && type)
{ {
char *client_name; if (weechat_strcasecmp(type, "get") == 0)
reply = xmpp_stanza_reply(stanza);
xmpp_stanza_set_type(reply, "result");
client_name = weechat_string_eval_expression("weechat ${info:version}",
NULL, NULL, NULL);
identity = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(identity, "identity");
xmpp_stanza_set_attribute(identity, "category", "client");
xmpp_stanza_set_attribute(identity, "name", client_name);
xmpp_stanza_set_attribute(identity, "type", "pc");
xmpp_stanza_add_child(query, identity);
xmpp_stanza_release(identity);
#define FEATURE(ns) \
feature = xmpp_stanza_new(account->context); \
xmpp_stanza_set_name(feature, "feature"); \
xmpp_stanza_set_attribute(feature, "var", ns); \
xmpp_stanza_add_child(query, feature); \
xmpp_stanza_release(feature);
FEATURE("eu.siacs.conversations.axolotl.devicelist+notify");
FEATURE("http://jabber.org/protocol/caps");
FEATURE("http://jabber.org/protocol/chatstates");
FEATURE("http://jabber.org/protocol/disco#info");
FEATURE("http://jabber.org/protocol/disco#items");
FEATURE("http://jabber.org/protocol/muc");
FEATURE("http://jabber.org/protocol/nick+notify");
FEATURE("jabber:iq:version");
FEATURE("jabber:x:conference");
FEATURE("jabber:x:oob");
FEATURE("storage:bookmarks+notify");
FEATURE("urn:xmpp:avatar:metadata+notify");
FEATURE("urn:xmpp:chat-markers:0");
FEATURE("urn:xmpp:idle:1");
//FEATURE("urn:xmpp:jingle-message:0");
//FEATURE("urn:xmpp:jingle:1");
//FEATURE("urn:xmpp:jingle:apps:dtls:0");
//FEATURE("urn:xmpp:jingle:apps:file-transfer:3");
//FEATURE("urn:xmpp:jingle:apps:file-transfer:4");
//FEATURE("urn:xmpp:jingle:apps:file-transfer:5");
//FEATURE("urn:xmpp:jingle:apps:rtp:1");
//FEATURE("urn:xmpp:jingle:apps:rtp:audio");
//FEATURE("urn:xmpp:jingle:apps:rtp:video");
//FEATURE("urn:xmpp:jingle:jet-omemo:0");
//FEATURE("urn:xmpp:jingle:jet:0");
//FEATURE("urn:xmpp:jingle:transports:ibb:1");
//FEATURE("urn:xmpp:jingle:transports:ice-udp:1");
//FEATURE("urn:xmpp:jingle:transports:s5b:1");
FEATURE("urn:xmpp:message-correct:0");
FEATURE("urn:xmpp:ping");
FEATURE("urn:xmpp:receipts");
FEATURE("urn:xmpp:time");
#undef FEATURE
x = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(x, "x");
xmpp_stanza_set_ns(x, "jabber:x:data");
xmpp_stanza_set_attribute(x, "type", "result");
if (uname(&osinfo) < 0)
{
*osinfo.sysname = 0;
*osinfo.release = 0;
}
// This is utter bullshit, TODO: anything but this.
{ {
field = xmpp_stanza_new(account->context); reply = connection__get_caps(xmpp_stanza_reply(stanza), account, NULL);
xmpp_stanza_set_name(field, "field");
xmpp_stanza_set_attribute(field, "var", "FORM_TYPE");
xmpp_stanza_set_attribute(field, "type", "hidden");
value = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(value, "value");
text = xmpp_stanza_new(account->context); xmpp_send(conn, reply);
xmpp_stanza_set_text(text, "urn:xmpp:dataforms:softwareinfo"); xmpp_stanza_release(reply);
xmpp_stanza_add_child(value, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(field, value);
xmpp_stanza_release(value);
xmpp_stanza_add_child(x, field);
xmpp_stanza_release(field);
} }
if (weechat_strcasecmp(type, "result") == 0)
{ {
field = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(field, "field");
xmpp_stanza_set_attribute(field, "var", "ip_version");
xmpp_stanza_set_attribute(field, "type", "text-multi");
value = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(value, "value");
text = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(text, "ipv4");
xmpp_stanza_add_child(value, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(field, value);
xmpp_stanza_release(value);
value = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(value, "value");
text = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(text, "ipv6");
xmpp_stanza_add_child(value, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(field, value);
xmpp_stanza_release(value);
xmpp_stanza_add_child(x, field);
xmpp_stanza_release(field);
} }
{
field = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(field, "field");
xmpp_stanza_set_attribute(field, "var", "os");
value = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(value, "value");
text = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(text, osinfo.sysname);
xmpp_stanza_add_child(value, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(field, value);
xmpp_stanza_release(value);
xmpp_stanza_add_child(x, field);
xmpp_stanza_release(field);
}
{
field = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(field, "field");
xmpp_stanza_set_attribute(field, "var", "os_version");
value = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(value, "value");
text = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(text, osinfo.release);
xmpp_stanza_add_child(value, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(field, value);
xmpp_stanza_release(value);
xmpp_stanza_add_child(x, field);
xmpp_stanza_release(field);
}
{
field = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(field, "field");
xmpp_stanza_set_attribute(field, "var", "software");
value = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(value, "value");
text = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(text, "weechat");
xmpp_stanza_add_child(value, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(field, value);
xmpp_stanza_release(value);
xmpp_stanza_add_child(x, field);
xmpp_stanza_release(field);
}
{
field = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(field, "field");
xmpp_stanza_set_attribute(field, "var", "software_version");
value = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(value, "value");
text = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(text, weechat_info_get("version", NULL));
xmpp_stanza_add_child(value, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(field, value);
xmpp_stanza_release(value);
xmpp_stanza_add_child(x, field);
xmpp_stanza_release(field);
}
xmpp_stanza_add_child(query, x);
xmpp_stanza_release(x);
xmpp_stanza_add_child(reply, query);
xmpp_send(conn, reply);
xmpp_stanza_release(reply);
free(client_name);
} }
pubsub = xmpp_stanza_get_child_by_name_and_ns( pubsub = xmpp_stanza_get_child_by_name_and_ns(
@ -926,14 +960,47 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd
{ {
item = xmpp_stanza_get_child_by_name(items, "item"); item = xmpp_stanza_get_child_by_name(items, "item");
if (item) if (item)
item_id = xmpp_stanza_get_id(item);
if (item && item_id && weechat_strcasecmp(item_id, "current") == 0)
{ {
item_id = xmpp_stanza_get_id(item);
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 && account->omemo) if (list && account->omemo)
{ {
omemo__handle_devicelist(account->omemo, from, items); omemo__handle_devicelist(account->omemo,
from ? from : account_jid(account), items);
xmpp_stanza_t *children[2] = {NULL};
for (device = xmpp_stanza_get_children(list);
device; device = xmpp_stanza_get_next(device))
{
const char *name = xmpp_stanza_get_name(device);
if (weechat_strcasecmp(name, "device") != 0)
continue;
const char *device_id = xmpp_stanza_get_id(device);
char bundle_node[128] = {0};
snprintf(bundle_node, sizeof(bundle_node),
"eu.siacs.conversations.axolotl.bundles:%s",
device_id);
children[1] = NULL;
children[0] =
stanza__iq_pubsub_items(account->context, NULL,
strdup(bundle_node));
children[0] =
stanza__iq_pubsub(account->context, NULL, children,
with_noop("http://jabber.org/protocol/pubsub"));
char *uuid = xmpp_uuid_gen(account->context);
children[0] =
stanza__iq(account->context, NULL, children, NULL, uuid,
to ? strdup(to) : NULL, from ? strdup(from) : NULL,
strdup("get"));
xmpp_free(account->context, uuid);
xmpp_send(conn, children[0]);
xmpp_stanza_release(children[0]);
}
if (weechat_strcasecmp(account_jid(account), from) == 0) if (weechat_strcasecmp(account_jid(account), from) == 0)
{ {
@ -975,6 +1042,11 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd
} }
reply = account__get_devicelist(account); reply = account__get_devicelist(account);
char *uuid = xmpp_uuid_gen(account->context);
xmpp_stanza_set_id(reply, uuid);
xmpp_free(account->context, uuid);
xmpp_stanza_set_attribute(reply, "to", from);
xmpp_stanza_set_attribute(reply, "from", to);
xmpp_send(conn, reply); xmpp_send(conn, reply);
xmpp_stanza_release(reply); xmpp_stanza_release(reply);
} }
@ -997,7 +1069,8 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd
strlen("eu.siacs.conversations.axolotl.bundles:"); strlen("eu.siacs.conversations.axolotl.bundles:");
if (account->omemo && strlen(items_node) > node_prefix) if (account->omemo && strlen(items_node) > node_prefix)
{ {
omemo__handle_bundle(account->omemo, from, omemo__handle_bundle(account->omemo,
from ? from : account_jid(account),
strtol(items_node+node_prefix, strtol(items_node+node_prefix,
NULL, 10), NULL, 10),
items); items);
@ -1046,6 +1119,12 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd
weechat_string_dyn_concat(command, intext, -1); weechat_string_dyn_concat(command, intext, -1);
} }
weechat_command(account->buffer, *command); weechat_command(account->buffer, *command);
struct t_channel *ptr_channel =
channel__search(account, jid);
struct t_gui_buffer *ptr_buffer =
ptr_channel ? ptr_channel->buffer : NULL;
if (ptr_buffer)
weechat_buffer_set(ptr_buffer, "short_name", name);
weechat_string_dyn_free(command, 1); weechat_string_dyn_free(command, 1);
} }
@ -1108,7 +1187,6 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status,
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};
xmpp_handler_add(conn, &connection__version_handler, xmpp_handler_add(conn, &connection__version_handler,
"jabber:iq:version", "iq", NULL, account); "jabber:iq:version", "iq", NULL, account);
@ -1135,8 +1213,15 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status,
xmpp_stanza_set_ns(pres__c, "http://jabber.org/protocol/caps"); xmpp_stanza_set_ns(pres__c, "http://jabber.org/protocol/caps");
xmpp_stanza_set_attribute(pres__c, "hash", "sha-1"); xmpp_stanza_set_attribute(pres__c, "hash", "sha-1");
xmpp_stanza_set_attribute(pres__c, "node", "http://weechat.org"); xmpp_stanza_set_attribute(pres__c, "node", "http://weechat.org");
snprintf(cap_hash, sizeof(cap_hash), "%027ld=", time(NULL));
xmpp_stanza_t *caps = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(caps, "caps");
char *cap_hash;
caps = connection__get_caps(caps, account, &cap_hash);
xmpp_stanza_release(caps);
xmpp_stanza_set_attribute(pres__c, "ver", cap_hash); xmpp_stanza_set_attribute(pres__c, "ver", cap_hash);
free(cap_hash);
children[0] = pres__c; children[0] = pres__c;
pres__status = xmpp_stanza_new(account->context); pres__status = xmpp_stanza_new(account->context);
@ -1206,21 +1291,26 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status,
children[0] = children[0] =
stanza__iq_pubsub(account->context, NULL, children, stanza__iq_pubsub(account->context, NULL, children,
with_noop("http://jabber.org/protocol/pubsub")); with_noop("http://jabber.org/protocol/pubsub"));
char *uuid = xmpp_uuid_gen(account->context);
children[0] = children[0] =
stanza__iq(account->context, NULL, children, NULL, strdup("fetch1"), stanza__iq(account->context, NULL, children, NULL, uuid,
strdup(account_jid(account)), strdup(account_jid(account)), strdup(account_jid(account)), strdup(account_jid(account)),
strdup("get")); strdup("get"));
xmpp_free(account->context, uuid);
xmpp_send(conn, children[0]); xmpp_send(conn, children[0]);
xmpp_stanza_release(children[0]); xmpp_stanza_release(children[0]);
omemo__init(account->buffer, &account->omemo, account->name); omemo__init(account->buffer, &account->omemo, account->name);
children[0] = if (account->omemo)
omemo__get_bundle(account->context, {
strdup(account_jid(account)), NULL, account->omemo); children[0] =
xmpp_send(conn, children[0]); omemo__get_bundle(account->context,
xmpp_stanza_release(children[0]); strdup(account_jid(account)), NULL, account->omemo);
xmpp_send(conn, children[0]);
xmpp_stanza_release(children[0]);
}
(void) weechat_hook_signal_send("xmpp_account_connected", (void) weechat_hook_signal_send("xmpp_account_connected",
WEECHAT_HOOK_SIGNAL_STRING, account->name); WEECHAT_HOOK_SIGNAL_STRING, account->name);
@ -1235,7 +1325,6 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status,
char* connection__rand_string(int length) char* connection__rand_string(int length)
{ {
char *string = malloc(length); char *string = malloc(length);
srand(time(NULL));
for(int i = 0; i < length; ++i){ for(int i = 0; i < length; ++i){
string[i] = '0' + rand()%72; // starting on '0', ending on '}' string[i] = '0' + rand()%72; // starting on '0', ending on '}'
if (!((string[i] >= '0' && string[i] <= '9') || if (!((string[i] >= '0' && string[i] <= '9') ||

@ -34,16 +34,20 @@ int input__data(struct t_gui_buffer *buffer, const char *text)
return WEECHAT_RC_OK; return WEECHAT_RC_OK;
} }
channel__send_message(account, channel, channel->id, text); if (channel__send_message(account, channel, channel->id, text) == WEECHAT_RC_OK)
return WEECHAT_RC_OK;
else
{
return WEECHAT_RC_OK_EAT;
}
} }
else else
{ {
weechat_printf(buffer, weechat_printf(buffer,
_("%s%s: this buffer is not a channel!"), _("%s%s: this buffer is not a channel!"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME); weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
return WEECHAT_RC_OK;
} }
return WEECHAT_RC_OK;
} }
int input__data_cb(const void *pointer, void *data, int input__data_cb(const void *pointer, void *data,

@ -1,4 +1,4 @@
(define-module (gnu packages messaging) (define-module (libomemo)
#:use-module (gnu packages) #:use-module (gnu packages)
#:use-module (gnu packages admin) #:use-module (gnu packages admin)
#:use-module (gnu packages aidc) #:use-module (gnu packages aidc)

1129
omemo.c

File diff suppressed because it is too large Load Diff

@ -46,11 +46,11 @@ void omemo__handle_devicelist(struct t_omemo *omemo, const char *jid,
void omemo__handle_bundle(struct t_omemo *omemo, const char *jid, void omemo__handle_bundle(struct t_omemo *omemo, const char *jid,
uint32_t device_id, xmpp_stanza_t *items); uint32_t device_id, xmpp_stanza_t *items);
char *omemo__decode(struct t_omemo *omemo, const char *jid, char *omemo__decode(struct t_account *account, const char *jid,
xmpp_stanza_t *encrypted); xmpp_stanza_t *encrypted);
xmpp_stanza_t *omemo__encode(struct t_omemo *omemo, const char *jid, xmpp_stanza_t *omemo__encode(struct t_account *account, const char *jid,
uint32_t device_id, const char *unencrypted); const char *unencrypted);
void omemo__free(struct t_omemo *omemo); void omemo__free(struct t_omemo *omemo);

@ -98,9 +98,36 @@ xmpp_stanza_t *stanza__iq_pubsub_items(xmpp_ctx_t *context, xmpp_stanza_t *base,
if (node) if (node)
{ {
xmpp_stanza_set_attribute(parent, "node", node); xmpp_stanza_set_attribute(parent, "node", node);
}
return parent;
}
xmpp_stanza_t *stanza__iq_pubsub_subscribe(xmpp_ctx_t *context, xmpp_stanza_t *base,
struct t_string *node, struct t_string *jid)
{
xmpp_stanza_t *parent = base;
if (!parent)
{
parent = xmpp_stanza_new(context);
xmpp_stanza_set_name(parent, "subscribe");
}
if (node)
{
xmpp_stanza_set_attribute(parent, "node", node->value);
node->finalize(node);
free(node); free(node);
} }
if (jid)
{
xmpp_stanza_set_attribute(parent, "jid", jid->value);
jid->finalize(jid);
free(jid);
}
return parent; return parent;
} }
@ -408,3 +435,31 @@ xmpp_stanza_t *stanza__iq_ping(xmpp_ctx_t *context, xmpp_stanza_t *base,
return parent; return parent;
} }
xmpp_stanza_t *stanza__iq_query(xmpp_ctx_t *context, xmpp_stanza_t *base,
struct t_string *ns, struct t_string *node)
{
xmpp_stanza_t *parent = base;
if (!parent)
{
parent = xmpp_stanza_new(context);
xmpp_stanza_set_name(parent, "query");
}
if (ns)
{
xmpp_stanza_set_ns(parent, ns->value);
ns->finalize(ns);
free(ns);
}
if (node)
{
xmpp_stanza_set_attribute(parent, "node", node->value);
node->finalize(node);
free(node);
}
return parent;
}

@ -78,6 +78,9 @@ xmpp_stanza_t *stanza__iq_pubsub(xmpp_ctx_t *context, xmpp_stanza_t *base,
xmpp_stanza_t *stanza__iq_pubsub_items(xmpp_ctx_t *context, xmpp_stanza_t *base, char *node); xmpp_stanza_t *stanza__iq_pubsub_items(xmpp_ctx_t *context, xmpp_stanza_t *base, char *node);
xmpp_stanza_t *stanza__iq_pubsub_subscribe(xmpp_ctx_t *context, xmpp_stanza_t *base,
struct t_string *node, struct t_string *jid);
xmpp_stanza_t *stanza__iq_pubsub_publish(xmpp_ctx_t *context, xmpp_stanza_t *base, xmpp_stanza_t *stanza__iq_pubsub_publish(xmpp_ctx_t *context, xmpp_stanza_t *base,
xmpp_stanza_t **children, struct t_string *node); xmpp_stanza_t **children, struct t_string *node);
@ -114,4 +117,7 @@ xmpp_stanza_t *stanza__iq_enable(xmpp_ctx_t *context, xmpp_stanza_t *base,
xmpp_stanza_t *stanza__iq_ping(xmpp_ctx_t *context, xmpp_stanza_t *base, xmpp_stanza_t *stanza__iq_ping(xmpp_ctx_t *context, xmpp_stanza_t *base,
struct t_string *ns); struct t_string *ns);
xmpp_stanza_t *stanza__iq_query(xmpp_ctx_t *context, xmpp_stanza_t *base,
struct t_string *ns, struct t_string *node);
#endif /*WEECHAT_XMPP_STANZA_H*/ #endif /*WEECHAT_XMPP_STANZA_H*/

Loading…
Cancel
Save