src/pEpEngine.c
author vb
Tue, 05 Aug 2014 20:33:20 +0200
changeset 14 c99db0b8fc0f
parent 10 ead888e73384
child 15 98a6c1cc9160
permissions -rw-r--r--
...
vb@0
     1
#define PEP_ENGINE_VERSION "0.4.0"
vb@0
     2
vb@0
     3
// this is 20 safewords with 79 chars max
vb@0
     4
#define MAX_SAFEWORDS_SPACE (20 * 80)
vb@0
     5
vb@0
     6
// XML parameters string
vb@0
     7
#define PARMS_MAX 32768
vb@0
     8
vb@0
     9
// maximum busy wait time in ms
vb@0
    10
#define BUSY_WAIT_TIME 5000
vb@0
    11
vb@0
    12
// maximum line length for reading gpg.conf
vb@0
    13
#define MAX_LINELENGTH 1024
vb@0
    14
vb@0
    15
// default keyserver
vb@0
    16
#define DEFAULT_KEYSERVER "hkp://keys.gnupg.net"
vb@0
    17
vb@0
    18
#ifdef WIN32
vb@0
    19
#include "platform_windows.h"
vb@0
    20
#define LOCAL_DB windoze_local_db()
vb@0
    21
#define SYSTEM_DB windoze_system_db()
vb@0
    22
#define LIBGPGME "libgpgme-11.dll"
vb@0
    23
#else // UNIX
vb@0
    24
#define _POSIX_C_SOURCE 200809L
vb@0
    25
#include <dlfcn.h>
vb@0
    26
#include "platform_unix.h"
vb@0
    27
#define LOCAL_DB unix_local_db()
vb@0
    28
#ifndef SYSTEM_DB
vb@0
    29
#define SYSTEM_DB "/usr/share/pEp/system.db"
vb@0
    30
#endif
vb@0
    31
#ifndef LIBGPGME
vb@0
    32
#define LIBGPGME "libgpgme-pthread.so"
vb@0
    33
#endif
vb@0
    34
#endif
vb@0
    35
vb@0
    36
#include <locale.h>
vb@0
    37
#include <stdlib.h>
vb@0
    38
#include <string.h>
vb@0
    39
#include <assert.h>
vb@0
    40
#include <stdio.h>
vb@0
    41
vb@0
    42
#ifndef NDEBUG
vb@0
    43
#include <stdio.h>
vb@0
    44
#endif
vb@0
    45
vb@0
    46
#include <gpgme.h>
vb@0
    47
#include "sqlite3.h"
vb@0
    48
vb@0
    49
#define _EXPORT_PEP_ENGINE_DLL
vb@0
    50
#include "pEpEngine.h"
vb@0
    51
vb@0
    52
#define NOT_IMPLEMENTED assert(0)
vb@0
    53
vb@0
    54
// init
vb@0
    55
vb@0
    56
typedef const char * (*gpgme_check_version_t)(const char*);
vb@0
    57
typedef gpgme_error_t (*gpgme_set_locale_t)(gpgme_ctx_t CTX, int CATEGORY,
vb@0
    58
        const char *VALUE);
vb@0
    59
typedef gpgme_error_t (*gpgme_new_t)(gpgme_ctx_t *CTX);
vb@0
    60
typedef void (*gpgme_release_t)(gpgme_ctx_t CTX);
vb@0
    61
typedef gpgme_error_t (*gpgme_set_protocol_t)(gpgme_ctx_t CTX,
vb@0
    62
        gpgme_protocol_t PROTO);
vb@0
    63
typedef void (*gpgme_set_armor_t)(gpgme_ctx_t CTX, int YES);
vb@0
    64
vb@0
    65
// data
vb@0
    66
vb@0
    67
typedef gpgme_error_t (*gpgme_data_new_t)(gpgme_data_t *DH);
vb@0
    68
typedef gpgme_error_t (*gpgme_data_new_from_mem_t)(gpgme_data_t *DH,
vb@0
    69
        const char *BUFFER, size_t SIZE, int COPY);
vb@0
    70
typedef void (*gpgme_data_release_t)(gpgme_data_t DH);
vb@0
    71
typedef gpgme_data_type_t (*gpgme_data_identify_t)(gpgme_data_t DH);
vb@0
    72
typedef size_t (*gpgme_data_seek_t)(gpgme_data_t DH, size_t OFFSET,
vb@0
    73
        int WHENCE);
vb@0
    74
typedef size_t (*gpgme_data_read_t)(gpgme_data_t DH, void *BUFFER,
vb@0
    75
        size_t LENGTH);
vb@0
    76
vb@0
    77
// encrypt and decrypt
vb@0
    78
vb@0
    79
typedef gpgme_error_t (*gpgme_op_decrypt_t)(gpgme_ctx_t CTX,
vb@0
    80
        gpgme_data_t CIPHER, gpgme_data_t PLAIN);
vb@0
    81
typedef gpgme_error_t (*gpgme_op_verify_t)(gpgme_ctx_t CTX, gpgme_data_t SIG,
vb@0
    82
        gpgme_data_t SIGNED_TEXT, gpgme_data_t PLAIN);
vb@0
    83
typedef gpgme_error_t (*gpgme_op_decrypt_verify_t)(gpgme_ctx_t CTX,
vb@0
    84
        gpgme_data_t CIPHER, gpgme_data_t PLAIN);
vb@0
    85
typedef gpgme_decrypt_result_t (*gpgme_op_decrypt_result_t)(gpgme_ctx_t CTX);
vb@0
    86
typedef gpgme_error_t (*gpgme_op_encrypt_sign_t)(gpgme_ctx_t CTX,
vb@0
    87
        gpgme_key_t RECP[], gpgme_encrypt_flags_t FLAGS, gpgme_data_t PLAIN,
vb@0
    88
        gpgme_data_t CIPHER);
vb@0
    89
typedef gpgme_verify_result_t (*gpgme_op_verify_result_t)(gpgme_ctx_t CTX);
vb@0
    90
vb@0
    91
// keys
vb@0
    92
vb@0
    93
typedef gpgme_error_t (*gpgme_get_key_t)(gpgme_ctx_t CTX, const char *FPR,
vb@0
    94
        gpgme_key_t *R_KEY, int SECRET);
vb@0
    95
typedef gpgme_error_t (*gpgme_op_genkey_t)(gpgme_ctx_t CTX, const char *PARMS,
vb@0
    96
        gpgme_data_t PUBLIC, gpgme_data_t SECRET);
vb@0
    97
typedef gpgme_genkey_result_t (*gpgme_op_genkey_result_t)(gpgme_ctx_t CTX);
vb@0
    98
typedef gpgme_error_t (*gpgme_op_delete_t)(gpgme_ctx_t CTX,
vb@0
    99
        const gpgme_key_t KEY, int ALLOW_SECRET);
vb@0
   100
typedef gpgme_error_t (*gpgme_op_import_t)(gpgme_ctx_t CTX,
vb@0
   101
        gpgme_data_t KEYDATA);
vb@0
   102
typedef gpgme_error_t (*gpgme_op_export_t)(gpgme_ctx_t CTX,
vb@0
   103
        const char *PATTERN, gpgme_export_mode_t MODE, gpgme_data_t KEYDATA);
vb@0
   104
typedef gpgme_error_t (*gpgme_set_keylist_mode_t)(gpgme_ctx_t CTX,
vb@0
   105
        gpgme_keylist_mode_t MODE);
vb@0
   106
typedef gpgme_keylist_mode_t (*gpgme_get_keylist_mode_t)(gpgme_ctx_t CTX);
vb@0
   107
typedef gpgme_error_t (*gpgme_op_keylist_start_t)(gpgme_ctx_t CTX,
vb@0
   108
        const char *PATTERN, int SECRET_ONLY);
vb@0
   109
typedef gpgme_error_t (*gpgme_op_keylist_next_t)(gpgme_ctx_t CTX,
vb@0
   110
        gpgme_key_t *R_KEY);
vb@0
   111
typedef gpgme_error_t (*gpgme_op_keylist_end_t)(gpgme_ctx_t CTX);
vb@0
   112
typedef gpgme_error_t (*gpgme_op_import_keys_t)(gpgme_ctx_t CTX,
vb@0
   113
        gpgme_key_t *KEYS);
vb@0
   114
typedef void (*gpgme_key_ref_t)(gpgme_key_t KEY);
vb@0
   115
typedef void (*gpgme_key_unref_t)(gpgme_key_t KEY);
vb@0
   116
vb@0
   117
typedef struct {
vb@0
   118
	const char *version;
vb@0
   119
    const char *passphrase;
vb@0
   120
	void * gpgme;
vb@0
   121
	gpgme_ctx_t ctx;
vb@0
   122
vb@0
   123
	sqlite3 *db;
vb@0
   124
	sqlite3 *system_db;
vb@0
   125
vb@0
   126
	sqlite3_stmt *log;
vb@0
   127
	sqlite3_stmt *safeword;
vb@0
   128
	sqlite3_stmt *get_identity;
vb@0
   129
	sqlite3_stmt *set_person;
vb@0
   130
	sqlite3_stmt *set_pgp_keypair;
vb@0
   131
	sqlite3_stmt *set_identity;
vb@0
   132
	sqlite3_stmt *set_trust;
vb@8
   133
    sqlite3_stmt *get_trust;
vb@0
   134
vb@0
   135
	gpgme_check_version_t gpgme_check;
vb@0
   136
	gpgme_set_locale_t gpgme_set_locale;
vb@0
   137
	gpgme_new_t gpgme_new;
vb@0
   138
	gpgme_release_t gpgme_release;
vb@0
   139
	gpgme_set_protocol_t gpgme_set_protocol;
vb@0
   140
	gpgme_set_armor_t gpgme_set_armor;
vb@0
   141
vb@0
   142
	gpgme_data_new_t gpgme_data_new;
vb@0
   143
	gpgme_data_new_from_mem_t gpgme_data_new_from_mem;
vb@0
   144
	gpgme_data_release_t gpgme_data_release;
vb@0
   145
	gpgme_data_identify_t gpgme_data_identify;
vb@0
   146
	gpgme_data_seek_t gpgme_data_seek;
vb@0
   147
	gpgme_data_read_t gpgme_data_read;
vb@0
   148
vb@0
   149
	gpgme_op_decrypt_t gpgme_op_decrypt;
vb@0
   150
	gpgme_op_verify_t gpgme_op_verify;
vb@0
   151
	gpgme_op_decrypt_verify_t gpgme_op_decrypt_verify;
vb@0
   152
	gpgme_op_decrypt_result_t gpgme_op_decrypt_result;
vb@0
   153
	gpgme_op_encrypt_sign_t gpgme_op_encrypt_sign;
vb@0
   154
	gpgme_op_verify_result_t gpgme_op_verify_result;
vb@0
   155
vb@0
   156
	gpgme_get_key_t gpgme_get_key;
vb@0
   157
	gpgme_op_genkey_t gpgme_op_genkey;
vb@0
   158
    gpgme_op_genkey_result_t gpgme_op_genkey_result;
vb@0
   159
    gpgme_op_delete_t gpgme_op_delete;
vb@0
   160
    gpgme_op_import_t gpgme_op_import;
vb@0
   161
    gpgme_op_export_t gpgme_op_export;
vb@0
   162
    gpgme_set_keylist_mode_t gpgme_set_keylist_mode;
vb@0
   163
    gpgme_get_keylist_mode_t gpgme_get_keylist_mode;
vb@0
   164
    gpgme_op_keylist_start_t gpgme_op_keylist_start;
vb@0
   165
    gpgme_op_keylist_next_t gpgme_op_keylist_next;
vb@0
   166
    gpgme_op_keylist_end_t gpgme_op_keylist_end;
vb@0
   167
    gpgme_op_import_keys_t gpgme_op_import_keys;
vb@0
   168
    gpgme_key_ref_t gpgme_key_ref;
vb@0
   169
    gpgme_key_unref_t gpgme_key_unref;
vb@0
   170
} pEpSession;
vb@0
   171
vb@0
   172
static bool ensure_keyserver()
vb@0
   173
{
vb@0
   174
    static char buf[MAX_LINELENGTH];
vb@0
   175
    int n;
vb@0
   176
    FILE *f = fopen(gpg_conf(), "r");
vb@0
   177
vb@0
   178
    if (f != NULL) {
vb@0
   179
        while (!feof(f)) {
vb@0
   180
            char * s = fgets(buf, MAX_LINELENGTH, f);
vb@0
   181
            if (s && !feof(f)) {
vb@0
   182
                char * t = strtok(s, " ");
vb@0
   183
                if (t && strcmp(t, "keyserver") == 0)
vb@0
   184
                {
vb@0
   185
                    fclose(f);
vb@0
   186
                    return true;
vb@0
   187
                }
vb@0
   188
            }
vb@0
   189
        }
vb@0
   190
        f = freopen(gpg_conf(), "a", f);
vb@0
   191
    }
vb@0
   192
    else {
vb@0
   193
        f = fopen(gpg_conf(), "w");
vb@0
   194
    }
vb@0
   195
vb@0
   196
    assert(f);
vb@0
   197
    if (f == NULL)
vb@0
   198
        return false;
vb@0
   199
vb@0
   200
    n = fprintf(f, "keyserver %s\n", DEFAULT_KEYSERVER);
vb@0
   201
    assert(n >= 0);
vb@0
   202
    fclose(f);
vb@0
   203
vb@0
   204
    return true;
vb@0
   205
}
vb@0
   206
vb@0
   207
