CpEpEngine.cpp
author Markus Schaber <markus@pep-security.net>
Sat, 13 Jan 2018 14:02:03 +0100
branchCOM-74
changeset 267 ae02fcd56811
parent 264 aa6bd84bd6c3
child 270 c713a265866f
permissions -rw-r--r--
COM-74: Expose _PEP_enc_format to app for EncryptMessage
vb@0
     1
// CpEpEngine.cpp : Implementation of CpEpEngine
vb@0
     2
vb@0
     3
#include "stdafx.h"
vb@0
     4
#include "CpEpEngine.h"
krista@261
     5
#include <mutex>
vb@0
     6
vb@10
     7
using namespace std;
vb@10
     8
using namespace pEp::utility;
vb@0
     9
vb@0
    10
// CpEpEngine
krista@261
    11
std::mutex CpEpEngine::init_mutex;
vb@0
    12
vb@0
    13
STDMETHODIMP CpEpEngine::InterfaceSupportsErrorInfo(REFIID riid)
vb@0
    14
{
markus@234
    15
    static const IID* const arr[] =
markus@234
    16
    {
markus@234
    17
        &IID_IpEpEngine,
markus@233
    18
        &IID_IpEpEngine2,
markus@234
    19
    };
vb@0
    20
markus@234
    21
    for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
markus@234
    22
    {
markus@234
    23
        if (InlineIsEqualGUID(*arr[i], riid))
markus@234
    24
            return S_OK;
markus@234
    25
    }
markus@234
    26
    return S_FALSE;
vb@0
    27
}
vb@0
    28
markus@189
    29
// The second argument is optional, and currently supports PEP_STATUS.
markus@189
    30
#define FAIL(msg, ...) error(msg, __VA_ARGS__)
vb@0
    31
markus@172
    32
STDMETHODIMP CpEpEngine::VerboseLogging(VARIANT_BOOL enable)
vb@51
    33
{
markus@234
    34
    verbose_mode = enable != VARIANT_FALSE;
markus@234
    35
    return S_OK;
vb@60
    36
}
vb@60
    37
markus@172
    38
STDMETHODIMP CpEpEngine::PassiveMode(VARIANT_BOOL enable)
vb@60
    39
{
markus@234
    40
    ::config_passive_mode(get_session(), enable != VARIANT_FALSE);
markus@234
    41
    return S_OK;
vb@60
    42
}
vb@60
    43
markus@172
    44
STDMETHODIMP CpEpEngine::UnencryptedSubject(VARIANT_BOOL enable)
vb@60
    45
{
markus@234
    46
    ::config_unencrypted_subject(get_session(), enable != VARIANT_FALSE);
markus@234
    47
    return S_OK;
vb@51
    48
}
vb@0
    49
Dean@184
    50
STDMETHODIMP CpEpEngine::ExportKey(BSTR fpr, BSTR * keyData)
Dean@183
    51
{
Dean@183
    52
    assert(fpr);
Dean@185
    53
    assert(keyData);
Dean@183
    54
markus@192
    55
    if (!(fpr && keyData))
Dean@183
    56
        return E_INVALIDARG;
Dean@183
    57
Dean@183
    58
    string _fpr = utf8_string(fpr);
Dean@183
    59
    char *_key_data = NULL;
Dean@183
    60
    size_t _size = 0;
Dean@183
    61
Dean@183
    62
    ::PEP_STATUS status = ::export_key(get_session(), _fpr.c_str(), &_key_data, &_size);
Dean@183
    63
    assert(status != ::PEP_OUT_OF_MEMORY);
Dean@183
    64
    if (status == ::PEP_OUT_OF_MEMORY)
Dean@183
    65
        return E_OUTOFMEMORY;
Dean@183
    66
Dean@183
    67
    if (status != ::PEP_STATUS_OK)
markus@189
    68
        return FAIL(L"export_key", status);
Dean@183
    69
Dean@183
    70
    _bstr_t b_key_data(utf16_string(_key_data).c_str());
Dean@183
    71
    pEp_free(_key_data);
markus@234
    72
    *keyData = b_key_data.Detach();
Dean@183
    73
Dean@183
    74
    return S_OK;
Dean@183
    75
}
Dean@183
    76
markus@177
    77
STDMETHODIMP CpEpEngine::Log(BSTR title, BSTR entity, BSTR description, BSTR comment)
vb@0
    78
{
markus@234
    79
    string _title;
markus@234
    80
    string _entity;
markus@234
    81
    string _description;
markus@234
    82
    string _comment;
markus@234
    83
    HRESULT result = S_OK;
vb@0
    84
markus@234
    85
    assert(title);
markus@234
    86
    if (title)
markus@234
    87
        _title = utf8_string(title);
markus@234
    88
    else
markus@234
    89
        result = E_INVALIDARG;
vb@0
    90
markus@234
    91
    assert(entity);
markus@234
    92
    if (entity)
markus@234
    93
        _entity = utf8_string(entity);
markus@234
    94
    else
markus@234
    95
        result = E_INVALIDARG;
vb@0
    96
markus@234
    97
    if (description)
markus@234
    98
        _description = utf8_string(description);
vb@0
    99
markus@234
   100
    if (comment)
markus@234
   101
        _comment = utf8_string(comment);
vb@0
   102
markus@234
   103
    if (result != S_OK)
markus@234
   104
        return result;
vb@0
   105
markus@234
   106
    PEP_STATUS _status = ::log_event(get_session(), _title.c_str(), _entity.c_str(), _description.c_str(), _comment.c_str());
markus@234
   107
    assert(_status == PEP_STATUS_OK);
markus@234
   108
    if (_status != PEP_STATUS_OK)
markus@234
   109
        return FAIL(L"log_event", _status);
markus@234
   110
    else
markus@234
   111
        return S_OK;
vb@0
   112
}
vb@0
   113
Dean@202
   114
STDMETHODIMP CpEpEngine::Trustwords(BSTR fpr, BSTR lang, LONG max_words, BSTR * words)
vb@0
   115
{
markus@234
   116
    assert(fpr);
markus@234
   117
    assert(max_words >= 0);
markus@234
   118
    assert(words);
vb@0
   119
markus@234
   120
    HRESULT result = S_OK;
vb@0
   121
markus@234
   122
    string _fpr;
markus@234
   123
    if (fpr)
markus@234
   124
        _fpr = utf8_string(fpr);
markus@234
   125
    else
markus@234
   126
        result = E_INVALIDARG;
vb@0
   127
markus@234
   128
    string _lang;
markus@234
   129
    if (lang) {
markus@234
   130
        _lang = utf8_string(lang);
markus@234
   131
        if (_lang.length()) {
markus@234
   132
            if (_lang.length() != 2)
markus@234
   133
                result = E_INVALIDARG;
markus@234
   134
        }
markus@234
   135
        else
markus@234
   136
            _lang = "en";
markus@234
   137
    }
markus@234
   138
    else
markus@234
   139
        _lang = "en";
vb@0
   140
markus@234
   141
    if (max_words < 0)
markus@234
   142
        result = E_INVALIDARG;
vb@0
   143
markus@234
   144
    if (words == NULL)
markus@234
   145
        result = E_INVALIDARG;
vb@0
   146
markus@234
   147
    if (result != S_OK)
markus@234
   148
        return result;
vb@0
   149
markus@234
   150
    char *_words = NULL;
markus@234
   151
    size_t _wsize = 0;
vb@0
   152
markus@234
   153
    PEP_STATUS status = ::trustwords(get_session(), _fpr.c_str(), _lang.c_str(), &_words, &_wsize, max_words);
markus@234
   154
    assert(status != PEP_OUT_OF_MEMORY);
markus@234
   155
    if (status == PEP_OUT_OF_MEMORY)
markus@234
   156
        return E_OUTOFMEMORY;
vb@0
   157
markus@234
   158
    if (_words == NULL) {
markus@234
   159
        *words = NULL;
markus@234
   160
        return FAIL(L"Trustwords: _words == NULL", status);
markus@234
   161
    }
markus@234
   162
    else {
markus@234
   163
        *words = utf16_bstr(_words);
markus@234
   164
        pEp_free(_words);
markus@234
   165
        return S_OK;
markus@234
   166
    }
vb@0
   167
}
vb@0
   168
Dean@202
   169
STDMETHODIMP CpEpEngine::GetTrustwords(struct pEpIdentity *id1, struct pEpIdentity *id2, BSTR lang, VARIANT_BOOL full, BSTR *words)
markus@190
   170
{
markus@190
   171
    assert(id1);
markus@190
   172
    assert(id2);
markus@190
   173
    assert(words);
markus@190
   174
markus@192
   175
    if (!(id1 && id2 && words))
markus@190
   176
    {
markus@190
   177
        return E_INVALIDARG;
markus@190
   178
    }
markus@190
   179
markus@190
   180
    HRESULT result = S_OK;
markus@190
   181
markus@190
   182
    pEp_identity* _id1 = NULL;
markus@190
   183
    pEp_identity* _id2 = NULL;
markus@190
   184
    string _lang;
markus@190
   185
    *words = NULL;
markus@190
   186
markus@190
   187
    try {
markus@190
   188
        _id1 = new_identity(id1);
markus@190
   189
        _id2 = new_identity(id2);
markus@190
   190
Thomas@230
   191
        if (lang) {
markus@190
   192
            _lang = utf8_string(lang);
markus@190
   193
            if (_lang.length() == 0) {
markus@190
   194
                _lang = "en";
markus@234
   195
            }
markus@234
   196
            else if (_lang.length() != 2) {
markus@190
   197
                result = E_INVALIDARG;
markus@190
   198
            }
markus@234
   199
        }
markus@234
   200
        else {
markus@190
   201
            _lang = "en";
markus@190
   202
        }
markus@234
   203
    }
markus@234
   204
    catch (bad_alloc&) {
markus@190
   205
        result = E_OUTOFMEMORY;
markus@234
   206
    }
markus@234
   207
    catch (exception& ex) {
markus@190
   208
        result = FAIL(ex.what());
markus@190
   209
    }
markus@190
   210
markus@190
   211
    char* _words;
markus@190
   212
    size_t _size;
Dean@203
   213
    if (result == S_OK) {
markus@190
   214
        auto status = ::get_trustwords(get_session(), _id1, _id2, _lang.c_str(), &_words, &_size, full != 0 /* convert variant bool to C bool */);
markus@190
   215
markus@190
   216
        if (status == PEP_OUT_OF_MEMORY) {
markus@190
   217
            result = E_OUTOFMEMORY;
markus@190
   218
        }
markus@190
   219
        else if (status == PEP_TRUSTWORD_NOT_FOUND) {
Dean@202
   220
            result = FAIL(L"GetTrustwords: Trustword not found", status);
markus@190
   221
        }
markus@190
   222
        else if (!words) {
Dean@202
   223
            result = FAIL(L"GetTrustwords: _words == NULL", status);
markus@190
   224
        }
markus@190
   225
        else {
markus@190
   226
            *words = utf16_bstr(_words);
markus@190
   227
            pEp_free(_words);
markus@190
   228
        }
markus@190
   229
    }
markus@190
   230
markus@190
   231
    free_identity(_id1);
markus@190
   232
    free_identity(_id2);
markus@190
   233
markus@190
   234
    return result;
markus@190
   235
}
markus@190
   236
