merged in ENGINE-214 (message 2.0)
authorKrista Bennett <krista@pep-project.org>
Tue, 10 Oct 2017 02:58:25 +0200
changeset 214961bcd6a4a837
parent 2146 ece6509ca285
parent 2148 4c114255f86d
child 2150 cfbfa7df0b07
merged in ENGINE-214 (message 2.0)
     1.1 --- a/src/message.h	Mon Oct 09 10:50:25 2017 +0200
     1.2 +++ b/src/message.h	Tue Oct 10 02:58:25 2017 +0200
     1.3 @@ -163,4 +163,3 @@
     1.4  #ifdef __cplusplus
     1.5  }
     1.6  #endif
     1.7 -
     2.1 --- a/src/message_api.c	Mon Oct 09 10:50:25 2017 +0200
     2.2 +++ b/src/message_api.c	Tue Oct 10 02:58:25 2017 +0200
     2.3 @@ -100,6 +100,41 @@
     2.4      }
     2.5  }
     2.6  
     2.7 +static char * encapsulate_message_wrap_info(const char *msg_wrap_info, const char *longmsg)
     2.8 +{
     2.9 +    assert(msg_wrap_info);
    2.10 +    
    2.11 +    if (!msg_wrap_info) {
    2.12 +        if (!longmsg)
    2.13 +            return NULL;
    2.14 +        else {
    2.15 +            char *result = strdup(longmsg);
    2.16 +            assert(result);
    2.17 +            return result;            
    2.18 +        }    
    2.19 +    }
    2.20 +    
    2.21 +    if (longmsg == NULL)
    2.22 +        longmsg = "";
    2.23 +        
    2.24 +    const char * const newlines = "\n\n";
    2.25 +    const size_t NL_LEN = 2;
    2.26 +        
    2.27 +    const size_t bufsize = PEP_MSG_WRAP_KEY_LEN + strlen(msg_wrap_info) + NL_LEN + strlen(longmsg) + 1;
    2.28 +    char * ptext = calloc(1, bufsize);
    2.29 +    assert(ptext);
    2.30 +    if (ptext == NULL)
    2.31 +        return NULL;
    2.32 +
    2.33 +    strlcpy(ptext, PEP_MSG_WRAP_KEY, bufsize);
    2.34 +    strlcat(ptext, msg_wrap_info, bufsize);
    2.35 +    strlcat(ptext, newlines, bufsize);
    2.36 +    strlcat(ptext, longmsg, bufsize);
    2.37 +
    2.38 +    return ptext;
    2.39 +}
    2.40 +
    2.41 +
    2.42  static char * combine_short_and_long(const char *shortmsg, const char *longmsg)
    2.43  {
    2.44      assert(shortmsg);
    2.45 @@ -122,18 +157,16 @@
    2.46      if (longmsg == NULL)
    2.47          longmsg = "";
    2.48  
    2.49 -    const char * const subject = "Subject: ";
    2.50 -    const size_t SUBJ_LEN = 9;
    2.51      const char * const newlines = "\n\n";
    2.52      const size_t NL_LEN = 2;
    2.53  
    2.54 -    const size_t bufsize = SUBJ_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
    2.55 +    const size_t bufsize = PEP_SUBJ_KEY_LEN + strlen(shortmsg) + NL_LEN + strlen(longmsg) + 1;
    2.56      char * ptext = calloc(1, bufsize);
    2.57      assert(ptext);
    2.58      if (ptext == NULL)
    2.59          return NULL;
    2.60  
    2.61 -    strlcpy(ptext, subject, bufsize);
    2.62 +    strlcpy(ptext, PEP_SUBJ_KEY, bufsize);
    2.63      strlcat(ptext, shortmsg, bufsize);
    2.64      strlcat(ptext, newlines, bufsize);
    2.65      strlcat(ptext, longmsg, bufsize);
    2.66 @@ -141,62 +174,106 @@
    2.67      return ptext;
    2.68  }
    2.69  
    2.70 -static int separate_short_and_long(const char *src, char **shortmsg, char **longmsg)
    2.71 +/* 
    2.72 +   WARNING: For the moment, this only works for the first line of decrypted
    2.73 +   plaintext because we don't need more. IF WE DO, THIS MUST BE EXPANDED, or
    2.74 +   we need a delineated section to parse separately
    2.75 +   
    2.76 +   Does case-insensitive compare of keys, so sending in a lower-cased
    2.77 +   string constant saves a bit of computation
    2.78 + */
    2.79 +static PEP_STATUS get_data_from_encapsulated_line(const char* plaintext, const char* key, 
    2.80 +                                                  const size_t keylen, char** data, 
    2.81 +                                                  char** modified_msg) {
    2.82 +    char* _data = NULL;
    2.83 +    char* _modified = NULL;
    2.84 +    
    2.85 +    if (strncasecmp(plaintext, key, keylen) == 0) {
    2.86 +        const char *line_end = strchr(plaintext, '\n');
    2.87 +
    2.88 +        if (line_end == NULL) {
    2.89 +            _data = strdup(plaintext + keylen);
    2.90 +            assert(_data);
    2.91 +            if (_data == NULL)
    2.92 +                return PEP_OUT_OF_MEMORY;
    2.93 +        }
    2.94 +        else {
    2.95 +            size_t n = line_end - plaintext;
    2.96 +
    2.97 +            if (*(line_end - 1) == '\r')
    2.98 +                _data = strndup(plaintext + keylen, n - (keylen + 1));
    2.99 +            else
   2.100 +                _data = strndup(plaintext + keylen, n - keylen);
   2.101 +            assert(_data);
   2.102 +            if (_data == NULL)
   2.103 +                return PEP_OUT_OF_MEMORY;
   2.104 +
   2.105 +            while (*(plaintext + n) && (*(plaintext + n) == '\n' || *(plaintext + n) == '\r'))
   2.106 +                ++n;
   2.107 +
   2.108 +            if (*(plaintext + n)) {
   2.109 +                _modified = strdup(plaintext + n);
   2.110 +                assert(_modified);
   2.111 +                if (_modified == NULL)
   2.112 +                    return PEP_OUT_OF_MEMORY;
   2.113 +            }
   2.114 +        }
   2.115 +    }
   2.116 +    *data = _data;
   2.117 +    *modified_msg = _modified;
   2.118 +    return PEP_STATUS_OK;
   2.119 +}
   2.120 +
   2.121 +
   2.122 +static int separate_short_and_long(const char *src, char **shortmsg, char** msg_wrap_info, char **longmsg)
   2.123  {
   2.124      char *_shortmsg = NULL;
   2.125 +    char *_msg_wrap_info = NULL;
   2.126      char *_longmsg = NULL;
   2.127  
   2.128      assert(src);
   2.129      assert(shortmsg);
   2.130 +    assert(msg_wrap_info);
   2.131      assert(longmsg);
   2.132  
   2.133 -    if (src == NULL || shortmsg == NULL || longmsg == NULL)
   2.134 +    if (src == NULL || shortmsg == NULL || msg_wrap_info == NULL || longmsg == NULL)
   2.135          return -1;
   2.136  
   2.137      *shortmsg = NULL;
   2.138      *longmsg = NULL;
   2.139 -
   2.140 -    if (strncasecmp(src, "subject: ", 9) == 0) {
   2.141 -        char *line_end = strchr(src, '\n');
   2.142 -
   2.143 -        if (line_end == NULL) {
   2.144 -            _shortmsg = strdup(src + 9);
   2.145 -            assert(_shortmsg);
   2.146 -            if (_shortmsg == NULL)
   2.147 -                goto enomem;
   2.148 -            // _longmsg = NULL;
   2.149 -        }
   2.150 -        else {
   2.151 -            size_t n = line_end - src;
   2.152 -
   2.153 -            if (*(line_end - 1) == '\r')
   2.154 -                _shortmsg = strndup(src + 9, n - 10);
   2.155 -            else
   2.156 -                _shortmsg = strndup(src + 9, n - 9);
   2.157 -            assert(_shortmsg);
   2.158 -            if (_shortmsg == NULL)
   2.159 -                goto enomem;
   2.160 -
   2.161 -            while (*(src + n) && (*(src + n) == '\n' || *(src + n) == '\r'))
   2.162 -                ++n;
   2.163 -
   2.164 -            if (*(src + n)) {
   2.165 -                _longmsg = strdup(src + n);
   2.166 -                assert(_longmsg);
   2.167 -                if (_longmsg == NULL)
   2.168 -                    goto enomem;
   2.169 -            }
   2.170 -        }
   2.171 -        *shortmsg = _shortmsg;
   2.172 +    *msg_wrap_info = NULL;
   2.173 +
   2.174 +    // We generated the input here. If we ever need more than one header value to be
   2.175 +    // encapsulated and hidden in the encrypted text, we will have to modify this.
   2.176 +    // As is, we're either doing this with a version 1.0 client, in which case
   2.177 +    // the only encapsulated header value is subject, or 2.0+, in which the
   2.178 +    // message wrap info is the only encapsulated header value. If we need this
   2.179 +    // to be more complex, we're going to have to do something more elegant
   2.180 +    // and efficient.    
   2.181 +    PEP_STATUS status = get_data_from_encapsulated_line(src, PEP_SUBJ_KEY_LC, 
   2.182 +                                                        PEP_SUBJ_KEY_LEN, 
   2.183 +                                                        &_shortmsg, &_longmsg);
   2.184 +                                                        
   2.185 +    if (_shortmsg) {
   2.186 +        if (status == PEP_STATUS_OK)
   2.187 +            *shortmsg = _shortmsg;
   2.188 +        else
   2.189 +            goto enomem;
   2.190      }
   2.191      else {
   2.192 -        // If there's no "Subject: " and the shortmsg is
   2.193 -        // pEp (or anything else), then we shouldn't be replacing it.
   2.194 -        // Chances are that the message wasn't encrypted
   2.195 -        // using pEp and that the actually subject IS pEp. In any event,
   2.196 -        // erasing the subject line when we don't have one in the plaintext
   2.197 -        // isn't the right behaviour.
   2.198 -        // _shortmsg = strdup("");
   2.199 +        status = get_data_from_encapsulated_line(src, PEP_MSG_WRAP_KEY_LC, 
   2.200 +                                                 PEP_MSG_WRAP_KEY_LEN, 
   2.201 +                                                 &_msg_wrap_info, &_longmsg);
   2.202 +        if (_msg_wrap_info) {
   2.203 +            if (status == PEP_STATUS_OK)
   2.204 +                *msg_wrap_info = _msg_wrap_info;
   2.205 +            else
   2.206 +                goto enomem;
   2.207 +        }
   2.208 +    }
   2.209 +    
   2.210 +    // If there was no secret data hiding in the first line...
   2.211 +    if (!_shortmsg && !_msg_wrap_info) {
   2.212          _longmsg = strdup(src);
   2.213          assert(_longmsg);
   2.214          if (_longmsg == NULL)
   2.215 @@ -209,6 +286,7 @@
   2.216  
   2.217  enomem:
   2.218      free(_shortmsg);
   2.219 +    free(_msg_wrap_info);
   2.220      free(_longmsg);
   2.221  
   2.222      return -1;
   2.223 @@ -330,6 +408,49 @@
   2.224      return PEP_STATUS_OK;
   2.225  }
   2.226  
   2.227 +
   2.228 +static message* extract_minimal_envelope(const message* src, 
   2.229 +                                         PEP_msg_direction direct) {
   2.230 +                                             
   2.231 +    unsigned char pepstr[] = PEP_SUBJ_STRING;
   2.232 +    
   2.233 +    message* envelope = new_message(direct);
   2.234 +    if (!envelope)
   2.235 +        return NULL;
   2.236 +        
   2.237 +    envelope->shortmsg = _pep_subj_copy();
   2.238 +    if (!envelope->shortmsg)
   2.239 +        return NULL;
   2.240 +
   2.241 +    if (src->from) {
   2.242 +        envelope->from = identity_dup(src->from);
   2.243 +        if (!envelope->from)
   2.244 +            return NULL;
   2.245 +    }
   2.246 +
   2.247 +    if (src->to) {
   2.248 +        envelope->to = identity_list_dup(src->to);
   2.249 +        if (!envelope->to)
   2.250 +            return NULL;
   2.251 +    }
   2.252 +
   2.253 +    if (src->cc) {
   2.254 +        envelope->cc = identity_list_dup(src->cc);
   2.255 +        if (!envelope->cc)
   2.256 +            return NULL;
   2.257 +    }
   2.258 +
   2.259 +    if (src->bcc) {
   2.260 +        envelope->bcc = identity_list_dup(src->bcc);
   2.261 +        if (!envelope->bcc)
   2.262 +            return NULL;
   2.263 +    }
   2.264 +
   2.265 +    envelope->enc_format = src->enc_format;        
   2.266 +    
   2.267 +    return envelope;
   2.268 +}
   2.269 +
   2.270  static message * clone_to_empty_message(const message * src)
   2.271  {
   2.272      PEP_STATUS status;
   2.273 @@ -357,6 +478,35 @@
   2.274      return NULL;
   2.275  }
   2.276  
   2.277 +static message* wrap_message_as_attachment(message* envelope, 
   2.278 +    const message* attachment) {
   2.279 +    
   2.280 +    message* _envelope = NULL;
   2.281 +    
   2.282 +    if (!envelope) {
   2.283 +        _envelope = extract_minimal_envelope(attachment, PEP_dir_outgoing);
   2.284 +        envelope = _envelope;
   2.285 +    }
   2.286 +    
   2.287 +    char* message_text = NULL;
   2.288 +    /* Turn message into a MIME-blob */
   2.289 +    PEP_STATUS status = mime_encode_message(attachment, false, &message_text);
   2.290 +    
   2.291 +    if (status != PEP_STATUS_OK) {
   2.292 +        free(_envelope);
   2.293 +        return NULL;
   2.294 +    }
   2.295 +    
   2.296 +    size_t message_len = strlen(message_text);
   2.297 +    
   2.298 +    bloblist_t* message_blob = new_bloblist(message_text, message_len,
   2.299 +                                            "message/rfc822", NULL);
   2.300 +    
   2.301 +    envelope->attachments = message_blob;
   2.302 +    
   2.303 +    return envelope;
   2.304 +}
   2.305 +
   2.306  static PEP_STATUS encrypt_PGP_MIME(
   2.307      PEP_SESSION session,
   2.308      const message *src,
   2.309 @@ -373,31 +523,18 @@
   2.310      size_t csize;
   2.311      assert(dst->longmsg == NULL);
   2.312      dst->enc_format = PEP_enc_PGP_MIME;
   2.313 -    unsigned char pepstr[] = PEP_SUBJ_STRING;
   2.314 -
   2.315 -    if (src->shortmsg && strcmp(src->shortmsg, "pEp") != 0 
   2.316 -                      && _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0) {
   2.317 -        if (session->unencrypted_subject) {
   2.318 -            dst->shortmsg = strdup(src->shortmsg);
   2.319 -            assert(dst->shortmsg);
   2.320 -            if (dst->shortmsg == NULL)
   2.321 -                goto enomem;
   2.322 -            ptext = src->longmsg;
   2.323 -        }
   2.324 -        else {
   2.325 -            ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   2.326 -            if (ptext == NULL)
   2.327 -                goto enomem;
   2.328 -            free_ptext = true;
   2.329 -        }
   2.330 -    }
   2.331 -    else if (src->longmsg) {
   2.332 -        ptext = src->longmsg;
   2.333 -    }
   2.334 -    else {
   2.335 -        ptext = (char*)pepstr;
   2.336 -    }
   2.337 -
   2.338 +
   2.339 +    if (src->shortmsg)
   2.340 +        dst->shortmsg = strdup(src->shortmsg);
   2.341 +
   2.342 +    // Right now, we only encrypt inner messages or outer messages. There
   2.343 +    // is no in-between. All messages are to be wrapped or are a wrapper.
   2.344 +    // FIXME: rename this flag!!!
   2.345 +    const char* msg_wrap_info = (flags & PEP_encrypt_flag_inner_message ? 
   2.346 +                                 "INNER" : "OUTER");
   2.347 +    
   2.348 +    ptext = encapsulate_message_wrap_info(msg_wrap_info, src->longmsg);
   2.349 +        
   2.350      message *_src = calloc(1, sizeof(message));
   2.351      assert(_src);
   2.352      if (_src == NULL)
   2.353 @@ -463,185 +600,185 @@
   2.354      return status;
   2.355  }
   2.356  
   2.357 -static PEP_STATUS encrypt_PGP_in_pieces(
   2.358 -    PEP_SESSION session,
   2.359 -    const message *src,
   2.360 -    stringlist_t *keys,
   2.361 -    message *dst,
   2.362 -    PEP_encrypt_flags_t flags
   2.363 -    )
   2.364 -{
   2.365 -    PEP_STATUS status = PEP_STATUS_OK;
   2.366 -    char *ctext = NULL;
   2.367 -    size_t csize;
   2.368 -    char *ptext = NULL;
   2.369 -    bool free_ptext = false;
   2.370 -    unsigned char pepstr[] = PEP_SUBJ_STRING;
   2.371 -    
   2.372 -    assert(dst->longmsg == NULL);
   2.373 -    assert(dst->attachments == NULL);
   2.374 -
   2.375 -    dst->enc_format = PEP_enc_pieces;
   2.376 -
   2.377 -    bool nosign = (flags & PEP_encrypt_flag_force_unsigned);
   2.378 -
   2.379 -    if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0 && 
   2.380 -        _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0) {
   2.381 -        if (session->unencrypted_subject) {
   2.382 -            dst->shortmsg = strdup(src->shortmsg);
   2.383 -            assert(dst->shortmsg);
   2.384 -            if (dst->shortmsg == NULL)
   2.385 -                goto enomem;
   2.386 -            ptext = src->longmsg;
   2.387 -        }
   2.388 -        else {
   2.389 -            ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   2.390 -            if (ptext == NULL)
   2.391 -                goto enomem;
   2.392 -            free_ptext = true;
   2.393 -        }
   2.394 -
   2.395 -        if (nosign)
   2.396 -            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   2.397 -                &csize);
   2.398 -        else 
   2.399 -            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   2.400 -                &csize);
   2.401 -        if (free_ptext)
   2.402 -            free(ptext);
   2.403 -        free_ptext = false;
   2.404 -        if (ctext) {
   2.405 -            dst->longmsg = ctext;
   2.406 -        }
   2.407 -        else {
   2.408 -            goto pep_error;
   2.409 -        }
   2.410 -    }
   2.411 -    else if (src->longmsg && src->longmsg[0]) {
   2.412 -        ptext = src->longmsg;
   2.413 -        if (nosign)
   2.414 -            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   2.415 -                &csize);
   2.416 -        else 
   2.417 -            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   2.418 -                &csize);
   2.419 -        if (ctext) {
   2.420 -            dst->longmsg = ctext;
   2.421 -        }
   2.422 -        else {
   2.423 -            goto pep_error;
   2.424 -        }
   2.425 -    }
   2.426 -    else {
   2.427 -        dst->longmsg = strdup("");
   2.428 -        assert(dst->longmsg);
   2.429 -        if (dst->longmsg == NULL)
   2.430 -            goto enomem;
   2.431 -    }
   2.432 -
   2.433 -    if (src->longmsg_formatted && src->longmsg_formatted[0]) {
   2.434 -        ptext = src->longmsg_formatted;
   2.435 -        if (nosign)
   2.436 -            status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   2.437 -                &csize);
   2.438 -        else 
   2.439 -            status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   2.440 -                &csize);
   2.441 -        if (ctext) {
   2.442 -
   2.443 -            bloblist_t *_a = bloblist_add(dst->attachments, ctext, csize,
   2.444 -                "application/octet-stream", "file://PGPexch.htm.pgp");
   2.445 -            if (_a == NULL)
   2.446 -                goto enomem;
   2.447 -            if (dst->attachments == NULL)
   2.448 -                dst->attachments = _a;
   2.449 -        }
   2.450 -        else {
   2.451 -            goto pep_error;
   2.452 -        }
   2.453 -    }
   2.454 -
   2.455 -    if (src->attachments) {
   2.456 -        if (dst->attachments == NULL) {
   2.457 -            dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
   2.458 -            if (dst->attachments == NULL)
   2.459 -                goto enomem;
   2.460 -        }
   2.461 -
   2.462 -        bloblist_t *_s = src->attachments;
   2.463 -        bloblist_t *_d = dst->attachments;
   2.464 -
   2.465 -        for (int n = 0; _s; _s = _s->next) {
   2.466 -            if (_s->value == NULL && _s->size == 0) {
   2.467 -                _d = bloblist_add(_d, NULL, 0, _s->mime_type, _s->filename);
   2.468 -                if (_d == NULL)
   2.469 -                    goto enomem;
   2.470 -            }
   2.471 -            else {
   2.472 -                size_t psize = _s->size;
   2.473 -                ptext = _s->value;
   2.474 -                if (nosign)
   2.475 -                    status = encrypt_only(session, keys, ptext, psize, &ctext,
   2.476 -                        &csize);
   2.477 -                else 
   2.478 -                    status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
   2.479 -                        &csize);
   2.480 -                if (ctext) {
   2.481 -                    char *filename = NULL;
   2.482 -
   2.483 -                    char *attach_fn = _s->filename;
   2.484 -                    if (attach_fn && !is_cid_uri(attach_fn)) {
   2.485 -                        size_t len = strlen(_s->filename);
   2.486 -                        size_t bufsize = len + 5; // length of .pgp extension + NUL
   2.487 -                        bool already_uri = false;
   2.488 -                        if (is_file_uri(attach_fn))
   2.489 -                            already_uri = true;
   2.490 -                        else
   2.491 -                            bufsize += 7; // length of file://
   2.492 -                            
   2.493 -                        filename = calloc(1, bufsize);
   2.494 -                        if (filename == NULL)
   2.495 -                            goto enomem;
   2.496 -
   2.497 -                        if (!already_uri)
   2.498 -                            strlcpy(filename, "file://", bufsize);
   2.499 -                        // First char is NUL, so we're ok, even if not copying above. (calloc)
   2.500 -                        strlcat(filename, _s->filename, bufsize);
   2.501 -                        strlcat(filename, ".pgp", bufsize);
   2.502 -                    }
   2.503 -                    else {
   2.504 -                        filename = calloc(1, 27);
   2.505 -                        if (filename == NULL)
   2.506 -                            goto enomem;
   2.507 -
   2.508 -                        ++n;
   2.509 -                        n &= 0xffff;
   2.510 -                        snprintf(filename, 20, "file://Attachment%d.pgp", n);
   2.511 -                    }
   2.512 -
   2.513 -                    _d = bloblist_add(_d, ctext, csize, "application/octet-stream",
   2.514 -                        filename);
   2.515 -                    free(filename);
   2.516 -                    if (_d == NULL)
   2.517 -                        goto enomem;
   2.518 -                }
   2.519 -                else {
   2.520 -                    goto pep_error;
   2.521 -                }
   2.522 -            }
   2.523 -        }
   2.524 -    }
   2.525 -
   2.526 -    return PEP_STATUS_OK;
   2.527 -
   2.528 -enomem:
   2.529 -    status = PEP_OUT_OF_MEMORY;
   2.530 -
   2.531 -pep_error:
   2.532 -    if (free_ptext)
   2.533 -        free(ptext);
   2.534 -    return status;
   2.535 -}
   2.536 +// static PEP_STATUS encrypt_PGP_in_pieces(
   2.537 +//     PEP_SESSION session,
   2.538 +//     const message *src,
   2.539 +//     stringlist_t *keys,
   2.540 +//     message *dst,
   2.541 +//     PEP_encrypt_flags_t flags
   2.542 +//     )
   2.543 +// {
   2.544 +//     PEP_STATUS status = PEP_STATUS_OK;
   2.545 +//     char *ctext = NULL;
   2.546 +//     size_t csize;
   2.547 +//     char *ptext = NULL;
   2.548 +//     bool free_ptext = false;
   2.549 +//     unsigned char pepstr[] = PEP_SUBJ_STRING;
   2.550 +//     
   2.551 +//     assert(dst->longmsg == NULL);
   2.552 +//     assert(dst->attachments == NULL);
   2.553 +// 
   2.554 +//     dst->enc_format = PEP_enc_pieces;
   2.555 +// 
   2.556 +//     bool nosign = (flags & PEP_encrypt_flag_force_unsigned);
   2.557 +// 
   2.558 +//     if (src->shortmsg && src->shortmsg[0] && strcmp(src->shortmsg, "pEp") != 0 && 
   2.559 +//         _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0) {
   2.560 +//         if (session->unencrypted_subject) {
   2.561 +//             dst->shortmsg = strdup(src->shortmsg);
   2.562 +//             assert(dst->shortmsg);
   2.563 +//             if (dst->shortmsg == NULL)
   2.564 +//                 goto enomem;
   2.565 +//             ptext = src->longmsg;
   2.566 +//         }
   2.567 +//         else {
   2.568 +//             ptext = combine_short_and_long(src->shortmsg, src->longmsg);
   2.569 +//             if (ptext == NULL)
   2.570 +//                 goto enomem;
   2.571 +//             free_ptext = true;
   2.572 +//         }
   2.573 +// 
   2.574 +//         if (nosign)
   2.575 +//             status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   2.576 +//                 &csize);
   2.577 +//         else 
   2.578 +//             status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   2.579 +//                 &csize);
   2.580 +//         if (free_ptext)
   2.581 +//             free(ptext);
   2.582 +//         free_ptext = false;
   2.583 +//         if (ctext) {
   2.584 +//             dst->longmsg = ctext;
   2.585 +//         }
   2.586 +//         else {
   2.587 +//             goto pep_error;
   2.588 +//         }
   2.589 +//     }
   2.590 +//     else if (src->longmsg && src->longmsg[0]) {
   2.591 +//         ptext = src->longmsg;
   2.592 +//         if (nosign)
   2.593 +//             status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   2.594 +//                 &csize);
   2.595 +//         else 
   2.596 +//             status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   2.597 +//                 &csize);
   2.598 +//         if (ctext) {
   2.599 +//             dst->longmsg = ctext;
   2.600 +//         }
   2.601 +//         else {
   2.602 +//             goto pep_error;
   2.603 +//         }
   2.604 +//     }
   2.605 +//     else {
   2.606 +//         dst->longmsg = strdup("");
   2.607 +//         assert(dst->longmsg);
   2.608 +//         if (dst->longmsg == NULL)
   2.609 +//             goto enomem;
   2.610 +//     }
   2.611 +// 
   2.612 +//     if (src->longmsg_formatted && src->longmsg_formatted[0]) {
   2.613 +//         ptext = src->longmsg_formatted;
   2.614 +//         if (nosign)
   2.615 +//             status = encrypt_only(session, keys, ptext, strlen(ptext), &ctext,
   2.616 +//                 &csize);
   2.617 +//         else 
   2.618 +//             status = encrypt_and_sign(session, keys, ptext, strlen(ptext), &ctext,
   2.619 +//                 &csize);
   2.620 +//         if (ctext) {
   2.621 +// 
   2.622 +//             bloblist_t *_a = bloblist_add(dst->attachments, ctext, csize,
   2.623 +//                 "application/octet-stream", "file://PGPexch.htm.pgp");
   2.624 +//             if (_a == NULL)
   2.625 +//                 goto enomem;
   2.626 +//             if (dst->attachments == NULL)
   2.627 +//                 dst->attachments = _a;
   2.628 +//         }
   2.629 +//         else {
   2.630 +//             goto pep_error;
   2.631 +//         }
   2.632 +//     }
   2.633 +// 
   2.634 +//     if (src->attachments) {
   2.635 +//         if (dst->attachments == NULL) {
   2.636 +//             dst->attachments = new_bloblist(NULL, 0, NULL, NULL);
   2.637 +//             if (dst->attachments == NULL)
   2.638 +//                 goto enomem;
   2.639 +//         }
   2.640 +// 
   2.641 +//         bloblist_t *_s = src->attachments;
   2.642 +//         bloblist_t *_d = dst->attachments;
   2.643 +// 
   2.644 +//         for (int n = 0; _s; _s = _s->next) {
   2.645 +//             if (_s->value == NULL && _s->size == 0) {
   2.646 +//                 _d = bloblist_add(_d, NULL, 0, _s->mime_type, _s->filename);
   2.647 +//                 if (_d == NULL)
   2.648 +//                     goto enomem;
   2.649 +//             }
   2.650 +//             else {
   2.651 +//                 size_t psize = _s->size;
   2.652 +//                 ptext = _s->value;
   2.653 +//                 if (nosign)
   2.654 +//                     status = encrypt_only(session, keys, ptext, psize, &ctext,
   2.655 +//                         &csize);
   2.656 +//                 else 
   2.657 +//                     status = encrypt_and_sign(session, keys, ptext, psize, &ctext,
   2.658 +//                         &csize);
   2.659 +//                 if (ctext) {
   2.660 +//                     char *filename = NULL;
   2.661 +// 
   2.662 +//                     char *attach_fn = _s->filename;
   2.663 +//                     if (attach_fn && !is_cid_uri(attach_fn)) {
   2.664 +//                         size_t len = strlen(_s->filename);
   2.665 +//                         size_t bufsize = len + 5; // length of .pgp extension + NUL
   2.666 +//                         bool already_uri = false;
   2.667 +//                         if (is_file_uri(attach_fn))
   2.668 +//                             already_uri = true;
   2.669 +//                         else
   2.670 +//                             bufsize += 7; // length of file://
   2.671 +//                             
   2.672 +//                         filename = calloc(1, bufsize);
   2.673 +//                         if (filename == NULL)
   2.674 +//                             goto enomem;
   2.675 +// 
   2.676 +//                         if (!already_uri)
   2.677 +//                             strlcpy(filename, "file://", bufsize);
   2.678 +//                         // First char is NUL, so we're ok, even if not copying above. (calloc)
   2.679 +//                         strlcat(filename, _s->filename, bufsize);
   2.680 +//                         strlcat(filename, ".pgp", bufsize);
   2.681 +//                     }
   2.682 +//                     else {
   2.683 +//                         filename = calloc(1, 27);
   2.684 +//                         if (filename == NULL)
   2.685 +//                             goto enomem;
   2.686 +// 
   2.687 +//                         ++n;
   2.688 +//                         n &= 0xffff;
   2.689 +//                         snprintf(filename, 20, "file://Attachment%d.pgp", n);
   2.690 +//                     }
   2.691 +// 
   2.692 +//                     _d = bloblist_add(_d, ctext, csize, "application/octet-stream",
   2.693 +//                         filename);
   2.694 +//                     free(filename);
   2.695 +//                     if (_d == NULL)
   2.696 +//                         goto enomem;
   2.697 +//                 }
   2.698 +//                 else {
   2.699 +//                     goto pep_error;
   2.700 +//                 }
   2.701 +//             }
   2.702 +//         }
   2.703 +//     }
   2.704 +// 
   2.705 +//     return PEP_STATUS_OK;
   2.706 +// 
   2.707 +// enomem:
   2.708 +//     status = PEP_OUT_OF_MEMORY;
   2.709 +// 
   2.710 +// pep_error:
   2.711 +//     if (free_ptext)
   2.712 +//         free(ptext);
   2.713 +//     return status;
   2.714 +// }
   2.715  
   2.716  static char * keylist_to_string(const stringlist_t *keylist)
   2.717  {
   2.718 @@ -1127,7 +1264,9 @@
   2.719      PEP_STATUS status = PEP_STATUS_OK;
   2.720      message * msg = NULL;
   2.721      stringlist_t * keys = NULL;
   2.722 -
   2.723 +    message* inner_message = NULL;
   2.724 +    message* _src = src;
   2.725 +    
   2.726      assert(session);
   2.727      assert(src);
   2.728      assert(dst);
   2.729 @@ -1254,31 +1393,40 @@
   2.730          return ADD_TO_LOG(PEP_UNENCRYPTED);
   2.731      }
   2.732      else {
   2.733 -        msg = clone_to_empty_message(src);
   2.734 +        
   2.735 +        // FIXME - this logic may need to change if we allow
   2.736 +        // wrappers to attach keys (e.g w/ transport)        
   2.737 +        if (!(flags & PEP_encrypt_flag_inner_message)) {
   2.738 +            PEP_STATUS status = encrypt_message(session, src, extra, &inner_message,
   2.739 +                                                enc_format,
   2.740 +                                                flags | PEP_encrypt_flag_inner_message);
   2.741 +            _src = wrap_message_as_attachment(NULL, inner_message);
   2.742 +        } else {
   2.743 +            if (!(flags & PEP_encrypt_flag_force_no_attached_key))
   2.744 +                attach_own_key(session, _src);
   2.745 +        }
   2.746 +        msg = clone_to_empty_message(_src);
   2.747          if (msg == NULL)
   2.748              goto enomem;
   2.749  
   2.750 -        if (!(flags & PEP_encrypt_flag_force_no_attached_key))
   2.751 -            attach_own_key(session, src);
   2.752 -
   2.753          switch (enc_format) {
   2.754 -        case PEP_enc_PGP_MIME:
   2.755 -        case PEP_enc_PEP: // BUG: should be implemented extra
   2.756 -            status = encrypt_PGP_MIME(session, src, keys, msg, flags);
   2.757 -            break;
   2.758 -
   2.759 -        case PEP_enc_pieces:
   2.760 -            status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
   2.761 -            break;
   2.762 -
   2.763 -        /* case PEP_enc_PEP:
   2.764 -            // TODO: implement
   2.765 -            NOT_IMPLEMENTED */
   2.766 -
   2.767 -        default:
   2.768 -            assert(0);
   2.769 -            status = PEP_ILLEGAL_VALUE;
   2.770 -            GOTO(pep_error);
   2.771 +            case PEP_enc_PGP_MIME:
   2.772 +            case PEP_enc_PEP: // BUG: should be implemented extra
   2.773 +                status = encrypt_PGP_MIME(session, _src, keys, msg, flags);
   2.774 +                break;
   2.775 +
   2.776 +            // case PEP_enc_pieces:
   2.777 +            //     status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
   2.778 +            //     break;
   2.779 +
   2.780 +            /* case PEP_enc_PEP:
   2.781 +                // TODO: implement
   2.782 +                NOT_IMPLEMENTED */
   2.783 +
   2.784 +            default:
   2.785 +                assert(0);
   2.786 +                status = PEP_ILLEGAL_VALUE;
   2.787 +                GOTO(pep_error);
   2.788          }
   2.789  
   2.790          if (status == PEP_OUT_OF_MEMORY)
   2.791 @@ -1291,7 +1439,7 @@
   2.792      free_stringlist(keys);
   2.793  
   2.794      if (msg && msg->shortmsg == NULL) {
   2.795 -        msg->shortmsg = _pep_subj_copy();
   2.796 +        msg->shortmsg = strdup("");
   2.797          assert(msg->shortmsg);
   2.798          if (msg->shortmsg == NULL)
   2.799              goto enomem;
   2.800 @@ -1308,6 +1456,12 @@
   2.801      }
   2.802  
   2.803      *dst = msg;
   2.804 +    
   2.805 +    // ??? FIXME: Check to be sure we don't have references btw _src and msg. 
   2.806 +    // I don't think we do.
   2.807 +    if (_src && _src != src)
   2.808 +        free_message(_src);
   2.809 +        
   2.810      return ADD_TO_LOG(status);
   2.811  
   2.812  enomem:
   2.813 @@ -1316,10 +1470,14 @@
   2.814  pep_error:
   2.815      free_stringlist(keys);
   2.816      free_message(msg);
   2.817 +    if (_src && _src != src)
   2.818 +        free_message(_src);
   2.819  
   2.820      return ADD_TO_LOG(status);
   2.821  }
   2.822  
   2.823 +
   2.824 +// FIXME: Update if needed for the wrapped fun bits
   2.825  DYNAMIC_API PEP_STATUS encrypt_message_for_self(
   2.826          PEP_SESSION session,
   2.827          pEp_identity* target_id,
   2.828 @@ -1381,9 +1539,9 @@
   2.829              status = encrypt_PGP_MIME(session, src, keys, msg, flags);
   2.830              break;
   2.831  
   2.832 -        case PEP_enc_pieces:
   2.833 -            status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
   2.834 -            break;
   2.835 +        // case PEP_enc_pieces:
   2.836 +        //     status = encrypt_PGP_in_pieces(session, src, keys, msg, flags);
   2.837 +        //     break;
   2.838  
   2.839          /* case PEP_enc_PEP:
   2.840              NOT_IMPLEMENTED */
   2.841 @@ -1464,7 +1622,8 @@
   2.842  }
   2.843  
   2.844  
   2.845 -PEP_STATUS _get_detached_signature(message* msg, bloblist_t** signature_blob) {
   2.846 +static PEP_STATUS _get_detached_signature(message* msg, 
   2.847 +                                          bloblist_t** signature_blob) {
   2.848      bloblist_t* attach_curr = msg->attachments;
   2.849  
   2.850      *signature_blob = NULL;
   2.851 @@ -1480,8 +1639,8 @@
   2.852      return PEP_STATUS_OK;
   2.853  }
   2.854  
   2.855 -PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
   2.856 -                            char** stext, size_t* ssize) {
   2.857 +static PEP_STATUS _get_signed_text(const char* ptext, const size_t psize,
   2.858 +                                   char** stext, size_t* ssize) {
   2.859  
   2.860      char* signed_boundary = NULL;
   2.861      char* signpost = strstr(ptext, "Content-Type: multipart/signed");
   2.862 @@ -1551,9 +1710,9 @@
   2.863      return PEP_STATUS_OK;
   2.864  }
   2.865  
   2.866 -PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
   2.867 -                            stringlist_t** keylist_in_out, 
   2.868 -                            pEp_identity* from) {
   2.869 +static PEP_STATUS combine_keylists(PEP_SESSION session, stringlist_t** verify_in, 
   2.870 +                                   stringlist_t** keylist_in_out, 
   2.871 +                                   pEp_identity* from) {
   2.872      
   2.873      if (!verify_in || !(*verify_in)) // this isn't really a problem.
   2.874          return PEP_STATUS_OK;
   2.875 @@ -1628,11 +1787,11 @@
   2.876      return status;
   2.877  }
   2.878  
   2.879 -PEP_STATUS amend_rating_according_to_sender_and_recipients(
   2.880 -    PEP_SESSION session,
   2.881 -    PEP_rating *rating,
   2.882 -    pEp_identity *sender,
   2.883 -    stringlist_t *recipients) {
   2.884 +static PEP_STATUS amend_rating_according_to_sender_and_recipients(
   2.885 +       PEP_SESSION session,
   2.886 +       PEP_rating *rating,
   2.887 +       pEp_identity *sender,
   2.888 +       stringlist_t *recipients) {
   2.889      
   2.890      PEP_STATUS status = PEP_STATUS_OK;
   2.891  
   2.892 @@ -1668,6 +1827,335 @@
   2.893      return status;
   2.894  }
   2.895  
   2.896 +static PEP_STATUS check_for_sync_msg(PEP_SESSION session, 
   2.897 +                                     message* src,
   2.898 +                                     PEP_rating* rating, 
   2.899 +                                     PEP_decrypt_flags_t* flags,
   2.900 +                                     stringlist_t** keylist) {
   2.901 +    assert(session);
   2.902 +    assert(src);
   2.903 +    assert(rating);
   2.904 +    assert(keylist);
   2.905 +    
   2.906 +    if (session->sync_session->inject_sync_msg){
   2.907 +        PEP_STATUS status = receive_DeviceState_msg(session, src, *rating, *keylist);
   2.908 +        if (status == PEP_MESSAGE_CONSUME ||
   2.909 +            status == PEP_MESSAGE_IGNORE) {
   2.910 +            *flags |= (status == PEP_MESSAGE_IGNORE) ?
   2.911 +                        PEP_decrypt_flag_ignore :
   2.912 +                        PEP_decrypt_flag_consume;
   2.913 +        }
   2.914 +        else if (status != PEP_STATUS_OK) {
   2.915 +            return ADD_TO_LOG(status);
   2.916 +        }
   2.917 +    }
   2.918 +    return PEP_STATUS_OK;
   2.919 +}
   2.920 +
   2.921 +static PEP_STATUS sync_if_no_key(PEP_STATUS decrypt_status, PEP_SESSION session) {
   2.922 +    if (decrypt_status == PEP_DECRYPT_NO_KEY) {
   2.923 +        PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
   2.924 +        if (sync_status == PEP_OUT_OF_MEMORY){
   2.925 +            return PEP_OUT_OF_MEMORY;
   2.926 +        }
   2.927 +    }
   2.928 +    return PEP_STATUS_OK;
   2.929 +}
   2.930 +
   2.931 +// FIXME: Do we need to remove the attachment? I think we do...
   2.932 +static bool pull_up_attached_main_msg(message* src) {
   2.933 +    char* slong = src->longmsg;
   2.934 +    char* sform = src->longmsg_formatted;
   2.935 +    bloblist_t* satt = src->attachments;
   2.936 +    
   2.937 +    if ((!slong || slong[0] == '\0')
   2.938 +         && (!sform || sform[0] == '\0')) {
   2.939 +        if (satt) {
   2.940 +            const char* inner_mime_type = satt->mime_type;
   2.941 +            if (strcasecmp(inner_mime_type, "text/plain") == 0) {
   2.942 +                free(slong); /* in case of "" */
   2.943 +                src->longmsg = strndup(satt->value, satt->size); 
   2.944 +                
   2.945 +                bloblist_t* next_node = satt->next;
   2.946 +                if (next_node) {
   2.947 +                    inner_mime_type = next_node->mime_type;
   2.948 +                    if (strcasecmp(inner_mime_type, "text/html") == 0) {
   2.949 +                        free(sform);
   2.950 +                        src->longmsg_formatted = strndup(next_node->value, next_node->size);
   2.951 +                    }
   2.952 +                }
   2.953 +            }
   2.954 +            else if (strcasecmp(inner_mime_type, "text/html") == 0) {
   2.955 +                free(sform);
   2.956 +                src->longmsg_formatted = strndup(satt->value, satt->size);
   2.957 +            }
   2.958 +        }
   2.959 +        return true;
   2.960 +    }
   2.961 +    return false;
   2.962 +}
   2.963 +
   2.964 +static PEP_STATUS unencapsulate_hidden_fields(message* src, message* msg,
   2.965 +                                              char** msg_wrap_info) {
   2.966 +    unsigned char pepstr[] = PEP_SUBJ_STRING;
   2.967 +    PEP_STATUS status = PEP_STATUS_OK;
   2.968 +    
   2.969 +    switch (src->enc_format) {
   2.970 +        case PEP_enc_PGP_MIME:
   2.971 +        case PEP_enc_pieces:
   2.972 +        case PEP_enc_PGP_MIME_Outlook1:
   2.973 +        
   2.974 +            status = copy_fields(msg, src);
   2.975 +            if (status != PEP_STATUS_OK)
   2.976 +                return status;
   2.977 +
   2.978 +            // FIXME: This is a mess. Talk with VB about how far we go to identify
   2.979 +            if (is_a_pEpmessage(src) || (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
   2.980 +                _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0))
   2.981 +            {
   2.982 +                char * shortmsg = NULL;
   2.983 +                char * longmsg = NULL;
   2.984 +                
   2.985 +                if (msg->longmsg) {
   2.986 +                    int r = separate_short_and_long(msg->longmsg, 
   2.987 +                                                    &shortmsg, 
   2.988 +                                                    msg_wrap_info,
   2.989 +                                                    &longmsg);
   2.990 +                
   2.991 +                    if (r == -1)
   2.992 +                        return PEP_OUT_OF_MEMORY;
   2.993 +                }
   2.994 +
   2.995 +                // We only use the shortmsg in version 1.0 messages; if it occurs where we
   2.996 +                // didn't replace the subject, we ignore this all
   2.997 +                if (!(*msg_wrap_info)) {
   2.998 +                    if (!shortmsg || 
   2.999 +                        (src->shortmsg != NULL && strcmp(src->shortmsg, "pEp") != 0 &&
  2.1000 +                         _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) != 0)) {
  2.1001 +                             
  2.1002 +                        if (shortmsg != NULL)
  2.1003 +                            free(shortmsg);                        
  2.1004 +                        if (src->shortmsg == NULL) {
  2.1005 +                            shortmsg = strdup("");
  2.1006 +                        }
  2.1007 +                        else {
  2.1008 +                            // FIXME: is msg->shortmsg always a copy of
  2.1009 +                            // src->shortmsg already?
  2.1010 +                            // if so, we need to change the logic so
  2.1011 +                            // that in this case, we don't free msg->shortmsg
  2.1012 +                            // and do this strdup, etc.
  2.1013 +                            shortmsg = strdup(src->shortmsg); 
  2.1014 +                        }        
  2.1015 +                    }
  2.1016 +                }
  2.1017 +                
  2.1018 +                free(msg->shortmsg);
  2.1019 +                free(msg->longmsg);
  2.1020 +
  2.1021 +                msg->shortmsg = shortmsg;
  2.1022 +                msg->longmsg = longmsg;
  2.1023 +            }
  2.1024 +            else {
  2.1025 +                msg->shortmsg = strdup(src->shortmsg);
  2.1026 +                assert(msg->shortmsg);
  2.1027 +                if (msg->shortmsg == NULL)
  2.1028 +                    return PEP_OUT_OF_MEMORY;
  2.1029 +            }
  2.1030 +            break;
  2.1031 +        default:
  2.1032 +                // BUG: must implement more
  2.1033 +                NOT_IMPLEMENTED
  2.1034 +    }
  2.1035 +    return PEP_STATUS_OK;
  2.1036 +
  2.1037 +}
  2.1038 +
  2.1039 +static PEP_STATUS verify_decrypted(PEP_SESSION session,
  2.1040 +                                   message* msg, 
  2.1041 +                                   pEp_identity* sender,
  2.1042 +                                   char* plaintext, 
  2.1043 +                                   size_t plaintext_size,
  2.1044 +                                   stringlist_t** keylist,
  2.1045 +                                   PEP_STATUS* decrypt_status,
  2.1046 +                                   PEP_cryptotech crypto) {
  2.1047 +    bloblist_t* detached_sig = NULL;
  2.1048 +    PEP_STATUS status = _get_detached_signature(msg, &detached_sig);
  2.1049 +    
  2.1050 +    if (detached_sig) {
  2.1051 +        char* dsig_text = detached_sig->value;
  2.1052 +        size_t dsig_size = detached_sig->size;
  2.1053 +        size_t ssize = 0;
  2.1054 +        char* stext = NULL;
  2.1055 +
  2.1056 +        status = _get_signed_text(plaintext, plaintext_size, &stext, &ssize);
  2.1057 +        stringlist_t *verify_keylist = NULL;
  2.1058 +
  2.1059 +        if (ssize > 0 && stext) {
  2.1060 +            status = cryptotech[crypto].verify_text(session, stext,
  2.1061 +                                                    ssize, dsig_text, dsig_size,
  2.1062 +                                                    &verify_keylist);
  2.1063 +
  2.1064 +            if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
  2.1065 +            {
  2.1066 +                *decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
  2.1067 +            
  2.1068 +                status = combine_keylists(session, &verify_keylist, keylist, sender);
  2.1069 +            }
  2.1070 +        }
  2.1071 +    }
  2.1072 +    return status;
  2.1073 +}
  2.1074 +
  2.1075 +static PEP_STATUS _decrypt_in_pieces(PEP_SESSION session, 
  2.1076 +                                     message* src, 
  2.1077 +                                     message** msg_ptr, 
  2.1078 +                                     char* ptext,
  2.1079 +                                     size_t psize) {
  2.1080 +                            
  2.1081 +    PEP_STATUS status = PEP_UNKNOWN_ERROR;
  2.1082 +    
  2.1083 +    *msg_ptr = clone_to_empty_message(src);
  2.1084 +
  2.1085 +    if (*msg_ptr == NULL)
  2.1086 +        return PEP_OUT_OF_MEMORY;
  2.1087 +
  2.1088 +    message* msg = *msg_ptr;
  2.1089 +
  2.1090 +    msg->longmsg = ptext;
  2.1091 +    ptext = NULL;
  2.1092 +
  2.1093 +    bloblist_t *_m = msg->attachments;
  2.1094 +    if (_m == NULL && src->attachments && src->attachments->value) {
  2.1095 +        msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
  2.1096 +        _m = msg->attachments;
  2.1097 +    }
  2.1098 +
  2.1099 +    bloblist_t *_s;
  2.1100 +    for (_s = src->attachments; _s; _s = _s->next) {
  2.1101 +        if (_s->value == NULL && _s->size == 0){
  2.1102 +            _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
  2.1103 +            if (_m == NULL)
  2.1104 +                return PEP_OUT_OF_MEMORY;
  2.1105 +
  2.1106 +        }
  2.1107 +        else if (is_encrypted_attachment(_s)) {
  2.1108 +            stringlist_t *_keylist = NULL;
  2.1109 +            char *attctext  = _s->value;
  2.1110 +            size_t attcsize = _s->size;
  2.1111 +
  2.1112 +            free(ptext);
  2.1113 +            ptext = NULL;
  2.1114 +
  2.1115 +            // FIXME: What about attachments with separate sigs???
  2.1116 +            status = decrypt_and_verify(session, attctext, attcsize,
  2.1117 +                                        NULL, 0,
  2.1118 +                                        &ptext, &psize, &_keylist);
  2.1119 +            free_stringlist(_keylist); // FIXME: Why do we do this?
  2.1120 +
  2.1121 +            if (ptext) {
  2.1122 +                if (is_encrypted_html_attachment(_s)) {
  2.1123 +                    msg->longmsg_formatted = ptext;
  2.1124 +                    ptext = NULL;
  2.1125 +                }
  2.1126 +                else {
  2.1127 +                    static const char * const mime_type = "application/octet-stream";
  2.1128 +                    char * const filename =
  2.1129 +                        without_double_ending(_s->filename);
  2.1130 +                    if (filename == NULL)
  2.1131 +                        return PEP_OUT_OF_MEMORY;
  2.1132 +
  2.1133 +                    _m = bloblist_add(_m, ptext, psize, mime_type,
  2.1134 +                        filename);
  2.1135 +                    free(filename);
  2.1136 +                    if (_m == NULL)
  2.1137 +                        return PEP_OUT_OF_MEMORY;
  2.1138 +
  2.1139 +                    ptext = NULL;
  2.1140 +
  2.1141 +                    if (msg->attachments == NULL)
  2.1142 +                        msg->attachments = _m;
  2.1143 +                }
  2.1144 +            }
  2.1145 +            else {
  2.1146 +                char *copy = malloc(_s->size);
  2.1147 +                assert(copy);
  2.1148 +                if (copy == NULL)
  2.1149 +                    return PEP_OUT_OF_MEMORY;
  2.1150 +                memcpy(copy, _s->value, _s->size);
  2.1151 +                _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  2.1152 +                if (_m == NULL)
  2.1153 +                    return PEP_OUT_OF_MEMORY;
  2.1154 +            }
  2.1155 +        }
  2.1156 +        else {
  2.1157 +            char *copy = malloc(_s->size);
  2.1158 +            assert(copy);
  2.1159 +            if (copy == NULL)
  2.1160 +                return PEP_OUT_OF_MEMORY;
  2.1161 +            memcpy(copy, _s->value, _s->size);
  2.1162 +            _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  2.1163 +            if (_m == NULL)
  2.1164 +                return PEP_OUT_OF_MEMORY;
  2.1165 +        }
  2.1166 +    }
  2.1167 +    return status;
  2.1168 +}
  2.1169 +
  2.1170 +static PEP_STATUS get_crypto_text(message* src, char** crypto_text, size_t* text_size) {
  2.1171 +                
  2.1172 +    // this is only here because of how NOT_IMPLEMENTED works            
  2.1173 +    PEP_STATUS status = PEP_STATUS_OK;
  2.1174 +                    
  2.1175 +    switch (src->enc_format) {
  2.1176 +        case PEP_enc_PGP_MIME:
  2.1177 +            *crypto_text = src->attachments->next->value;
  2.1178 +            *text_size = src->attachments->next->size;
  2.1179 +            break;
  2.1180 +
  2.1181 +        case PEP_enc_PGP_MIME_Outlook1:
  2.1182 +            *crypto_text = src->attachments->value;
  2.1183 +            *text_size = src->attachments->size;
  2.1184 +            break;
  2.1185 +
  2.1186 +        case PEP_enc_pieces:
  2.1187 +            *crypto_text = src->longmsg;
  2.1188 +            *text_size = strlen(*crypto_text);
  2.1189 +            break;
  2.1190 +
  2.1191 +        default:
  2.1192 +            NOT_IMPLEMENTED
  2.1193 +    }
  2.1194 +    
  2.1195 +    return status;
  2.1196 +}
  2.1197 +
  2.1198 +static PEP_STATUS import_priv_keys_from_decrypted_msg(PEP_SESSION session,
  2.1199 +                                                      message* src, 
  2.1200 +                                                      message* msg,
  2.1201 +                                                      bool* imported_keys,
  2.1202 +                                                      bool* imported_private,
  2.1203 +                                                      identity_list** private_il) {
  2.1204 +                                                          
  2.1205 +    PEP_STATUS status = PEP_STATUS_OK;
  2.1206 +    
  2.1207 +    // check for private key in decrypted message attachment while importing
  2.1208 +    identity_list *_private_il = NULL;
  2.1209 +    *imported_keys = import_attached_keys(session, msg, &_private_il);
  2.1210 +    
  2.1211 +    if (_private_il && identity_list_length(_private_il) == 1 &&
  2.1212 +        _private_il->ident->address)
  2.1213 +        *imported_private = true;
  2.1214 +
  2.1215 +    if (private_il && imported_private)
  2.1216 +        *private_il = _private_il;
  2.1217 +    else
  2.1218 +        free_identity_list(_private_il);
  2.1219 +
  2.1220 +    if (imported_keys)
  2.1221 +        status = _update_identity_for_incoming_message(session, src);
  2.1222 +        
  2.1223 +    return status;
  2.1224 +}
  2.1225  
  2.1226  DYNAMIC_API PEP_STATUS _decrypt_message(
  2.1227          PEP_SESSION session,
  2.1228 @@ -1679,6 +2167,18 @@
  2.1229          identity_list **private_il
  2.1230      )
  2.1231  {
  2.1232 +    
  2.1233 +    assert(session);
  2.1234 +    assert(src);
  2.1235 +    assert(dst);
  2.1236 +    assert(keylist);
  2.1237 +    assert(rating);
  2.1238 +    assert(flags);
  2.1239 +
  2.1240 +    if (!(session && src && dst && keylist && rating && flags))
  2.1241 +        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  2.1242 +
  2.1243 +    /*** Begin init ***/
  2.1244      PEP_STATUS status = PEP_STATUS_OK;
  2.1245      PEP_STATUS decrypt_status = PEP_CANNOT_DECRYPT_UNKNOWN;
  2.1246      message *msg = NULL;
  2.1247 @@ -1687,19 +2187,15 @@
  2.1248      char *ptext = NULL;
  2.1249      size_t psize;
  2.1250      stringlist_t *_keylist = NULL;
  2.1251 -    unsigned char pepstr[] = PEP_SUBJ_STRING;
  2.1252 -
  2.1253 -    assert(session);
  2.1254 -    assert(src);
  2.1255 -    assert(dst);
  2.1256 -    assert(keylist);
  2.1257 -    assert(rating);
  2.1258 -    assert(flags);
  2.1259 -
  2.1260 -    if (!(session && src && dst && keylist && rating && flags))
  2.1261 -        return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
  2.1262 +
  2.1263 +    *dst = NULL;
  2.1264 +    *keylist = NULL;
  2.1265 +    *rating = PEP_rating_undefined;
  2.1266  
  2.1267      *flags = 0;
  2.1268 +    /*** End init ***/
  2.1269 +
  2.1270 +    /*** Begin Import any attached public keys and update identities accordingly ***/
  2.1271  
  2.1272      // Private key in unencrypted mail are ignored -> NULL
  2.1273      bool imported_keys = import_attached_keys(session, src, NULL);
  2.1274 @@ -1710,6 +2206,9 @@
  2.1275      if(status != PEP_STATUS_OK)
  2.1276          return ADD_TO_LOG(status);
  2.1277  
  2.1278 +    /*** End Import any attached public keys and update identities accordingly ***/
  2.1279 +    
  2.1280 +    /*** Begin get detached signatures that are attached to the encrypted message ***/
  2.1281      // Get detached signature, if any
  2.1282      bloblist_t* detached_sig = NULL;
  2.1283      char* dsig_text = NULL;
  2.1284 @@ -1719,250 +2218,93 @@
  2.1285          dsig_text = detached_sig->value;
  2.1286          dsig_size = detached_sig->size;
  2.1287      }
  2.1288 -
  2.1289 +    /*** End get detached signatures that are attached to the encrypted message ***/
  2.1290 +
  2.1291 +    /*** Determine encryption format ***/
  2.1292      PEP_cryptotech crypto = determine_encryption_format(src);
  2.1293  
  2.1294 -    *dst = NULL;
  2.1295 -    *keylist = NULL;
  2.1296 -    *rating = PEP_rating_undefined;
  2.1297 -
  2.1298 -    switch (src->enc_format) {
  2.1299 -        case PEP_enc_none:
  2.1300 -            *rating = PEP_rating_unencrypted;
  2.1301 -            if (imported_keys)
  2.1302 -                remove_attached_keys(src);
  2.1303 -            if(session->sync_session->inject_sync_msg){
  2.1304 -                status = receive_DeviceState_msg(session, src, *rating, *keylist);
  2.1305 -                if (status == PEP_MESSAGE_CONSUME ||
  2.1306 -                    status == PEP_MESSAGE_IGNORE) {
  2.1307 -                    free_message(msg);
  2.1308 -                    msg = NULL;
  2.1309 -                    *flags |= (status == PEP_MESSAGE_IGNORE) ?
  2.1310 -                                PEP_decrypt_flag_ignore :
  2.1311 -                                PEP_decrypt_flag_consume;
  2.1312 -                }
  2.1313 -                else if (status != PEP_STATUS_OK) {
  2.1314 -                    return ADD_TO_LOG(status);
  2.1315 -                }
  2.1316 -            }
  2.1317 -            
  2.1318 -            char* slong = src->longmsg;
  2.1319 -            char* sform = src->longmsg_formatted;
  2.1320 -            bloblist_t* satt = src->attachments;
  2.1321 -            
  2.1322 -            if ((!slong || slong[0] == '\0')
  2.1323 -                 && (!sform || sform[0] == '\0')) {
  2.1324 -                if (satt) {
  2.1325 -                    const char* inner_mime_type = satt->mime_type;
  2.1326 -                    if (strcasecmp(inner_mime_type, "text/plain") == 0) {
  2.1327 -                        free(slong); /* in case of "" */
  2.1328 -                        src->longmsg = strndup(satt->value, satt->size); // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
  2.1329 -                        
  2.1330 -                        bloblist_t* next_node = satt->next;
  2.1331 -                        if (next_node) {
  2.1332 -                            inner_mime_type = next_node->mime_type;
  2.1333 -                            if (strcasecmp(inner_mime_type, "text/html") == 0) {
  2.1334 -                                free(sform);
  2.1335 -                                src->longmsg_formatted = strndup(next_node->value, next_node->size);  // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
  2.1336 -                            }
  2.1337 -                        }
  2.1338 -                    }
  2.1339 -                    else if (strcasecmp(inner_mime_type, "text/html") == 0) {
  2.1340 -                        free(sform);
  2.1341 -                        src->longmsg_formatted = strndup(satt->value, satt->size);  // N.B.: longmsg might be shorter, if attachment contains NUL bytes which are not allowed in text/plain!
  2.1342 -                    }
  2.1343 -                }
  2.1344 -            }
  2.1345 -            
  2.1346 -            return ADD_TO_LOG(PEP_UNENCRYPTED);
  2.1347 -
  2.1348 -        case PEP_enc_PGP_MIME:
  2.1349 -            ctext = src->attachments->next->value;
  2.1350 -            csize = src->attachments->next->size;
  2.1351 -            break;
  2.1352 -
  2.1353 -        case PEP_enc_PGP_MIME_Outlook1:
  2.1354 -            ctext = src->attachments->value;
  2.1355 -            csize = src->attachments->size;
  2.1356 -            break;
  2.1357 -
  2.1358 -        case PEP_enc_pieces:
  2.1359 -            ctext = src->longmsg;
  2.1360 -            csize = strlen(ctext);
  2.1361 -            break;
  2.1362 -
  2.1363 -        default:
  2.1364 -            NOT_IMPLEMENTED
  2.1365 +    // Check for and deal with unencrypted messages
  2.1366 +    if (src->enc_format == PEP_enc_none) {
  2.1367 +
  2.1368 +        *rating = PEP_rating_unencrypted;
  2.1369 +
  2.1370 +        if (imported_keys)
  2.1371 +            remove_attached_keys(src);
  2.1372 +
  2.1373 +        status = check_for_sync_msg(session, src, rating, flags, keylist);
  2.1374 +        
  2.1375 +        if (status != PEP_STATUS_OK)
  2.1376 +            return ADD_TO_LOG(status);
  2.1377 +                                    
  2.1378 +        pull_up_attached_main_msg(src);
  2.1379 +        
  2.1380 +        return ADD_TO_LOG(PEP_UNENCRYPTED);
  2.1381      }
  2.1382 +
  2.1383 +    status = get_crypto_text(src, &ctext, &csize);
  2.1384 +    if (status != PEP_STATUS_OK)
  2.1385 +        return status;
  2.1386 +    
  2.1387 +    /** Ok, we should be ready to decrypt. Try decrypt and verify first! **/
  2.1388      status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  2.1389                                                     csize, dsig_text, dsig_size,
  2.1390                                                     &ptext, &psize, &_keylist);
  2.1391 -    if (status > PEP_CANNOT_DECRYPT_UNKNOWN){
  2.1392 +
  2.1393 +    if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  2.1394          GOTO(pep_error);
  2.1395 -    }
  2.1396  
  2.1397      decrypt_status = status;
  2.1398 -
  2.1399 -    if (status == PEP_DECRYPT_NO_KEY){
  2.1400 -        PEP_STATUS sync_status = inject_DeviceState_event(session, CannotDecrypt, NULL, NULL);
  2.1401 -        if (sync_status == PEP_OUT_OF_MEMORY){
  2.1402 -            status = PEP_OUT_OF_MEMORY;
  2.1403 -            goto pep_error;
  2.1404 -        }
  2.1405 -    }
  2.1406 +    
  2.1407 +    /* inject appropriate sync message if we couldn't decrypt due to no key */
  2.1408 +    if (sync_if_no_key(decrypt_status, session) == PEP_OUT_OF_MEMORY)
  2.1409 +        goto pep_error;
  2.1410  
  2.1411      bool imported_private_key_address = false;
  2.1412  
  2.1413 -    if (ptext) {
  2.1414 +    if (ptext) { 
  2.1415 +        /* we got a plaintext from decryption */
  2.1416          switch (src->enc_format) {
  2.1417 +            
  2.1418              case PEP_enc_PGP_MIME:
  2.1419              case PEP_enc_PGP_MIME_Outlook1:
  2.1420 +            
  2.1421                  status = mime_decode_message(ptext, psize, &msg);
  2.1422                  if (status != PEP_STATUS_OK)
  2.1423                      goto pep_error;
  2.1424                  
  2.1425 -                char* mlong = msg->longmsg;
  2.1426 -                char* mform = msg->longmsg_formatted;
  2.1427 -                bloblist_t* matt = msg->attachments;
  2.1428 -                
  2.1429 -                if ((!mlong || mlong[0] == '\0')
  2.1430 -                     && (!mform || mform[0] == '\0')) {
  2.1431 -                    if (matt) {
  2.1432 -                        const char* inner_mime_type = matt->mime_type;
  2.1433 -                        if (strcasecmp(inner_mime_type, "text/plain") == 0) {
  2.1434 -                            free(mlong); /* in case of "" */
  2.1435 -                            msg->longmsg = strndup(matt->value, matt->size);
  2.1436 -                            
  2.1437 -                            bloblist_t* next_node = matt->next;
  2.1438 -                            if (next_node) {
  2.1439 -                                inner_mime_type = next_node->mime_type;
  2.1440 -                                if (strcasecmp(inner_mime_type, "text/html") == 0) {
  2.1441 -                                    free(mform);
  2.1442 -                                    msg->longmsg_formatted = strndup(next_node->value, next_node->size);
  2.1443 -                                }
  2.1444 -                            }
  2.1445 -                        }
  2.1446 -                        else if (strcasecmp(inner_mime_type, "text/html") == 0) {
  2.1447 -                            free(mform);
  2.1448 -                            msg->longmsg_formatted = strndup(matt->value, matt->size);
  2.1449 -                        }
  2.1450 -                    }
  2.1451 -                    if (msg->shortmsg) {
  2.1452 -                        free(src->shortmsg);
  2.1453 -                        src->shortmsg = strdup(msg->shortmsg);
  2.1454 -                    }
  2.1455 +                /* Ensure messages whose maintext is in the attachments
  2.1456 +                   move main text into message struct longmsg et al */
  2.1457 +                if (pull_up_attached_main_msg(msg) && msg->shortmsg) {
  2.1458 +                    free(src->shortmsg);
  2.1459 +                    src->shortmsg = strdup(msg->shortmsg);
  2.1460                  }
  2.1461  
  2.1462 -                if (decrypt_status != PEP_DECRYPTED_AND_VERIFIED) {
  2.1463 -                    status = _get_detached_signature(msg, &detached_sig);
  2.1464 -                    if (decrypt_status == PEP_DECRYPTED && detached_sig) {
  2.1465 -                        dsig_text = detached_sig->value;
  2.1466 -                        dsig_size = detached_sig->size;
  2.1467 -                        size_t ssize = 0;
  2.1468 -                        char* stext = NULL;
  2.1469 -
  2.1470 -                        status = _get_signed_text(ptext, psize, &stext, &ssize);
  2.1471 -                        stringlist_t *_verify_keylist = NULL;
  2.1472 -
  2.1473 -                        if (ssize > 0 && stext) {
  2.1474 -                            status = cryptotech[crypto].verify_text(session, stext,
  2.1475 -                                                                    ssize, dsig_text, dsig_size,
  2.1476 -                                                                    &_verify_keylist);
  2.1477 -
  2.1478 -                            if (status == PEP_VERIFIED || status == PEP_VERIFIED_AND_TRUSTED)
  2.1479 -                            {
  2.1480 -                                decrypt_status = PEP_DECRYPTED_AND_VERIFIED;
  2.1481 -                            
  2.1482 -                                status = combine_keylists(session, &_verify_keylist, &_keylist, src->from);
  2.1483 -                            }
  2.1484 -                        }
  2.1485 -                    }
  2.1486 +                /* if decrypted, but not verified... */
  2.1487 +                if (decrypt_status == PEP_DECRYPTED) {
  2.1488 +                    
  2.1489 +                    // check for private key in decrypted message attachment while importing
  2.1490 +                    status = import_priv_keys_from_decrypted_msg(session, src, msg,
  2.1491 +                                                                 &imported_keys,
  2.1492 +                                                                 &imported_private_key_address,
  2.1493 +                                                                 private_il);
  2.1494 +                    if (status != PEP_STATUS_OK)
  2.1495 +                        GOTO(pep_error);            
  2.1496 +                                                                 
  2.1497 +                    status = verify_decrypted(session,
  2.1498 +                                              msg, src->from,
  2.1499 +                                              ptext, psize,
  2.1500 +                                              &_keylist,
  2.1501 +                                              &decrypt_status,
  2.1502 +                                              crypto);
  2.1503                  }
  2.1504                  break;
  2.1505  
  2.1506              case PEP_enc_pieces:
  2.1507 -                msg = clone_to_empty_message(src);
  2.1508 -                if (msg == NULL)
  2.1509 +                status = _decrypt_in_pieces(session, src, &msg, ptext, psize);
  2.1510 +            
  2.1511 +                if (status == PEP_OUT_OF_MEMORY)
  2.1512                      goto enomem;
  2.1513  
  2.1514 -                msg->longmsg = ptext;
  2.1515 -                ptext = NULL;
  2.1516 -
  2.1517 -                bloblist_t *_m = msg->attachments;
  2.1518 -                if (_m == NULL && src->attachments && src->attachments->value) {
  2.1519 -                    msg->attachments = new_bloblist(NULL, 0, NULL, NULL);
  2.1520 -                    _m = msg->attachments;
  2.1521 -                }
  2.1522 -
  2.1523 -                bloblist_t *_s;
  2.1524 -                for (_s = src->attachments; _s; _s = _s->next) {
  2.1525 -                    if (_s->value == NULL && _s->size == 0){
  2.1526 -                        _m = bloblist_add(_m, NULL, 0, _s->mime_type, _s->filename);
  2.1527 -                        if (_m == NULL)
  2.1528 -                            goto enomem;
  2.1529 -
  2.1530 -                    }
  2.1531 -                    else if (is_encrypted_attachment(_s)) {
  2.1532 -                        stringlist_t *_keylist = NULL;
  2.1533 -                        char *attctext  = _s->value;
  2.1534 -                        size_t attcsize = _s->size;
  2.1535 -
  2.1536 -                        free(ptext);
  2.1537 -                        ptext = NULL;
  2.1538 -
  2.1539 -                        // FIXME: What about attachments with separate sigs???
  2.1540 -                        status = decrypt_and_verify(session, attctext, attcsize,
  2.1541 -                                                    NULL, 0,
  2.1542 -                                                    &ptext, &psize, &_keylist);
  2.1543 -                        free_stringlist(_keylist); // FIXME: Why do we do this?
  2.1544 -
  2.1545 -                        if (ptext) {
  2.1546 -                            if (is_encrypted_html_attachment(_s)) {
  2.1547 -                                msg->longmsg_formatted = ptext;
  2.1548 -                                ptext = NULL;
  2.1549 -                            }
  2.1550 -                            else {
  2.1551 -                                static const char * const mime_type = "application/octet-stream";
  2.1552 -                                char * const filename =
  2.1553 -                                    without_double_ending(_s->filename);
  2.1554 -                                if (filename == NULL)
  2.1555 -                                    goto enomem;
  2.1556 -
  2.1557 -                                _m = bloblist_add(_m, ptext, psize, mime_type,
  2.1558 -                                    filename);
  2.1559 -                                free(filename);
  2.1560 -                                if (_m == NULL)
  2.1561 -                                    goto enomem;
  2.1562 -
  2.1563 -                                ptext = NULL;
  2.1564 -
  2.1565 -                                if (msg->attachments == NULL)
  2.1566 -                                    msg->attachments = _m;
  2.1567 -                            }
  2.1568 -                        }
  2.1569 -                        else {
  2.1570 -                            char *copy = malloc(_s->size);
  2.1571 -                            assert(copy);
  2.1572 -                            if (copy == NULL)
  2.1573 -                                goto enomem;
  2.1574 -                            memcpy(copy, _s->value, _s->size);
  2.1575 -                            _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  2.1576 -                            if (_m == NULL)
  2.1577 -                                goto enomem;
  2.1578 -                        }
  2.1579 -                    }
  2.1580 -                    else {
  2.1581 -                        char *copy = malloc(_s->size);
  2.1582 -                        assert(copy);
  2.1583 -                        if (copy == NULL)
  2.1584 -                            goto enomem;
  2.1585 -                        memcpy(copy, _s->value, _s->size);
  2.1586 -                        _m = bloblist_add(_m, copy, _s->size, _s->mime_type, _s->filename);
  2.1587 -                        if (_m == NULL)
  2.1588 -                            goto enomem;
  2.1589 -                    }
  2.1590 -                }
  2.1591 -
  2.1592                  break;
  2.1593  
  2.1594              default:
  2.1595 @@ -1970,117 +2312,74 @@
  2.1596                  NOT_IMPLEMENTED
  2.1597          }
  2.1598  
  2.1599 -        switch (src->enc_format) {
  2.1600 -            case PEP_enc_PGP_MIME:
  2.1601 -            case PEP_enc_pieces:
  2.1602 -            case PEP_enc_PGP_MIME_Outlook1:
  2.1603 -                status = copy_fields(msg, src);
  2.1604 -                if (status != PEP_STATUS_OK)
  2.1605 -                {
  2.1606 -                    GOTO(pep_error);
  2.1607 +        if (status == PEP_OUT_OF_MEMORY)
  2.1608 +            goto enomem;
  2.1609 +            
  2.1610 +        if (status != PEP_STATUS_OK)
  2.1611 +            goto pep_error;
  2.1612 +
  2.1613 +        if (decrypt_status == PEP_DECRYPTED || decrypt_status == PEP_DECRYPTED_AND_VERIFIED) {
  2.1614 +            char* wrap_info = NULL;
  2.1615 +            status = unencapsulate_hidden_fields(src, msg, &wrap_info);
  2.1616 +            
  2.1617 +            // FIXME: replace with enums, check status
  2.1618 +            if (wrap_info) {
  2.1619 +                if (strcmp(wrap_info, "OUTER") == 0) {
  2.1620 +                    // this only occurs in with a direct outer wrapper
  2.1621 +                    // where the actual content is in the inner wrapper
  2.1622 +                    
  2.1623 +                    bloblist_t* actual_message = msg->attachments;
  2.1624 +                    
  2.1625 +                    while (actual_message) {
  2.1626 +                        char* mime_type = actual_message->mime_type;
  2.1627 +                        if (mime_type) {
  2.1628 +                            // libetpan appears to change the mime_type on this one.
  2.1629 +                            // *growl*
  2.1630 +                            if (strcmp("message/rfc822", mime_type) == 0 ||
  2.1631 +                                strcmp("text/rfc822", mime_type) == 0)
  2.1632 +                                break;
  2.1633 +                        }
  2.1634 +                        actual_message = actual_message->next;
  2.1635 +                    }
  2.1636 +                    
  2.1637 +                    if (actual_message) {
  2.1638 +                        message* inner_message = NULL;
  2.1639 +                        status = mime_decode_message(actual_message->value, 
  2.1640 +                                                     actual_message->size, 
  2.1641 +                                                     &inner_message);
  2.1642 +                        if (status != PEP_STATUS_OK)
  2.1643 +                            GOTO(pep_error);
  2.1644 +                            
  2.1645 +                        free_stringlist(*keylist);
  2.1646 +                        *keylist == NULL;
  2.1647 +                        
  2.1648 +                        free_message(*dst);
  2.1649 +                        
  2.1650 +                        *dst = NULL;
  2.1651 +                        *rating = PEP_rating_undefined;
  2.1652 +                        *flags = 0;
  2.1653 +
  2.1654 +                        message* inner_dec_msg = NULL;
  2.1655 +                        
  2.1656 +                        decrypt_status = decrypt_message(session,
  2.1657 +                                                         inner_message,
  2.1658 +                                                         &inner_dec_msg,
  2.1659 +                                                         keylist,
  2.1660 +                                                         rating,
  2.1661 +                                                         flags);
  2.1662 +                                                         
  2.1663 +                        *dst = inner_dec_msg;
  2.1664 +                        return decrypt_status;
  2.1665 +                    }
  2.1666                  }
  2.1667 -
  2.1668 -                // added p=p because outlook is on crack.
  2.1669 -                if (src->shortmsg == NULL || strcmp(src->shortmsg, "pEp") == 0 ||
  2.1670 -                    strcmp(src->shortmsg, "p=p") == 0 ||
  2.1671 -                    _unsigned_signed_strcmp(pepstr, src->shortmsg, PEP_SUBJ_BYTELEN) == 0)
  2.1672 -                {
  2.1673 -                    char * shortmsg = NULL;
  2.1674 -                    char * longmsg = NULL;
  2.1675 -
  2.1676 -                    if (msg->longmsg) {
  2.1677 -                        int r = separate_short_and_long(msg->longmsg, &shortmsg,
  2.1678 -                                &longmsg);
  2.1679 -                    
  2.1680 -                        if (r == -1)
  2.1681 -                            goto enomem;
  2.1682 -                    }
  2.1683 -
  2.1684 -                    if (shortmsg == NULL) {
  2.1685 -                        if (src->shortmsg == NULL)
  2.1686 -                            shortmsg = strdup("");
  2.1687 -                        else {
  2.1688 -                            // FIXME: is msg->shortmsg always a copy of
  2.1689 -                            // src->shortmsg already?
  2.1690 -                            // if so, we need to change the logic so
  2.1691 -                            // that in this case, we don't free msg->shortmsg
  2.1692 -                            // and do this strdup, etc.
  2.1693 -                            shortmsg = strdup(src->shortmsg);
  2.1694 -                        }
  2.1695 -                    }
  2.1696 -
  2.1697 -
  2.1698 -                    free(msg->shortmsg);
  2.1699 -                    free(msg->longmsg);
  2.1700 -
  2.1701 -                    msg->shortmsg = shortmsg;
  2.1702 -                    msg->longmsg = longmsg;
  2.1703 -                }
  2.1704 -                else {
  2.1705 -                    msg->shortmsg = strdup(src->shortmsg);
  2.1706 -                    assert(msg->shortmsg);
  2.1707 -                    if (msg->shortmsg == NULL)
  2.1708 -                        goto enomem;
  2.1709 -                }
  2.1710 -                break;
  2.1711 -            default:
  2.1712 -                    // BUG: must implement more
  2.1713 -                    NOT_IMPLEMENTED
  2.1714 +            }
  2.1715          }
  2.1716 -
  2.1717 -        // check for private key in decrypted message attachement while inporting
  2.1718 -        identity_list *_private_il = NULL;
  2.1719 -        imported_keys = import_attached_keys(session, msg, &_private_il);
  2.1720 -        if (_private_il &&
  2.1721 -            identity_list_length(_private_il) == 1 &&
  2.1722 -            _private_il->ident->address)
  2.1723 -        {
  2.1724 -            imported_private_key_address = true;
  2.1725 -        }
  2.1726 -
  2.1727 -        if(private_il && imported_private_key_address){
  2.1728 -            *private_il = _private_il;
  2.1729 -        }else{
  2.1730 -            free_identity_list(_private_il);
  2.1731 -        }
  2.1732 -
  2.1733 -        if(decrypt_status == PEP_DECRYPTED){
  2.1734 -
  2.1735 -            // TODO optimize if import_attached_keys didn't import any key
  2.1736 -
  2.1737 -            // In case message did decrypt, but no valid signature could be found
  2.1738 -            // then retry decrypt+verify after importing key.
  2.1739 -
  2.1740 -            // Update msg->from in case we just imported a key
  2.1741 -            // we would need to check signature
  2.1742 -
  2.1743 -            status = _update_identity_for_incoming_message(session, src);
  2.1744 -            if(status != PEP_STATUS_OK)
  2.1745 -            {
  2.1746 -                GOTO(pep_error);
  2.1747 -            }
  2.1748 -
  2.1749 -            char *re_ptext = NULL;
  2.1750 -            size_t re_psize;
  2.1751 -
  2.1752 -            free_stringlist(_keylist);
  2.1753 -            _keylist = NULL;
  2.1754 -
  2.1755 -            status = cryptotech[crypto].decrypt_and_verify(session, ctext,
  2.1756 -                csize, dsig_text, dsig_size, &re_ptext, &re_psize, &_keylist);
  2.1757 -
  2.1758 -            free(re_ptext);
  2.1759 -
  2.1760 -            if (status > PEP_CANNOT_DECRYPT_UNKNOWN)
  2.1761 -            {
  2.1762 -                GOTO(pep_error);
  2.1763 -            }
  2.1764 -
  2.1765 -            decrypt_status = status;
  2.1766 -        }
  2.1767 -
  2.1768 +        
  2.1769          *rating = decrypt_rating(decrypt_status);
  2.1770  
  2.1771 +        /* Ok, now we have a keylist used for decryption/verification.
  2.1772 +           now we need to update the message rating with the 
  2.1773 +           sender and recipients in mind */
  2.1774          status = amend_rating_according_to_sender_and_recipients(session,
  2.1775                                                                   rating,
  2.1776                                                                   src->from,
  2.1777 @@ -2088,55 +2387,54 @@
  2.1778  
  2.1779          if (status != PEP_STATUS_OK)
  2.1780              GOTO(pep_error);
  2.1781 -    }
  2.1782 -    else
  2.1783 -    {
  2.1784 +            
  2.1785 +    } 
  2.1786 +    else {
  2.1787 +        // We did not get a plaintext out of the decryption process.
  2.1788 +        // Abort and return error.
  2.1789          *rating = decrypt_rating(decrypt_status);
  2.1790          goto pep_error;
  2.1791      }
  2.1792  
  2.1793 -    // Case of own key imported from own trusted message
  2.1794 -    if (// Message have been reliably decrypted
  2.1795 -        msg &&
  2.1796 -        *rating >= PEP_rating_trusted &&
  2.1797 -        imported_private_key_address &&
  2.1798 -        // to is [own]
  2.1799 +    /* 
  2.1800 +       Ok, at this point, we know we have a reliably decrypted message.
  2.1801 +       Prepare the output message for return.
  2.1802 +    */
  2.1803 +    
  2.1804 +    // 1. Check to see if this message is to us and contains an own key imported 
  2.1805 +    // from own trusted message 
  2.1806 +    if (msg && *rating >= PEP_rating_trusted && imported_private_key_address &&
  2.1807          msg->to->ident->user_id &&
  2.1808 -        strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0
  2.1809 -        )
  2.1810 -    {
  2.1811 +        strcmp(msg->to->ident->user_id, PEP_OWN_USERID) == 0) {
  2.1812 +
  2.1813 +        // flag it as such
  2.1814          *flags |= PEP_decrypt_flag_own_private_key;
  2.1815      }
  2.1816  
  2.1817 +    // 2. Clean up message and prepare for return 
  2.1818      if (msg) {
  2.1819 +        
  2.1820 +        /* add pEp-related status flags to header */
  2.1821          decorate_message(msg, *rating, _keylist);
  2.1822 +        
  2.1823          if (imported_keys)
  2.1824              remove_attached_keys(msg);
  2.1825 -        if (*rating >= PEP_rating_reliable &&
  2.1826 -            session->sync_session->inject_sync_msg) {
  2.1827 -            status = receive_DeviceState_msg(session, msg, *rating, _keylist);
  2.1828 -            if (status == PEP_MESSAGE_CONSUME ||
  2.1829 -                status == PEP_MESSAGE_IGNORE) {
  2.1830 -                free_message(msg);
  2.1831 -                msg = NULL;
  2.1832 -                *flags |= (status == PEP_MESSAGE_IGNORE) ?
  2.1833 -                            PEP_decrypt_flag_ignore :
  2.1834 -                            PEP_decrypt_flag_consume;
  2.1835 -
  2.1836 -            }
  2.1837 -            else if (status != PEP_STATUS_OK){
  2.1838 +            
  2.1839 +        if (*rating >= PEP_rating_reliable) { 
  2.1840 +            status = check_for_sync_msg(session, src, rating, flags, &_keylist);
  2.1841 +        
  2.1842 +            if (status != PEP_STATUS_OK)
  2.1843                  goto pep_error;
  2.1844 -            }
  2.1845          }
  2.1846 -    }
  2.1847 -    if (msg) {
  2.1848 +        
  2.1849 +        // copy message id to output message        
  2.1850          if (src->id) {
  2.1851              msg->id = strdup(src->id);
  2.1852              assert(msg->id);
  2.1853              if (msg->id == NULL)
  2.1854                  goto enomem;
  2.1855          }
  2.1856 -    }
  2.1857 +    } // End prepare output message for return
  2.1858  
  2.1859      *dst = msg;
  2.1860      *keylist = _keylist;
     3.1 --- a/src/message_api.h	Mon Oct 09 10:50:25 2017 +0200
     3.2 +++ b/src/message_api.h	Tue Oct 10 02:58:25 2017 +0200
     3.3 @@ -33,7 +33,11 @@
     3.4      // This flag is for special use cases and should not be used
     3.5      // by normal pEp clients!
     3.6      PEP_encrypt_flag_force_unsigned = 0x2,
     3.7 -    PEP_encrypt_flag_force_no_attached_key = 0x4
     3.8 +    PEP_encrypt_flag_force_no_attached_key = 0x4,
     3.9 +    
    3.10 +    // This is used for outer messages (used to wrap the real message)
    3.11 +    // This is only used internally and (eventually) by transport functions
    3.12 +    PEP_encrypt_flag_inner_message = 0x8
    3.13  } PEP_encrypt_flags; 
    3.14  
    3.15  typedef unsigned int PEP_encrypt_flags_t;
     4.1 --- a/src/pEp_internal.h	Mon Oct 09 10:50:25 2017 +0200
     4.2 +++ b/src/pEp_internal.h	Tue Oct 10 02:58:25 2017 +0200
     4.3 @@ -37,6 +37,19 @@
     4.4  #define PEP_SUBJ_BYTELEN 5
     4.5  #endif
     4.6  
     4.7 +#ifndef PEP_SUBJ_KEY
     4.8 +#define PEP_SUBJ_KEY "Subject: "
     4.9 +#define PEP_SUBJ_KEY_LC "subject: "
    4.10 +#define PEP_SUBJ_KEY_LEN 9
    4.11 +#endif
    4.12 +
    4.13 +#ifndef PEP_MSG_WRAP_KEY
    4.14 +#define PEP_MSG_WRAP_KEY "pEp-Wrapped-Message-Info: "
    4.15 +#define PEP_MSG_WRAP_KEY_LC "pep-wrapped-message-info: "
    4.16 +#define PEP_MSG_WRAP_KEY_LEN 26
    4.17 +#endif
    4.18 +
    4.19 +
    4.20  #include "platform.h"
    4.21  
    4.22  #ifdef WIN32
     5.1 --- a/test/external_revoke_test.cc	Mon Oct 09 10:50:25 2017 +0200
     5.2 +++ b/test/external_revoke_test.cc	Tue Oct 10 02:58:25 2017 +0200
     5.3 @@ -247,6 +247,9 @@
     5.4      
     5.5      // encrypt something to the key
     5.6      cout << "Creating message…\n";
     5.7 +    
     5.8 +    // cout << "First, update identity though!\n";
     5.9 +    // status = update_identity(session, recip1);
    5.10      to_list = new_identity_list(identity_dup(recip1)); // to bob
    5.11      outgoing_msg = new_message(PEP_dir_outgoing);
    5.12      assert(outgoing_msg);
    5.13 @@ -258,8 +261,8 @@
    5.14      cout << "Message created.\n";
    5.15  
    5.16      status = encrypt_message(session, outgoing_msg, NULL, &encrypted_outgoing_msg, PEP_enc_PGP_MIME, 0);
    5.17 -
    5.18      ct = (encrypted_outgoing_msg ? encrypted_outgoing_msg->to->ident->comm_type : outgoing_msg->to->ident->comm_type);
    5.19 +    
    5.20  
    5.21      // CHECK STATUS???
    5.22      cout << "Encryption returns with status " << tl_status_string(status) << endl;
    5.23 @@ -285,11 +288,13 @@
    5.24      status = decrypt_message(session, encrypted_outgoing_msg, &decrypted_msg, &keylist, &rating, &flags);
    5.25      cout << "Decryption returns with status " << tl_status_string(status) << endl;
    5.26      assert(status == PEP_STATUS_OK);
    5.27 -
    5.28 +    assert(decrypted_msg);
    5.29 +    
    5.30      // check rating
    5.31      cout << "Rating of decrypted message to trusted recip: " << tl_rating_string(rating) << endl;
    5.32      assert(rating == PEP_rating_reliable);
    5.33  
    5.34 +    status = update_identity(session, decrypted_msg->to->ident);
    5.35      ct = (decrypted_msg ? decrypted_msg->to->ident->comm_type : outgoing_msg->to->ident->comm_type);
    5.36  
    5.37      cout << "comm_type: " << tl_ct_string(ct) << endl;