DYNAMIC_API PEP_STATUS init(PEP_SESSION *session)
vb@0
   208
{
vb@0
   209
	gpgme_error_t gpgme_error;
vb@0
   210
	int int_result;
vb@0
   211
	const char *sql_log;
vb@0
   212
	const char *sql_safeword;
vb@0
   213
	const char *sql_get_identity;
vb@0
   214
	const char *sql_set_person;
vb@0
   215
	const char *sql_set_pgp_keypair;
vb@0
   216
	const char *sql_set_identity;
vb@0
   217
	const char *sql_set_trust;
vb@8
   218
    const char *sql_get_trust;
vb@8
   219
vb@0
   220
    bool bResult;
vb@0
   221
vb@0
   222
	assert(sqlite3_threadsafe());
vb@0
   223
	if (!sqlite3_threadsafe())
vb@0
   224
		return PEP_INIT_SQLITE3_WITHOUT_MUTEX;
vb@0
   225
vb@0
   226
	assert(session);
vb@0
   227
	*session = NULL;
vb@0
   228
vb@0
   229
    pEpSession *_session = (pEpSession *) calloc(1, sizeof(pEpSession));
vb@0
   230
	assert(_session);
vb@0
   231
	if (_session == NULL)
vb@0
   232
		return PEP_OUT_OF_MEMORY;
vb@0
   233
	
vb@0
   234
	_session->version = PEP_ENGINE_VERSION;
vb@0
   235
vb@0
   236
    bResult = ensure_keyserver();
vb@0
   237
    assert(bResult);
vb@0
   238
vb@0
   239
    // to do: implement something useful
vb@0
   240
    _session->passphrase = "";
vb@0
   241
vb@0
   242
	_session->gpgme = dlopen(LIBGPGME, RTLD_LAZY);
vb@0
   243
	if (_session->gpgme == NULL) {
vb@0
   244
		free(_session);
vb@0
   245
		return PEP_INIT_CANNOT_LOAD_GPGME;
vb@0
   246
	}
vb@0
   247
vb@0
   248
	_session->gpgme_set_locale
vb@0
   249
        = (gpgme_set_locale_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   250
                "gpgme_set_locale");
vb@0
   251
	assert(_session->gpgme_set_locale);
vb@0
   252
vb@0
   253
	_session->gpgme_check
vb@0
   254
        = (gpgme_check_version_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   255
                "gpgme_check_version");
vb@0
   256
	assert(_session->gpgme_check);
vb@0
   257
vb@0
   258
	_session->gpgme_new
vb@0
   259
        = (gpgme_new_t) (intptr_t) dlsym(_session->gpgme, "gpgme_new");
vb@0
   260
	assert(_session->gpgme_new);
vb@0
   261
vb@0
   262
	_session->gpgme_release
vb@0
   263
        = (gpgme_release_t) (intptr_t) dlsym(_session->gpgme, "gpgme_release");
vb@0
   264
	assert(_session->gpgme_release);
vb@0
   265
vb@0
   266
	_session->gpgme_set_protocol
vb@0
   267
        = (gpgme_set_protocol_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   268
                "gpgme_set_protocol");
vb@0
   269
	assert(_session->gpgme_set_protocol);
vb@0
   270
vb@0
   271
	_session->gpgme_set_armor
vb@0
   272
        = (gpgme_set_armor_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   273
                "gpgme_set_armor");
vb@0
   274
	assert(_session->gpgme_set_armor);
vb@0
   275
vb@0
   276
	_session->gpgme_data_new
vb@0
   277
        = (gpgme_data_new_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   278
                "gpgme_data_new");
vb@0
   279
	assert(_session->gpgme_data_new);
vb@0
   280
vb@0
   281
	_session->gpgme_data_new_from_mem
vb@0
   282
        = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   283
                "gpgme_data_new_from_mem");
vb@0
   284
	assert(_session->gpgme_data_new_from_mem);
vb@0
   285
vb@0
   286
	_session->gpgme_data_release
vb@0
   287
        = (gpgme_data_release_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   288
                "gpgme_data_release");
vb@0
   289
	assert(_session->gpgme_data_release);
vb@0
   290
vb@0
   291
	_session->gpgme_data_identify
vb@0
   292
        = (gpgme_data_identify_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   293
                "gpgme_data_identify");
vb@0
   294
	assert(_session->gpgme_data_identify);
vb@0
   295
vb@0
   296
	_session->gpgme_data_seek
vb@0
   297
        = (gpgme_data_seek_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   298
                "gpgme_data_seek");
vb@0
   299
	assert(_session->gpgme_data_seek);
vb@0
   300
vb@0
   301
	_session->gpgme_data_read
vb@0
   302
        = (gpgme_data_read_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   303
                "gpgme_data_read");
vb@0
   304
	assert(_session->gpgme_data_read);
vb@0
   305
vb@0
   306
	_session->gpgme_op_decrypt
vb@0
   307
        = (gpgme_op_decrypt_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   308
                "gpgme_op_decrypt");
vb@0
   309
	assert(_session->gpgme_op_decrypt);
vb@0
   310
vb@0
   311
	_session->gpgme_op_verify
vb@0
   312
        = (gpgme_op_verify_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   313
                "gpgme_op_verify");
vb@0
   314
	assert(_session->gpgme_op_verify);
vb@0
   315
vb@0
   316
	_session->gpgme_op_decrypt_verify
vb@0
   317
        = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   318
                "gpgme_op_decrypt_verify");
vb@0
   319
	assert(_session->gpgme_op_decrypt_verify);
vb@0
   320
vb@0
   321
	_session->gpgme_op_decrypt_result
vb@0
   322
        = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   323
                "gpgme_op_decrypt_result");
vb@0
   324
	assert(_session->gpgme_op_decrypt_result);
vb@0
   325
vb@0
   326
	_session->gpgme_op_encrypt_sign
vb@0
   327
        = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   328
                "gpgme_op_encrypt_sign");
vb@0
   329
	assert(_session->gpgme_op_encrypt_sign);
vb@0
   330
vb@0
   331
	_session->gpgme_op_verify_result
vb@0
   332
        = (gpgme_op_verify_result_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   333
                "gpgme_op_verify_result");
vb@0
   334
	assert(_session->gpgme_op_verify_result);
vb@0
   335
	
vb@0
   336
	_session->gpgme_get_key
vb@0
   337
        = (gpgme_get_key_t) (intptr_t) dlsym(_session->gpgme, "gpgme_get_key");
vb@0
   338
	assert(_session->gpgme_get_key);
vb@0
   339
vb@0
   340
	_session->gpgme_op_genkey
vb@0
   341
        = (gpgme_op_genkey_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   342
                "gpgme_op_genkey");
vb@0
   343
	assert(_session->gpgme_op_genkey);
vb@0
   344
vb@0
   345
	_session->gpgme_op_genkey_result
vb@0
   346
        = (gpgme_op_genkey_result_t) (intptr_t) dlsym(_session->gpgme,
vb@0
   347
                "gpgme_op_genkey_result");
vb@0
   348
	assert(_session->gpgme_op_genkey_result);
vb@0
   349
vb@0
   350
    _session->gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
vb@0
   351
        dlsym(_session->gpgme, "gpgme_op_delete");
vb@0
   352
	assert(_session->gpgme_op_delete);
vb@0
   353
vb@0
   354
    _session->gpgme_op_import = (gpgme_op_import_t) (intptr_t)
vb@0
   355
        dlsym(_session->gpgme, "gpgme_op_import");
vb@0
   356
	assert(_session->gpgme_op_import);
vb@0
   357
vb@0
   358
    _session->gpgme_op_export = (gpgme_op_export_t) (intptr_t)
vb@0
   359
        dlsym(_session->gpgme, "gpgme_op_export");
vb@0
   360
	assert(_session->gpgme_op_export);
vb@0
   361
vb@0
   362
    _session->gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
vb@0
   363
        dlsym(_session->gpgme, "gpgme_set_keylist_mode");
vb@0
   364
	assert(_session->gpgme_set_keylist_mode);
vb@0
   365
vb@0
   366
    _session->gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
vb@0
   367
        dlsym(_session->gpgme, "gpgme_get_keylist_mode");
vb@0
   368
	assert(_session->gpgme_get_keylist_mode);
vb@0
   369
vb@0
   370
    _session->gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
vb@0
   371
        dlsym(_session->gpgme, "gpgme_op_keylist_start");
vb@0
   372
	assert(_session->gpgme_op_keylist_start);
vb@0
   373
vb@0
   374
    _session->gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
vb@0
   375
        dlsym(_session->gpgme, "gpgme_op_keylist_next");
vb@0
   376
	assert(_session->gpgme_op_keylist_next);
vb@0
   377
vb@0
   378
    _session->gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
vb@0
   379
        dlsym(_session->gpgme, "gpgme_op_keylist_end");
vb@0
   380
	assert(_session->gpgme_op_keylist_end);
vb@0
   381
vb@0
   382
    _session->gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
vb@0
   383
        dlsym(_session->gpgme, "gpgme_op_import_keys");
vb@0
   384
	assert(_session->gpgme_op_import_keys);
vb@0
   385
vb@0
   386
    _session->gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
vb@0
   387
        dlsym(_session->gpgme, "gpgme_key_ref");
vb@0
   388
	assert(_session->gpgme_key_ref);
vb@0
   389
vb@0
   390
    _session->gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
vb@0
   391
        dlsym(_session->gpgme, "gpgme_key_unref");
vb@0
   392
	assert(_session->gpgme_key_unref);
vb@0
   393
vb@0
   394
	setlocale(LC_ALL, "");
vb@0
   395
	_session->version = _session->gpgme_check(NULL);
vb@0
   396
	_session->gpgme_set_locale(NULL, LC_CTYPE, setlocale (LC_CTYPE, NULL));
vb@0
   397
vb@0
   398
	gpgme_error = _session->gpgme_new(&_session->ctx);
vb@0
   399
	if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@0
   400
		dlclose(_session->gpgme);
vb@0
   401
		free(_session);
vb@0
   402
		return PEP_INIT_GPGME_INIT_FAILED;
vb@0
   403
	}
vb@0
   404
vb@0
   405
    gpgme_error = _session->gpgme_set_protocol(_session->ctx,
vb@0
   406
            GPGME_PROTOCOL_OpenPGP);
vb@0
   407
	assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@0
   408
vb@0
   409
	_session->gpgme_set_armor(_session->ctx, 1);
vb@0
   410
vb@0
   411
    assert(LOCAL_DB);
vb@0
   412
    if (LOCAL_DB == NULL) {
vb@0
   413
		_session->gpgme_release(_session->ctx);
vb@0
   414
		dlclose(_session->gpgme);
vb@0
   415
        free(_session);
vb@0
   416
        return PEP_INIT_CANNOT_OPEN_DB;
vb@0
   417
    }
vb@0
   418
vb@0
   419
	int_result = sqlite3_open_v2(
vb@0
   420
			LOCAL_DB,
vb@0
   421
			&_session->db,
vb@0
   422
			SQLITE_OPEN_READWRITE
vb@0
   423
				| SQLITE_OPEN_CREATE
vb@0
   424
				| SQLITE_OPEN_FULLMUTEX
vb@0
   425
				| SQLITE_OPEN_PRIVATECACHE,
vb@0
   426
			NULL 
vb@0
   427
		);
vb@0
   428
vb@0
   429
	if (int_result != SQLITE_OK) {
vb@0
   430
		sqlite3_close_v2(_session->db);
vb@0
   431
		_session->gpgme_release(_session->ctx);
vb@0
   432
		dlclose(_session->gpgme);
vb@0
   433
		free(_session);
vb@0
   434
		return PEP_INIT_CANNOT_OPEN_DB;
vb@0
   435
	}
vb@0
   436
vb@0
   437
	sqlite3_busy_timeout(_session->db, BUSY_WAIT_TIME);
vb@0
   438
vb@0
   439
    assert(SYSTEM_DB);
vb@0
   440
    if (SYSTEM_DB == NULL) {
vb@0
   441
		sqlite3_close_v2(_session->db);
vb@0
   442
		_session->gpgme_release(_session->ctx);
vb@0
   443
		dlclose(_session->gpgme);
vb@0
   444
		free(_session);
vb@0
   445
		return PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
vb@0
   446
    }
vb@0
   447
vb@0
   448
	int_result = sqlite3_open_v2(
vb@0
   449
			SYSTEM_DB, &_session->system_db,
vb@0
   450
			SQLITE_OPEN_READONLY
vb@0
   451
				| SQLITE_OPEN_FULLMUTEX
vb@0
   452
				| SQLITE_OPEN_SHAREDCACHE,
vb@0
   453
			NULL
vb@0
   454
		);
vb@0
   455
vb@0
   456
	if (int_result != SQLITE_OK) {
vb@0
   457
		sqlite3_close_v2(_session->system_db);
vb@0
   458
		sqlite3_close_v2(_session->db);
vb@0
   459
		_session->gpgme_release(_session->ctx);
vb@0
   460
		dlclose(_session->gpgme);
vb@0
   461
		free(_session);
vb@0
   462
		return PEP_INIT_CANNOT_OPEN_SYSTEM_DB;
vb@0
   463
	}
vb@0
   464
vb@0
   465
	sqlite3_busy_timeout(_session->system_db, 1000);
vb@0
   466
