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