src/pgp_gpg.c
author Krista Bennett <krista@pep-project.org>
Tue, 31 Jul 2018 21:39:01 +0200
branchENGINE-450-MARK-II
changeset 2795 4bd160717c54
parent 2792 bc4b1dff3fdb
child 2797 0ff0fc8d9683
child 2821 7fe5b66e570d
permissions -rw-r--r--
ENGINE-450: Fixes for 450 reintegrated, and fixed a mem bug that doesn't happen when you have a ton of keys, so it got missed before.
vb@1517
     1
// This file is under GNU General Public License 3.0
vb@1517
     2
// see LICENSE.txt
vb@1517
     3
vb@219
     4
#include "platform.h"
vb@130
     5
#include "pEp_internal.h"
vb@24
     6
#include "pgp_gpg.h"
vb@24
     7
vb@78
     8
#include <limits.h>
vb@78
     9
vb@62
    10
#include "wrappers.h"
vb@62
    11
vb@45
    12
#define _GPGERR(X) ((X) & 0xffffL)
vb@45
    13
vb@76
    14
static void *gpgme;
vb@76
    15
static struct gpg_s gpg;
vb@74
    16
krista@2789
    17
struct _str_ptr_and_bit {
krista@2789
    18
    const char* key;
krista@2789
    19
    int bit;
krista@2789
    20
};
krista@2789
    21
krista@2789
    22
typedef struct _str_ptr_and_bit str_ptr_and_bit;
krista@2789
    23
krista@2789
    24
int strptrcmp(const void* a, const void* b) {
krista@2789
    25
    return (int)((((str_ptr_and_bit*)(a))->key) - (((str_ptr_and_bit*)(b))->key));
krista@2789
    26
}
krista@2789
    27
krista@2789
    28
// This is in response to ENGINE-427. We should NOT be aiming to keep this here.
krista@2789
    29
bool quickfix_config(stringlist_t* keys, const char* config_file_path) {
krista@2789
    30
    static char buf[MAX_LINELENGTH];
krista@2789
    31
    size_t num_keys = stringlist_length(keys);
krista@2789
    32
krista@2789
    33
    // Open file
krista@2789
    34
krista@2789
    35
    FILE *f = Fopen(config_file_path, "r");    
krista@2789
    36
       
krista@2789
    37
    if (f == NULL)
krista@2789
    38
        return false;
krista@2789
    39
krista@2789
    40
    int i;
krista@2789
    41
    stringlist_t* _k;
krista@2789
    42
    stringlist_t* lines = new_stringlist(NULL);
krista@2789
    43
    int found = 0;
krista@2789
    44
krista@2789
    45
    char* s = NULL;
krista@2789
    46
krista@2789
    47
    // Go through every line in the file
krista@2789
    48
    while ((s = Fgets(buf, MAX_LINELENGTH, f))) {
krista@2789
    49
        // pointers to the keys found in this string
krista@2789
    50
        str_ptr_and_bit* found_keys = (str_ptr_and_bit*)(calloc(num_keys, sizeof(str_ptr_and_bit)));
krista@2789
    51
        int num_found_keys = 0;
krista@2789
    52
krista@2789
    53
        char* rest;
krista@2789
    54
        char* line_token = strtok_r(s, "\r\n", &rest);
krista@2789
    55
        if (!line_token)
krista@2789
    56
            line_token = s;
krista@2789
    57
            
krista@2789
    58
        if (*line_token == '#' || *line_token == '\0') {
krista@2789
    59
            stringlist_add(lines, strdup(line_token));
krista@2789
    60
            continue;
krista@2789
    61
        }
krista@2789
    62
krista@2789
    63
        bool only_key_on_line = false;
krista@2789
    64
        for (_k = keys, i = 1; _k; _k = _k->next, i<<=1) {
krista@2789
    65
            char* keypos = strstr(line_token, _k->value);
krista@2789
    66
            if (!keypos)
krista@2789
    67
                continue;
krista@2789
    68
            size_t keystr_len = strlen(_k->value);
krista@2789
    69
            char* nextpos = keypos + keystr_len;
krista@2789
    70
            bool notkey = false;
krista@2789
    71
            
krista@2789
    72
            if (keypos != line_token) {
krista@2789
    73
                char prevchar = *(keypos - 1);
krista@2789
    74
                switch (prevchar) {
krista@2789
    75
                    case '-':
krista@2789
    76
                    case ':':
krista@2789
    77
                    case '/':
krista@2789
    78
                        notkey = true;
krista@2789
    79
                        break;
krista@2789
    80
                    default:
krista@2789
    81
                        break;
krista@2789
    82
                }
krista@2789
    83
            }
krista@2789
    84
krista@2789
    85
            if (*nextpos && !notkey) {
krista@2789
    86
                char nextchar = *nextpos;
krista@2789
    87
                switch (nextchar) {
krista@2789
    88
                    case '-':
krista@2789
    89
                    case ':':
krista@2789
    90
                    case '/':
krista@2789
    91
                        notkey = true;
krista@2789
    92
                        break;
krista@2789
    93
                    default:
krista@2789
    94
                        break;
krista@2789
    95
                }
krista@2789
    96
            }
krista@2789
    97
            else if (line_token == keypos) {
krista@2789
    98
                only_key_on_line = true;
krista@2789
    99
                if (!(found & i)) {
krista@2789
   100
                    found |= i;
krista@2789
   101
                    stringlist_add(lines, strdup(line_token));
krista@2789
   102
                    num_found_keys++;
krista@2789
   103
                }
krista@2789
   104
                break;
krista@2789
   105
            }
krista@2789
   106
krista@2789
   107
            if (!notkey) {
krista@2789
   108
                // Ok, it's not just the key with a null terminator. So...
krista@2789
   109
                // add a pointer to the key to the list from this string
krista@2789
   110
                found_keys[num_found_keys].key = keypos; 	
krista@2789
   111
                found_keys[num_found_keys].bit = i;
krista@2789
   112
                num_found_keys++;
krista@2789
   113
            }
krista@2789
   114
            
krista@2789
   115
            // Check to see if there are more annoying occurences of this 
krista@2789
   116
            // key in the string
krista@2789
   117
            for (keypos = strstr(nextpos, _k->value); 
krista@2789
   118
                keypos; keypos = strstr(nextpos, _k->value)) {
krista@2789
   119
                notkey = false;
krista@2789
   120
                nextpos = keypos + keystr_len;
krista@2789
   121
                char prevchar = *(keypos - 1);
krista@2789
   122
                switch (prevchar) {
krista@2789
   123
                    case '-':
krista@2789
   124
                    case ':':
krista@2789
   125
                    case '/':
krista@2789
   126
                        notkey = true;
krista@2789
   127
                        break;
krista@2789
   128
                    default:
krista@2789
   129
                        break;
krista@2789
   130
                }
krista@2789
   131
                if (!notkey) {
krista@2789
   132
                    char nextchar = *nextpos;
krista@2789
   133
                    switch (nextchar) {
krista@2789
   134
                        case '-':
krista@2789
   135
                        case ':':
krista@2789
   136
                        case '/':
krista@2789
   137
                            notkey = true;
krista@2789
   138
                            break;
krista@2789
   139
                        default:
krista@2789
   140
                            break;
krista@2789
   141
                    }
krista@2789
   142
                }    
krista@2789
   143
                if (notkey)
krista@2789
   144
                    continue;
krista@2795
   145
                    
krista@2795
   146
                if (num_found_keys >= num_keys)
krista@2795
   147
                    found_keys = (str_ptr_and_bit*)realloc(found_keys, (num_found_keys + 1) * sizeof(str_ptr_and_bit));
krista@2795
   148
                    
krista@2789
   149
                found_keys[num_found_keys].key = keypos; 	
krista@2789
   150
                found_keys[num_found_keys].bit = i;
krista@2789
   151
                num_found_keys++;     
krista@2789
   152
            }
krista@2789
   153
        }
krista@2789
   154
        
krista@2789
   155
        if (!only_key_on_line) {
krista@2789
   156
            if (num_found_keys == 0)
krista@2789
   157
                stringlist_add(lines, strdup(line_token));        
krista@2789
   158
            else if (num_found_keys == 1 && (line_token == found_keys[0].key)) {
krista@2789
   159
                if (!(found & found_keys[0].bit)) {
krista@2789
   160
                    stringlist_add(lines, strdup(line_token)); 
krista@2789
   161
                    found |= found_keys[0].bit;
krista@2789
   162
                }
krista@2789
   163
            }
krista@2789
   164
            else {
krista@2789
   165
                qsort(found_keys, num_found_keys, sizeof(str_ptr_and_bit), strptrcmp);
krista@2789
   166
                int j;
krista@2789
   167
                const char* curr_start = line_token;
krista@2789
   168
                const char* next_start = NULL;
krista@2789
   169
                for (j = 0; j < num_found_keys; j++, curr_start = next_start) {
krista@2789
   170
                    next_start = found_keys[j].key;
krista@2789
   171
                    if (curr_start == next_start)
krista@2789
   172
                        continue;
krista@2789
   173
                    size_t copy_len = next_start - curr_start;
krista@2789
   174
                    const char* movable_end = next_start - 1;
krista@2789
   175
                    while (copy_len > 0 && (*movable_end == ' ' || *movable_end == '\t' || *movable_end == '\0')) {
krista@2789
   176
                        movable_end--;
krista@2789
   177
                        copy_len--;
krista@2789
   178
                    }
krista@2789
   179
                    if (copy_len > 0) {
krista@2789
   180
                        if (j == 0 || !(found & found_keys[j - 1].bit)) {
krista@2789
   181
                            // if j is 0 here, the first thing in the string wasn't a key, or we'd have continued.
krista@2789
   182
                            // otherwise, regardless of the value of j, we check that the "last" key (j-1) isn't already
krista@2789
   183
                            // found and dealt with.
krista@2789
   184
                            // Having passed that, we copy.
krista@2789
   185
                            stringlist_add(lines, strndup(curr_start, copy_len));
krista@2789
   186
                            if (j > 0)
krista@2789
   187
                                found |= found_keys[j-1].bit;
krista@2789
   188
                        }
krista@2789
   189
                    }
krista@2789
   190
                }
krista@2789
   191
                if (!(found & found_keys[num_found_keys - 1].bit)) {
krista@2789
   192
                    stringlist_add(lines, strdup(found_keys[num_found_keys - 1].key));
krista@2789
   193
                    found |= found_keys[num_found_keys - 1].bit;
krista@2789
   194
                }            
krista@2789
   195
            }
krista@2789
   196
        }
krista@2789
   197
        free(found_keys);
krista@2789
   198
        found_keys = NULL;
krista@2789
   199
    } // End of file
krista@2789
   200
    // then write all lines to file.
krista@2789
   201
    const char* line_end;
krista@2789
   202
#ifdef WIN32
krista@2789
   203
    line_end = "\r\n";
krista@2789
   204
#else
krista@2789
   205
    line_end = "\n";
krista@2789
   206
#endif    
krista@2789
   207
    size_t cf_path_len = strlen(config_file_path);
krista@2789
   208
    size_t new_buf_size = cf_path_len + 5; // + .old\0
krista@2789
   209
    char* old_config_path_fname = (char*)calloc(new_buf_size, 1);
krista@2789
   210
    if (!old_config_path_fname)
krista@2789
   211
        return false;
krista@2789
   212
    strlcpy(old_config_path_fname, config_file_path, new_buf_size);
krista@2789
   213
    strlcat(old_config_path_fname, ".old", new_buf_size);
krista@2789
   214
    int ret = Fclose(f);
krista@2789
   215
    assert(ret == 0);
krista@2789
   216
    if (ret != 0)
krista@2789
   217
        return false;
krista@2789
   218
    
krista@2789
   219
    ret = rename(config_file_path, old_config_path_fname);
krista@2789
   220
    assert(ret == 0);
krista@2789
   221
    if (ret != 0)
krista@2789
   222
        return false;
krista@2789
   223
krista@2789
   224
    // Ok, now open the thing for writing.
krista@2789
   225
    f = Fopen(config_file_path, "w");
krista@2789
   226
    
krista@2789
   227
    assert(f);
krista@2789
   228
    if (f == NULL)
krista@2789
   229
        return false;
krista@2789
   230
  
krista@2789
   231
    stringlist_t* cur_string;
krista@2789
   232
    
krista@2789
   233
    for (cur_string = lines; cur_string; cur_string = cur_string->next) {
krista@2789
   234
        ret = Fprintf(f, "%s%s", cur_string->value, line_end);
krista@2789
   235
        assert(ret >= 0);
krista@2789
   236
        if (ret < 0)
krista@2789
   237
            return false;
krista@2789
   238
    }
krista@2789
   239
    free_stringlist(lines); // FIXME: memory
krista@2789
   240
    
krista@2789
   241
    ret = Fclose(f);
krista@2789
   242
    assert(ret == 0);
krista@2789
   243
    if (ret != 0)
krista@2789
   244
        return false;
krista@2789
   245
krista@2789
   246
    return true;
krista@2789
   247
}
krista@2789
   248
krista@763
   249
static bool ensure_config_values(stringlist_t *keys, stringlist_t *values, const char* config_file_path)
vb@24
   250
{
vb@24
   251
    static char buf[MAX_LINELENGTH];
vb@78
   252
    int r;
vb@78
   253
    stringlist_t *_k;
vb@78
   254
    stringlist_t *_v;
vb@79
   255
    unsigned int i;
vb@78
   256
    unsigned int found = 0;
krista@2690
   257
    bool eof_nl = 0;
krista@2690
   258
    char * rest;
krista@2690
   259
    char * token;
krista@2690
   260
    char * s;
krista@2690
   261
    const char* line_end;
krista@2690
   262
krista@2690
   263
#ifdef WIN32
krista@2690
   264
    line_end = "\r\n";
krista@2690
   265
#else
krista@2690
   266
    line_end = "\n";
krista@2690
   267
#endif    
vb@62
   268
roker@1559
   269
    FILE *f = Fopen(config_file_path, "r");
vb@63
   270
    if (f == NULL && errno == ENOMEM)
vb@62
   271
        return false;
vb@24
   272
vb@24
   273
    if (f != NULL) {
krista@2789
   274
                
vb@78
   275
        int length = stringlist_length(keys);
vb@78
   276
krista@846
   277
        // make sure we 1) have the same number of keys and values
krista@846
   278
        // and 2) we don't have more key/value pairs than
krista@846
   279
        // the size of the bitfield used to hold the indices
krista@846
   280
        // of key/value pairs matching keys in the config file.
vb@78
   281
        assert(length <= sizeof(unsigned int) * CHAR_BIT);
vb@78
   282
        assert(length == stringlist_length(values));
krista@846
   283
        if (!(length == stringlist_length(values) &&
krista@846
   284
              length <= sizeof(unsigned int) * CHAR_BIT)) {
edouard@1803
   285
            Fclose(f);
krista@1426
   286
krista@846
   287
            return false;
krista@846
   288
        }
krista@1426
   289
krista@2690
   290
        while ((s = Fgets(buf, MAX_LINELENGTH, f))) {
krista@2690
   291
            token = strtok_r(s, " \t\r\n", &rest);
krista@2690
   292
            for (_k = keys, _v = values, i = 1;
krista@2690
   293
                 _k != NULL;
krista@2690
   294
                 _k = _k->next, _v = _v->next, i <<= 1) {
krista@2690
   295
krista@2690
   296
                if (((found & i) != i) && token &&
krista@2690
   297
                    (strncmp(token, _k->value, strlen(_k->value)) == 0)) {
krista@2690
   298
                    found |= i;
krista@2690
   299
                    break;
vb@24
   300
                }
vb@24
   301
            }
krista@2690
   302
            if (feof(f)) {
krista@2690
   303
                eof_nl = 1;
krista@2690
   304
                break;
krista@2690
   305
            }
krista@2690
   306
        }
krista@2690
   307
krista@2690
   308
        if (!s && ferror(f))
krista@2690
   309
            return false;
krista@763
   310
        f = Freopen(config_file_path, "a", f);
vb@24
   311
    }
vb@24
   312
    else {
krista@763
   313
        f = Fopen(config_file_path, "w");
vb@24
   314
    }
vb@24
   315
vb@24
   316
    assert(f);
vb@24
   317
    if (f == NULL)
vb@24
   318
        return false;
krista@2690
   319
    
krista@2690
   320
    if (eof_nl)
krista@2690
   321
        r = Fprintf(f, line_end);
vb@24
   322
vb@78
   323
    for (i = 1, _k = keys, _v = values; _k != NULL; _k = _k->next,
vb@78
   324
            _v = _v->next, i <<= 1) {
vb@78
   325
        if ((found & i) == 0) {
krista@2690
   326
            r = Fprintf(f, "%s %s%s", _k->value, _v->value, line_end);
vb@79
   327
            assert(r >= 0);
krista@2690
   328
            if (r < 0)
edouard@1803
   329
                return false;
vb@78
   330
        }
vb@78
   331
    }
vb@62
   332
vb@63
   333
    r = Fclose(f);
vb@62
   334
    assert(r == 0);
edouard@1803
   335
    if (r != 0)
edouard@1803
   336
        return false;
vb@24
   337
vb@24
   338
    return true;
vb@24
   339
}
vb@24
   340
krista@2057
   341