vb@0
   467
	int_result = sqlite3_exec(
vb@0
   468
		_session->db,
vb@0
   469
			"create table if not exists version_info ("
vb@0
   470
			"	id integer primary key,"
vb@0
   471
			"	timestamp integer default (datetime('now')) ,"
vb@0
   472
			"	version text,"
vb@0
   473
			"	comment text"
vb@0
   474
			");"
vb@0
   475
			"create table if not exists log ("
vb@0
   476
			"	timestamp integer default (datetime('now')) ,"
vb@0
   477
			"	title text not null,"
vb@0
   478
			"	entity text not null,"
vb@0
   479
			"	description text,"
vb@0
   480
			"	comment text"
vb@0
   481
			");"
vb@0
   482
			"create index if not exists log_timestamp on log ("
vb@0
   483
			"	timestamp"
vb@0
   484
			");"
vb@0
   485
			"create table if not exists pgp_keypair ("
vb@0
   486
			"	fpr text primary key,"
vb@0
   487
			"	public_id text unique,"
vb@0
   488
			"   private_id text,"
vb@0
   489
			"	created integer,"
vb@0
   490
			"	expires integer,"
vb@0
   491
			"	comment text"
vb@0
   492
			");"
vb@0
   493
            "create index if not exists pgp_keypair_expires on pgp_keypair ("
vb@0
   494
			"	expires"
vb@0
   495
			");"
vb@0
   496
			"create table if not exists person ("
vb@0
   497
			"	id text primary key,"
vb@0
   498
			"	username text not null,"
vb@0
   499
			"	main_key_id text"
vb@0
   500
			"		references pgp_keypair (fpr)"
vb@0
   501
			"		on delete set null,"
vb@0
   502
			"   lang text,"
vb@0
   503
			"	comment text"
vb@0
   504
			");"
vb@0
   505
			"create table if not exists identity ("
vb@0
   506
			"	address text primary key,"
vb@0
   507
			"	user_id text"
vb@0
   508
			"		references person (id)"
vb@0
   509
			"		on delete cascade,"
vb@0
   510
			"	main_key_id text"
vb@0
   511
			"		references pgp_keypair (fpr)"
vb@0
   512
			"		on delete set null,"
vb@0
   513
			"	comment text"
vb@0
   514
			");"
vb@0
   515
            "create table if not exists trust ("
vb@0
   516
            "   user_id text not null"
vb@0
   517
            "       references person (id)"
vb@0
   518
			"		on delete cascade,"
vb@0
   519
            "   pgp_keypair_fpr text not null"
vb@0
   520
            "       references pgp_keypair (fpr)"
vb@0
   521
            "       on delete cascade,"
vb@0
   522
            "   comm_type integer not null,"
vb@0
   523
			"	comment text"
vb@0
   524
            ");"
vb@0
   525
            "create unique index if not exists trust_index on trust ("
vb@0
   526
            "   user_id,"
vb@0
   527
            "   pgp_keypair_fpr"
vb@0
   528
            ");",
vb@0
   529
		NULL,
vb@0
   530
		NULL,
vb@0
   531
		NULL
vb@0
   532
	);
vb@0
   533
	assert(int_result == SQLITE_OK);
vb@0
   534
vb@0
   535
	int_result = sqlite3_exec(
vb@0
   536
		_session->db,
vb@0
   537
        "insert or replace into version_info (id, version) values (1, '1.0');",
vb@0
   538
		NULL,
vb@0
   539
		NULL,
vb@0
   540
		NULL
vb@0
   541
	);
vb@0
   542
	assert(int_result == SQLITE_OK);
vb@0
   543
vb@0
   544
	sql_log = "insert into log (title, entity, description, comment)"
vb@0
   545
			  "values (?1, ?2, ?3, ?4);";
vb@0
   546
    int_result = sqlite3_prepare_v2(_session->db, sql_log, strlen(sql_log),
vb@0
   547
            &_session->log, NULL);
vb@0
   548
	assert(int_result == SQLITE_OK);
vb@0
   549
vb@0
   550
	sql_safeword = "select id, word from wordlist where lang = lower(?1)"
vb@0
   551
                   "and id = ?2 ;";
vb@0
   552
    int_result = sqlite3_prepare_v2(_session->system_db, sql_safeword,
vb@0
   553
            strlen(sql_safeword), &_session->safeword, NULL);
vb@0
   554
	assert(int_result == SQLITE_OK);
vb@0
   555
vb@0
   556
	sql_get_identity =	"select fpr, identity.user_id, username, comm_type, lang"
vb@0
   557
                        "   from identity"
vb@0
   558
						"   join person on id = identity.user_id"
vb@0
   559
						"   join pgp_keypair on fpr = identity.main_key_id"
vb@0
   560
                        "   join trust on id = trust.user_id"
vb@0
   561
                        "       and pgp_keypair_fpr = identity.main_key_id"
vb@0
   562
						"   where address = ?1 ;";
vb@0
   563
vb@0
   564
    int_result = sqlite3_prepare_v2(_session->db, sql_get_identity,
vb@0
   565
            strlen(sql_get_identity), &_session->get_identity, NULL);
vb@0
   566
	assert(int_result == SQLITE_OK);
vb@0
   567
vb@0
   568
	sql_set_person = "insert or replace into person (id, username, lang)"
vb@0
   569
                     "values (?1, ?2, ?3) ;";
vb@0
   570
	sql_set_pgp_keypair = "insert or replace into pgp_keypair (fpr)"
vb@0
   571
                          "values (?1) ;";
vb@0
   572
    sql_set_identity = "insert or replace into identity (address, main_key_id,"
vb@0
   573
                       "user_id) values (?1, ?2, ?3) ;";
vb@0
   574
    sql_set_trust = "insert or replace into trust (user_id, pgp_keypair_fpr, comm_type)"
vb@0
   575
                        "values (?1, ?2, ?3) ;";
vb@0
   576
	
vb@8
   577
    sql_get_trust = "select user_id, comm_type from trust where user_id = ?1 and pgp_keypair_fpr = ?2 ;";
vb@8
   578
vb@0
   579
    int_result = sqlite3_prepare_v2(_session->db, sql_set_person,
vb@0
   580
            strlen(sql_set_person), &_session->set_person, NULL);
vb@0
   581
    assert(int_result == SQLITE_OK);
vb@0
   582
    int_result = sqlite3_prepare_v2(_session->db, sql_set_pgp_keypair,
vb@0
   583
            strlen(sql_set_pgp_keypair), &_session->set_pgp_keypair, NULL);
vb@0
   584
	assert(int_result == SQLITE_OK);
vb@0
   585
    int_result = sqlite3_prepare_v2(_session->db, sql_set_identity,
vb@0
   586
            strlen(sql_set_identity), &_session->set_identity, NULL);
vb@0
   587
	assert(int_result == SQLITE_OK);
vb@0
   588
    int_result = sqlite3_prepare_v2(_session->db, sql_set_trust,
vb@0
   589
            strlen(sql_set_trust), &_session->set_trust, NULL);
vb@0
   590
	assert(int_result == SQLITE_OK);
vb@8
   591
    int_result = sqlite3_prepare_v2(_session->db, sql_get_trust,
vb@8
   592
            strlen(sql_get_trust), &_session->get_trust, NULL);
vb@8
   593
    assert(int_result == SQLITE_OK);
vb@0
   594
vb@0
   595
	sqlite3_reset(_session->log);
vb@0
   596
    sqlite3_bind_text(_session->log, 1, "init", -1, SQLITE_STATIC);
vb@0
   597
    sqlite3_bind_text(_session->log, 2, "pEp " PEP_ENGINE_VERSION, -1,
vb@0
   598
            SQLITE_STATIC);
vb@0
   599
	do {
vb@0
   600
		int_result = sqlite3_step(_session->log);
vb@0
   601
		assert(int_result == SQLITE_DONE || int_result == SQLITE_BUSY);
vb@0
   602
	} while (int_result == SQLITE_BUSY);
vb@0
   603
    sqlite3_reset(_session->log);
vb@0
   604
vb@0
   605
	*session = (void *) _session;
vb@0
   606
	return PEP_STATUS_OK;
vb@0
   607
}
vb@0
   608
vb@0
   609
DYNAMIC_API void release(PEP_SESSION session)
vb@0
   610
{
vb@0
   611
	assert(session);
vb@0
   612
	pEpSession *_session = (pEpSession *) session;
vb@0
   613
vb@0
   614
	if (_session) {
vb@0
   615
		if (_session->db) {
vb@0
   616
			sqlite3_finalize(_session->safeword);
vb@0
   617
			sqlite3_finalize(_session->log);
vb@0
   618
			sqlite3_finalize(_session->get_identity);
vb@0
   619
			sqlite3_finalize(_session->set_identity);
vb@0
   620
			sqlite3_close_v2(_session->db);
vb@0
   621
			sqlite3_close_v2(_session->system_db);
vb@0
   622
		}
vb@0
   623
		if (_session->ctx)
vb@0
   624
			_session->gpgme_release(_session->ctx);
vb@0
   625
		dlclose(_session->gpgme);
vb@0
   626
	}
vb@0
   627
	free(_session);
vb@0
   628
}
vb@0
   629
vb@0
   630
stringlist_t *new_stringlist(const char *value)
vb@0
   631
{
vb@0
   632
    stringlist_t *result = (stringlist_t *) calloc(1, sizeof(stringlist_t));
vb@0
   633
    if (result && value) {
vb@0
   634
        result->value = strdup(value);
vb@0
   635
        assert(result->value);
vb@0
   636
        if (result->value == 0) {
vb@0
   637
            free(result);
vb@0
   638
            return NULL;
vb@0
   639
        }
vb@0
   640
    }
vb@0
   641
    return result;
vb@0
   642
}
vb@0
   643
vb@0
   644
stringlist_t *stringlist_add(stringlist_t *stringlist, const char *value)
vb@0
   645
{
vb@0
   646
    assert(value);
vb@0
   647
vb@0
   648
    if (stringlist == NULL)
vb@0
   649
        return new_stringlist(value);
vb@0
   650
vb@0
   651
    if (stringlist->next != NULL)
vb@0
   652
        return stringlist_add(stringlist->next, value);
vb@0
   653
vb@0
   654
    if (stringlist->value == NULL) {
vb@0
   655
        stringlist->value = strdup(value);
vb@0
   656
        assert(stringlist->value);
vb@0
   657
        if (stringlist->value == NULL)
vb@0
   658
            return NULL;
vb@0
   659
        return stringlist;
vb@0
   660
    }
vb@0
   661
vb@0
   662
    stringlist->next = new_stringlist(value);
vb@0
   663
    assert(stringlist->next);
vb@0
   664
    if (stringlist->next == NULL)
vb@0
   665
        return NULL;
vb@0
   666
vb@0
   667
    return stringlist->next;
vb@0
   668
}
vb@0
   669
vb@0
   670
int stringlist_length(const stringlist_t *stringlist)
vb@0
   671
{
vb@0
   672
    int len = 1;
vb@0
   673
    stringlist_t *_stringlist;
vb@0
   674
vb@0
   675
    assert(stringlist);
vb@0
   676
vb@0
   677
    if (stringlist->value == NULL)
vb@0
   678
        return 0;
vb@0
   679
vb@0
   680
    for (_stringlist=stringlist->next; _stringlist!=NULL; _stringlist=_stringlist->next)
vb@0
   681
        len += 1;
vb@0
   682
vb@0
   683
    return len;
vb@0
   684
}
vb@0
   685
vb@0
   686
void free_stringlist(stringlist_t *stringlist)
vb@0
   687
{
vb@0
   688
    if (stringlist) {
vb@0
   689
        free_stringlist(stringlist->next);
vb@0
   690
        free(stringlist->value);
vb@0
   691
        free(stringlist);
vb@0
   692
    }
vb@0
   693
}
vb@0
   694
vb@0
   695
DYNAMIC_API PEP_STATUS decrypt_and_verify(
vb@0
   696
        PEP_SESSION session, const char *ctext, size_t csize,
vb@0
   697
        char **ptext, size_t *psize, stringlist_t **keylist
vb@0
   698
    )
vb@0
   699
{
vb@0
   700
	pEpSession *_session = (pEpSession *) session;
vb@0
   701
vb@0
   702
	PEP_STATUS result;
vb@0
   703
	gpgme_error_t gpgme_error;
vb@0
   704
	gpgme_data_t cipher, plain;
vb@0
   705
	gpgme_data_type_t dt;
vb@0
   706
vb@0
   707
	stringlist_t *_keylist = NULL;
vb@0
   708
	int i_key = 0;
vb@0
   709
vb@0
   710
	assert(_session);
vb@0
   711
	assert(ctext);
vb@0
   712
	assert(csize);
vb@0
   713
	assert(ptext);
vb@0
   714
	assert(psize);
vb@0
   715
	assert(keylist);
vb@0
   716
vb@0
   717
	*ptext = NULL;
vb@0
   718
	*psize = 0;
vb@0
   719
	*keylist = NULL;
vb@0
   720
vb@0
   721
    gpgme_error = _session->gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
vb@0
   722
	assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@0
   723
	if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@0
   724
		if (gpgme_error == GPG_ERR_ENOMEM)
vb@0
   725
			return PEP_OUT_OF_MEMORY;
vb@0
   726
		else
vb@0
   727
			return PEP_UNKNOWN_ERROR;
vb@0
   728
	}
vb@0
   729
vb@0
   730
	gpgme_error = _session->gpgme_data_new(&plain);
vb@0
   731
	assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@0
   732
	if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@0
   733
		_session->gpgme_data_release(cipher);
vb@0
   734
		if (gpgme_error == GPG_ERR_ENOMEM)
vb@0
   735
			return PEP_OUT_OF_MEMORY;
vb@0
   736
		else
vb@0
   737
			return PEP_UNKNOWN_ERROR;
vb@0
   738
	}
vb@0
   739
vb@0
   740
	dt = _session->gpgme_data_identify(cipher);