markus@232
   237
STDMETHODIMP CpEpEngine::GetMessageTrustwords(
markus@232
   238
    /* [in] */ struct TextMessage *msg,
markus@232
   239
    /* [in] */ struct pEpIdentity *receivedBy,
markus@232
   240
    /* [in] */ SAFEARRAY *keylist,
markus@232
   241
    /* [defaultvalue][in] */ BSTR lang,
markus@232
   242
    /* [defaultvalue][in] */ VARIANT_BOOL full,
markus@232
   243
    /* [retval][out] */ BSTR *words) {
markus@232
   244
    assert(msg);
markus@232
   245
    assert(receivedBy);
markus@232
   246
    assert(words);
markus@232
   247
markus@232
   248
    if (!(msg && receivedBy && words))
markus@232
   249
    {
markus@232
   250
        return E_INVALIDARG;
markus@232
   251
    }
markus@232
   252
markus@232
   253
    HRESULT result = S_OK;
markus@232
   254
markus@232
   255
    pEp_identity * _received_by = NULL;
markus@232
   256
    ::message * _msg = NULL;
markus@232
   257
    ::stringlist_t *_keylist = NULL;
markus@232
   258
    string _lang;
markus@232
   259
    *words = NULL;
markus@232
   260
markus@232
   261
    try {
markus@232
   262
        _received_by = new_identity(receivedBy);
markus@232
   263
        _msg = text_message_to_C(msg);
markus@232
   264
markus@232
   265
        if (keylist) {
markus@232
   266
            _keylist = new_stringlist(keylist);
markus@232
   267
        }
markus@232
   268
markus@232
   269
        if (lang) {
markus@232
   270
            _lang = utf8_string(lang);
markus@232
   271
            if (_lang.length() == 0) {
markus@232
   272
                _lang = "en";
markus@232
   273
            }
markus@232
   274
            else if (_lang.length() != 2) {
markus@232
   275
                result = E_INVALIDARG;
markus@232
   276
            }
markus@232
   277
        }
markus@232
   278
        else {
markus@232
   279
            _lang = "en";
markus@232
   280
        }
markus@232
   281
    }
markus@232
   282
    catch (bad_alloc&) {
markus@232
   283
        result = E_OUTOFMEMORY;
markus@232
   284
    }
markus@232
   285
    catch (exception& ex) {
markus@232
   286
        result = FAIL(ex.what());
markus@232
   287
    }
markus@232
   288
markus@232
   289
    char* _words = NULL;
markus@232
   290
    if (result == S_OK) {
markus@232
   291
        auto status = ::get_message_trustwords(
markus@232
   292
            get_session(),
markus@232
   293
            _msg,
markus@232
   294
            _keylist,
markus@232
   295
            _received_by,
markus@232
   296
            _lang.c_str(),
markus@232
   297
            &_words,
markus@232
   298
            full != 0 /* convert variant bool to C bool */);
markus@232
   299
markus@232
   300
        if (status == PEP_OUT_OF_MEMORY) {
markus@232
   301
            result = E_OUTOFMEMORY;
markus@232
   302
        }
markus@232
   303
        else if (status == PEP_TRUSTWORD_NOT_FOUND) {
markus@232
   304
            result = FAIL(L"GetTrustwords: Trustword not found", status);
markus@232
   305
        }
markus@232
   306
        else if (!words) {
markus@232
   307
            result = FAIL(L"GetTrustwords: _words == NULL", status);
markus@232
   308
        }
markus@232
   309
        else {
markus@232
   310
            *words = utf16_bstr(_words);
markus@232
   311
        }
markus@232
   312
    }
markus@232
   313
markus@232
   314
    ::pEp_free(_words);
markus@232
   315
    ::free_message(_msg);
markus@232
   316
    ::free_stringlist(_keylist);
markus@232
   317
    ::free_identity(_received_by);
markus@232
   318
markus@232
   319
    return result;
markus@232
   320
}
markus@190
   321
markus@172
   322
STDMETHODIMP CpEpEngine::GetCrashdumpLog(LONG maxlines, BSTR * log)
vb@57
   323
{
markus@234
   324
    // COM-18: Currently, long == int on windows, so the check
markus@234
   325
    // for INT_MAX is not strictly necessary. However, the code
markus@234
   326
    // might get copy-pasted to other adapters in the future,
markus@234
   327
    // so safety first...
markus@234
   328
    assert(maxlines >= 0 && maxlines <= INT_MAX);
markus@234
   329
    assert(log);
vb@57
   330
markus@234
   331
    if (!(maxlines >= 0 && maxlines <= INT_MAX && log))
markus@234
   332
        return E_INVALIDARG;
vb@57
   333
markus@234
   334
    char *_log;
markus@234
   335
    PEP_STATUS status = ::get_crashdump_log(get_session(), (int)maxlines, &_log);
markus@234
   336
    assert(status == PEP_STATUS_OK);
markus@234
   337
    if (status == PEP_OUT_OF_MEMORY)
markus@234
   338
        return E_OUTOFMEMORY;
markus@234
   339
    if (status != PEP_STATUS_OK)
markus@234
   340
        return FAIL(L"GetCrashdumpLog", status);
markus@189
   341
    if (_log == NULL)
markus@189
   342
        return FAIL(L"GetCrashdumpLog: _log == NULL");
vb@57
   343
markus@234
   344
    *log = utf16_bstr(_log);
markus@234
   345
    pEp_free(_log);
markus@234
   346
    return S_OK;
vb@57
   347
}
vb@57
   348
markus@172
   349
STDMETHODIMP CpEpEngine::GetEngineVersion(BSTR * engine_version)
Dean@151
   350
{
markus@234
   351
    assert(engine_version);
Dean@151
   352
markus@234
   353
    if (!engine_version)
markus@234
   354
        return E_INVALIDARG;
Dean@151
   355
markus@234
   356
    const char *_engine_version = ::get_engine_version();
Dean@151
   357
markus@234
   358
    if (_engine_version == NULL)
markus@234
   359
        return FAIL(L"GetEngineVersion: _engine_version == NULL");
Dean@151
   360
markus@234
   361
    *engine_version = utf16_bstr(_engine_version);
Dean@151
   362
markus@234
   363
    return S_OK;
Dean@151
   364
}
Dean@151
   365
markus@177
   366
STDMETHODIMP CpEpEngine::GetLanguageList(BSTR * languages)
vb@59
   367
{
markus@234
   368
    assert(languages);
vb@59
   369
markus@234
   370
    if (!languages)
markus@234
   371
        return E_INVALIDARG;
vb@59
   372
markus@234
   373
    char *_languages;
markus@234
   374
    PEP_STATUS status = ::get_languagelist(get_session(), &_languages);
markus@234
   375
    assert(status == PEP_STATUS_OK);
markus@234
   376
    if (status == PEP_OUT_OF_MEMORY)
markus@234
   377
        return E_OUTOFMEMORY;
markus@189
   378
    if (status != PEP_STATUS_OK)
markus@189
   379
        return FAIL(L"GetLanguageList", status);
markus@234
   380
    if (_languages == NULL)
markus@234
   381
        return FAIL(L"GetLanguageList: _languages == NULL");
vb@59
   382
markus@234
   383
    *languages = utf16_bstr(_languages);
markus@234
   384
    pEp_free(_languages);
markus@234
   385
    return S_OK;
vb@59
   386
}
vb@59
   387
vb@219
   388
STDMETHODIMP CpEpEngine::SetIdentityFlags(struct pEpIdentity *identity, pEpIdentityFlags flags)
vb@218
   389
{
markus@234
   390
    assert(identity);
markus@234
   391
    if (!identity)
markus@234
   392
        return E_INVALIDARG;
vb@219
   393
markus@234
   394
    ::pEp_identity *_ident = nullptr;
vb@218
   395
markus@234
   396
    try {
markus@234
   397
        _ident = new_identity(identity);
markus@234
   398
        assert(_ident);
markus@234
   399
        if (_ident == NULL)
markus@234
   400
            return E_OUTOFMEMORY;
markus@234
   401
    }
markus@234
   402
    catch (bad_alloc&) {
markus@234
   403
        return E_OUTOFMEMORY;
markus@234
   404
    }
markus@234
   405
    catch (exception& ex) {
markus@234
   406
        return FAIL(ex.what());;
markus@234
   407
    }
vb@218
   408
markus@234
   409
    PEP_STATUS status = ::set_identity_flags(get_session(), _ident, (identity_flags_t)flags);
markus@234
   410
    ::free_identity(_ident);
markus@234
   411
    if (status != PEP_STATUS_OK)
markus@234
   412
        return FAIL(_T("SetIdentityFlags"), status);
vb@218
   413
markus@234
   414
    return S_OK;
vb@218
   415
}
vb@218
   416
vb@219
   417
STDMETHODIMP CpEpEngine::UnsetIdentityFlags(struct pEpIdentity *identity, pEpIdentityFlags flags)
vb@218
   418
{
markus@234
   419
    assert(identity);
markus@234
   420
    if (!identity)
markus@234
   421
        return E_INVALIDARG;
vb@219
   422
markus@234
   423
    ::pEp_identity *_ident = nullptr;
vb@218
   424
markus@234
   425
    try {
markus@234
   426
        _ident = new_identity(identity);
markus@234
   427
        assert(_ident);
markus@234
   428
        if (_ident == NULL)
markus@234
   429
            return E_OUTOFMEMORY;
markus@234
   430
    }
markus@234
   431
    catch (bad_alloc&) {
markus@234
   432
        return E_OUTOFMEMORY;
markus@234
   433
    }
markus@234
   434
    catch (exception& ex) {
markus@234
   435
        return FAIL(ex.what());;
markus@234
   436
    }
vb@218
   437
markus@234
   438
    PEP_STATUS status = ::unset_identity_flags(get_session(), _ident, (identity_flags_t)flags);
markus@234
   439
    ::free_identity(_ident);
markus@234
   440
    if (status != PEP_STATUS_OK)
markus@234
   441
        return FAIL(_T("UnsetIdentityFlags"), status);
vb@218
   442
markus@234
   443
    return S_OK;
vb@218
   444
}
vb@218
   445