char* _undot_address(const char* address) {
krista@2057
   342
    if (!address)
krista@2057
   343
        return NULL;
krista@2057
   344
    
krista@2057
   345
    int addr_len = strlen(address);
krista@2057
   346
    const char* at = strstr(address, "@");
krista@2057
   347
    
krista@2057
   348
    if (!at)
krista@2057
   349
        at = address + addr_len;
krista@2057
   350
        
krista@2066
   351
    char* retval = calloc(1, addr_len + 1);
krista@2057
   352
krista@2057
   353
    const char* addr_curr = address;
krista@2057
   354
    char* retval_curr = retval;
krista@2057
   355
    
krista@2057
   356
    while (addr_curr < at) {
krista@2057
   357
        if (*addr_curr == '.') {
krista@2057
   358
            addr_curr++;
krista@2057
   359
            continue;
krista@2057
   360
        }
krista@2057
   361
        *retval_curr = *addr_curr;
krista@2057
   362
        retval_curr++;
krista@2057
   363
        addr_curr++;
krista@2057
   364
    }
krista@2057
   365
    if (*addr_curr == '@')
krista@2057
   366
        strcat(retval_curr, addr_curr);
krista@2057
   367
    
krista@2057
   368
    return retval;
krista@2057
   369
}
krista@2057
   370
krista@2057
   371
static bool _email_heuristic_match(const char* str1, const char* str2) {
krista@2057
   372
    if (!str1 || !str2)
krista@2057
   373
        return false;
krista@2057
   374
        
krista@2057
   375
    if (strcasecmp(str1, str2) == 0)
krista@2057
   376
        return true;
krista@2057
   377
    
krista@2057
   378
    int len1 = strlen(str1);
krista@2057
   379
    int len2 = strlen(str2);
krista@2057
   380
    
krista@2057
   381
    // otherwise, we work against dotted usernames
krista@2057
   382
    const char* at1 = strstr(str1, "@");
krista@2057
   383
    const char* at2 = strstr(str2, "@");
krista@2057
   384
    
krista@2057
   385
    if (!at1)
krista@2057
   386
        at1 = str1 + len1;
krista@2057
   387
    
krista@2057
   388
    if (!at2)
krista@2057
   389
        at2 = str2 + len2;
krista@2057
   390
        
krista@2057
   391
    // This sucks. And is expensive. Here we go.
krista@2057
   392
    const char* str1_curr = str1;
krista@2057
   393
    const char* str2_curr = str2;
krista@2057
   394
    
krista@2057
   395
    while (str1_curr > at1 && str2_curr > at2) {
krista@2057
   396
        if (*str1_curr == '.') {
krista@2057
   397
            str1_curr++;
krista@2057
   398
            continue;
krista@2057
   399
        }
krista@2057
   400
krista@2057
   401
        if (*str2_curr == '.') {
krista@2057
   402
            str2_curr++;
krista@2057
   403
            continue;
krista@2057
   404
        }
krista@2057
   405
        
krista@2057
   406
        if (tolower(*str1_curr) != tolower(*str2_curr))
krista@2057
   407
            return false;
krista@2057
   408
        
krista@2057
   409
        str1_curr++;
krista@2057
   410
        str2_curr++;
krista@2057
   411
    }
krista@2057
   412
    if (str1_curr == at1 && str2_curr == at2)
krista@2057
   413
        return true;
krista@2057
   414
    
krista@2057
   415
    return false;
krista@2057
   416
}
krista@763
   417
krista@2461
   418
static PEP_STATUS _version_test(const char *s)
krista@2461
   419
{
krista@2461
   420
    char *_s = strdup(s);
krista@2461
   421
    if (!_s)
krista@2461
   422
        return PEP_OUT_OF_MEMORY;
krista@2461
   423
krista@2461
   424
    int major;
krista@2461
   425
    int minor;
krista@2461
   426
    int revision;
krista@2461
   427
krista@2461
   428
    char *lasts = NULL;
krista@2461
   429
    char *p = strtok_r(_s, ".", &lasts);
krista@2461
   430
    if (!p)
krista@2461
   431
        goto unsupported;
krista@2461
   432
    else
krista@2461
   433
        major = atoi(p);
krista@2461
   434
krista@2461
   435
    p = strtok_r(NULL, ".", &lasts);
krista@2461
   436
    if (!p)
krista@2461
   437
        goto unsupported;
krista@2461
   438
    else
krista@2461
   439
        minor = atoi(p);
krista@2461
   440
krista@2461
   441
    p = strtok_r(NULL, ".", &lasts);
krista@2461
   442
    if (!p)
krista@2461
   443
        goto unsupported;
krista@2461
   444
    else
krista@2461
   445
        revision = atoi(p);
krista@2461
   446
krista@2461
   447
    free(_s);
krista@2461
   448
    _s = NULL;
krista@2461
   449
krista@2461
   450
    if (major > 2)
krista@2461
   451
        return PEP_STATUS_OK;
krista@2461
   452
krista@2461
   453
    if (major == 2 && minor > 1)
krista@2461
   454
        return PEP_STATUS_OK;
krista@2461
   455
krista@2461
   456
    if (major == 2 && minor == 0 && revision == 30)
krista@2461
   457
        return PEP_STATUS_OK;
krista@2461
   458
krista@2461
   459
    if (major == 2 && minor == 1 && revision >= 17)
krista@2461
   460
        return PEP_STATUS_OK;
krista@2461
   461
krista@2461
   462
unsupported:
krista@2461
   463
    free(_s);
krista@2461
   464
    return PEP_INIT_UNSUPPORTED_GPG_VERSION;
krista@2461
   465
}
krista@2461
   466
vb@62
   467
PEP_STATUS pgp_init(PEP_SESSION session, bool in_first)
vb@24
   468
{
vb@66
   469
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
   470
    gpgme_error_t gpgme_error;
vb@62
   471
    bool bResult;
krista@1426
   472
vb@62
   473
    if (in_first) {
vb@78
   474
        stringlist_t *conf_keys   = new_stringlist("keyserver");
vb@78
   475
        stringlist_t *conf_values = new_stringlist("hkp://keys.gnupg.net");
vb@79
   476
vb@78
   477
        stringlist_add(conf_keys, "cert-digest-algo");
vb@78
   478
        stringlist_add(conf_values, "SHA256");
vb@78
   479
vb@80
   480
        stringlist_add(conf_keys, "no-emit-version");
vb@80
   481
        stringlist_add(conf_values, "");
vb@80
   482
vb@80
   483
        stringlist_add(conf_keys, "no-comments");
vb@80
   484
        stringlist_add(conf_values, "");
vb@80
   485
vb@80
   486
        stringlist_add(conf_keys, "personal-cipher-preferences");
vb@80
   487
        stringlist_add(conf_values, "AES AES256 AES192 CAST5");
vb@80
   488
vb@80
   489
        stringlist_add(conf_keys, "personal-digest-preferences");
vb@312
   490
        stringlist_add(conf_values, "SHA256 SHA512 SHA384 SHA224");
krista@763
   491
krista@1569
   492
        stringlist_add(conf_keys, "ignore-time-conflict");
krista@1569
   493
        stringlist_add(conf_values, "");
krista@1569
   494
krista@2461
   495
        stringlist_add(conf_keys, "allow-freeform-uid");
krista@2461
   496
        stringlist_add(conf_values, "");
krista@2461
   497
krista@2789
   498
krista@2789
   499
        // ENGINE-427 - quick fix here. This will be removed in a few
krista@2789
   500
        // versions, but we need to clean up our mess.
krista@2789
   501
        int compare_result = -1;
krista@2789
   502
        status = compare_cached_engine_version_to_other(session,
krista@2789
   503
                                                        &compare_result, 
krista@2792
   504
                                                        1, 0, 441);            
krista@2789
   505
krista@2789
   506
        bResult = true;
krista@2789
   507
        // status != OK => no cached engine version, i.e. first-time run.
krista@2789
   508
        if (compare_result < 0 && status == PEP_STATUS_OK)
krista@2703
   509
#if defined(WIN32) || defined(NDEBUG)
krista@2789
   510
            bResult = quickfix_config(conf_keys, gpg_conf());
krista@2789
   511
        if (bResult)
krista@2789
   512
            bResult = ensure_config_values(conf_keys, conf_values, gpg_conf());
krista@2703
   513
#else
krista@2789
   514
            bResult = quickfix_config(conf_keys, gpg_conf(false));
krista@2789
   515
        if (bResult)
krista@2789
   516
            bResult = ensure_config_values(conf_keys, conf_values, gpg_conf(false));
krista@2703
   517
#endif
krista@2789
   518
        status = PEP_STATUS_OK;
krista@2789
   519
        
vb@78
   520
        free_stringlist(conf_keys);
vb@78
   521
        free_stringlist(conf_values);
vb@78
   522
Edouard@175
   523
        assert(bResult);
krista@2461
   524
        if (!bResult) {
Edouard@175
   525
            status = PEP_INIT_NO_GPG_HOME;
Edouard@175
   526
            goto pep_error;
Edouard@175
   527
        }
Edouard@175
   528
krista@763
   529
        conf_keys = new_stringlist("default-cache-ttl");
krista@763
   530
        conf_values = new_stringlist("300");
krista@763
   531
krista@763
   532
        stringlist_add(conf_keys, "max-cache-ttl");
krista@763
   533
        stringlist_add(conf_values, "1200");
krista@763
   534
krista@2792
   535
        if (compare_result < 0 && status == PEP_STATUS_OK)
krista@2703
   536
#if defined(WIN32) || defined(NDEBUG)
krista@2792
   537
            bResult = quickfix_config(conf_keys, gpg_agent_conf());
krista@2792
   538
        if (bResult)
krista@2792
   539
            bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf());
krista@2792
   540
 #else        
krista@2792
   541
            bResult = quickfix_config(conf_keys, gpg_agent_conf(false));
krista@2792
   542
        if (bResult)
krista@2792
   543
            bResult = ensure_config_values(conf_keys, conf_values, gpg_agent_conf(false));
krista@2792
   544
 #endif
krista@763
   545
        free_stringlist(conf_keys);
krista@763
   546
        free_stringlist(conf_values);
krista@763
   547
krista@763
   548
        assert(bResult);
krista@2461
   549
        if (!bResult) {
krista@2461
   550
            status = PEP_INIT_CANNOT_CONFIG_GPG_AGENT;
krista@763
   551
            goto pep_error;
krista@763
   552
        }
Edouard@175
   553
vb@62
   554
        gpgme = dlopen(LIBGPGME, RTLD_LAZY);
vb@62
   555
        if (gpgme == NULL) {
krista@2740
   556
            // FIXME: Hotfix here?
vb@66
   557
            status = PEP_INIT_CANNOT_LOAD_GPGME;
vb@66
   558
            goto pep_error;
vb@62
   559
        }
vb@62
   560
vb@62
   561
        memset(&gpg, 0, sizeof(struct gpg_s));
vb@62
   562
krista@2461
   563
        gpg.gpgme_get_engine_info
krista@2461
   564
            = (gpgme_get_engine_info_t) (intptr_t) dlsym(gpgme,
krista@2461
   565
            "gpgme_get_engine_info");
krista@2461
   566
        assert(gpg.gpgme_get_engine_info);
krista@2461
   567
krista@2461
   568
        gpgme_engine_info_t info;
krista@2461
   569
        int err = gpg.gpgme_get_engine_info(&info);
krista@2461
   570
        assert(err == GPG_ERR_NO_ERROR);
krista@2461
   571
        if (err != GPG_ERR_NO_ERROR)
krista@2461
   572
            return PEP_OUT_OF_MEMORY;
krista@2461
   573
krista@2461
   574
        assert(info->version);
krista@2461
   575
        if (!info->version)
krista@2461
   576
            return PEP_INIT_CANNOT_DETERMINE_GPG_VERSION;
krista@2461
   577
krista@2461
   578
        status = _version_test(info->version);
krista@2461
   579
        if (status != PEP_STATUS_OK)
krista@2461
   580
            return status;
krista@2461
   581
vb@62
   582
        gpg.gpgme_set_locale
vb@62
   583
            = (gpgme_set_locale_t) (intptr_t) dlsym(gpgme,
vb@62
   584
            "gpgme_set_locale");
vb@62
   585
        assert(gpg.gpgme_set_locale);
vb@62
   586
vb@62
   587
        gpg.gpgme_check
vb@62
   588
            = (gpgme_check_version_t) (intptr_t) dlsym(gpgme,
vb@62
   589
            "gpgme_check_version");
vb@62
   590
        assert(gpg.gpgme_check);
vb@62
   591
vb@62
   592
        gpg.gpgme_new
vb@62
   593
            = (gpgme_new_t) (intptr_t) dlsym(gpgme, "gpgme_new");
vb@62
   594
        assert(gpg.gpgme_new);
vb@62
   595
vb@62
   596
        gpg.gpgme_release
vb@62
   597
            = (gpgme_release_t) (intptr_t) dlsym(gpgme, "gpgme_release");
vb@62
   598
        assert(gpg.gpgme_release);
vb@62
   599
vb@62
   600
        gpg.gpgme_set_protocol
vb@62
   601
            = (gpgme_set_protocol_t) (intptr_t) dlsym(gpgme,
vb@62
   602
            "gpgme_set_protocol");
vb@62
   603
        assert(gpg.gpgme_set_protocol);
vb@62
   604
vb@62
   605
        gpg.gpgme_set_armor
vb@62
   606
            = (gpgme_set_armor_t) (intptr_t) dlsym(gpgme,
vb@62
   607
            "gpgme_set_armor");
vb@62
   608
        assert(gpg.gpgme_set_armor);
vb@62
   609
vb@62
   610
        gpg.gpgme_data_new
vb@62
   611
            = (gpgme_data_new_t) (intptr_t) dlsym(gpgme,
vb@62
   612
            "gpgme_data_new");
vb@62
   613
        assert(gpg.gpgme_data_new);
vb@62
   614
vb@62
   615
        gpg.gpgme_data_new_from_mem
vb@62
   616
            = (gpgme_data_new_from_mem_t) (intptr_t) dlsym(gpgme,
vb@62
   617
            "gpgme_data_new_from_mem");
vb@62
   618
        assert(gpg.gpgme_data_new_from_mem);
vb@62
   619
vb@221
   620
        gpg.gpgme_data_new_from_cbs
vb@221
   621
            = (gpgme_data_new_from_cbs_t) (intptr_t) dlsym(gpgme,
vb@221
   622
            "gpgme_data_new_from_cbs");
vb@221
   623
        assert(gpg.gpgme_data_new_from_cbs);
vb@221
   624
vb@62
   625
        gpg.gpgme_data_release
vb@62
   626
            = (gpgme_data_release_t) (intptr_t) dlsym(gpgme,
vb@62
   627
            "gpgme_data_release");
vb@62
   628
        assert(gpg.gpgme_data_release);
vb@62
   629
vb@62
   630
        gpg.gpgme_data_identify
vb@62
   631
            = (gpgme_data_identify_t) (intptr_t) dlsym(gpgme,
vb@62
   632
            "gpgme_data_identify");
vb@62
   633
        assert(gpg.gpgme_data_identify);
vb@62
   634
vb@62
   635
        gpg.gpgme_data_seek
vb@62
   636
            = (gpgme_data_seek_t) (intptr_t) dlsym(gpgme,
vb@62
   637
            "gpgme_data_seek");
vb@62
   638
        assert(gpg.gpgme_data_seek);
vb@62
   639
vb@62
   640
        gpg.gpgme_data_read
vb@62
   641
            = (gpgme_data_read_t) (intptr_t) dlsym(gpgme,
vb@62
   642
            "gpgme_data_read");
vb@62
   643
        assert(gpg.gpgme_data_read);
vb@62
   644
vb@62
   645
        gpg.gpgme_op_decrypt
vb@62
   646
            = (gpgme_op_decrypt_t) (intptr_t) dlsym(gpgme,
vb@62
   647
            "gpgme_op_decrypt");
vb@62
   648
        assert(gpg.gpgme_op_decrypt);
vb@62
   649
vb@62
   650
        gpg.gpgme_op_verify
vb@62
   651
            = (gpgme_op_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   652
            "gpgme_op_verify");
vb@62
   653
        assert(gpg.gpgme_op_verify);
vb@62
   654
vb@62
   655
        gpg.gpgme_op_decrypt_verify
vb@62
   656
            = (gpgme_op_decrypt_verify_t) (intptr_t) dlsym(gpgme,
vb@62
   657
            "gpgme_op_decrypt_verify");
vb@62
   658
        assert(gpg.gpgme_op_decrypt_verify);
vb@24
   659
vb@62
   660
        gpg.gpgme_op_decrypt_result
vb@62
   661
            = (gpgme_op_decrypt_result_t) (intptr_t) dlsym(gpgme,
vb@62
   662
            "gpgme_op_decrypt_result");
vb@62
   663
        assert(gpg.gpgme_op_decrypt_result);
vb@62
   664
vb@62
   665
        gpg.gpgme_op_encrypt_sign
vb@62
   666
            = (gpgme_op_encrypt_sign_t) (intptr_t) dlsym(gpgme,
vb@62
   667
            "gpgme_op_encrypt_sign");
vb@62
   668
        assert(gpg.gpgme_op_encrypt_sign);
vb@62
   669
krista@1639
   670
        gpg.gpgme_op_encrypt
krista@1639
   671
            = (gpgme_op_encrypt_t) (intptr_t) dlsym(gpgme,
krista@1639
   672
            "gpgme_op_encrypt");
krista@1639
   673
        assert(gpg.gpgme_op_encrypt);
krista@1639
   674
vb@62
   675
        gpg.gpgme_op_verify_result
vb@62
   676
            = (gpgme_op_verify_result_t) (intptr_t) dlsym(gpgme,
vb@62
   677
            "gpgme_op_verify_result");
vb@62
   678
        assert(gpg.gpgme_op_verify_result);
vb@62
   679
vb@62
   680
        gpg.gpgme_signers_clear
vb@62
   681
            = (gpgme_signers_clear_t) (intptr_t) dlsym(gpgme,
vb@62
   682
            "gpgme_signers_clear");
vb@62
   683
        assert(gpg.gpgme_signers_clear);
vb@62
   684
vb@62
   685
        gpg.gpgme_signers_add
vb@62
   686
            = (gpgme_signers_add_t) (intptr_t) dlsym(gpgme,
vb@62
   687
            "gpgme_signers_add");
vb@62
   688
        assert(gpg.gpgme_signers_add);
vb@62
   689
kgrothoff@1926
   690
        gpg.gpgme_set_passphrase_cb
kgrothoff@1926
   691
            = (gpgme_set_passphrase_cb_t) (intptr_t) dlsym(gpgme,
kgrothoff@1926
   692
            "gpgme_set_passphrase_cb");
kgrothoff@1926
   693
        assert(gpg.gpgme_set_passphrase_cb);
kgrothoff@1926
   694
vb@62
   695
        gpg.gpgme_get_key
vb@62
   696
            = (gpgme_get_key_t) (intptr_t) dlsym(gpgme, "gpgme_get_key");
vb@62
   697
        assert(gpg.gpgme_get_key);
krista@1920
   698
        
roker@2055
   699
        #ifdef GPGME_VERSION_NUMBER
krista@1921
   700
        #if (GPGME_VERSION_NUMBER >= 0x010700)
krista@1921
   701
                gpg.gpgme_op_createkey
krista@1921
   702
                    = (gpgme_op_createkey_t) (intptr_t) dlsym(gpgme,
krista@1921
   703
                    "gpgme_op_createkey");
krista@1921
   704
                assert(gpg.gpgme_op_createkey);
krista@1925
   705
                
krista@1925
   706
                gpg.gpgme_op_createsubkey
krista@1925
   707
                    = (gpgme_op_createsubkey_t) (intptr_t) dlsym(gpgme,
krista@1925
   708
                    "gpgme_op_createsubkey");
krista@1925
   709
                assert(gpg.gpgme_op_createsubkey);
krista@1925
   710
krista@1921
   711
        #endif
krista@1921
   712
        #endif
krista@1921
   713
        
vb@62
   714
        gpg.gpgme_op_genkey
vb@62
   715
            = (gpgme_op_genkey_t) (intptr_t) dlsym(gpgme,
vb@62
   716
            "gpgme_op_genkey");
vb@62
   717
        assert(gpg.gpgme_op_genkey);
vb@62
   718
vb@62
   719
        gpg.gpgme_op_genkey_result
vb@62
   720
            = (gpgme_op_genkey_result_t) (intptr_t) dlsym(gpgme,
vb@62
   721
            "gpgme_op_genkey_result");
vb@62
   722
        assert(gpg.gpgme_op_genkey_result);
vb@62
   723
vb@62
   724
        gpg.gpgme_op_delete = (gpgme_op_delete_t) (intptr_t)
vb@62
   725
            dlsym(gpgme, "gpgme_op_delete");
vb@62
   726
        assert(gpg.gpgme_op_delete);
vb@62
   727
vb@62
   728
        gpg.gpgme_op_import = (gpgme_op_import_t) (intptr_t)
vb@62
   729
            dlsym(gpgme, "gpgme_op_import");
vb@62
   730
        assert(gpg.gpgme_op_import);
vb@62
   731
Edouard@728
   732
        gpg.gpgme_op_import_result
Edouard@728
   733
            = (gpgme_op_import_result_t) (intptr_t) dlsym(gpgme,
Edouard@728
   734
            "gpgme_op_import_result");
Edouard@728
   735
        assert(gpg.gpgme_op_import_result);
Edouard@728
   736
vb@62
   737
        gpg.gpgme_op_export = (gpgme_op_export_t) (intptr_t)
vb@62
   738
            dlsym(gpgme, "gpgme_op_export");
vb@62
   739
        assert(gpg.gpgme_op_export);
vb@62
   740
vb@62
   741
        gpg.gpgme_set_keylist_mode = (gpgme_set_keylist_mode_t) (intptr_t)
vb@62
   742
            dlsym(gpgme, "gpgme_set_keylist_mode");
vb@62
   743
        assert(gpg.gpgme_set_keylist_mode);
vb@62
   744
vb@62
   745
        gpg.gpgme_get_keylist_mode = (gpgme_get_keylist_mode_t) (intptr_t)
vb@62
   746
            dlsym(gpgme, "gpgme_get_keylist_mode");
vb@62
   747
        assert(gpg.gpgme_get_keylist_mode);
vb@62
   748
vb@62
   749
        gpg.gpgme_op_keylist_start = (gpgme_op_keylist_start_t) (intptr_t)
vb@62
   750
            dlsym(gpgme, "gpgme_op_keylist_start");
vb@62
   751
        assert(gpg.gpgme_op_keylist_start);
vb@62
   752
vb@62
   753
        gpg.gpgme_op_keylist_next = (gpgme_op_keylist_next_t) (intptr_t)
vb@62
   754
            dlsym(gpgme, "gpgme_op_keylist_next");
vb@62
   755
        assert(gpg.gpgme_op_keylist_next);
vb@62
   756
vb@62
   757
        gpg.gpgme_op_keylist_end = (gpgme_op_keylist_end_t) (intptr_t)
vb@62
   758
            dlsym(gpgme, "gpgme_op_keylist_end");
vb@62
   759
        assert(gpg.gpgme_op_keylist_end);
vb@62
   760
vb@62
   761
        gpg.gpgme_op_import_keys = (gpgme_op_import_keys_t) (intptr_t)
vb@62
   762
            dlsym(gpgme, "gpgme_op_import_keys");
vb@62
   763
        assert(gpg.gpgme_op_import_keys);
vb@62
   764
vb@62
   765
        gpg.gpgme_key_ref = (gpgme_key_ref_t) (intptr_t)
vb@62
   766
            dlsym(gpgme, "gpgme_key_ref");
vb@62
   767
        assert(gpg.gpgme_key_ref);
vb@62
   768
vb@62
   769
        gpg.gpgme_key_unref = (gpgme_key_unref_t) (intptr_t)
vb@62
   770
            dlsym(gpgme, "gpgme_key_unref");
vb@62
   771
        assert(gpg.gpgme_key_unref);
vb@62
   772
vb@1387
   773
		gpg.gpgme_key_release = (gpgme_key_release_t)(intptr_t)
vb@1387
   774
			dlsym(gpgme, "gpgme_key_release");
vb@1387
   775
		assert(gpg.gpgme_key_release);
vb@1387
   776
vb@221
   777
        gpg.gpgme_op_edit = (gpgme_op_edit_t) (intptr_t)
vb@221
   778
            dlsym(gpgme, "gpgme_op_edit");
vb@221
   779
        assert(gpg.gpgme_op_edit);
vb@221
   780
vb@223
   781
        gpg.gpgme_io_write = (gpgme_io_write_t) (intptr_t)
vb@223
   782
            dlsym(gpgme, "gpgme_io_write");
vb@223
   783
        assert(gpg.gpgme_io_write);
vb@223
   784
vb@62
   785
        gpg.version = gpg.gpgme_check(NULL);
krista@1426
   786
roker@879
   787
        const char * const cLocal = setlocale(LC_ALL, NULL);
Edouard@348
   788
        if (!cLocal || (strcmp(cLocal, "C") == 0))
vb@62
   789
            setlocale(LC_ALL, "");
vb@62
   790
vb@62
   791
        gpg.gpgme_set_locale(NULL, LC_CTYPE, setlocale(LC_CTYPE, NULL));
vb@62
   792
#ifdef LC_MESSAGES // Windoze
vb@62
   793
        gpg.gpgme_set_locale (NULL, LC_MESSAGES, setlocale(LC_MESSAGES, NULL));
vb@62
   794
#endif
vb@24
   795
    }