vb@0
   741
	switch (dt) {
vb@0
   742
	case GPGME_DATA_TYPE_PGP_SIGNED:
vb@0
   743
	case GPGME_DATA_TYPE_PGP_OTHER:
vb@0
   744
        gpgme_error = _session->gpgme_op_decrypt_verify(_session->ctx, cipher,
vb@0
   745
                plain);
vb@0
   746
		assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@0
   747
		assert(gpgme_error != GPG_ERR_NO_DATA);
vb@0
   748
vb@0
   749
		switch (gpgme_error) {
vb@0
   750
		case GPG_ERR_NO_ERROR:
vb@0
   751
			{
vb@14
   752
                gpgme_verify_result_t gpgme_verify_result;
vb@0
   753
                char *_buffer = NULL;
vb@0
   754
				size_t reading;
vb@0
   755
                size_t length = _session->gpgme_data_seek(plain, 0, SEEK_END);
vb@0
   756
                gpgme_signature_t gpgme_signature;
vb@0
   757
vb@0
   758
				assert(length != -1);
vb@0
   759
				_session->gpgme_data_seek(plain, 0, SEEK_SET);
vb@0
   760
vb@0
   761
				// TODO: make things less memory consuming
vb@0
   762
                // the following algorithm allocates memory for the complete
vb@0
   763
                // text
vb@0
   764
vb@0
   765
                _buffer = malloc(length + 1);
vb@0
   766
                assert(_buffer);
vb@0
   767
                if (_buffer == NULL) {
vb@0
   768
                    _session->gpgme_data_release(plain);
vb@0
   769
                    _session->gpgme_data_release(cipher);
vb@0
   770
                    return PEP_OUT_OF_MEMORY;
vb@0
   771
                }
vb@0
   772
vb@0
   773
                reading = _session->gpgme_data_read(plain, _buffer, length);
vb@0
   774
				assert(length == reading);
vb@0
   775
vb@0
   776
                gpgme_verify_result =
vb@0
   777
                    _session->gpgme_op_verify_result(_session->ctx);
vb@0
   778
				assert(gpgme_verify_result);
vb@0
   779
                gpgme_signature = gpgme_verify_result->signatures;
vb@0
   780
vb@0
   781
				if (gpgme_signature) {
vb@0
   782
                    stringlist_t *k;
vb@0
   783
                    _keylist = new_stringlist(NULL);
vb@0
   784
                    assert(_keylist);
vb@0
   785
                    if (_keylist == NULL) {
vb@0
   786
						_session->gpgme_data_release(plain);
vb@0
   787
						_session->gpgme_data_release(cipher);
vb@0
   788
                        free(_buffer);
vb@0
   789
                        return PEP_OUT_OF_MEMORY;
vb@0
   790
                    }
vb@0
   791
                    k = _keylist;
vb@0
   792
vb@0
   793
                    result = PEP_DECRYPTED_AND_VERIFIED;
vb@0
   794
					do {
vb@0
   795
                        switch (gpgme_signature->status) {
vb@0
   796
                        case GPG_ERR_NO_ERROR:
vb@0
   797
                            k = stringlist_add(k, gpgme_signature->fpr);
vb@0
   798
                            break;
vb@0
   799
                        case GPG_ERR_CERT_REVOKED:
vb@0
   800
                        case GPG_ERR_BAD_SIGNATURE:
vb@0
   801
                            result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@0
   802
                            break;
vb@0
   803
                        case GPG_ERR_SIG_EXPIRED:
vb@0
   804
                        case GPG_ERR_KEY_EXPIRED:
vb@0
   805
                        case GPG_ERR_NO_PUBKEY:
vb@0
   806
                            k = stringlist_add(k, gpgme_signature->fpr);
vb@0
   807
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@0
   808
                                result = PEP_DECRYPTED;
vb@0
   809
                            break;
vb@0
   810
                        case GPG_ERR_GENERAL:
vb@0
   811
                            break;
vb@0
   812
                        default:
vb@0
   813
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@0
   814
                                result = PEP_DECRYPTED;
vb@0
   815
                            break;
vb@0
   816
                        }
vb@0
   817
					} while ((gpgme_signature = gpgme_signature->next));
vb@0
   818
				} else {
vb@0
   819
					result = PEP_DECRYPTED;
vb@0
   820
				}
vb@0
   821
vb@0
   822
				if (result == PEP_DECRYPTED_AND_VERIFIED
vb@0
   823
                        || result == PEP_DECRYPTED) {
vb@0
   824
					*ptext = _buffer;
vb@0
   825
					*psize = reading;
vb@0
   826
                    (*ptext)[*psize] = 0; // safeguard for naive users
vb@0
   827
					*keylist = _keylist;
vb@0
   828
				}
vb@0
   829
                else {
vb@0
   830
                    free_stringlist(_keylist);
vb@0
   831
                    free(_buffer);
vb@0
   832
	            }
vb@0
   833
				break;
vb@0
   834
			}
vb@0
   835
		case GPG_ERR_DECRYPT_FAILED:
vb@0
   836
			result = PEP_DECRYPT_WRONG_FORMAT;
vb@0
   837
			break;
vb@0
   838
		case GPG_ERR_BAD_PASSPHRASE:
vb@0
   839
			NOT_IMPLEMENTED;
vb@14
   840
        default:
vb@14
   841
            {
vb@14
   842
                gpgme_decrypt_result_t gpgme_decrypt_result = _session->gpgme_op_decrypt_result(_session->ctx);
vb@14
   843
                result = PEP_CANNOT_DECRYPT_UNKNOWN;
vb@14
   844
vb@14
   845
                if (gpgme_decrypt_result != NULL) {
vb@14
   846
                    *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
vb@14
   847
                    assert(*keylist);
vb@14
   848
                    if (*keylist == NULL) {
vb@14
   849
                        result = PEP_OUT_OF_MEMORY;
vb@14
   850
                        break;
vb@14
   851
                    }
vb@14
   852
                    
vb@14
   853
                    stringlist_t *_keylist = *keylist;
vb@14
   854
                    for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
vb@14
   855
                        _keylist = stringlist_add(_keylist, r->keyid);
vb@14
   856
                        assert(_keylist);
vb@14
   857
                        if (_keylist == NULL) {
vb@14
   858
                            free_stringlist(*keylist);
vb@14
   859
                            *keylist = NULL;
vb@14
   860
                            result = PEP_OUT_OF_MEMORY;
vb@14
   861
                            break;
vb@14
   862
                        }
vb@14
   863
                    }
vb@14
   864
                    if (result == PEP_OUT_OF_MEMORY)
vb@14
   865
                        break;
vb@14
   866
                }
vb@14
   867
            }
vb@0
   868
		}
vb@0
   869
		break;
vb@0
   870
vb@0
   871
	default:
vb@0
   872
		result = PEP_DECRYPT_WRONG_FORMAT;
vb@0
   873
	}
vb@0
   874
vb@0
   875
	_session->gpgme_data_release(plain);
vb@0
   876
	_session->gpgme_data_release(cipher);
vb@0
   877
	return result;
vb@0
   878
}
vb@0
   879
vb@0
   880
DYNAMIC_API PEP_STATUS verify_text(
vb@0
   881
        PEP_SESSION session, const char *text, size_t size,
vb@0
   882
        const char *signature, size_t sig_size, stringlist_t **keylist
vb@0
   883
    )
vb@0
   884
{
vb@0
   885
	pEpSession *_session = (pEpSession *) session;
vb@0
   886
vb@0
   887
	PEP_STATUS result;
vb@0
   888
	gpgme_error_t gpgme_error;
vb@0
   889
	gpgme_data_t d_text, d_sig;
vb@0
   890
    stringlist_t *_keylist;
vb@0
   891
vb@0
   892
    assert(session);
vb@0
   893
    assert(text);
vb@0
   894
    assert(size);
vb@0
   895
    assert(signature);
vb@0
   896
    assert(sig_size);
vb@0
   897
    assert(keylist);
vb@0
   898
vb@0
   899
    *keylist = NULL;
vb@0
   900
vb@0
   901
    gpgme_error = _session->gpgme_data_new_from_mem(&d_text, text, size, 0);
vb@0
   902
	assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@0
   903
	if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@0
   904
		if (gpgme_error == GPG_ERR_ENOMEM)
vb@0
   905
			return PEP_OUT_OF_MEMORY;
vb@0
   906
		else
vb@0
   907
			return PEP_UNKNOWN_ERROR;
vb@0
   908
	}
vb@0
   909
vb@0
   910
    gpgme_error = _session->gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
vb@0
   911
	assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@0
   912
	if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@0
   913
		_session->gpgme_data_release(d_text);
vb@0
   914
		if (gpgme_error == GPG_ERR_ENOMEM)
vb@0
   915
			return PEP_OUT_OF_MEMORY;
vb@0
   916
		else
vb@0
   917
			return PEP_UNKNOWN_ERROR;
vb@0
   918
	}
vb@0
   919
vb@0
   920
    gpgme_error = _session->gpgme_op_verify(_session->ctx, d_sig, d_text, NULL);
vb@0
   921
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@0
   922
vb@0
   923
    switch (gpgme_error) {
vb@0
   924
    case GPG_ERR_NO_ERROR:
vb@0
   925
        {
vb@0
   926
            gpgme_verify_result_t gpgme_verify_result;
vb@0
   927
            gpgme_signature_t gpgme_signature;
vb@0
   928
vb@0
   929
            gpgme_verify_result =
vb@0
   930
                _session->gpgme_op_verify_result(_session->ctx);
vb@0
   931
            assert(gpgme_verify_result);
vb@0
   932
            gpgme_signature = gpgme_verify_result->signatures;
vb@0
   933
vb@0
   934
            if (gpgme_signature) {
vb@0
   935
                stringlist_t *k;
vb@0
   936
                _keylist = new_stringlist(NULL);
vb@0
   937
                assert(_keylist);
vb@0
   938
                if (_keylist == NULL) {
vb@0
   939
                    _session->gpgme_data_release(d_text);
vb@0
   940
                    _session->gpgme_data_release(d_sig);
vb@0
   941
                    return PEP_OUT_OF_MEMORY;
vb@0
   942
                }
vb@0
   943
                k = _keylist;
vb@0
   944
vb@0
   945
                result = PEP_VERIFIED;
vb@0
   946
                do {
vb@0
   947
                    k = stringlist_add(k, gpgme_signature->fpr);
vb@0
   948
                    if (k == NULL) {
vb@0
   949
                        free_stringlist(_keylist);
vb@0
   950
                        _session->gpgme_data_release(d_text);
vb@0
   951
                        _session->gpgme_data_release(d_sig);
vb@0
   952
                        return PEP_OUT_OF_MEMORY;
vb@0
   953
                    }
vb@0
   954
                    if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
vb@0
   955
                        if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
vb@0
   956
                                || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
vb@0
   957
                            if (result == PEP_VERIFIED
vb@0
   958
                                    || result == PEP_VERIFIED_AND_TRUSTED)
vb@0
   959
                                result = PEP_UNENCRYPTED;
vb@0
   960
                        }
vb@0
   961
                        else {
vb@0
   962
                            result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@0
   963
                            break;
vb@0
   964
                        }
vb@0
   965
                    }
vb@0
   966
                    else {
vb@0
   967
                        if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
vb@0
   968
                            if (result == PEP_VERIFIED)
vb@0
   969
                                result = PEP_VERIFIED_AND_TRUSTED;
vb@0
   970
                        }
vb@0
   971
                        if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
vb@0
   972
                            // good
vb@0
   973
                        }
vb@0
   974
                        else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
vb@0
   975
                            result = PEP_VERIFY_NO_KEY;
vb@0
   976
                        }
vb@0
   977
                        else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
vb@0
   978
                            if (result == PEP_VERIFIED
vb@0
   979
                                    || result == PEP_VERIFIED_AND_TRUSTED)
vb@0
   980
                                result = PEP_UNENCRYPTED;
vb@0
   981
                        }
vb@0
   982
                        else {
vb@0
   983
                            // do nothing
vb@0
   984
                        }
vb@0
   985
                    }
vb@0
   986
                } while ((gpgme_signature = gpgme_signature->next));
vb@0
   987
                *keylist = _keylist;
vb@0
   988
            } else {
vb@0
   989
                result = PEP_UNENCRYPTED;
vb@0
   990
            }
vb@0
   991
            break;
vb@0
   992
        }
vb@0
   993
        break;
vb@0
   994
    case GPG_ERR_NO_DATA:
vb@0
   995
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@0
   996
        break;
vb@0
   997
    case GPG_ERR_INV_VALUE:
vb@0
   998
    default:
vb@0
   999
        result = PEP_UNKNOWN_ERROR;
vb@0
  1000
        break;
vb@0
  1001
    }
vb@0
  1002
vb@0
  1003
    _session->gpgme_data_release(d_text);
vb@0
  1004
    _session->gpgme_data_release(d_sig);
vb@0
  1005
vb@0
  1006
    return result;
vb@0
  1007
}
vb@0
  1008
vb@0
  1009
DYNAMIC_API PEP_STATUS encrypt_and_sign(
vb@0
  1010
        PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
vb@0
  1011
        size_t psize, char **ctext, size_t *csize
vb@0
  1012
    )
vb@0
  1013
{
vb@0
  1014
	pEpSession *_session = (pEpSession *) session;
vb@0
  1015
vb@0
  1016
	PEP_STATUS result;
vb@0
  1017
	gpgme_error_t gpgme_error;
vb@0
  1018
	gpgme_data_t plain, cipher;
vb@0
  1019
	gpgme_key_t *rcpt;
vb@0
  1020
	gpgme_encrypt_flags_t flags;
vb@0
  1021
	const stringlist_t *_keylist;
vb@0
  1022
    int i, j;
vb@0
  1023
vb@0
  1024
	assert(_session);
vb@0
  1025
	assert(keylist);
vb@0
  1026
	assert(ptext);
vb@0
  1027
	assert(psize);
vb@0
  1028
	assert(ctext);
vb@0
  1029
	assert(csize);
vb@0
  1030
vb@0
  1031
	*ctext = NULL;
vb@0
  1032
	*csize = 0;
vb@0
  1033
vb@0
  1034
    gpgme_error = _session->gpgme_data_new_from_mem(&plain, ptext, psize, 0);
vb@0
  1035
	assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@0
  1036
	if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@0
  1037
		if (gpgme_error == GPG_ERR_ENOMEM)
vb@0
  1038
			return PEP_OUT_OF_MEMORY;
vb@0
  1039
		else
vb@0
  1040
			return PEP_UNKNOWN_ERROR;
vb@0
  1041
	}
