aboutsummaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
authorfiaxh <git@mx.ax.lt>2017-03-12 02:49:53 +0100
committerfiaxh <git@mx.ax.lt>2017-03-12 02:52:43 +0100
commit7e1ecb34cb1eca2b74949c7ddc2ad52fb02e3a77 (patch)
tree1a7a479efffafcf5098798fd5ce8d815bf4503a9 /plugins
parent63fffcddce49e231e82ee60aef4a23a16caa931e (diff)
downloaddino-7e1ecb34cb1eca2b74949c7ddc2ad52fb02e3a77.tar.gz
dino-7e1ecb34cb1eca2b74949c7ddc2ad52fb02e3a77.zip
Move PGP support into plugin
Diffstat (limited to 'plugins')
-rw-r--r--plugins/CMakeLists.txt2
-rw-r--r--plugins/gpgme-vala/CMakeLists.txt59
-rw-r--r--plugins/gpgme-vala/src/gpgme_fix.c12
-rw-r--r--plugins/gpgme-vala/src/gpgme_fix.h12
-rw-r--r--plugins/gpgme-vala/src/gpgme_helper.vala113
-rw-r--r--plugins/gpgme-vala/vapi/gpg-error.vapi451
-rw-r--r--plugins/gpgme-vala/vapi/gpgme.deps1
-rw-r--r--plugins/gpgme-vala/vapi/gpgme.vapi512
-rw-r--r--plugins/gpgme-vala/vapi/gpgme_public.vapi161
-rw-r--r--plugins/omemo/CMakeLists.txt1
-rw-r--r--plugins/openpgp/CMakeLists.txt61
-rw-r--r--plugins/openpgp/data/account_settings_item.ui31
-rw-r--r--plugins/openpgp/src/account_settings_entry.vala18
-rw-r--r--plugins/openpgp/src/account_settings_widget.vala61
-rw-r--r--plugins/openpgp/src/encryption_list_entry.vala26
-rw-r--r--plugins/openpgp/src/manager.vala78
-rw-r--r--plugins/openpgp/src/plugin.vala29
-rw-r--r--plugins/openpgp/src/register_plugin.vala3
-rw-r--r--plugins/openpgp/src/xmpp_flag.vala25
-rw-r--r--plugins/openpgp/src/xmpp_module.vala154
20 files changed, 1809 insertions, 1 deletions
diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt
index 3acf3f50..1ac73180 100644
--- a/plugins/CMakeLists.txt
+++ b/plugins/CMakeLists.txt
@@ -1,2 +1,4 @@
+add_subdirectory(gpgme-vala)
add_subdirectory(omemo)
+add_subdirectory(openpgp)
add_subdirectory(signal-protocol)
diff --git a/plugins/gpgme-vala/CMakeLists.txt b/plugins/gpgme-vala/CMakeLists.txt
new file mode 100644
index 00000000..b5b13c69
--- /dev/null
+++ b/plugins/gpgme-vala/CMakeLists.txt
@@ -0,0 +1,59 @@
+find_package(Vala REQUIRED)
+find_package(PkgConfig REQUIRED)
+find_package(GPGME REQUIRED)
+include(${VALA_USE_FILE})
+
+set(GPGME_VALA_PACKAGES
+ gee-0.8
+ glib-2.0
+)
+
+pkg_check_modules(GPGME_VALA REQUIRED ${GPGME_VALA_PACKAGES})
+
+vala_precompile(GPGME_VALA_C
+SOURCES
+ "src/gpgme_helper.vala"
+CUSTOM_VAPIS
+ "${CMAKE_CURRENT_SOURCE_DIR}/vapi/gpgme.vapi"
+ "${CMAKE_CURRENT_SOURCE_DIR}/vapi/gpgme_public.vapi"
+ "${CMAKE_CURRENT_SOURCE_DIR}/vapi/gpg-error.vapi"
+PACKAGES
+ ${GPGME_VALA_PACKAGES}
+GENERATE_VAPI
+ gpgme-vala
+GENERATE_HEADER
+ gpgme-vala
+OPTIONS
+ ${GLOBAL_DEBUG_FLAGS}
+ --thread
+)
+
+set(CFLAGS ${VALA_CFLAGS} ${GPGME_VALA_CFLAGS} ${GPGME_CFLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/src)
+add_definitions(${CFLAGS})
+add_library(gpgme-vala ${GPGME_VALA_C} src/gpgme_fix.c)
+target_link_libraries(gpgme-vala ${GPGME_VALA_LIBRARIES} ${GPGME_LIBRARIES})
+set_property(TARGET gpgme-vala PROPERTY POSITION_INDEPENDENT_CODE ON)
+
+add_custom_command(OUTPUT "${CMAKE_BINARY_DIR}/exports/gpgme_fix.h"
+COMMAND
+ cp "${CMAKE_CURRENT_SOURCE_DIR}/src/gpgme_fix.h" "${CMAKE_BINARY_DIR}/exports/gpgme_fix.h"
+DEPENDS
+ "${CMAKE_CURRENT_SOURCE_DIR}/src/gpgme_fix.h"
+COMMENT
+ Copy header file gpgme_fix.h
+)
+
+add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/exports/gpgme.vapi
+COMMAND
+ cat "${CMAKE_BINARY_DIR}/exports/gpgme-vala.vapi" "${CMAKE_CURRENT_SOURCE_DIR}/vapi/gpgme_public.vapi" > "${CMAKE_BINARY_DIR}/exports/gpgme.vapi"
+DEPENDS
+ ${CMAKE_BINARY_DIR}/exports/gpgme-vala.vapi
+ ${CMAKE_CURRENT_SOURCE_DIR}/vapi/gpgme_public.vapi
+)
+
+add_custom_target(gpgme-vapi
+DEPENDS
+ ${CMAKE_BINARY_DIR}/exports/gpgme_fix.h
+ ${CMAKE_BINARY_DIR}/exports/gpgme.vapi
+)
+
diff --git a/plugins/gpgme-vala/src/gpgme_fix.c b/plugins/gpgme-vala/src/gpgme_fix.c
new file mode 100644
index 00000000..2bc139e9
--- /dev/null
+++ b/plugins/gpgme-vala/src/gpgme_fix.c
@@ -0,0 +1,12 @@
+#include <gpgme_fix.h>
+
+static GRecMutex gpgme_global_mutex = {0};
+
+gpgme_key_t gpgme_key_ref_vapi (gpgme_key_t key) {
+ gpgme_key_ref(key);
+ return key;
+}
+gpgme_key_t gpgme_key_unref_vapi (gpgme_key_t key) {
+ gpgme_key_unref(key);
+ return key;
+} \ No newline at end of file
diff --git a/plugins/gpgme-vala/src/gpgme_fix.h b/plugins/gpgme-vala/src/gpgme_fix.h
new file mode 100644
index 00000000..3daa7db0
--- /dev/null
+++ b/plugins/gpgme-vala/src/gpgme_fix.h
@@ -0,0 +1,12 @@
+#ifndef GPGME_FIX
+#define GPGME_FIX 1
+
+#include <glib.h>
+#include <gpgme.h>
+
+static GRecMutex gpgme_global_mutex;
+
+gpgme_key_t gpgme_key_ref_vapi (gpgme_key_t key);
+gpgme_key_t gpgme_key_unref_vapi (gpgme_key_t key);
+
+#endif \ No newline at end of file
diff --git a/plugins/gpgme-vala/src/gpgme_helper.vala b/plugins/gpgme-vala/src/gpgme_helper.vala
new file mode 100644
index 00000000..9efa2b4c
--- /dev/null
+++ b/plugins/gpgme-vala/src/gpgme_helper.vala
@@ -0,0 +1,113 @@
+using Gee;
+using GPG;
+
+namespace GPGHelper {
+
+private static bool initialized = false;
+
+public static string encrypt_armor(string plain, Key[] keys, EncryptFlags flags) throws GLib.Error {
+ initialize();
+
+ global_mutex.lock();
+ Data plain_data = Data.create_from_memory(plain.data, false);
+ Context context = Context.create();
+ context.set_armor(true);
+ Data enc_data = context.op_encrypt(keys, flags, plain_data);
+ global_mutex.unlock();
+ return get_string_from_data(enc_data);
+}
+
+public static string decrypt(string encr) throws GLib.Error {
+ initialize();
+
+ global_mutex.lock();
+ Data enc_data = Data.create_from_memory(encr.data, false);
+ Context context = Context.create();
+ Data dec_data = context.op_decrypt(enc_data);
+ global_mutex.unlock();
+ return get_string_from_data(dec_data);
+}
+
+public static string sign(string plain, SigMode mode) throws GLib.Error {
+ initialize();
+
+ global_mutex.lock();
+ Data plain_data = Data.create_from_memory(plain.data, false);
+ Context context = Context.create();
+ Data signed_data = context.op_sign(plain_data, mode);
+ global_mutex.unlock();
+ return get_string_from_data(signed_data);
+}
+
+public static string? get_sign_key(string signature, string? text) throws GLib.Error {
+ initialize();
+
+ global_mutex.lock();
+ Data sig_data = Data.create_from_memory(signature.data, false);
+ Data text_data;
+ if (text != null) {
+ text_data = Data.create_from_memory(text.data, false);
+ } else {
+ text_data = Data.create();
+ }
+ Context context = Context.create();
+ context.op_verify(sig_data, text_data);
+ VerifyResult* verify_res = context.op_verify_result();
+ if (verify_res == null || verify_res.signatures == null) return null;
+ global_mutex.unlock();
+ return verify_res.signatures.fpr;
+}
+
+public static Gee.List<Key> get_keylist(string? pattern = null, bool secret_only = false) throws GLib.Error {
+ initialize();
+
+ Gee.List<Key> keys = new ArrayList<Key>();
+ Context context = Context.create();
+ context.op_keylist_start(pattern, secret_only ? 1 : 0);
+ try {
+ while (true) {
+ Key key = context.op_keylist_next();
+ keys.add(key);
+ }
+ } catch (Error e) {
+ if (e.code != GPGError.ErrorCode.EOF) throw e;
+ }
+ return keys;
+}
+
+public static Key? get_public_key(string sig) throws GLib.Error {
+ initialize();
+
+ global_mutex.lock();
+ Context context = Context.create();
+ Key key = context.get_key(sig, false);
+ global_mutex.unlock();
+ return key;
+}
+
+private static string get_string_from_data(Data data) {
+ initialize();
+
+ data.seek(0);
+ uint8[] buf = new uint8[256];
+ ssize_t? len = null;
+ string res = "";
+ do {
+ len = data.read(buf);
+ if (len > 0) {
+ string part = (string) buf;
+ part = part.substring(0, (long) len);
+ res += part;
+ }
+ } while (len > 0);
+ return res;
+}
+
+private static void initialize() {
+ if (!initialized) {
+ check_version();
+ initialized = true;
+ }
+}
+
+} \ No newline at end of file
diff --git a/plugins/gpgme-vala/vapi/gpg-error.vapi b/plugins/gpgme-vala/vapi/gpg-error.vapi
new file mode 100644
index 00000000..2c915c8a
--- /dev/null
+++ b/plugins/gpgme-vala/vapi/gpg-error.vapi
@@ -0,0 +1,451 @@
+/* gcrypt.vapi
+ *
+ * Copyright:
+ * 2008 Jiqing Qiang
+ * 2008, 2010, 2012-2013 Evan Nemerson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author:
+ * Jiqing Qiang <jiqing.qiang@gmail.com>
+ * Evan Nemerson <evan@coeus-group.com>
+ */
+
+
+
+[CCode (cheader_filename = "gpg-error.h")]
+namespace GPGError {
+ [CCode (cname = "gpg_err_source_t", cprefix = "GPG_ERR_SOURCE_")]
+ public enum ErrorSource {
+ UNKNOWN,
+ GCRYPT,
+ GPG,
+ GPGSM,
+ GPGAGENT,
+ PINENTRY,
+ SCD,
+ GPGME,
+ KEYBOX,
+ KSBA,
+ DIRMNGR,
+ GSTI,
+ ANY,
+ USER_1,
+ USER_2,
+ USER_3,
+ USER_4,
+
+ /* This is one more than the largest allowed entry. */
+ DIM
+ }
+
+ [CCode (cname = "gpg_err_code_t", cprefix = "GPG_ERR_")]
+ public enum ErrorCode {
+ NO_ERROR,
+ GENERAL,
+ UNKNOWN_PACKET,
+ UNKNOWN_VERSION,
+ PUBKEY_ALGO,
+ DIGEST_ALGO,
+ BAD_PUBKEY,
+ BAD_SECKEY,
+ BAD_SIGNATURE,
+ NO_PUBKEY,
+ CHECKSUM,
+ BAD_PASSPHRASE,
+ CIPHER_ALGO,
+ KEYRING_OPEN,
+ INV_PACKET,
+ INV_ARMOR,
+ NO_USER_ID,
+ NO_SECKEY,
+ WRONG_SECKEY,
+ BAD_KEY,
+ COMPR_ALGO,
+ NO_PRIME,
+ NO_ENCODING_METHOD,
+ NO_ENCRYPTION_SCHEME,
+ NO_SIGNATURE_SCHEME,
+ INV_ATTR,
+ NO_VALUE,
+ NOT_FOUND,
+ VALUE_NOT_FOUND,
+ SYNTAX,
+ BAD_MPI,
+ INV_PASSPHRASE,
+ SIG_CLASS,
+ RESOURCE_LIMIT,
+ INV_KEYRING,
+ TRUSTDB,
+ BAD_CERT,
+ INV_USER_ID,
+ UNEXPECTED,
+ TIME_CONFLICT,
+ KEYSERVER,
+ WRONG_PUBKEY_ALGO,
+ TRIBUTE_TO_D_A,
+ WEAK_KEY,
+ INV_KEYLEN,
+ INV_ARG,
+ BAD_URI,
+ INV_URI,
+ NETWORK,
+ UNKNOWN_HOST,
+ SELFTEST_FAILED,
+ NOT_ENCRYPTED,
+ NOT_PROCESSED,
+ UNUSABLE_PUBKEY,
+ UNUSABLE_SECKEY,
+ INV_VALUE,
+ BAD_CERT_CHAIN,
+ MISSING_CERT,
+ NO_DATA,
+ BUG,
+ NOT_SUPPORTED,
+ INV_OP,
+ TIMEOUT,
+ INTERNAL,
+ EOF_GCRYPT,
+ INV_OBJ,
+ TOO_SHORT,
+ TOO_LARGE,
+ NO_OBJ,
+ NOT_IMPLEMENTED,
+ CONFLICT,
+ INV_CIPHER_MODE,
+ INV_FLAG,
+ INV_HANDLE,
+ TRUNCATED,
+ INCOMPLETE_LINE,
+ INV_RESPONSE,
+ NO_AGENT,
+ AGENT,
+ INV_DATA,
+ ASSUAN_SERVER_FAULT,
+ ASSUAN,
+ INV_SESSION_KEY,
+ INV_SEXP,
+ UNSUPPORTED_ALGORITHM,
+ NO_PIN_ENTRY,
+ PIN_ENTRY,
+ BAD_PIN,
+ INV_NAME,
+ BAD_DATA,
+ INV_PARAMETER,
+ WRONG_CARD,
+ NO_DIRMNGR,
+ DIRMNGR,
+ CERT_REVOKED,
+ NO_CRL_KNOWN,
+ CRL_TOO_OLD,
+ LINE_TOO_LONG,
+ NOT_TRUSTED,
+ CANCELED,
+ BAD_CA_CERT,
+ CERT_EXPIRED,
+ CERT_TOO_YOUNG,
+ UNSUPPORTED_CERT,
+ UNKNOWN_SEXP,
+ UNSUPPORTED_PROTECTION,
+ CORRUPTED_PROTECTION,
+ AMBIGUOUS_NAME,
+ CARD,
+ CARD_RESET,
+ CARD_REMOVED,
+ INV_CARD,
+ CARD_NOT_PRESENT,
+ NO_PKCS15_APP,
+ NOT_CONFIRMED,
+ CONFIGURATION,
+ NO_POLICY_MATCH,
+ INV_INDEX,
+ INV_ID,
+ NO_SCDAEMON,
+ SCDAEMON,
+ UNSUPPORTED_PROTOCOL,
+ BAD_PIN_METHOD,
+ CARD_NOT_INITIALIZED,
+ UNSUPPORTED_OPERATION,
+ WRONG_KEY_USAGE,
+ NOTHING_FOUND,
+ WRONG_BLOB_TYPE,
+ MISSING_VALUE,
+ HARDWARE,
+ PIN_BLOCKED,
+ USE_CONDITIONS,
+ PIN_NOT_SYNCED,
+ INV_CRL,
+ BAD_BER,
+ INV_BER,
+ ELEMENT_NOT_FOUND,
+ IDENTIFIER_NOT_FOUND,
+ INV_TAG,
+ INV_LENGTH,
+ INV_KEYINFO,
+ UNEXPECTED_TAG,
+ NOT_DER_ENCODED,
+ NO_CMS_OBJ,
+ INV_CMS_OBJ,
+ UNKNOWN_CMS_OBJ,
+ UNSUPPORTED_CMS_OBJ,
+ UNSUPPORTED_ENCODING,
+ UNSUPPORTED_CMS_VERSION,
+ UNKNOWN_ALGORITHM,
+ INV_ENGINE,
+ PUBKEY_NOT_TRUSTED,
+ DECRYPT_FAILED,
+ KEY_EXPIRED,
+ SIG_EXPIRED,
+ ENCODING_PROBLEM,
+ INV_STATE,
+ DUP_VALUE,
+ MISSING_ACTION,
+ MODULE_NOT_FOUND,
+ INV_OID_STRING,
+ INV_TIME,
+ INV_CRL_OBJ,
+ UNSUPPORTED_CRL_VERSION,
+ INV_CERT_OBJ,
+ UNKNOWN_NAME,
+ LOCALE_PROBLEM,
+ NOT_LOCKED,
+ PROTOCOL_VIOLATION,
+ INV_MAC,
+ INV_REQUEST,
+ UNKNOWN_EXTN,
+ UNKNOWN_CRIT_EXTN,
+ LOCKED,
+ UNKNOWN_OPTION,
+ UNKNOWN_COMMAND,
+ BUFFER_TOO_SHORT,
+ SEXP_INV_LEN_SPEC,
+ SEXP_STRING_TOO_LONG,
+ SEXP_UNMATCHED_PAREN,
+ SEXP_NOT_CANONICAL,
+ SEXP_BAD_CHARACTER,
+ SEXP_BAD_QUOTATION,
+ SEXP_ZERO_PREFIX,
+ SEXP_NESTED_DH,
+ SEXP_UNMATCHED_DH,
+ SEXP_UNEXPECTED_PUNC,
+ SEXP_BAD_HEX_CHAR,
+ SEXP_ODD_HEX_NUMBERS,
+ SEXP_BAD_OCT_CHAR,
+ ASS_GENERAL,
+ ASS_ACCEPT_FAILED,
+ ASS_CONNECT_FAILED,
+ ASS_INV_RESPONSE,
+ ASS_INV_VALUE,
+ ASS_INCOMPLETE_LINE,
+ ASS_LINE_TOO_LONG,
+ ASS_NESTED_COMMANDS,
+ ASS_NO_DATA_CB,
+ ASS_NO_INQUIRE_CB,
+ ASS_NOT_A_SERVER,
+ ASS_NOT_A_CLIENT,
+ ASS_SERVER_START,
+ ASS_READ_ERROR,
+ ASS_WRITE_ERROR,
+ ASS_TOO_MUCH_DATA,
+ ASS_UNEXPECTED_CMD,
+ ASS_UNKNOWN_CMD,
+ ASS_SYNTAX,
+ ASS_CANCELED,
+ ASS_NO_INPUT,
+ ASS_NO_OUTPUT,
+ ASS_PARAMETER,
+ ASS_UNKNOWN_INQUIRE,
+ USER_1,
+ USER_2,
+ USER_3,
+ USER_4,
+ USER_5,
+ USER_6,
+ USER_7,
+ USER_8,
+ USER_9,
+ USER_10,
+ USER_11,
+ USER_12,
+ USER_13,
+ USER_14,
+ USER_15,
+ USER_16,
+ MISSING_ERRNO,
+ UNKNOWN_ERRNO,
+ EOF,
+
+ E2BIG,
+ EACCES,
+ EADDRINUSE,
+ EADDRNOTAVAIL,
+ EADV,
+ EAFNOSUPPORT,
+ EAGAIN,
+ EALREADY,
+ EAUTH,
+ EBACKGROUND,
+ EBADE,
+ EBADF,
+ EBADFD,
+ EBADMSG,
+ EBADR,
+ EBADRPC,
+ EBADRQC,
+ EBADSLT,
+ EBFONT,
+ EBUSY,
+ ECANCELED,
+ ECHILD,
+ ECHRNG,
+ ECOMM,
+ ECONNABORTED,
+ ECONNREFUSED,
+ ECONNRESET,
+ ED,
+ EDEADLK,
+ EDEADLOCK,
+ EDESTADDRREQ,
+ EDIED,
+ EDOM,
+ EDOTDOT,
+ EDQUOT,
+ EEXIST,
+ EFAULT,
+ EFBIG,
+ EFTYPE,
+ EGRATUITOUS,
+ EGREGIOUS,
+ EHOSTDOWN,
+ EHOSTUNREACH,
+ EIDRM,
+ EIEIO,
+ EILSEQ,
+ EINPROGRESS,
+ EINTR,
+ EINVAL,
+ EIO,
+ EISCONN,
+ EISDIR,
+ EISNAM,
+ EL2HLT,
+ EL2NSYNC,
+ EL3HLT,
+ EL3RST,
+ ELIBACC,
+ ELIBBAD,
+ ELIBEXEC,
+ ELIBMAX,
+ ELIBSCN,
+ ELNRNG,
+ ELOOP,
+ EMEDIUMTYPE,
+ EMFILE,
+ EMLINK,
+ EMSGSIZE,
+ EMULTIHOP,
+ ENAMETOOLONG,
+ ENAVAIL,
+ ENEEDAUTH,
+ ENETDOWN,
+ ENETRESET,
+ ENETUNREACH,
+ ENFILE,
+ ENOANO,
+ ENOBUFS,
+ ENOCSI,
+ ENODATA,
+ ENODEV,
+ ENOENT,
+ ENOEXEC,
+ ENOLCK,
+ ENOLINK,
+ ENOMEDIUM,
+ ENOMEM,
+ ENOMSG,
+ ENONET,
+ ENOPKG,
+ ENOPROTOOPT,
+ ENOSPC,
+ ENOSR,
+ ENOSTR,
+ ENOSYS,
+ ENOTBLK,
+ ENOTCONN,
+ ENOTDIR,
+ ENOTEMPTY,
+ ENOTNAM,
+ ENOTSOCK,
+ ENOTSUP,
+ ENOTTY,
+ ENOTUNIQ,
+ ENXIO,
+ EOPNOTSUPP,
+ EOVERFLOW,
+ EPERM,
+ EPFNOSUPPORT,
+ EPIPE,
+ EPROCLIM,
+ EPROCUNAVAIL,
+ EPROGMISMATCH,
+ EPROGUNAVAIL,
+ EPROTO,
+ EPROTONOSUPPORT,
+ EPROTOTYPE,
+ ERANGE,
+ EREMCHG,
+ EREMOTE,
+ EREMOTEIO,
+ ERESTART,
+ EROFS,
+ ERPCMISMATCH,
+ ESHUTDOWN,
+ ESOCKTNOSUPPORT,
+ ESPIPE,
+ ESRCH,
+ ESRMNT,
+ ESTALE,
+ ESTRPIPE,
+ ETIME,
+ ETIMEDOUT,
+ ETOOMANYREFS,
+ ETXTBSY,
+ EUCLEAN,
+ EUNATCH,
+ EUSERS,
+ EWOULDBLOCK,
+ EXDEV,
+ EXFULL,
+
+ /* This is one more than the largest allowed entry. */
+ CODE_DIM
+ }
+
+ [CCode (cname = "gpg_err_code_t", cprefix = "gpg_err_")]
+ public struct Error : uint {
+ [CCode (cname = "gpg_err_make")]
+ public Error (ErrorSource source, ErrorCode code);
+ [CCode (cname = "gpg_err_make_from_errno")]
+ public Error.from_errno (ErrorSource source, int err);
+ public ErrorCode code { [CCode (cname = "gpg_err_code")] get; }
+ public ErrorSource source { [CCode (cname = "gpg_err_source")] get; }
+
+ [CCode (cname = "gpg_strerror")]
+ public unowned string to_string ();
+
+ [CCode (cname = "gpg_strsource")]
+ public unowned string source_to_string ();
+ }
+} \ No newline at end of file
diff --git a/plugins/gpgme-vala/vapi/gpgme.deps b/plugins/gpgme-vala/vapi/gpgme.deps
new file mode 100644
index 00000000..a0f4f82b
--- /dev/null
+++ b/plugins/gpgme-vala/vapi/gpgme.deps
@@ -0,0 +1 @@
+gpg-error
diff --git a/plugins/gpgme-vala/vapi/gpgme.vapi b/plugins/gpgme-vala/vapi/gpgme.vapi
new file mode 100644
index 00000000..48d11b8c
--- /dev/null
+++ b/plugins/gpgme-vala/vapi/gpgme.vapi
@@ -0,0 +1,512 @@
+/* libgpgme.vapi
+ *
+ * Copyright (C) 2009 Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+
+[CCode (lower_case_cprefix = "gpgme_", cheader_filename = "gpgme.h")]
+namespace GPG {
+ [CCode (cheader_filename = "gpgme_fix.h")]
+ public static GLib.RecMutex global_mutex;
+
+ [CCode (cname = "struct _gpgme_engine_info")]
+ public struct EngineInfo {
+ EngineInfo* next;
+ Protocol protocol;
+ string file_name;
+ string version;
+ string req_version;
+ string? home_dir;
+ }
+
+ [CCode (cname = "struct _gpgme_op_verify_result")]
+ public struct VerifyResult {
+ Signature* signatures;
+ string? file_name;
+ }
+
+ [CCode (cname = "struct _gpgme_op_sign_result")]
+ public struct SignResult {
+ InvalidKey invalid_signers;
+ Signature* signatures;
+ }
+
+ [CCode (cname = "struct _gpgme_op_encrypt_result")]
+ public struct EncryptResult {
+ InvalidKey invalid_signers;
+ }
+
+ [CCode (cname = "struct _gpgme_op_decrypt_result")]
+ public struct DecryptResult {
+ string unsupported_algorithm;
+ bool wrong_key_usage;
+ Recipient recipients;
+ string filename;
+ }
+
+ [CCode (cname = "struct _gpgme_recipient")]
+ public struct Recipient {
+ Recipient *next;
+ string keyid;
+ PublicKeyAlgorithm pubkey_algo;
+ GPGError.Error status;
+ }
+
+ [CCode (cname = "struct _gpgme_invalid_key")]
+ public struct InvalidKey {
+ InvalidKey *next;
+ string fpr;
+ GPGError.Error reason;
+ }
+
+ [CCode (cname = "struct _gpgme_signature")]
+ public struct Signature {
+ Signature *next;
+ Sigsum summary;
+ string fpr;
+ GPGError.Error status;
+ SigNotation notations;
+ ulong timestamp;
+ ulong exp_timestamp;
+ bool wrong_key_usage;
+ PKAStatus pka_trust;
+ bool chain_model;
+ Validity validity;
+ GPGError.Error validity_reason;
+ PublicKeyAlgorithm pubkey_algo;
+ HashAlgorithm hash_algo;
+ string? pka_adress;
+ }
+
+ public enum PKAStatus {
+ NOT_AVAILABLE,
+ BAD,
+ OKAY,
+ RFU
+ }
+
+ [CCode (cname = "gpgme_sigsum_t", cprefix = "GPGME_SIGSUM_")]
+ public enum Sigsum {
+ VALID,
+ GREEN,
+ RED,
+ KEY_REVOKED,
+ KEY_EXPIRED,
+ SIG_EXPIRED,
+ KEY_MISSING,
+ CRL_MISSING,
+ CRL_TOO_OLD,
+ BAD_POLICY,
+ SYS_ERROR
+ }
+
+ [CCode (cname = "gpgme_data_encoding_t", cprefix = "GPGME_DATA_ENCODING_")]
+ public enum DataEncoding {
+ NONE,
+ BINARY,
+ BASE64,
+ ARMOR,
+ URL,
+ URLESC,
+ URL0
+ }
+
+ [CCode (cname = "gpgme_hash_algo_t", cprefix = "GPGME_MD_")]
+ public enum HashAlgorithm {
+ NONE,
+ MD5,
+ SHA1,
+ RMD160,
+ MD2,
+ TIGER,
+ HAVAL,
+ SHA256,
+ SHA384,
+ SHA512,
+ MD4,
+ MD_CRC32,
+ MD_CRC32_RFC1510,
+ MD_CRC24_RFC2440
+ }
+
+ [CCode (cname = "gpgme_export_mode_t", cprefix = "GPGME_EXPORT_MODE_")]
+ public enum ExportMode {
+ EXTERN
+ }
+
+ [CCode (cprefix = "GPGME_AUDITLOG_")]
+ public enum AuditLogFlag {
+ HTML,
+ WITH_HELP
+ }
+
+ [CCode (cname = "gpgme_status_code_t", cprefix = "GPGME_STATUS_")]
+ public enum StatusCode {
+ EOF,
+ ENTER,
+ LEAVE,
+ ABORT,
+ GOODSIG,
+ BADSIG,
+ ERRSIG,
+ BADARMOR,
+ RSA_OR_IDEA,
+ KEYEXPIRED,
+ KEYREVOKED,
+ TRUST_UNDEFINED,
+ TRUST_NEVER,
+ TRUST_MARGINAL,
+ TRUST_FULLY,
+ TRUST_ULTIMATE,
+ SHM_INFO,
+ SHM_GET,
+ SHM_GET_BOOL,
+ SHM_GET_HIDDEN,
+ NEED_PASSPHRASE,
+ VALIDSIG,
+ SIG_ID,
+ SIG_TO,
+ ENC_TO,
+ NODATA,
+ BAD_PASSPHRASE,
+ NO_PUBKEY,
+ NO_SECKEY,
+ NEED_PASSPHRASE_SYM,
+ DECRYPTION_FAILED,
+ DECRYPTION_OKAY,
+ MISSING_PASSPHRASE,
+ GOOD_PASSPHRASE,
+ GOODMDC,
+ BADMDC,
+ ERRMDC,
+ IMPORTED,
+ IMPORT_OK,
+ IMPORT_PROBLEM,
+ IMPORT_RES,
+ FILE_START,
+ FILE_DONE,
+ FILE_ERROR,
+ BEGIN_DECRYPTION,
+ END_DECRYPTION,
+ BEGIN_ENCRYPTION,
+ END_ENCRYPTION,
+ DELETE_PROBLEM,
+ GET_BOOL,
+ GET_LINE,
+ GET_HIDDEN,
+ GOT_IT,
+ PROGRESS,
+ SIG_CREATED,
+ SESSION_KEY,
+ NOTATION_NAME,
+ NOTATION_DATA,
+ POLICY_URL,
+ BEGIN_STREAM,
+ END_STREAM,
+ KEY_CREATED,
+ USERID_HINT,
+ UNEXPECTED,
+ INV_RECP,
+ NO_RECP,
+ ALREADY_SIGNED,
+ SIGEXPIRED,
+ EXPSIG,
+ EXPKEYSIG,
+ TRUNCATED,
+ ERROR,
+ NEWSIG,
+ REVKEYSIG,
+ SIG_SUBPACKET,
+ NEED_PASSPHRASE_PIN,
+ SC_OP_FAILURE,
+ SC_OP_SUCCESS,
+ CARDCTRL,
+ BACKUP_KEY_CREATED,
+ PKA_TRUST_BAD,
+ PKA_TRUST_GOOD,
+ PLAINTEXT
+ }
+
+ [Flags]
+ [CCode (cname="unsigned int")]
+ public enum ImportStatusFlags {
+ [CCode (cname = "GPGME_IMPORT_NEW")]
+ NEW,
+ [CCode (cname = "GPGME_IMPORT_UID")]
+ UID,
+ [CCode (cname = "GPGME_IMPORT_SIG")]
+ SIG,
+ [CCode (cname = "GPGME_IMPORT_SUBKEY")]
+ SUBKEY,
+ [CCode (cname = "GPGME_IMPORT_SECRET")]
+ SECRET
+ }
+
+ [Compact]
+ [CCode (cname = "struct gpgme_context", free_function = "gpgme_release", cprefix = "gpgme_")]
+ public class Context {
+ private static GPGError.Error new(out Context ctx);
+
+ public static Context create() throws GLib.Error {
+ Context ctx;
+ throw_if_error(@new(out ctx));
+ return ctx;
+ }
+
+ public GPGError.Error set_protocol(Protocol p);
+ public Protocol get_protocol();
+
+ public void set_armor(bool yes);
+ public bool get_armor();
+
+ public void set_textmode(bool yes);
+ public bool get_textmode();
+
+ public GPGError.Error set_keylist_mode(KeylistMode mode);
+ public KeylistMode get_keylist_mode();
+
+ public void set_include_certs(int nr_of_certs = -256);
+
+ public int get_include_certs();
+
+ public void set_passphrase_cb(passphrase_callback cb, void* hook_value = null);
+
+ public void get_passphrase_cb(out passphrase_callback cb, out void* hook_value);
+
+ public GPGError.Error set_locale(int category, string val);
+
+ [CCode (cname = "gpgme_ctx_get_engine_info")]
+ public EngineInfo* get_engine_info();
+
+ [CCode (cname = "gpgme_ctx_set_engine_info")]
+ public GPGError.Error set_engine_info(Protocol proto, string file_name, string home_dir);
+
+ public void signers_clear();
+
+ public GPGError.Error signers_add(Key key);
+
+ public Key* signers_enum(int n);
+
+ public void sig_notation_clear();
+
+ public GPGError.Error sig_notation_add(string name, string val, SigNotationFlags flags);
+
+ public SigNotation* sig_notation_get();
+
+ [CCode (cname = "gpgme_get_key")]
+ private GPGError.Error get_key_(string fpr, out Key key, bool secret);
+
+ [CCode (cname = "gpgme_get_key_")]
+ public Key get_key(string fpr, bool secret) throws GLib.Error {
+ Key key;
+ throw_if_error(get_key_(fpr, out key, secret));
+ return key;
+ }
+
+ public Context* wait(out GPGError.Error status, bool hang);
+
+ public SignResult* op_sign_result();
+
+ [CCode (cname = "gpgme_op_sign")]
+ public GPGError.Error op_sign_(Data plain, Data sig, SigMode mode);
+
+ [CCode (cname = "gpgme_op_sign_")]
+ public Data op_sign(Data plain, SigMode mode) throws GLib.Error {
+ Data sig = Data.create();
+ throw_if_error(op_sign_(plain, sig, mode));
+ return sig;
+ }
+
+ public VerifyResult* op_verify_result();
+
+ [CCode (cname = "gpgme_op_verify")]
+ public GPGError.Error op_verify_(Data sig, Data signed_text, Data? plaintext);
+
+ [CCode (cname = "gpgme_op_verify_")]
+ public Data op_verify(Data sig, Data signed_text) throws GLib.Error {
+ Data plaintext = Data.create();
+ throw_if_error(op_verify_(sig, signed_text, plaintext));
+ return plaintext;
+ }
+
+ public EncryptResult* op_encrypt_result();
+
+ [CCode (cname = "gpgme_op_encrypt")]
+ public GPGError.Error op_encrypt_([CCode (array_length = false)] Key[] recp, EncryptFlags flags, Data plain, Data cipher);
+
+ [CCode (cname = "gpgme_op_encrypt_")]
+ public Data op_encrypt(Key[] recp, EncryptFlags flags, Data plain) throws GLib.Error {
+ Data cipher = Data.create();
+ throw_if_error(op_encrypt_(recp, flags, plain, cipher));
+ return cipher;
+ }
+
+ public DecryptResult* op_decrypt_result();
+
+ [CCode (cname = "gpgme_op_decrypt")]
+ public GPGError.Error op_decrypt_(Data cipher, Data plain);
+
+ [CCode (cname = "gpgme_op_decrypt_")]
+ public Data op_decrypt(Data cipher) throws GLib.Error {
+ Data plain = Data.create();
+ throw_if_error(op_decrypt_(cipher, plain));
+ return plain;
+ }
+
+ public GPGError.Error op_export(string? pattern, ExportMode mode, Data keydata);
+
+ public GPGError.Error op_import(Data keydata);
+
+ public unowned ImportResult op_import_result();
+
+ [CCode (cname = "gpgme_op_keylist_start")]
+ private GPGError.Error op_keylist_start_(string? pattern = null, int secret_only = 0);
+
+ [CCode (cname = "gpgme_op_keylist_start_")]
+ public void op_keylist_start(string? pattern = null, int secret_only = 0) throws GLib.Error {
+ throw_if_error(op_keylist_start_(pattern, secret_only));
+ }
+
+ [CCode (cname = "gpgme_op_keylist_next")]
+ private GPGError.Error op_keylist_next_(out Key key);
+
+ [CCode (cname = "gpgme_op_keylist_next_")]
+ public Key op_keylist_next() throws GLib.Error {
+ Key key;
+ throw_if_error(op_keylist_next_(out key));
+ return key;
+ }
+
+ [CCode (cname = "gpgme_op_keylist_end")]
+ private GPGError.Error op_keylist_end_();
+
+ [CCode (cname = "gpgme_op_keylist_end_")]
+ public void op_keylist_end() throws GLib.Error {
+ throw_if_error(op_keylist_end_());
+ }
+
+ public KeylistResult op_keylist_result();
+ }
+
+ [Compact]
+ [CCode (cname = "struct _gpgme_import_status")]
+ public class ImportStatus {
+
+ public ImportStatus? next;
+ public string fpr;
+ public GPGError.Error result;
+ public ImportStatusFlags status;
+ }
+
+ [Compact]
+ [CCode (cname = "struct _gpgme_op_import_result")]
+ public class ImportResult {
+ public int considered;
+ public int no_user_id;
+ public int imported;
+ public int imported_rsa;
+ public int unchanged;
+ public int new_user_ids;
+ public int new_sub_keys;
+ public int new_signatures;
+ public int new_revocations;
+ public int secret_read;
+ public int secret_imported;
+ public int secret_unchanged;
+ public int not_imported;
+ public ImportStatus imports;
+ }
+
+ [Compact]
+ [CCode (cname = "struct _gpgme_op_keylist_result")]
+ public class KeylistResult {
+ uint truncated;
+ }
+
+ [Compact]
+ [CCode (cname = "struct gpgme_data", free_function = "gpgme_data_release", cprefix = "gpgme_data_")]
+ public class Data {
+
+ public static GPGError.Error new(out Data d);
+
+ public static Data create() throws GLib.Error {
+ Data data;
+ throw_if_error(@new(out data));
+ return data;
+ }
+
+
+ [CCode (cname = "gpgme_data_new_from_mem")]
+ public static GPGError.Error new_from_memory(out Data d, uint8[] buffer, bool copy);
+
+ public static Data create_from_memory(uint8[] buffer, bool copy) throws GLib.Error {
+ Data data;
+ throw_if_error(new_from_memory(out data, buffer, copy));
+ return data;
+ }
+
+ [CCode (cname = "gpgme_data_new_from_file")]
+ public static GPGError.Error create_from_file(out Data d, string filename, int copy = 1);
+
+ [CCode (cname = "gpgme_data_release_and_get_mem")]
+ public string release_and_get_mem(out size_t len);
+
+ public ssize_t read(uint8[] buf);
+
+ public ssize_t write(uint8[] buf);
+
+ public long seek(long offset, int whence=0);
+
+ public DataEncoding *get_encoding();
+
+ public GPGError.Error set_encoding(DataEncoding enc);
+ }
+
+ [CCode (cname = "gpgme_get_protocol_name")]
+ public unowned string get_protocol_name(Protocol p);
+
+ [CCode (cname = "gpgme_pubkey_algo_name")]
+ public unowned string get_public_key_algorithm_name(PublicKeyAlgorithm algo);
+
+ [CCode (cname = "gpgme_hash_algo_name")]
+ public unowned string get_hash_algorithm_name(HashAlgorithm algo);
+
+ [CCode (cname = "gpgme_passphrase_cb_t", has_target = false)]
+ public delegate GPGError.Error passphrase_callback(void* hook, string uid_hint, string passphrase_info, bool prev_was_bad, int fd);
+
+ [CCode (cname = "gpgme_engine_check_version")]
+ public GPGError.Error engine_check_version(Protocol proto);
+
+ [CCode (cname = "gpgme_get_engine_information")]
+ public GPGError.Error get_engine_information(out EngineInfo engine_info);
+
+ [CCode (cname = "gpgme_strerror_r")]
+ public int strerror_r(GPGError.Error err, uint8[] buf);
+
+ [CCode (cname = "gpgme_strerror")]
+ public unowned string strerror(GPGError.Error err);
+
+ private void throw_if_error(GPGError.Error error) throws GLib.Error {
+ if (error.code != GPGError.ErrorCode.NO_ERROR) {
+ throw new GLib.Error(-1, error.code, error.to_string());
+ }
+ }
+}
diff --git a/plugins/gpgme-vala/vapi/gpgme_public.vapi b/plugins/gpgme-vala/vapi/gpgme_public.vapi
new file mode 100644
index 00000000..942839ac
--- /dev/null
+++ b/plugins/gpgme-vala/vapi/gpgme_public.vapi
@@ -0,0 +1,161 @@
+[CCode (lower_case_cprefix = "gpgme_", cheader_filename = "gpgme.h,gpgme_fix.h")]
+namespace GPG {
+
+[CCode (cname = "gpgme_check_version")]
+public unowned string check_version(string? required_version = null);
+
+[Compact]
+[CCode (cname = "struct _gpgme_key", ref_function = "gpgme_key_ref_vapi", unref_function = "gpgme_key_unref_vapi", free_function = "gpgme_key_release")]
+public class Key {
+ public bool revoked;
+ public bool expired;
+ public bool disabled;
+ public bool invalid;
+ public bool can_encrypt;
+ public bool can_sign;
+ public bool can_certify;
+ public bool can_authenticate;
+ public bool is_qualified;
+ public bool secret;
+ public Protocol protocol;
+ public string issuer_serial;
+ public string issuer_name;
+ public string chain_id;
+ public Validity owner_trust;
+ [CCode(array_null_terminated = true)]
+ public SubKey[] subkeys;
+ [CCode(array_null_terminated = true)]
+ public UserID[] uids;
+ public KeylistMode keylist_mode;
+ public string fpr;
+}
+
+[CCode (cname = "struct _gpgme_user_id")]
+public struct UserID {
+ UserID* next;
+
+ bool revoked;
+ bool invalid;
+ Validity validity;
+ string uid;
+ string name;
+ string email;
+ string comment;
+ KeySig signatures;
+}
+
+[CCode (cname = "struct _gpgme_key_sig")]
+public struct KeySig {
+ KeySig* next;
+ bool invoked;
+ bool expired;
+ bool invalid;
+ bool exportable;
+ PublicKeyAlgorithm algo;
+ string keyid;
+ long timestamp;
+ long expires;
+// GPGError.Error status;
+ string uid;
+ string name;
+ string email;
+ string comment;
+ uint sig_class;
+ SigNotation notations;
+}
+
+[CCode (cname = "struct _gpgme_subkey")]
+public struct SubKey {
+ SubKey* next;
+ bool revoked;
+ bool expired;
+ bool disabled;
+ bool invalid;
+ bool can_encrypt;
+ bool can_sign;
+ bool can_certify;
+ bool secret;
+ bool can_authenticate;
+ bool is_qualified;
+ bool is_cardkey;
+ PublicKeyAlgorithm algo;
+ uint length;
+ string keyid;
+
+ string fpr;
+ long timestamp;
+ long expires;
+ string? cardnumber;
+}
+
+[CCode (cname = "struct _gpgme_sig_notation")]
+public struct SigNotation {
+ SigNotation* next;
+ string? name;
+ string value;
+ int name_len;
+ int value_len;
+ SigNotationFlags flags;
+ bool human_readable;
+ bool critical;
+}
+
+[CCode (cname = "gpgme_sig_notation_flags_t", cprefix = "GPGME_SIG_NOTATION_")]
+public enum SigNotationFlags {
+ HUMAN_READABLE,
+ CRITICAL
+}
+
+[CCode (cname = "gpgme_sig_mode_t", cprefix = "GPGME_SIG_MODE_")]
+public enum SigMode {
+ NORMAL,
+ DETACH,
+ CLEAR
+}
+
+[CCode (cname = "gpgme_encrypt_flags_t", cprefix = "GPGME_ENCRYPT_")]
+public enum EncryptFlags {
+ ALWAYS_TRUST,
+ NO_ENCRYPT_TO
+}
+
+[CCode (cname = "gpgme_pubkey_algo_t", cprefix = "GPGME_PK_")]
+public enum PublicKeyAlgorithm {
+ RSA,
+ RSA_E,
+ RSA_S,
+ ELG_E,
+ DSA,
+ ELG
+}
+
+[CCode (cname = "gpgme_protocol_t", cprefix = "GPGME_PROTOCOL_")]
+public enum Protocol {
+ OpenPGP,
+ CMS,
+ GPGCONF,
+ ASSUAN,
+ UNKNOWN
+}
+
+[CCode (cname = "gpgme_keylist_mode_t", cprefix = "GPGME_KEYLIST_MODE_")]
+public enum KeylistMode {
+ LOCAL,
+ EXTERN,
+ SIGS,
+ SIG_NOTATIONS,
+ EPHEMERAL,
+ VALIDATE
+}
+
+[CCode (cname = "gpgme_validity_t", cprefix = "GPGME_VALIDITY_")]
+public enum Validity {
+ UNKNOWN,
+ UNDEFINED,
+ NEVER,
+ MARGINAL,
+ FULL,
+ ULTIMATE
+}
+
+} \ No newline at end of file
diff --git a/plugins/omemo/CMakeLists.txt b/plugins/omemo/CMakeLists.txt
index fba75ab4..14e34088 100644
--- a/plugins/omemo/CMakeLists.txt
+++ b/plugins/omemo/CMakeLists.txt
@@ -4,7 +4,6 @@ include(${VALA_USE_FILE})
set(OMEMO_PACKAGES
gee-0.8
- gio-2.0
glib-2.0
gtk+-3.0
gmodule-2.0
diff --git a/plugins/openpgp/CMakeLists.txt b/plugins/openpgp/CMakeLists.txt
new file mode 100644
index 00000000..a230872e
--- /dev/null
+++ b/plugins/openpgp/CMakeLists.txt
@@ -0,0 +1,61 @@
+find_package(Vala REQUIRED)
+find_package(PkgConfig REQUIRED)
+include(${VALA_USE_FILE})
+include(GlibCompileResourcesSupport)
+
+set(OPENPGP_PACKAGES
+ gee-0.8
+ glib-2.0
+ gtk+-3.0
+ gmodule-2.0
+ sqlite3
+)
+
+pkg_check_modules(OPENPGP REQUIRED ${OPENPGP_PACKAGES})
+
+set(RESOURCE_LIST
+ account_settings_item.ui
+)
+
+compile_gresources(
+ OPENPGP_GRESOURCES_TARGET
+ OPENPGP_GRESOURCES_XML
+ TARGET ${CMAKE_CURRENT_BINARY_DIR}/resources/resources.c
+ TYPE EMBED_C
+ RESOURCES ${RESOURCE_LIST}
+ PREFIX /org/dino-im
+ SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/data
+)
+
+vala_precompile(OPENPGP_VALA_C
+SOURCES
+ src/account_settings_entry.vala
+ src/account_settings_widget.vala
+ src/encryption_list_entry.vala
+ src/manager.vala
+ src/plugin.vala
+ src/register_plugin.vala
+ src/xmpp_flag.vala
+ src/xmpp_module.vala
+CUSTOM_VAPIS
+ ${CMAKE_BINARY_DIR}/exports/gpgme.vapi
+ ${CMAKE_BINARY_DIR}/exports/xmpp-vala.vapi
+ ${CMAKE_BINARY_DIR}/exports/qlite.vapi
+ ${CMAKE_BINARY_DIR}/exports/dino.vapi
+PACKAGES
+ ${OPENPGP_PACKAGES}
+GRESOURCES
+ ${OPENPGP_GRESOURCES_XML}
+OPTIONS
+ --target-glib=2.38
+ ${GLOBAL_DEBUG_FLAGS}
+ --thread
+)
+
+set(CFLAGS ${VALA_CFLAGS} ${OPENPGP_CFLAGS})
+add_definitions(${CFLAGS})
+add_library(openpgp SHARED ${OPENPGP_VALA_C} ${OPENPGP_GRESOURCES_TARGET})
+add_dependencies(openpgp dino-vapi gpgme-vapi)
+target_link_libraries(openpgp libdino gpgme-vala)
+set_target_properties(openpgp PROPERTIES PREFIX "")
+set_target_properties(openpgp PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins/)
diff --git a/plugins/openpgp/data/account_settings_item.ui b/plugins/openpgp/data/account_settings_item.ui
new file mode 100644
index 00000000..95f09046
--- /dev/null
+++ b/plugins/openpgp/data/account_settings_item.ui
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="DinoPluginsOpenPgpAccountSettingsWidget">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkButton" id="pgp_button">
+ <property name="relief">none</property>
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="pgp_label">
+ <property name="xalign">0</property>
+ <property name="visible">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="name">label</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkComboBox" id="pgp_combobox">
+ <property name="hexpand">True</property>
+ <property name="width_request">200</property>
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="name">entry</property>
+ </packing>
+ </child>
+ </template>
+</interface> \ No newline at end of file
diff --git a/plugins/openpgp/src/account_settings_entry.vala b/plugins/openpgp/src/account_settings_entry.vala
new file mode 100644
index 00000000..1deef763
--- /dev/null
+++ b/plugins/openpgp/src/account_settings_entry.vala
@@ -0,0 +1,18 @@
+namespace Dino.Plugins.OpenPgp {
+
+public class AccountSettingsEntry : Plugins.AccountSettingsEntry {
+
+ public override string id { get {
+ return "pgp_key_picker";
+ }}
+
+ public override string name { get {
+ return "OpenPGP";
+ }}
+
+ public override Plugins.AccountSettingsWidget get_widget() {
+ return new AccountSettingsWidget();
+ }
+}
+
+} \ No newline at end of file
diff --git a/plugins/openpgp/src/account_settings_widget.vala b/plugins/openpgp/src/account_settings_widget.vala
new file mode 100644
index 00000000..b9e6edbd
--- /dev/null
+++ b/plugins/openpgp/src/account_settings_widget.vala
@@ -0,0 +1,61 @@
+using Dino.Entities;
+
+namespace Dino.Plugins.OpenPgp {
+
+[GtkTemplate (ui = "/org/dino-im/account_settings_item.ui")]
+
+private class AccountSettingsWidget : Gtk.Stack, Plugins.AccountSettingsWidget {
+ [GtkChild] private Gtk.Label pgp_label;
+ [GtkChild] private Gtk.Button pgp_button;
+ [GtkChild] private Gtk.ComboBox pgp_combobox;
+
+ private Gtk.ListStore list_store = new Gtk.ListStore(2, typeof(string), typeof(string?));
+
+ public AccountSettingsWidget() {
+ Gtk.CellRendererText renderer = new Gtk.CellRendererText();
+ renderer.set_padding(0, 0);
+ pgp_combobox.pack_start(renderer, true);
+ pgp_combobox.add_attribute(renderer, "markup", 0);
+ pgp_button.clicked.connect(() => { activated(); this.set_visible_child_name("entry"); pgp_combobox.popup(); });
+ }
+
+ public void deactivate() {
+ this.set_visible_child_name("label");
+ }
+
+ private void key_changed() {
+ Gtk.TreeIter selected;
+ pgp_combobox.get_active_iter(out selected);
+ Value text;
+ list_store.get_value(selected, 0, out text);
+ pgp_label.set_markup((string) text);
+ deactivate();
+ }
+
+ public void set_account(Account account) {
+ populate_pgp_combobox(account);
+ }
+
+ private void populate_pgp_combobox(Account account) {
+ pgp_combobox.changed.disconnect(key_changed);
+
+ Gtk.TreeIter iter;
+ pgp_combobox.set_model(list_store);
+
+ list_store.clear();
+ list_store.append(out iter);
+ pgp_label.set_markup("Disabled\n<span font='9'>Select key</span>");
+ list_store.set(iter, 0, "Disabled\n<span font='9'>Select key</span>", 1, null);
+ Gee.List<GPG.Key> list = GPGHelper.get_keylist(null, true);
+ foreach (GPG.Key key in list) {
+ list_store.append(out iter);
+ list_store.set(iter, 0, @"<span font='11'>$(Markup.escape_text(key.uids[0].uid))</span>\n<span font='9'>0x$(Markup.escape_text(key.fpr[0:16]))</span>");
+ list_store.set(iter, 1, key.fpr);
+ }
+
+ pgp_combobox.set_active(0);
+ pgp_combobox.changed.connect(key_changed);
+ }
+}
+
+} \ No newline at end of file
diff --git a/plugins/openpgp/src/encryption_list_entry.vala b/plugins/openpgp/src/encryption_list_entry.vala
new file mode 100644
index 00000000..96607e1e
--- /dev/null
+++ b/plugins/openpgp/src/encryption_list_entry.vala
@@ -0,0 +1,26 @@
+using Dino.Entities;
+
+namespace Dino.Plugins.OpenPgp {
+
+private class EncryptionListEntry : Plugins.EncryptionListEntry, Object {
+
+ private StreamInteractor stream_interactor;
+
+ public EncryptionListEntry(StreamInteractor stream_interactor) {
+ this.stream_interactor = stream_interactor;
+ }
+
+ public Entities.Encryption encryption { get {
+ return Encryption.PGP;
+ }}
+
+ public string name { get {
+ return "OpenPGP";
+ }}
+
+ public bool can_encrypt(Entities.Conversation conversation) {
+ return Manager.get_instance(stream_interactor).get_key_id(conversation.account, conversation.counterpart) != null;
+ }
+}
+
+} \ No newline at end of file
diff --git a/plugins/openpgp/src/manager.vala b/plugins/openpgp/src/manager.vala
new file mode 100644
index 00000000..81077088
--- /dev/null
+++ b/plugins/openpgp/src/manager.vala
@@ -0,0 +1,78 @@
+using Gee;
+using Xmpp;
+
+using Xmpp;
+using Dino.Entities;
+
+namespace Dino.Plugins.OpenPgp {
+
+ public class Manager : StreamInteractionModule, Object {
+ public const string id = "pgp_manager";
+
+ public const string MESSAGE_ENCRYPTED = "pgp";
+
+ private StreamInteractor stream_interactor;
+ private Database db;
+ private HashMap<Jid, string> pgp_key_ids = new HashMap<Jid, string>(Jid.hash_bare_func, Jid.equals_bare_func);
+
+ public static void start(StreamInteractor stream_interactor, Database db) {
+ Manager m = new Manager(stream_interactor, db);
+ stream_interactor.add_module(m);
+ }
+
+ private Manager(StreamInteractor stream_interactor, Database db) {
+ this.stream_interactor = stream_interactor;
+ this.db = db;
+
+ stream_interactor.account_added.connect(on_account_added);
+ MessageManager.get_instance(stream_interactor).pre_message_received.connect(on_pre_message_received);
+ MessageManager.get_instance(stream_interactor).pre_message_send.connect(on_pre_message_send);
+ }
+
+ private void on_pre_message_received(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
+ if (MessageFlag.get_flag(message_stanza) != null && MessageFlag.get_flag(message_stanza).decrypted) {
+ message.encryption = Encryption.PGP;
+ }
+ }
+
+ private void on_pre_message_send(Entities.Message message, Xmpp.Message.Stanza message_stanza, Conversation conversation) {
+ if (message.encryption == Encryption.PGP) {
+ string? key_id = get_key_id(conversation.account, message.counterpart);
+ bool encrypted = false;
+ if (key_id != null) {
+ encrypted = stream_interactor.get_stream(conversation.account).get_module(Module.IDENTITY).encrypt(message_stanza, key_id);
+ }
+ if (!encrypted) {
+ message.marked = Entities.Message.Marked.WONTSEND;
+ }
+ }
+ }
+
+ public string? get_key_id(Account account, Jid jid) {
+ return db.get_pgp_key(jid);
+ }
+
+ public static Manager? get_instance(StreamInteractor stream_interactor) {
+ return (Manager) stream_interactor.get_module(id);
+ }
+
+ internal string get_id() {
+ return id;
+ }
+
+ private void on_account_added(Account account) {
+ stream_interactor.module_manager.get_module(account, Module.IDENTITY).received_jid_key_id.connect((stream, jid, key_id) => {
+ on_jid_key_received(account, new Jid(jid), key_id);
+ });
+ }
+
+ private void on_jid_key_received(Account account, Jid jid, string key_id) {
+ if (!pgp_key_ids.has_key(jid) || pgp_key_ids[jid] != key_id) {
+ if (!MucManager.get_instance(stream_interactor).is_groupchat_occupant(jid, account)) {
+ db.set_pgp_key(jid.bare_jid, key_id);
+ }
+ }
+ pgp_key_ids[jid] = key_id;
+ }
+ }
+} \ No newline at end of file
diff --git a/plugins/openpgp/src/plugin.vala b/plugins/openpgp/src/plugin.vala
new file mode 100644
index 00000000..d25c8cd0
--- /dev/null
+++ b/plugins/openpgp/src/plugin.vala
@@ -0,0 +1,29 @@
+namespace Dino.Plugins.OpenPgp {
+
+ public class Plugin : Plugins.RootInterface, Object {
+ public Dino.Application app;
+ public Database db;
+
+ private Module module;
+ private EncryptionListEntry list_entry;
+ private AccountSettingsEntry settings_entry;
+
+ public void registered(Dino.Application app) {
+ this.app = app;
+ this.module = new Module();
+ this.list_entry = new EncryptionListEntry(app.stream_interaction);
+ this.settings_entry = new AccountSettingsEntry();
+ app.plugin_registry.register_encryption_list_entry(list_entry);
+ app.plugin_registry.register_account_settings_entry(settings_entry);
+ app.stream_interaction.module_manager.initialize_account_modules.connect((account, list) => {
+ list.add(new Module());
+ });
+ Manager.start(app.stream_interaction, app.db);
+ }
+
+ public void shutdown() {
+ // Nothing to do
+ }
+ }
+
+}
diff --git a/plugins/openpgp/src/register_plugin.vala b/plugins/openpgp/src/register_plugin.vala
new file mode 100644
index 00000000..c5d811a7
--- /dev/null
+++ b/plugins/openpgp/src/register_plugin.vala
@@ -0,0 +1,3 @@
+public Type register_plugin(Module module) {
+ return typeof (Dino.Plugins.OpenPgp.Plugin);
+} \ No newline at end of file
diff --git a/plugins/openpgp/src/xmpp_flag.vala b/plugins/openpgp/src/xmpp_flag.vala
new file mode 100644
index 00000000..5ace26bd
--- /dev/null
+++ b/plugins/openpgp/src/xmpp_flag.vala
@@ -0,0 +1,25 @@
+using Gee;
+
+using Xmpp;
+using Xmpp.Core;
+
+namespace Dino.Plugins.OpenPgp {
+
+public class Flag : XmppStreamFlag {
+ public const string ID = "pgp";
+ public HashMap<string, string> key_ids = new HashMap<string, string>();
+
+ public string? get_key_id(string jid) { return key_ids[get_bare_jid(jid)]; }
+
+ public void set_key_id(string jid, string key) { key_ids[get_bare_jid(jid)] = key; }
+
+ public static Flag? get_flag(XmppStream stream) { return (Flag?) stream.get_flag(NS_URI, ID); }
+
+ public static bool has_flag(XmppStream stream) { return get_flag(stream) != null; }
+
+ public override string get_ns() { return NS_URI; }
+
+ public override string get_id() { return ID; }
+}
+
+} \ No newline at end of file
diff --git a/plugins/openpgp/src/xmpp_module.vala b/plugins/openpgp/src/xmpp_module.vala
new file mode 100644
index 00000000..440be5f1
--- /dev/null
+++ b/plugins/openpgp/src/xmpp_module.vala
@@ -0,0 +1,154 @@
+using GPG;
+
+using Xmpp;
+using Xmpp.Core;
+
+namespace Dino.Plugins.OpenPgp {
+ private const string NS_URI = "jabber:x";
+ private const string NS_URI_ENCRYPTED = NS_URI + ":encrypted";
+ private const string NS_URI_SIGNED = NS_URI + ":signed";
+
+ public class Module : XmppStreamModule {
+ public const string ID = "0027_current_pgp_usage";
+ public static ModuleIdentity<Module> IDENTITY = new ModuleIdentity<Module>(NS_URI, ID);
+
+ public signal void received_jid_key_id(XmppStream stream, string jid, string key_id);
+
+ private string? signed_status;
+ private string? own_key_id;
+
+ public Module() {
+ signed_status = gpg_sign("");
+ if (signed_status != null) own_key_id = gpg_verify(signed_status, "");
+ }
+
+ public bool encrypt(Message.Stanza message, string key_id) {
+ string? enc_body = gpg_encrypt(message.body, new string[] {key_id, own_key_id});
+ if (enc_body != null) {
+ message.stanza.put_node(new StanzaNode.build("x", NS_URI_ENCRYPTED).add_self_xmlns().put_node(new StanzaNode.text(enc_body)));
+ message.body = "[This message is OpenPGP encrypted (see XEP-0027)]";
+ return true;
+ }
+ return false;
+ }
+
+ public string? get_cyphertext(Message.Stanza message) {
+ StanzaNode? x_node = message.stanza.get_subnode("x", NS_URI_ENCRYPTED);
+ return x_node == null ? null : x_node.get_string_content();
+ }
+
+ public override void attach(XmppStream stream) {
+ Presence.Module.require(stream);
+ stream.get_module(Presence.Module.IDENTITY).received_presence.connect(on_received_presence);
+ stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.connect(on_pre_send_presence_stanza);
+ Message.Module.require(stream);
+ stream.get_module(Message.Module.IDENTITY).pre_received_message.connect(on_pre_received_message);
+ stream.add_flag(new Flag());
+ }
+
+ public override void detach(XmppStream stream) {
+ stream.get_module(Presence.Module.IDENTITY).received_presence.disconnect(on_received_presence);
+ stream.get_module(Presence.Module.IDENTITY).pre_send_presence_stanza.disconnect(on_pre_send_presence_stanza);
+ stream.get_module(Message.Module.IDENTITY).pre_received_message.disconnect(on_pre_received_message);
+ }
+
+ public static void require(XmppStream stream) {
+ if (stream.get_module(IDENTITY) == null) stream.add_module(new Module());
+ }
+
+ public override string get_ns() { return NS_URI; }
+ public override string get_id() { return ID; }
+
+ private void on_received_presence(XmppStream stream, Presence.Stanza presence) {
+ StanzaNode x_node = presence.stanza.get_subnode("x", NS_URI_SIGNED);
+ if (x_node != null) {
+ string? sig = x_node.get_string_content();
+ if (sig != null) {
+ string signed_data = presence.status == null ? "" : presence.status;
+ string? key_id = gpg_verify(sig, signed_data);
+ if (key_id != null) {
+ Flag.get_flag(stream).set_key_id(presence.from, key_id);
+ received_jid_key_id(stream, presence.from, key_id);
+ }
+ }
+ }
+ }
+
+ private void on_pre_send_presence_stanza(XmppStream stream, Presence.Stanza presence) {
+ if (presence.type_ == Presence.Stanza.TYPE_AVAILABLE && signed_status != null) {
+ presence.stanza.put_node(new StanzaNode.build("x", NS_URI_SIGNED).add_self_xmlns().put_node(new StanzaNode.text(signed_status)));
+ }
+ }
+
+ private void on_pre_received_message(XmppStream stream, Message.Stanza message) {
+ string? encrypted = get_cyphertext(message);
+ if (encrypted != null) {
+ MessageFlag flag = new MessageFlag();
+ message.add_flag(flag);
+ string? decrypted = gpg_decrypt(encrypted);
+ if (decrypted != null) {
+ flag.decrypted = true;
+ message.body = decrypted;
+ }
+ }
+ }
+
+ private static string? gpg_encrypt(string plain, string[] key_ids) {
+ GPG.Key[] keys = new GPG.Key[key_ids.length];
+ string encr;
+ try {
+ for (int i = 0; i < key_ids.length; i++) {
+ keys[i] = GPGHelper.get_public_key(key_ids[i]);
+ }
+ encr = GPGHelper.encrypt_armor(plain, keys, GPG.EncryptFlags.ALWAYS_TRUST);
+ } catch (Error e) {
+ return null;
+ }
+ int encryption_start = encr.index_of("\n\n") + 2;
+ return encr.substring(encryption_start, encr.length - "\n-----END PGP MESSAGE-----".length - encryption_start);
+ }
+
+ private static string? gpg_decrypt(string enc) {
+ string armor = "-----BEGIN PGP MESSAGE-----\n\n" + enc + "\n-----END PGP MESSAGE-----";
+ string? decr = null;
+ try {
+ decr = GPGHelper.decrypt(armor);
+ } catch (Error e) { }
+ return decr;
+ }
+
+ private static string? gpg_verify(string sig, string signed_text) {
+ string armor = "-----BEGIN PGP MESSAGE-----\n\n" + sig + "\n-----END PGP MESSAGE-----";
+ string? sign_key = null;
+ try {
+ sign_key = GPGHelper.get_sign_key(armor, signed_text);
+ } catch (Error e) { }
+ return sign_key;
+ }
+
+ private static string? gpg_sign(string str) {
+ string signed;
+ try {
+ signed = GPGHelper.sign(str, GPG.SigMode.CLEAR);
+ } catch (Error e) {
+ return null;
+ }
+ int signature_start = signed.index_of("-----BEGIN PGP SIGNATURE-----");
+ signature_start = signed.index_of("\n\n", signature_start) + 2;
+ return signed.substring(signature_start, signed.length - "\n-----END PGP SIGNATURE-----".length - signature_start);
+ }
+ }
+
+ public class MessageFlag : Message.MessageFlag {
+ public const string id = "pgp";
+
+ public bool decrypted = false;
+
+ public static MessageFlag? get_flag(Message.Stanza message) {
+ return (MessageFlag) message.get_flag(NS_URI, id);
+ }
+
+ public override string get_ns() { return NS_URI; }
+ public override string get_id() { return id; }
+ }
+}