COM-54: Attachment Blob CID Support COM-54-ENGINE-9
authorMarkus Schaber <markus@pep-security.net>
Wed, 14 Jun 2017 23:46:37 +0200
branchCOM-54-ENGINE-9
changeset 251ded328cde93f
parent 248 e55fc51ec0f9
child 253 8223c75216ae
COM-54: Attachment Blob CID Support
CpEpEngine.cpp
CpEpEngine.h
pEpCOMServerAdapter.idl
pEp_utility.cpp
pEp_utility.h
     1.1 --- a/CpEpEngine.cpp	Fri Apr 21 17:11:50 2017 +0200
     1.2 +++ b/CpEpEngine.cpp	Wed Jun 14 23:46:37 2017 +0200
     1.3 @@ -14,6 +14,7 @@
     1.4      {
     1.5          &IID_IpEpEngine,
     1.6          &IID_IpEpEngine2,
     1.7 +        &IID_IpEpEngine3,
     1.8      };
     1.9  
    1.10      for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
    1.11 @@ -317,6 +318,92 @@
    1.12      return result;
    1.13  }
    1.14  
    1.15 +STDMETHODIMP CpEpEngine::GetMessageTrustwordsEx(
    1.16 +    /* [in] */ struct TextMessageEx *msg,
    1.17 +    /* [in] */ struct pEpIdentity *receivedBy,
    1.18 +    /* [in] */ SAFEARRAY *keylist,
    1.19 +    /* [defaultvalue][in] */ BSTR lang,
    1.20 +    /* [defaultvalue][in] */ VARIANT_BOOL full,
    1.21 +    /* [retval][out] */ BSTR *words) {
    1.22 +    assert(msg);
    1.23 +    assert(receivedBy);
    1.24 +    assert(words);
    1.25 +
    1.26 +    if (!(msg && receivedBy && words))
    1.27 +    {
    1.28 +        return E_INVALIDARG;
    1.29 +    }
    1.30 +
    1.31 +    HRESULT result = S_OK;
    1.32 +
    1.33 +    pEp_identity * _received_by = NULL;
    1.34 +    ::message * _msg = NULL;
    1.35 +    ::stringlist_t *_keylist = NULL;
    1.36 +    string _lang;
    1.37 +    *words = NULL;
    1.38 +
    1.39 +    try {
    1.40 +        _received_by = new_identity(receivedBy);
    1.41 +        _msg = text_message_to_C(msg);
    1.42 +
    1.43 +        if (keylist) {
    1.44 +            _keylist = new_stringlist(keylist);
    1.45 +        }
    1.46 +
    1.47 +        if (lang) {
    1.48 +            _lang = utf8_string(lang);
    1.49 +            if (_lang.length() == 0) {
    1.50 +                _lang = "en";
    1.51 +            }
    1.52 +            else if (_lang.length() != 2) {
    1.53 +                result = E_INVALIDARG;
    1.54 +            }
    1.55 +        }
    1.56 +        else {
    1.57 +            _lang = "en";
    1.58 +        }
    1.59 +    }
    1.60 +    catch (bad_alloc&) {
    1.61 +        result = E_OUTOFMEMORY;
    1.62 +    }
    1.63 +    catch (exception& ex) {
    1.64 +        result = FAIL(ex.what());
    1.65 +    }
    1.66 +
    1.67 +    char* _words = NULL;
    1.68 +    if (result == S_OK) {
    1.69 +        auto status = ::get_message_trustwords(
    1.70 +            get_session(),
    1.71 +            _msg,
    1.72 +            _keylist,
    1.73 +            _received_by,
    1.74 +            _lang.c_str(),
    1.75 +            &_words,
    1.76 +            full != 0 /* convert variant bool to C bool */);
    1.77 +
    1.78 +        if (status == PEP_OUT_OF_MEMORY) {
    1.79 +            result = E_OUTOFMEMORY;
    1.80 +        }
    1.81 +        else if (status == PEP_TRUSTWORD_NOT_FOUND) {
    1.82 +            result = FAIL(L"GetTrustwords: Trustword not found", status);
    1.83 +        }
    1.84 +        else if (!words) {
    1.85 +            result = FAIL(L"GetTrustwords: _words == NULL", status);
    1.86 +        }
    1.87 +        else {
    1.88 +            *words = utf16_bstr(_words);
    1.89 +        }
    1.90 +    }
    1.91 +
    1.92 +    ::pEp_free(_words);
    1.93 +    ::free_message(_msg);
    1.94 +    ::free_stringlist(_keylist);
    1.95 +    ::free_identity(_received_by);
    1.96 +
    1.97 +    return result;
    1.98 +}
    1.99 +
   1.100 +
   1.101  STDMETHODIMP CpEpEngine::GetCrashdumpLog(LONG maxlines, BSTR * log)
   1.102  {
   1.103      // COM-18: Currently, long == int on windows, so the check
   1.104 @@ -862,6 +949,54 @@
   1.105      return S_OK;
   1.106  }
   1.107  
   1.108 +STDMETHODIMP CpEpEngine::EncryptMessageEx(TextMessageEx * src, TextMessageEx * dst, SAFEARRAY * extra, pEpEncryptFlags flags)
   1.109 +{
   1.110 +    assert(src);
   1.111 +    assert(dst);
   1.112 +
   1.113 +    if (!(src && dst))
   1.114 +        return E_INVALIDARG;
   1.115 +
   1.116 +    ::message *_src = text_message_to_C(src);
   1.117 +
   1.118 +    // COM-19: Initialize msg_dst to NULL, or we end up calling
   1.119 +    // free_message() below with a pointer to random garbage in
   1.120 +    // case of an error in encrypt_message().
   1.121 +    ::message *msg_dst = NULL;
   1.122 +    ::stringlist_t *_extra = new_stringlist(extra); // can cope with NULL
   1.123 +
   1.124 +                                                    // _PEP_enc_format is intentionally hardcoded to PEP_enc_PEP:
   1.125 +                                                    // 2016-10-02 14:10 < fdik> schabi: actually, all adapters now must use PEP_enc_PEP
   1.126 +    PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
   1.127 +    PEP_STATUS status = ::encrypt_message(get_session(), _src, _extra, &msg_dst, PEP_enc_PEP, engineFlags);
   1.128 +    ::free_stringlist(_extra);
   1.129 +
   1.130 +    if (status == PEP_STATUS_OK)
   1.131 +        text_message_from_C(dst, msg_dst);
   1.132 +    else
   1.133 +        text_message_from_C(dst, _src);
   1.134 +
   1.135 +    ::free_message(msg_dst);
   1.136 +    ::free_message(_src);
   1.137 +
   1.138 +    if (status == PEP_OUT_OF_MEMORY)
   1.139 +        return E_OUTOFMEMORY;
   1.140 +
   1.141 +    // COM-41: Enhanced PEP status handling
   1.142 +    if ((status != PEP_STATUS_OK) && (status < PEP_UNENCRYPTED || status >= PEP_TRUSTWORD_NOT_FOUND))
   1.143 +        return FAIL("Failure to encrypt message", status);
   1.144 +
   1.145 +    // Statii like PEP_UNENCRYPTED due to no private key
   1.146 +    // should not be a catastrophic failure here. Using S_FALSE
   1.147 +    // still allows clients to differentiate with S_OK,
   1.148 +    // although this does not work out of the box with
   1.149 +    // the standard .NET mapping of COM.
   1.150 +    if (status != PEP_STATUS_OK)
   1.151 +        return S_FALSE;
   1.152 +
   1.153 +    return S_OK;
   1.154 +}
   1.155 +
   1.156  
   1.157  STDMETHODIMP CpEpEngine::EncryptMessageForSelf(pEpIdentity * target_id, TextMessage * src, TextMessage * dst, pEpEncryptFlags flags)
   1.158  {
   1.159 @@ -904,6 +1039,47 @@
   1.160      return S_OK;
   1.161  }
   1.162  
   1.163 +STDMETHODIMP CpEpEngine::EncryptMessageForSelfEx(pEpIdentity * target_id, TextMessageEx * src, TextMessageEx * dst, pEpEncryptFlags flags)
   1.164 +{
   1.165 +    assert(target_id);
   1.166 +    assert(src);
   1.167 +    assert(dst);
   1.168 +
   1.169 +    if (!(target_id && src && dst))
   1.170 +        return E_INVALIDARG;
   1.171 +
   1.172 +    PEP_encrypt_flags_t engineFlags = (PEP_encrypt_flags_t)flags;
   1.173 +
   1.174 +    ::pEp_identity *_target_id = new_identity(target_id);
   1.175 +
   1.176 +    ::message *_src = text_message_to_C(src);
   1.177 +
   1.178 +    // COM-19: Initialize msg_dst to NULL, or we end up calling
   1.179 +    // free_message() below with a pointer to random garbage in
   1.180 +    // case of an error in encrypt_message_for_self().
   1.181 +    ::message *msg_dst = NULL;
   1.182 +    PEP_STATUS status = ::encrypt_message_for_self(get_session(), _target_id, _src, &msg_dst, PEP_enc_PEP, engineFlags);
   1.183 +
   1.184 +    if (status == PEP_STATUS_OK)
   1.185 +        text_message_from_C(dst, msg_dst);
   1.186 +    else
   1.187 +        text_message_from_C(dst, _src);
   1.188 +
   1.189 +    ::free_message(msg_dst);
   1.190 +    ::free_message(_src);
   1.191 +    ::free_identity(_target_id);
   1.192 +
   1.193 +    if (status == PEP_OUT_OF_MEMORY)
   1.194 +        return E_OUTOFMEMORY;
   1.195 +
   1.196 +    // Different to encrypt_message, this should never fail (we ought to always
   1.197 +    // have a private key for ourself).#
   1.198 +    if (status != PEP_STATUS_OK)
   1.199 +        return FAIL("Failure to encrypt message", status);
   1.200 +
   1.201 +    return S_OK;
   1.202 +}
   1.203 +
   1.204  STDMETHODIMP CpEpEngine::DecryptMessage(TextMessage * src, TextMessage * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEpRating *rating)
   1.205  {
   1.206      assert(src);
   1.207 @@ -944,6 +1120,46 @@
   1.208      return S_OK;
   1.209  }
   1.210  
   1.211 +STDMETHODIMP CpEpEngine::DecryptMessageEx(TextMessageEx * src, TextMessageEx * dst, SAFEARRAY ** keylist, pEpDecryptFlags *flags, pEpRating *rating)
   1.212 +{
   1.213 +    assert(src);
   1.214 +    assert(dst);
   1.215 +    assert(keylist);
   1.216 +    assert(flags);
   1.217 +    assert(rating);
   1.218 +
   1.219 +    if (!(src && dst && keylist && flags && rating))
   1.220 +        return E_INVALIDARG;
   1.221 +
   1.222 +    *keylist = NULL;
   1.223 +    *rating = pEpRatingUndefined;
   1.224 +
   1.225 +    ::message *_src = text_message_to_C(src);
   1.226 +    ::message *msg_dst = NULL;
   1.227 +    ::stringlist_t *_keylist = NULL;
   1.228 +    ::PEP_rating _rating;
   1.229 +
   1.230 +    PEP_decrypt_flags_t engineflags = 0;
   1.231 +    PEP_STATUS status = ::decrypt_message(get_session(), _src, &msg_dst, &_keylist, &_rating, &engineflags);
   1.232 +
   1.233 +    *flags = (pEpDecryptFlags)engineflags;
   1.234 +
   1.235 +    if (msg_dst)
   1.236 +        text_message_from_C(dst, msg_dst);
   1.237 +
   1.238 +    ::free_message(_src);
   1.239 +    ::free_message(msg_dst);
   1.240 +
   1.241 +    if (_keylist) {
   1.242 +        *keylist = string_array(_keylist);
   1.243 +        free_stringlist(_keylist);
   1.244 +    }
   1.245 +
   1.246 +    *rating = (pEpRating)_rating;
   1.247 +
   1.248 +    return S_OK;
   1.249 +}
   1.250 +
   1.251  STDMETHODIMP CpEpEngine::OutgoingMessageRating(TextMessage *msg, pEpRating * pVal)
   1.252  {
   1.253      assert(msg);
   1.254 @@ -963,6 +1179,25 @@
   1.255      return S_OK;
   1.256  }
   1.257  
   1.258 +STDMETHODIMP CpEpEngine::OutgoingMessageRatingEx(TextMessageEx *msg, pEpRating * pVal)
   1.259 +{
   1.260 +    assert(msg);
   1.261 +    assert(pVal);
   1.262 +
   1.263 +    if (!(msg  && pVal))
   1.264 +        return E_INVALIDARG;
   1.265 +
   1.266 +    ::message *_msg = text_message_to_C(msg);
   1.267 +
   1.268 +    PEP_rating _rating;
   1.269 +    PEP_STATUS status = ::outgoing_message_rating(get_session(), _msg, &_rating);
   1.270 +    if (status != PEP_STATUS_OK)
   1.271 +        return FAIL(L"cannot get message rating", status);
   1.272 +
   1.273 +    *pVal = (pEpRating)_rating;
   1.274 +    return S_OK;
   1.275 +}
   1.276 +
   1.277  STDMETHODIMP CpEpEngine::IdentityRating(struct pEpIdentity *ident, pEpRating * pVal)
   1.278  {
   1.279      ::pEp_identity *_ident;
     2.1 --- a/CpEpEngine.h	Fri Apr 21 17:11:50 2017 +0200
     2.2 +++ b/CpEpEngine.h	Wed Jun 14 23:46:37 2017 +0200
     2.3 @@ -24,7 +24,7 @@
     2.4      public CComObjectRootEx<CComObjectThreadModel>,
     2.5  	public CComCoClass<CpEpEngine, &CLSID_pEpEngine>,
     2.6  	public ISupportErrorInfo,
     2.7 -	public IpEpEngine2
     2.8 +	public IpEpEngine3
     2.9  {
    2.10  protected:
    2.11      static int examine_identity(pEp_identity *ident, void *management);
    2.12 @@ -53,6 +53,7 @@
    2.13  BEGIN_COM_MAP(CpEpEngine)
    2.14      COM_INTERFACE_ENTRY(IpEpEngine)
    2.15      COM_INTERFACE_ENTRY(IpEpEngine2)
    2.16 +    COM_INTERFACE_ENTRY(IpEpEngine3)
    2.17      COM_INTERFACE_ENTRY(ISupportErrorInfo)
    2.18  END_COM_MAP()
    2.19  
    2.20 @@ -180,7 +181,14 @@
    2.21          /* [in] */ SAFEARRAY *keylist,
    2.22          /* [defaultvalue][in] */ BSTR lang,
    2.23          /* [defaultvalue][in] */ VARIANT_BOOL full,
    2.24 -        /* [retval][out] */ BSTR *words);
    2.25 +        /* [retval][out] */ BSTR *words); 
    2.26 +    STDMETHOD(GetMessageTrustwordsEx)(
    2.27 +            /* [in] */ struct TextMessageEx *msg,
    2.28 +            /* [in] */ struct pEpIdentity *receivedBy,
    2.29 +            /* [in] */ SAFEARRAY *keylist,
    2.30 +            /* [defaultvalue][in] */ BSTR lang,
    2.31 +            /* [defaultvalue][in] */ VARIANT_BOOL full,
    2.32 +            /* [retval][out] */ BSTR *words);
    2.33      STDMETHOD(GetCrashdumpLog)(LONG maxlines, BSTR * log);
    2.34      STDMETHOD(GetEngineVersion)(BSTR * engineVersion);
    2.35      STDMETHOD(GetLanguageList)(BSTR * languages);
    2.36 @@ -211,6 +219,9 @@
    2.37      STDMETHOD(EncryptMessage)(TextMessage * src, TextMessage * dst, SAFEARRAY * extra, pEpEncryptFlags flags);
    2.38      STDMETHOD(DecryptMessage)(TextMessage * src, TextMessage * dst, SAFEARRAY ** keylist, pEpDecryptFlags* flags, pEpRating *rating);
    2.39      STDMETHOD(OutgoingMessageRating)(TextMessage *msg, pEpRating * pVal);
    2.40 +    STDMETHOD(EncryptMessageEx)(TextMessageEx * src, TextMessageEx * dst, SAFEARRAY * extra, pEpEncryptFlags flags);
    2.41 +    STDMETHOD(DecryptMessageEx)(TextMessageEx * src, TextMessageEx * dst, SAFEARRAY ** keylist, pEpDecryptFlags* flags, pEpRating *rating);
    2.42 +    STDMETHOD(OutgoingMessageRatingEx)(TextMessageEx *msg, pEpRating * pVal);
    2.43      STDMETHOD(IdentityRating)(pEpIdentity * ident, pEpRating * pVal);
    2.44  	STDMETHOD(ColorFromRating)(pEpRating rating, pEpColor * pVal);
    2.45  
    2.46 @@ -221,6 +232,13 @@
    2.47          pEpEncryptFlags flags
    2.48          );
    2.49  
    2.50 +    STDMETHOD(EncryptMessageForSelfEx)(
    2.51 +        pEpIdentity * target_id,
    2.52 +        TextMessageEx* src,
    2.53 +        TextMessageEx *dst,
    2.54 +        pEpEncryptFlags flags
    2.55 +        );
    2.56 +
    2.57  	// Event callbacks
    2.58  
    2.59  	STDMETHOD(RegisterCallbacks)(IpEpEngineCallbacks *new_callback);
     3.1 --- a/pEpCOMServerAdapter.idl	Fri Apr 21 17:11:50 2017 +0200
     3.2 +++ b/pEpCOMServerAdapter.idl	Wed Jun 14 23:46:37 2017 +0200
     3.3 @@ -322,6 +322,78 @@
     3.4  };
     3.5  
     3.6  [
     3.7 +    object,
     3.8 +    uuid(FB58B932-77CA-4042-B7CB-FF659358951D),
     3.9 +    oleautomation,
    3.10 +    nonextensible,
    3.11 +    pointer_default(unique)
    3.12 +]
    3.13 +interface IpEpEngine3 : IpEpEngine2
    3.14 +{
    3.15 +    [uuid(F5E2FB60-591B-4F75-8D95-6DA13B4BB98E)] struct BlobEx {
    3.16 +        SAFEARRAY(BYTE) value;
    3.17 +        BSTR MimeType;
    3.18 +        BSTR Filename;
    3.19 +        BSTR ContentId;
    3.20 +    };
    3.21 +
    3.22 +    [uuid(EC006D4A-B2D5-46D6-9B1B-3C6D4123CCF3)] struct TextMessageEx
    3.23 + {
    3.24 +        pEpMsgDirection Dir;
    3.25 +        BSTR Id;
    3.26 +        BSTR ShortMsg;
    3.27 +        BSTR LongMsg;
    3.28 +        BSTR LongMsgFormatted;
    3.29 +        SAFEARRAY(struct BlobEx) Attachments;
    3.30 +        hyper Sent; // Timestamp: 64 Bit time_t from mktime(), seconds since January 1, 1970, 0:00 UTC.
    3.31 +        hyper Recv; // Timestamp: 64 Bit time_t from mktime(), seconds since January 1, 1970, 0:00 UTC.
    3.32 +        struct pEpIdentity From;
    3.33 +        SAFEARRAY(struct pEpIdentity) To;
    3.34 +        struct pEpIdentity RecvBy;
    3.35 +        SAFEARRAY(struct pEpIdentity) Cc;
    3.36 +        SAFEARRAY(struct pEpIdentity) Bcc;
    3.37 +        SAFEARRAY(struct pEpIdentity) ReplyTo;
    3.38 +        SAFEARRAY(BSTR) References;
    3.39 +        SAFEARRAY(BSTR) Keywords;
    3.40 +        BSTR Comments;
    3.41 +        SAFEARRAY(struct StringPair) OptFields;
    3.42 +    };
    3.43 +
    3.44 +
    3.45 +    HRESULT EncryptMessageEx(
    3.46 +        [in] struct TextMessageEx *src,
    3.47 +        [out] struct TextMessageEx * dst,
    3.48 +        [in] SAFEARRAY(BSTR) extra,
    3.49 +        [in, defaultvalue(pEpEncryptFlagDefault)] pEpEncryptFlags flags);
    3.50 +
    3.51 +    HRESULT DecryptMessageEx(
    3.52 +        [in] struct TextMessageEx *src,
    3.53 +        [out] struct TextMessageEx * dst,
    3.54 +        [out] SAFEARRAY(BSTR) *keylist,
    3.55 +        [out] pEpDecryptFlags* flags,
    3.56 +        [out, retval] pEpRating *rating);
    3.57 +
    3.58 +    HRESULT OutgoingMessageRatingEx([in] struct TextMessageEx *msg, [out, retval] pEpRating * pVal);
    3.59 +
    3.60 +    HRESULT GetMessageTrustwordsEx(
    3.61 +        [in] struct TextMessageEx *msg,
    3.62 +        [in] struct pEpIdentity * receivedBy,
    3.63 +        [in] SAFEARRAY(BSTR) keylist,
    3.64 +        [in, defaultvalue("en")] BSTR lang,
    3.65 +        [in, defaultvalue(0)] VARIANT_BOOL full,
    3.66 +        [out, retval] BSTR * words
    3.67 +    );
    3.68 +
    3.69 +    HRESULT EncryptMessageForSelfEx(
    3.70 +        [in] struct pEpIdentity* target_id,
    3.71 +        [in] struct TextMessageEx* src,
    3.72 +        [out] struct TextMessageEx* dst,
    3.73 +        [in, defaultvalue(pEpEncryptFlagDefault)] pEpEncryptFlags flags
    3.74 +    );
    3.75 +}
    3.76 +
    3.77 +
    3.78 +[
    3.79      uuid(564A4350-419E-47F1-B0DF-6FCCF0CD0BBC),
    3.80      version(1.0),
    3.81  ]
    3.82 @@ -333,7 +405,8 @@
    3.83          uuid(5FF6682B-727B-4DFE-A68D-28982874C0C7)
    3.84      ]
    3.85      coclass pEpEngine {
    3.86 -        [default] interface IpEpEngine2;
    3.87 +        [default] interface IpEpEngine3;
    3.88 +        interface IpEpEngine2;
    3.89          interface IpEpEngine;
    3.90          interface IpEpEngineCallbacks2;
    3.91      };
     4.1 --- a/pEp_utility.cpp	Fri Apr 21 17:11:50 2017 +0200
     4.2 +++ b/pEp_utility.cpp	Wed Jun 14 23:46:37 2017 +0200
     4.3 @@ -205,6 +205,34 @@
     4.4              return _blob;
     4.5          }
     4.6  
     4.7 +        template<> BlobEx *from_C< BlobEx *, bloblist_t >(bloblist_t *tl)
     4.8 +        {
     4.9 +            assert(tl);
    4.10 +
    4.11 +            CComSafeArray<BYTE> sa;
    4.12 +            if (tl) {
    4.13 +                sa.Create(tl->size);
    4.14 +                if (tl->size) {
    4.15 +                    char *data;
    4.16 +                    SafeArrayAccessData(sa, (void **)&data);
    4.17 +                    memcpy(data, tl->value, tl->size);
    4.18 +                    SafeArrayUnaccessData(sa);
    4.19 +                }
    4.20 +            }
    4.21 +            else {
    4.22 +                sa.Create((ULONG)0);
    4.23 +            }
    4.24 +
    4.25 +            BlobEx *_blob = new BlobEx();
    4.26 +
    4.27 +            _blob->value = sa.Detach();
    4.28 +            _blob->MimeType = bstr(tl->mime_type);
    4.29 +            _blob->Filename = bstr(tl->filename);
    4.30 +            _blob->ContentId = bstr(tl->content_id);
    4.31 +
    4.32 +            return _blob;
    4.33 +        }
    4.34 +
    4.35          template< class T > int length(T *);
    4.36  
    4.37          template< class T2, class T > SAFEARRAY * array_from_C(T *tl)
    4.38 @@ -312,6 +340,31 @@
    4.39              memset(msg, 0, sizeof(TextMessage));
    4.40          }
    4.41  
    4.42 +        void clear_text_message(TextMessageEx *msg)
    4.43 +        {
    4.44 +            assert(msg);
    4.45 +            if (!msg)
    4.46 +                return;
    4.47 +
    4.48 +            SysFreeString(msg->Id);
    4.49 +            SysFreeString(msg->ShortMsg);
    4.50 +            SysFreeString(msg->LongMsg);
    4.51 +            SysFreeString(msg->LongMsgFormatted);
    4.52 +            SafeArrayDestroy(msg->Attachments);
    4.53 +            clear_identity_s(msg->From);
    4.54 +            SafeArrayDestroy(msg->To);
    4.55 +            clear_identity_s(msg->RecvBy);
    4.56 +            SafeArrayDestroy(msg->Cc);
    4.57 +            SafeArrayDestroy(msg->Bcc);
    4.58 +            SafeArrayDestroy(msg->ReplyTo);
    4.59 +            SafeArrayDestroy(msg->References);
    4.60 +            SafeArrayDestroy(msg->Keywords);
    4.61 +            SysFreeString(msg->Comments);
    4.62 +            SafeArrayDestroy(msg->OptFields);
    4.63 +
    4.64 +            memset(msg, 0, sizeof(TextMessage));
    4.65 +        }
    4.66 +
    4.67          void text_message_from_C(TextMessage *msg2, const ::message *msg)
    4.68          {
    4.69              assert(msg2);
    4.70 @@ -352,6 +405,46 @@
    4.71              msg2->OptFields = array_from_C<StringPair, stringpair_list_t>(msg->opt_fields);
    4.72          }
    4.73  
    4.74 +        void text_message_from_C(TextMessageEx *msg2, const ::message *msg)
    4.75 +        {
    4.76 +            assert(msg2);
    4.77 +            assert(msg);
    4.78 +
    4.79 +            if (!msg2) {
    4.80 +                msg2 = (TextMessageEx *)calloc(1, sizeof(TextMessageEx));
    4.81 +                assert(msg2);
    4.82 +                if (!msg2)
    4.83 +                    throw bad_alloc();
    4.84 +            }
    4.85 +            else {
    4.86 +                clear_text_message(msg2);
    4.87 +            }
    4.88 +
    4.89 +            if (!msg)
    4.90 +                return;
    4.91 +
    4.92 +            msg2->Dir = (pEpMsgDirection)msg->dir;
    4.93 +            msg2->Id = bstr(msg->id);
    4.94 +            msg2->ShortMsg = bstr(msg->shortmsg);
    4.95 +            msg2->LongMsg = bstr(msg->longmsg);
    4.96 +            msg2->LongMsgFormatted = bstr(msg->longmsg_formatted);
    4.97 +            msg2->Attachments = array_from_C<BlobEx, bloblist_t>(msg->attachments);
    4.98 +            if (msg->sent)
    4.99 +                msg2->Sent = mktime(msg->sent);
   4.100 +            if (msg->recv)
   4.101 +                msg2->Recv = mktime(msg->recv);
   4.102 +            msg2->From = identity_s(msg->from);
   4.103 +            msg2->To = array_from_C<pEpIdentity, identity_list>(msg->to);
   4.104 +            msg2->RecvBy = identity_s(msg->recv_by);
   4.105 +            msg2->Cc = array_from_C<pEpIdentity, identity_list>(msg->cc);
   4.106 +            msg2->Bcc = array_from_C<pEpIdentity, identity_list>(msg->bcc);
   4.107 +            msg2->ReplyTo = array_from_C<pEpIdentity, identity_list>(msg->reply_to);
   4.108 +            msg2->References = string_array(msg->references);
   4.109 +            msg2->Keywords = string_array(msg->keywords);
   4.110 +            msg2->Comments = bstr(msg->comments);
   4.111 +            msg2->OptFields = array_from_C<StringPair, stringpair_list_t>(msg->opt_fields);
   4.112 +        }
   4.113 +
   4.114          char * str(BSTR s)
   4.115          {
   4.116              string str = utf8_string(s);
   4.117 @@ -370,6 +463,15 @@
   4.118              memset(&b, 0, sizeof(Blob));
   4.119          }
   4.120  
   4.121 +        void clear_blob(BlobEx& b)
   4.122 +        {
   4.123 +            SysFreeString(b.Filename);
   4.124 +            SysFreeString(b.MimeType);
   4.125 +            SysFreeString(b.ContentId);
   4.126 +            SafeArrayDestroy(b.value);
   4.127 +            memset(&b, 0, sizeof(Blob));
   4.128 +        }
   4.129 +
   4.130          bloblist_t *bloblist(SAFEARRAY *sa)
   4.131          {
   4.132              if (sa == NULL)
   4.133 @@ -383,7 +485,7 @@
   4.134              if (size <= 0)
   4.135                  return NULL;
   4.136  
   4.137 -            bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL);
   4.138 +            bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL, NULL);
   4.139              if (bl == NULL)
   4.140                  throw bad_alloc();
   4.141  
   4.142 @@ -417,7 +519,68 @@
   4.143                          throw bad_alloc();
   4.144  
   4.145                  }
   4.146 -                _bl = bloblist_add(_bl, buffer, size, str(b.MimeType), str(b.Filename));
   4.147 +                _bl = bloblist_add(_bl, buffer, size, str(b.MimeType), str(b.Filename), "");
   4.148 +                if (_bl == NULL) {
   4.149 +                    free(buffer);
   4.150 +                    clear_blob(b);
   4.151 +                    free_bloblist(bl);
   4.152 +                    throw bad_alloc();
   4.153 +                }
   4.154 +
   4.155 +                clear_blob(b);
   4.156 +            }
   4.157 +
   4.158 +            return bl;
   4.159 +        }
   4.160 +
   4.161 +        bloblist_t *bloblistEx(SAFEARRAY *sa)
   4.162 +        {
   4.163 +            if (sa == NULL)
   4.164 +                return NULL;
   4.165 +
   4.166 +            LONG lbound, ubound;
   4.167 +            SafeArrayGetLBound(sa, 1, &lbound);
   4.168 +            SafeArrayGetUBound(sa, 1, &ubound);
   4.169 +
   4.170 +            size_t size = ubound - lbound + 1;
   4.171 +            if (size <= 0)
   4.172 +                return NULL;
   4.173 +
   4.174 +            bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL, NULL);
   4.175 +            if (bl == NULL)
   4.176 +                throw bad_alloc();
   4.177 +
   4.178 +            bloblist_t *_bl = bl;
   4.179 +            for (LONG i = lbound; i <= ubound; i++) {
   4.180 +                BlobEx b;
   4.181 +                memset(&b, 0, sizeof(BlobEx));
   4.182 +                SafeArrayGetElement(sa, &i, &b);
   4.183 +
   4.184 +                LONG _lbound, _ubound;
   4.185 +                SafeArrayGetLBound(b.value, 1, &_lbound);
   4.186 +                SafeArrayGetUBound(b.value, 1, &_ubound);
   4.187 +                size_t size = _ubound - _lbound + 1;
   4.188 +
   4.189 +                char *buffer;
   4.190 +                if (size) {
   4.191 +                    buffer = (char *)malloc(size + 1);
   4.192 +                    if (buffer == NULL)
   4.193 +                        throw bad_alloc();
   4.194 +
   4.195 +                    char *data;
   4.196 +
   4.197 +                    SafeArrayAccessData(b.value, (void **)&data);
   4.198 +                    memcpy(buffer, data, size);
   4.199 +                    buffer[size] = 0; // safeguard
   4.200 +                    SafeArrayUnaccessData(sa);
   4.201 +                }
   4.202 +                else {
   4.203 +                    buffer = _strdup("");
   4.204 +                    if (buffer == NULL)
   4.205 +                        throw bad_alloc();
   4.206 +
   4.207 +                }
   4.208 +                _bl = bloblist_add(_bl, buffer, size, str(b.MimeType), str(b.Filename), str(b.ContentId));
   4.209                  if (_bl == NULL) {
   4.210                      free(buffer);
   4.211                      clear_blob(b);
   4.212 @@ -569,6 +732,37 @@
   4.213              return msg2;
   4.214          }
   4.215  
   4.216 +        ::message * text_message_to_C(TextMessageEx *msg)
   4.217 +        {
   4.218 +            assert(msg);
   4.219 +            if (!msg)
   4.220 +                throw invalid_argument("msg");
   4.221 +
   4.222 +            ::message * msg2 = new_message((PEP_msg_direction)msg->Dir);
   4.223 +            if (msg2 == NULL)
   4.224 +                throw bad_alloc();
   4.225 +
   4.226 +            msg2->id = str(msg->Id);
   4.227 +            msg2->shortmsg = str(msg->ShortMsg);
   4.228 +            msg2->longmsg = str(msg->LongMsg);
   4.229 +            msg2->longmsg_formatted = str(msg->LongMsgFormatted);
   4.230 +            msg2->attachments = bloblistEx(msg->Attachments);
   4.231 +            msg2->sent = new_timestamp(msg->Sent);
   4.232 +            msg2->recv = new_timestamp(msg->Recv);
   4.233 +            msg2->from = new_identity(&msg->From);
   4.234 +            msg2->to = identities(msg->To);
   4.235 +            msg2->recv_by = new_identity(&msg->RecvBy);
   4.236 +            msg2->cc = identities(msg->Cc);
   4.237 +            msg2->bcc = identities(msg->Bcc);
   4.238 +            msg2->reply_to = identities(msg->ReplyTo);
   4.239 +            msg2->references = new_stringlist(msg->References);
   4.240 +            msg2->keywords = new_stringlist(msg->Keywords);
   4.241 +            msg2->comments = str(msg->Comments);
   4.242 +            msg2->opt_fields = stringpair_list(msg->OptFields);
   4.243 +
   4.244 +            return msg2;
   4.245 +        }
   4.246 +
   4.247  		void opt_field_array_from_C(stringpair_list_t* spair_list, LPSAFEARRAY* pair_list_out) {
   4.248  			assert(spair_list);
   4.249  			assert(pair_list_out);
     5.1 --- a/pEp_utility.h	Fri Apr 21 17:11:50 2017 +0200
     5.2 +++ b/pEp_utility.h	Wed Jun 14 23:46:37 2017 +0200
     5.3 @@ -83,5 +83,8 @@
     5.4  
     5.5          ::message * text_message_to_C(TextMessage *msg);
     5.6          void text_message_from_C(TextMessage *msg2, const ::message *msg);
     5.7 +
     5.8 +        ::message * text_message_to_C(TextMessageEx *msg);
     5.9 +        void text_message_from_C(TextMessageEx *msg2, const ::message *msg);
    5.10      }
    5.11  }