vb@0
  1042
vb@0
  1043
	gpgme_error = _session->gpgme_data_new(&cipher);
vb@0
  1044
	assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@0
  1045
	if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@0
  1046
		_session->gpgme_data_release(plain);
vb@0
  1047
		if (gpgme_error == GPG_ERR_ENOMEM)
vb@0
  1048
			return PEP_OUT_OF_MEMORY;
vb@0
  1049
		else
vb@0
  1050
			return PEP_UNKNOWN_ERROR;
vb@0
  1051
	}
vb@0
  1052
vb@0
  1053
    rcpt = (gpgme_key_t *) calloc(stringlist_length(keylist) + 1,
vb@0
  1054
            sizeof(gpgme_key_t));
vb@0
  1055
	assert(rcpt);
vb@0
  1056
	if (rcpt == NULL) {
vb@0
  1057
		_session->gpgme_data_release(plain);
vb@0
  1058
		_session->gpgme_data_release(cipher);
vb@0
  1059
		return PEP_OUT_OF_MEMORY;
vb@0
  1060
	}
vb@0
  1061
vb@0
  1062
    for (_keylist=keylist, i=0; _keylist!=NULL; _keylist=_keylist->next, i++) {
vb@0
  1063
		assert(_keylist->value);
vb@0
  1064
        gpgme_error = _session->gpgme_get_key(_session->ctx, _keylist->value,
vb@0
  1065
                &rcpt[i], 0);
vb@0
  1066
		assert(gpgme_error != GPG_ERR_ENOMEM);
vb@0
  1067
vb@0
  1068
		switch (gpgme_error) {
vb@0
  1069
		case GPG_ERR_ENOMEM:
vb@0
  1070
            for (j=0; j<i; j++)
vb@0
  1071
                _session->gpgme_key_unref(rcpt[j]);
vb@0
  1072
			free(rcpt);
vb@0
  1073
			_session->gpgme_data_release(plain);
vb@0
  1074
			_session->gpgme_data_release(cipher);
vb@0
  1075
			return PEP_OUT_OF_MEMORY;
vb@0
  1076
		case GPG_ERR_NO_ERROR:
vb@0
  1077
			break;
vb@0
  1078
		case GPG_ERR_EOF:
vb@0
  1079
            for (j=0; j<i; j++)
vb@0
  1080
                _session->gpgme_key_unref(rcpt[j]);
vb@0
  1081
			free(rcpt);
vb@0
  1082
			_session->gpgme_data_release(plain);
vb@0
  1083
			_session->gpgme_data_release(cipher);
vb@0
  1084
			return PEP_KEY_NOT_FOUND;
vb@0
  1085
		case GPG_ERR_AMBIGUOUS_NAME:
vb@0
  1086
            for (j=0; j<i; j++)
vb@0
  1087
                _session->gpgme_key_unref(rcpt[j]);
vb@0
  1088
			free(rcpt);
vb@0
  1089
			_session->gpgme_data_release(plain);
vb@0
  1090
			_session->gpgme_data_release(cipher);
vb@0
  1091
			return PEP_KEY_HAS_AMBIG_NAME;
vb@0
  1092
        default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
vb@0
  1093
                 // FPR is not a fingerprint or key ID
vb@0
  1094
            for (j=0; j<i; j++)
vb@0
  1095
                _session->gpgme_key_unref(rcpt[j]);
vb@0
  1096
			free(rcpt);
vb@0
  1097
			_session->gpgme_data_release(plain);
vb@0
  1098
			_session->gpgme_data_release(cipher);
vb@0
  1099
			return PEP_GET_KEY_FAILED;
vb@0
  1100
		}
vb@0
  1101
	}
vb@0
  1102
vb@0
  1103
	// TODO: remove that and replace with proper key management
vb@0
  1104
	flags  = GPGME_ENCRYPT_ALWAYS_TRUST;
vb@0
  1105
vb@0
  1106
    gpgme_error = _session->gpgme_op_encrypt_sign(_session->ctx, rcpt, flags,
vb@0
  1107
            plain, cipher);
vb@0
  1108
	switch (gpgme_error) {
vb@0
  1109
	case GPG_ERR_NO_ERROR:
vb@0
  1110
		{
vb@0
  1111
            char *_buffer = NULL;
vb@0
  1112
			size_t reading;
vb@0
  1113
            size_t length = _session->gpgme_data_seek(cipher, 0, SEEK_END);
vb@0
  1114
            assert(length != -1);
vb@0
  1115
			_session->gpgme_data_seek(cipher, 0, SEEK_SET);
vb@0
  1116
vb@0
  1117
			// TODO: make things less memory consuming
vb@0
  1118
            // the following algorithm allocates a buffer for the complete text
vb@0
  1119
vb@0
  1120
            _buffer = (char *) malloc(length + 1);
vb@0
  1121
            assert(_buffer);
vb@0
  1122
            if (_buffer == NULL) {
vb@0
  1123
                for (j=0; j<stringlist_length(keylist); j++)
vb@0
  1124
                    _session->gpgme_key_unref(rcpt[j]);
vb@0
  1125
                free(rcpt);
vb@0
  1126
                _session->gpgme_data_release(plain);
vb@0
  1127
                _session->gpgme_data_release(cipher);
vb@0
  1128
                return PEP_OUT_OF_MEMORY;
vb@0
  1129
            }
vb@0
  1130
vb@0
  1131
            reading = _session->gpgme_data_read(cipher, _buffer, length);
vb@0
  1132
			assert(length == reading);
vb@0
  1133
vb@0
  1134
			*ctext = _buffer;
vb@0
  1135
			*csize = reading;
vb@0
  1136
			(*ctext)[*csize] = 0; // safeguard for naive users
vb@0
  1137
			result = PEP_STATUS_OK;
vb@0
  1138
			break;
vb@0
  1139
		}
vb@0
  1140
	default:
vb@0
  1141
		result = PEP_UNKNOWN_ERROR;
vb@0
  1142
	}
vb@0
  1143
vb@0
  1144
    for (j=0; j<stringlist_length(keylist); j++)
vb@0
  1145
        _session->gpgme_key_unref(rcpt[j]);
vb@0
  1146
	free(rcpt);
vb@0
  1147
	_session->gpgme_data_release(plain);
vb@0
  1148
	_session->gpgme_data_release(cipher);
vb@0
  1149
	return result;
vb@0
  1150
}
vb@0
  1151
vb@0
  1152
DYNAMIC_API PEP_STATUS log_event(
vb@0
  1153
        PEP_SESSION session, const char *title, const char *entity,
vb@0
  1154
        const char *description, const char *comment
vb@0
  1155
    )
vb@0
  1156
{
vb@0
  1157
	pEpSession *_session = (pEpSession *) session;
vb@0
  1158
	PEP_STATUS status = PEP_STATUS_OK;
vb@0
  1159
	int result;
vb@0
  1160
vb@0
  1161
	assert(_session);
vb@0
  1162
	assert(title);
vb@0
  1163
	assert(entity);
vb@0
  1164
vb@0
  1165
	sqlite3_reset(_session->log);
vb@0
  1166
	sqlite3_bind_text(_session->log, 1, title, -1, SQLITE_STATIC);
vb@0
  1167
	sqlite3_bind_text(_session->log, 2, entity, -1, SQLITE_STATIC);
vb@0
  1168
	if (description)
vb@0
  1169
        sqlite3_bind_text(_session->log, 3, description, -1, SQLITE_STATIC);
vb@0
  1170
	else
vb@0
  1171
		sqlite3_bind_null(_session->log, 3);
vb@0
  1172
	if (comment)
vb@0
  1173
		sqlite3_bind_text(_session->log, 4, comment, -1, SQLITE_STATIC);
vb@0
  1174
	else
vb@0
  1175
		sqlite3_bind_null(_session->log, 4);
vb@0
  1176
	do {
vb@0
  1177
		result = sqlite3_step(_session->log);
vb@0
  1178
		assert(result == SQLITE_DONE || result == SQLITE_BUSY);
vb@0
  1179
		if (result != SQLITE_DONE && result != SQLITE_BUSY)
vb@0
  1180
			status = PEP_UNKNOWN_ERROR;
vb@0
  1181
	} while (result == SQLITE_BUSY);
vb@0
  1182
	sqlite3_reset(_session->log);
vb@0
  1183
vb@0
  1184
	return status;
vb@0
  1185
}
vb@0
  1186
vb@0
  1187
DYNAMIC_API PEP_STATUS safeword(
vb@0
  1188
            PEP_SESSION session, uint16_t value, const char *lang,
vb@0
  1189
            char **word, size_t *wsize
vb@0
  1190
        )
vb@0
  1191
{
vb@0
  1192
	pEpSession *_session = (pEpSession *) session;
vb@0
  1193
	PEP_STATUS status = PEP_STATUS_OK;
vb@0
  1194
	int result;
vb@0
  1195
vb@0
  1196
	assert(_session);
vb@0
  1197
	assert(word);
vb@0
  1198
	assert(wsize);
vb@0
  1199
vb@0
  1200
	*word = NULL;
vb@0
  1201
	*wsize = 0;
vb@0
  1202
vb@0
  1203
	if (lang == NULL)
vb@0
  1204
		lang = "en";
vb@0
  1205
vb@0
  1206
	assert((lang[0] >= 'A' && lang[0] <= 'Z')
vb@0
  1207
            || (lang[0] >= 'a' && lang[0] <= 'z'));
vb@0
  1208
	assert((lang[1] >= 'A' && lang[1] <= 'Z')
vb@0
  1209
            || (lang[1] >= 'a' && lang[1] <= 'z'));
vb@0
  1210
	assert(lang[2] == 0);
vb@0
  1211
vb@0
  1212
	sqlite3_reset(_session->safeword);
vb@0
  1213
    sqlite3_bind_text(_session->safeword, 1, lang, -1, SQLITE_STATIC);
vb@0
  1214
	sqlite3_bind_int(_session->safeword, 2, value);
vb@0
  1215
vb@0
  1216
	result = sqlite3_step(_session->safeword);
vb@0
  1217
	if (result == SQLITE_ROW) {
vb@0
  1218
        *word = strdup((const char *) sqlite3_column_text(_session->safeword,
vb@0
  1219
                    1));
vb@0
  1220
		if (*word)
vb@0
  1221
            *wsize = sqlite3_column_bytes(_session->safeword, 1);
vb@0
  1222
		else
vb@0
  1223
			status = PEP_SAFEWORD_NOT_FOUND;
vb@0
  1224
	} else
vb@0
  1225
		status = PEP_SAFEWORD_NOT_FOUND;
vb@0
  1226
vb@0
  1227
	sqlite3_reset(_session->safeword);
vb@0
  1228
	return status;
vb@0
  1229
}
vb@0
  1230
vb@0
  1231
DYNAMIC_API PEP_STATUS safewords(
vb@0
  1232
        PEP_SESSION session, const char *fingerprint, const char *lang,
vb@0
  1233
        char **words, size_t *wsize, int max_words
vb@0
  1234
    )
vb@0
  1235
{
vb@0
  1236
	const char *source = fingerprint;
vb@0
  1237
	char *buffer = calloc(1, MAX_SAFEWORDS_SPACE);
vb@0
  1238
	char *dest = buffer;
vb@0
  1239
	size_t fsize;
vb@0
  1240
    PEP_STATUS _status;
vb@0
  1241
vb@0
  1242
	assert(session);
vb@0
  1243
	assert(fingerprint);
vb@0
  1244
	assert(words);
vb@0
  1245
	assert(wsize);
vb@0
  1246
	assert(max_words >= 0);
vb@0
  1247
vb@0
  1248
	*words = NULL;
vb@0
  1249
	*wsize = 0;
vb@0
  1250
vb@0
  1251
    assert(buffer);
vb@0
  1252
    if (buffer == NULL)
vb@0
  1253
        return PEP_OUT_OF_MEMORY;
vb@0
  1254
vb@0
  1255
	fsize = strlen(fingerprint);
vb@0
  1256
vb@0
  1257
	if (lang == NULL)
vb@0
  1258
		lang = "en";
vb@0
  1259
vb@0
  1260
	assert((lang[0] >= 'A' && lang[0] <= 'Z')
vb@0
  1261
            || (lang[0] >= 'a' && lang[0] <= 'z'));
vb@0
  1262
	assert((lang[1] >= 'A' && lang[1] <= 'Z')
vb@0
  1263
            || (lang[1] >= 'a' && lang[1] <= 'z'));
vb@0
  1264
	assert(lang[2] == 0);
vb@0
  1265
vb@0
  1266
	int n_words = 0;
vb@0
  1267
	while (source < fingerprint + fsize) {
vb@0
  1268
		uint16_t value;
vb@0
  1269
		char *word;
vb@0
  1270
		size_t _wsize;
vb@0
  1271
		int j;
vb@0
  1272
vb@0
  1273
        for (value=0, j=0; j < 4 && source < fingerprint + fsize; ) {
vb@0
  1274
			if (*source >= 'a' && *source <= 'f')
vb@0
  1275
				value += (*source - 'a' + 10) << (3 - j++) * 4;
vb@0
  1276
			else if (*source >= 'A' && *source <= 'F')
vb@0
  1277
				value += (*source - 'A' + 10) << (3 - j++) * 4;
vb@0
  1278
			else if (*source >= '0' && *source <= '9')
vb@0
  1279
				value += (*source - '0') << (3 - j++) * 4;
vb@0
  1280
			
vb@0
  1281
			source++;
vb@0
  1282
		}
vb@0
  1283
vb@0
  1284
		_status = safeword(session, value, lang, &word, &_wsize);
vb@0
  1285
        if (_status == PEP_OUT_OF_MEMORY) {
vb@0
  1286
            free(buffer);
vb@0
  1287
            return PEP_OUT_OF_MEMORY;
vb@0
  1288
        }
vb@0
  1289
		if (word == NULL) {
vb@0
  1290
            free(buffer);
vb@0
  1291
			return PEP_SAFEWORD_NOT_FOUND;
vb@0
  1292
        }
vb@0
  1293
vb@0
  1294
		if (dest + _wsize < buffer + MAX_SAFEWORDS_SPACE - 1) {
vb@0
  1295
			strncpy(dest, word, _wsize);
vb@0
  1296
            free(word);
vb@0
  1297
			dest += _wsize;
vb@0
  1298
		}
vb@0
  1299
		else {
vb@0
  1300
            free(word);
vb@0
  1301
			break; // buffer full
vb@0
  1302
        }
vb@0
  1303
vb@0
  1304
		if (source < fingerprint + fsize
vb@0
  1305
                && dest + _wsize < buffer + MAX_SAFEWORDS_SPACE - 1)
vb@0
  1306
			*dest++ = ' ';
vb@0
  1307
vb@0
  1308
		++n_words;
vb@0
  1309
		if (max_words && n_words >= max_words)
vb@0
  1310
			break;
vb@0
  1311
	}
vb@0
  1312
vb@0
  1313
	*words = buffer;
vb@0
  1314
	*wsize = dest - buffer;
vb@0
  1315
	return PEP_STATUS_OK;
vb@0
  1316
}
vb@0
  1317