vb@24
   796
krista@1426
   797
    gpg.gpgme_check(NULL);
vb@62
   798
    gpgme_error = gpg.gpgme_new(&session->ctx);
vb@45
   799
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   800
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@66
   801
        status = PEP_INIT_GPGME_INIT_FAILED;
vb@66
   802
        goto pep_error;
vb@24
   803
    }
vb@46
   804
    assert(session->ctx);
vb@24
   805
vb@62
   806
    gpgme_error = gpg.gpgme_set_protocol(session->ctx, GPGME_PROTOCOL_OpenPGP);
vb@45
   807
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   808
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   809
vb@62
   810
    gpg.gpgme_set_armor(session->ctx, 1);
vb@24
   811
vb@24
   812
    return PEP_STATUS_OK;
vb@66
   813
vb@66
   814
pep_error:
vb@66
   815
    pgp_release(session, in_first);
vb@66
   816
    return status;
vb@24
   817
}
vb@24
   818
vb@62
   819
void pgp_release(PEP_SESSION session, bool out_last)
vb@24
   820
{
vb@62
   821
    if (session->ctx) {
vb@74
   822
        gpg.gpgme_release(session->ctx);
vb@62
   823
        session->ctx = NULL;
vb@62
   824
    }
vb@62
   825
vb@74
   826
    if (out_last)
vb@74
   827
        if (gpgme)
vb@74
   828
            dlclose(gpgme);
vb@24
   829
}
vb@24
   830
vb@24
   831
PEP_STATUS pgp_decrypt_and_verify(
vb@24
   832
    PEP_SESSION session, const char *ctext, size_t csize,
krista@1397
   833
    const char *dsigtext, size_t dsigsize,
vb@24
   834
    char **ptext, size_t *psize, stringlist_t **keylist
vb@24
   835
    )
vb@24
   836
{
vb@24
   837
    PEP_STATUS result;
vb@24
   838
    gpgme_error_t gpgme_error;
vb@24
   839
    gpgme_data_t cipher, plain;
vb@24
   840
    gpgme_data_type_t dt;
krista@1579
   841
    gpgme_decrypt_result_t gpgme_decrypt_result = NULL;
vb@24
   842
vb@24
   843
    stringlist_t *_keylist = NULL;
roker@723
   844
    //int i_key = 0;
vb@24
   845
vb@46
   846
    assert(session);
vb@24
   847
    assert(ctext);
vb@24
   848
    assert(csize);
vb@24
   849
    assert(ptext);
vb@24
   850
    assert(psize);
vb@24
   851
    assert(keylist);
vb@24
   852
vb@24
   853
    *ptext = NULL;
vb@24
   854
    *psize = 0;
vb@24
   855
    *keylist = NULL;
vb@24
   856
vb@74
   857
    gpgme_error = gpg.gpgme_data_new_from_mem(&cipher, ctext, csize, 0);
vb@45
   858
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   859
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   860
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
   861
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   862
            return PEP_OUT_OF_MEMORY;
vb@24
   863
        else
vb@24
   864
            return PEP_UNKNOWN_ERROR;
vb@24
   865
    }
vb@24
   866
vb@74
   867
    gpgme_error = gpg.gpgme_data_new(&plain);
vb@45
   868
    gpgme_error = _GPGERR(gpgme_error);
vb@24
   869
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
   870
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
   871
        gpg.gpgme_data_release(cipher);
vb@24
   872
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
   873
            return PEP_OUT_OF_MEMORY;
vb@24
   874
        else
vb@24
   875
            return PEP_UNKNOWN_ERROR;
vb@24
   876
    }
vb@24
   877
krista@1579
   878
vb@74
   879
    dt = gpg.gpgme_data_identify(cipher);
vb@24
   880
    switch (dt) {
edouard@1421
   881
#if GPGME_VERSION_NUMBER > 0x010600
vb@1419
   882
    case GPGME_DATA_TYPE_PGP_ENCRYPTED:
edouard@1420
   883
#endif
vb@24
   884
    case GPGME_DATA_TYPE_PGP_SIGNED:
vb@24
   885
    case GPGME_DATA_TYPE_PGP_OTHER:
krista@1426
   886
        if (dsigtext) {
krista@1426
   887
            gpgme_error = gpg.gpgme_op_decrypt(session->ctx, cipher, plain);
krista@1426
   888
        }
krista@1426
   889
        else {
krista@1426
   890
            gpgme_error = gpg.gpgme_op_decrypt_verify(session->ctx, cipher,
krista@1426
   891
                plain);
krista@1426
   892
        }
vb@45
   893
        gpgme_error = _GPGERR(gpgme_error);
vb@24
   894
        assert(gpgme_error != GPG_ERR_INV_VALUE);
krista@2681
   895
//        assert(gpgme_error != GPG_ERR_NO_DATA);
vb@24
   896
vb@24
   897
        switch (gpgme_error) {
vb@344
   898
            case GPG_ERR_NO_ERROR:
vb@344
   899
            {
krista@2681
   900
                // EFail: We should get an MDC warning if there were modifications
krista@2681
   901
                //        and never make it here. So the decrypted text is not
krista@2681
   902
                //        returned regardless.
krista@1579
   903
                gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
krista@1591
   904
                /* NOW is when we have to process the decrypt_result, period.
krista@1591
   905
                   it is only valid until the next call on the context. */
krista@1591
   906
                   
krista@1591
   907
                gpgme_key_t key;
krista@1591
   908
                memset(&key,0,sizeof(key));
krista@1591
   909
                stringlist_t* recipient_keylist = new_stringlist(NULL);
krista@1592
   910
                if (!recipient_keylist) {
krista@1592
   911
                    gpg.gpgme_data_release(plain);
krista@1592
   912
                    gpg.gpgme_data_release(cipher);
krista@1592
   913
                    if (recipient_keylist)
krista@1592
   914
                        free_stringlist(recipient_keylist);
krista@1591
   915
                    return PEP_OUT_OF_MEMORY;
krista@1592
   916
                }
krista@1591
   917
               
krista@1591
   918
                if (gpgme_decrypt_result != NULL) {
krista@1591
   919
                    stringlist_t* _keylist = recipient_keylist;
krista@1591
   920
                    for (gpgme_recipient_t r = gpgme_decrypt_result->recipients; r != NULL; r = r->next) {
krista@1591
   921
                        // GPGME may give subkey's fpr instead of primary key's fpr.
krista@1591
   922
                        // Therefore we ask for the primary fingerprint instead
krista@1591
   923
                        // we assume that gpgme_get_key can find key by subkey's fpr
krista@1591
   924
                        gpgme_error = gpg.gpgme_get_key(session->ctx,
krista@1591
   925
                            r->keyid, &key, 0);
krista@1591
   926
                        gpgme_error = _GPGERR(gpgme_error);
krista@1591
   927
                        assert(gpgme_error != GPG_ERR_ENOMEM);
krista@1591
   928
                        if (gpgme_error == GPG_ERR_ENOMEM) {
krista@1591
   929
                            free_stringlist(_keylist);
krista@1591
   930
                            result = PEP_OUT_OF_MEMORY;
krista@1591
   931
                        }
krista@1591
   932
                        // Primary key is given as the first subkey
krista@1591
   933
                        if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1591
   934
                            key && key->subkeys && key->subkeys->fpr
krista@1591
   935
                            && key->subkeys->fpr[0]) {
krista@1591
   936
                            _keylist = stringlist_add(_keylist, key->subkeys->fpr);
krista@1591
   937
 
krista@1591
   938
                            gpg.gpgme_key_unref(key);
krista@1591
   939
 
krista@1591
   940
                        }
krista@1591
   941
                    }
krista@1591
   942
                    assert(_keylist);
krista@1591
   943
                    if (_keylist == NULL) {
krista@1591
   944
                        free_stringlist(recipient_keylist);
krista@1591
   945
                        if (*keylist)
krista@1591
   946
                            free_stringlist(*keylist);
krista@1591
   947
                        *keylist = NULL;
krista@1591
   948
                        result = PEP_OUT_OF_MEMORY;
krista@1591
   949
                    }
krista@1591
   950
                } /* Ok, so now we have any recipients it was encrypted for
krista@1591
   951
                     in recipient_keylist */
krista@1591
   952
            
krista@1591
   953
                   
vb@344
   954
                gpgme_verify_result_t gpgme_verify_result;
vb@344
   955
                char *_buffer = NULL;
vb@344
   956
                size_t reading;
vb@344
   957
                size_t length = gpg.gpgme_data_seek(plain, 0, SEEK_END);
vb@344
   958
                gpgme_signature_t gpgme_signature;
vb@24
   959
vb@344
   960
                assert(length != -1);
vb@344
   961
                gpg.gpgme_data_seek(plain, 0, SEEK_SET);
vb@24
   962
vb@344
   963
                // TODO: make things less memory consuming
vb@344
   964
                // the following algorithm allocates memory for the complete
vb@344
   965
                // text
vb@24
   966
vb@344
   967
                _buffer = malloc(length + 1);
vb@344
   968
                assert(_buffer);
vb@344
   969
                if (_buffer == NULL) {
vb@74
   970
                    gpg.gpgme_data_release(plain);
vb@74
   971
                    gpg.gpgme_data_release(cipher);
krista@1591
   972
                    if (recipient_keylist)
krista@1591
   973
                        free_stringlist(recipient_keylist);
vb@24
   974
                    return PEP_OUT_OF_MEMORY;
vb@24
   975
                }
vb@24
   976
vb@344
   977
                reading = gpg.gpgme_data_read(plain, _buffer, length);
vb@344
   978
                assert(length == reading);
vb@24
   979
krista@1427
   980
                if (dsigtext) {  // Is this safe to do?
krista@1427
   981
                    gpgme_data_t sigdata;
krista@1427
   982
                    gpg.gpgme_data_new_from_mem(&sigdata, dsigtext,
krista@1427
   983
                                                dsigsize, 0);
vb@1434
   984
                    gpg.gpgme_op_verify(session->ctx, sigdata, plain, NULL);
krista@1431
   985
                    gpg.gpgme_data_release(sigdata);
krista@1427
   986
                }
krista@1426
   987
vb@344
   988
                gpgme_verify_result =
vb@344
   989
                    gpg.gpgme_op_verify_result(session->ctx);
vb@344
   990
                assert(gpgme_verify_result);
vb@344
   991
                gpgme_signature = gpgme_verify_result->signatures;
krista@1426
   992
krista@1584
   993
                if (!gpgme_signature) {
krista@1584
   994
                    // try cleartext sig verification
krista@1584
   995
                    gpg.gpgme_op_verify(session->ctx, plain, NULL, plain);
krista@1584
   996
                    gpgme_verify_result =
krista@1584
   997
                        gpg.gpgme_op_verify_result(session->ctx);
krista@1584
   998
                            assert(gpgme_verify_result);
roker@2055
   999
                    gpgme_signature = gpgme_verify_result->signatures;
krista@1584
  1000
                }
krista@1584
  1001
vb@344
  1002
                if (gpgme_signature) {
vb@344
  1003
                    stringlist_t *k;
vb@344
  1004
                    _keylist = new_stringlist(NULL);
vb@24
  1005
                    assert(_keylist);
vb@24
  1006
                    if (_keylist == NULL) {
vb@344
  1007
                        gpg.gpgme_data_release(plain);
vb@344
  1008
                        gpg.gpgme_data_release(cipher);
vb@344
  1009
                        free(_buffer);
vb@344
  1010
                        return PEP_OUT_OF_MEMORY;
vb@344
  1011
                    }
vb@344
  1012
                    k = _keylist;
vb@344
  1013
vb@344
  1014
                    result = PEP_DECRYPTED_AND_VERIFIED;
krista@1427
  1015
                    gpg.gpgme_check(NULL);
krista@1591
  1016
                    do { /* get all signers and put them at the front off
krista@1591
  1017
                            the keylist (likely only one) */
vb@344
  1018
                        switch (_GPGERR(gpgme_signature->status)) {
vb@344
  1019
                        case GPG_ERR_NO_ERROR:
Edouard@505
  1020
                        {
krista@1426
  1021
                            // Some versions of gpg returns signer's
Edouard@674
  1022
                            // signing subkey fingerprint instead of
Edouard@674
  1023
                            // signer's primary key fingerprint.
krista@1426
  1024
                            // This is meant to get signer's primary
Edouard@674
  1025
                            // key fingerprint, using subkey's.
Edouard@674
  1026
Edouard@728
  1027
                            gpgme_key_t key = NULL;
Edouard@505
  1028
Edouard@505
  1029
                            gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@505
  1030
                                gpgme_signature->fpr, &key, 0);
Edouard@505
  1031
                            gpgme_error = _GPGERR(gpgme_error);
Edouard@505
  1032
                            assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@505
  1033
                            if (gpgme_error == GPG_ERR_ENOMEM) {
Edouard@505
  1034
                                free_stringlist(_keylist);
Edouard@505
  1035
                                gpg.gpgme_data_release(plain);
Edouard@505
  1036
                                gpg.gpgme_data_release(cipher);
Edouard@505
  1037
                                free(_buffer);
Edouard@505
  1038
                                return PEP_OUT_OF_MEMORY;
Edouard@505
  1039
                            }
Edouard@505
  1040
                            // Primary key is given as the first subkey
krista@1426
  1041
                            if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
  1042
                                key && key->subkeys && key->subkeys->fpr
Edouard@674
  1043
                                && key->subkeys->fpr[0])
Edouard@674
  1044
                            {
Edouard@505
  1045
                                k = stringlist_add(k, key->subkeys->fpr);
Edouard@677
  1046
Edouard@674
  1047
                                gpg.gpgme_key_unref(key);
Edouard@677
  1048
Edouard@677
  1049
                                if (k == NULL) {
Edouard@677
  1050
                                    free_stringlist(_keylist);
krista@1591
  1051
                                    if (recipient_keylist)
krista@1591
  1052
                                        free (recipient_keylist);
Edouard@677
  1053
                                    gpg.gpgme_data_release(plain);
Edouard@677
  1054
                                    gpg.gpgme_data_release(cipher);
Edouard@677
  1055
                                    free(_buffer);
Edouard@677
  1056
                                    return PEP_OUT_OF_MEMORY;
Edouard@677
  1057
                                }
Edouard@674
  1058
                            }
krista@1426
  1059
                            else
Edouard@674
  1060
                            {
Edouard@505
  1061
                                result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@505
  1062
                                break;
Edouard@505
  1063
                            }
vb@344
  1064
                            break;
Edouard@505
  1065
                        }
vb@344
  1066
                        case GPG_ERR_CERT_REVOKED:
vb@344
  1067
                        case GPG_ERR_BAD_SIGNATURE:
krista@2703
  1068
			    result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
krista@2703
  1069
                            //result = PEP_DECRYPT_BAD_SIGNATURE;
vb@344
  1070
                            break;
vb@344
  1071
                        case GPG_ERR_SIG_EXPIRED:
vb@344
  1072
                        case GPG_ERR_KEY_EXPIRED:
vb@344
  1073
                        case GPG_ERR_NO_PUBKEY:
vb@344
  1074
                            k = stringlist_add(k, gpgme_signature->fpr);
Edouard@674
  1075
                            if (k == NULL) {
Edouard@674
  1076
                                free_stringlist(_keylist);
krista@1591
  1077
                                if (recipient_keylist)
krista@1591
  1078
                                    free_stringlist(recipient_keylist);
Edouard@674
  1079
                                gpg.gpgme_data_release(plain);
Edouard@674
  1080
                                gpg.gpgme_data_release(cipher);
Edouard@674
  1081
                                free(_buffer);
Edouard@674
  1082
                                return PEP_OUT_OF_MEMORY;
Edouard@674
  1083
                            }
vb@344
  1084
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@344
  1085
                                result = PEP_DECRYPTED;
vb@344
  1086
                            break;
vb@344
  1087
                        case GPG_ERR_GENERAL:
vb@344
  1088
                            break;
vb@344
  1089
                        default:
vb@344
  1090
                            if (result == PEP_DECRYPTED_AND_VERIFIED)
vb@344
  1091
                                result = PEP_DECRYPTED;
vb@344
  1092
                            break;
vb@344
  1093
                        }
vb@344
  1094
                    } while ((gpgme_signature = gpgme_signature->next));
vb@344
  1095
                }