markus@172
   446
STDMETHODIMP CpEpEngine::StartKeyserverLookup()
vb@24
   447
{
markus@234
   448
    if (identity_queue.load())
markus@234
   449
        return S_OK;
vb@24
   450
markus@234
   451
    identity_queue.store(new identity_queue_t());
markus@234
   452
    keymanagement_thread = new thread(::do_keymanagement, retrieve_next_identity, (void *)identity_queue.load());
markus@165
   453
markus@234
   454
    return S_OK;
vb@24
   455
}
vb@24
   456
markus@172
   457
STDMETHODIMP CpEpEngine::StopKeyserverLookup()
vb@24
   458
{
markus@234
   459
    if (identity_queue.load() == NULL)
markus@234
   460
        return S_OK;
vb@24
   461
markus@234
   462
    identity_queue_t *_iq = identity_queue.load();
markus@234
   463
    identity_queue.store(NULL);
vb@25
   464
markus@234
   465
    pEp_identity_cpp shutdown;
markus@234
   466
    _iq->push_front(shutdown);
vb@24
   467
markus@234
   468
    keymanagement_thread->join();
markus@234
   469
    delete keymanagement_thread;
markus@234
   470
    keymanagement_thread = NULL;
vb@24
   471
markus@234
   472
    delete _iq;
vb@24
   473
markus@234
   474
    return S_OK;
vb@24
   475
}
vb@24
   476
markus@172
   477