vb@0
  1318
pEp_identity *new_identity(
vb@0
  1319
        const char *address, const char *fpr, const char *user_id,
vb@0
  1320
        const char *username
vb@0
  1321
    )
vb@0
  1322
{
vb@0
  1323
    pEp_identity *result = calloc(1, sizeof(pEp_identity));
vb@0
  1324
    assert(result);
vb@0
  1325
    if (result) {
vb@0
  1326
        if (address) {
vb@0
  1327
            result->address = strdup(address);
vb@0
  1328
            assert(result->address);
vb@0
  1329
            if (result->address == NULL) {
vb@0
  1330
                free(result);
vb@0
  1331
                return NULL;
vb@0
  1332
            }
vb@0
  1333
            result->address_size = strlen(address);
vb@0
  1334
        }
vb@0
  1335
        if (fpr) {
vb@0
  1336
            result->fpr = strdup(fpr);
vb@0
  1337
            assert(result->fpr);
vb@0
  1338
            if (result->fpr == NULL) {
vb@0
  1339
                free_identity(result);
vb@0
  1340
                return NULL;
vb@0
  1341
            }
vb@0
  1342
            result->fpr_size = strlen(fpr);
vb@0
  1343
        }
vb@0
  1344
        if (user_id) {
vb@0
  1345
            result->user_id = strdup(user_id);
vb@0
  1346
            assert(result->user_id);
vb@0
  1347
            if (result->user_id == NULL) {
vb@0
  1348
                free_identity(result);
vb@0
  1349
                return NULL;
vb@0
  1350
            }
vb@0
  1351
            result->user_id_size = strlen(user_id);
vb@0
  1352
        }
vb@0
  1353
        if (username) {
vb@0
  1354
            result->username = strdup(username);
vb@0
  1355
            assert(result->username);
vb@0
  1356
            if (result->username == NULL) {
vb@0
  1357
                free_identity(result);
vb@0
  1358
                return NULL;
vb@0
  1359
            }
vb@0
  1360
            result->username_size = strlen(username);
vb@0
  1361
        }
vb@0
  1362
        result->struct_size = sizeof(pEp_identity);
vb@0
  1363
    }
vb@0
  1364
    return result;
vb@0
  1365
}
vb@0
  1366
vb@0
  1367
void free_identity(pEp_identity *identity)
vb@0
  1368
{
vb@0
  1369
    if (identity) {
vb@0
  1370
        free(identity->address);
vb@0
  1371
        free(identity->fpr);
vb@0
  1372
        free(identity->user_id);
vb@0
  1373
        free(identity->username);
vb@0
  1374
        free(identity);
vb@0
  1375
    }
vb@0
  1376
}
vb@0
  1377
vb@0
  1378
DYNAMIC_API PEP_STATUS get_identity(
vb@0
  1379
        PEP_SESSION session, const char *address,
vb@0
  1380
        pEp_identity **identity
vb@0
  1381
    )
vb@0
  1382
{
vb@0
  1383
	pEpSession *_session = (pEpSession *) session;
vb@0
  1384
	PEP_STATUS status = PEP_STATUS_OK;
vb@0
  1385
	static pEp_identity *_identity;
vb@0
  1386
	int result;
vb@0
  1387
	const char *_lang;
vb@0
  1388
vb@0
  1389
	assert(session);
vb@0
  1390
	assert(address);
vb@8
  1391
    assert(address[0]);
vb@0
  1392
vb@0
  1393
    sqlite3_reset(_session->get_identity);
vb@0
  1394
    sqlite3_bind_text(_session->get_identity, 1, address, -1, SQLITE_STATIC);
vb@0
  1395
vb@0
  1396
    result = sqlite3_step(_session->get_identity);
vb@0
  1397
	switch (result) {
vb@0
  1398
	case SQLITE_ROW:
vb@0
  1399
        _identity = new_identity(
vb@0
  1400
                address,
vb@0
  1401
                (const char *) sqlite3_column_text(_session->get_identity, 0),
vb@0
  1402
                (const char *) sqlite3_column_text(_session->get_identity, 1),
vb@0
  1403
                (const char *) sqlite3_column_text(_session->get_identity, 2)
vb@0
  1404
                );
vb@0
  1405
        assert(_identity);
vb@0
  1406
        if (_identity == NULL)
vb@0
  1407
            return PEP_OUT_OF_MEMORY;
vb@0
  1408
vb@0
  1409
        _identity->comm_type = (PEP_comm_type) sqlite3_column_int(_session->get_identity, 3);
vb@0
  1410
        _lang = (const char *) sqlite3_column_text(_session->get_identity, 4);
vb@0
  1411
        if (_lang && _lang[0]) {
vb@0
  1412
			assert(_lang[0] >= 'a' && _lang[0] <= 'z');
vb@0
  1413
			assert(_lang[1] >= 'a' && _lang[1] <= 'z');
vb@0
  1414
			assert(_lang[2] == 0);
vb@0
  1415
			_identity->lang[0] = _lang[0];
vb@0
  1416
			_identity->lang[1] = _lang[1];
vb@0
  1417
            _identity->lang[2] = 0;
vb@0
  1418
		}
vb@0
  1419
		*identity = _identity;
vb@0
  1420
		break;
vb@0
  1421
	default:
vb@0
  1422
        status = PEP_CANNOT_FIND_IDENTITY;
vb@0
  1423
		*identity = NULL;
vb@0
  1424
	}
vb@0
  1425
vb@0
  1426
    sqlite3_reset(_session->get_identity);
vb@0
  1427
	return status;
vb@0
  1428
}
vb@0
  1429
vb@0
  1430
DYNAMIC_API PEP_STATUS set_identity(
vb@0
  1431
        PEP_SESSION session, const pEp_identity *identity
vb@0
  1432
    )
vb@0
  1433
{
vb@0
  1434
	pEpSession *_session = (pEpSession *) session;
vb@0
  1435
	int result;
vb@0
  1436
vb@0
  1437
	assert(session);
vb@0
  1438
	assert(identity);
vb@0
  1439
	assert(identity->address);
vb@0
  1440
	assert(identity->fpr);
vb@0
  1441
	assert(identity->user_id);
vb@0
  1442
	assert(identity->username);
vb@0
  1443
vb@0
  1444
	sqlite3_exec(_session->db, "BEGIN ;", NULL, NULL, NULL);
vb@0
  1445
vb@0
  1446
	sqlite3_reset(_session->set_person);
vb@0
  1447
    sqlite3_bind_text(_session->set_person, 1, identity->user_id, -1,
vb@0
  1448
            SQLITE_STATIC);
vb@0
  1449
    sqlite3_bind_text(_session->set_person, 2, identity->username, -1,
vb@0
  1450
            SQLITE_STATIC);
vb@0
  1451
	if (identity->lang[0])
vb@0
  1452
        sqlite3_bind_text(_session->set_person, 3, identity->lang, 1,
vb@0
  1453
                SQLITE_STATIC);
vb@0
  1454
	else
vb@0
  1455
		sqlite3_bind_null(_session->set_person, 3);
vb@0
  1456
	result = sqlite3_step(_session->set_person);
vb@0
  1457
	sqlite3_reset(_session->set_person);
vb@0
  1458
	if (result != SQLITE_DONE) {
vb@0
  1459
		sqlite3_exec(_session->db, "ROLLBACK ;", NULL, NULL, NULL);
vb@0
  1460
		return PEP_CANNOT_SET_PERSON;
vb@0
  1461
	}
vb@0
  1462
vb@0
  1463
	sqlite3_reset(_session->set_pgp_keypair);
vb@0
  1464
    sqlite3_bind_text(_session->set_pgp_keypair, 1, identity->fpr, -1,
vb@0
  1465
            SQLITE_STATIC);
vb@0
  1466
	result = sqlite3_step(_session->set_pgp_keypair);
vb@0
  1467
	sqlite3_reset(_session->set_pgp_keypair);
vb@0
  1468
	if (result != SQLITE_DONE) {
vb@0
  1469
		sqlite3_exec(_session->db, "ROLLBACK ;", NULL, NULL, NULL);
vb@0
  1470
		return PEP_CANNOT_SET_PGP_KEYPAIR;
vb@0
  1471
	}
vb@0
  1472
vb@0
  1473
	sqlite3_reset(_session->set_identity);
vb@0
  1474
    sqlite3_bind_text(_session->set_identity, 1, identity->address, -1,
vb@0
  1475
            SQLITE_STATIC);
vb@0
  1476
    sqlite3_bind_text(_session->set_identity, 2, identity->fpr, -1,
vb@0
  1477
            SQLITE_STATIC);
vb@0
  1478
    sqlite3_bind_text(_session->set_identity, 3, identity->user_id, -1,
vb@0
  1479
            SQLITE_STATIC);
vb@0
  1480
	result = sqlite3_step(_session->set_identity);
vb@0
  1481
	sqlite3_reset(_session->set_identity);
vb@0
  1482
	if (result != SQLITE_DONE) {
vb@0
  1483
		sqlite3_exec(_session->db, "ROLLBACK ;", NULL, NULL, NULL);
vb@0
  1484
		return PEP_CANNOT_SET_IDENTITY;
vb@0
  1485
	}
vb@0
  1486
vb@0
  1487
	sqlite3_reset(_session->set_trust);
vb@0
  1488
    sqlite3_bind_text(_session->set_trust, 1, identity->user_id, -1,
vb@0
  1489
            SQLITE_STATIC);
vb@0
  1490
    sqlite3_bind_text(_session->set_trust, 2, identity->fpr, -1,
vb@0
  1491
            SQLITE_STATIC);
vb@0
  1492
	sqlite3_bind_int(_session->set_trust, 3, identity->comm_type);
vb@0
  1493
	result = sqlite3_step(_session->set_trust);
vb@0
  1494
	sqlite3_reset(_session->set_trust);
vb@0
  1495
	if (result != SQLITE_DONE) {
vb@0
  1496
		sqlite3_exec(_session->db, "ROLLBACK ;", NULL, NULL, NULL);
vb@0
  1497
		return PEP_CANNOT_SET_IDENTITY;
vb@0
  1498
	}
vb@0
  1499
vb@0
  1500
    result = sqlite3_exec(_session->db, "COMMIT ;", NULL, NULL, NULL);
vb@0
  1501
	if (result == SQLITE_OK)
vb@0
  1502
		return PEP_STATUS_OK;
vb@0
  1503
	else
vb@0
  1504
		return PEP_COMMIT_FAILED;
vb@0
  1505
}
vb@0
  1506
vb@0
  1507
DYNAMIC_API PEP_STATUS generate_keypair(
vb@0
  1508
        PEP_SESSION session, pEp_identity *identity
vb@0
  1509
    )
