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