CpEpEngine.cpp
author Markus Schaber <markus@pep-security.net>
Wed, 07 Feb 2018 19:42:45 +0100
branchCOM-74
changeset 272 0cd9b4cde17c
parent 271 92866cd8b0c4
child 273 30be98685afa
permissions -rw-r--r--
COM-74: Expose _PEP_enc_format to app for EncryptMessage

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