STDMETHODIMP CpEpEngine::Myself(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@0
   478
{
markus@234
   479
    assert(ident);
markus@234
   480
    assert(result);
vb@0
   481
markus@234
   482
    if (!(ident && result))
markus@234
   483
        return E_INVALIDARG;
vb@0
   484
markus@234
   485
    ::pEp_identity *_ident = 0;
markus@196
   486
markus@234
   487
    try {
markus@234
   488
        _ident = new_identity(ident);
markus@234
   489
        assert(_ident);
markus@234
   490
        if (_ident == NULL)
markus@234
   491
            return E_OUTOFMEMORY;
markus@234
   492
    }
markus@234
   493
    catch (bad_alloc&) {
markus@234
   494
        return E_OUTOFMEMORY;
markus@234
   495
    }
markus@234
   496
    catch (exception& ex) {
markus@234
   497
        return FAIL(ex.what());;
markus@234
   498
    }
vb@0
   499
markus@84
   500
markus@234
   501
    // DEBUG CODE - REMOVE BEFORE RELEASE!
markus@234
   502
    // SyncHandshakeResult handshakeResult;
markus@234
   503
    //
markus@234
   504
    // HRESULT res = Fire_NotifyHandshake(ident, result, signal, &handshakeResult);
markus@234
   505
    // 
markus@234
   506
    // HRESULT res2 = Fire_TestEvent(15, _bstr_t( "hallo"));
vb@0
   507
markus@234
   508
    PEP_STATUS status = ::myself(get_session(), _ident);
markus@234
   509
markus@234
   510
    if (status == PEP_STATUS_OK) {
markus@234
   511
        assert(_ident->fpr);
markus@234
   512
        copy_identity(result, _ident);
markus@234
   513
        ::free_identity(_ident);
markus@234
   514
        return S_OK;
markus@234
   515
    }
markus@234
   516
    else {
markus@234
   517
        ::free_identity(_ident);
markus@234
   518
        if (status == PEP_OUT_OF_MEMORY)
markus@234
   519
            return E_OUTOFMEMORY;
markus@234
   520
        else
markus@234
   521
            return FAIL(L"myself", status);
markus@234
   522
    }
vb@0
   523
}
vb@0
   524
markus@172
   525
STDMETHODIMP CpEpEngine::UpdateIdentity(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@0
   526
{
markus@234
   527
    assert(ident);
markus@234
   528
    assert(result);
vb@0
   529
markus@234
   530
    if (!(ident && result))
markus@234
   531
        return E_INVALIDARG;
vb@0
   532
markus@234
   533
    ::pEp_identity *_ident;
markus@234
   534
    try {
markus@234
   535
        _ident = new_identity(ident);
markus@234
   536
    }
markus@234
   537
    catch (bad_alloc&) {
markus@234
   538
        return E_OUTOFMEMORY;
markus@234
   539
    }
markus@234
   540
    catch (exception& ex) {
markus@234
   541
        return FAIL(ex.what());
markus@234
   542
    }
markus@196
   543
markus@234
   544
    assert(_ident);
markus@234
   545
    if (_ident == NULL)
markus@234
   546
        return E_OUTOFMEMORY;
vb@0
   547
markus@234
   548
    PEP_STATUS status = ::update_identity(get_session(), _ident);
vb@0
   549
markus@234
   550
    if (status == PEP_STATUS_OK) {
markus@234
   551
        assert(_ident->fpr); // Guaranteed not NULL, but possibly empty string.
markus@234
   552
        copy_identity(result, _ident);
markus@234
   553
        ::free_identity(_ident);
markus@234
   554
        return S_OK;
markus@234
   555
    }
markus@234
   556
    else if (status == PEP_GET_KEY_FAILED) {
markus@234
   557
        if (_ident->fpr) {
markus@234
   558
            pEp_free(_ident->fpr);
markus@234
   559
            _ident->fpr = NULL;
markus@234
   560
        }
markus@234
   561
        copy_identity(result, _ident);
markus@234
   562
        result->Fpr = NULL;
markus@234
   563
        ::free_identity(_ident);
markus@234
   564
        return S_OK;
markus@234
   565
    }
markus@234
   566
    else {
markus@234
   567
        ::free_identity(_ident);
markus@234
   568
        if (status == PEP_OUT_OF_MEMORY)
markus@234
   569
            return E_OUTOFMEMORY;
markus@234
   570
        else
markus@234
   571
            return FAIL(L"UpdateIdentity", status);
markus@234
   572
    }
vb@0
   573
}
vb@0
   574
markus@172
   575
STDMETHODIMP CpEpEngine::KeyMistrusted(struct pEpIdentity *ident)
vb@4
   576
{
markus@234
   577
    ::pEp_identity *_ident;
vb@4
   578
markus@234
   579
    assert(ident);
markus@234
   580
    if (!ident)
markus@234
   581
        return E_INVALIDARG;
vb@4
   582
markus@234
   583
    try {
markus@234
   584
        _ident = new_identity(ident);
markus@234
   585
    }
markus@234
   586
    catch (bad_alloc&) {
markus@234
   587
        return E_OUTOFMEMORY;
markus@234
   588
    }
markus@234
   589
    catch (exception& ex) {
markus@234
   590
        return FAIL(ex.what());;
markus@234
   591
    }
vb@4
   592
markus@234
   593
    PEP_STATUS status = ::key_mistrusted(get_session(), _ident);
markus@234
   594
    free_identity(_ident);
vb@49
   595
markus@234
   596
    if (status == PEP_OUT_OF_MEMORY)
markus@234
   597
        return E_OUTOFMEMORY;
vb@4
   598
markus@234
   599
    if (status == PEP_KEY_NOT_FOUND)
markus@234
   600
        return FAIL(L"key not found");
vb@4
   601
markus@234
   602
    if (status != ::PEP_STATUS_OK)
markus@234
   603
        return FAIL(L"cannot revoke compromized key", status);
vb@4
   604
markus@234
   605
    return S_OK;
vb@4
   606
}
vb@4
   607
markus@264
   608
STDMETHODIMP CpEpEngine::UndoLastMistrust()
markus@264
   609
{
markus@264
   610
	PEP_STATUS status = ::undo_last_mistrust(get_session());
markus@264
   611
markus@264
   612
	if (status == PEP_CANNOT_FIND_IDENTITY)
markus@264
   613
		return FAIL(L"Cannot find identity!", status);
markus@264
   614
markus@264
   615
	if (status != ::PEP_STATUS_OK)
markus@264
   616
		return FAIL(L"cannot revoke compromized key", status);
markus@264
   617
markus@264
   618
	return S_OK;
markus@264
   619
}
markus@264
   620
markus@172
   621
STDMETHODIMP CpEpEngine::KeyResetTrust(struct pEpIdentity *ident)
Edouard@53
   622
{
markus@234
   623
    ::pEp_identity *_ident;
Edouard@53
   624
markus@234
   625
    assert(ident);
Edouard@53
   626
markus@234
   627
    if (!ident)
markus@234
   628
        return E_INVALIDARG;
Edouard@53
   629
markus@234
   630
    try {
markus@234
   631
        _ident = new_identity(ident);
markus@234
   632
    }
markus@234
   633
    catch (bad_alloc&) {
markus@234
   634
        return E_OUTOFMEMORY;
markus@234
   635
    }
markus@234
   636
    catch (exception& ex) {
markus@234
   637
        return FAIL(ex.what());;
markus@234
   638
    }
Edouard@53
   639
markus@234
   640
    PEP_STATUS status = ::key_reset_trust(get_session(), _ident);
markus@234
   641
    free_identity(_ident);
Edouard@53
   642
markus@234
   643
    if (status == PEP_OUT_OF_MEMORY)
markus@234
   644
        return E_OUTOFMEMORY;
Edouard@53
   645
markus@234
   646
    if (status == PEP_KEY_NOT_FOUND)
markus@234
   647
        return FAIL(L"key not found");
Edouard@53
   648
markus@234
   649
    if (status != ::PEP_STATUS_OK)
markus@234
   650
        return FAIL(L"cannot reset trust", status);
markus@234
   651
markus@234
   652
    return S_OK;
Edouard@53
   653
}
Edouard@53
   654
vb@28
   655
int CpEpEngine::examine_identity(pEp_identity *ident, void *management)
vb@28
   656
{
markus@234
   657
    assert(ident);
markus@234
   658
    assert(management);
markus@234
   659
    if (!(ident && management))
markus@234
   660
        return -1;
vb@28
   661
markus@234
   662
    CpEpEngine *me = (CpEpEngine *)management;
vb@28
   663
markus@234
   664
    if (me->identity_queue.load() == NULL)
markus@234
   665
        return 0;
vb@28
   666
markus@234
   667
    try {
markus@234
   668
        me->identity_queue.load()->push_back(ident);
markus@234
   669
    }
markus@234
   670
    catch (exception&) {
markus@234
   671
        return -1;
markus@234
   672
    }
vb@28
   673
markus@234
   674
    return 0;
vb@28
   675
}
vb@28
   676
vb@0
   677
::pEp_identity * CpEpEngine::retrieve_next_identity(void *management)
vb@0
   678
{
markus@234
   679
    assert(management);
markus@234
   680
    if (!management)
markus@234
   681
        return NULL;
markus@192
   682
markus@234
   683
    identity_queue_t *iq = (identity_queue_t *)management;
vb@0
   684
markus@234
   685
    do /* poll queue */ {
markus@234
   686
        if (iq->size())
markus@234
   687
            break;
markus@234
   688
        ::Sleep(100);
markus@234
   689
    } while (true);
vb@0
   690
markus@234
   691
    ::pEp_identity *_ident;
markus@234
   692
    pEp_identity_cpp& ident = iq->front();
vb@0
   693
markus@234
   694
    if (ident.address.size() == 0)
markus@234
   695
        return NULL;
vb@0
   696
markus@234
   697
    _ident = ident.to_pEp_identity();
markus@234
   698
    iq->pop_front();
vb@0
   699
markus@234
   700
    return _ident;
vb@0
   701
}
vb@0
   702
markus@164
   703
PEP_STATUS CpEpEngine::messageToSend(void * obj, message *msg)
vb@74
   704
{
markus@234
   705
    assert(msg);
markus@234
   706
    assert(obj);
markus@234
   707
    if (!(msg && obj))
markus@234
   708
        return PEP_ILLEGAL_VALUE;
vb@75
   709
markus@234
   710
    TextMessage _msg;
markus@234
   711
    memset(&_msg, 0, sizeof(TextMessage));
vb@82
   712
markus@234
   713
    text_message_from_C(&_msg, msg);
markus@234
   714
    CpEpEngine *me = (CpEpEngine *)obj;
markus@234
   715
    HRESULT r = me->Fire_MessageToSend(&_msg);
markus@234
   716
    assert(r == S_OK);
markus@234
   717
    clear_text_message(&_msg);
markus@234
   718
    if (r == E_OUTOFMEMORY)
markus@234
   719
        return PEP_OUT_OF_MEMORY;
markus@234
   720
    if (r != S_OK)
markus@234
   721
        return PEP_UNKNOWN_ERROR;
vb@75
   722
markus@234
   723
    return PEP_STATUS_OK;
vb@74
   724
}
vb@74
   725
markus@172
   726
STDMETHODIMP CpEpEngine::BlacklistAdd(BSTR fpr)
vb@65
   727
{
markus@234
   728
    assert(fpr);
markus@234
   729
    if (!fpr)
markus@234
   730
        return E_INVALIDARG;
vb@65
   731
markus@234
   732
    string _fpr = utf8_string(fpr);
markus@234
   733
    PEP_STATUS status = ::blacklist_add(get_session(), _fpr.c_str());
markus@234
   734
    assert(status == PEP_STATUS_OK);
markus@234
   735
    if (status != PEP_STATUS_OK)
markus@234
   736
        return FAIL(L"blacklist_add failed in pEp engine", status);
vb@65
   737
markus@234
   738
    return S_OK;
vb@65
   739
}
vb@65
   740
markus@172
   741
STDMETHODIMP CpEpEngine::BlacklistDelete(BSTR fpr)
vb@65
   742
{
markus@234
   743
    assert(fpr);
markus@234
   744
    if (!fpr)
markus@234
   745
        return E_INVALIDARG;
vb@65
   746
markus@234
   747
    string _fpr = utf8_string(fpr);
markus@234
   748
    PEP_STATUS status = ::blacklist_delete(get_session(), _fpr.c_str());
markus@234
   749
    assert(status == PEP_STATUS_OK);
markus@234
   750
    if (status != PEP_STATUS_OK)
markus@234
   751
        return FAIL(L"blacklist_delete failed in pEp engine", status);
vb@65
   752
markus@234
   753
    return S_OK;
vb@65
   754
}
vb@65
   755
markus@172
   756
STDMETHODIMP CpEpEngine::BlacklistIsListed(BSTR fpr, VARIANT_BOOL *listed)
vb@65
   757
{
markus@234
   758
    assert(fpr);
markus@234
   759
    assert(listed);
vb@65
   760
markus@234
   761
    if (!(fpr && listed))
markus@234
   762
        return E_INVALIDARG;
markus@192
   763
markus@234
   764
    string _fpr = utf8_string(fpr);
markus@234
   765
    bool result;
markus@234
   766
    PEP_STATUS status = ::blacklist_is_listed(get_session(), _fpr.c_str(), &result);
markus@234
   767
    assert(status == PEP_STATUS_OK);
markus@234
   768
    if (status != PEP_STATUS_OK)
markus@234
   769
        return FAIL(L"blacklist_is_listed failed in pEp engine", status);
vb@65
   770
markus@234
   771
    *listed = result ? VARIANT_TRUE : VARIANT_FALSE;
markus@234
   772
    return S_OK;
vb@65
   773
}
vb@65
   774
Dean@187
   775
STDMETHODIMP CpEpEngine::BlacklistRetrieve(SAFEARRAY **blacklist)
vb@65
   776
{
markus@234
   777
    assert(blacklist);
vb@65
   778
markus@234
   779
    if (!blacklist)
markus@234
   780
        return E_INVALIDARG;
markus@192
   781
markus@234
   782
    ::stringlist_t *_blacklist = NULL;
markus@234
   783
    PEP_STATUS status = ::blacklist_retrieve(get_session(), &_blacklist);
markus@234
   784
    assert(status == PEP_STATUS_OK);
markus@234
   785
    if (status != PEP_STATUS_OK)
markus@234
   786
        return FAIL(L"blacklist_retrieve failed in pEp engine", status);
markus@234
   787
    assert(_blacklist);
vb@65
   788
markus@234
   789
    *blacklist = string_array(_blacklist);
markus@234
   790
    ::free_stringlist(_blacklist);
markus@234
   791
    return S_OK;
vb@65
   792
}
vb@65
   793
vb@0
   794
HRESULT CpEpEngine::error(_bstr_t msg)
vb@0
   795
{
markus@234
   796
    _bstr_t helpFile = L"";
markus@234
   797
    _bstr_t source = L"pEp COM Adapter";
vb@0
   798
markus@234
   799
    ICreateErrorInfo *cei;
markus@234
   800
    if (SUCCEEDED(CreateErrorInfo(&cei))) {
markus@234
   801
        cei->SetDescription(msg);
markus@234
   802
        cei->SetGUID(__uuidof(IpEpEngine));
markus@234
   803
        cei->SetHelpContext(0);
markus@234
   804
        cei->SetHelpFile(helpFile);
markus@234
   805
        cei->SetSource(source);
vb@0
   806
markus@234
   807
        IErrorInfo *errinfo;
markus@234
   808
        if (SUCCEEDED(cei->QueryInterface(IID_IErrorInfo, (LPVOID FAR*) &errinfo))) {
markus@234
   809
            SetErrorInfo(0, errinfo);
markus@234
   810
            errinfo->Release();
markus@234
   811
        }
markus@234
   812
        cei->Release();
markus@234
   813
    }
markus@234
   814
    return E_FAIL;
vb@0
   815
}
vb@15
   816
markus@189
   817
HRESULT CpEpEngine::error(_bstr_t msg, PEP_STATUS status)
markus@189
   818
{
markus@189
   819
    std::stringstream stream;
markus@189
   820
    stream << msg;
markus@189
   821
    stream << ": ";
markus@189
   822
    stream << std::hex << status;
markus@234
   823
markus@189
   824
    error(stream.str().c_str());
markus@189
   825
markus@189
   826
    if (status == ::PEP_OUT_OF_MEMORY)
markus@189
   827
        return E_OUTOFMEMORY;
markus@189
   828
markus@189
   829
    return E_FAIL;
markus@189
   830
}
markus@189
   831
markus@172
   832
STDMETHODIMP CpEpEngine::EncryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY * extra, pEpEncryptFlags flags)
vb@15
   833
{
markus@267
   834
	return EncryptMessage2(src, dst, extra, flags, pEpEncPep);
markus@267
   835
}
markus@267
   836
markus@267
   837
STDMETHODIMP CpEpEngine::EncryptMessage2(TextMessage * src, TextMessage * dst, SAFEARRAY * extra, pEpEncryptFlags flags, pEpEncFormat encFormat)
markus@267
   838
{
markus@234
   839
    assert(src);
markus@234
   840
    assert(dst);
vb@15
   841
markus@234
   842
    if (!(src && dst))
markus@234
   843
        return E_INVALIDARG;
markus@192
   844
markus@234
   845
    ::message *_src = text_message_to_C(src);
markus@191
   846
markus@267
   847
	_PEP_enc_format _encFormat = (_PEP_enc_format)encFormat;
markus@267
   848
markus@234
   849
    // COM-19: Initialize msg_dst to NULL, or we end up calling
markus@234
   850
    // free_message() below with a pointer to random garbage in
markus@234
   851
    // case of an error in encrypt_message().
markus@234
   852
    ::message *msg_dst = NULL;
markus@234
   853
    ::stringlist_t *_extra = new_stringlist(extra); // can cope with NULL
vb@16
   854
markus@267
   855
    // _PEP_enc_format used to be intentionally hardcoded to PEP_enc_PEP:
markus@267
   856
    // Since COM-74, this has been changed to an explicit parameter, to allow the engine to attach
markus@267
   857
	// the keys and headers to outgoing, unencrypted messages.
markus@234
   858
    PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
markus@267
   859
    PEP_STATUS status = ::encrypt_message(get_session(), _src, _extra, &msg_dst, _encFormat, engineFlags);
markus@234
   860
    ::free_stringlist(_extra);
vb@16
   861
markus@234
   862
    if (status == PEP_STATUS_OK)
markus@234
   863
        text_message_from_C(dst, msg_dst);
markus@234
   864
    else
markus@234
   865
        text_message_from_C(dst, _src);
vb@38
   866
markus@234
   867
    ::free_message(msg_dst);
markus@234
   868
    ::free_message(_src);
vb@16
   869
markus@234
   870
    if (status == PEP_OUT_OF_MEMORY)
markus@234
   871
        return E_OUTOFMEMORY;
vb@46
   872
markus@234
   873
    // COM-41: Enhanced PEP status handling
markus@234
   874
    if ((status != PEP_STATUS_OK) && (status < PEP_UNENCRYPTED || status >= PEP_TRUSTWORD_NOT_FOUND))
markus@234
   875
        return FAIL("Failure to encrypt message", status);
markus@204
   876
markus@234
   877
    // Statii like PEP_UNENCRYPTED due to no private key
markus@234
   878
    // should not be a catastrophic failure here. Using S_FALSE
markus@234
   879
    // still allows clients to differentiate with S_OK,
markus@234
   880
    // although this does not work out of the box with
markus@234
   881
    // the standard .NET mapping of COM.
markus@234
   882
    if (status != PEP_STATUS_OK)
markus@234
   883
        return S_FALSE;
markus@197
   884
markus@234
   885
    return S_OK;
vb@15
   886
}
vb@15
   887
markus@238
   888
markus@254
   889
STDMETHODIMP CpEpEngine::EncryptMessageForSelf(pEpIdentity * targetId, TextMessage * src, TextMessage * dst, pEpEncryptFlags flags)
markus@238
   890
{
markus@254
   891
    assert(targetId);
markus@238
   892
    assert(src);
markus@238
   893
    assert(dst);
markus@238
   894
markus@254
   895
    if (!(targetId && src && dst))
markus@238
   896
        return E_INVALIDARG;
markus@238
   897
markus@240
   898
    PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
markus@240
   899
markus@254
   900
    ::pEp_identity *_target_id = new_identity(targetId);
markus@238
   901
markus@238
   902
    ::message *_src = text_message_to_C(src);
markus@238
   903
markus@238
   904
    // COM-19: Initialize msg_dst to NULL, or we end up calling
markus@238
   905
    // free_message() below with a pointer to random garbage in
markus@239
   906
    // case of an error in encrypt_message_for_self().
markus@238
   907
    ::message *msg_dst = NULL;
markus@240
   908
    PEP_STATUS status = ::encrypt_message_for_self(get_session(), _target_id, _src, &msg_dst, PEP_enc_PEP, engineFlags);
markus@238
   909
markus@238
   910
    if (status == PEP_STATUS_OK)
markus@238
   911
        text_message_from_C(dst, msg_dst);
markus@238
   912
    else
markus@238
   913
        text_message_from_C(dst, _src);
markus@238
   914
markus@238
   915
    ::free_message(msg_dst);
markus@238
   916
    ::free_message(_src);
markus@238
   917
    ::free_identity(_target_id);
markus@238
   918
markus@238
   919
    if (status == PEP_OUT_OF_MEMORY)
markus@238
   920
        return E_OUTOFMEMORY;
markus@238
   921
markus@238
   922
    // Different to encrypt_message, this should never fail (we ought to always
markus@238
   923
    // have a private key for ourself).#
markus@238
   924
    if (status != PEP_STATUS_OK)
markus@238
   925
        return FAIL("Failure to encrypt message", status);
markus@238
   926
markus@238
   927
    return S_OK;
markus@238
   928
}
markus@238
   929
markus@172
   930
STDMETHODIMP CpEpEngine::DecryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEpRating *rating)
vb@15
   931
{
markus@234
   932
    assert(src);
markus@234
   933
    assert(dst);
markus@234
   934
    assert(keylist);
markus@234
   935
    assert(flags);
markus@234
   936
    assert(rating);
vb@15
   937
markus@234
   938
    if (!(src && dst && keylist && flags && rating))
markus@234
   939
        return E_INVALIDARG;
markus@192
   940
markus@234
   941
    *keylist = NULL;
markus@234
   942
    *rating = pEpRatingUndefined;
vb@40
   943
markus@234
   944
    ::message *_src = text_message_to_C(src);
markus@234
   945
    ::message *msg_dst = NULL;
markus@234
   946
    ::stringlist_t *_keylist = NULL;
markus@234
   947
    ::PEP_rating _rating;
vb@16
   948
markus@234
   949
    PEP_decrypt_flags_t engineflags = 0;
markus@234
   950
    PEP_STATUS status = ::decrypt_message(get_session(), _src, &msg_dst, &_keylist, &_rating, &engineflags);
markus@167
   951
markus@234
   952
    *flags = (pEpDecryptFlags)engineflags;
vb@42
   953
markus@234
   954
    if (msg_dst)
markus@234
   955
        text_message_from_C(dst, msg_dst);
vb@42
   956
markus@234
   957
    ::free_message(_src);
markus@234
   958
    ::free_message(msg_dst);
vb@16
   959
markus@234
   960
    if (_keylist) {
markus@234
   961
        *keylist = string_array(_keylist);
markus@234
   962
        free_stringlist(_keylist);
markus@234
   963
    }
vb@18
   964
markus@234
   965
    *rating = (pEpRating)_rating;
vb@18
   966
markus@234
   967
    return S_OK;
vb@15
   968
}
vb@15
   969
