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