vb@344
  1096
                else {
vb@344
  1097
                    result = PEP_DECRYPTED;
vb@344
  1098
                }
vb@344
  1099
vb@344
  1100
                if (result == PEP_DECRYPTED_AND_VERIFIED
vb@344
  1101
                    || result == PEP_DECRYPTED) {
vb@344
  1102
                    *ptext = _buffer;
vb@344
  1103
                    *psize = reading;
vb@344
  1104
                    (*ptext)[*psize] = 0; // safeguard for naive users
vb@344
  1105
                    *keylist = _keylist;
edouard@1933
  1106
                    if (recipient_keylist) {
krista@1591
  1107
                        if (!_keylist)
roker@2055
  1108
                            *keylist = new_stringlist(""); // no sig
krista@1591
  1109
                        if (!(*keylist)) {
krista@1591
  1110
                            free_stringlist(_keylist);
krista@1591
  1111
                            if (recipient_keylist)
krista@1591
  1112
                                free_stringlist(recipient_keylist);
krista@1591
  1113
                            gpg.gpgme_data_release(plain);
krista@1591
  1114
                            gpg.gpgme_data_release(cipher);
krista@1591
  1115
                            free(_buffer);
krista@1591
  1116
                            return PEP_OUT_OF_MEMORY;
roker@2055
  1117
                        }
krista@1591
  1118
                        stringlist_append(*keylist, recipient_keylist);
edouard@1933
  1119
                    }
vb@344
  1120
                }
vb@344
  1121
                else {
vb@344
  1122
                    free_stringlist(_keylist);
krista@1591
  1123
                    if (recipient_keylist)
krista@1591
  1124
                        free_stringlist(recipient_keylist);
vb@344
  1125
                    free(_buffer);
vb@344
  1126
                }
vb@344
  1127
                break;
vb@344
  1128
            }
vb@344
  1129
            case GPG_ERR_BAD_PASSPHRASE:
krista@2681
  1130
            case GPG_ERR_NO_DATA:
Edouard@725
  1131
                result = PEP_DECRYPT_NO_KEY;
Edouard@725
  1132
                break;
vb@344
  1133
            case GPG_ERR_DECRYPT_FAILED:
vb@344
  1134
            default:
vb@344
  1135
            {
krista@1579
  1136
                gpgme_decrypt_result = gpg.gpgme_op_decrypt_result(session->ctx);
vb@344
  1137
                result = PEP_DECRYPT_NO_KEY;
vb@344
  1138
vb@344
  1139
                if (gpgme_decrypt_result != NULL) {
vb@344
  1140
                    if (gpgme_decrypt_result->unsupported_algorithm)
vb@344
  1141
                        *keylist = new_stringlist(gpgme_decrypt_result->unsupported_algorithm);
vb@344
  1142
                    else
vb@344
  1143
                        *keylist = new_stringlist("");
vb@344
  1144
                    assert(*keylist);
vb@344
  1145
                    if (*keylist == NULL) {
vb@24
  1146
                        result = PEP_OUT_OF_MEMORY;
vb@24
  1147
                        break;
vb@24
  1148
                    }
vb@24
  1149
                }
vb@24
  1150
            }
vb@24
  1151
        }
vb@24
  1152
        break;
vb@24
  1153
vb@24
  1154
    default:
vb@24
  1155
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
  1156
    }
vb@24
  1157
vb@74
  1158
    gpg.gpgme_data_release(plain);
vb@74
  1159
    gpg.gpgme_data_release(cipher);
vb@24
  1160
    return result;
vb@24
  1161
}
vb@24
  1162
vb@24
  1163
PEP_STATUS pgp_verify_text(
vb@24
  1164
    PEP_SESSION session, const char *text, size_t size,
vb@24
  1165
    const char *signature, size_t sig_size, stringlist_t **keylist
vb@24
  1166
    )
vb@24
  1167
{
vb@24
  1168
    PEP_STATUS result;
vb@24
  1169
    gpgme_error_t gpgme_error;
vb@24
  1170
    gpgme_data_t d_text, d_sig;
vb@24
  1171
    stringlist_t *_keylist;
vb@24
  1172
vb@24
  1173
    assert(session);
vb@24
  1174
    assert(text);
vb@24
  1175
    assert(size);
vb@24
  1176
    assert(signature);
vb@24
  1177
    assert(sig_size);
vb@24
  1178
    assert(keylist);
vb@24
  1179
vb@24
  1180
    *keylist = NULL;
vb@24
  1181
vb@74
  1182
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_text, text, size, 0);
vb@45
  1183
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1184
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1185
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
  1186
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
  1187
            return PEP_OUT_OF_MEMORY;
vb@24
  1188
        else
vb@24
  1189
            return PEP_UNKNOWN_ERROR;
vb@24
  1190
    }
vb@24
  1191
vb@74
  1192
    gpgme_error = gpg.gpgme_data_new_from_mem(&d_sig, signature, sig_size, 0);
vb@45
  1193
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1194
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1195
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
  1196
        gpg.gpgme_data_release(d_text);
vb@24
  1197
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
  1198
            return PEP_OUT_OF_MEMORY;
vb@24
  1199
        else
vb@24
  1200
            return PEP_UNKNOWN_ERROR;
vb@24
  1201
    }
vb@24
  1202
vb@74
  1203
    gpgme_error = gpg.gpgme_op_verify(session->ctx, d_sig, d_text, NULL);
vb@45
  1204
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1205
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  1206
vb@24
  1207
    switch (gpgme_error) {
vb@24
  1208
    case GPG_ERR_NO_ERROR:
vb@24
  1209
    {
vb@24
  1210
        gpgme_verify_result_t gpgme_verify_result;
vb@24
  1211
        gpgme_signature_t gpgme_signature;
vb@24
  1212
vb@24
  1213
        gpgme_verify_result =
vb@74
  1214
            gpg.gpgme_op_verify_result(session->ctx);
vb@24
  1215
        assert(gpgme_verify_result);
vb@24
  1216
        gpgme_signature = gpgme_verify_result->signatures;
vb@24
  1217
vb@24
  1218
        if (gpgme_signature) {
vb@24
  1219
            stringlist_t *k;
vb@24
  1220
            _keylist = new_stringlist(NULL);
vb@24
  1221
            assert(_keylist);
vb@24
  1222
            if (_keylist == NULL) {
vb@74
  1223
                gpg.gpgme_data_release(d_text);
vb@74
  1224
                gpg.gpgme_data_release(d_sig);
vb@24
  1225
                return PEP_OUT_OF_MEMORY;
vb@24
  1226
            }
vb@24
  1227
            k = _keylist;
vb@24
  1228
vb@24
  1229
            result = PEP_VERIFIED;
vb@24
  1230
            do {
Edouard@502
  1231
                gpgme_key_t key;
Edouard@502
  1232
                memset(&key,0,sizeof(key));
Edouard@502
  1233
krista@1426
  1234
                // GPGME may give subkey's fpr instead of primary key's fpr.
Edouard@502
  1235
                // Therefore we ask for the primary fingerprint instead
Edouard@502
  1236
                // we assume that gpgme_get_key can find key by subkey's fpr
Edouard@502
  1237
                gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@502
  1238
                    gpgme_signature->fpr, &key, 0);
Edouard@502
  1239
                gpgme_error = _GPGERR(gpgme_error);
Edouard@502
  1240
                assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@502
  1241
                if (gpgme_error == GPG_ERR_ENOMEM) {
vb@24
  1242
                    free_stringlist(_keylist);
Edouard@505
  1243
                    gpg.gpgme_data_release(d_text);
Edouard@505
  1244
                    gpg.gpgme_data_release(d_sig);
vb@24
  1245
                    return PEP_OUT_OF_MEMORY;
vb@24
  1246
                }
Edouard@502
  1247
                // Primary key is given as the first subkey
krista@1426
  1248
                if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
  1249
                    key && key->subkeys && key->subkeys->fpr
Edouard@674
  1250
                    && key->subkeys->fpr[0])
Edouard@674
  1251
                {
Edouard@504
  1252
                    k = stringlist_add(k, key->subkeys->fpr);
Edouard@677
  1253
Edouard@674
  1254
                    gpg.gpgme_key_unref(key);
Edouard@677
  1255
Edouard@677
  1256
                    if (k == NULL) {
Edouard@677
  1257
                        free_stringlist(_keylist);
Edouard@677
  1258
                        gpg.gpgme_data_release(d_text);
Edouard@677
  1259
                        gpg.gpgme_data_release(d_sig);
Edouard@677
  1260
                        return PEP_OUT_OF_MEMORY;
Edouard@677
  1261
                    }
Edouard@502
  1262
                }
Edouard@502
  1263
                else {
Edouard@502
  1264
                    result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
Edouard@502
  1265
                    break;
Edouard@502
  1266
                }
Edouard@502
  1267
vb@24
  1268
                if (gpgme_signature->summary & GPGME_SIGSUM_RED) {
vb@24
  1269
                    if (gpgme_signature->summary & GPGME_SIGSUM_KEY_EXPIRED
vb@24
  1270
                        || gpgme_signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
vb@24
  1271
                        if (result == PEP_VERIFIED
vb@24
  1272
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
  1273
                            result = PEP_UNENCRYPTED;
vb@24
  1274
                    }
vb@24
  1275
                    else {
vb@24
  1276
                        result = PEP_DECRYPT_SIGNATURE_DOES_NOT_MATCH;
vb@24
  1277
                        break;
vb@24
  1278
                    }
vb@24
  1279
                }
vb@24
  1280
                else {
vb@24
  1281
                    if (gpgme_signature->summary & GPGME_SIGSUM_VALID) {
vb@24
  1282
                        if (result == PEP_VERIFIED)
vb@24
  1283
                            result = PEP_VERIFIED_AND_TRUSTED;
vb@24
  1284
                    }
vb@24
  1285
                    if (gpgme_signature->summary & GPGME_SIGSUM_GREEN) {
vb@24
  1286
                        // good
vb@24
  1287
                    }
vb@24
  1288
                    else if (gpgme_signature->summary & GPGME_SIGSUM_KEY_MISSING) {
vb@24
  1289
                        result = PEP_VERIFY_NO_KEY;
vb@24
  1290
                    }
vb@24
  1291
                    else if (gpgme_signature->summary & GPGME_SIGSUM_SYS_ERROR) {
vb@24
  1292
                        if (result == PEP_VERIFIED
vb@24
  1293
                            || result == PEP_VERIFIED_AND_TRUSTED)
vb@24
  1294
                            result = PEP_UNENCRYPTED;
vb@24
  1295
                    }
vb@24
  1296
                    else {
vb@24
  1297
                        // do nothing
vb@24
  1298
                    }
vb@24
  1299
                }
vb@24
  1300
            } while ((gpgme_signature = gpgme_signature->next));
vb@24
  1301
            *keylist = _keylist;
vb@24
  1302
        }
vb@24
  1303
        else {
vb@24
  1304
            result = PEP_UNENCRYPTED;
vb@24
  1305
        }
vb@24
  1306
        break;
vb@24
  1307
    }
vb@24
  1308
        break;
vb@24
  1309
    case GPG_ERR_NO_DATA:
vb@24
  1310
        result = PEP_DECRYPT_WRONG_FORMAT;
vb@24
  1311
        break;
vb@24
  1312
    case GPG_ERR_INV_VALUE:
vb@24
  1313
    default:
vb@24
  1314
        result = PEP_UNKNOWN_ERROR;
vb@24
  1315
        break;
vb@24
  1316
    }