markus@254
   970
STDMETHODIMP CpEpEngine::ReEvaluateMessageRating(TextMessage * msg, SAFEARRAY * x_KeyList, pEpRating x_EncStatus, pEpRating *rating)
edouard@249
   971
{
edouard@249
   972
    assert(msg);
markus@254
   973
    assert(x_EncStatus != PEP_rating_undefined);
edouard@249
   974
    assert(rating);
edouard@249
   975
Thomas@257
   976
    if (!(msg && x_EncStatus != PEP_rating_undefined && rating))
edouard@249
   977
        return E_INVALIDARG;
edouard@249
   978
edouard@249
   979
    *rating = pEpRatingUndefined;
edouard@249
   980
edouard@249
   981
    ::message *_msg = text_message_to_C(msg);
markus@254
   982
    ::stringlist_t *_keylist = new_stringlist(x_KeyList);
edouard@249
   983
    ::PEP_rating _rating = PEP_rating_undefined;
edouard@249
   984
markus@254
   985
    PEP_STATUS status = ::re_evaluate_message_rating(get_session(), _msg, _keylist, (PEP_rating)x_EncStatus, &_rating);
edouard@249
   986
markus@254
   987
    ::free_stringlist(_keylist);
edouard@249
   988
    ::free_message(_msg);
edouard@249
   989
edouard@249
   990
    *rating = (pEpRating)_rating;
edouard@249
   991
edouard@249
   992
    return S_OK;
edouard@249
   993
}
edouard@249
   994
markus@172
   995
STDMETHODIMP CpEpEngine::OutgoingMessageRating(TextMessage *msg, pEpRating * pVal)
vb@15
   996
{
markus@234
   997
    assert(msg);
markus@234
   998
    assert(pVal);
vb@15
   999
markus@234
  1000
    if (!(msg  && pVal))
markus@234
  1001
        return E_INVALIDARG;
markus@192
  1002
markus@234
  1003
    ::message *_msg = text_message_to_C(msg);
vb@19
  1004
markus@234
  1005
    PEP_rating _rating;
markus@234
  1006
    PEP_STATUS status = ::outgoing_message_rating(get_session(), _msg, &_rating);
markus@234
  1007
    if (status != PEP_STATUS_OK)
markus@234
  1008
        return FAIL(L"cannot get message rating", status);
vb@16
  1009
markus@234
  1010
    *pVal = (pEpRating)_rating;
markus@234
  1011
    return S_OK;
vb@15
  1012
}
vb@18
  1013
markus@172
  1014
STDMETHODIMP CpEpEngine::IdentityRating(struct pEpIdentity *ident, pEpRating * pVal)
vb@18
  1015
{
markus@234
  1016
    ::pEp_identity *_ident;
vb@18
  1017
markus@234
  1018
    assert(ident);
markus@234
  1019
    assert(pVal);
vb@18
  1020
markus@234
  1021
    if (!(ident  && pVal))
markus@234
  1022
        return E_INVALIDARG;
markus@192
  1023
markus@234
  1024
    try {
markus@234
  1025
        _ident = new_identity(ident);
markus@234
  1026
    }
markus@234
  1027
    catch (bad_alloc&) {
markus@234
  1028
        return E_OUTOFMEMORY;
markus@234
  1029
    }
markus@234
  1030
    catch (exception& ex) {
markus@234
  1031
        return FAIL(ex.what());;
markus@234
  1032
    }
vb@18
  1033
markus@234
  1034
    PEP_rating _rating;
markus@234
  1035
    PEP_STATUS status = ::identity_rating(get_session(), _ident, &_rating);
markus@234
  1036
    free_identity(_ident);
markus@192
  1037
markus@234
  1038
    if (status != PEP_STATUS_OK)
markus@234
  1039
        return FAIL(L"cannot get message color", status);
vb@18
  1040
markus@234
  1041
    *pVal = (pEpRating)_rating;
markus@234
  1042
    return S_OK;
vb@18
  1043
}
vb@48
  1044
markus@172
  1045
STDMETHODIMP CpEpEngine::ColorFromRating(pEpRating rating, pEpColor * pVal)
markus@164
  1046
{
markus@234
  1047
    assert(pVal);
markus@164
  1048
markus@234
  1049
    if (!pVal)
markus@234
  1050
        return E_INVALIDARG;
markus@192
  1051
markus@234
  1052
    PEP_rating engineRating = (PEP_rating)rating;
markus@234
  1053
    PEP_color _color = ::color_from_rating(engineRating);
markus@164
  1054
markus@234
  1055
    *pVal = (pEpColor)_color;
markus@164
  1056
markus@234
  1057
    return S_OK;
markus@164
  1058
}
markus@164
  1059
markus@254
  1060
