diff --git a/CMakeLists.txt b/CMakeLists.txt
index cc551a64..ba9d93dd 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,5 @@
cmake_minimum_required(VERSION 3.0)
+project(Dino LANGUAGES C)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
# Prepare Plugins
diff --git a/libdino/src/service/database.vala b/libdino/src/service/database.vala
index 5a92446d..604fcdcc 100644
--- a/libdino/src/service/database.vala
+++ b/libdino/src/service/database.vala
@@ -236,40 +236,50 @@ public class Database : Qlite.Database {
message.fts_rebuild();
}
if (oldVersion < 8) {
- exec("""
- insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide)
- select conversation.id, message.time, message.local_time, 1, message.id, 0
- from message join conversation on
- message.account_id=conversation.account_id and
- message.counterpart_id=conversation.jid_id and
- message.type=conversation.type+1 and
- (message.counterpart_resource=conversation.resource or message.type != 3)
- where
- message.body not in (select info from file_transfer where info not null) and
- message.id not in (select info from file_transfer where info not null)
- union
- select conversation.id, message.time, message.local_time, 2, file_transfer.id, 0
- from file_transfer
- join message on
- file_transfer.info=message.id
- join conversation on
- file_transfer.account_id=conversation.account_id and
- file_transfer.counterpart_id=conversation.jid_id and
- message.type=conversation.type+1 and
- (message.counterpart_resource=conversation.resource or message.type != 3)""");
+ try {
+ exec("""
+ insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide)
+ select conversation.id, message.time, message.local_time, 1, message.id, 0
+ from message join conversation on
+ message.account_id=conversation.account_id and
+ message.counterpart_id=conversation.jid_id and
+ message.type=conversation.type+1 and
+ (message.counterpart_resource=conversation.resource or message.type != 3)
+ where
+ message.body not in (select info from file_transfer where info not null) and
+ message.id not in (select info from file_transfer where info not null)
+ union
+ select conversation.id, message.time, message.local_time, 2, file_transfer.id, 0
+ from file_transfer
+ join message on
+ file_transfer.info=message.id
+ join conversation on
+ file_transfer.account_id=conversation.account_id and
+ file_transfer.counterpart_id=conversation.jid_id and
+ message.type=conversation.type+1 and
+ (message.counterpart_resource=conversation.resource or message.type != 3)""");
+ } catch (Error e) {
+ stderr.printf("Failed to upgrade to database version 8: %s\n", e.message);
+ Process.exit(-1);
+ }
}
if (oldVersion < 9) {
- exec("""
- insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide)
- select conversation.id, message.time, message.local_time, 1, message.id, 1
- from message join conversation on
- message.account_id=conversation.account_id and
- message.counterpart_id=conversation.jid_id and
- message.type=conversation.type+1 and
- (message.counterpart_resource=conversation.resource or message.type != 3)
- where
- message.body in (select info from file_transfer where info not null) or
- message.id in (select info from file_transfer where info not null)""");
+ try {
+ exec("""
+ insert into content_item (conversation_id, time, local_time, content_type, foreign_id, hide)
+ select conversation.id, message.time, message.local_time, 1, message.id, 1
+ from message join conversation on
+ message.account_id=conversation.account_id and
+ message.counterpart_id=conversation.jid_id and
+ message.type=conversation.type+1 and
+ (message.counterpart_resource=conversation.resource or message.type != 3)
+ where
+ message.body in (select info from file_transfer where info not null) or
+ message.id in (select info from file_transfer where info not null)""");
+ } catch (Error e) {
+ stderr.printf("Failed to upgrade to database version 8: %s\n", e.message);
+ Process.exit(-1);
+ }
}
}
diff --git a/main/src/ui/avatar_generator.vala b/main/src/ui/avatar_generator.vala
index 012dabe4..2a6aa397 100644
--- a/main/src/ui/avatar_generator.vala
+++ b/main/src/ui/avatar_generator.vala
@@ -5,6 +5,7 @@ using Gtk;
using Dino.Entities;
using Xmpp;
+using Xmpp.Util;
namespace Dino.Ui {
@@ -259,10 +260,10 @@ public class AvatarGenerator {
}
private static void set_source_hex_color(Context ctx, string hex_color) {
- ctx.set_source_rgba((double) hex_color.substring(0, 2).to_long(null, 16) / 255,
- (double) hex_color.substring(2, 2).to_long(null, 16) / 255,
- (double) hex_color.substring(4, 2).to_long(null, 16) / 255,
- hex_color.length > 6 ? (double) hex_color.substring(6, 2).to_long(null, 16) / 255 : 1);
+ ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255,
+ (double) from_hex(hex_color.substring(2, 2)) / 255,
+ (double) from_hex(hex_color.substring(4, 2)) / 255,
+ hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1);
}
}
diff --git a/main/src/ui/avatar_image.vala b/main/src/ui/avatar_image.vala
index d98e5baa..cc700f00 100644
--- a/main/src/ui/avatar_image.vala
+++ b/main/src/ui/avatar_image.vala
@@ -1,6 +1,7 @@
using Gtk;
using Dino.Entities;
using Xmpp;
+using Xmpp.Util;
namespace Dino.Ui {
@@ -74,10 +75,10 @@ public class AvatarImage : Misc {
}
private static void set_source_hex_color(Cairo.Context ctx, string hex_color) {
- ctx.set_source_rgba((double) hex_color.substring(0, 2).to_long(null, 16) / 255,
- (double) hex_color.substring(2, 2).to_long(null, 16) / 255,
- (double) hex_color.substring(4, 2).to_long(null, 16) / 255,
- hex_color.length > 6 ? (double) hex_color.substring(6, 2).to_long(null, 16) / 255 : 1);
+ ctx.set_source_rgba((double) from_hex(hex_color.substring(0, 2)) / 255,
+ (double) from_hex(hex_color.substring(2, 2)) / 255,
+ (double) from_hex(hex_color.substring(4, 2)) / 255,
+ hex_color.length > 6 ? (double) from_hex(hex_color.substring(6, 2)) / 255 : 1);
}
public override bool draw(Cairo.Context ctx_in) {
diff --git a/main/src/ui/conversation_selector/conversation_selector_row.vala b/main/src/ui/conversation_selector/conversation_selector_row.vala
index 37b8ebde..46f6c1a8 100644
--- a/main/src/ui/conversation_selector/conversation_selector_row.vala
+++ b/main/src/ui/conversation_selector/conversation_selector_row.vala
@@ -136,7 +136,11 @@ public class ConversationSelectorRow : ListBoxRow {
nick_label.label = last_message.direction == Message.DIRECTION_SENT ? _("Me") + ": " : "";
}
- message_label.label = Markup.escape_text((/\s+/).replace_literal(last_message.body, -1, 0, " "));
+ try {
+ message_label.label = Markup.escape_text((/\s+/).replace_literal(last_message.body, -1, 0, " "));
+ } catch (RegexError e) {
+ assert_not_reached();
+ }
break;
case FileItem.TYPE:
FileItem file_item = last_content_item as FileItem;
diff --git a/main/src/ui/global_search.vala b/main/src/ui/global_search.vala
index 73a61dc5..db7dbc0f 100644
--- a/main/src/ui/global_search.vala
+++ b/main/src/ui/global_search.vala
@@ -206,27 +206,31 @@ public class GlobalSearch : Overlay {
// Color the keywords
int elongated_by = 0;
- Regex highlight_regex = new Regex(regex_str);
- MatchInfo match_info;
- string markup_text_bak = markup_text.down();
- highlight_regex.match(markup_text_bak, 0, out match_info);
- for (; match_info.matches(); match_info.next()) {
- int start, end;
- match_info.fetch_pos(0, out start, out end);
- markup_text = markup_text[0:start+elongated_by] + "" + markup_text[start+elongated_by:end+elongated_by] + "" + markup_text[end+elongated_by:markup_text.length];
- elongated_by += "".length + "".length;
+ try {
+ Regex highlight_regex = new Regex(regex_str);
+ MatchInfo match_info;
+ string markup_text_bak = markup_text.down();
+ highlight_regex.match(markup_text_bak, 0, out match_info);
+ for (; match_info.matches(); match_info.next()) {
+ int start, end;
+ match_info.fetch_pos(0, out start, out end);
+ markup_text = markup_text[0:start+elongated_by] + "" + markup_text[start+elongated_by:end+elongated_by] + "" + markup_text[end+elongated_by:markup_text.length];
+ elongated_by += "".length + "".length;
+ }
+ markup_text_bak += ""; // We need markup_text_bak to live until here because url_regex.match does not copy the string
+
+ label.label = markup_text;
+ grid.attach(label, 1, 1, 1, 1);
+
+ Button button = new Button() { relief=ReliefStyle.NONE, visible=true };
+ button.clicked.connect(() => {
+ selected_item(item);
+ });
+ button.add(grid);
+ return button;
+ } catch (RegexError e) {
+ assert_not_reached();
}
- markup_text_bak += ""; // We need markup_text_bak to live until here because url_regex.match does not copy the string
-
- label.label = markup_text;
- grid.attach(label, 1, 1, 1, 1);
-
- Button button = new Button() { relief=ReliefStyle.NONE, visible=true };
- button.clicked.connect(() => {
- selected_item(item);
- });
- button.add(grid);
- return button;
}
private Grid get_context_message_widget(MessageItem item) {
diff --git a/main/src/ui/notifications.vala b/main/src/ui/notifications.vala
index b8792bee..e495e629 100644
--- a/main/src/ui/notifications.vala
+++ b/main/src/ui/notifications.vala
@@ -125,8 +125,10 @@ public class Notifications : Object {
string body = _("%s invited you to %s").printf(display_name, display_room);
notification.set_body(body);
- Cairo.ImageSurface jid_avatar = yield (new AvatarGenerator(40, 40)).draw_jid(stream_interactor, from_jid, account);
- notification.set_icon(get_pixbuf_icon(jid_avatar));
+ try {
+ Cairo.ImageSurface jid_avatar = yield (new AvatarGenerator(40, 40)).draw_jid(stream_interactor, from_jid, account);
+ notification.set_icon(get_pixbuf_icon(jid_avatar));
+ } catch (Error e) { }
Conversation conversation = stream_interactor.get_module(ConversationManager.IDENTITY).create_conversation(room_jid, account, Conversation.Type.GROUPCHAT);
notification.set_default_action_and_target_value("app.open-muc-join", new Variant.int32(conversation.id));
diff --git a/main/src/ui/unified_window_controller.vala b/main/src/ui/unified_window_controller.vala
index 1ca3daae..21725574 100644
--- a/main/src/ui/unified_window_controller.vala
+++ b/main/src/ui/unified_window_controller.vala
@@ -153,11 +153,19 @@ public class UnifiedWindowController : Object {
private void update_conversation_topic(string? subtitle = null) {
if (subtitle != null) {
- conversation_topic = (/\s+/).replace_literal(subtitle, -1, 0, " ");
+ try {
+ conversation_topic = (/\s+/).replace_literal(subtitle, -1, 0, " ");
+ } catch (RegexError e) {
+ assert_not_reached();
+ }
} else if (conversation.type_ == Conversation.Type.GROUPCHAT) {
string? subject = stream_interactor.get_module(MucManager.IDENTITY).get_groupchat_subject(conversation.counterpart, conversation.account);
if (subject != null) {
- conversation_topic = (/\s+/).replace_literal(subject, -1, 0, " ");
+ try {
+ conversation_topic = (/\s+/).replace_literal(subject, -1, 0, " ");
+ } catch (RegexError e) {
+ assert_not_reached();
+ }
} else {
conversation_topic = null;
}
diff --git a/main/src/ui/util/helper.vala b/main/src/ui/util/helper.vala
index 449936fc..c3353fb6 100644
--- a/main/src/ui/util/helper.vala
+++ b/main/src/ui/util/helper.vala
@@ -188,15 +188,19 @@ public static string parse_add_markup(string s_, string? highlight_word, bool pa
}
if (highlight_word != null) {
- Regex highlight_regex = new Regex("\\b" + Regex.escape_string(highlight_word.down()) + "\\b");
- MatchInfo match_info;
- highlight_regex.match(s.down(), 0, out match_info);
- if (match_info.matches()) {
- int start, end;
- match_info.fetch_pos(0, out start, out end);
- return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
- "" + s[start:end] + "" +
- parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped);
+ try {
+ Regex highlight_regex = new Regex("\\b" + Regex.escape_string(highlight_word.down()) + "\\b");
+ MatchInfo match_info;
+ highlight_regex.match(s.down(), 0, out match_info);
+ if (match_info.matches()) {
+ int start, end;
+ match_info.fetch_pos(0, out start, out end);
+ return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
+ "" + s[start:end] + "" +
+ parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped);
+ }
+ } catch (RegexError e) {
+ assert_not_reached();
}
}
@@ -206,15 +210,19 @@ public static string parse_add_markup(string s_, string? highlight_word, bool pa
for (int i = 0; i < markup_string.length; i++) {
string markup_esc = Regex.escape_string(markup_string[i]);
- Regex regex = new Regex("(^|\\s)" + markup_esc + "(\\S.*?\\S|\\S)" + markup_esc + "($|\\s)");
- MatchInfo match_info;
- regex.match(s.down(), 0, out match_info);
- if (match_info.matches()) {
- int start, end;
- match_info.fetch_pos(2, out start, out end);
- return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
- @"<$(convenience_tag[i])>" + s[start:end] + @"$(convenience_tag[i])>" +
- parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped);
+ try {
+ Regex regex = new Regex("(^|\\s)" + markup_esc + "(\\S.*?\\S|\\S)" + markup_esc + "($|\\s)");
+ MatchInfo match_info;
+ regex.match(s.down(), 0, out match_info);
+ if (match_info.matches()) {
+ int start, end;
+ match_info.fetch_pos(2, out start, out end);
+ return parse_add_markup(s[0:start], highlight_word, parse_links, parse_text_markup, already_escaped) +
+ @"<$(convenience_tag[i])>" + s[start:end] + @"$(convenience_tag[i])>" +
+ parse_add_markup(s[end:s.length], highlight_word, parse_links, parse_text_markup, already_escaped);
+ }
+ } catch (RegexError e) {
+ assert_not_reached();
}
}
}
diff --git a/plugins/omemo/src/file_transfer/file_decryptor.vala b/plugins/omemo/src/file_transfer/file_decryptor.vala
index 6998fef2..bc6f8592 100644
--- a/plugins/omemo/src/file_transfer/file_decryptor.vala
+++ b/plugins/omemo/src/file_transfer/file_decryptor.vala
@@ -38,36 +38,40 @@ public class OmemoFileDecryptor : FileDecryptor, Object {
return this.url_regex.match(http_file_receive.url) || (receive_data as OmemoHttpFileReceiveData) != null;
}
- public async InputStream decrypt_file(InputStream encrypted_stream, Conversation conversation, FileTransfer file_transfer, FileReceiveData receive_data) {
- OmemoHttpFileReceiveData? omemo_http_receive_data = receive_data as OmemoHttpFileReceiveData;
- if (omemo_http_receive_data == null) assert(false);
+ public async InputStream decrypt_file(InputStream encrypted_stream, Conversation conversation, FileTransfer file_transfer, FileReceiveData receive_data) throws FileReceiveError {
+ try {
+ OmemoHttpFileReceiveData? omemo_http_receive_data = receive_data as OmemoHttpFileReceiveData;
+ if (omemo_http_receive_data == null) assert(false);
- // Decode IV and key
- MatchInfo match_info;
- this.url_regex.match(omemo_http_receive_data.original_url, 0, out match_info);
- uint8[] iv_and_key = hex_to_bin(match_info.fetch(2).up());
- uint8[] iv, key;
- if (iv_and_key.length == 44) {
- iv = iv_and_key[0:12];
- key = iv_and_key[12:44];
- } else {
- iv = iv_and_key[0:16];
- key = iv_and_key[16:48];
+ // Decode IV and key
+ MatchInfo match_info;
+ this.url_regex.match(omemo_http_receive_data.original_url, 0, out match_info);
+ uint8[] iv_and_key = hex_to_bin(match_info.fetch(2).up());
+ uint8[] iv, key;
+ if (iv_and_key.length == 44) {
+ iv = iv_and_key[0:12];
+ key = iv_and_key[12:44];
+ } else {
+ iv = iv_and_key[0:16];
+ key = iv_and_key[16:48];
+ }
+
+ // Read data
+ uint8[] buf = new uint8[256];
+ Array data = new Array(false, true, 0);
+ size_t len = -1;
+ do {
+ len = yield encrypted_stream.read_async(buf);
+ data.append_vals(buf, (uint) len);
+ } while(len > 0);
+
+ // Decrypt
+ uint8[] cleartext = Signal.aes_decrypt(Cipher.AES_GCM_NOPADDING, key, iv, data.data);
+ file_transfer.encryption = Encryption.OMEMO;
+ return new MemoryInputStream.from_data(cleartext);
+ } catch (Error e) {
+ throw new FileReceiveError.DECRYPTION_FAILED("OMEMO file decryption error: %s".printf(e.message));
}
-
- // Read data
- uint8[] buf = new uint8[256];
- Array data = new Array(false, true, 0);
- size_t len = -1;
- do {
- len = yield encrypted_stream.read_async(buf);
- data.append_vals(buf, (uint) len);
- } while(len > 0);
-
- // Decrypt
- uint8[] cleartext = Signal.aes_decrypt(Cipher.AES_GCM_NOPADDING, key, iv, data.data);
- file_transfer.encryption = Encryption.OMEMO;
- return new MemoryInputStream.from_data(cleartext);
}
private uint8[] hex_to_bin(string hex) {
diff --git a/plugins/omemo/src/logic/manager.vala b/plugins/omemo/src/logic/manager.vala
index a71dfd9d..53e02e37 100644
--- a/plugins/omemo/src/logic/manager.vala
+++ b/plugins/omemo/src/logic/manager.vala
@@ -326,22 +326,22 @@ public class Manager : StreamInteractionModule, Object {
store.identity_key_store.local_registration_id = Random.int_range(1, int32.MAX);
Signal.ECKeyPair key_pair = Plugin.get_context().generate_key_pair();
- store.identity_key_store.identity_key_private = key_pair.private.serialize();
- store.identity_key_store.identity_key_public = key_pair.public.serialize();
+ store.identity_key_store.identity_key_private = new Bytes(key_pair.private.serialize());
+ store.identity_key_store.identity_key_public = new Bytes(key_pair.public.serialize());
identity_id = (int) db.identity.insert().or("REPLACE")
.value(db.identity.account_id, account.id)
.value(db.identity.device_id, (int) store.local_registration_id)
- .value(db.identity.identity_key_private_base64, Base64.encode(store.identity_key_store.identity_key_private))
- .value(db.identity.identity_key_public_base64, Base64.encode(store.identity_key_store.identity_key_public))
+ .value(db.identity.identity_key_private_base64, Base64.encode(store.identity_key_store.identity_key_private.get_data()))
+ .value(db.identity.identity_key_public_base64, Base64.encode(store.identity_key_store.identity_key_public.get_data()))
.perform();
} catch (Error e) {
// Ignore error
}
} else {
store.identity_key_store.local_registration_id = ((!)row)[db.identity.device_id];
- store.identity_key_store.identity_key_private = Base64.decode(((!)row)[db.identity.identity_key_private_base64]);
- store.identity_key_store.identity_key_public = Base64.decode(((!)row)[db.identity.identity_key_public_base64]);
+ store.identity_key_store.identity_key_private = new Bytes(Base64.decode(((!)row)[db.identity.identity_key_private_base64]));
+ store.identity_key_store.identity_key_public = new Bytes(Base64.decode(((!)row)[db.identity.identity_key_public_base64]));
identity_id = ((!)row)[db.identity.id];
}
diff --git a/plugins/omemo/src/ui/util.vala b/plugins/omemo/src/ui/util.vala
index 88d30b3b..cf61ed82 100644
--- a/plugins/omemo/src/ui/util.vala
+++ b/plugins/omemo/src/ui/util.vala
@@ -1,3 +1,5 @@
+using Xmpp.Util;
+
namespace Dino.Plugins.Omemo {
public static string fingerprint_from_base64(string b64) {
@@ -19,7 +21,7 @@ public static string fingerprint_markup(string s) {
for (int i = 0; i < s.length; i += 4) {
string four_chars = s.substring(i, 4).down();
- int raw = (int) four_chars.to_long(null, 16);
+ int raw = (int) from_hex(four_chars);
uint8[] bytes = {(uint8) ((raw >> 8) & 0xff - 128), (uint8) (raw & 0xff - 128)};
Checksum checksum = new Checksum(ChecksumType.SHA1);
@@ -57,4 +59,4 @@ public static string fingerprint_markup(string s) {
return "" + markup + "";
}
-}
\ No newline at end of file
+}
diff --git a/plugins/openpgp/src/file_transfer/file_decryptor.vala b/plugins/openpgp/src/file_transfer/file_decryptor.vala
index 7668023e..97eb9f43 100644
--- a/plugins/openpgp/src/file_transfer/file_decryptor.vala
+++ b/plugins/openpgp/src/file_transfer/file_decryptor.vala
@@ -35,7 +35,7 @@ public class PgpFileDecryptor : FileDecryptor, Object {
}
return new MemoryInputStream.from_data(clear_data.data, GLib.free);
} catch (Error e) {
- throw new FileReceiveError.DECRYPTION_FAILED("PGP file decrypt error: %s".printf(e.message));
+ throw new FileReceiveError.DECRYPTION_FAILED("PGP file decryption error: %s".printf(e.message));
}
}
}
diff --git a/plugins/openpgp/src/util.vala b/plugins/openpgp/src/util.vala
index 7c42b578..d40cf6ef 100644
--- a/plugins/openpgp/src/util.vala
+++ b/plugins/openpgp/src/util.vala
@@ -1,6 +1,7 @@
using Gtk;
using Dino.Entities;
+using Xmpp.Util;
namespace Dino.Plugins.OpenPgp {
@@ -10,7 +11,7 @@ public static string markup_colorize_id(string s, bool is_fingerprint) {
for (int i = 0; i < s.length; i += 4) {
string four_chars = s.substring(i, 4).down();
- int raw = (int) four_chars.to_long(null, 16);
+ int raw = (int) from_hex(four_chars);
uint8[] bytes = {(uint8) ((raw >> 8) & 0xff - 128), (uint8) (raw & 0xff - 128)};
Checksum checksum = new Checksum(ChecksumType.SHA1);
diff --git a/plugins/signal-protocol/src/simple_iks.vala b/plugins/signal-protocol/src/simple_iks.vala
index 1e575515..5247c455 100644
--- a/plugins/signal-protocol/src/simple_iks.vala
+++ b/plugins/signal-protocol/src/simple_iks.vala
@@ -3,8 +3,8 @@ using Gee;
namespace Signal {
public class SimpleIdentityKeyStore : IdentityKeyStore {
- public override uint8[] identity_key_private { get; set; }
- public override uint8[] identity_key_public { get; set; }
+ public override Bytes identity_key_private { get; set; }
+ public override Bytes identity_key_public { get; set; }
public override uint32 local_registration_id { get; set; }
private Map> trusted_identities = new HashMap>();
@@ -37,4 +37,4 @@ public class SimpleIdentityKeyStore : IdentityKeyStore {
}
}
-}
\ No newline at end of file
+}
diff --git a/plugins/signal-protocol/src/store.vala b/plugins/signal-protocol/src/store.vala
index 2e277478..632ff8cc 100644
--- a/plugins/signal-protocol/src/store.vala
+++ b/plugins/signal-protocol/src/store.vala
@@ -1,8 +1,8 @@
namespace Signal {
public abstract class IdentityKeyStore : Object {
- public abstract uint8[] identity_key_private { get; set; }
- public abstract uint8[] identity_key_public { get; set; }
+ public abstract Bytes identity_key_private { get; set; }
+ public abstract Bytes identity_key_public { get; set; }
public abstract uint32 local_registration_id { get; set; }
public signal void trusted_identity_added(TrustedIdentity id);
@@ -112,8 +112,8 @@ public class Store : Object {
static int iks_get_identity_key_pair(out Buffer public_data, out Buffer private_data, void* user_data) {
Store store = (Store) user_data;
- public_data = new Buffer.from(store.identity_key_store.identity_key_public);
- private_data = new Buffer.from(store.identity_key_store.identity_key_private);
+ public_data = new Buffer.from(store.identity_key_store.identity_key_public.get_data());
+ private_data = new Buffer.from(store.identity_key_store.identity_key_private.get_data());
return 0;
}
diff --git a/plugins/signal-protocol/tests/common.vala b/plugins/signal-protocol/tests/common.vala
index 26e90185..9bb9b1dc 100644
--- a/plugins/signal-protocol/tests/common.vala
+++ b/plugins/signal-protocol/tests/common.vala
@@ -15,8 +15,8 @@ Store setup_test_store_context(Context global_context) {
store.identity_key_store.local_registration_id = (Random.next_int() % 16380) + 1;
ECKeyPair key_pair = global_context.generate_key_pair();
- store.identity_key_store.identity_key_private = key_pair.private.serialize();
- store.identity_key_store.identity_key_public = key_pair.public.serialize();
+ store.identity_key_store.identity_key_private = new Bytes(key_pair.private.serialize());
+ store.identity_key_store.identity_key_public = new Bytes(key_pair.public.serialize());
} catch (Error e) {
fail_if_reached();
}
diff --git a/plugins/signal-protocol/vapi/signal-protocol-public.vapi b/plugins/signal-protocol/vapi/signal-protocol-public.vapi
index 0a4456ad..1952beb1 100644
--- a/plugins/signal-protocol/vapi/signal-protocol-public.vapi
+++ b/plugins/signal-protocol/vapi/signal-protocol-public.vapi
@@ -218,9 +218,14 @@ namespace Signal {
[CCode (instance_pos = 1, cname = "ec_public_key_serialize")]
private int serialize_([CCode (pos = 0)] out Buffer buffer);
[CCode (cname = "ec_public_key_serialize_")]
- public uint8[] serialize() throws GLib.Error {
+ public uint8[] serialize() {
Buffer buffer;
- throw_by_code(serialize_(out buffer));
+ try {
+ throw_by_code(serialize_(out buffer));
+ } catch (GLib.Error e) {
+ // Can only throw for invalid arguments or out of memory.
+ GLib.assert_not_reached();
+ }
return buffer.data;
}
public int compare(ECPublicKey other);
@@ -235,7 +240,12 @@ namespace Signal {
[CCode (cname = "ec_private_key_serialize_")]
public uint8[] serialize() throws GLib.Error {
Buffer buffer;
- throw_by_code(serialize_(out buffer));
+ try {
+ throw_by_code(serialize_(out buffer));
+ } catch (GLib.Error e) {
+ // Can only throw for invalid arguments or out of memory.
+ GLib.assert_not_reached();
+ }
return buffer.data;
}
public int compare(ECPublicKey other);
diff --git a/xmpp-vala/CMakeLists.txt b/xmpp-vala/CMakeLists.txt
index a0c15579..e0f01723 100644
--- a/xmpp-vala/CMakeLists.txt
+++ b/xmpp-vala/CMakeLists.txt
@@ -79,6 +79,8 @@ SOURCES
"src/module/xep/0368_srv_records_tls.vala"
"src/module/xep/0380_explicit_encryption.vala"
"src/module/xep/pixbuf_storage.vala"
+
+ "src/util.vala"
PACKAGES
${ENGINE_PACKAGES}
GENERATE_VAPI
@@ -110,6 +112,7 @@ if(BUILD_TESTS)
"tests/testcase.vala"
"tests/stanza.vala"
+ "tests/util.vala"
CUSTOM_VAPIS
${CMAKE_BINARY_DIR}/exports/xmpp-vala_internal.vapi
PACKAGES
diff --git a/xmpp-vala/src/core/stanza_reader.vala b/xmpp-vala/src/core/stanza_reader.vala
index c90390b5..1727847d 100644
--- a/xmpp-vala/src/core/stanza_reader.vala
+++ b/xmpp-vala/src/core/stanza_reader.vala
@@ -52,8 +52,6 @@ public class StanzaReader {
buffer_fill = (int) yield ((!)input).read_async(buffer, GLib.Priority.DEFAULT, cancellable);
if (buffer_fill == 0) throw new XmlError.EOF("End of input stream reached.");
buffer_pos = 0;
- } catch (TlsError e) {
- throw new XmlError.TLS("TlsError: %s".printf(e.message));
} catch (GLib.IOError e) {
throw new XmlError.IO("GLib.IOError: %s".printf(e.message));
}
diff --git a/xmpp-vala/src/module/xep/0166_jingle.vala b/xmpp-vala/src/module/xep/0166_jingle.vala
index 06e3d5c8..86396f30 100644
--- a/xmpp-vala/src/module/xep/0166_jingle.vala
+++ b/xmpp-vala/src/module/xep/0166_jingle.vala
@@ -543,7 +543,7 @@ public class Session {
throw new IqError.BAD_REQUEST("session-accept with unnegotiated transport method");
}
transport.on_transport_accept(content.transport);
- StanzaNode description = content.description; // TODO(hrxi): handle this :P
+ // TODO(hrxi): handle content.description :)
stream.get_module(Iq.Module.IDENTITY).send_iq(stream, new Iq.Stanza.result(iq));
state = State.CONNECTING;
diff --git a/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala b/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala
index 25fe3ce4..951ea7b7 100644
--- a/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala
+++ b/xmpp-vala/src/module/xep/0234_jingle_file_transfer.vala
@@ -56,8 +56,13 @@ public class Module : Jingle.ContentType, XmppStreamModule {
.put_node(new StanzaNode.build("size", NS_URI).put_node(new StanzaNode.text(size.to_string()))));
// TODO(hrxi): Add the mandatory hash field
- Jingle.Session session = stream.get_module(Jingle.Module.IDENTITY)
- .create_session(stream, Jingle.TransportType.STREAMING, receiver_full_jid, Jingle.Senders.INITIATOR, "a-file-offer", description); // TODO(hrxi): Why "a-file-offer"?
+ Jingle.Session session;
+ try {
+ session = stream.get_module(Jingle.Module.IDENTITY)
+ .create_session(stream, Jingle.TransportType.STREAMING, receiver_full_jid, Jingle.Senders.INITIATOR, "a-file-offer", description); // TODO(hrxi): Why "a-file-offer"?
+ } catch (Jingle.Error e) {
+ throw new IOError.FAILED(@"couldn't create Jingle session: $(e.message)");
+ }
session.terminate_on_connection_close = false;
yield session.conn.input_stream.close_async();
diff --git a/xmpp-vala/src/util.vala b/xmpp-vala/src/util.vala
new file mode 100644
index 00000000..34a05b7a
--- /dev/null
+++ b/xmpp-vala/src/util.vala
@@ -0,0 +1,50 @@
+namespace Xmpp.Util {
+
+// Parse a number from a hexadecimal representation.
+//
+// Skips any whitespace at the start of the string, parses as many valid
+// characters as hexadecimal digits as possible (possibly zero) and returns
+// them as an integer value.
+//
+// ```
+// // 0x0
+// print("0x%lx\n", from_hex(""));
+//
+// // 0x123abc
+// print("0x%lx\n", from_hex("123abc"));
+//
+// // 0x0
+// print("0x%lx\n", from_hex("0x123abc"));
+//
+// // 0xa
+// print("0x%lx\n", from_hex("A quick brown fox jumps over the lazy dog."));
+//
+// // 0xfeed
+// print("0x%lx\n", from_hex(" FEED ME "));
+// ```
+
+public long from_hex(string numeral) {
+ long result = 0;
+ bool skipping_whitespace = true;
+ foreach (uint8 byte in numeral.data) {
+ char c = (char)byte;
+ if (skipping_whitespace && c.isspace()) {
+ continue;
+ }
+ skipping_whitespace = false;
+ int digit;
+ if ('0' <= c && c <= '9') {
+ digit = c - '0';
+ } else if ('A' <= c && c <= 'F') {
+ digit = c - 'A' + 10;
+ } else if ('a' <= c && c <= 'f') {
+ digit = c - 'a' + 10;
+ } else {
+ break;
+ }
+ result = (result << 4) | digit;
+ }
+ return result;
+}
+
+}
diff --git a/xmpp-vala/tests/common.vala b/xmpp-vala/tests/common.vala
index 01cc7d09..b91bbf7c 100644
--- a/xmpp-vala/tests/common.vala
+++ b/xmpp-vala/tests/common.vala
@@ -4,6 +4,7 @@ int main(string[] args) {
GLib.Test.init(ref args);
GLib.Test.set_nonfatal_assertions();
TestSuite.get_root().add_suite(new Xmpp.Test.StanzaTest().get_suite());
+ TestSuite.get_root().add_suite(new Xmpp.Test.UtilTest().get_suite());
return GLib.Test.run();
}
diff --git a/xmpp-vala/tests/util.vala b/xmpp-vala/tests/util.vala
new file mode 100644
index 00000000..9d893776
--- /dev/null
+++ b/xmpp-vala/tests/util.vala
@@ -0,0 +1,24 @@
+using Xmpp.Util;
+
+namespace Xmpp.Test {
+
+class UtilTest : Gee.TestCase {
+ public UtilTest() {
+ base("util");
+
+ add_hex_test(0x0, "");
+ add_hex_test(0x123abc, "123abc");
+ add_hex_test(0x0, "0x123abc");
+ add_hex_test(0xa, "A quick brown fox jumps over the lazy dog.");
+ add_hex_test(0xfeed, " FEED ME ");
+ }
+
+ private void add_hex_test(int expected, string str) {
+ string test_name = @"from_hex(\"$(str)\")";
+ add_test(test_name, () => {
+ fail_if_not_eq_int(expected, (int)from_hex(str));
+ });
+ }
+}
+
+}