vb@24
  1317
vb@74
  1318
    gpg.gpgme_data_release(d_text);
vb@74
  1319
    gpg.gpgme_data_release(d_sig);
vb@24
  1320
vb@24
  1321
    return result;
vb@24
  1322
}
vb@24
  1323
krista@1639
  1324
krista@1639
  1325
static PEP_STATUS pgp_encrypt_sign_optional(    
vb@24
  1326
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1327
    size_t psize, char **ctext, size_t *csize, bool sign
krista@1639
  1328
)
roker@2055
  1329
{
vb@24
  1330
    PEP_STATUS result;
vb@24
  1331
    gpgme_error_t gpgme_error;
vb@24
  1332
    gpgme_data_t plain, cipher;
vb@24
  1333
    gpgme_key_t *rcpt;
vb@24
  1334
    gpgme_encrypt_flags_t flags;
vb@24
  1335
    const stringlist_t *_keylist;
vb@24
  1336
    int i, j;
vb@24
  1337
vb@46
  1338
    assert(session);
vb@24
  1339
    assert(keylist);
vb@24
  1340
    assert(ptext);
vb@24
  1341
    assert(psize);
vb@24
  1342
    assert(ctext);
vb@24
  1343
    assert(csize);
vb@24
  1344
vb@24
  1345
    *ctext = NULL;
vb@24
  1346
    *csize = 0;
vb@24
  1347
vb@74
  1348
    gpgme_error = gpg.gpgme_data_new_from_mem(&plain, ptext, psize, 0);
vb@45
  1349
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1350
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1351
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@24
  1352
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
  1353
            return PEP_OUT_OF_MEMORY;
vb@24
  1354
        else
vb@24
  1355
            return PEP_UNKNOWN_ERROR;
vb@24
  1356
    }
vb@24
  1357
vb@74
  1358
    gpgme_error = gpg.gpgme_data_new(&cipher);
vb@45
  1359
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1360
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1361
    if (gpgme_error != GPG_ERR_NO_ERROR) {
vb@74
  1362
        gpg.gpgme_data_release(plain);
vb@24
  1363
        if (gpgme_error == GPG_ERR_ENOMEM)
vb@24
  1364
            return PEP_OUT_OF_MEMORY;
vb@24
  1365
        else
vb@24
  1366
            return PEP_UNKNOWN_ERROR;
vb@24
  1367
    }
vb@24
  1368
vb@109
  1369
    rcpt = calloc(stringlist_length(keylist) + 1, sizeof(gpgme_key_t));
vb@24
  1370
    assert(rcpt);
vb@24
  1371
    if (rcpt == NULL) {
vb@74
  1372
        gpg.gpgme_data_release(plain);
vb@74
  1373
        gpg.gpgme_data_release(cipher);
vb@24
  1374
        return PEP_OUT_OF_MEMORY;
vb@24
  1375
    }
vb@24
  1376
vb@74
  1377
    gpg.gpgme_signers_clear(session->ctx);
vb@24
  1378
vb@24
  1379
    for (_keylist = keylist, i = 0; _keylist != NULL; _keylist = _keylist->next, i++) {
vb@24
  1380
        assert(_keylist->value);
vb@74
  1381
        gpgme_error = gpg.gpgme_get_key(session->ctx, _keylist->value,
vb@24
  1382
            &rcpt[i], 0);
vb@45
  1383
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  1384
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1385
vb@24
  1386
        switch (gpgme_error) {
vb@24
  1387
        case GPG_ERR_ENOMEM:
vb@24
  1388
            for (j = 0; j<i; j++)
vb@74
  1389
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1390
            free(rcpt);
vb@74
  1391
            gpg.gpgme_data_release(plain);
vb@74
  1392
            gpg.gpgme_data_release(cipher);
vb@24
  1393
            return PEP_OUT_OF_MEMORY;
vb@24
  1394
        case GPG_ERR_NO_ERROR:
krista@1639
  1395
            if (i == 0 && sign) {
vb@74
  1396
                gpgme_error_t _gpgme_error = gpg.gpgme_signers_add(session->ctx, rcpt[0]);
vb@45
  1397
                _gpgme_error = _GPGERR(_gpgme_error);
vb@24
  1398
                assert(_gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  1399
            }
vb@24
  1400
            break;
vb@24
  1401
        case GPG_ERR_EOF:
vb@24
  1402
            for (j = 0; j<i; j++)
vb@74
  1403
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1404
            free(rcpt);
vb@74
  1405
            gpg.gpgme_data_release(plain);
vb@74
  1406
            gpg.gpgme_data_release(cipher);
vb@24
  1407
            return PEP_KEY_NOT_FOUND;
vb@24
  1408
        case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1409
            for (j = 0; j<i; j++)
vb@74
  1410
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1411
            free(rcpt);
vb@74
  1412
            gpg.gpgme_data_release(plain);
vb@74
  1413
            gpg.gpgme_data_release(cipher);
vb@24
  1414
            return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1415
        default: // GPG_ERR_INV_VALUE if CTX or R_KEY is not a valid pointer or
vb@24
  1416
            // FPR is not a fingerprint or key ID
vb@24
  1417
            for (j = 0; j<i; j++)
vb@74
  1418
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1419
            free(rcpt);
vb@74
  1420
            gpg.gpgme_data_release(plain);
vb@74
  1421
            gpg.gpgme_data_release(cipher);
vb@24
  1422
            return PEP_GET_KEY_FAILED;
vb@24
  1423
        }
vb@24
  1424
    }
vb@24
  1425
vb@24
  1426
    // TODO: remove that and replace with proper key management
vb@24
  1427
    flags = GPGME_ENCRYPT_ALWAYS_TRUST;
krista@1639
  1428
    
krista@1639
  1429
    if (sign) {
krista@1639
  1430
        gpgme_error = gpg.gpgme_op_encrypt_sign(session->ctx, rcpt, flags,
krista@1639
  1431
            plain, cipher);
krista@1639
  1432
    }
krista@1639
  1433
    else {
krista@1639
  1434
        gpgme_error = gpg.gpgme_op_encrypt(session->ctx, rcpt, flags,
krista@1639
  1435
            plain, cipher);
krista@1639
  1436
    }
krista@1639
  1437
    
vb@45
  1438
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1439
    switch (gpgme_error) {
vb@24
  1440
    case GPG_ERR_NO_ERROR:
vb@24
  1441
    {
vb@24
  1442
        char *_buffer = NULL;
vb@24
  1443
        size_t reading;
vb@74
  1444
        size_t length = gpg.gpgme_data_seek(cipher, 0, SEEK_END);
vb@24
  1445
        assert(length != -1);
vb@74
  1446
        gpg.gpgme_data_seek(cipher, 0, SEEK_SET);
vb@24
  1447
vb@24
  1448
        // TODO: make things less memory consuming
vb@24
  1449
        // the following algorithm allocates a buffer for the complete text
vb@24
  1450
vb@112
  1451
        _buffer = malloc(length + 1);
vb@24
  1452
        assert(_buffer);
vb@24
  1453
        if (_buffer == NULL) {
vb@24
  1454
            for (j = 0; j<stringlist_length(keylist); j++)
vb@74
  1455
                gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1456
            free(rcpt);
vb@74
  1457
            gpg.gpgme_data_release(plain);
vb@74
  1458
            gpg.gpgme_data_release(cipher);
vb@24
  1459
            return PEP_OUT_OF_MEMORY;
vb@24
  1460
        }
vb@24
  1461
vb@74
  1462
        reading = gpg.gpgme_data_read(cipher, _buffer, length);
vb@24
  1463
        assert(length == reading);
vb@24
  1464
vb@24
  1465
        *ctext = _buffer;
vb@24
  1466
        *csize = reading;
vb@24
  1467
        (*ctext)[*csize] = 0; // safeguard for naive users
vb@24
  1468
        result = PEP_STATUS_OK;
vb@24
  1469
        break;
vb@24
  1470
    }
vb@24
  1471
    default:
vb@24
  1472
        result = PEP_UNKNOWN_ERROR;
vb@24
  1473
    }
vb@24
  1474
vb@24
  1475
    for (j = 0; j<stringlist_length(keylist); j++)
vb@74
  1476
        gpg.gpgme_key_unref(rcpt[j]);
vb@24
  1477
    free(rcpt);
vb@74
  1478
    gpg.gpgme_data_release(plain);
vb@74
  1479
    gpg.gpgme_data_release(cipher);
vb@24
  1480
    return result;
vb@24
  1481
}
vb@24
  1482
krista@1639
  1483
PEP_STATUS pgp_encrypt_only(
krista@1639
  1484
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1485
    size_t psize, char **ctext, size_t *csize
krista@1639
  1486
    )
krista@1639
  1487
{
krista@1639
  1488
    return pgp_encrypt_sign_optional(session, keylist, ptext,
krista@1639
  1489
        psize, ctext, csize, false);
krista@1639
  1490
}
krista@1639
  1491
krista@1639
  1492
PEP_STATUS pgp_encrypt_and_sign(
krista@1639
  1493
    PEP_SESSION session, const stringlist_t *keylist, const char *ptext,
krista@1639
  1494
    size_t psize, char **ctext, size_t *csize
krista@1639
  1495
    )
krista@1639
  1496
{
krista@1639
  1497
    return pgp_encrypt_sign_optional(session, keylist, ptext,
krista@1639
  1498
        psize, ctext, csize, true);
krista@1639
  1499
}
krista@1639
  1500
krista@1925
  1501
krista@1925
  1502
static PEP_STATUS find_single_key(
krista@1925
  1503
        PEP_SESSION session,
krista@1925
  1504
        const char *fpr,
krista@1925
  1505
        gpgme_key_t *key
krista@1925
  1506
    )
krista@1925
  1507
{
krista@1925
  1508
    gpgme_error_t gpgme_error;
krista@1925
  1509
krista@1925
  1510
    *key = NULL;
krista@1925
  1511
kgrothoff@1926
  1512
//    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
kgrothoff@1926
  1513
kgrothoff@1926
  1514
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, key, 0);
kgrothoff@1926
  1515
krista@1925
  1516
    gpgme_error = _GPGERR(gpgme_error);
krista@1925
  1517
    switch (gpgme_error) {
krista@1925
  1518
    case GPG_ERR_NO_ERROR:
krista@1925
  1519
        break;
krista@1925
  1520
    case GPG_ERR_INV_VALUE:
krista@1925
  1521
        assert(0);
krista@1925
  1522
        return PEP_UNKNOWN_ERROR;
krista@1925
  1523
    default:
krista@1925
  1524
        return PEP_GET_KEY_FAILED;
krista@1925
  1525
    };
krista@1925
  1526
kgrothoff@1926
  1527
//    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, key);
kgrothoff@1926
  1528
//    gpgme_error = _GPGERR(gpgme_error);
kgrothoff@1926
  1529
//    assert(gpgme_error != GPG_ERR_INV_VALUE);
krista@1925
  1530
kgrothoff@1926
  1531
//    gpg.gpgme_op_keylist_end(session->ctx);
krista@1925
  1532
krista@1925
  1533
    return PEP_STATUS_OK;
krista@1925
  1534
}
krista@1925
  1535
krista@1925
  1536
krista@1914
  1537
static PEP_STATUS _pgp_createkey(PEP_SESSION session, pEp_identity *identity) {
krista@1914
  1538
    PEP_STATUS status = PEP_VERSION_MISMATCH;
krista@1914
  1539
roker@2055
  1540
    if (identity && identity->address) {
krista@1914
  1541
#ifdef GPGME_VERSION_NUMBER 
krista@1914
  1542
#if (GPGME_VERSION_NUMBER >= 0x010700)
krista@1920
  1543
        gpgme_error_t gpgme_error;
kgrothoff@1926
  1544
        int userid_size = strlen(identity->address) + 1;
krista@1921
  1545
        char* userid = (char*)(calloc(1, userid_size));
krista@1921
  1546
        if (!userid)
krista@1921
  1547
            return PEP_OUT_OF_MEMORY;
kgrothoff@1926
  1548
        strlcpy(userid, identity->address, userid_size);
krista@1921
  1549
        gpgme_error = gpg.gpgme_op_createkey(session->ctx, userid, "RSA", 
krista@1924
  1550
                                             0, 31536000, NULL, 
krista@1927
  1551
                                             GPGME_CREATE_NOPASSWD | GPGME_CREATE_FORCE);
krista@1920
  1552
        gpgme_error = _GPGERR(gpgme_error);
krista@1921
  1553
krista@1921
  1554
        free(userid);
krista@1921
  1555
krista@1920
  1556
        if (gpgme_error != GPG_ERR_NOT_SUPPORTED) {
krista@1920
  1557
            switch (gpgme_error) {
krista@1924
  1558
                case GPG_ERR_NO_ERROR:
roker@2055
  1559
                    break;
krista@1924
  1560
                case GPG_ERR_INV_VALUE:
krista@1924
  1561
                    return PEP_ILLEGAL_VALUE;
krista@1924
  1562
                case GPG_ERR_GENERAL:
krista@1924
  1563
                    return PEP_CANNOT_CREATE_KEY;
krista@1924
  1564
                default:
krista@1924
  1565
                    assert(0);
krista@1924
  1566
                    return PEP_UNKNOWN_ERROR;
roker@2055
  1567
            }
krista@1924
  1568
krista@1924
  1569
            /* This is the same regardless of whether we got it from genkey or createkey */
krista@1924
  1570
            gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
krista@1924
  1571
            assert(gpgme_genkey_result);
krista@1924
  1572
            assert(gpgme_genkey_result->fpr);
krista@1924
  1573
kgrothoff@1926
  1574
            char* fpr = strdup(gpgme_genkey_result->fpr);
krista@1925
  1575
            gpgme_key_t key;
krista@1925
  1576
            PEP_STATUS key_status = find_single_key(session, fpr, &key);
krista@1925
  1577
            if (!key || key_status != PEP_STATUS_OK)
krista@1925
  1578
                return PEP_CANNOT_CREATE_KEY;
roker@2055
  1579
            
krista@1925
  1580
            gpgme_error = gpg.gpgme_op_createsubkey(session->ctx, key, 
krista@1925
  1581
                                                    "RSA", 0, 
krista@1925
  1582
                                                    31536000, GPGME_CREATE_NOPASSWD 
krista@1925
  1583
                                                    | GPGME_CREATE_ENCR);
krista@1925
  1584
krista@1925
  1585
            switch (gpgme_error) {
krista@1925
  1586
                case GPG_ERR_NO_ERROR:
roker@2055
  1587
                    break;
krista@1925
  1588
                case GPG_ERR_INV_VALUE:
krista@1925
  1589
                    return PEP_ILLEGAL_VALUE;
krista@1925
  1590
                case GPG_ERR_GENERAL:
krista@1925
  1591
                    return PEP_CANNOT_CREATE_KEY;
krista@1925
  1592
                default:
krista@1925
  1593
                    assert(0);
krista@1925
  1594
                    return PEP_UNKNOWN_ERROR;
roker@2055
  1595
            }
krista@1925
  1596
            
krista@1924
  1597
            free(identity->fpr);
kgrothoff@1926
  1598
            identity->fpr = fpr;
krista@1924
  1599
            if (identity->fpr == NULL)
krista@1924
  1600
                return PEP_OUT_OF_MEMORY;
krista@1924
  1601
kgrothoff@1926
  1602
//            gpg.gpgme_key_unref(key);
krista@1925
  1603
            
kgrothoff@1926
  1604
            status = pgp_replace_only_uid(session, fpr,
roker@2055
  1605
                        identity->username, identity->address);
krista@1920
  1606
        }
krista@1914
  1607
#endif
krista@1914
  1608
#endif
krista@1914
  1609
    }
krista@1914
  1610
    
krista@1914
  1611
    return status;
krista@1914
  1612
}
krista@1914
  1613
vb@24
  1614
PEP_STATUS pgp_generate_keypair(
vb@24
  1615
    PEP_SESSION session, pEp_identity *identity
vb@24
  1616
    )