STDMETHODIMP CpEpEngine::OwnIdentitiesRetrieve(LPSAFEARRAY* ownIdentities)
vb@219
  1061
{
markus@254
  1062
    assert(ownIdentities);
markus@254
  1063
    if (!ownIdentities)
markus@234
  1064
        return E_INVALIDARG;
vb@219
  1065
markus@254
  1066
    *ownIdentities = nullptr;
vb@219
  1067
markus@234
  1068
    ::identity_list *il = nullptr;
markus@234
  1069
    PEP_STATUS status = ::own_identities_retrieve(get_session(), &il);
markus@234
  1070
    if (status == PEP_OUT_OF_MEMORY) {
markus@234
  1071
        return E_OUTOFMEMORY;
markus@234
  1072
    }
markus@234
  1073
    else if (status != PEP_STATUS_OK)
markus@234
  1074
    {
markus@234
  1075
        return FAIL(_T("OwnIdentitiesRetrieve"), status);
markus@234
  1076
    }
vb@220
  1077
markus@234
  1078
    SAFEARRAY * _own_identities = nullptr;
markus@234
  1079
    try {
markus@234
  1080
        _own_identities = array_from_C<pEpIdentity, identity_list>(il);
markus@234
  1081
    }
markus@234
  1082
    catch (exception& ex)
markus@234
  1083
    {
markus@234
  1084
        ::free_identity_list(il);
markus@234
  1085
        try {
markus@234
  1086
            dynamic_cast<bad_alloc&>(ex);
markus@234
  1087
        }
markus@234
  1088
        catch (bad_cast&)
markus@234
  1089
        {
markus@234
  1090
            return FAIL(ex.what());
markus@234
  1091
        }
markus@234
  1092
        return E_OUTOFMEMORY;
markus@234
  1093
    }
markus@234
  1094
    free_identity_list(il);
vb@220
  1095
markus@254
  1096
    *ownIdentities = _own_identities;
markus@234
  1097
    return S_OK;
vb@219
  1098
}
vb@219
  1099
markus@172
  1100
STDMETHODIMP CpEpEngine::TrustPersonalKey(struct pEpIdentity *ident, struct pEpIdentity *result)
vb@48
  1101
{
markus@234
  1102
    ::pEp_identity *_ident;
vb@48
  1103
markus@234
  1104
    assert(ident);
markus@234
  1105
    assert(result);
vb@48
  1106
markus@234
  1107
    if (!ident || !result)
markus@234
  1108
        return E_INVALIDARG;
markus@192
  1109
markus@234
  1110
    try {
markus@234
  1111
        _ident = new_identity(ident);
markus@234
  1112
    }
markus@234
  1113
    catch (bad_alloc&) {
markus@234
  1114
        return E_OUTOFMEMORY;
markus@234
  1115
    }
markus@234
  1116
    catch (exception& ex) {
markus@234
  1117
        return FAIL(ex.what());;
markus@234
  1118
    }
vb@48
  1119
markus@234
  1120
    if (verbose_mode) {
markus@234
  1121
        stringstream ss;
markus@234
  1122
        ss << "TrustPersonalKey called with ";
markus@234
  1123
        ss << utf8_string(ident->Address);
markus@234
  1124
        ss << L": ";
markus@234
  1125
        ss << ident->CommType;
markus@234
  1126
        verbose(ss.str());
markus@234
  1127
    }
vb@52
  1128
markus@234
  1129
    PEP_STATUS status = ::trust_personal_key(get_session(), _ident);
vb@52
  1130
markus@234
  1131
    if (verbose_mode) {
markus@234
  1132
        stringstream ss;
markus@234
  1133
        ss << "result ";
markus@234
  1134
        ss << status;
markus@234
  1135
        ss << " for ";
markus@234
  1136
        ss << _ident->address;
markus@234
  1137
        ss << L": ";
markus@234
  1138
        ss << _ident->comm_type;
markus@234
  1139
        verbose(ss.str());
markus@234
  1140
    }
vb@52
  1141
markus@234
  1142
    if (status == PEP_STATUS_OK)
markus@234
  1143
        copy_identity(result, _ident);
vb@50
  1144
markus@234
  1145
    free_identity(_ident);
markus@234
  1146
    if (status == PEP_OUT_OF_MEMORY)
markus@234
  1147
        return E_OUTOFMEMORY;
markus@234
  1148
    else if (status != PEP_STATUS_OK)
markus@234
  1149
        return FAIL(L"failure while executing TrustPersonalKey()", status);
vb@48
  1150
markus@234
  1151
    return S_OK;
markus@165
  1152
}
markus@165
  1153
markus@165
  1154
// keysync api
markus@165
  1155
markus@169
  1156
void CpEpEngine::start_keysync()
markus@165
  1157
{
markus@234
  1158
    // acquire the lock
markus@235
  1159
    std::unique_lock<std::recursive_mutex> lock(keysync_mutex);
markus@165
  1160
markus@234
  1161
    // Assert if we're not already running.
markus@188
  1162
    assert(!this->keysync_thread);
markus@165
  1163
markus@234
  1164
    // Ensure we are not aborting the new thread due to a
markus@234
  1165
    // left over flag.
markus@234
  1166
    keysync_abort_requested = false;
markus@165
  1167
markus@234
  1168
    // Init our keysync session
krista@261
  1169
	{ // begin lock scope
krista@261
  1170
		std::lock_guard<std::mutex> lock(init_mutex);
krista@261
  1171
		PEP_STATUS status = ::init(&keysync_session);
krista@261
  1172
		::register_sync_callbacks(keysync_session, (void*)this, messageToSend, notifyHandshake, inject_sync_msg, retrieve_next_sync_msg);
krista@261
  1173
		assert(status == PEP_STATUS_OK);
krista@261
  1174
	} // end lock scope
markus@175
  1175
markus@175
  1176
    attach_sync_session(get_session(), keysync_session);
markus@165
  1177
markus@188
  1178
    // We need to marshal the callbacks to the keysync thread
markus@188
  1179
    LPSTREAM marshaled_callbacks;
markus@188
  1180
markus@188
  1181
    auto result = CoMarshalInterThreadInterfaceInStream(IID_IpEpEngineCallbacks, client_callbacks, &marshaled_callbacks);
markus@188
  1182
    assert(result == S_OK);
markus@188
  1183
markus@234
  1184
    // Star the keysync thread
markus@234
  1185
    keysync_thread = new thread(do_keysync_in_thread, this, marshaled_callbacks);
markus@188
  1186
}
markus@165
  1187
markus@234
  1188
void CpEpEngine::do_keysync_in_thread(CpEpEngine* self, LPSTREAM marshaled_callbacks)
markus@188
  1189
{
markus@188
  1190
    assert(self);
markus@234
  1191
    assert(marshaled_callbacks);
markus@192
  1192
markus@188
  1193
    // We need to initialize COM here for successfull delivery of the callbacks.
markus@188
  1194
    // As we don't create any COM instances in our thread, the COMINIT value is
markus@188
  1195
    // currently irrelevant, so we go with the safest value.
markus@188
  1196
    auto res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
markus@188
  1197
    assert(res == S_OK);
markus@188
  1198
markus@188
  1199
    LPVOID vp;
markus@188
  1200
markus@188
  1201
    res = CoGetInterfaceAndReleaseStream(marshaled_callbacks, IID_IpEpEngineCallbacks, &vp);
markus@188
  1202
    assert(SUCCEEDED(res));
markus@188
  1203
markus@232
  1204
    self->client_last_signalled_polling_state = false;
markus@188
  1205
    self->client_callbacks_on_sync_thread = static_cast<IpEpEngineCallbacks*>(vp);
markus@188
  1206
markus@232
  1207
    res = self->client_callbacks_on_sync_thread->QueryInterface(
markus@232
  1208
        &self->client_callbacks2_on_sync_thread);
markus@232
  1209
    if (res != S_OK)
markus@232
  1210
        self->client_callbacks2_on_sync_thread = NULL;
markus@232
  1211
markus@188
  1212
    ::do_sync_protocol(self->keysync_session, self);
markus@188
  1213
markus@188
  1214
    self->client_callbacks_on_sync_thread->Release();
markus@188
  1215
markus@188
  1216
    self->client_callbacks_on_sync_thread = NULL;
markus@188
  1217
markus@232
  1218
    if (self->client_callbacks2_on_sync_thread)
markus@232
  1219
        self->client_callbacks2_on_sync_thread->Release();
markus@232
  1220
    self->client_callbacks2_on_sync_thread = NULL;
markus@232
  1221
markus@188
  1222
    CoUninitialize();
markus@165
  1223
}
markus@165
  1224
markus@169
  1225
void CpEpEngine::stop_keysync()
markus@165
  1226
{
markus@234
  1227
    // acquire the lock
markus@235
  1228
    std::unique_lock<std::recursive_mutex> lock(keysync_mutex);
markus@165
  1229
markus@188
  1230
    // Do nothing if keysync is not running.
markus@188
  1231
    if (!keysync_thread)
markus@188
  1232
        return;
markus@165
  1233
markus@188
  1234
    assert(!keysync_abort_requested);
markus@234
  1235
    // signal that we're gonna abort
markus@234
  1236
    keysync_abort_requested = true;
markus@165
  1237
markus@234
  1238
    // Notify the keysync thread
markus@234
  1239
    keysync_condition.notify_all();
markus@165
  1240
markus@234
  1241
    // Wait for the other thread to finish and clean up
markus@234
  1242
    while (keysync_abort_requested)
markus@234
  1243
        keysync_condition.wait(lock);
markus@165
  1244
markus@234
  1245
    // collect the child thread for the thread to end
markus@234
  1246
    keysync_thread->join();
markus@165
  1247
markus@234
  1248
    // clean up
markus@234
  1249
    delete keysync_thread;
markus@234
  1250
    keysync_thread = NULL;
markus@188
  1251
markus@188
  1252
    ::detach_sync_session(get_session());
markus@234
  1253
    ::unregister_sync_callbacks(keysync_session);
krista@261
  1254
krista@261
  1255
	std::lock_guard<std::mutex> releaselock(init_mutex);
markus@234
  1256
    release(keysync_session);
markus@180
  1257
    keysync_session = NULL;
markus@165
  1258
}
markus@165
  1259
markus@165
  1260
