diff --git a/plugins/omemo/CMakeLists.txt b/plugins/omemo/CMakeLists.txt
index 5126d05b..f88abbd5 100644
--- a/plugins/omemo/CMakeLists.txt
+++ b/plugins/omemo/CMakeLists.txt
@@ -54,6 +54,7 @@ CUSTOM_VAPIS
${CMAKE_BINARY_DIR}/exports/xmpp-vala.vapi
${CMAKE_BINARY_DIR}/exports/qlite.vapi
${CMAKE_BINARY_DIR}/exports/dino.vapi
+ ${CMAKE_CURRENT_SOURCE_DIR}/vapi/qrencode.vapi
PACKAGES
${OMEMO_PACKAGES}
GRESOURCES
@@ -63,7 +64,7 @@ GRESOURCES
add_definitions(${VALA_CFLAGS} -DGETTEXT_PACKAGE=\"${GETTEXT_PACKAGE}\" -DLOCALE_INSTALL_DIR=\"${LOCALE_INSTALL_DIR}\")
add_library(omemo SHARED ${OMEMO_VALA_C} ${OMEMO_GRESOURCES_TARGET})
add_dependencies(omemo ${GETTEXT_PACKAGE}-translations)
-target_link_libraries(omemo libdino signal-protocol-vala ${OMEMO_PACKAGES})
+target_link_libraries(omemo libdino signal-protocol-vala qrencode ${OMEMO_PACKAGES})
set_target_properties(omemo PROPERTIES PREFIX "")
set_target_properties(omemo PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins/)
diff --git a/plugins/omemo/data/contact_details_dialog.ui b/plugins/omemo/data/contact_details_dialog.ui
index 856c7af4..a5e8511b 100644
--- a/plugins/omemo/data/contact_details_dialog.ui
+++ b/plugins/omemo/data/contact_details_dialog.ui
@@ -110,6 +110,7 @@
20
20
14
+ 40
14
horizontal
True
@@ -122,14 +123,38 @@
-
+
+ False
+ show_qrcode
+ left
+ True
+
+
+ True
+ 10
+
+
+ True
+
+
+
+
+
diff --git a/plugins/omemo/src/contact_details_dialog.vala b/plugins/omemo/src/contact_details_dialog.vala
index b14a108a..575437ff 100644
--- a/plugins/omemo/src/contact_details_dialog.vala
+++ b/plugins/omemo/src/contact_details_dialog.vala
@@ -3,6 +3,8 @@ using Xmpp;
using Gee;
using Qlite;
using Dino.Entities;
+using Qrencode;
+using Gdk;
namespace Dino.Plugins.Omemo {
@@ -23,6 +25,9 @@ public class ContactDetailsDialog : Gtk.Dialog {
[GtkChild] private ListBox keys;
[GtkChild] private Switch auto_accept;
[GtkChild] private Button copy;
+ [GtkChild] private Button show_qrcode;
+ [GtkChild] private Image qrcode;
+ [GtkChild] private Popover qrcode_popover;
private void set_device_trust(Row device, bool trust) {
Database.IdentityMetaTable.TrustLevel trust_level = trust ? Database.IdentityMetaTable.TrustLevel.TRUSTED : Database.IdentityMetaTable.TrustLevel.UNTRUSTED;
@@ -87,7 +92,7 @@ public class ContactDetailsDialog : Gtk.Dialog {
if(row == lbr) {
Row updated_device = plugin.db.identity_meta.with_address(device[plugin.db.identity_meta.identity_id], device[plugin.db.identity_meta.address_name]).with(plugin.db.identity_meta.device_id, "=", device[plugin.db.identity_meta.device_id]).single().row().inner;
ManageKeyDialog manage_dialog = new ManageKeyDialog(updated_device, plugin.db);
- manage_dialog.set_transient_for((Window) get_toplevel());
+ manage_dialog.set_transient_for((Gtk.Window) get_toplevel());
manage_dialog.present();
manage_dialog.response.connect((response) => {
set_row(response, device[plugin.db.identity_meta.now_active], img, status_lbl, lbl, lbr);
@@ -184,6 +189,12 @@ public class ContactDetailsDialog : Gtk.Dialog {
own_fingerprint.set_markup(fingerprint_markup(fingerprint));
copy.clicked.connect(() => {Clipboard.get_default(get_display()).set_text(fingerprint, fingerprint.length);});
+
+ int sid = plugin.db.identity.row_with(plugin.db.identity.account_id, account.id)[plugin.db.identity.device_id];
+ Pixbuf pixbuf = new QRcode(@"xmpp:$(account.bare_jid)?omemo-sid-$(sid)=$(fingerprint)", 2).to_pixbuf();
+ pixbuf = pixbuf.scale_simple(150, 150, InterpType.NEAREST);
+ qrcode.set_from_pixbuf(pixbuf);
+ show_qrcode.clicked.connect(qrcode_popover.popup);
}
new_keys.set_header_func((row, before_row) => {
diff --git a/plugins/omemo/vapi/qrencode.vapi b/plugins/omemo/vapi/qrencode.vapi
new file mode 100644
index 00000000..54c201ab
--- /dev/null
+++ b/plugins/omemo/vapi/qrencode.vapi
@@ -0,0 +1,50 @@
+using Gdk;
+
+[CCode (cheader_filename = "qrencode.h")]
+namespace Qrencode {
+
+ [CCode (cname = "QRecLevel", cprefix = "QR_ECLEVEL_")]
+ public enum ECLevel {
+ L,
+ M,
+ Q,
+ H
+ }
+
+ [CCode (cname = "QRencodeMode", cprefix = "QR_MODE_")]
+ public enum EncodeMode {
+ NUL,
+ NUM,
+ AN,
+ [CCode (cname = "QR_MODE_8")]
+ EIGHT_BIT,
+ KANJI,
+ STRUCTURE,
+ ECI,
+ FNC1FIRST,
+ FNC1SECOND
+ }
+
+ [CCode (cname = "QRcode", free_function = "QRcode_free", has_type_id = false)]
+ [Compact]
+ public class QRcode {
+ private int version;
+ private int width;
+ [CCode (array_length = false)]
+ private uint8[] data;
+
+ [CCode (cname = "QRcode_encodeString")]
+ public QRcode (string str, int version = 0, ECLevel level = ECLevel.L, EncodeMode hint = EncodeMode.EIGHT_BIT, bool casesensitive = true);
+
+ public Pixbuf to_pixbuf() {
+ uint8[] bitmap = new uint8[3*width*width];
+ for (int i = 0; i < width*width; i++) {
+ uint8 color = (data[i] & 1) == 1 ? 0 : 255;
+ bitmap[i*3] = color;
+ bitmap[i*3+1] = color;
+ bitmap[i*3+2] = color;
+ }
+ return new Pixbuf.from_data(bitmap, Colorspace.RGB, false, 8, width, width, width*3);
+ }
+ }
+}