vb@24
  1617
{
vb@24
  1618
    assert(session);
vb@24
  1619
    assert(identity);
vb@24
  1620
    assert(identity->address);
vb@298
  1621
    assert(identity->fpr == NULL || identity->fpr[0] == 0);
vb@24
  1622
    assert(identity->username);
vb@24
  1623
krista@1914
  1624
    PEP_STATUS status = _pgp_createkey(session, identity);
krista@1914
  1625
    
krista@1924
  1626
    if (status != PEP_VERSION_MISMATCH)
krista@1914
  1627
        return status;
krista@1924
  1628
        
krista@1924
  1629
    gpgme_error_t gpgme_error;
krista@1924
  1630
    char *parms;
krista@1924
  1631
    const char *template =
krista@1924
  1632
        "<GnupgKeyParms format=\"internal\">\n"
krista@1924
  1633
        "Key-Type: RSA\n"
krista@1924
  1634
        "Key-Length: 4096\n"
krista@1924
  1635
        "Subkey-Type: RSA\n"
krista@1924
  1636
        "Subkey-Length: 4096\n"
krista@1924
  1637
        "Name-Real: %s\n"
krista@1924
  1638
        "Name-Email: %s\n"
krista@1924
  1639
        /* "Passphrase: %s\n" */
krista@1924
  1640
        "Expire-Date: 1y\n"
krista@1924
  1641
        "</GnupgKeyParms>\n";
krista@1924
  1642
    int result;
vb@24
  1643
krista@1924
  1644
    parms = calloc(1, PARMS_MAX);
krista@1924
  1645
    assert(parms);
krista@1924
  1646
    if (parms == NULL)
krista@1924
  1647
        return PEP_OUT_OF_MEMORY;
krista@1914
  1648
krista@1924
  1649
    result = snprintf(parms, PARMS_MAX, template, identity->username,
krista@1924
  1650
        identity->address); // , session->passphrase);
krista@1924
  1651
    assert(result < PARMS_MAX);
krista@1924
  1652
    if (result >= PARMS_MAX) {
vb@24
  1653
        free(parms);
krista@1924
  1654
        return PEP_BUFFER_TOO_SMALL;
vb@24
  1655
    }
vb@24
  1656
krista@1924
  1657
    gpgme_error = gpg.gpgme_op_genkey(session->ctx, parms, NULL, NULL);
krista@1924
  1658
    gpgme_error = _GPGERR(gpgme_error);
krista@1924
  1659
    free(parms);
krista@1924
  1660
krista@1924
  1661
    switch (gpgme_error) {
krista@1924
  1662
    case GPG_ERR_NO_ERROR:
krista@1924
  1663
        break;
krista@1924
  1664
    case GPG_ERR_INV_VALUE:
krista@1924
  1665
        return PEP_ILLEGAL_VALUE;
krista@1924
  1666
    case GPG_ERR_GENERAL:
krista@1924
  1667
        return PEP_CANNOT_CREATE_KEY;
krista@1924
  1668
    default:
krista@1924
  1669
        assert(0);
krista@1924
  1670
        return PEP_UNKNOWN_ERROR;
krista@1924
  1671
    }
krista@1924
  1672
krista@1914
  1673
    gpgme_genkey_result_t gpgme_genkey_result = gpg.gpgme_op_genkey_result(session->ctx);
vb@24
  1674
    assert(gpgme_genkey_result);
vb@24
  1675
    assert(gpgme_genkey_result->fpr);
vb@24
  1676
vb@298
  1677
    free(identity->fpr);
vb@24
  1678
    identity->fpr = strdup(gpgme_genkey_result->fpr);
vb@298
  1679
    if (identity->fpr == NULL)
vb@298
  1680
        return PEP_OUT_OF_MEMORY;
vb@24
  1681
vb@24
  1682
    return PEP_STATUS_OK;
vb@24
  1683
}
vb@24
  1684
vb@24
  1685
PEP_STATUS pgp_delete_keypair(PEP_SESSION session, const char *fpr)
vb@24
  1686
{
vb@24
  1687
    gpgme_error_t gpgme_error;
vb@24
  1688
    gpgme_key_t key;
vb@24
  1689
vb@24
  1690
    assert(session);
vb@24
  1691
    assert(fpr);
vb@24
  1692
vb@74
  1693
    gpgme_error = gpg.gpgme_get_key(session->ctx, fpr, &key, 0);
vb@45
  1694
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1695
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1696
    switch (gpgme_error) {
vb@24
  1697
    case GPG_ERR_NO_ERROR:
vb@24
  1698
        break;
vb@24
  1699
    case GPG_ERR_EOF:
vb@24
  1700
        return PEP_KEY_NOT_FOUND;
vb@24
  1701
    case GPG_ERR_INV_VALUE:
vb@24
  1702
        return PEP_ILLEGAL_VALUE;
vb@24
  1703
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1704
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1705
    case GPG_ERR_ENOMEM:
vb@24
  1706
        return PEP_OUT_OF_MEMORY;
vb@24
  1707
    default:
vb@24
  1708
        assert(0);
vb@24
  1709
        return PEP_UNKNOWN_ERROR;
vb@24
  1710
    }
vb@24
  1711
vb@74
  1712
    gpgme_error = gpg.gpgme_op_delete(session->ctx, key, 1);
vb@45
  1713
    gpgme_error = _GPGERR(gpgme_error);
vb@74
  1714
    gpg.gpgme_key_unref(key);
vb@24
  1715
    switch (gpgme_error) {
vb@24
  1716
    case GPG_ERR_NO_ERROR:
vb@24
  1717
        break;
vb@24
  1718
    case GPG_ERR_INV_VALUE:
vb@24
  1719
        assert(0);
vb@24
  1720
        return PEP_UNKNOWN_ERROR;
vb@24
  1721
    case GPG_ERR_NO_PUBKEY:
vb@24
  1722
        assert(0);
vb@24
  1723
        return PEP_KEY_NOT_FOUND;
vb@24
  1724
    case GPG_ERR_AMBIGUOUS_NAME:
vb@24
  1725
        assert(0);
vb@24
  1726
        return PEP_KEY_HAS_AMBIG_NAME;
vb@24
  1727
    default:
vb@24
  1728
        assert(0);
vb@24
  1729
        return PEP_UNKNOWN_ERROR;
vb@24
  1730
    }
vb@24
  1731
vb@24
  1732
    return PEP_STATUS_OK;
vb@24
  1733
}
vb@24
  1734
Edouard@728
  1735
PEP_STATUS pgp_import_keydata(PEP_SESSION session, const char *key_data,
Edouard@728
  1736
                              size_t size, identity_list **private_idents)
vb@24
  1737
{
vb@24
  1738
    gpgme_error_t gpgme_error;
vb@24
  1739
    gpgme_data_t dh;
vb@24
  1740
vb@24
  1741
    assert(session);
vb@24
  1742
    assert(key_data);
krista@1426
  1743
krista@1426
  1744
    if(private_idents)
Edouard@728
  1745
        *private_idents = NULL;
vb@24
  1746
vb@74
  1747
    gpgme_error = gpg.gpgme_data_new_from_mem(&dh, key_data, size, 0);
vb@45
  1748
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1749
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1750
    switch (gpgme_error) {
vb@24
  1751
    case GPG_ERR_NO_ERROR:
vb@24
  1752
        break;
vb@24
  1753
    case GPG_ERR_ENOMEM:
vb@24
  1754
        return PEP_OUT_OF_MEMORY;
vb@24
  1755
    case GPG_ERR_INV_VALUE:
vb@24
  1756
        assert(0);
vb@24
  1757
        return PEP_UNKNOWN_ERROR;
vb@24
  1758
    default:
vb@24
  1759
        assert(0);
vb@24
  1760
        return PEP_UNKNOWN_ERROR;
vb@24
  1761
    }
vb@24
  1762
Edouard@728
  1763
    gpgme_import_result_t gpgme_import_result;
Edouard@728
  1764
vb@74
  1765
    gpgme_error = gpg.gpgme_op_import(session->ctx, dh);
vb@45
  1766
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1767
    switch (gpgme_error) {
vb@24
  1768
    case GPG_ERR_NO_ERROR:
krista@1426
  1769
        if(private_idents)
Edouard@728
  1770
        {
Edouard@728
  1771
            gpgme_import_result =
Edouard@728
  1772
                gpg.gpgme_op_import_result(session->ctx);
Edouard@728
  1773
            assert(gpgme_import_result);
vb@1302
  1774
            if (!gpgme_import_result) {
vb@1302
  1775
                gpg.gpgme_data_release(dh);
vb@1302
  1776
                return PEP_UNKNOWN_ERROR;
vb@1302
  1777
            }
vb@1302
  1778
Edouard@728
  1779
            gpgme_import_status_t import;
krista@1426
  1780
            for (import = gpgme_import_result->imports;
krista@1426
  1781
                 import;
Edouard@728
  1782
                 import = import->next)
Edouard@728
  1783
             {
Edouard@728
  1784
                if (import &&
Edouard@728
  1785
                    import->result == GPG_ERR_NO_ERROR &&
Edouard@728
  1786
                    import->status & GPGME_IMPORT_SECRET )
Edouard@728
  1787
                {
Edouard@728
  1788
                    gpgme_key_t key = NULL;
Edouard@728
  1789
Edouard@728
  1790
                    gpgme_error = gpg.gpgme_get_key(session->ctx,
Edouard@728
  1791
                        import->fpr, &key, 0);
Edouard@728
  1792
                    gpgme_error = _GPGERR(gpgme_error);
Edouard@728
  1793
                    assert(gpgme_error != GPG_ERR_ENOMEM);
Edouard@728
  1794
                    if (gpgme_error == GPG_ERR_ENOMEM) {
Edouard@728
  1795
                        gpg.gpgme_data_release(dh);
Edouard@728
  1796
                        return PEP_OUT_OF_MEMORY;
Edouard@728
  1797
                    }
krista@1426
  1798
krista@1426
  1799
                    if (gpgme_error == GPG_ERR_NO_ERROR &&
krista@1426
  1800
                        key && key->uids &&
Edouard@728
  1801
                        key->uids->email && key->uids->name)
Edouard@728
  1802
                    {
Edouard@728
  1803
                        pEp_identity *ident = new_identity(
Edouard@728
  1804
                             key->uids->email, import->fpr, NULL, key->uids->name);
Edouard@728
  1805
Edouard@728
  1806
                        gpg.gpgme_key_unref(key);
Edouard@728
  1807
Edouard@728
  1808
                        if (ident == NULL) {
Edouard@728
  1809
                            gpg.gpgme_data_release(dh);
Edouard@728
  1810
                            return PEP_OUT_OF_MEMORY;
Edouard@728
  1811
                        }
Edouard@728
  1812
Edouard@728
  1813
                        *private_idents = identity_list_add(*private_idents, ident);
Edouard@728
  1814
Edouard@728
  1815
                        if (*private_idents == NULL) {
Edouard@728
  1816
                            gpg.gpgme_data_release(dh);
Edouard@728
  1817
                            return PEP_OUT_OF_MEMORY;
Edouard@728
  1818
                        }
Edouard@728
  1819
                    }
krista@1426
  1820
                    else
Edouard@728
  1821
                    {
Edouard@728
  1822
                        gpg.gpgme_key_unref(key);
Edouard@728
  1823
                        gpg.gpgme_data_release(dh);
Edouard@728
  1824
                        return PEP_UNKNOWN_ERROR;
Edouard@728
  1825
                    }
Edouard@728
  1826
                }
Edouard@728
  1827
            }
Edouard@728
  1828
        }
vb@24
  1829
        break;
vb@24
  1830
    case GPG_ERR_INV_VALUE:
vb@24
  1831
        assert(0);
vb@74
  1832
        gpg.gpgme_data_release(dh);
vb@24
  1833
        return PEP_UNKNOWN_ERROR;
vb@24
  1834
    case GPG_ERR_NO_DATA:
vb@74
  1835
        gpg.gpgme_data_release(dh);
vb@24
  1836
        return PEP_ILLEGAL_VALUE;
vb@24
  1837
    default:
vb@24
  1838
        assert(0);
vb@74
  1839
        gpg.gpgme_data_release(dh);
vb@24
  1840
        return PEP_UNKNOWN_ERROR;
vb@24
  1841
    }
vb@24
  1842
vb@74
  1843
    gpg.gpgme_data_release(dh);
vb@24
  1844
    return PEP_STATUS_OK;
vb@24
  1845
}
vb@24
  1846
Edouard@170
  1847
PEP_STATUS pgp_export_keydata(
vb@1103
  1848
        PEP_SESSION session, const char *fpr, char **key_data, size_t *size,
vb@1103
  1849
        bool secret
vb@24
  1850
    )
vb@24
  1851
{
vb@24
  1852
    gpgme_error_t gpgme_error;
vb@24
  1853
    gpgme_data_t dh;
vb@24
  1854
    size_t _size;
vb@24
  1855
    char *buffer;
vb@24
  1856
    int reading;
vb@24
  1857
vb@24
  1858
    assert(session);
vb@24
  1859
    assert(fpr);
vb@24
  1860
    assert(key_data);
vb@24
  1861
    assert(size);
vb@24
  1862
vb@74
  1863
    gpgme_error = gpg.gpgme_data_new(&dh);
vb@45
  1864
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1865
    assert(gpgme_error != GPG_ERR_ENOMEM);
vb@24
  1866
    switch (gpgme_error) {
vb@24
  1867
    case GPG_ERR_NO_ERROR:
vb@24
  1868
        break;
vb@24
  1869
    case GPG_ERR_ENOMEM:
vb@24
  1870
        return PEP_OUT_OF_MEMORY;
vb@24
  1871
    case GPG_ERR_INV_VALUE:
vb@24
  1872
        assert(0);
vb@24
  1873
        return PEP_UNKNOWN_ERROR;
vb@24
  1874
    default:
vb@24
  1875
        assert(0);
vb@24
  1876
        return PEP_UNKNOWN_ERROR;
vb@24
  1877
    }
vb@24
  1878
vb@1103
  1879
    if (secret)
vb@1103
  1880
        gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
edouard@1163
  1881
            GPGME_EXPORT_MODE_SECRET, dh);
vb@1103
  1882
    else
vb@1103
  1883
        gpgme_error = gpg.gpgme_op_export(session->ctx, fpr,
vb@1103
  1884
            GPGME_EXPORT_MODE_MINIMAL, dh);
vb@45
  1885
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  1886
    switch (gpgme_error) {
vb@24
  1887
    case GPG_ERR_NO_ERROR:
vb@24
  1888
        break;
vb@24
  1889
    case GPG_ERR_EOF:
vb@74
  1890
        gpg.gpgme_data_release(dh);
vb@24
  1891
        return PEP_KEY_NOT_FOUND;
vb@24
  1892
    case GPG_ERR_INV_VALUE:
vb@24
  1893
        assert(0);
vb@74
  1894
        gpg.gpgme_data_release(dh);
vb@24
  1895
        return PEP_UNKNOWN_ERROR;
vb@24
  1896
    default:
vb@24
  1897
        assert(0);
vb@74
  1898
        gpg.gpgme_data_release(dh);
vb@24
  1899
        return PEP_UNKNOWN_ERROR;
vb@24
  1900
    };
vb@24
  1901
vb@74
  1902
    _size = gpg.gpgme_data_seek(dh, 0, SEEK_END);
vb@24
  1903
    assert(_size != -1);
vb@74
  1904
    gpg.gpgme_data_seek(dh, 0, SEEK_SET);
vb@24
  1905
vb@24
  1906
    buffer = malloc(_size + 1);
vb@24
  1907
    assert(buffer);
vb@24
  1908
    if (buffer == NULL) {
vb@74
  1909
        gpg.gpgme_data_release(dh);
vb@24
  1910
        return PEP_OUT_OF_MEMORY;
vb@24
  1911
    }
vb@24
  1912
vb@74
  1913
    reading = gpg.gpgme_data_read(dh, buffer, _size);
vb@24
  1914
    assert(_size == reading);
edouard@1803
  1915
    if(_size != reading)
edouard@1803
  1916
        return PEP_CANNOT_EXPORT_KEY;
vb@24
  1917
vb@24
  1918
    // safeguard for the naive user
vb@24
  1919
    buffer[_size] = 0;
vb@24
  1920
vb@24
  1921
    *key_data = buffer;
vb@24
  1922
    *size = _size;
vb@24
  1923
vb@74
  1924
    gpg.gpgme_data_release(dh);
vb@24
  1925
    return PEP_STATUS_OK;
vb@24
  1926
}
vb@24
  1927
krista@1426
  1928
PEP_STATUS pgp_list_keyinfo(PEP_SESSION session, const char* pattern,
krista@1031
  1929
                            stringpair_list_t** keyinfo_list)
krista@1426
  1930
{
krista@1005
  1931
    gpgme_error_t gpgme_error;
krista@1005
  1932
    assert(session);
krista@1031
  1933
    assert(keyinfo_list);
krista@1426
  1934
krista@1031
  1935
    if (!session || !keyinfo_list)
krista@1005
  1936
        return PEP_ILLEGAL_VALUE;
krista@1426
  1937
krista@1031
  1938
    *keyinfo_list = NULL;
krista@1426
  1939
krista@1031
  1940
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
krista@1005
  1941
    gpgme_error = _GPGERR(gpgme_error);
krista@1426
  1942
krista@1005
  1943
    switch(gpgme_error) {
krista@1005
  1944
        case GPG_ERR_NO_ERROR:
krista@1005
  1945
            break;
krista@1005
  1946
        case GPG_ERR_INV_VALUE:
krista@1005
  1947
            assert(0);
krista@1005
  1948
            return PEP_UNKNOWN_ERROR;
krista@1005
  1949
        default:
krista@1005
  1950
            gpg.gpgme_op_keylist_end(session->ctx);
krista@1426
  1951
            return PEP_GET_KEY_FAILED;
krista@1005
  1952
    };
krista@1426
  1953
krista@1005
  1954
    gpgme_key_t key;
krista@1031
  1955
    stringpair_list_t* _keyinfo_list = new_stringpair_list(NULL);
krista@1031
  1956
    stringpair_list_t* list_curr = _keyinfo_list;
krista@1031
  1957
    stringpair_t* pair = NULL;
krista@1426
  1958
krista@1426
  1959
    do {
krista@1005
  1960
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
krista@1005
  1961
        gpgme_error = _GPGERR(gpgme_error);
krista@1426
  1962
krista@1005
  1963
        switch(gpgme_error) {
krista@1005
  1964
            case GPG_ERR_EOF:
krista@1005
  1965
                break;
krista@1005
  1966
            case GPG_ERR_NO_ERROR:
krista@1005
  1967
                assert(key);
krista@1005
  1968
                assert(key->subkeys);
krista@1005
  1969
                if (!key || !key->subkeys)
krista@1005
  1970
                    return PEP_GET_KEY_FAILED;
krista@1040
  1971
krista@1005
  1972
                // first subkey is primary key
krista@1005
  1973
                char* fpr = key->subkeys->fpr;
roker@1199
  1974
                char* uid = key->uids->uid;
krista@1187
  1975
krista@1005
  1976
                assert(fpr);
roker@1199
  1977
                assert(uid);
krista@1031
  1978
                if (!fpr)
krista@1005
  1979
                    return PEP_GET_KEY_FAILED;
krista@1426
  1980
krista@1050
  1981
                if (key->subkeys->revoked)
krista@1040
  1982
                    continue;
krista@1426
  1983
krista@1031
  1984
                pair = new_stringpair(fpr, uid);
krista@1019
  1985
krista@1031
  1986
                assert(pair);
krista@1426
  1987
krista@1031
  1988
                if (pair) {
krista@1031
  1989
                    list_curr = stringpair_list_add(list_curr, pair);
krista@1031
  1990
                    pair = NULL;
krista@1426
  1991
krista@1005
  1992
                    assert(list_curr);
krista@1005
  1993
                    if (list_curr != NULL)
krista@1005
  1994
                        break;
krista@1005
  1995
                    else
krista@1031
  1996
                        free_stringpair(pair);
krista@1005
  1997
                }
krista@1031
  1998
                // else fallthrough (list_curr or pair wasn't allocateable)
krista@1005
  1999
            case GPG_ERR_ENOMEM:
krista@1031
  2000
                free_stringpair_list(_keyinfo_list);
krista@1005
  2001
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  2002
                return PEP_OUT_OF_MEMORY;
krista@1005
  2003
            default:
krista@1005
  2004
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1005
  2005
                return PEP_UNKNOWN_ERROR;
krista@1005
  2006
        }
krista@1005
  2007
    } while (gpgme_error != GPG_ERR_EOF);
krista@1426
  2008
krista@1032
  2009
    if (_keyinfo_list->value == NULL) {
krista@1031
  2010
        free_stringpair_list(_keyinfo_list);
krista@1031
  2011
        _keyinfo_list = NULL;
krista@1005
  2012
    }
krista@1426
  2013
krista@1031
  2014
    *keyinfo_list = _keyinfo_list;
krista@1426
  2015
krista@1005
  2016
    return PEP_STATUS_OK;
krista@1005
  2017
}
krista@1005
  2018