int CpEpEngine::inject_sync_msg(void * msg, void * management)
markus@165
  1261
{
markus@234
  1262
    assert(msg);
markus@234
  1263
    assert(management);
markus@234
  1264
    // check argument
markus@234
  1265
    if (!msg)
markus@234
  1266
        return E_INVALIDARG;
markus@234
  1267
    if (!management)
markus@234
  1268
        return ERROR_INVALID_HANDLE;
markus@165
  1269
markus@234
  1270
    CpEpEngine* me = (CpEpEngine*)management;
markus@169
  1271
markus@234
  1272
    // acquire the lock
markus@235
  1273
    std::unique_lock<std::recursive_mutex> lock(me->keysync_mutex);
markus@165
  1274
markus@234
  1275
    // check whether we're in a valid state running:
markus@234
  1276
    if (!me->keysync_thread)
markus@234
  1277
        return E_ASYNC_OPERATION_NOT_STARTED;
markus@165
  1278
markus@234
  1279
    // queue the message
markus@234
  1280
    me->keysync_queue.push(msg);
markus@165
  1281
markus@234
  1282
    // notify the receivers
markus@234
  1283
    me->keysync_condition.notify_all();
markus@170
  1284
markus@170
  1285
    return S_OK;
markus@165
  1286
}
markus@165
  1287
vb@227
  1288
void * CpEpEngine::retrieve_next_sync_msg(void * management, time_t *timeout)
markus@165
  1289
{
markus@234
  1290
    // sanity check
markus@234
  1291
    assert(management);
markus@234
  1292
    if (!(management))
markus@234
  1293
        return NULL;
markus@169
  1294
markus@234
  1295
    CpEpEngine* me = (CpEpEngine*)management;
markus@165
  1296
markus@232
  1297
    if ((timeout && *timeout)
markus@232
  1298
        && me->client_callbacks2_on_sync_thread
markus@232
  1299
        && me->client_last_signalled_polling_state == false)
markus@232
  1300
    {
markus@232
  1301
        me->client_callbacks2_on_sync_thread->NeedFastPolling(VARIANT_TRUE);
markus@233
  1302
        me->client_last_signalled_polling_state = true;
markus@232
  1303
    }
markus@232
  1304
    else if (!(timeout && *timeout)
markus@232
  1305
        && me->client_callbacks2_on_sync_thread
markus@232
  1306
        && me->client_last_signalled_polling_state == true)
markus@232
  1307
    {
markus@232
  1308
        me->client_callbacks2_on_sync_thread->NeedFastPolling(VARIANT_FALSE);
markus@233
  1309
        me->client_last_signalled_polling_state = false;
markus@232
  1310
    }
markus@232
  1311
markus@234
  1312
    // acquire the lock
markus@235
  1313
    std::unique_lock<std::recursive_mutex> lock(me->keysync_mutex);
markus@234
  1314
markus@234
  1315
    if (me->notify_handshake_finished)
markus@234
  1316
        me->notify_handshake_deliver_result();
markus@234
  1317
markus@232
  1318
    if (timeout && *timeout) {
edouard@245
  1319
        std::chrono::steady_clock::time_point end_time = std::chrono::steady_clock::now()
markus@232
  1320
            + std::chrono::seconds(*timeout);
markus@165
  1321
markus@232
  1322
        while (me->keysync_queue.empty() && !me->keysync_abort_requested)
markus@232
  1323
        {
markus@232
  1324
            auto status = me->keysync_condition.wait_until(lock, end_time);
markus@165
  1325
markus@234
  1326
            if (me->notify_handshake_finished)
markus@234
  1327
                me->notify_handshake_deliver_result();
markus@234
  1328
markus@232
  1329
            if (status == std::cv_status::timeout)
markus@232
  1330
            {
markus@232
  1331
                *timeout = 1; // Signal timeout
markus@232
  1332
                return NULL;
edouard@244
  1333
            } 
edouard@244
  1334
            else 
edouard@244
  1335
            {
edouard@245
  1336
                std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
edouard@245
  1337
edouard@244
  1338
                if (now < end_time) 
edouard@244
  1339
                {
edouard@246
  1340
                    *timeout = std::chrono::duration_cast<std::chrono::seconds>(end_time - now).count();
edouard@244
  1341
                } 
edouard@244
  1342
                else 
edouard@244
  1343
                {
edouard@244
  1344
                    *timeout = 0;
edouard@244
  1345
                }
markus@234
  1346
            }
markus@232
  1347
        }
markus@232
  1348
    }
markus@234
  1349
    else
markus@232
  1350
    {
markus@232
  1351
        while (me->keysync_queue.empty() && !me->keysync_abort_requested)
markus@232
  1352
        {
markus@232
  1353
            me->keysync_condition.wait(lock);
markus@234
  1354
markus@234
  1355
            if (me->notify_handshake_finished)
markus@234
  1356
                me->notify_handshake_deliver_result();
markus@232
  1357
        }
markus@232
  1358
    }
markus@165
  1359
markus@232
  1360
    if (me->keysync_abort_requested) {
markus@232
  1361
        // we acknowledge that we're quitting...
markus@232
  1362
        me->keysync_abort_requested = false;
markus@169
  1363
markus@232
  1364
        // We signal the main thread that we got his signal
markus@232
  1365
        // so it can gain the mutex again and call join() on us.
markus@232
  1366
        me->keysync_condition.notify_all();
markus@165
  1367
markus@232
  1368
        // and tell the pep engine we're done.
markus@232
  1369
        if (timeout)
markus@232
  1370
            *timeout = 0; // signal for termination.
markus@232
  1371
        return NULL;
markus@232
  1372
    }
markus@165
  1373
markus@234
  1374
    assert(!me->keysync_queue.empty());
markus@165
  1375
markus@234
  1376
    // Pop the message and return it.
markus@234
  1377
    void* msg = me->keysync_queue.front();
markus@234
  1378
    assert(msg);
markus@232
  1379
markus@234
  1380
    me->keysync_queue.pop();
markus@232
  1381
markus@234
  1382
    return msg;
vb@48
  1383
}
markus@84
  1384
markus@84
  1385
markus@84
  1386
// Event callbacks
markus@84
  1387
markus@172
  1388
STDMETHODIMP CpEpEngine::RegisterCallbacks(IpEpEngineCallbacks* new_callbacks)
markus@84
  1389
{
markus@188
  1390
    // check for valid parameter
markus@188
  1391
    if (!new_callbacks)
markus@188
  1392
        return E_INVALIDARG;
markus@84
  1393
markus@188
  1394
    // don't allow double registration.
markus@188
  1395
    if (this->client_callbacks)
markus@188
  1396
        return E_ILLEGAL_STATE_CHANGE;
markus@188
  1397
markus@188
  1398
    this->client_callbacks = new_callbacks;
markus@188
  1399
    new_callbacks->AddRef();
markus@188
  1400
markus@234
  1401
    start_keysync();
markus@84
  1402
markus@234
  1403
    return S_OK;
markus@84
  1404
}
markus@84
  1405
markus@188
  1406
STDMETHODIMP CpEpEngine::UnregisterCallbacks()
markus@84
  1407
{
markus@188
  1408
    // don't allow double deregistration.
markus@188
  1409
    // S_FALSE still is no error (as double deregistration is not fatal).
markus@188
  1410
    if (!this->client_callbacks)
markus@188
  1411
        return S_FALSE;
markus@84
  1412
markus@188
  1413
    stop_keysync();
markus@169
  1414
markus@188
  1415
    this->client_callbacks->Release();
markus@84
  1416
markus@188
  1417
    this->client_callbacks = NULL;
markus@188
  1418
markus@188
  1419
    return S_OK;
markus@84
  1420
}
markus@84
  1421
markus@177
  1422
STDMETHODIMP CpEpEngine::OpenPGPListKeyinfo(BSTR search_pattern, LPSAFEARRAY* keyinfo_list) {
markus@234
  1423
    assert(keyinfo_list);
krista@154
  1424
markus@234
  1425
    if (keyinfo_list == NULL)
markus@234
  1426
        return E_INVALIDARG;
krista@154
  1427
markus@234
  1428
    string _pattern = "";
markus@234
  1429
    if (search_pattern)
markus@234
  1430
        _pattern = utf8_string(search_pattern);
markus@234
  1431
    ::stringpair_list_t* _keyinfo_list = NULL;
krista@154
  1432
markus@234
  1433
    PEP_STATUS status = ::OpenPGP_list_keyinfo(get_session(), _pattern.c_str(), &_keyinfo_list);
markus@234
  1434
    assert(status != PEP_OUT_OF_MEMORY);
markus@234
  1435
    if (status == PEP_OUT_OF_MEMORY)
markus@234
  1436
        return E_OUTOFMEMORY;
krista@154
  1437
markus@234
  1438
    if (status != ::PEP_STATUS_OK)
markus@234
  1439
        return FAIL(L"OpenPGP_list_keyinfo", status);
krista@154
  1440
markus@234
  1441
    if (_keyinfo_list && _keyinfo_list->value) {
markus@234
  1442
        ::opt_field_array_from_C(_keyinfo_list, keyinfo_list);
markus@234
  1443
    }
markus@234
  1444
    else {
markus@234
  1445
        ::free_stringpair_list(_keyinfo_list);
markus@234
  1446
        return FAIL(L"OpenPGP_list_keyinfo: no keys found");
markus@234
  1447
    }
markus@165
  1448
markus@234
  1449
    ::free_stringpair_list(_keyinfo_list);
markus@234
  1450
    return S_OK;
markus@165
  1451
krista@154
  1452
}
krista@154
  1453
markus@172
  1454
HRESULT CpEpEngine::Fire_MessageToSend(TextMessage * msg)
markus@84
  1455
{
markus@234
  1456
    assert(msg);
markus@188
  1457
    assert(this->client_callbacks_on_sync_thread);
markus@84
  1458
markus@234
  1459
    if (!msg)
markus@234
  1460
        return E_INVALIDARG;
markus@192
  1461
markus@234
  1462
    if (!this->client_callbacks_on_sync_thread)
markus@234
  1463
        return E_ILLEGAL_METHOD_CALL;
markus@192
  1464
markus@188
  1465
    auto result = this->client_callbacks_on_sync_thread->MessageToSend(msg);
markus@84
  1466
markus@234
  1467
    return result;
markus@84
  1468
}
markus@84
  1469
markus@234
  1470
// This method is called from the keysync thread, and dispatches
markus@234
  1471
// the handshake asynchroneously to a background thread,
markus@234
  1472
// so the engine can continue working.
markus@234
  1473