vb@0
  1510
{
vb@0
  1511
	pEpSession *_session = (pEpSession *) session;
vb@0
  1512
	gpgme_error_t gpgme_error;
vb@0
  1513
    char *parms;
vb@0
  1514
    const char *template =
vb@0
  1515
        "<GnupgKeyParms format=\"internal\">\n"
vb@0
  1516
        "Key-Type: RSA\n"
vb@0
  1517
        "Key-Length: 4096\n"
vb@0
  1518
        "Name-Real: %s\n"
vb@0
  1519
        "Name-Email: %s\n"
vb@0
  1520
        /* "Passphrase: %s\n" */
vb@0
  1521
        "Expire-Date: 1y\n"
vb@0
  1522
        "</GnupgKeyParms>\n";
vb@0
  1523
    int result;
vb@0
  1524
    gpgme_genkey_result_t gpgme_genkey_result;
vb@0
  1525
vb@0
  1526
    assert(session);
vb@0
  1527
    assert(identity);
vb@0
  1528
    assert(identity->address);
vb@0
  1529
    assert(identity->fpr == NULL);
vb@0
  1530
    assert(identity->username);
vb@0
  1531
    
vb@0
  1532
    parms = calloc(1, PARMS_MAX);
vb@0
  1533
    assert(parms);
vb@0
  1534
    if (parms == NULL)
vb@0
  1535
        return PEP_OUT_OF_MEMORY;
vb@0
  1536
vb@0
  1537
    result = snprintf(parms, PARMS_MAX, template, identity->username,
vb@0
  1538
            identity->address); // , _session->passphrase);
vb@0
  1539
    assert(result < PARMS_MAX);
vb@0
  1540
    if (result >= PARMS_MAX) {
vb@0
  1541
        free(parms);
vb@0
  1542
        return PEP_BUFFER_TOO_SMALL;
vb@0
  1543
    }
vb@0
  1544
vb@0
  1545
    gpgme_error = _session->gpgme_op_genkey(_session->ctx, parms, NULL, NULL);
vb@0
  1546
    free(parms);
vb@0
  1547
vb@0
  1548
    switch (gpgme_error) {
vb@0
  1549
    case GPG_ERR_NO_ERROR:
vb@0
  1550
        break;
vb@0
  1551
    case GPG_ERR_INV_VALUE:
vb@0
  1552
        return PEP_ILLEGAL_VALUE;
vb@0
  1553
    case GPG_ERR_GENERAL:
vb@0
  1554
        return PEP_CANNOT_CREATE_KEY;
vb@0
  1555
    default:
vb@0
  1556
        assert(0);
vb@0
  1557
        return PEP_UNKNOWN_ERROR;
vb@0
  1558
    }
vb@0
  1559
vb@0
  1560
    gpgme_genkey_result = _session->gpgme_op_genkey_result(_session->ctx);
vb@0
  1561
    assert(gpgme_genkey_result);
vb@0
  1562
    assert(gpgme_genkey_result->fpr);
vb@0
  1563
vb@0
  1564
    identity->fpr = strdup(gpgme_genkey_result->fpr);
vb@0
  1565
vb@0
  1566
    return PEP_STATUS_OK;
vb@0
  1567
}
vb@0
  1568
vb@0
  1569
PEP_STATUS delete_keypair(PEP_SESSION session, const char *fpr)
vb@0
  1570
{
vb@0
  1571
	pEpSession *_session = (pEpSession *) session;
vb@0
  1572
	gpgme_error_t gpgme_error;
vb@0
  1573
    gpgme_key_t key;
vb@0
  1574
vb@0
  1575
    assert(session);
vb@0
  1576
    assert(fpr);
vb@0
  1577
vb@0
  1578
    gpgme_error = _session->gpgme_get_key(_session->ctx, fpr, &key, 0);
vb@0
  1579
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@0
  1580
    switch (gpgme_error) {
vb@0
  1581
    case GPG_ERR_NO_ERROR:
vb@0
  1582
        break;
vb@0
  1583
    case GPG_ERR_EOF:
vb@0
  1584
        return PEP_KEY_NOT_FOUND;
vb@0
  1585
    case GPG_ERR_INV_VALUE:
vb@0
  1586
        return PEP_ILLEGAL_VALUE;
vb@0
  1587
    case GPG_ERR_AMBIGUOUS_NAME:
vb@0
  1588
        return PEP_KEY_HAS_AMBIG_NAME;
vb@0
  1589
    case GPG_ERR_ENOMEM:
vb@0
  1590
        return PEP_OUT_OF_MEMORY;
vb@0
  1591
    default:
vb@0
  1592
        assert(0);
vb@0
  1593
        return PEP_UNKNOWN_ERROR;
vb@0
  1594
    }
vb@0
  1595
vb@0
  1596
    gpgme_error = _session->gpgme_op_delete(_session->ctx, key, 1);
vb@0
  1597
    _session->gpgme_key_unref(key);
vb@0
  1598
    switch (gpgme_error) {
vb@0
  1599
    case GPG_ERR_NO_ERROR:
vb@0
  1600
        break;
vb@0
  1601
    case GPG_ERR_INV_VALUE:
vb@0
  1602
        assert(0);
vb@0
  1603
        return PEP_UNKNOWN_ERROR;
vb@0
  1604
    case GPG_ERR_NO_PUBKEY:
vb@0
  1605
        assert(0);
vb@0
  1606
        return PEP_KEY_NOT_FOUND;
vb@0
  1607
    case GPG_ERR_AMBIGUOUS_NAME:
vb@0
  1608
        assert(0);
vb@0
  1609
        return PEP_KEY_HAS_AMBIG_NAME;
vb@0
  1610
    default:
vb@0
  1611
        assert(0);
vb@0
  1612
        return PEP_UNKNOWN_ERROR;
vb@0
  1613
    }
vb@0
  1614
vb@0
  1615
    return PEP_STATUS_OK;
vb@0
  1616
}
vb@0
  1617
vb@0
  1618
PEP_STATUS import_key(PEP_SESSION session, const char *key_data, size_t size)
vb@0
  1619
{
vb@0
  1620
	pEpSession *_session = (pEpSession *) session;
vb@0
  1621
	gpgme_error_t gpgme_error;
vb@0
  1622
    gpgme_data_t dh;
vb@0
  1623
vb@0
  1624
    assert(session);
vb@0
  1625
    assert(key_data);
vb@0
  1626
vb@0
  1627
    gpgme_error = _session->gpgme_data_new_from_mem(&dh, key_data, size, 0);
vb@0
  1628
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@0
  1629
    switch (gpgme_error) {
vb@0
  1630
    case GPG_ERR_NO_ERROR:
vb@0
  1631
        break;
vb@0
  1632
    case GPG_ERR_ENOMEM:
vb@0
  1633
        return PEP_OUT_OF_MEMORY;
vb@0
  1634
    case GPG_ERR_INV_VALUE:
vb@0
  1635
        assert(0);
vb@0
  1636
        return PEP_UNKNOWN_ERROR;
vb@0
  1637
    default:
vb@0
  1638
        assert(0);
vb@0
  1639
        return PEP_UNKNOWN_ERROR;
vb@0
  1640
    }
vb@0
  1641
vb@0
  1642
    gpgme_error = _session->gpgme_op_import(_session->ctx, dh);
vb@0
  1643
    switch (gpgme_error) {
vb@0
  1644
    case GPG_ERR_NO_ERROR:
vb@0
  1645
        break;
vb@0
  1646
    case GPG_ERR_INV_VALUE:
vb@0
  1647
        assert(0);
vb@0
  1648
        _session->gpgme_data_release(dh);
vb@0
  1649
        return PEP_UNKNOWN_ERROR;
vb@0
  1650
    case GPG_ERR_NO_DATA:
vb@0
  1651
        _session->gpgme_data_release(dh);
vb@0
  1652
        return PEP_ILLEGAL_VALUE;
vb@0
  1653
    default:
vb@0
  1654
        assert(0);
vb@0
  1655
        _session->gpgme_data_release(dh);
vb@0
  1656
        return PEP_UNKNOWN_ERROR;
vb@0
  1657
    }
vb@0
  1658
vb@0
  1659
    _session->gpgme_data_release(dh);
vb@0
  1660
    return PEP_STATUS_OK;
vb@0
  1661
}
vb@0
  1662
vb@0
  1663
PEP_STATUS export_key(
vb@0
  1664
        PEP_SESSION session, const char *fpr, char **key_data, size_t *size
vb@0
  1665
    )
vb@0
  1666
{
vb@0
  1667
	pEpSession *_session = (pEpSession *) session;
vb@0
  1668
	gpgme_error_t gpgme_error;
vb@0
  1669
    gpgme_data_t dh;
vb@0
  1670
    size_t _size;
vb@0
  1671
    char *buffer;
vb@0
  1672
    int reading;
vb@0
  1673
vb@0
  1674
    assert(session);
vb@0
  1675
    assert(fpr);
vb@0
  1676
    assert(key_data);
vb@0
  1677
    assert(size);
vb@0
  1678
vb@0
  1679
    gpgme_error = _session->gpgme_data_new(&dh);
vb@0
  1680
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@0
  1681
    switch (gpgme_error) {
vb@0
  1682
    case GPG_ERR_NO_ERROR:
vb@0
  1683
        break;
vb@0
  1684
    case GPG_ERR_ENOMEM:
vb@0
  1685
        return PEP_OUT_OF_MEMORY;
vb@0
  1686
    case GPG_ERR_INV_VALUE:
vb@0
  1687
        assert(0);
vb@0
  1688
        return PEP_UNKNOWN_ERROR;
vb@0
  1689
    default:
vb@0
  1690
        assert(0);
vb@0
  1691
        return PEP_UNKNOWN_ERROR;
vb@0
  1692
    }
vb@0
  1693
vb@0
  1694
    gpgme_error = _session->gpgme_op_export(_session->ctx, fpr,
vb@0
  1695
            GPGME_EXPORT_MODE_MINIMAL, dh);
vb@0
  1696
    switch (gpgme_error) {
vb@0
  1697
    case GPG_ERR_NO_ERROR:
vb@0
  1698
        break;
vb@0
  1699
    case GPG_ERR_EOF:
vb@0
  1700
        _session->gpgme_data_release(dh);
vb@0
  1701
        return PEP_KEY_NOT_FOUND;
vb@0
  1702
    case GPG_ERR_INV_VALUE:
vb@0
  1703
        assert(0);
vb@0
  1704
        _session->gpgme_data_release(dh);
vb@0
  1705
        return PEP_UNKNOWN_ERROR;
vb@0
  1706
    default:
vb@0
  1707
        assert(0);
vb@0
  1708
        _session->gpgme_data_release(dh);
vb@0
  1709
        return PEP_UNKNOWN_ERROR;
vb@0
  1710
    };
vb@0
  1711
vb@0
  1712
    _size = _session->gpgme_data_seek(dh, 0, SEEK_END);
vb@0
  1713
    assert(_size != -1);
vb@0
  1714
    _session->gpgme_data_seek(dh, 0, SEEK_SET);
vb@0
  1715
vb@0
  1716
    buffer = malloc(_size + 1);
vb@0
  1717
    assert(buffer);
vb@0
  1718
    if (buffer == NULL) {
vb@0
  1719
        _session->gpgme_data_release(dh);
vb@0
  1720
        return PEP_OUT_OF_MEMORY;
vb@0
  1721
    }
vb@0
  1722
vb@0
  1723
    reading = _session->gpgme_data_read(dh, buffer, _size);
vb@0
  1724
    assert(_size == reading);
vb@0
  1725
vb@0
  1726
    // safeguard for the naive user
vb@0
  1727
    buffer[_size] = 0;
vb@0
  1728
vb@0
  1729
    *key_data = buffer;
vb@0
  1730
    *size = _size;
vb@0
  1731
vb@0
  1732
    _session->gpgme_data_release(dh);
vb@0
  1733
    return PEP_STATUS_OK;
vb@0
  1734
}
vb@0
  1735
vb@0
  1736
static void _switch_mode(pEpSession *_session, gpgme_keylist_mode_t remove_mode,
vb@0
  1737
        gpgme_keylist_mode_t add_mode)
vb@0
  1738
{
vb@0
  1739
	gpgme_error_t gpgme_error;
vb@0
  1740
    gpgme_keylist_mode_t mode;
vb@0
  1741
vb@0
  1742
    mode = _session->gpgme_get_keylist_mode(_session->ctx);
vb@0
  1743
vb@0
  1744
    mode &= ~remove_mode;
vb@0
  1745
    mode |= add_mode;
vb@0
  1746
vb@0
  1747
    gpgme_error = _session->gpgme_set_keylist_mode(_session->ctx, mode);
vb@0
  1748
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@0
  1749
}
vb@0
  1750
vb@0
  1751
PEP_STATUS recv_key(PEP_SESSION session, const char *pattern)
vb@0
  1752
{
vb@0
  1753
	pEpSession *_session = (pEpSession *) session;
vb@0
  1754
	gpgme_error_t gpgme_error;
vb@0
  1755
    gpgme_key_t key;
vb@0
  1756
vb@0
  1757
    assert(session);
vb@0
  1758
    assert(pattern);
vb@0
  1759
vb@0
  1760
    _switch_mode(_session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
vb@0
  1761
vb@0
  1762
    gpgme_error = _session->gpgme_op_keylist_start(_session->ctx, pattern, 0);
vb@0
  1763
    switch (gpgme_error) {
vb@0
  1764
    case GPG_ERR_NO_ERROR:
vb@0
  1765
        break;
vb@0
  1766
    case GPG_ERR_INV_VALUE:
vb@0
  1767
        assert(0);
vb@0
  1768
        _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
vb@0
  1769
                GPGME_KEYLIST_MODE_LOCAL);
vb@0
  1770
        return PEP_UNKNOWN_ERROR;
vb@0
  1771
    default:
vb@0
  1772
        _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
vb@0
  1773
                GPGME_KEYLIST_MODE_LOCAL);
vb@0
  1774
        return PEP_GET_KEY_FAILED;
vb@0
  1775
    };
vb@0
  1776
