pEp_utility.cpp
author Markus Schaber <markus@pep-security.net>
Tue, 03 May 2016 20:15:26 +0200
changeset 71 8d19e1c194f0
parent 69 8e47cec9271b
child 74 f2531096699e
permissions -rw-r--r--
Fix com server registration via /Regserver
vb@10
     1
#include "stdafx.h"
vb@33
     2
#include "pEp_utility.h"
vb@33
     3
vb@33
     4
using namespace ATL;
vb@10
     5
vb@10
     6
namespace pEp {
vb@10
     7
    namespace utility {
vb@10
     8
        pEp_identity_cpp::pEp_identity_cpp(const ::pEp_identity *_ident)
vb@10
     9
            : me(false)
vb@10
    10
        {
vb@10
    11
            if (_ident->address)
vb@10
    12
                address = _ident->address;
vb@10
    13
            if (_ident->fpr)
vb@10
    14
                fpr = _ident->fpr;
vb@10
    15
            if (_ident->user_id)
vb@10
    16
                user_id = _ident->user_id;
vb@10
    17
            if (_ident->username)
vb@10
    18
                username = _ident->username;
vb@10
    19
            comm_type = (pEp_comm_type) _ident->comm_type;
vb@10
    20
            lang = _ident->lang;
vb@10
    21
        }
vb@10
    22
vb@10
    23
        pEp_identity_cpp::pEp_identity_cpp(const pEp_identity_s *_ident)
vb@10
    24
            : me(false)
vb@10
    25
        {
vb@10
    26
            if (_ident->address)
vb@10
    27
                address = utf8_string(_ident->address);
vb@10
    28
            if (_ident->fpr)
vb@10
    29
                fpr = utf8_string(_ident->fpr);
vb@10
    30
            if (_ident->user_id)
vb@10
    31
                user_id = utf8_string(_ident->user_id);
vb@10
    32
            if (_ident->username)
vb@10
    33
                username = utf8_string(_ident->username);
vb@10
    34
            comm_type = _ident->comm_type;
vb@10
    35
            if (_ident->lang)
vb@10
    36
                lang = utf8_string(_ident->lang);
vb@10
    37
        }
vb@10
    38
vb@10
    39
        pEp_identity * pEp_identity_cpp::to_pEp_identity()
vb@10
    40
        {
vb@10
    41
            ::pEp_identity *_ident = ::new_identity(this->address.c_str(), this->fpr.c_str(), this->user_id.c_str(), this->username.c_str());
vb@10
    42
            assert(_ident);
vb@10
    43
            if (_ident == NULL)
vb@10
    44
                throw bad_alloc();
vb@10
    45
vb@10
    46
            _ident->comm_type = (::PEP_comm_type) this->comm_type;
vb@10
    47
            _ident->me = this->me;
vb@10
    48
vb@10
    49
            assert(this->lang.size() == 0 || this->lang.size() == 2);
vb@10
    50
vb@10
    51
            if (this->lang.size()) {
vb@10
    52
                _ident->lang[0] = this->lang[0];
vb@10
    53
                _ident->lang[1] = this->lang[1];
vb@10
    54
            }
vb@10
    55
vb@10
    56
            return _ident;
vb@10
    57
        }
vb@10
    58
vb@10
    59
        pEp_identity_s * pEp_identity_cpp::to_pEp_identity_s()
vb@10
    60
        {
vb@10
    61
            pEp_identity_s *_ident = (pEp_identity_s *) calloc(1, sizeof(pEp_identity_s));
vb@10
    62
            assert(_ident);
vb@10
    63
            if (_ident == NULL)
vb@10
    64
                throw bad_alloc();
vb@10
    65
vb@40
    66
            _ident->address = utf16_bstr(this->address);
vb@10
    67
            _ident->comm_type = this->comm_type;
vb@40
    68
            _ident->fpr = utf16_bstr(this->fpr);
vb@40
    69
            _ident->lang = utf16_bstr(this->lang);
vb@40
    70
            _ident->username = utf16_bstr(this->username);
vb@40
    71
            _ident->user_id = utf16_bstr(this->user_id);
vb@10
    72
vb@10
    73
            return _ident;
vb@10
    74
        }
vb@10
    75
vb@10
    76
        void copy_identity(pEp_identity_s * ident_s, const pEp_identity * ident)
vb@10
    77
        {
vb@10
    78
            assert(ident_s);
vb@10
    79
vb@10
    80
            ::memset(ident_s, 0, sizeof(pEp_identity_s));
vb@10
    81
            if (ident) {
vb@10
    82
                if (ident->address)
vb@40
    83
                    ident_s->address = utf16_bstr(ident->address);
vb@10
    84
                if (ident->fpr)
vb@40
    85
                    ident_s->fpr = utf16_bstr(ident->fpr);
vb@10
    86
                if (ident->user_id)
vb@40
    87
                    ident_s->user_id = utf16_bstr(ident->user_id);
vb@10
    88
                if (ident->username)
vb@40
    89
                    ident_s->username = utf16_bstr(ident->username);
vb@10
    90
                ident_s->comm_type = (pEp_comm_type) ident->comm_type;
vb@10
    91
                if (ident->lang)
vb@40
    92
                    ident_s->lang = utf16_bstr(ident->lang);
vb@10
    93
            }
vb@10
    94
        }
vb@10
    95
vb@10
    96
        ::pEp_identity *new_identity(const pEp_identity_s * ident)
vb@10
    97
        {
vb@37
    98
            if (ident == NULL)
vb@37
    99
                return NULL;
vb@37
   100
vb@10
   101
            ::pEp_identity *_ident;
vb@10
   102
vb@10
   103
            string _address;
vb@10
   104
            string _fpr;
vb@10
   105
            string _user_id;
vb@10
   106
            string _username;
vb@10
   107
vb@10
   108
            if (ident->address)
vb@10
   109
                _address = utf8_string(ident->address);
vb@10
   110
            if (ident->fpr) {
vb@10
   111
                _fpr = utf8_string(ident->fpr);
vb@10
   112
                for (auto p = _fpr.begin(); p != _fpr.end(); ++p) {
vb@10
   113
                    if (*p >= 'A' && *p <= 'Z')
vb@10
   114
                        continue;
vb@10
   115
                    if (*p >= '0' && *p <= '9')
vb@10
   116
                        continue;
vb@10
   117
                    throw invalid_argument("invalid hex digits in fingerprint");
vb@10
   118
                }
vb@10
   119
            }
vb@10
   120
            if (ident->user_id)
vb@10
   121
                _user_id = utf8_string(ident->user_id);
vb@10
   122
            if (ident->username)
vb@10
   123
                _username = utf8_string(ident->username);
vb@10
   124
vb@10
   125
            _ident = ::new_identity(_address.c_str(), _fpr.c_str(), _user_id.c_str(), _username.c_str());
vb@10
   126
            assert(_ident);
vb@10
   127
            if (_ident == NULL)
vb@10
   128
                throw bad_alloc();
vb@10
   129
vb@10
   130
            _ident->comm_type = (PEP_comm_type) ident->comm_type;
vb@10
   131
vb@10
   132
            if (ident->lang) {
vb@10
   133
                string _lang = utf8_string(ident->lang);
vb@10
   134
                if (_lang.length() != 0) {
vb@10
   135
                    if (_lang.length() != 2) {
vb@10
   136
                        ::free_identity(_ident);
vb@10
   137
                        throw invalid_argument("invalid language code");
vb@10
   138
                    }
vb@10
   139
                    if (_lang[0] < 'a' || _lang[0] > 'z') {
vb@10
   140
                        ::free_identity(_ident);
vb@10
   141
                        throw invalid_argument("invalid language code");
vb@10
   142
                    }
vb@10
   143
                    if (_lang[1] < 'a' || _lang[1] > 'z') {
vb@10
   144
                        ::free_identity(_ident);
vb@10
   145
                        throw invalid_argument("invalid language code");
vb@10
   146
                    }
vb@10
   147
                    _ident->lang[0] = _lang[0];
vb@10
   148
                    _ident->lang[1] = _lang[1];
vb@10
   149
                }
vb@10
   150
            }
vb@10
   151
vb@10
   152
            return _ident;
vb@10
   153
        }
vb@33
   154
vb@33
   155
        template< class T2, class T > T2 from_C(T *tl);
vb@33
   156
vb@41
   157
        BSTR bstr(char *s)
vb@33
   158
        {
vb@42
   159
            if (s == NULL)
vb@33
   160
                return _bstr_t(L"").Detach();
vb@42
   161
vb@42
   162
            return utf16_bstr(s);
vb@33
   163
        }
vb@33
   164
vb@33
   165
        template<> blob *from_C< blob *, bloblist_t >(bloblist_t *tl)
vb@33
   166
        {
vb@33
   167
            CComSafeArray<BYTE> sa;
vb@33
   168
            sa.Create(tl->size);
vb@33
   169
vb@43
   170
            char *data;
vb@43
   171
            SafeArrayAccessData(sa, (void **) &data);
vb@43
   172
            memcpy(data, tl->value, tl->size);
vb@43
   173
            SafeArrayUnaccessData(sa);
vb@33
   174
vb@33
   175
            blob *_blob = new blob();
vb@33
   176
vb@33
   177
            _blob->value = sa.Detach();
vb@33
   178
            _blob->mime_type = bstr(tl->mime_type);
vb@33
   179
            _blob->filename = bstr(tl->filename);
vb@33
   180
vb@33
   181
            return _blob;
vb@33
   182
        }
vb@33
   183
vb@33
   184
        template< class T > int length(T *);
vb@33
   185
vb@33
   186
        template< class T2, class T > SAFEARRAY * array_from_C(T *tl)
vb@33
   187
        {
vb@39
   188
            if (tl == NULL)
vb@39
   189
                return newSafeArray<T2>(0);
vb@39
   190
vb@33
   191
            int len = length<T>(tl);
vb@33
   192
vb@33
   193
            LPSAFEARRAY sa = newSafeArray<T2>(len);
vb@33
   194
            LONG lbound, ubound;
vb@33
   195
            SafeArrayGetLBound(sa, 1, &lbound);
vb@33
   196
            SafeArrayGetUBound(sa, 1, &ubound);
vb@33
   197
vb@33
   198
            T *_tl = tl;
vb@38
   199
            for (LONG i = lbound; i <= ubound; _tl = _tl->next, i++)
vb@33
   200
                SafeArrayPutElement(sa, &i, from_C<T2 *, T>(_tl));
vb@33
   201
vb@33
   202
            return sa;
vb@33
   203
        }
vb@33
   204
vb@41
   205
        void clear_identity_s(pEp_identity_s& ident)
vb@41
   206
        {
vb@41
   207
            SysFreeString(ident.address);
vb@41
   208
            SysFreeString(ident.fpr);
vb@41
   209
            SysFreeString(ident.lang);
vb@41
   210
            SysFreeString(ident.username);
vb@41
   211
            SysFreeString(ident.user_id);
vb@41
   212
vb@41
   213
            memset(&ident, 0, sizeof(pEp_identity_s));
vb@41
   214
        }
vb@41
   215
vb@33
   216
        template<> pEp_identity_s from_C< pEp_identity_s, pEp_identity >(pEp_identity *tl)
vb@33
   217
        {
vb@33
   218
            pEp_identity_s _ident;
vb@41
   219
            memset(&_ident, 0, sizeof(_ident));
vb@41
   220
vb@39
   221
            if (tl)
vb@39
   222
                copy_identity(&_ident, tl);
vb@33
   223
            return _ident;
vb@33
   224
        }
vb@33
   225
vb@33
   226
        pEp_identity_s identity_s(pEp_identity *ident)
vb@33
   227
        {
vb@33
   228
            return from_C< pEp_identity_s, pEp_identity >(ident);
vb@33
   229
        }
vb@33
   230
vb@33
   231
        template<> pEp_identity_s *from_C< pEp_identity_s *, identity_list >(identity_list *il)
vb@33
   232
        {
vb@33
   233
            pEp_identity_s *ident = new pEp_identity_s();
vb@41
   234
            memset(ident, 0, sizeof(pEp_identity_s));
vb@41
   235
vb@39
   236
            if (il)
vb@39
   237
                copy_identity(ident, il->ident);
vb@33
   238
            return ident;
vb@33
   239
        }
vb@33
   240
vb@33
   241
        template<> opt_field *from_C< opt_field *, stringpair_list_t >(stringpair_list_t * sp)
vb@33
   242
        {
vb@33
   243
            opt_field *fld = new opt_field();
vb@39
   244
            if (sp) {
vb@39
   245
                fld->name = bstr(sp->value->key);
vb@39
   246
                fld->value = bstr(sp->value->value);
vb@39
   247
            }
vb@33
   248
            return fld;
vb@33
   249
        }
vb@33
   250
vb@33
   251
        template<> int length<identity_list>(identity_list *tl)
vb@33
   252
        {
vb@33
   253
            return identity_list_length(tl);
vb@33
   254
        }
vb@33
   255
vb@33
   256
        template<> int length<bloblist_t>(bloblist_t *tl)
vb@33
   257
        {
vb@33
   258
            return bloblist_length(tl);
vb@33
   259
        }
vb@33
   260
vb@33
   261
        template<> int length<stringpair_list_t>(stringpair_list_t *tl)
vb@33
   262
        {
vb@33
   263
            return stringpair_list_length(tl);
vb@33
   264
        }
vb@33
   265
vb@41
   266
        void clear_text_message(text_message *msg)
vb@41
   267
        {
vb@41
   268
            SysFreeString(msg->id);
vb@41
   269
            SysFreeString(msg->shortmsg);
vb@41
   270
            SysFreeString(msg->longmsg);
vb@41
   271
            SysFreeString(msg->longmsg_formatted);
vb@41
   272
            SafeArrayDestroy(msg->attachments);
vb@41
   273
            clear_identity_s(msg->from);
vb@41
   274
            SafeArrayDestroy(msg->to);
vb@41
   275
            clear_identity_s(msg->recv_by);
vb@41
   276
            SafeArrayDestroy(msg->cc);
vb@41
   277
            SafeArrayDestroy(msg->bcc);
vb@41
   278
            SafeArrayDestroy(msg->reply_to);
vb@41
   279
            SafeArrayDestroy(msg->references);
vb@41
   280
            SafeArrayDestroy(msg->keywords);
vb@41
   281
            SysFreeString(msg->comments);
vb@41
   282
            SafeArrayDestroy(msg->opt_fields);
vb@41
   283
vb@41
   284
            memset(msg, 0, sizeof(text_message));
vb@41
   285
        }
vb@41
   286
vb@37
   287
        void text_message_from_C(text_message *msg2, ::message *msg)
vb@33
   288
        {
vb@37
   289
            assert(msg2);
vb@33
   290
            assert(msg);
vb@33
   291
vb@41
   292
            clear_text_message(msg2);
vb@41
   293
vb@33
   294
            msg2->dir = (pEp_msg_direction) msg->dir;
vb@33
   295
            msg2->id = bstr(msg->id);
vb@33
   296
            msg2->shortmsg = bstr(msg->shortmsg);
vb@33
   297
            msg2->longmsg = bstr(msg->longmsg);
vb@33
   298
            msg2->longmsg_formatted = bstr(msg->longmsg_formatted);
vb@33
   299
            msg2->attachments = array_from_C<blob, bloblist_t>(msg->attachments);
vb@39
   300
            if (msg->sent)
vb@39
   301
                msg2->sent = mktime(msg->sent);
vb@39
   302
            if (msg->recv)
vb@39
   303
                msg2->recv = mktime(msg->recv);
vb@33
   304
            msg2->from = identity_s(msg->from);
vb@33
   305
            msg2->to = array_from_C<pEp_identity_s, identity_list>(msg->to);
vb@33
   306
            msg2->recv_by = identity_s(msg->recv_by);
vb@33
   307
            msg2->cc = array_from_C<pEp_identity_s, identity_list>(msg->cc);
vb@33
   308
            msg2->bcc = array_from_C<pEp_identity_s, identity_list>(msg->bcc);
vb@33
   309
            msg2->reply_to = array_from_C<pEp_identity_s, identity_list>(msg->reply_to);
vb@40
   310
            msg2->references = string_array(msg->references);
vb@40
   311
            msg2->keywords = string_array(msg->keywords);
vb@33
   312
            msg2->comments = bstr(msg->comments);
vb@33
   313
            msg2->opt_fields = array_from_C<opt_field, stringpair_list_t>(msg->opt_fields);
vb@33
   314
        }
vb@33
   315
vb@37
   316
        char * str(BSTR s)
vb@33
   317
        {
vb@37
   318
            string str = utf8_string(s);
vb@37
   319
            char *_s = _strdup(str.c_str());
vb@33
   320
            if (_s == NULL)
vb@33
   321
                throw bad_alloc();
vb@33
   322
vb@37
   323
            return _s;
vb@33
   324
        }
vb@33
   325
vb@41
   326
        void clear_blob(blob& b)
vb@41
   327
        {
vb@41
   328
            SysFreeString(b.filename);
vb@41
   329
            SysFreeString(b.mime_type);
vb@41
   330
            SafeArrayDestroy(b.value);
vb@41
   331
            memset(&b, 0, sizeof(blob));
vb@41
   332
        }
vb@41
   333
vb@33
   334
        bloblist_t *bloblist(SAFEARRAY *sa)
vb@33
   335
        {
vb@37
   336
            if (sa == NULL)
vb@37
   337
                return NULL;
vb@37
   338
vb@33
   339
            LONG lbound, ubound;
vb@33
   340
            SafeArrayGetLBound(sa, 1, &lbound);
vb@33
   341
            SafeArrayGetUBound(sa, 1, &ubound);
vb@33
   342
vb@33
   343
            size_t size = ubound - lbound + 1;
vb@33
   344
            if (size <= 0)
vb@33
   345
                return NULL;
vb@33
   346
vb@33
   347
            bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL);
vb@33
   348
            if (bl == NULL)
vb@33
   349
                throw bad_alloc();
vb@33
   350
vb@33
   351
            bloblist_t *_bl = bl;
vb@33
   352
            for (LONG i = lbound; i <= ubound; i++) {
vb@33
   353
                blob b;
vb@38
   354
                memset(&b, 0, sizeof(blob));
vb@33
   355
                SafeArrayGetElement(sa, &i, &b);
vb@33
   356
vb@38
   357
                LONG _lbound, _ubound;
vb@38
   358
                SafeArrayGetLBound(b.value, 1, &_lbound);
vb@38
   359
                SafeArrayGetUBound(b.value, 1, &_ubound);
vb@38
   360
                size_t size = _ubound - _lbound + 1;
vb@38
   361
vb@33
   362
                char *buffer = (char *) malloc(size);
vb@33
   363
                if (buffer == NULL)
vb@33
   364
                    throw bad_alloc();
vb@33
   365
vb@33
   366
                char *data;
vb@33
   367
vb@33
   368
                SafeArrayAccessData(b.value, (void **) &data);
vb@33
   369
                memcpy(buffer, data, size);
vb@33
   370
                SafeArrayUnaccessData(sa);
vb@33
   371
vb@38
   372
                _bl = bloblist_add(_bl, buffer, size, str(b.mime_type), str(b.filename));
vb@33
   373
                if (_bl == NULL) {
vb@42
   374
                    free(buffer);
vb@41
   375
                    clear_blob(b);
vb@33
   376
                    free_bloblist(bl);
vb@33
   377
                    throw bad_alloc();
vb@33
   378
                }
vb@33
   379
vb@41
   380
                clear_blob(b);
vb@33
   381
            }
vb@33
   382
vb@33
   383
            return bl;
vb@33
   384
        }
vb@33
   385
vb@33
   386
        identity_list *identities(SAFEARRAY * sa)
vb@33
   387
        {
vb@37
   388
            if (sa == NULL)
vb@37
   389
                return NULL;
vb@37
   390
vb@33
   391
            LONG lbound, ubound;
vb@33
   392
            SafeArrayGetLBound(sa, 1, &lbound);
vb@33
   393
            SafeArrayGetUBound(sa, 1, &ubound);
vb@33
   394
vb@33
   395
            size_t size = ubound - lbound + 1;
vb@33
   396
            if (size <= 0)
vb@33
   397
                return NULL;
vb@33
   398
vb@33
   399
            identity_list *il = new_identity_list(NULL);
vb@33
   400
vb@33
   401
            identity_list *_il = il;
vb@33
   402
            for (LONG i = lbound; i <= ubound; i++) {
vb@33
   403
                pEp_identity_s s;
vb@41
   404
                memset(&s, 0, sizeof(pEp_identity_s));
vb@33
   405
                SafeArrayGetElement(sa, &i, &s);
vb@33
   406
vb@33
   407
                pEp_identity *ident;
vb@33
   408
                try {
vb@33
   409
                    ident = new_identity(&s);
vb@33
   410
                }
vb@33
   411
                catch (bad_alloc&) {
vb@41
   412
                    clear_identity_s(s);
vb@33
   413
                    throw bad_alloc();
vb@33
   414
                }
vb@33
   415
vb@41
   416
                clear_identity_s(s);
vb@33
   417
vb@33
   418
                _il = identity_list_add(_il, ident);
vb@33
   419
                if (_il == NULL) {
vb@33
   420
                    free_identity_list(il);
vb@33
   421
                    throw bad_alloc();
vb@33
   422
                }
vb@33
   423
            }
vb@33
   424
vb@33
   425
            return il;
vb@33
   426
        }
vb@33
   427
vb@33
   428
        stringpair_t *new_stringpair(opt_field *fld)
vb@33
   429
        {
vb@33
   430
            stringpair_t *pair = ::new_stringpair(str(fld->name), str(fld->value));
vb@33
   431
            if (pair == NULL)
vb@33
   432
                throw bad_alloc();
vb@33
   433
vb@33
   434
            return pair;
vb@33
   435
        }
vb@33
   436
vb@41
   437
        void clear_opt_field(opt_field& f)
vb@41
   438
        {
vb@41
   439
            SysFreeString(f.name);
vb@41
   440
            SysFreeString(f.value);
vb@41
   441
            memset(&f, 0, sizeof(opt_field));
vb@41
   442
        }
vb@41
   443
vb@33
   444
        stringpair_list_t *stringpair_list(SAFEARRAY * sa)
vb@33
   445
        {
vb@37
   446
            if (sa == NULL)
vb@37
   447
                return NULL;
vb@37
   448
vb@33
   449
            LONG lbound, ubound;
vb@33
   450
            SafeArrayGetLBound(sa, 1, &lbound);
vb@33
   451
            SafeArrayGetUBound(sa, 1, &ubound);
vb@33
   452
vb@33
   453
            size_t size = ubound - lbound + 1;
vb@33
   454
            if (size <= 0)
vb@33
   455
                return NULL;
vb@33
   456
vb@33
   457
            stringpair_list_t *il = new_stringpair_list(NULL);
vb@33
   458
vb@33
   459
            stringpair_list_t *_il = il;
vb@33
   460
            for (LONG i = lbound; i <= ubound; i++) {
vb@33
   461
                opt_field s;
vb@37
   462
                memset(&s, 0, sizeof(opt_field));
vb@33
   463
                SafeArrayGetElement(sa, &i, &s);
vb@33
   464
vb@33
   465
                stringpair_t *pair;
vb@33
   466
                try {
vb@33
   467
                    pair = new_stringpair(&s);
vb@33
   468
                }
vb@33
   469
                catch (bad_alloc&) {
vb@41
   470
                    clear_opt_field(s);
vb@33
   471
                    throw bad_alloc();
vb@33
   472
                }
vb@33
   473
vb@41
   474
                clear_opt_field(s);
vb@33
   475
vb@33
   476
                _il = stringpair_list_add(_il, pair);
vb@33
   477
                if (_il == NULL) {
vb@33
   478
                    free_stringpair_list(il);
vb@33
   479
                    throw bad_alloc();
vb@33
   480
                }
vb@33
   481
            }
vb@33
   482
vb@33
   483
            return il;
vb@33
   484
        }
vb@33
   485
        
vb@33
   486
        ::message * text_message_to_C(text_message *msg)
vb@33
   487
        {
vb@33
   488
            assert(msg);
vb@33
   489
vb@39
   490
            ::message * msg2 = new_message((PEP_msg_direction) msg->dir);
vb@37
   491
            if (msg2 == NULL)
vb@37
   492
                throw bad_alloc();
vb@33
   493
vb@33
   494
            msg2->id = str(msg->id);
vb@33
   495
            msg2->shortmsg = str(msg->shortmsg);
vb@33
   496
            msg2->longmsg = str(msg->longmsg);
vb@33
   497
            msg2->longmsg_formatted = str(msg->longmsg_formatted);
vb@33
   498
            msg2->attachments = bloblist(msg->attachments);
vb@33
   499
            msg2->sent = new_timestamp(msg->sent);
vb@33
   500
            msg2->recv = new_timestamp(msg->recv);
vb@33
   501
            msg2->from = new_identity(&msg->from);
vb@33
   502
            msg2->to = identities(msg->to);
vb@33
   503
            msg2->recv_by = new_identity(&msg->recv_by);
vb@33
   504
            msg2->cc = identities(msg->cc);
vb@33
   505
            msg2->bcc = identities(msg->bcc);
vb@33
   506
            msg2->reply_to = identities(msg->reply_to);
vb@33
   507
            msg2->references = new_stringlist(msg->references);
vb@33
   508
            msg2->keywords = new_stringlist(msg->keywords);
vb@33
   509
            msg2->comments = str(msg->comments);
vb@33
   510
            msg2->opt_fields = stringpair_list(msg->opt_fields);
vb@33
   511
vb@33
   512
            return msg2;
vb@33
   513
        }
vb@10
   514
    }
vb@10
   515
}