PEP_STATUS CpEpEngine::notifyHandshake(void * obj, pEp_identity *self, pEp_identity *partner, sync_handshake_signal signal)
markus@84
  1474
{
markus@234
  1475
    assert(self && partner);
markus@234
  1476
    if (!(self && partner))
markus@234
  1477
        return PEP_ILLEGAL_VALUE;
markus@192
  1478
markus@234
  1479
    CpEpEngine *me = (CpEpEngine *)obj;
markus@234
  1480
markus@234
  1481
    if (me->notify_handshake_active) {
markus@236
  1482
        // We don't support concurrent handshakes currently, 
markus@236
  1483
        // with the exception of an abort of the handshake, 
markus@236
  1484
        // which we deliver synchroneously (as it's non-blocking).
markus@236
  1485
        if (signal == SYNC_NOTIFY_TIMEOUT) {
markus@236
  1486
            pEpIdentity timeout_self;
markus@236
  1487
            pEpIdentity timeout_partner;
markus@236
  1488
            SyncHandshakeSignal timeout_signal = (SyncHandshakeSignal)signal;
markus@236
  1489
            copy_identity(&timeout_self, self);
markus@236
  1490
            copy_identity(&timeout_partner, partner);
markus@236
  1491
            SyncHandshakeResult result;
markus@236
  1492
            auto res = me->client_callbacks_on_sync_thread->NotifyHandshake(&timeout_self, &timeout_partner, timeout_signal, &result);
markus@236
  1493
markus@236
  1494
            clear_identity_s(timeout_self);
markus@236
  1495
            clear_identity_s(timeout_partner);
markus@236
  1496
markus@236
  1497
            if (FAILED(res)) {
markus@236
  1498
                IErrorInfo* errorInfo = NULL;
markus@236
  1499
                if (FAILED(GetErrorInfo(0, &errorInfo)))
markus@236
  1500
                    errorInfo = NULL;
markus@236
  1501
markus@236
  1502
                // The _com_error takes ownership of the errorInfo
markus@236
  1503
                // and will Release() it. It can also cope with
markus@236
  1504
                // NULL errorInfos.
markus@236
  1505
                _com_error error(res, errorInfo);
markus@236
  1506
markus@236
  1507
                string _description = utf8_string(
markus@236
  1508
                    error.ErrorMessage());
markus@236
  1509
markus@236
  1510
                string _comment = utf8_string(error.Description());
markus@236
  1511
markus@236
  1512
                auto source = error.Source();
markus@236
  1513
                if (source.length() > 0) {
markus@236
  1514
                    _comment += "\r\nSource: ";
markus@236
  1515
                    _comment += utf8_string(source);
markus@236
  1516
                }
markus@236
  1517
markus@236
  1518
                ::log_event(me->keysync_session,
markus@236
  1519
                    "Error on NotifyHandshakeTimeout",
markus@236
  1520
                    "pEp COM Adapter",
markus@236
  1521
                    _description.c_str(),
markus@236
  1522
                    _comment.c_str());
markus@236
  1523
markus@236
  1524
                return PEP_UNKNOWN_ERROR;
markus@236
  1525
            }
markus@236
  1526
markus@236
  1527
            if (res != S_OK)
markus@236
  1528
markus@236
  1529
            return PEP_STATUS_OK;
markus@236
  1530
        }
markus@236
  1531
markus@236
  1532
        ::log_event(me->keysync_session, "Reentrant notify_handshake call!", "pEp COM Adapter", NULL, NULL);
markus@234
  1533
        return PEP_UNKNOWN_ERROR;
markus@234
  1534
    }
markus@234
  1535
markus@234
  1536
    assert(!(me->notify_handshake_active
markus@234
  1537
        || me->notify_handshake_finished
markus@234
  1538
        || me->notify_handshake_thread));
markus@234
  1539
markus@234
  1540
    me->notify_handshake_active = true;
markus@234
  1541
markus@234
  1542
    copy_identity(&me->notify_handshake_self, self);
markus@234
  1543
    copy_identity(&me->notify_handshake_partner, partner);
markus@234
  1544
    me->notify_handshake_signal = (SyncHandshakeSignal)signal;
markus@234
  1545
markus@234
  1546
    // We need to marshal the callbacks to the keysync thread
markus@234
  1547
    LPSTREAM marshaled_callbacks;
markus@234
  1548
markus@234
  1549
    auto result = CoMarshalInterThreadInterfaceInStream(IID_IpEpEngineCallbacks, me->client_callbacks_on_sync_thread, &marshaled_callbacks);
markus@234
  1550
    assert(result == S_OK);
markus@234
  1551
markus@234
  1552
    me->notify_handshake_thread = new thread(notify_handshake_background_thread, me, marshaled_callbacks);
markus@234
  1553
markus@234
  1554
    return PEP_STATUS_OK;
markus@84
  1555
}
markus@234
  1556
markus@234
  1557
// This method also runs in the keysync thread, called by
markus@234
  1558
// retrieve_next_sync_msg() to deliver back the results
markus@234
  1559
// of the sync into the engine.
markus@234
  1560
void CpEpEngine::notify_handshake_deliver_result()
markus@234
  1561
{
markus@234
  1562
    assert(notify_handshake_active
markus@234
  1563
        && notify_handshake_finished);
markus@234
  1564
    if (!(notify_handshake_active
markus@234
  1565
        && notify_handshake_finished))
markus@234
  1566
        return;
markus@234
  1567
markus@234
  1568
    notify_handshake_thread->join();
markus@234
  1569
    notify_handshake_thread = NULL;
markus@234
  1570
markus@234
  1571
    Identity partner = new_identity(&notify_handshake_partner);
markus@234
  1572
markus@234
  1573
    if (FAILED(notify_handshake_error))
markus@234
  1574
    {
markus@234
  1575
        IErrorInfo *errorInfo = NULL;
markus@234
  1576
markus@234
  1577
        if (notify_handshake_error_info) {
markus@234
  1578
            LPVOID lp = NULL;
markus@234
  1579
            auto res = CoGetInterfaceAndReleaseStream(notify_handshake_error_info, IID_IErrorInfo, &lp);
markus@234
  1580
markus@234
  1581
            if (SUCCEEDED(res) && lp)
markus@234
  1582
                errorInfo = static_cast<IErrorInfo*>(lp);
markus@234
  1583
        }
markus@234
  1584
markus@234
  1585
        // The _com_error takes ownership of the errorInfo
markus@234
  1586
        // and will Release() it. It can also cope with
markus@234
  1587
        // NULL errorInfos.
markus@234
  1588
        _com_error error(notify_handshake_error, errorInfo);
markus@234
  1589
markus@234
  1590
        string _description = utf8_string(
markus@234
  1591
            error.ErrorMessage());
markus@234
  1592
markus@234
  1593
        string _comment = utf8_string(error.Description());
markus@234
  1594
markus@234
  1595
        auto source = error.Source();
markus@234
  1596
        if (source.length() > 0) {
markus@234
  1597
            _comment += "\r\nSource: ";
markus@234
  1598
            _comment += utf8_string(source);
markus@234
  1599
        }
markus@234
  1600
markus@234
  1601
        ::log_event(keysync_session,
markus@234
  1602
            "Notify Handshake Failed!",
markus@234
  1603
            "pEp COM Adapter",
markus@234
  1604
            _description.c_str(),
markus@234
  1605
            _comment.c_str());
markus@234
  1606
markus@234
  1607
        ::deliverHandshakeResult(keysync_session, partner, SYNC_HANDSHAKE_CANCEL);
markus@234
  1608
    }
markus@234
  1609
    else {
markus@234
  1610
        ::deliverHandshakeResult(
markus@234
  1611
            keysync_session,
markus@234
  1612
            partner,
markus@234
  1613
            (sync_handshake_result)notify_handshake_result);
markus@234
  1614
    }
markus@234
  1615
    notify_handshake_error_info = NULL;
markus@234
  1616
markus@236
  1617
    clear_identity_s(notify_handshake_self);
markus@236
  1618
    clear_identity_s(notify_handshake_partner);
markus@234
  1619
    notify_handshake_active = false;
markus@234
  1620
    notify_handshake_finished = false;
markus@234
  1621
}
markus@234
  1622
markus@234
  1623
// Method on the background thread, calling into Outlook to
markus@234
  1624
// trigger the Handshake notification, and then scheduling
markus@234
  1625
// the result back to the main thread.
markus@234
  1626
void CpEpEngine::notify_handshake_background_thread(CpEpEngine* self, LPSTREAM marshaled_callbacks)
markus@234
  1627
{
markus@234
  1628
    assert(self);
markus@234
  1629
markus@234
  1630
    // We need to initialize COM here for successfull delivery of the callbacks.
markus@234
  1631
    // As we don't create any COM instances in our thread, the COMINIT value is
markus@234
  1632
    // currently irrelevant, so we go with the safest value.
markus@234
  1633
    auto res = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
markus@234
  1634
    assert(res == S_OK);
markus@234
  1635
markus@234
  1636
    LPVOID vp;
markus@234
  1637
markus@234
  1638
    res = CoGetInterfaceAndReleaseStream(marshaled_callbacks, IID_IpEpEngineCallbacks, &vp);
markus@234
  1639
    assert(SUCCEEDED(res));
markus@234
  1640
markus@234
  1641
    auto client_callbacks_on_sync_thread = static_cast<IpEpEngineCallbacks*>(vp);
markus@234
  1642
markus@234
  1643
    self->notify_handshake_error = client_callbacks_on_sync_thread->NotifyHandshake(
markus@234
  1644
        &self->notify_handshake_self,
markus@234
  1645
        &self->notify_handshake_partner,
markus@234
  1646
        self->notify_handshake_signal,
markus@234
  1647
        &self->notify_handshake_result);
markus@234
  1648
markus@234
  1649
    if (FAILED(self->notify_handshake_error)) {
markus@234
  1650
        IErrorInfo* errorInfo = NULL;
markus@234
  1651
markus@234
  1652
        res = GetErrorInfo(0, &errorInfo);
markus@234
  1653
markus@234
  1654
        if (res = S_OK && errorInfo != NULL) {
markus@234
  1655
            res = CoMarshalInterThreadInterfaceInStream(
markus@234
  1656
                IID_IErrorInfo,
markus@234
  1657
                errorInfo,
markus@234
  1658
                &self->notify_handshake_error_info);
markus@234
  1659
markus@234
  1660
            errorInfo->Release();
markus@234
  1661
        }
markus@234
  1662
    }
markus@234
  1663
markus@234
  1664
    // notify the keysync thread.
markus@234
  1665
    self->notify_handshake_finished = true;
markus@234
  1666
    self->keysync_condition.notify_all();
edouard@244
  1667
}