vb@0
  1777
    do {
vb@0
  1778
        gpgme_error = _session->gpgme_op_keylist_next(_session->ctx, &key);
vb@0
  1779
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@0
  1780
        switch (gpgme_error) {
vb@0
  1781
        case GPG_ERR_EOF:
vb@0
  1782
            break;
vb@0
  1783
        case GPG_ERR_NO_ERROR:
vb@0
  1784
            {
vb@0
  1785
                gpgme_error_t gpgme_error;
vb@0
  1786
                gpgme_key_t keys[2];
vb@0
  1787
vb@0
  1788
                keys[0] = key;
vb@0
  1789
                keys[1] = NULL;
vb@0
  1790
vb@0
  1791
                gpgme_error = _session->gpgme_op_import_keys(_session->ctx, keys);
vb@0
  1792
                _session->gpgme_key_unref(key);
vb@0
  1793
                assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@0
  1794
                assert(gpgme_error != GPG_ERR_CONFLICT);
vb@0
  1795
            }
vb@0
  1796
            break;
vb@0
  1797
        case GPG_ERR_ENOMEM:
vb@0
  1798
            _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
vb@0
  1799
                    GPGME_KEYLIST_MODE_LOCAL);
vb@0
  1800
            _session->gpgme_op_keylist_end(_session->ctx);
vb@0
  1801
            return PEP_OUT_OF_MEMORY;
vb@0
  1802
        default:
vb@0
  1803
            // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
vb@0
  1804
            // reading first key
vb@0
  1805
#ifndef NDEBUG
vb@0
  1806
            fprintf(stderr, "warning: unknown result 0x%x of"
vb@0
  1807
                    " gpgme_op_keylist_next()\n", gpgme_error);
vb@0
  1808
#endif
vb@0
  1809
            gpgme_error = GPG_ERR_EOF;
vb@0
  1810
            break;
vb@0
  1811
        };
vb@0
  1812
    } while (gpgme_error != GPG_ERR_EOF);
vb@0
  1813
vb@0
  1814
    _session->gpgme_op_keylist_end(_session->ctx);
vb@0
  1815
    _switch_mode(_session, GPGME_KEYLIST_MODE_EXTERN,
vb@0
  1816
            GPGME_KEYLIST_MODE_LOCAL);
vb@0
  1817
    return PEP_STATUS_OK;
vb@0
  1818
}
vb@0
  1819
vb@0
  1820
DYNAMIC_API PEP_STATUS find_keys(
vb@0
  1821
        PEP_SESSION session, const char *pattern, stringlist_t **keylist
vb@0
  1822
    )
vb@0
  1823
{
vb@0
  1824
	pEpSession *_session = (pEpSession *) session;
vb@0
  1825
	gpgme_error_t gpgme_error;
vb@0
  1826
    gpgme_key_t key;
vb@0
  1827
    stringlist_t *_keylist;
vb@0
  1828
    char *fpr;
vb@0
  1829
vb@0
  1830
    assert(session);
vb@0
  1831
    assert(pattern);
vb@0
  1832
    assert(keylist);
vb@0
  1833
vb@0
  1834
    *keylist = NULL;
vb@0
  1835
vb@0
  1836
    gpgme_error = _session->gpgme_op_keylist_start(_session->ctx, pattern, 0);
vb@0
  1837
    switch (gpgme_error) {
vb@0
  1838
    case GPG_ERR_NO_ERROR:
vb@0
  1839
        break;
vb@0
  1840
    case GPG_ERR_INV_VALUE:
vb@0
  1841
        assert(0);
vb@0
  1842
        return PEP_UNKNOWN_ERROR;
vb@0
  1843
    default:
vb@0
  1844
        return PEP_GET_KEY_FAILED;
vb@0
  1845
    };
vb@0
  1846
vb@0
  1847
    _keylist = new_stringlist(NULL);
vb@0
  1848
    stringlist_t *_k = _keylist;
vb@0
  1849
vb@0
  1850
    do {
vb@0
  1851
        gpgme_error = _session->gpgme_op_keylist_next(_session->ctx, &key);
vb@0
  1852
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@0
  1853
        switch (gpgme_error) {
vb@0
  1854
        case GPG_ERR_EOF:
vb@0
  1855
            break;
vb@0
  1856
        case GPG_ERR_NO_ERROR:
vb@0
  1857
            assert(key);
vb@0
  1858
            assert(key->subkeys);
vb@0
  1859
            fpr = key->subkeys->fpr;
vb@0
  1860
            assert(fpr);
vb@0
  1861
            _k = stringlist_add(_k, fpr);
vb@0
  1862
            assert(_k);
vb@0
  1863
            if (_k != NULL)
vb@0
  1864
                break;
vb@0
  1865
        case GPG_ERR_ENOMEM:
vb@0
  1866
            free_stringlist(_keylist);
vb@0
  1867
            _session->gpgme_op_keylist_end(_session->ctx);
vb@0
  1868
            return PEP_OUT_OF_MEMORY;
vb@0
  1869
        default:
vb@0
  1870
            // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
vb@0
  1871
            // reading first key
vb@0
  1872
#ifndef NDEBUG
vb@0
  1873
            fprintf(stderr, "warning: unknown result 0x%x of"
vb@0
  1874
                    " gpgme_op_keylist_next()\n", gpgme_error);
vb@0
  1875
#endif
vb@0
  1876
            gpgme_error = GPG_ERR_EOF;
vb@0
  1877
            break;
vb@0
  1878
        };
vb@0
  1879
    } while (gpgme_error != GPG_ERR_EOF);
vb@0
  1880
vb@0
  1881
    _session->gpgme_op_keylist_end(_session->ctx);
vb@0
  1882
    *keylist = _keylist;
vb@0
  1883
    return PEP_STATUS_OK;
vb@0
  1884
}
vb@0
  1885
vb@0
  1886
PEP_STATUS send_key(PEP_SESSION session, const char *pattern)
vb@0
  1887
{
vb@0
  1888
	pEpSession *_session = (pEpSession *) session;
vb@0
  1889
	gpgme_error_t gpgme_error;
vb@0
  1890
vb@8
  1891
    assert(session);
vb@8
  1892
    assert(pattern);
vb@8
  1893
vb@0
  1894
    gpgme_error = _session->gpgme_op_export(_session->ctx, pattern,
vb@0
  1895
            GPGME_EXPORT_MODE_EXTERN, NULL);
vb@0
  1896
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@0
  1897
    if (gpgme_error == GPG_ERR_NO_ERROR)
vb@0
  1898
        return PEP_STATUS_OK;
vb@0
  1899
    else
vb@0
  1900
        return PEP_CANNOT_SEND_KEY;
vb@0
  1901
}
vb@0
  1902
vb@0
  1903
void pEp_free(void *p)
vb@0
  1904
{
vb@0
  1905
    free(p);
vb@0
  1906
}
vb@0
  1907
vb@8
  1908
DYNAMIC_API PEP_STATUS get_trust(PEP_SESSION session, pEp_identity *identity)
vb@8
  1909
{
vb@8
  1910
    pEpSession *_session = (pEpSession *) session;
vb@8
  1911
    PEP_STATUS status = PEP_STATUS_OK;
vb@8
  1912
    int result;
vb@8
  1913
vb@8
  1914
    assert(session);
vb@8
  1915
    assert(identity);
vb@8
  1916
    assert(identity->user_id);
vb@8
  1917
    assert(identity->user_id[0]);
vb@8
  1918
    assert(identity->fpr);
vb@8
  1919
    assert(identity->fpr[0]);
vb@8
  1920
vb@8
  1921
    identity->comm_type = PEP_ct_unknown;
vb@8
  1922
vb@8
  1923
    sqlite3_reset(_session->get_trust);
vb@8
  1924
    sqlite3_bind_text(_session->get_trust, 1, identity->user_id, -1, SQLITE_STATIC);
vb@8
  1925
    sqlite3_bind_text(_session->get_trust, 2, identity->fpr, -1, SQLITE_STATIC);
vb@8
  1926
vb@8
  1927
    result = sqlite3_step(_session->get_trust);
vb@8
  1928
    switch (result) {
vb@8
  1929
    case SQLITE_ROW: {
vb@8
  1930
        const char * user_id = (const char *) sqlite3_column_text(_session->get_trust, 1);
vb@8
  1931
        int comm_type = (PEP_comm_type) sqlite3_column_int(_session->get_trust, 2);
vb@8
  1932
vb@8
  1933
        if (strcmp(user_id, identity->user_id) != 0) {
vb@8
  1934
            free(identity->user_id);
vb@8
  1935
            identity->user_id = strdup(user_id);
vb@8
  1936
            assert(identity->user_id);
vb@8
  1937
            if (identity->user_id == NULL)
vb@8
  1938
                return PEP_OUT_OF_MEMORY;
vb@8
  1939
        }
vb@8
  1940
        identity->comm_type = comm_type;
vb@8
  1941
        break;
vb@8
  1942
    }
vb@8
  1943
 
vb@8
  1944
    default:
vb@8
  1945
        status = PEP_CANNOT_FIND_IDENTITY;
vb@8
  1946
    }
vb@8
  1947
vb@8
  1948
    sqlite3_reset(_session->get_trust);
vb@8
  1949
    return status;
vb@9
  1950
}
vb@9
  1951
vb@9
  1952
DYNAMIC_API PEP_STATUS get_key_rating(
vb@9
  1953
    PEP_SESSION session,
vb@9
  1954
    const char *fpr,
vb@9
  1955
    PEP_comm_type *comm_type
vb@9
  1956
    )
vb@9
  1957
{
vb@9
  1958
    pEpSession *_session = (pEpSession *) session;
vb@9
  1959
    PEP_STATUS status = PEP_STATUS_OK;
vb@9
  1960
    gpgme_error_t gpgme_error;
vb@9
  1961
    gpgme_key_t key;
vb@9
  1962
vb@9
  1963
    assert(session);
vb@9
  1964
    assert(fpr);
vb@9
  1965
    assert(comm_type);
vb@9
  1966
    
vb@9
  1967
    *comm_type = PEP_ct_unknown;
vb@9
  1968
vb@9
  1969
    gpgme_error = _session->gpgme_op_keylist_start(_session->ctx, fpr, 0);
vb@9
  1970
    switch (gpgme_error) {
vb@9
  1971
    case GPG_ERR_NO_ERROR:
vb@9
  1972
        break;
vb@9
  1973
    case GPG_ERR_INV_VALUE:
vb@9
  1974
        assert(0);
vb@9
  1975
        return PEP_UNKNOWN_ERROR;
vb@9
  1976
    default:
vb@9
  1977
        return PEP_GET_KEY_FAILED;
vb@9
  1978
    };
vb@9
  1979
vb@9
  1980
    gpgme_error = _session->gpgme_op_keylist_next(_session->ctx, &key);
vb@9
  1981
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@9
  1982
vb@14
  1983
    if (key == NULL) {
vb@14
  1984
        _session->gpgme_op_keylist_end(_session->ctx);
vb@14
  1985
        return PEP_KEY_NOT_FOUND;
vb@14
  1986
    }
vb@14
  1987
vb@9
  1988
    switch (key->protocol) {
vb@9
  1989
    case GPGME_PROTOCOL_OpenPGP:
vb@9
  1990
    case GPGME_PROTOCOL_DEFAULT:
vb@9
  1991
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
vb@9
  1992
        break;
vb@9
  1993
    case GPGME_PROTOCOL_CMS:
vb@9
  1994
        *comm_type = PEP_ct_CMS_unconfirmed;
vb@9
  1995
        break;
vb@9
  1996
    default:
vb@9
  1997
        *comm_type = PEP_ct_unknown;
vb@9
  1998
        _session->gpgme_op_keylist_end(_session->ctx);
vb@9
  1999
        return PEP_STATUS_OK;
vb@9
  2000
    }
vb@9
  2001
vb@9
  2002
    switch (gpgme_error) {
vb@9
  2003
    case GPG_ERR_EOF:
vb@9
  2004
        break;
vb@9
  2005
    case GPG_ERR_NO_ERROR:
vb@9
  2006
        assert(key);
vb@9
  2007
        assert(key->subkeys);
vb@9
  2008
        for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
vb@9
  2009
            if (sk->length < 1024)
vb@9
  2010
                *comm_type = PEP_ct_key_too_short;
vb@9
  2011
            else if (
vb@9
  2012
                (
vb@9
  2013
                       (sk->pubkey_algo == GPGME_PK_RSA)
vb@9
  2014
                    || (sk->pubkey_algo == GPGME_PK_RSA_E)
vb@9
  2015
                    || (sk->pubkey_algo == GPGME_PK_RSA_S)
vb@9
  2016
                )
vb@9
  2017
                && sk->length == 1024
vb@9
  2018
            )
vb@9
  2019
                *comm_type = PEP_ct_OpenPGP_1024_RSA_unconfirmed;
vb@9
  2020
vb@9
  2021
            if (sk->invalid) {
vb@9
  2022
                *comm_type = PEP_ct_key_b0rken;
vb@9
  2023
                break;
vb@9
  2024
            }
vb@9
  2025
            if (sk->expired) {
vb@9
  2026
                *comm_type = PEP_ct_key_expired;
vb@9
  2027
                break;
vb@9
  2028
            }
vb@9
  2029
            if (sk->revoked) {
vb@9
  2030
                *comm_type = PEP_ct_key_revoked;
vb@9
  2031
                break;
vb@9
  2032
            }
vb@9
  2033
        }
vb@9
  2034
        break;
vb@9
  2035
    case GPG_ERR_ENOMEM:
vb@9
  2036
        _session->gpgme_op_keylist_end(_session->ctx);
vb@10
  2037
        *comm_type = PEP_ct_unknown;
vb@9
  2038
        return PEP_OUT_OF_MEMORY;
vb@9
  2039
    default:
vb@9
  2040
        // BUG: GPGME returns an illegal value instead of GPG_ERR_EOF after
vb@9
  2041
        // reading first key
vb@9
  2042
#ifndef NDEBUG
vb@9
  2043
        fprintf(stderr, "warning: unknown result 0x%x of"
vb@9
  2044
            " gpgme_op_keylist_next()\n", gpgme_error);
vb@9
  2045
#endif
vb@9
  2046
        gpgme_error = GPG_ERR_EOF;
vb@9
  2047
        break;
vb@9
  2048
    };
vb@9
  2049
vb@9
  2050
    _session->gpgme_op_keylist_end(_session->ctx);
vb@9
  2051
vb@9
  2052
    return status;
vb@14
  2053
}