Tony Olagbaiye 2 years ago
commit 5c50107bb9
No known key found for this signature in database
GPG Key ID: 9E2FF3BDEBDFC910

@ -5,10 +5,12 @@ export CC=gcc CXX="g++ -fdiagnostics-color=always"
# Miscellaneous packages.
ENVIRONMENTS=(
weechat # Debug runs
profanity # Test
)
# Environment packages.
PACKAGES=(
profanity # Test
autoconf # Deps with autoreconf
autoconf-archive # Deps with m4 tooling
automake # Deps with automake
@ -25,7 +27,7 @@ PACKAGES=(
libxml2 # Dep (libxml2)
libstrophe # Dep (strophe)
libgcrypt # Dep (gcrypt)
libsignal-protocol-c # Dep (libsignal)
libsignal-protocol-c -l libomemo.scm # Dep (libsignal)
lmdb lmdbxx # Dep (lmdb)
rnp # Dep (rnpgp)
)
@ -34,11 +36,17 @@ echo direnv: fetching source - weechat
mkdir -p /tmp/guix-build-weechat-3.2.drv-0
tar -C /tmp/guix-build-weechat-3.2.drv-0 -xJf $(guix build --source weechat)
echo direnv: fetching source - libomemo-c
mkdir -p /tmp/guix-build-libomemo-c-2.3.3.drv-0
ln -sf $(guix build --source -f libomemo.scm) /tmp/guix-build-libomemo-c-2.3.3.drv-0
use guix \
${ENVIRONMENTS[@]} --ad-hoc ${PACKAGES[@]} \
--with-debug-info=profanity\
--with-debug-info=weechat \
--with-debug-info=libstrophe \
--with-debug-info=libsignal-protocol-c \
--with-debug-info=libomemo-c\
--with-debug-info=lmdb \
--with-debug-info=rnp \
clang clang:extra ccls gdb

@ -16,7 +16,7 @@
[[https://github.com/bqv/weechat-xmpp/issues?q=is:issue+is:closed][file:https://img.shields.io/github/issues-closed/bqv/weechat-xmpp.svg]]
[[https://github.com/bqv/weechat-xmpp/blob/master/LICENSE][file:https://img.shields.io/github/license/bqv/weechat-xmpp.svg]]
[[https://github.com/bqv/weechat-extras/][file:https://img.shields.io/badge/weechat--extras-xmpp-blue.svg]]
[[https://github.com/bqv/weechat-extras/][file:https://inverse.chat/badge.svg?room=weechat@muc.xa0.uk]]
[[https://inverse.chat/#converse/room?jid=weechat@muc.xa0.uk][file:https://inverse.chat/badge.svg?room=weechat@muc.xa0.uk]]
| Status: | XMPP for power users and digital masochists |
| Location: | [[http://github.com/bqv/weechat-xmpp]] |
@ -31,14 +31,14 @@
My priority here is to have an android-available XMPP client
that hides as little as possible from the user. To use this with
android, set up a relay (`/relay`) and see weechat-android.
I'm gonna rewrite this in C++ at some point when I have a feel
for the full behaviour of an average client.
I might rewrite this in C++ at some point when I feel like I
can do it without burning out.
* Usage
1. Start with =/xmpp add=, use =/help xmpp= for instructions.
1. Start with =/account add=, use =/help account= for instructions.
2. Use =/xmpp connect <account-name>= with the name set at
2. Use =/account connect <account-name>= with the name set at
add-time.
* Installing
@ -49,7 +49,8 @@
- libstrophe (dynamic, dependency)
- libxml2 (dynamic, dependency)
- libsignal-protocol-c (dynamic, dependency)
- lmdb (dynamic, dependency)
- libomemo-c (libsignal-protocol-c) (dynamic, dependency)
- rnp (dynamic, dependency)
- weechat (>= v3.0)
@ -95,6 +96,7 @@
* [-] OOB messages
* [X] Single media on a line
* [ ] Multiple media inline (protocol?)
* [ ] Encrypted (pgp/omemo)
* [X] Buffer autoswitch on enter/open
* [X] Handle open/enter jids with a resource without breaking
* [X] Allow /close without crashing
@ -119,18 +121,18 @@
* [X] [#B] Leaves
* [X] [#B] Tracking
* [X] [#B] Set/show topic
* [-] OMEMO (libsignal-protocol-c)
* [-] Presence
* [X] OMEMO (libomemo-c)
* [X] Presence
* [X] Disco
* [X] Disco response
* [-] Key Generation / storage (lmdb)
* [X] Key Generation / storage (lmdb)
* [X] Generation
* [?] Storage
* [-] Announce
* [X] Storage
* [X] Announce
* [X] Device ID
* [ ] Bundles
* [ ] Messages
* [ ] [#C] MUC PMs
* [X] Bundles
* [X] Messages
* [X] [#C] MUC PMs
* [X] [#A] Send typing notifications
* [X] [#A] Recv typing notifications
* [X] [#C] Read receipts
@ -156,7 +158,6 @@
* [X] Decryption
* [X] Encryption
* [X] Custom set/clear key (/pgp)
* [ ] OOB data and media
* [ ] Room Explorer (https://search.jabber.network/docs/api)
** TODO [#C] Implement completion engine (milestone v0.3)
** TODO [#D] Close all issues (milestone v1.0)
@ -167,7 +168,7 @@
Please submit a pull request or create an issue
to add a new or missing feature.
* Testemonials
* Testimonials
"Weechat-Strophe - for the discerning dual IRCer XMPPer" -- [[github.com/janicez][Ellenor et al Bjornsdottir]]

@ -11,6 +11,7 @@
#include <libxml/xmlwriter.h>
#include "plugin.h"
#include "xmpp/stanza.h"
#include "config.h"
#include "input.h"
#include "omemo.h"
@ -89,7 +90,7 @@ int account__search_option(const char *option_name)
return -1;
}
struct t_account_device *account__search_device(struct t_account *account, int id)
struct t_account_device *account__search_device(struct t_account *account, uint32_t id)
{
struct t_account_device *ptr_device;
@ -117,6 +118,7 @@ void account__add_device(struct t_account *account,
new_device = malloc(sizeof(*new_device));
new_device->id = device->id;
new_device->name = strdup(device->name);
new_device->label = device->label ? strdup(device->label) : NULL;
new_device->prev_device = account->last_device;
new_device->next_device = NULL;
@ -150,6 +152,8 @@ void account__free_device(struct t_account *account, struct t_account_device *de
(device->next_device)->prev_device = device->prev_device;
/* free device data */
if (device->label)
free(device->label);
if (device->name)
free(device->name);
@ -164,6 +168,59 @@ void account__free_device_all(struct t_account *account)
account__free_device(account, account->devices);
}
xmpp_stanza_t *account__get_devicelist(struct t_account *account)
{
xmpp_stanza_t *parent, **children;
struct t_account_device *device;
const char *ns, *node;
char id[64] = {0};
int i = 0;
device = malloc(sizeof(struct t_account_device));
device->id = account->omemo->device_id;
snprintf(id, sizeof(id), "%u", device->id);
device->name = strdup(id);
device->label = strdup("weechat");
children = malloc(sizeof(xmpp_stanza_t *) * 128);
children[i++] = stanza__iq_pubsub_publish_item_list_device(
account->context, NULL, with_noop(device->name), NULL);
free(device->label);
free(device->name);
free(device);
for (device = account->devices; device;
device = device->next_device)
{
if (device->id != account->omemo->device_id)
children[i++] = stanza__iq_pubsub_publish_item_list_device(
account->context, NULL, with_noop(device->name), NULL);
}
children[i] = NULL;
node = "eu.siacs.conversations.axolotl";
children[0] = stanza__iq_pubsub_publish_item_list(
account->context, NULL, children, with_noop(node));
children[1] = NULL;
children[0] = stanza__iq_pubsub_publish_item(
account->context, NULL, children, with_noop("current"));
node = "eu.siacs.conversations.axolotl.devicelist";
children[0] = stanza__iq_pubsub_publish(account->context,
NULL, children,
with_noop(node));
ns = "http://jabber.org/protocol/pubsub";
children[0] = stanza__iq_pubsub(account->context, NULL,
children, with_noop(ns));
parent = stanza__iq(account->context, NULL,
children, NULL, strdup("announce1"),
NULL, NULL, strdup("set"));
free(children);
return parent;
}
struct t_account_mam_query *account__add_mam_query(struct t_account *account,
struct t_channel *channel,
const char *id,
@ -692,7 +749,7 @@ int account__timer_cb(const void *pointer, void *data, int remaining_calls)
struct t_account *ptr_account;
for (ptr_account = accounts; ptr_account;
ptr_account = ptr_account->next_account)
ptr_account = ptr_account ? ptr_account->next_account : NULL)
{
if (ptr_account->is_connected
&& (xmpp_conn_is_connecting(ptr_account->connection)

@ -66,8 +66,9 @@ enum t_account_option
struct t_account_device
{
int id;
uint32_t id;
char *name;
char *label;
struct t_account_device *prev_device;
struct t_account_device *next_device;
@ -128,10 +129,11 @@ extern char *account_options[][2];
struct t_account *account__search(const char *account_name);
struct t_account *account__casesearch (const char *account_name);
int account__search_option(const char *option_name);
struct t_account_device *account__search_device(struct t_account *account, int id);
struct t_account_device *account__search_device(struct t_account *account, uint32_t id);
void account__add_device(struct t_account *account, struct t_account_device *device);
void account__free_device(struct t_account *account, struct t_account_device *device);
void account__free_device_all(struct t_account *account);
xmpp_stanza_t *account__get_devicelist(struct t_account *account);
struct t_account_mam_query *account__add_mam_query(struct t_account *account,
struct t_channel *channel,
const char *id,

@ -2,6 +2,7 @@
// License, version 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdint.h>
#include <string.h>
#include <strophe.h>

@ -10,29 +10,61 @@
#include <strophe.h>
#include "plugin.h"
#include "omemo.h"
#include "account.h"
#include "omemo.h"
#include "user.h"
#include "channel.h"
#include "input.h"
#include "buffer.h"
#include "pgp.h"
#include "util.h"
const char *channel__transport_name(enum t_channel_transport transport)
{
switch (transport)
{
case CHANNEL_TRANSPORT_PLAINTEXT:
case CHANNEL_TRANSPORT_PLAIN:
return "PLAINTEXT";
case CHANNEL_TRANSPORT_OMEMO:
return "OMEMO";
case CHANNEL_TRANSPORT_PGP:
return "PGP";
case CHANNEL_TRANSPORT_OTR:
return "OTR";
default:
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 *ptr_account;
@ -80,7 +112,7 @@ struct t_gui_buffer *channel__search_buffer(struct t_account *account,
{
struct t_hdata *hdata_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");
ptr_buffer = weechat_hdata_get_list(hdata_buffer, "gui_buffers");
@ -91,18 +123,18 @@ struct t_gui_buffer *channel__search_buffer(struct t_account *account,
{
ptr_type = weechat_buffer_get_string(ptr_buffer, "localvar_type");
ptr_account_name = weechat_buffer_get_string(ptr_buffer,
"localvar_server");
ptr_channel_name = weechat_buffer_get_string(ptr_buffer,
"localvar_channel");
"localvar_account");
ptr_remote_jid = weechat_buffer_get_string(ptr_buffer,
"localvar_remote_jid");
if (ptr_type && ptr_type[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))
&& (strcmp(ptr_type, "channel") == 0))
&& (strcmp(ptr_type, "room") == 0))
|| (( (type == CHANNEL_TYPE_PM))
&& (strcmp(ptr_type, "private") == 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;
}
@ -119,13 +151,13 @@ struct t_gui_buffer *channel__create_buffer(struct t_account *account,
{
struct t_gui_buffer *ptr_buffer;
int buffer_created;
const char *short_name, *localvar_channel;
char buffer_name[256];
const char *short_name, *localvar_remote_jid;
char buffer_name[1024];
buffer_created = 0;
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);
if (ptr_buffer)
@ -145,17 +177,19 @@ struct t_gui_buffer *channel__create_buffer(struct t_account *account,
if (buffer_created)
{
char *res = strrchr(name, '/');
if (!weechat_buffer_get_integer(ptr_buffer, "short_name_is_set"))
weechat_buffer_set(ptr_buffer, "short_name", name);
weechat_buffer_set(ptr_buffer, "short_name",
res ? res + 1 : name);
}
else
{
short_name = weechat_buffer_get_string (ptr_buffer, "short_name");
localvar_channel = weechat_buffer_get_string(ptr_buffer,
"localvar_channel");
short_name = weechat_buffer_get_string(ptr_buffer, "short_name");
localvar_remote_jid = weechat_buffer_get_string(ptr_buffer,
"localvar_remote_jid");
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",
xmpp_jid_node(account->context, name));
@ -165,18 +199,19 @@ struct t_gui_buffer *channel__create_buffer(struct t_account *account,
account_option_set(account, ACCOUNT_OPTION_NICKNAME,
xmpp_jid_node(account->context, account_jid(account)));
weechat_buffer_set(ptr_buffer, "name", name);
weechat_buffer_set(ptr_buffer, "notify",
(type == CHANNEL_TYPE_PM) ? "3" : "1");
weechat_buffer_set(ptr_buffer, "localvar_set_type",
(type == CHANNEL_TYPE_PM) ? "private" : "channel");
weechat_buffer_set(ptr_buffer, "localvar_set_nick",
account_nickname(account));
weechat_buffer_set(ptr_buffer, "localvar_set_server", account->name);
weechat_buffer_set(ptr_buffer, "localvar_set_channel", name);
weechat_buffer_set(ptr_buffer, "localvar_set_account", account->name);
weechat_buffer_set(ptr_buffer, "localvar_set_remote_jid", name);
weechat_buffer_set(ptr_buffer, "input_multiline", "1");
if (buffer_created)
{
(void) weechat_hook_signal_send ("logger_backlog",
(void) weechat_hook_signal_send("logger_backlog",
WEECHAT_HOOK_SIGNAL_POINTER,
ptr_buffer);
weechat_buffer_set(ptr_buffer, "input_get_unknown_commands", "1");
@ -271,8 +306,15 @@ struct t_channel *channel__new(struct t_account *account,
new_channel->type = type;
new_channel->id = strdup(id);
new_channel->name = strdup(name);
new_channel->transport = CHANNEL_TRANSPORT_PLAINTEXT;
new_channel->pgp_id = NULL;
new_channel->transport = CHANNEL_TRANSPORT_PLAIN;
new_channel->omemo.enabled = type == CHANNEL_TYPE_PM ? 1 : 0;
new_channel->omemo.devicelist_requests = weechat_hashtable_new(64,
WEECHAT_HASHTABLE_STRING, WEECHAT_HASHTABLE_POINTER, NULL, NULL);
new_channel->omemo.bundle_requests = weechat_hashtable_new(64,
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.creator = NULL;
@ -788,8 +830,8 @@ void channel__free(struct t_account *account,
free(channel->id);
if (channel->name)
free(channel->name);
if (channel->pgp_id)
free(channel->pgp_id);
if (channel->pgp.id)
free(channel->pgp.id);
if (channel->topic.value)
free(channel->topic.value);
if (channel->topic.creator)
@ -914,10 +956,13 @@ struct t_channel_member *channel__add_member(struct t_account *account,
user->profile.status_text ? " [" : "",
user->profile.status_text ? user->profile.status_text : "",
user->profile.status_text ? "]" : "",
user->profile.pgp_id ? weechat_color("gray") : "",
user->profile.pgp_id ? " with PGP:" : "",
user->profile.pgp_id || user->profile.omemo ? weechat_color("gray") : "",
user->profile.pgp_id || user->profile.omemo ? " with " : "",
user->profile.pgp_id ? "PGP:" : "",
user->profile.pgp_id ? user->profile.pgp_id : "",
user->profile.pgp_id ? weechat_color("reset") : "");
user->profile.omemo && user->profile.pgp_id ? " and " : "",
user->profile.omemo ? "OMEMO" : "",
user->profile.pgp_id || user->profile.omemo ? weechat_color("reset") : "");
return member;
}
@ -983,7 +1028,7 @@ struct t_channel_member *channel__remove_member(struct t_account *account,
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)
{
channel__send_reads(account, channel);
@ -997,17 +1042,51 @@ void channel__send_message(struct t_account *account, struct t_channel *channel,
xmpp_stanza_set_id(message, id);
xmpp_free(account->context, id);
char *url = strstr(body, "http");
if (channel->pgp_id)
if (account->omemo && channel->omemo.enabled)
{
xmpp_stanza_t *encrypted = omemo__encode(account, to, body);
if (!encrypted)
{
weechat_printf_date_tags(channel->buffer, 0, "notify_none", "%s%s",
weechat_prefix("error"), "OMEMO Error");
channel__set_transport(channel, CHANNEL_TRANSPORT_PLAIN, 1);
xmpp_stanza_release(message);
return WEECHAT_RC_ERROR;
}
xmpp_stanza_add_child(message, encrypted);
xmpp_stanza_release(encrypted);
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.enabled && channel->pgp.id)
{
xmpp_stanza_t *message__x = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__x, "x");
xmpp_stanza_set_ns(message__x, "jabber:x:encrypted");
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)
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);
xmpp_stanza_add_child(message__x, message__x__text);
@ -1026,28 +1105,17 @@ void channel__send_message(struct t_account *account, struct t_channel *channel,
xmpp_message_set_body(message, PGP_ADVICE);
if (ciphertext && channel->transport != CHANNEL_TRANSPORT_PGP)
{
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));
}
channel__set_transport(channel, CHANNEL_TRANSPORT_PGP, 0);
}
else
{
xmpp_message_set_body(message, body);
if (channel->transport != CHANNEL_TRANSPORT_PLAINTEXT)
{
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));
}
channel__set_transport(channel, CHANNEL_TRANSPORT_PLAIN, 0);
}
if (url)
char *url = strstr(body, "http");
if (url && channel->transport == CHANNEL_TRANSPORT_PLAIN)
{
xmpp_stanza_t *message__x = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(message__x, "x");
@ -1070,11 +1138,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_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_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_stanza_release(message);
if (channel->type != CHANNEL_TYPE_MUC)
@ -1083,6 +1168,8 @@ void channel__send_message(struct t_account *account, struct t_channel *channel,
"%s\t%s",
user__as_prefix_raw(account, account_jid(account)),
body);
return WEECHAT_RC_OK;
}
void channel__send_reads(struct t_account *account, struct t_channel *channel)

@ -15,9 +15,11 @@ enum t_channel_type
enum t_channel_transport
{
CHANNEL_TRANSPORT_PLAINTEXT,
CHANNEL_TRANSPORT_PLAIN,
CHANNEL_TRANSPORT_OMEMO,
CHANNEL_TRANSPORT_PGP,
CHANNEL_TRANSPORT_OTR,
CHANNEL_TRANSPORT_OX,
};
struct t_channel_typing
@ -63,7 +65,18 @@ struct t_channel
char *id;
char *name;
enum t_channel_transport transport;
char *pgp_id;
struct {
int enabled;
struct t_hashtable *devicelist_requests;
struct t_hashtable *bundle_requests;
} omemo;
struct {
int enabled;
char *id;
} pgp;
struct {
int enabled;
} otr;
struct t_channel_topic topic;
@ -92,6 +105,9 @@ struct t_channel
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_channel *channel__search(struct t_account *account,
@ -179,7 +195,7 @@ struct t_channel_member *channel__remove_member(struct t_account *account,
struct t_channel *channel,
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);
void channel__send_reads(struct t_account *account, struct t_channel *channel);

@ -4,12 +4,12 @@
#include <strophe.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "plugin.h"
//#include "oauth.h"
#include "account.h"
#include "user.h"
#include "channel.h"
@ -501,7 +501,7 @@ int command__enter(const void *pointer, void *data,
}
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(
ptr_account->context,
@ -756,6 +756,41 @@ int command__mam(const void *pointer, void *data,
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,
struct t_gui_buffer *buffer, int argc,
char **argv, char **argv_eol)
@ -786,13 +821,48 @@ int command__pgp(const void *pointer, void *data,
{
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;
}
@ -810,6 +880,9 @@ int command__xml(const void *pointer, void *data,
buffer__get_account_and_channel(buffer, &ptr_account, &ptr_channel);
if (!ptr_account)
return WEECHAT_RC_ERROR;
if (!ptr_account->is_connected)
{
weechat_printf(buffer,
@ -821,7 +894,7 @@ int command__xml(const void *pointer, void *data,
if (argc > 1)
{
stanza = xmpp_stanza_new_from_string(ptr_account->context,
argv_eol[0]);
argv_eol[1]);
if (!stanza)
return WEECHAT_RC_ERROR;
@ -906,15 +979,33 @@ void command__init()
if (!hook)
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(
"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: recipient keyid"),
NULL, &command__pgp, NULL, NULL);
if (!hook)
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(
"xml",
N_("send a raw xml stanza"),

@ -3,6 +3,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <strophe.h>

@ -3,6 +3,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <strophe.h>

@ -24,6 +24,7 @@
void connection__init()
{
srand(time(NULL));
xmpp_initialize();
}
@ -85,11 +86,12 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void
struct t_account *account = (struct t_account *)userdata;
struct t_user *user;
struct t_channel *channel;
xmpp_stanza_t *iq__x_signed, *iq__x_muc_user, *show, *idle, *iq__x__item, *iq__c, *iq__status;
const char *from, *from_bare, *from_res, *type, *role = NULL, *affiliation = NULL, *jid = NULL;
xmpp_stanza_t *pres__x_signed, *pres__x_muc_user, *show, *idle, *pres__x__item, *pres__c, *pres__status;
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;
char *clientid = NULL, *status;
to = xmpp_stanza_get_to(stanza);
from = xmpp_stanza_get_from(stanza);
if (from == NULL)
return 1;
@ -100,44 +102,107 @@ int connection__presence_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void
show__text = show ? xmpp_stanza_get_text(show) : NULL;
idle = xmpp_stanza_get_child_by_name_and_ns(stanza, "idle", "urn:xmpp:idle:1");
idle__since = idle ? xmpp_stanza_get_attribute(idle, "since") : NULL;
iq__x_signed = xmpp_stanza_get_child_by_name_and_ns(
pres__x_signed = xmpp_stanza_get_child_by_name_and_ns(
stanza, "x", "jabber:x:signed");
if (iq__x_signed)
if (pres__x_signed)
{
certificate = xmpp_stanza_get_text(iq__x_signed);
certificate = xmpp_stanza_get_text(pres__x_signed);
}
iq__c = xmpp_stanza_get_child_by_name_and_ns(
pres__c = xmpp_stanza_get_child_by_name_and_ns(
stanza, "c", "http://jabber.org/protocol/caps");
if (iq__c)
if (pres__c)
{
node = xmpp_stanza_get_attribute(iq__c, "node");
ver = xmpp_stanza_get_attribute(iq__c, "ver");
node = xmpp_stanza_get_attribute(pres__c, "node");
ver = xmpp_stanza_get_attribute(pres__c, "ver");
if (node && ver)
{
int len = strlen(node)+1+strlen(ver);
int len = strlen(node)+1+strlen(ver) + 1;
clientid = malloc(sizeof(char)*len);
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]);
}
}
iq__status = xmpp_stanza_get_child_by_name(stanza, "status");
status = iq__status ? xmpp_stanza_get_text(iq__status) : NULL;
iq__x_muc_user = xmpp_stanza_get_child_by_name_and_ns(
pres__status = xmpp_stanza_get_child_by_name(stanza, "status");
status = pres__status ? xmpp_stanza_get_text(pres__status) : NULL;
pres__x_muc_user = xmpp_stanza_get_child_by_name_and_ns(
stanza, "x", "http://jabber.org/protocol/muc#user");
channel = channel__search(account, from_bare);
if (weechat_strcasecmp(type, "unavailable") && !iq__x_muc_user && !channel)
if (weechat_strcasecmp(type, "unavailable") != 0 && !pres__x_muc_user && !channel)
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 (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))
{
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(xmpp_stanza_get_name(iq__x__item), "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;
}
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");
role = xmpp_stanza_get_attribute(pres__x__item, "role");
affiliation = xmpp_stanza_get_attribute(pres__x__item, "affiliation");
jid = xmpp_stanza_get_attribute(pres__x__item, "jid");
user = user__search(account, from);
if (!user)
@ -164,7 +229,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);
if (channel->type != CHANNEL_TYPE_MUC)
channel->pgp_id = user->profile.pgp_id;
channel->pgp.id = user->profile.pgp_id;
}
if (channel)
@ -202,7 +267,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);
if (channel->type != CHANNEL_TYPE_MUC)
channel->pgp_id = user->profile.pgp_id;
channel->pgp.id = user->profile.pgp_id;
}
if (channel)
@ -225,8 +290,8 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
(void) conn;
struct t_account *account = (struct t_account *)userdata;
struct t_channel *channel;
xmpp_stanza_t *x, *body, *delay, *topic, *replace, *request, *markable, *composing, *sent, *received, *result, *forwarded;
struct t_channel *channel, *parent_channel;
xmpp_stanza_t *x, *body, *delay, *topic, *replace, *request, *markable, *composing, *sent, *received, *result, *forwarded, *event, *items, *item, *list, *device, *encrypted, **children;
const char *type, *from, *nick, *from_bare, *to, *to_bare, *id, *thread, *replace_id, *timestamp;
char *text, *intext, *difftext = NULL, *cleartext = NULL;
struct tm time = {0};
@ -239,6 +304,9 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
if (topic != NULL)
{
intext = xmpp_stanza_get_text(topic);
type = xmpp_stanza_get_type(stanza);
if (type != NULL && strcmp(type, "error") == 0)
return 1;
from = xmpp_stanza_get_from(stanza);
if (from == NULL)
return 1;
@ -246,7 +314,12 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
from = xmpp_jid_resource(account->context, from);
channel = channel__search(account, from_bare);
if (!channel)
{
if (weechat_strcasecmp(type, "groupchat") == 0)
channel = channel__new(account, CHANNEL_TYPE_MUC, from_bare, from_bare);
else
channel = channel__new(account, CHANNEL_TYPE_PM, from_bare, from_bare);
}
channel__update_topic(channel, intext ? intext : "", from, 0);
if (intext != NULL)
xmpp_free(account->context, intext);
@ -314,6 +387,71 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
}
}
event = xmpp_stanza_get_child_by_name_and_ns(
stanza, "event", "http://jabber.org/protocol/pubsub#event");
if (event)
{
items = xmpp_stanza_get_child_by_name(event, "items");
if (items)
{
const char *items_node = xmpp_stanza_get_attribute(items, "node");
from = xmpp_stanza_get_from(stanza);
to = xmpp_stanza_get_to(stanza);
if (items_node
&& weechat_strcasecmp(items_node,
"eu.siacs.conversations.axolotl.devicelist") == 0)
{
item = xmpp_stanza_get_child_by_name(items, "item");
if (item)
{
list = xmpp_stanza_get_child_by_name_and_ns(
item, "list", "eu.siacs.conversations.axolotl");
if (list)
{
if (account->omemo)
{
omemo__handle_devicelist(account->omemo,
from ? from : account_jid(account), items);
}
children = malloc(sizeof(*children) * (3 + 1));
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,
strdup(to), strdup(from), strdup("get"));
xmpp_free(account->context, uuid);
xmpp_send(conn, children[0]);
xmpp_stanza_release(children[0]);
}
}
}
}
}
}
return 1;
}
type = xmpp_stanza_get_type(stanza);
@ -339,12 +477,19 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
const char *channel_id = weechat_strcasecmp(account_jid(account), from_bare)
== 0 ? to_bare : from_bare;
channel = channel__search(account, channel_id);
parent_channel = channel__search(account, channel_id);
const char *pm_id = weechat_strcasecmp(account_jid(account), from_bare)
== 0 ? to : from;
channel = parent_channel;
if (!channel)
channel = channel__new(account,
weechat_strcasecmp(type, "groupchat") == 0
? CHANNEL_TYPE_MUC : CHANNEL_TYPE_PM,
channel_id, channel_id);
if (channel && channel->type == CHANNEL_TYPE_MUC
&& weechat_strcasecmp(type, "chat") == 0)
channel = channel__new(account, CHANNEL_TYPE_PM,
pm_id, pm_id);
if (id && (markable || request))
{
@ -399,6 +544,12 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
weechat_list_add(channel->unreads, unread->id, WEECHAT_LIST_POS_END, unread);
}
encrypted = xmpp_stanza_get_child_by_name_and_ns(stanza, "encrypted",
"eu.siacs.conversations.axolotl");
if (encrypted && account->omemo)
{
cleartext = omemo__decode(account, from_bare, encrypted);
}
x = xmpp_stanza_get_child_by_name_and_ns(stanza, "x", "jabber:x:encrypted");
intext = xmpp_stanza_get_text(body);
if (x)
@ -539,6 +690,12 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
? xmpp_jid_resource(account->context, from)
: from;
}
else if (parent_channel && parent_channel->type == CHANNEL_TYPE_MUC)
{
nick = weechat_strcasecmp(channel->name, from) == 0
? xmpp_jid_resource(account->context, from)
: xmpp_jid_bare(account->context, from);
}
delay = xmpp_stanza_get_child_by_name_and_ns(stanza, "delay", "urn:xmpp:delay");
timestamp = delay ? xmpp_stanza_get_attribute(delay, "stamp") : NULL;
if (timestamp)
@ -574,13 +731,13 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
weechat_string_dyn_concat(dyn_tags, replace_id, -1);
}
if (date != 0)
if (date != 0 || encrypted)
weechat_string_dyn_concat(dyn_tags, ",notify_none", -1);
else if (channel->type == CHANNEL_TYPE_PM
&& weechat_strcasecmp(from_bare, account_jid(account)) != 0)
weechat_string_dyn_concat(dyn_tags, ",notify_private", -1);
else
weechat_string_dyn_concat(dyn_tags, ",log1", -1);
weechat_string_dyn_concat(dyn_tags, ",notify_message,log1", -1);
const char *edit = replace ? "* " : ""; // Losing which message was edited, sadly
if (x && text == cleartext && channel->transport != CHANNEL_TRANSPORT_PGP)
@ -590,9 +747,9 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
weechat_prefix("network"), weechat_color("gray"),
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_prefix("network"), weechat_color("gray"),
channel__transport_name(channel->transport));
@ -622,42 +779,38 @@ int connection__message_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *
return 1;
}
int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
xmpp_stanza_t *connection__get_caps(xmpp_stanza_t *reply, struct t_account *account, char **hash)
{
struct t_account *account = (struct t_account *)userdata;
xmpp_stanza_t *reply, *query, *identity, *feature, *x, *field, *value, *text, *fin;
xmpp_stanza_t *pubsub, *items, *item, *list, *device, **children;
xmpp_stanza_t *storage, *conference, *nick;
static struct utsname osinfo;
const char *id = xmpp_stanza_get_id(stanza);
query = xmpp_stanza_get_child_by_name_and_ns(
stanza, "query", "http://jabber.org/protocol/disco#info");
const char *type = xmpp_stanza_get_attribute(stanza, "type");
if (query && type && weechat_strcasecmp(type, "get") == 0)
{
char *client_name;
reply = xmpp_stanza_reply(stanza);
xmpp_stanza_set_type(reply, "result");
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");
client_name = weechat_string_eval_expression("weechat ${info:version}",
NULL, NULL, NULL);
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);
identity = xmpp_stanza_new(account->context);
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);
#define FEATURE(ns) \
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_set_attribute(feature, "var", NS); \
xmpp_stanza_add_child(query, feature); \
xmpp_stanza_release(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");
@ -693,167 +846,137 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd
FEATURE("urn:xmpp:time");
#undef FEATURE
x = xmpp_stanza_new(account->context);
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.
{
field = xmpp_stanza_new(account->context);
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");
#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
text = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(text, "urn:xmpp:dataforms:softwareinfo");
xmpp_stanza_add_child(value, text);
xmpp_stanza_release(text);
xmpp_stanza_add_child(query, x);
xmpp_stanza_release(x);
xmpp_stanza_add_child(field, value);
xmpp_stanza_release(value);
xmpp_stanza_set_type(reply, "result");
xmpp_stanza_add_child(reply, query);
xmpp_stanza_add_child(x, field);
xmpp_stanza_release(field);
}
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)
{
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);
char *cap_hash = xmpp_base64_encode(account->context, digest, 20);
*hash = strdup(cap_hash);
xmpp_free(account->context, cap_hash);
}
{
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);
return reply;
}
xmpp_stanza_add_child(x, field);
xmpp_stanza_release(field);
}
int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userdata)
{
struct t_account *account = (struct t_account *)userdata;
xmpp_stanza_t *reply, *query, *text, *fin;
xmpp_stanza_t *pubsub, *items, *item, *list, *bundle, *device;
xmpp_stanza_t *storage, *conference, *nick;
const char *id = xmpp_stanza_get_id(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(
stanza, "query", "http://jabber.org/protocol/disco#info");
const char *type = xmpp_stanza_get_attribute(stanza, "type");
if (query && type)
{
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);
}
if (weechat_strcasecmp(type, "get") == 0)
{
field = xmpp_stanza_new(account->context);
xmpp_stanza_set_name(field, "field");
xmpp_stanza_set_attribute(field, "var", "software");
reply = connection__get_caps(xmpp_stanza_reply(stanza), account, NULL);
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);
xmpp_send(conn, reply);
xmpp_stanza_release(reply);
}
if (weechat_strcasecmp(type, "result") == 0)
{
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(
stanza, "pubsub", "http://jabber.org/protocol/pubsub");
if (pubsub)
{
const char *items_node, *item_id, *device_id, *ns, *node;
const char *items_node, *item_id, *device_id;
items = xmpp_stanza_get_child_by_name(pubsub, "items");
if (items)
@ -865,30 +988,64 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd
{
item = xmpp_stanza_get_child_by_name(items, "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(
item, "list", "eu.siacs.conversations.axolotl");
if (list && account->omemo)
{
account__free_device_all(account);
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)
{
struct t_account_device *dev;
char id[64] = {0};
int i = 0;
account__free_device_all(account);
dev = malloc(sizeof(struct t_account_device));
dev->id = account->omemo->device_id;
snprintf(id, sizeof(id), "%d", dev->id);
dev->name = strdup(id);
dev->label = strdup("weechat");
account__add_device(account, dev);
children = malloc(sizeof(xmpp_stanza_t *) * 128);
children[i++] = stanza__iq_pubsub_publish_item_list_device(
account->context, NULL, with_noop(dev->name));
free(dev->label);
free(dev->name);
free(dev);
@ -904,90 +1061,48 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd
dev = malloc(sizeof(struct t_account_device));
dev->id = atoi(device_id);
dev->name = strdup(device_id);
dev->label = NULL;
account__add_device(account, dev);
children[i++] = stanza__iq_pubsub_publish_item_list_device(
account->context, NULL, with_noop(dev->name));
free(dev->label);
free(dev->name);
free(dev);
}
children[i] = NULL;
node = "eu.siacs.conversations.axolotl";
children[0] = stanza__iq_pubsub_publish_item_list(
account->context, NULL, children, with_noop(node));
children[1] = NULL;
children[0] = stanza__iq_pubsub_publish_item(
account->context, NULL, children, with_noop("current"));
ns = "http://jabber.org/protocol/pubsub";
children[0] = stanza__iq_pubsub_publish(account->context,
NULL, children,
with_noop(ns));
children[0] = stanza__iq_pubsub(account->context, NULL,
children, with_noop(""));
reply = stanza__iq(account->context, xmpp_stanza_reply(stanza),
children, NULL, strdup("announce1"),
NULL, NULL, strdup("set"));
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_stanza_release(reply);
char bundle_node[128] = {0};
snprintf(bundle_node, sizeof(bundle_node),
"eu.siacs.conversations.axolotl.bundles:%d",
account->omemo->device_id);
xmpp_stanza_t *textchild[2] = {NULL};
textchild[0] = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(textchild[0], "b64enc1");
children[0] = stanza__iq_pubsub_publish_item_bundle_signedPreKeyPublic(
account->context, NULL, textchild, with_noop("1"));
textchild[0] = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(textchild[0], "b64enc2");
children[1] = stanza__iq_pubsub_publish_item_bundle_signedPreKeySignature(
account->context, NULL, textchild);
textchild[0] = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(textchild[0], "b64enc3");
children[2] = stanza__iq_pubsub_publish_item_bundle_identityKey(
account->context, NULL, textchild);
textchild[0] = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(textchild[0], "b64enc4");
children[3] = stanza__iq_pubsub_publish_item_bundle_prekeys_preKeyPublic(
account->context, NULL, textchild, with_noop("1"));
textchild[0] = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(textchild[0], "b64enc5");
children[4] = stanza__iq_pubsub_publish_item_bundle_prekeys_preKeyPublic(
account->context, NULL, textchild, with_noop("2"));
textchild[0] = xmpp_stanza_new(account->context);
xmpp_stanza_set_text(textchild[0], "b64enc6");
children[5] = stanza__iq_pubsub_publish_item_bundle_prekeys_preKeyPublic(
account->context, NULL, textchild, with_noop("3"));
children[6] = NULL;
children[3] = stanza__iq_pubsub_publish_item_bundle_prekeys(
account->context, NULL, &children[3]);
children[4] = NULL;
ns = "eu.siacs.conversations.axolotl";
children[0] = stanza__iq_pubsub_publish_item_bundle(
account->context, NULL, children, with_noop(ns));
children[1] = NULL;
children[0] = stanza__iq_pubsub_publish_item(
account->context, NULL, children, with_noop("current"));
children[0] = stanza__iq_pubsub_publish(account->context,
NULL, children,
with_noop(bundle_node));
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("announce2"),
strdup(account_jid(account)), strdup(account_jid(account)),
strdup("set"));
xmpp_send(conn, children[0]);
xmpp_stanza_release(children[0]);
free(children);
}
}
}
}
if (items_node
&& strncmp(items_node,
"eu.siacs.conversations.axolotl.bundles",
strnlen(items_node,
strlen("eu.siacs.conversations.axolotl.bundles"))) == 0)
{
item = xmpp_stanza_get_child_by_name(items, "item");
if (item)
{
bundle = xmpp_stanza_get_child_by_name_and_ns(item, "bundle", "eu.siacs.conversations.axolotl");
if (bundle)
{
size_t node_prefix =
strlen("eu.siacs.conversations.axolotl.bundles:");
if (account->omemo && strlen(items_node) > node_prefix)
{
omemo__handle_bundle(account->omemo,
from ? from : account_jid(account),
strtol(items_node+node_prefix,
NULL, 10),
items);
}
}
}
}
@ -1032,6 +1147,12 @@ int connection__iq_handler(xmpp_conn_t *conn, xmpp_stanza_t *stanza, void *userd
weechat_string_dyn_concat(command, intext, -1);
}
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);
}
@ -1094,7 +1215,6 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status,
xmpp_stanza_t *pres, *pres__c, *pres__status, *pres__status__text,
*pres__x, *pres__x__text, **children;
char cap_hash[28+1] = {0};
xmpp_handler_add(conn, &connection__version_handler,
"jabber:iq:version", "iq", NULL, account);
@ -1121,8 +1241,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_attribute(pres__c, "hash", "sha-1");
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);
free(cap_hash);
children[0] = pres__c;
pres__status = xmpp_stanza_new(account->context);
@ -1192,16 +1319,27 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status,
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, strdup("fetch1"),
stanza__iq(account->context, NULL, children, NULL, uuid,
strdup(account_jid(account)), strdup(account_jid(account)),
strdup("get"));
xmpp_free(account->context, uuid);
xmpp_send(conn, children[0]);
xmpp_stanza_release(children[0]);
omemo__init(account->buffer, &account->omemo, account->name);
if (account->omemo)
{
children[0] =
omemo__get_bundle(account->context,
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",
WEECHAT_HOOK_SIGNAL_STRING, account->name);
}
@ -1215,7 +1353,6 @@ void connection__handler(xmpp_conn_t *conn, xmpp_conn_event_t status,
char* connection__rand_string(int length)
{
char *string = malloc(length);
srand(time(NULL));
for(int i = 0; i < length; ++i){
string[i] = '0' + rand()%72; // starting on '0', ending on '}'
if (!((string[i] >= '0' && string[i] <= '9') ||

@ -4,6 +4,8 @@
#include <strophe.h>
#include <stdlib.h>
#include <stdint.h>
#include <weechat/weechat-plugin.h>
#include "plugin.h"
#include "account.h"
@ -32,16 +34,20 @@ int input__data(struct t_gui_buffer *buffer, const char *text)
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
{
weechat_printf(buffer,
_("%s%s: this buffer is not a channel!"),
weechat_prefix("error"), WEECHAT_XMPP_PLUGIN_NAME);
}
return WEECHAT_RC_OK;
}
}
int input__data_cb(const void *pointer, void *data,

@ -0,0 +1,126 @@
(define-module (libomemo)
#:use-module (gnu packages)
#:use-module (gnu packages admin)
#:use-module (gnu packages aidc)
#:use-module (gnu packages aspell)
#:use-module (gnu packages audio)
#:use-module (gnu packages autotools)
#:use-module (gnu packages avahi)
#:use-module (gnu packages base)
#:use-module (gnu packages bash)
#:use-module (gnu packages bison)
#:use-module (gnu packages boost)
#:use-module (gnu packages check)
#:use-module (gnu packages compression)
#:use-module (gnu packages cpp)
#:use-module (gnu packages crypto)
#:use-module (gnu packages curl)
#:use-module (gnu packages cyrus-sasl)
#:use-module (gnu packages databases)
#:use-module (gnu packages docbook)
#:use-module (gnu packages documentation)
#:use-module (gnu packages enchant)
#:use-module (gnu packages fontutils)
#:use-module (gnu packages freedesktop)
#:use-module (gnu packages gettext)
#:use-module (gnu packages glib)
#:use-module (gnu packages gnome)
#:use-module (gnu packages gnupg)
#:use-module (gnu packages golang)
#:use-module (gnu packages gperf)
#:use-module (gnu packages graphviz)
#:use-module (gnu packages gstreamer)
#:use-module (gnu packages gtk)
#:use-module (gnu packages guile)
#:use-module (gnu packages icu4c)
#:use-module (gnu packages image)
#:use-module (gnu packages kde)
#:use-module (gnu packages kerberos)
#:use-module (gnu packages less)
#:use-module (gnu packages libcanberra)
#:use-module (gnu packages libffi)
#:use-module (gnu packages libidn)
#:use-module (gnu packages libreoffice)
#:use-module (gnu packages linux)
#:use-module (gnu packages logging)
#:use-module (gnu packages lua)
#:use-module (gnu packages man)
#:use-module (gnu packages markup)
#:use-module (gnu packages matrix)
#:use-module (gnu packages mono)
#:use-module (gnu packages mpd)
#:use-module (gnu packages ncurses)
#:use-module (gnu packages networking)
#:use-module (gnu packages nss)
#:use-module (gnu packages pcre)
#:use-module (gnu packages perl)
#:use-module (gnu packages photo)
#:use-module (gnu packages php)
#:use-module (gnu packages pkg-config)
#:use-module (gnu packages protobuf)
#:use-module (gnu packages python)
#:use-module (gnu packages python-check)
#:use-module (gnu packages python-crypto)
#:use-module (gnu packages python-web)
#:use-module (gnu packages python-xyz)
#:use-module (gnu packages qt)
#:use-module (gnu packages readline)
#:use-module (gnu packages ruby)
#:use-module (gnu packages sphinx)
#:use-module (gnu packages sqlite)
#:use-module (gnu packages tcl)
#:use-module (gnu packages texinfo)
#:use-module (gnu packages textutils)
#:use-module (gnu packages tls)
#:use-module (gnu packages video)
#:use-module (gnu packages web)
#:use-module (gnu packages xdisorg)
#:use-module (gnu packages xiph)
#:use-module (gnu packages xml)
#:use-module (gnu packages xorg)
#:use-module (guix build-system cmake)
#:use-module (guix build-system go)
#:use-module (guix build-system glib-or-gtk)
#:use-module (guix build-system gnu)
#:use-module (guix build-system meson)
#:use-module (guix build-system perl)
#:use-module (guix build-system python)
#:use-module (guix build-system qt)
#:use-module (guix build-system trivial)
#:use-module (guix download)
#:use-module (guix git-download)
#:use-module (guix hg-download)
#:use-module ((guix licenses) #:prefix license:)
#:use-module (guix packages)
#:use-module (guix utils))
(define-public libomemo-c
(package
(name "libomemo-c")
(version "2.3.3")
(source (origin
(method git-fetch)
(uri (git-reference
(url "https://github.com/dino/libomemo-c")
(commit "06184660790daa42433e616fa3dee730717d1c1b")))
(file-name (git-file-name name version))
(sha256
(base32
"1wa85r1b54myabsbmbqlq9jz174mmvd02b8zy1j4j0kml0anp6nx"))))
(arguments
`(;; Required for proper linking and for tests to run.
#:configure-flags '("-DBUILD_SHARED_LIBS=on" "-DBUILD_TESTING=1")))
(build-system cmake-build-system)
(inputs `( ;; Required for tests:
("check" ,check)
("openssl" ,openssl)))
(native-inputs `(("pkg-config" ,pkg-config)))
(home-page "https://github.com/WhisperSystems/libsignal-protocol-c")
(synopsis "Implementation of a ratcheting forward secrecy protocol")
(description "libsignal-protocol-c is an implementation of a ratcheting
forward secrecy protocol that works in synchronous and asynchronous
messaging environments. It can be used with messaging software to provide
end-to-end encryption.")
(license license:gpl3+)))
libomemo-c

@ -9,7 +9,7 @@ FIND=find
INCLUDES=-Ilibstrophe \
$(shell xml2-config --cflags) \
$(shell pkg-config --cflags librnp-0) \
$(shell pkg-config --cflags libsignal-protocol-c)
$(shell pkg-config --cflags libomemo-c)
CFLAGS+=$(DBGCFLAGS) \
-fno-omit-frame-pointer -fPIC \
-std=gnu99 -gdwarf-4 \
@ -32,7 +32,7 @@ LDLIBS=-lstrophe \
-lpthread \
$(shell xml2-config --libs) \
$(shell pkg-config --libs librnp-0) \
$(shell pkg-config --libs libsignal-protocol-c) \
$(shell pkg-config --libs libomemo-c) \
-lgcrypt \
-llmdb

@ -4,6 +4,7 @@
#include <strophe.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <regex.h>

2000
omemo.c

File diff suppressed because it is too large Load Diff

@ -13,20 +13,44 @@ struct t_omemo
struct signal_protocol_store_context *store_context;
struct t_omemo_db *db;
char *db_path;
struct ratchet_identity_key_pair *identity;
uint32_t device_id;
};
struct t_omemo_bundle_req
{
char *id;
char *jid;
char *device;
char *message_text;
};
struct t_omemo_devicelist_req
{
char *id;
struct t_omemo_bundle_req bundle_req;
};
xmpp_stanza_t *omemo__get_bundle(xmpp_ctx_t *context, char *from, char *to,
struct t_omemo *omemo);
void omemo__init(struct t_gui_buffer *buffer, struct t_omemo **omemo,
const char *account_name);
void omemo__serialize(struct t_omemo *omemo, char **device,
char **identity, size_t *identity_len);
void omemo__handle_devicelist(struct t_omemo *omemo, const char *jid,
xmpp_stanza_t *items);
void omemo__handle_bundle(struct t_omemo *omemo, const char *jid,
uint32_t device_id, xmpp_stanza_t *items);
char *omemo__decode(struct t_account *account, const char *jid,
xmpp_stanza_t *encrypted);
void omemo__deserialize(struct t_omemo *omemo, const char *device,
const char *identity, size_t identity_len);
xmpp_stanza_t *omemo__encode(struct t_account *account, const char *jid,
const char *unencrypted);
void omemo__free(struct t_omemo *omemo);

@ -5,15 +5,11 @@
#ifndef _WEECHAT_XMPP_PLUGIN_H_
#define _WEECHAT_XMPP_PLUGIN_H_
#ifndef __cplusplus
#include <weechat/weechat-plugin.h>
#define weechat_plugin weechat_xmpp_plugin()
#define WEECHAT_XMPP_PLUGIN_NAME weechat_xmpp_plugin_name()
#define WEECHAT_XMPP_PLUGIN_VERSION weechat_xmpp_plugin_version()
#endif//__cplusplus
#define weechat_plugin weechat_xmpp_plugin
#define WEECHAT_XMPP_PLUGIN_NAME "xmpp"
#define WEECHAT_XMPP_PLUGIN_VERSION "0.1.1"
#define TIMER_INTERVAL_SEC 0.01
struct t_weechat_plugin *weechat_xmpp_plugin();
const char *weechat_xmpp_plugin_name();
const char *weechat_xmpp_plugin_version();
extern struct t_weechat_plugin *weechat_xmpp_plugin;
#endif /*WEECHAT_XMPP_PLUGIN_H*/

@ -3,6 +3,7 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <strophe.h>
@ -140,7 +141,7 @@ void user__nicklist_remove(struct t_account *account,
ptr_buffer = channel ? channel->buffer : account->buffer;
if ((ptr_nick = weechat_nicklist_search_nick(ptr_buffer, NULL, name)))
if (name && (ptr_nick = weechat_nicklist_search_nick(ptr_buffer, NULL, name)))
weechat_nicklist_remove_nick(ptr_buffer, ptr_nick);
}
@ -190,6 +191,7 @@ struct t_user *user__new(struct t_account *account,
new_user->profile.email = NULL;
new_user->profile.role = NULL;
new_user->profile.pgp_id = NULL;
new_user->profile.omemo = 0;
new_user->updated = 0;
new_user->is_away = 0;

@ -16,6 +16,7 @@ struct t_user_profile
char *role;
char *affiliation;
char *pgp_id;
int omemo;
};
struct t_user

@ -98,9 +98,36 @@ xmpp_stanza_t *stanza__iq_pubsub_items(xmpp_ctx_t *context, xmpp_stanza_t *base,
if (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);
}
if (jid)
{
xmpp_stanza_set_attribute(parent, "jid", jid->value);
jid->finalize(jid);
free(jid);
}
return parent;
}
@ -193,7 +220,7 @@ xmpp_stanza_t *stanza__iq_pubsub_publish_item_list(xmpp_ctx_t *context, xmpp_sta
}
xmpp_stanza_t *stanza__iq_pubsub_publish_item_list_device(xmpp_ctx_t *context, xmpp_stanza_t *base,
struct t_string *id)
struct t_string *id, struct t_string *label)
{
xmpp_stanza_t *parent = base;
@ -210,6 +237,13 @@ xmpp_stanza_t *stanza__iq_pubsub_publish_item_list_device(xmpp_ctx_t *context, x
free(id);
}
if (label)
{
xmpp_stanza_set_attribute(parent, "label", label->value);
label->finalize(label);
free(label);
}
return parent;
}
@ -401,3 +435,31 @@ xmpp_stanza_t *stanza__iq_ping(xmpp_ctx_t *context, xmpp_stanza_t *base,
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;
}

@ -49,6 +49,22 @@ static inline struct t_string *with_xmpp_free(char *value, xmpp_ctx_t *pointer)
return string;
}
static inline void stanza__set_text(xmpp_ctx_t *context, xmpp_stanza_t *parent,
struct t_string *value)
{
xmpp_stanza_t *text = xmpp_stanza_new(context);
if (value)
{
xmpp_stanza_set_text(text, value->value);
xmpp_stanza_add_child(parent, text);
value->finalize(value);
free(value);
}
xmpp_stanza_release(text);
}
xmpp_stanza_t *stanza__presence(xmpp_ctx_t *context, xmpp_stanza_t *base,
xmpp_stanza_t **children, const char *ns,
char *from, char *to, const char *type);
@ -62,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_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 **children, struct t_string *node);
@ -72,7 +91,7 @@ xmpp_stanza_t *stanza__iq_pubsub_publish_item_list(xmpp_ctx_t *context, xmpp_sta
xmpp_stanza_t **children, struct t_string *ns);
xmpp_stanza_t *stanza__iq_pubsub_publish_item_list_device(xmpp_ctx_t *context, xmpp_stanza_t *base,
struct t_string *id);
struct t_string *id, struct t_string *label);
xmpp_stanza_t *stanza__iq_pubsub_publish_item_bundle(xmpp_ctx_t *context, xmpp_stanza_t *base,
xmpp_stanza_t **children, struct t_string *ns);
@ -98,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,
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*/

Loading…
Cancel
Save