vb@46
  2019
static void _switch_mode(pEpSession *session, gpgme_keylist_mode_t remove_mode,
vb@24
  2020
    gpgme_keylist_mode_t add_mode)
vb@24
  2021
{
vb@24
  2022
    gpgme_error_t gpgme_error;
vb@24
  2023
    gpgme_keylist_mode_t mode;
vb@24
  2024
vb@74
  2025
    mode = gpg.gpgme_get_keylist_mode(session->ctx);
vb@24
  2026
vb@24
  2027
    mode &= ~remove_mode;
vb@24
  2028
    mode |= add_mode;
vb@24
  2029
vb@74
  2030
    gpgme_error = gpg.gpgme_set_keylist_mode(session->ctx, mode);
vb@45
  2031
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2032
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@24
  2033
}
vb@24
  2034
vb@24
  2035
PEP_STATUS pgp_recv_key(PEP_SESSION session, const char *pattern)
vb@24
  2036
{
vb@24
  2037
    gpgme_error_t gpgme_error;
vb@24
  2038
    gpgme_key_t key;
vb@24
  2039
vb@24
  2040
    assert(session);
vb@24
  2041
    assert(pattern);
vb@24
  2042
vb@46
  2043
    _switch_mode(session, GPGME_KEYLIST_MODE_LOCAL, GPGME_KEYLIST_MODE_EXTERN);
vb@24
  2044
vb@74
  2045
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, 0);
vb@45
  2046
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2047
    switch (gpgme_error) {
vb@24
  2048
    case GPG_ERR_NO_ERROR:
vb@24
  2049
        break;
vb@24
  2050
    case GPG_ERR_INV_VALUE:
vb@24
  2051
        assert(0);
vb@47
  2052
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  2053
        return PEP_UNKNOWN_ERROR;
vb@24
  2054
    default:
vb@47
  2055
        _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  2056
        return PEP_GET_KEY_FAILED;
vb@24
  2057
    };
vb@24
  2058
vb@47
  2059
    gpgme_ctx_t import_ctx;
vb@74
  2060
    gpgme_error = gpg.gpgme_new(&import_ctx);
vb@47
  2061
    assert(gpgme_error == GPG_ERR_NO_ERROR);
vb@47
  2062
vb@24
  2063
    do {
vb@74
  2064
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  2065
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  2066
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2067
        switch (gpgme_error) {
vb@24
  2068
        case GPG_ERR_EOF:
vb@24
  2069
            break;
vb@24
  2070
        case GPG_ERR_NO_ERROR:
vb@24
  2071
        {
vb@24
  2072
            gpgme_error_t gpgme_error;
vb@24
  2073
            gpgme_key_t keys[2];
vb@24
  2074
vb@24
  2075
            keys[0] = key;
vb@24
  2076
            keys[1] = NULL;
vb@24
  2077
vb@74
  2078
            gpgme_error = gpg.gpgme_op_import_keys(import_ctx, keys);
vb@45
  2079
            gpgme_error = _GPGERR(gpgme_error);
vb@74
  2080
            gpg.gpgme_key_unref(key);
vb@24
  2081
            assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2082
            assert(gpgme_error != GPG_ERR_CONFLICT);
vb@24
  2083
        }
vb@24
  2084
            break;
vb@24
  2085
        case GPG_ERR_ENOMEM:
vb@74
  2086
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  2087
            gpg.gpgme_release(import_ctx);
vb@47
  2088
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  2089
            return PEP_OUT_OF_MEMORY;
vb@24
  2090
        default:
vb@74
  2091
            gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  2092
            gpg.gpgme_release(import_ctx);
vb@47
  2093
            _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@46
  2094
            return PEP_UNKNOWN_ERROR;
vb@24
  2095
        };
vb@24
  2096
    } while (gpgme_error != GPG_ERR_EOF);
vb@24
  2097
vb@74
  2098
    gpg.gpgme_op_keylist_end(session->ctx);
vb@74
  2099
    gpg.gpgme_release(import_ctx);
vb@47
  2100
    _switch_mode(session, GPGME_KEYLIST_MODE_EXTERN, GPGME_KEYLIST_MODE_LOCAL);
vb@24
  2101
    return PEP_STATUS_OK;
vb@24
  2102
}
vb@24
  2103
krista@1357
  2104
static PEP_STATUS _pgp_search_keys(PEP_SESSION session, const char* pattern,
krista@1357
  2105
                            stringlist_t** keylist,
krista@1357
  2106
                            int private_only) {
vb@24
  2107
    gpgme_error_t gpgme_error;
vb@24
  2108
    gpgme_key_t key;
krista@1426
  2109
vb@24
  2110
    assert(session);
vb@24
  2111
    assert(keylist);
krista@1426
  2112
vb@24
  2113
    *keylist = NULL;
krista@1426
  2114
krista@1357
  2115
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, pattern, private_only);
vb@45
  2116
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2117
    switch (gpgme_error) {
krista@1357
  2118
        case GPG_ERR_NO_ERROR:
krista@1357
  2119
            break;
krista@1357
  2120
        case GPG_ERR_INV_VALUE:
krista@1357
  2121
            assert(0);
krista@1357
  2122
            return PEP_UNKNOWN_ERROR;
krista@1357
  2123
        default:
krista@1357
  2124
            gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  2125
            return PEP_GET_KEY_FAILED;
vb@24
  2126
    };
krista@1426
  2127
roker@880
  2128
    stringlist_t *_keylist = new_stringlist(NULL);
vb@24
  2129
    stringlist_t *_k = _keylist;
krista@1426
  2130
vb@24
  2131
    do {
vb@74
  2132
        gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  2133
        gpgme_error = _GPGERR(gpgme_error);
vb@24
  2134
        assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2135
        switch (gpgme_error) {
krista@1357
  2136
            case GPG_ERR_EOF:
vb@24
  2137
                break;
krista@1357
  2138
            case GPG_ERR_NO_ERROR:
krista@1357
  2139
                assert(key);
krista@1357
  2140
                assert(key->subkeys);
edouard@1525
  2141
                if(!key->subkeys)
krista@1357
  2142
                    break;
edouard@1525
  2143
                assert(key->uids);
edouard@1525
  2144
                gpgme_user_id_t kuid = key->uids;
krista@2057
  2145
                // check that at least one uid's email matches pattern exactly,
krista@2057
  2146
                // modulo the email-diff heuristic
edouard@1525
  2147
                while(kuid) {
krista@2681
  2148
                    if((pattern == NULL) ||
krista@2681
  2149
                       (strstr(pattern, "@") == NULL) || // not an email
krista@2681
  2150
                       (kuid->email && _email_heuristic_match(kuid->email, pattern)))
edouard@1760
  2151
                    { 
edouard@1525
  2152
                        char *fpr = key->subkeys->fpr;
edouard@1525
  2153
                        assert(fpr);
edouard@1525
  2154
                        _k = stringlist_add(_k, fpr);
edouard@1525
  2155
                        assert(_k);
edouard@1525
  2156
                        if (_k == NULL){
edouard@1525
  2157
                            free_stringlist(_keylist);
edouard@1525
  2158
                            gpg.gpgme_op_keylist_end(session->ctx);
edouard@1525
  2159
                            return PEP_OUT_OF_MEMORY;
edouard@1525
  2160
                        }
edouard@1525
  2161
                        break;
edouard@1525
  2162
                    }
edouard@1525
  2163
                    kuid = kuid->next;
edouard@1525
  2164
                }
edouard@1525
  2165
                break;
krista@1357
  2166
            case GPG_ERR_ENOMEM:
krista@1357
  2167
                free_stringlist(_keylist);
krista@1357
  2168
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  2169
                return PEP_OUT_OF_MEMORY;
krista@1357
  2170
            default:
krista@1357
  2171
                gpg.gpgme_op_keylist_end(session->ctx);
krista@1357
  2172
                return PEP_UNKNOWN_ERROR;
vb@24
  2173
        };
vb@24
  2174
    } while (gpgme_error != GPG_ERR_EOF);
krista@1426
  2175
vb@74
  2176
    gpg.gpgme_op_keylist_end(session->ctx);
krista@2098
  2177
    if (_keylist->value == NULL) {
vb@523
  2178
        free_stringlist(_keylist);
vb@523
  2179
        _keylist = NULL;
krista@2057
  2180
        
krista@2098
  2181
        if (pattern != NULL) {
krista@2098
  2182
            // If match failed, check to see if we've got a dotted address in the pattern.
krista@2098
  2183
            // (last chance of the heuristic, really)
krista@2098
  2184
            // If so, try again without any dots.
krista@2098
  2185
            const char* dotpos = strstr(pattern, ".");
krista@2098
  2186
            const char* atpos = strstr(pattern, "@");
krista@2098
  2187
            if (dotpos && atpos && (dotpos < atpos)) {
krista@2098
  2188
                char* undotted = _undot_address(pattern);
krista@2098
  2189
                if (undotted) {
krista@2098
  2190
                    PEP_STATUS status = _pgp_search_keys(session, undotted,
krista@2098
  2191
                                                         keylist, private_only);
krista@2098
  2192
                    free(undotted);
krista@2098
  2193
                    return status;
krista@2098
  2194
                }
krista@2057
  2195
            }
krista@2057
  2196
        }
krista@2057
  2197
    }    
krista@2057
  2198
    
vb@24
  2199
    *keylist = _keylist;
vb@24
  2200
    return PEP_STATUS_OK;
vb@24
  2201
}
vb@24
  2202
krista@1357
  2203
PEP_STATUS pgp_find_keys(
krista@1357
  2204
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
krista@1357
  2205
    )
krista@1357
  2206
{
krista@1357
  2207
    return _pgp_search_keys(session, pattern, keylist, 0);
krista@1426
  2208
}
krista@1357
  2209
krista@1357
  2210
PEP_STATUS pgp_find_private_keys(
krista@1357
  2211
    PEP_SESSION session, const char *pattern, stringlist_t **keylist
krista@1357
  2212
)
krista@1357
  2213
{
krista@1357
  2214
    return _pgp_search_keys(session, pattern, keylist, 1);
krista@1357
  2215
}
krista@1357
  2216
vb@2539
  2217
// this function is delivering a list of triples with fpr, email, name of all
vb@2539
  2218
// ultimatedly trusted private keys
vb@2539
  2219
vb@2539
  2220
PEP_STATUS pgp_find_trusted_private_keys(
vb@2539
  2221
        PEP_SESSION session, stringlist_t **keylist
vb@2539
  2222
    )
vb@2539
  2223
{
vb@2539
  2224
    assert(session && keylist);
vb@2539
  2225
    if (!session || !keylist)
krista@2458
  2226
        return PEP_ILLEGAL_VALUE;
krista@2458
  2227
vb@2539
  2228
    *keylist = NULL;
vb@2539
  2229
krista@2416
  2230
    gpgme_key_t key;
krista@2458
  2231
    gpgme_error_t gpgme_error;
vb@2539
  2232
vb@2539
  2233
    stringlist_t *private_keylist = NULL;
vb@2539
  2234
    PEP_STATUS status = pgp_find_private_keys(session, NULL, &private_keylist);
vb@2539
  2235
    if (status)
vb@2539
  2236
        return status;
vb@2539
  2237
    if (!private_keylist || !private_keylist->value)
vb@2539
  2238
        return status;
vb@2539
  2239
vb@2539
  2240
    stringlist_t *result_list = new_stringlist(NULL);
vb@2539
  2241
    if (!result_list)
vb@2539
  2242
        return PEP_OUT_OF_MEMORY;
vb@2539
  2243
    stringlist_t *_result_list = result_list;
vb@2539
  2244
vb@2539
  2245
    stringlist_t *keylist_curr;
vb@2539
  2246
    for (keylist_curr = private_keylist; keylist_curr && keylist_curr->value; keylist_curr = keylist_curr->next) {
vb@2539
  2247
        // a. get key data
vb@2539
  2248
        gpgme_error = gpg.gpgme_get_key(session->ctx, keylist_curr->value, &key, 1);
vb@2539
  2249
        gpgme_error = _GPGERR(gpgme_error);
vb@2539
  2250
        assert(gpgme_error != GPG_ERR_ENOMEM);
vb@2539
  2251
        switch (gpgme_error) {
vb@2539
  2252
            case GPG_ERR_NO_ERROR:
vb@2539
  2253
                break;
vb@2539
  2254
            case GPG_ERR_EOF:
vb@2539
  2255
                status = PEP_KEY_NOT_FOUND;
vb@2539
  2256
                break;
vb@2539
  2257
            case GPG_ERR_INV_VALUE:
vb@2539
  2258
                status = PEP_ILLEGAL_VALUE;
vb@2539
  2259
                break;
vb@2539
  2260
            case GPG_ERR_AMBIGUOUS_NAME:
vb@2539
  2261
                status = PEP_KEY_HAS_AMBIG_NAME;
vb@2539
  2262
                break;
vb@2539
  2263
            case GPG_ERR_ENOMEM:
vb@2539
  2264
                free_stringlist(result_list);
vb@2539
  2265
                free_stringlist(private_keylist);
vb@2539
  2266
                return PEP_OUT_OF_MEMORY;
vb@2539
  2267
            default:
vb@2539
  2268
                assert(0);
vb@2539
  2269
                status = PEP_UNKNOWN_ERROR;
vb@2539
  2270
        }
vb@2539
  2271
        if (key && gpgme_error == GPG_ERR_NO_ERROR) {
vb@2539
  2272
            if (key->revoked || key->disabled) {
vb@2539
  2273
                status = PEP_KEY_UNSUITABLE;
krista@2416
  2274
            }
vb@2539
  2275
            else {
vb@2539
  2276
                if (key->fpr && key->secret && key->can_encrypt && key->can_sign) {
vb@2539
  2277
                    if (key->owner_trust == GPGME_VALIDITY_ULTIMATE &&
vb@2539
  2278
                            key->uids && key->uids->email && key->uids->name) { 
vb@2539
  2279
                        _result_list = stringlist_add(_result_list, key->fpr);
vb@2539
  2280
                        if (!_result_list) {
vb@2539
  2281
                            free_stringlist(result_list);
vb@2539
  2282
                            free_stringlist(private_keylist);
vb@2539
  2283
                            return PEP_OUT_OF_MEMORY;
vb@2539
  2284
                        }
vb@2539
  2285
                        _result_list = stringlist_add(_result_list, key->uids->email);
vb@2539
  2286
                        if (!_result_list) {
vb@2539
  2287
                            free_stringlist(result_list);
vb@2539
  2288
                            free_stringlist(private_keylist);
vb@2539
  2289
                            return PEP_OUT_OF_MEMORY;
vb@2539
  2290
                        }
vb@2539
  2291
                        _result_list = stringlist_add(_result_list, key->uids->name);
vb@2539
  2292
                        if (!_result_list) {
vb@2539
  2293
                            free_stringlist(result_list);
vb@2539
  2294
                            free_stringlist(private_keylist);
vb@2539
  2295
                            return PEP_OUT_OF_MEMORY;
krista@2457
  2296
                        }
krista@2457
  2297
                    }
krista@2457
  2298
                }
krista@2416
  2299
            }
krista@2416
  2300
        }
krista@2416
  2301
    }
vb@2539
  2302
vb@2539
  2303
    free_stringlist(private_keylist);
vb@2539
  2304
    *keylist = result_list;
vb@2539
  2305
    return PEP_STATUS_OK;
krista@2416
  2306
}
krista@2416
  2307
vb@24
  2308
PEP_STATUS pgp_send_key(PEP_SESSION session, const char *pattern)
vb@24
  2309
{
vb@24
  2310
    gpgme_error_t gpgme_error;
vb@24
  2311
vb@24
  2312
    assert(session);
vb@24
  2313
    assert(pattern);
vb@24
  2314
vb@74
  2315
    gpgme_error = gpg.gpgme_op_export(session->ctx, pattern,
vb@24
  2316
        GPGME_EXPORT_MODE_EXTERN, NULL);
vb@45
  2317
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2318
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2319
    if (gpgme_error == GPG_ERR_NO_ERROR)
vb@24
  2320
        return PEP_STATUS_OK;
vb@24
  2321
    else
vb@24
  2322
        return PEP_CANNOT_SEND_KEY;
vb@24
  2323
}
vb@24
  2324
vb@24
  2325
PEP_STATUS pgp_get_key_rating(
vb@24
  2326
    PEP_SESSION session,
vb@24
  2327
    const char *fpr,
vb@24
  2328
    PEP_comm_type *comm_type
vb@24
  2329
    )
vb@24
  2330
{
vb@24
  2331
    PEP_STATUS status = PEP_STATUS_OK;
vb@24
  2332
    gpgme_error_t gpgme_error;
vb@24
  2333
    gpgme_key_t key;
vb@24
  2334
vb@24
  2335
    assert(session);
vb@24
  2336
    assert(fpr);
vb@24
  2337
    assert(comm_type);
vb@24
  2338
vb@24
  2339
    *comm_type = PEP_ct_unknown;
vb@24
  2340
vb@74
  2341
    gpgme_error = gpg.gpgme_op_keylist_start(session->ctx, fpr, 0);
vb@45
  2342
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2343
    switch (gpgme_error) {
vb@24
  2344
    case GPG_ERR_NO_ERROR:
vb@24
  2345
        break;
vb@24
  2346
    case GPG_ERR_INV_VALUE:
vb@24
  2347
        assert(0);
vb@24
  2348
        return PEP_UNKNOWN_ERROR;
vb@24
  2349
    default:
vb@24
  2350
        return PEP_GET_KEY_FAILED;
vb@24
  2351
    };
vb@24
  2352
vb@74
  2353
    gpgme_error = gpg.gpgme_op_keylist_next(session->ctx, &key);
vb@45
  2354
    gpgme_error = _GPGERR(gpgme_error);
vb@24
  2355
    assert(gpgme_error != GPG_ERR_INV_VALUE);
vb@24
  2356
vb@24
  2357
    if (key == NULL) {
vb@74
  2358
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2359
        return PEP_KEY_NOT_FOUND;
vb@24
  2360
    }
vb@24
  2361
vb@24
  2362
    switch (key->protocol) {
vb@24
  2363
    case GPGME_PROTOCOL_OpenPGP:
vb@24
  2364
    case GPGME_PROTOCOL_DEFAULT:
vb@24
  2365
        *comm_type = PEP_ct_OpenPGP_unconfirmed;
vb@24
  2366
        break;
vb@24
  2367
    case GPGME_PROTOCOL_CMS:
vb@24
  2368
        *comm_type = PEP_ct_CMS_unconfirmed;
vb@24
  2369
        break;
vb@24
  2370
    default:
vb@24
  2371
        *comm_type = PEP_ct_unknown;
vb@74
  2372
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2373
        return PEP_STATUS_OK;
vb@24
  2374
    }
vb@24
  2375
vb@24
  2376
    switch (gpgme_error) {
vb@24
  2377
    case GPG_ERR_EOF:
vb@24
  2378
        break;
vb@24
  2379
    case GPG_ERR_NO_ERROR:
vb@24
  2380
        assert(key);
vb@24
  2381
        assert(key->subkeys);
vb@24
  2382
        for (gpgme_subkey_t sk = key->subkeys; sk != NULL; sk = sk->next) {
vb@24
  2383
            if (sk->length < 1024)
vb@24
  2384
                *comm_type = PEP_ct_key_too_short;
vb@24
  2385
            else if (
vb@24
  2386
                (
vb@24
  2387
                (sk->pubkey_algo == GPGME_PK_RSA)
vb@24
  2388
                || (sk->pubkey_algo == GPGME_PK_RSA_E)
vb@24
  2389
                || (sk->pubkey_algo == GPGME_PK_RSA_S)
vb@24
  2390
                )
vb@24
  2391
                && sk->length == 1024
vb@24
  2392
                )
vb@122
  2393
                *comm_type = PEP_ct_OpenPGP_weak_unconfirmed;
vb@24
  2394
vb@24
  2395
            if (sk->invalid) {
vb@24
  2396
                *comm_type = PEP_ct_key_b0rken;
vb@24
  2397
                break;
vb@24
  2398
            }
vb@24
  2399
            if (sk->expired) {
vb@24
  2400
                *comm_type = PEP_ct_key_expired;
vb@24
  2401
                break;
vb@24
  2402
            }
vb@24
  2403
            if (sk->revoked) {
vb@24
  2404
                *comm_type = PEP_ct_key_revoked;
vb@24
  2405
                break;
vb@24
  2406
            }
vb@24
  2407
        }
vb@24
  2408
        break;
vb@24
  2409
    case GPG_ERR_ENOMEM:
vb@74
  2410
        gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2411
        *comm_type = PEP_ct_unknown;
vb@24
  2412
        return PEP_OUT_OF_MEMORY;
vb@24
  2413
    default:
vb@74
  2414
        gpg.gpgme_op_keylist_end(session->ctx);
vb@46
  2415
        return PEP_UNKNOWN_ERROR;
vb@24
  2416
    };
vb@24
  2417
vb@74
  2418
    gpg.gpgme_op_keylist_end(session->ctx);
vb@24
  2419
vb@24
  2420
    return status;
vb@24
  2421
}
vb@200
  2422
vb@200
  2423
krista@1924
  2424
static ssize_t _nullwriter(
krista@1924
  2425
        void *_handle,
krista@1924
  2426
        const void *buffer,
krista@1924
  2427
        size_t size
krista@1924
  2428
    )
krista@1924
  2429
{
krista@1924
  2430
    return size;
krista@1924
  2431
}
krista@1924
  2432
krista@1924
  2433
typedef struct _replace_only_uid_state {
krista@1924
  2434
    enum {
krista@1924
  2435
        replace_uid_command = 0,
krista@1924
  2436
        replace_uid_realname,
krista@1924
  2437
        replace_uid_email,
kgrothoff@1926
  2438
        replace_uid_comment,
krista@1924
  2439
        replace_uid_adduid_ok,
krista@1924
  2440
        replace_uid_select_for_delete,
krista@1924
  2441
        replace_uid_delete,
krista@1924
  2442
        replace_uid_delete_confirm,
krista@1924
  2443
        replace_uid_select_for_trust,
krista@1924
  2444
        replace_uid_trust,
krista@1924
  2445
        replace_uid_trust_ultimate,
krista@1924
  2446
        replace_uid_trust_ultimate_confirm,
krista@1924
  2447
        replace_uid_quit,
krista@1924
  2448
        replace_uid_save_okay,
krista@1924
  2449
        replace_uid_exit,
krista@1924
  2450
        replace_uid_error = -1
krista@1924
  2451
    } state;
krista@1924
  2452
const char *realname;
krista@1924
  2453
const char *email;
krista@1924
  2454
} replace_only_uid_state;
krista@1924
  2455
kgrothoff@1926
  2456
krista@1924
  2457
static gpgme_error_t replace_only_uid_fsm(
krista@1924
  2458
    void *_handle,
krista@1924
  2459
    gpgme_status_code_t statuscode,
krista@1924
  2460
    const char *args,
krista@1924
  2461
    int fd
krista@1924
  2462
)
krista@1924
  2463
{
krista@1924
  2464
    replace_only_uid_state *handle = _handle;
krista@1924
  2465
        
krista@1924
  2466
    switch (handle->state) {
krista@1924
  2467
        case replace_uid_command:
krista@1924
  2468
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2469
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2470
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2471
                    handle->state = replace_uid_error;
krista@1924
  2472
                    return GPG_ERR_GENERAL;
krista@1924
  2473
                }
krista@1924
  2474
                gpg.gpgme_io_write(fd, "adduid\n", 7);
krista@1924
  2475
                handle->state = replace_uid_realname;
krista@1924
  2476
            }
krista@1924
  2477
            break;
krista@1924
  2478
            
krista@1924
  2479
        case replace_uid_realname:
krista@1924
  2480
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2481
                assert(strcmp(args, "keygen.name") == 0);
krista@1924
  2482
                assert(handle->realname);
krista@1924
  2483
                if (strcmp(args, "keygen.name") || !handle->realname) {
krista@1924
  2484
                    handle->state = replace_uid_error;
krista@1924
  2485
                    return GPG_ERR_GENERAL;
krista@1924
  2486
                }
krista@1924
  2487
                size_t realname_strlen = strlen(handle->realname);
krista@1924
  2488
                char* realname = (char*)calloc(1, realname_strlen + 2); // \n + \0
krista@1924
  2489
                if (!realname) {
krista@1924
  2490
                    handle->state = replace_uid_error;
krista@1924
  2491
                    return GPG_ERR_ENOMEM;
krista@1924
  2492
                }
kgrothoff@1926
  2493
                strlcpy(realname, handle->realname, realname_strlen + 1);
roker@2055
  2494
                realname[realname_strlen] = '\n';
krista@1924
  2495
                gpg.gpgme_io_write(fd, realname, realname_strlen + 1);
krista@1924
  2496
                handle->state = replace_uid_email;
krista@1924
  2497
                free(realname);
krista@1924
  2498
            }
krista@1924
  2499
            break;
krista@1924
  2500
            
krista@1924
  2501
        case replace_uid_email:
krista@1924
  2502
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2503
                assert(strcmp(args, "keygen.email") == 0);
krista@1924
  2504
                assert(handle->email);
krista@1924
  2505
                if (strcmp(args, "keygen.email") || !handle->email) {
krista@1924
  2506
                    handle->state = replace_uid_error;
krista@1924
  2507
                    return GPG_ERR_GENERAL;
krista@1924
  2508
                }
krista@1924
  2509
                size_t email_strlen = strlen(handle->email);
krista@1924
  2510
                char* email = (char*)calloc(1, email_strlen + 2); // \n + \0
krista@1924
  2511
                if (!email) {
krista@1924
  2512
                    handle->state = replace_uid_error;
krista@1924
  2513
                    return GPG_ERR_ENOMEM;
krista@1924
  2514
                }
kgrothoff@1926
  2515
                strlcpy(email, handle->email, email_strlen + 1);
roker@2055
  2516
                email[email_strlen] = '\n';
krista@1924
  2517
                gpg.gpgme_io_write(fd, email, email_strlen + 1);
kgrothoff@1926
  2518
                handle->state = replace_uid_comment;
krista@1924
  2519
                free(email);
krista@1924
  2520
            }
krista@1924
  2521
            break;
krista@1924
  2522
kgrothoff@1926
  2523
        case replace_uid_comment:
kgrothoff@1926
  2524
            if (statuscode == GPGME_STATUS_GET_LINE) {
kgrothoff@1926
  2525
                assert(strcmp(args, "keygen.comment") == 0);
kgrothoff@1926
  2526
                if (strcmp(args, "keygen.comment") || !handle->email) {
kgrothoff@1926
  2527
                    handle->state = replace_uid_error;
kgrothoff@1926
  2528
                    return GPG_ERR_GENERAL;
kgrothoff@1926
  2529
                }
kgrothoff@1926
  2530
                gpg.gpgme_io_write(fd, "\n", 1);
kgrothoff@1926
  2531
                //handle->state = replace_uid_adduid_ok;
kgrothoff@1926
  2532
                handle->state = replace_uid_select_for_delete;
kgrothoff@1926
  2533
            }
kgrothoff@1926
  2534
            break;
kgrothoff@1926
  2535
/*
krista@1924
  2536
        case replace_uid_adduid_ok:
krista@1924
  2537
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2538
                assert(strcmp(args, "keygen.userid.cmd") == 0);
krista@1924
  2539
                if (strcmp(args, "keygen.userid.cmd")) {
krista@1924
  2540
                    handle->state = replace_uid_error;
krista@1924
  2541
                    return GPG_ERR_GENERAL;
krista@1924
  2542
                }
krista@1924
  2543
                gpg.gpgme_io_write(fd, "O\n", 2);
krista@1924
  2544
                handle->state = replace_uid_select_for_delete;
krista@1924
  2545
            }
krista@1924
  2546
            break;
kgrothoff@1926
  2547
	    */
krista@1924
  2548
krista@1924
  2549
        case replace_uid_select_for_delete:
krista@1924
  2550
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2551
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2552
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2553
                    handle->state = replace_uid_error;
krista@1924
  2554
                    return GPG_ERR_GENERAL;
krista@1924
  2555
                }
krista@1924
  2556
                gpg.gpgme_io_write(fd, "uid 1\n", 6);
krista@1924
  2557
                handle->state = replace_uid_delete;
krista@1924
  2558
            }
krista@1924
  2559
            break;
krista@1924
  2560
krista@1924
  2561
        case replace_uid_delete:
krista@1924
  2562
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2563
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2564
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2565
                    handle->state = replace_uid_error;
krista@1924
  2566
                    return GPG_ERR_GENERAL;
krista@1924
  2567
                }
krista@1924
  2568
                gpg.gpgme_io_write(fd, "deluid\n", 7);
krista@1924
  2569
                handle->state = replace_uid_delete_confirm;
krista@1924
  2570
            }
krista@1924
  2571
            break;
krista@1924
  2572
krista@1924
  2573
        case replace_uid_delete_confirm:
kgrothoff@1926
  2574
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2575
                assert(strcmp(args, "keyedit.remove.uid.okay") == 0);
krista@1924
  2576
                if (strcmp(args, "keyedit.remove.uid.okay")) {
krista@1924
  2577
                    handle->state = replace_uid_error;
krista@1924
  2578
                    return GPG_ERR_GENERAL;
krista@1924
  2579
                }
krista@1924
  2580
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2581
                handle->state = replace_uid_select_for_trust;
krista@1924
  2582
            }
krista@1924
  2583
            break;
krista@1924
  2584
krista@1924
  2585
        case replace_uid_select_for_trust:
krista@1924
  2586
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2587
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2588
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2589
                    handle->state = replace_uid_error;
krista@1924
  2590
                    return GPG_ERR_GENERAL;
krista@1924
  2591
                }
kgrothoff@1926
  2592
                gpg.gpgme_io_write(fd, "uid 1\n", 6);
krista@1924
  2593
                handle->state = replace_uid_trust;
krista@1924
  2594
            }
krista@1924
  2595
            break;
krista@1924
  2596
krista@1924
  2597
        case replace_uid_trust:
krista@1924
  2598
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2599
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2600
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2601
                    handle->state = replace_uid_error;
krista@1924
  2602
                    return GPG_ERR_GENERAL;
krista@1924
  2603
                }
kgrothoff@1926
  2604
                gpg.gpgme_io_write(fd, "trust\n", 6);
krista@1924
  2605
                handle->state = replace_uid_trust_ultimate;
krista@1924
  2606
            }
krista@1924
  2607
            break;
krista@1924
  2608
krista@1924
  2609
        case replace_uid_trust_ultimate:
krista@1924
  2610
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2611
                assert(strcmp(args, "edit_ownertrust.value") == 0);
krista@1924
  2612
                if (strcmp(args, "edit_ownertrust.value")) {
krista@1924
  2613
                    handle->state = replace_uid_error;
krista@1924
  2614
                    return GPG_ERR_GENERAL;
krista@1924
  2615
                }
krista@1924
  2616
                gpg.gpgme_io_write(fd, "5\n", 2);
krista@1924
  2617
                handle->state = replace_uid_trust_ultimate_confirm;
krista@1924
  2618
            }
krista@1924
  2619
            break;
krista@1924
  2620
krista@1924
  2621
        case replace_uid_trust_ultimate_confirm:
kgrothoff@1926
  2622
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2623
                assert(strcmp(args, "edit_ownertrust.set_ultimate.okay") == 0);
krista@1924
  2624
                if (strcmp(args, "edit_ownertrust.set_ultimate.okay")) {
krista@1924
  2625
                    handle->state = replace_uid_error;
krista@1924
  2626
                    return GPG_ERR_GENERAL;
krista@1924
  2627
                }
krista@1924
  2628
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2629
                handle->state = replace_uid_quit;
krista@1924
  2630
            }
krista@1924
  2631
            break;
krista@1924
  2632
krista@1924
  2633
        case replace_uid_quit:
krista@1924
  2634
            if (statuscode == GPGME_STATUS_GET_LINE) {
krista@1924
  2635
                assert(strcmp(args, "keyedit.prompt") == 0);
krista@1924
  2636
                if (strcmp(args, "keyedit.prompt")) {
krista@1924
  2637
                    handle->state = replace_uid_error;
krista@1924
  2638
                    return GPG_ERR_GENERAL;
krista@1924
  2639
                }
krista@1924
  2640
                gpg.gpgme_io_write(fd, "quit\n", 5);
krista@1924
  2641
                handle->state = replace_uid_save_okay;
krista@1924
  2642
            }
krista@1924
  2643
            break;
krista@1924
  2644
krista@1924
  2645
        case replace_uid_save_okay:
kgrothoff@1926
  2646
            if (statuscode == GPGME_STATUS_GET_BOOL) {
krista@1924
  2647
                assert(strcmp(args, "keyedit.save.okay") == 0);
krista@1924
  2648
                if (strcmp(args, "keyedit.save.okay")) {
krista@1924
  2649
                    handle->state = replace_uid_error;
krista@1924
  2650
                    return GPG_ERR_GENERAL;
krista@1924
  2651
                }
krista@1924
  2652
                gpg.gpgme_io_write(fd, "Y\n", 2);
krista@1924
  2653
                handle->state = replace_uid_exit;
krista@1924
  2654
            }
krista@1924
  2655
            break;
krista@1924
  2656
krista@1924
  2657
        case replace_uid_exit:
krista@1924
  2658
            break;
krista@1924 </