merge "default" into "ENGINE-320" and solved one merge conflict. :-) ENGINE-320
authorRoker <roker@pep-project.org>
Mon, 15 Jan 2018 17:07:05 +0100
branchENGINE-320
changeset 23794ab7ad77efaf
parent 2318 fb3871072566
parent 2378 b244047cdacc
merge "default" into "ENGINE-320" and solved one merge conflict. :-)
src/message_api.c
src/mime.c
     1.1 --- a/.hgignore	Fri Dec 15 15:05:41 2017 +0100
     1.2 +++ b/.hgignore	Mon Jan 15 17:07:05 2018 +0100
     1.3 @@ -57,3 +57,7 @@
     1.4  secring.gpg
     1.5  trustdb.gpg
     1.6  .pEp_management.db
     1.7 +.cache
     1.8 +__pycache__
     1.9 +*.pyc
    1.10 +test/python_tests/test?
     2.1 --- a/.hgtags	Fri Dec 15 15:05:41 2017 +0100
     2.2 +++ b/.hgtags	Mon Jan 15 17:07:05 2018 +0100
     2.3 @@ -4,3 +4,4 @@
     2.4  a1ba15c1ac041c780e52e759db6b77d116f29c72 0.8.0
     2.5  3efe9ded2561d3f6d406acbcbcee01b823cb4de8 for_Outlook-1.1.10
     2.6  fa00137505b8528c77efe8df40963f5fef452cad 0.9.0 release
     2.7 +b70a6082836b89f8718b23dcba0624d6db318033 ENGINE-323 fixed
     3.1 --- a/build-android/jni/Android.mk	Fri Dec 15 15:05:41 2017 +0100
     3.2 +++ b/build-android/jni/Android.mk	Mon Jan 15 17:07:05 2018 +0100
     3.3 @@ -29,13 +29,13 @@
     3.4  #
     3.5  LOCAL_CFLAGS    += -DSQLITE_TEMP_STORE=3
     3.6  
     3.7 -LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../src \
     3.8 -                    $(LOCAL_PATH)/../../asn.1 \
     3.9 +LOCAL_C_INCLUDES += $(LOCAL_PATH)/../../asn.1 \
    3.10                      $(GPGME_INCLUDE_PATH) \
    3.11                      $(LIBETPAN_PATH)/include
    3.12  LOCAL_C_INCLUDES += $(GPGBUILD)/include
    3.13  
    3.14 -LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)/../../src
    3.15 +$(shell sh $(LOCAL_PATH)/../takeOutHeaderFiles.sh $(LOCAL_PATH)../../)
    3.16 +LOCAL_EXPORT_C_INCLUDES += $(LOCAL_PATH)../include
    3.17  
    3.18  ENGINE_SRC_FILES := $(shell find $(LOCAL_PATH)/../../src/ ! -name "*netpgp*" -name "*.c")
    3.19  #ENGINE_SRC_FILES := $(wildcard $(LOCAL_PATH)/../../src/*.c)
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/build-android/takeOutHeaderFiles.sh	Mon Jan 15 17:07:05 2018 +0100
     4.3 @@ -0,0 +1,9 @@
     4.4 +#!/bin/sh
     4.5 +
     4.6 +set -e
     4.7 +engine_dir="$1"
     4.8 +
     4.9 +mkdir -p "$engine_dir/build-android/include/pEp"
    4.10 +cd "$engine_dir/src"
    4.11 +cp *.h "$engine_dir/build-android/include/pEp"
    4.12 +
     5.1 --- a/src/Makefile	Fri Dec 15 15:05:41 2017 +0100
     5.2 +++ b/src/Makefile	Mon Jan 15 17:07:05 2018 +0100
     5.3 @@ -80,6 +80,7 @@
     5.4  .PHONY: clean
     5.5  clean:
     5.6  	rm -f *.d *.o *.a $(TARGET) *.dll *.so *.zip *.d.* *.def *~
     5.7 +	rm -Rf $(TARGET).dSYM
     5.8  
     5.9  .PHONY: install
    5.10  install: $(TARGET)
     6.1 --- a/src/message_api.c	Fri Dec 15 15:05:41 2017 +0100
     6.2 +++ b/src/message_api.c	Mon Jan 15 17:07:05 2018 +0100
     6.3 @@ -29,7 +29,8 @@
     6.4      return false;
     6.5  }
     6.6  
     6.7 -static bool is_wrapper(message* src) {
     6.8 +static bool is_wrapper(message* src)
     6.9 +{
    6.10      bool retval = false;
    6.11      
    6.12      if (src) {
    6.13 @@ -62,20 +63,23 @@
    6.14  }
    6.15  
    6.16  
    6.17 -static stringpair_t* search_optfields(const message* msg, const char* key) {
    6.18 -    stringpair_list_t* opt_fields = msg->opt_fields;
    6.19 -    
    6.20 -    const stringpair_list_t* curr;
    6.21 -    
    6.22 -    for (curr = opt_fields; curr && curr->value; curr = curr->next) {
    6.23 -        if (curr->value->key) {
    6.24 -            if (strcasecmp(curr->value->key, key) == 0)
    6.25 -                return curr->value;
    6.26 -        }
    6.27 -    } 
    6.28 -    
    6.29 -    return NULL;
    6.30 -}
    6.31 +/*
    6.32 + * static stringpair_t* search_optfields(const message* msg, const char* key) {
    6.33 + *     if (msg && key) {
    6.34 + *         stringpair_list_t* opt_fields = msg->opt_fields;
    6.35 + *         
    6.36 + *         const stringpair_list_t* curr;
    6.37 + *         
    6.38 + *         for (curr = opt_fields; curr && curr->value; curr = curr->next) {
    6.39 + *             if (curr->value->key) {
    6.40 + *                 if (strcasecmp(curr->value->key, key) == 0)
    6.41 + *                     return curr->value;
    6.42 + *             }
    6.43 + *         } 
    6.44 + *     }
    6.45 + *     return NULL;
    6.46 + * }
    6.47 + */
    6.48  
    6.49  static char * keylist_to_string(const stringlist_t *keylist)
    6.50  {
    6.51 @@ -1415,15 +1419,15 @@
    6.52      assert(session);
    6.53      assert(src);
    6.54      assert(dst);
    6.55 -    assert(enc_format != PEP_enc_none);
    6.56 -
    6.57 -    if (!(session && src && dst && enc_format != PEP_enc_none))
    6.58 +
    6.59 +    if (!(session && src && dst))
    6.60          return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
    6.61  
    6.62      if (src->dir == PEP_dir_incoming)
    6.63          return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
    6.64  
    6.65      determine_encryption_format(src);
    6.66 +    // TODO: change this for multi-encryption in message format 2.0
    6.67      if (src->enc_format != PEP_enc_none)
    6.68          return ADD_TO_LOG(PEP_ILLEGAL_VALUE);
    6.69  
    6.70 @@ -1450,7 +1454,7 @@
    6.71  
    6.72      identity_list * _il;
    6.73  
    6.74 -    if ((_il = src->bcc) && _il->ident)
    6.75 +    if (enc_format != PEP_enc_none && (_il = src->bcc) && _il->ident)
    6.76      {
    6.77          // BCC limited support:
    6.78          //     - App splits mails with BCC in multiple mails.
    6.79 @@ -1524,7 +1528,7 @@
    6.80          }
    6.81      }
    6.82  
    6.83 -    if (!dest_keys_found ||
    6.84 +    if (enc_format == PEP_enc_none || !dest_keys_found ||
    6.85          stringlist_length(keys)  == 0 ||
    6.86          _rating(max_comm_type,
    6.87                  PEP_rating_undefined) < PEP_rating_reliable)
    6.88 @@ -2194,7 +2198,7 @@
    6.89                                       char* ptext,
    6.90                                       size_t psize) {
    6.91                              
    6.92 -    PEP_STATUS status = PEP_UNKNOWN_ERROR;
    6.93 +    PEP_STATUS status = PEP_STATUS_OK;
    6.94      
    6.95      *msg_ptr = clone_to_empty_message(src);
    6.96  
    6.97 @@ -2552,9 +2556,7 @@
    6.98             now we need to update the message rating with the 
    6.99             sender and recipients in mind */
   6.100          status = amend_rating_according_to_sender_and_recipients(session,
   6.101 -                                                                 rating,
   6.102 -                                                                 src->from,
   6.103 -                                                                 _keylist);
   6.104 +                rating, src->from, _keylist);
   6.105  
   6.106          if (status != PEP_STATUS_OK)
   6.107              GOTO(pep_error);
   6.108 @@ -3191,10 +3193,7 @@
   6.109          GOTO(pep_error);
   6.110      }
   6.111  
   6.112 -    // Clear the encryption status, or mime_encode will ignore
   6.113 -    // the plaintext and do all sorts of other stupid things
   6.114 -    enc_msg->enc_format = PEP_enc_none;
   6.115 -    status = mime_encode_message(enc_msg, false, mime_ciphertext);
   6.116 +    status = _mime_encode_message_internal(enc_msg, false, mime_ciphertext, false);
   6.117  
   6.118  pep_error:
   6.119      free_message(tmp_msg);
   6.120 @@ -3380,10 +3379,8 @@
   6.121      if (status != PEP_STATUS_OK)
   6.122          GOTO(pep_error);
   6.123  
   6.124 -    status = amend_rating_according_to_sender_and_recipients(session,
   6.125 -                                                             &_rating,
   6.126 -                                                             msg->from,
   6.127 -                                                             _keylist);
   6.128 +    status = amend_rating_according_to_sender_and_recipients(session, &_rating,
   6.129 +            msg->from, _keylist);
   6.130      if (status == PEP_STATUS_OK)
   6.131          *rating = _rating;
   6.132      
     7.1 --- a/src/message_api.h	Fri Dec 15 15:05:41 2017 +0100
     7.2 +++ b/src/message_api.h	Mon Jan 15 17:07:05 2018 +0100
     7.3 @@ -49,7 +49,8 @@
     7.4  //      session (in)        session handle
     7.5  //      src (in)            message to encrypt
     7.6  //      extra (in)          extra keys for encryption
     7.7 -//      dst (out)           pointer to new encrypted message or NULL on failure
     7.8 +//      dst (out)           pointer to new encrypted message or NULL if no
     7.9 +//                          encryption could take place
    7.10  //      enc_format (in)     encrypted format
    7.11  //      flags (in)          flags to set special encryption features
    7.12  //
    7.13 @@ -60,9 +61,9 @@
    7.14  //      PEP_KEY_HAS_AMBIG_NAME          at least one of the receipient keys has
    7.15  //                                      an ambiguous name
    7.16  //      PEP_GET_KEY_FAILED              cannot retrieve key
    7.17 -//      PEP_UNENCRYPTED                 no recipients with usable key, 
    7.18 -//                                      message is left unencrypted,
    7.19 -//                                      and key is attached to it
    7.20 +//      PEP_UNENCRYPTED                 on demand or no recipients with usable
    7.21 +//                                      key, is left unencrypted, and key is
    7.22 +//                                      attached to it
    7.23  //
    7.24  //  caveat:
    7.25  //      the ownershop of src remains with the caller
     8.1 --- a/src/mime.c	Fri Dec 15 15:05:41 2017 +0100
     8.2 +++ b/src/mime.c	Mon Jan 15 17:07:05 2018 +0100
     8.3 @@ -97,6 +97,20 @@
     8.4      return status;
     8.5  }
     8.6  
     8.7 +static bool known_ascii_type(const char* mime_type) {
     8.8 +    const char* text_types[] = {"application/pgp-keys",
     8.9 +                                "application/pgp-encrypted"};
    8.10 +    const int TEXT_TYPE_ARRAY_SIZE = sizeof(text_types)/sizeof(text_types[0]);
    8.11 +    
    8.12 +    int i;
    8.13 +    
    8.14 +    for (i = 0; i < TEXT_TYPE_ARRAY_SIZE; i++) {
    8.15 +        if (strcmp(text_types[i], mime_type) == 0)
    8.16 +            return true;
    8.17 +    }
    8.18 +    return false;
    8.19 +}
    8.20 +
    8.21  
    8.22  static PEP_STATUS mime_attachment(
    8.23          bloblist_t *blob,
    8.24 @@ -122,7 +136,9 @@
    8.25          mime_type = blob->mime_type;
    8.26  
    8.27      pEp_rid_list_t* resource = parse_uri(blob->filename);
    8.28 -    mime = get_file_part(resource, mime_type, blob->value_ref, blob->size, transport_encode);
    8.29 +    bool already_ascii = known_ascii_type(mime_type);
    8.30 +    mime = get_file_part(resource, mime_type, blob->value_ref, blob->size, 
    8.31 +                         (already_ascii ? false : transport_encode));
    8.32      free_rid_list(resource);
    8.33      
    8.34      assert(mime);
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/pEp_string.c	Mon Jan 15 17:07:05 2018 +0100
     9.3 @@ -0,0 +1,52 @@
     9.4 +// This file is under GNU General Public License 3.0
     9.5 +// see LICENSE.txt
     9.6 +
     9.7 +#include "pEp_string.h"
     9.8 +
     9.9 +#include <stdlib.h>
    9.10 +#include <assert.h>
    9.11 +
    9.12 +DYNAMIC_API char * new_string(const char *src, size_t len)
    9.13 +{
    9.14 +    assert(src || len);
    9.15 +    if (!(src || len))
    9.16 +        return NULL;
    9.17 +
    9.18 +    char *s = NULL;
    9.19 +    if (src) {
    9.20 +        if (len)
    9.21 +            s = strndup(src, len);
    9.22 +        else
    9.23 +            s = strdup(src);
    9.24 +        assert(s);
    9.25 +    }
    9.26 +    else {
    9.27 +        s = calloc(1, len);
    9.28 +        assert(s);
    9.29 +    }
    9.30 +
    9.31 +    return s;
    9.32 +}
    9.33 +
    9.34 +
    9.35 +DYNAMIC_API void free_string(char *s)
    9.36 +{
    9.37 +    free(s);
    9.38 +}
    9.39 +
    9.40 +DYNAMIC_API char * string_dup(const char *src, size_t len)
    9.41 +{
    9.42 +    assert(src);
    9.43 +    if (!src)
    9.44 +        return NULL;
    9.45 +
    9.46 +    char *s = NULL;
    9.47 +    if (len)
    9.48 +        s = strndup(src, len);
    9.49 +    else
    9.50 +        s = strdup(src);
    9.51 +    assert(s);
    9.52 +
    9.53 +    return s;
    9.54 +}
    9.55 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/pEp_string.h	Mon Jan 15 17:07:05 2018 +0100
    10.3 @@ -0,0 +1,56 @@
    10.4 +// This file is under GNU General Public License 3.0
    10.5 +// see LICENSE.txt
    10.6 +
    10.7 +#pragma once
    10.8 +
    10.9 +#include <string.h>
   10.10 +#include "dynamic_api.h"
   10.11 +
   10.12 +#ifdef __cplusplus
   10.13 +extern "C" {
   10.14 +#endif
   10.15 +
   10.16 +
   10.17 +// new_string() - allocate a new string
   10.18 +//
   10.19 +//  parameters:
   10.20 +//      src (in)        string to copy or NULL
   10.21 +//      len (in)        length of newly created string or 0 for default
   10.22 +//
   10.23 +//  return value:
   10.24 +//      pointer to string object or NULL if out of memory
   10.25 +//
   10.26 +//  caveat:
   10.27 +//      one of the two parameters has to be set at least
   10.28 +//
   10.29 +//  calling with str and len is equivalent to strndup()
   10.30 +//  calling with str but len=0 is equivalent to strdup()
   10.31 +//  calling with str=NULL and len is equivalent to calloc()
   10.32 +
   10.33 +DYNAMIC_API char * new_string(const char *src, size_t len);
   10.34 +
   10.35 +
   10.36 +// free_string() - free memory occupied by string
   10.37 +//
   10.38 +//  parameters:
   10.39 +//      s (in)          pointer to string to free
   10.40 +
   10.41 +DYNAMIC_API void free_string(char *s);
   10.42 +
   10.43 +
   10.44 +// string_dup() - duplicate a string
   10.45 +//
   10.46 +//  parameters:
   10.47 +//      src (in)        string to duplicate
   10.48 +//      len (in)        length of newly created string or 0 for default
   10.49 +//
   10.50 +//  return value:
   10.51 +//      pointer to copy or NULL if out of memory
   10.52 +
   10.53 +DYNAMIC_API char * string_dup(const char *src, size_t len);
   10.54 +
   10.55 +
   10.56 +#ifdef __cplusplus
   10.57 +}
   10.58 +#endif
   10.59 +
    11.1 --- a/test/message_api_test.cc	Fri Dec 15 15:05:41 2017 +0100
    11.2 +++ b/test/message_api_test.cc	Mon Jan 15 17:07:05 2018 +0100
    11.3 @@ -12,8 +12,160 @@
    11.4  
    11.5  using namespace std;
    11.6  
    11.7 +void test_MIME_decrypt_message()
    11.8 +{
    11.9 +	static const std::string private_key =
   11.10 +        "-----BEGIN PGP PRIVATE KEY BLOCK-----\n"
   11.11 +        "\n"
   11.12 +        "lQOmBFpCxkEBCCC8ugYsWOsv966JOl5Ahdw6YiobbU9peFLV8aMBOG+oNIPs3BQj\n"
   11.13 +        "u3FUugkVqA5In93oqVgNZ2LU6Y/RWldN+Pc4IMf6qSZnTBj/1ffBjuqAow1hPEYV\n"
   11.14 +        "354LNYoQtJXioY0X8FjRgt+NoBPphRbo+XJ0uIQckJey6uvvtukEZkMLM1ur1aID\n"
   11.15 +        "9biJZ7yXtJM7KxN5792Vo2gGp/1hlFW6SfM7E0g60L5DT8C/BsYeKtMmxKNZngo6\n"
   11.16 +        "ZBxLDAcxMcT5UpRW79B34pTINZAEsvLeT7TLajzqP/OggUrFkkwLr3KJk09aFF+6\n"
   11.17 +        "TN6CI2fDdSqdoPVEgNrZE9zFqAgVWOdhLOHRpXgt7wARAQABAAgZATpqsN4xRaIk\n"
   11.18 +        "giMdmujkGoMqB/ypoCOW0mqcp3ThESSqWR/Dh8n//k+poHj0Atf7fzie6JNsKruM\n"
   11.19 +        "Yo3mdIzyuuxHsONp6xEtNnkDgEB4WTb2btQQFrNaWXNTPzGVqiBoBShcw5xI7SiG\n"
   11.20 +        "CKaDlCePbaAHyBHO0uzBdVFo6czqkceXSJ+hNDY7xbURbkgIA5SGJ+8cssmcKKoc\n"
   11.21 +        "LDY34S3Pu0gG3+K6gSedYaHAqVVQn8dmEitvDFQ96sTNIpPiMp5Tc+/8UXziF91f\n"
   11.22 +        "XRrXYX9o3nkCvz01qtjR4LQVDztysm3/VmDcsjqhzALiiBLigyglpE5DEp0+wMUq\n"
   11.23 +        "gw5TpWZ63lf6XjEEEM+c+D3HHsEnh24+DNU2OyfFZGpp9olSaTDcXtEBuBTt/Uhy\n"
   11.24 +        "NnqF4MswQ2me4Lfr4D4sUS5jtsKkee+2IQuwtg/bBVYsL6MfV2llJco2vrOCb6y8\n"
   11.25 +        "u9CnQhRbVBd6kBMiJeE50Ijk3jP78GrkPm3rGWKCWRuXVr07+U2MsEnvSkkBfpEE\n"
   11.26 +        "EOi2NcXCCJux9xZv0xOyWogXDVLVrrhs8/PGjJO1IeaMtmrzleo3azUbWus/BYLA\n"
   11.27 +        "vJkO+PElg/MCc2ub5hFs7IqSbLmteWFiSOzTcdHNWeqETsixAc8dpbq0zhkPwdzA\n"
   11.28 +        "otLEBS3mpaB29Bpt9lzgewHoVI/o/OvUFFaP+b1Fd4wOJH8EELZPWw+85tSB1l63\n"
   11.29 +        "4B+77YoBc9wDBFg7Pt4Eo0eghFZ/159YTA1bcr3fZ8bYIgiHHNLC/Fsx+sUu00PC\n"
   11.30 +        "ctLrOxGRbuDyNy2rsezf8Bz8xpihBPuBmSbKoaZguSazgpuC1LPkVbQQVaN1h+Ir\n"
   11.31 +        "9/tJufw+hT9Eggvx5xtCo7GD1trnx0xLKbQhVGVzdCBUb25pIDxlbmdpbmUtMzIy\n"
   11.32 +        "QHBlcHRlc3QuY2g+iQE8BBMBCAAiBQJaQsZBAhsDBgsJCAcDAgYVCAIJCgsEFgID\n"
   11.33 +        "AQIeAQIXgAAKCRCvYy6fx5m31NWeCCCXgm1J7Pq4ECKaMZcp7WoWguXQW+Ellgrx\n"
   11.34 +        "B6EjZmvy1iB0RYaDz6F0HCXd0WtC2YDlkxJ47rKBHsnmcyHbFNlY0fgc5Uhs7apI\n"
   11.35 +        "bBMHHRGwl8pie05DqxQ0jBxO2esk/IPJDhLXw7gZvaY/9PUS669QWoq+L/Hhph8V\n"
   11.36 +        "5v65jnw2937bOaf6wvEUUj2cg6cUaPTZSXv26vxUrT8RD+DxbQiNjJIeGRfVj3QY\n"
   11.37 +        "9GCTcp45ZaB8kLQEVayFrC3Jougcklk5DS1zlFCHiYLa4cco/68XHL7/CFdIxxsK\n"
   11.38 +        "Rd/3FYWX6zfQZJs5U6KmGy18cXvk0OOtTru9aNHR0YiLj4Vs8K+mWA10vZ0DpgRa\n"
   11.39 +        "QsZBAQggwrnOsiJ3JNB+mTm9pZbX4mUkw7OXrar1CvOVDqrnI+H+Z9/DC1FDEupw\n"
   11.40 +        "8mD3fFV4veO6smjb9wWAXhmU88OxXziChM8WJlWz2GrZPoM2DIYu1gLycp7wo1Md\n"
   11.41 +        "mzhd/5tpBWMJ4gGS9AjvQc5ffk7JVBAnmhh4ZtdoEctHMJs7+1RhXE7KUM1QWjew\n"
   11.42 +        "2GAVAaw+KsuXvqsF8soXvlFaHe9sTHKXKUD/MN4WWPR3SIvC4yoadlUpCMfooXf8\n"
   11.43 +        "ZCFLbVirkqGy5AakF7thlaTq7bxEX5BQbP/DjVuTTd311jk4x7oT+1bT7D6iIoES\n"
   11.44 +        "DKfYijw+059CrCbjFUn3/RRg5sx/55FA2XEAEQEAAQAIHiu228SYwSeGGM2cLUt1\n"
   11.45 +        "vBxKeYDnmeb2aJFfUnia/E3NZ7f4/0fUo9qkv9th0l1asMLsU1bG/I6NcR5u3sYE\n"
   11.46 +        "iham0IIxHTdY6QluHzwN573TB8OqoLQDo2D/ATf95PhDcsWvUKIomU1ojhG3Wy+3\n"
   11.47 +        "TzIseD97O9hWhjnsaRxr1QDclghnNffz589T40wAQAkdQlfDuBABberGNR0DsCZq\n"
   11.48 +        "w1xx1+EaEt8o7sXfRMFKoBLJzya0toJNIBGdXCXVPFPtYx6RAiD1KoufgXwVCBaL\n"
   11.49 +        "CHc8QvurgyMBghc9pBcdGs60fNhWn1U4qeWzPOHO95ZWVFObBiuGqkX25revf1Dg\n"
   11.50 +        "RTY5OsBTBBDdnMElWA+l6ctlSX8vNUQBin7aPbHu1HrmUxH9EiKwUd6jdoFmssw7\n"
   11.51 +        "soohAfYJCsuTQLHPI+9W6okF4rjlvl0aS2cN4HSbLjTwdNiUgIHVKJPDq8WDgCsV\n"
   11.52 +        "bR09wsLkohmoX/qZFEQMKdr7A2ar64zQzpx6ZFB0kS71Fr6+rFUAIzePBBDg8QXr\n"
   11.53 +        "J/R6iZYnMNv/mzyNunbM3B7siwbILS1kLeS6lTYeaKORa7JFRc776rkWV//P1Soc\n"
   11.54 +        "nW2byeBxNxOmdNXlNsA6Gg8O4rn3rxEgBZlsOYUG1ZcPZZu8kNFkLTYP+mgFIP3I\n"
   11.55 +        "izn858IbnNFm0HjRMGiS+zip2r/rgbniIhLQ2l7/BBCL+2x0+Ww5I/el6A7k+y2X\n"
   11.56 +        "3xazBVOQfpPl9BgMdsuO0BBlN5RpbTfE8TVpWneeamAuRJh7ArApbAS508Thw7Sj\n"
   11.57 +        "8iLKXj5yScAEC2WO9ZsHqJ/RN3VyhCCI0u3Y75wB3qfcroZUlwvQb/WfH8/vHr2O\n"
   11.58 +        "E72YoprbNOmRFZ7LZkRX56URRn2JASMEGAEIAAkFAlpCxkECGwwACgkQr2Mun8eZ\n"
   11.59 +        "t9RozQggkb/Lb08g4w99CcXq6hV28D5bOHjiEx4XNdkeLVExhfk1zgQ9lf4rjyb2\n"
   11.60 +        "ox+e3Dc5S590NoYg/35vd/QWPsg1JiCvAu296lzOLtIiTAI1KGUJdbsLxRIduOU7\n"
   11.61 +        "6n/KVxRG4w4kJqpbu+UzBY7KtDbWzapJx8v0sdsTOVxg7kFxvYtra5TRaPfce4EX\n"
   11.62 +        "ox2V2HPhtFNSILH8Jqh/R0PV5RRbNFHZA4cKXkBJMw3BcpbpXeLCXiD6P3FNVSKh\n"
   11.63 +        "Rkd3JY0XJhwbvGPCRWkobtxkieZe0bCmKu8+gw0Zqm2QNA7J6iMT4rMZWH9k7lpp\n"
   11.64 +        "okyt7GheXlwKEtVQSAcH/NalK9Q+ckaQttA=\n"
   11.65 +        "=KACn\n"
   11.66 +        "-----END PGP PRIVATE KEY BLOCK-----\n"
   11.67 +        "\n";
   11.68 +
   11.69 +    static const std::string mimetext =
   11.70 +        "To: denden@peptest.ch\r\n"
   11.71 +        "From: Lars Rohwedder <roker@pep-project.org>\r\n"
   11.72 +        "Subject: Test for ENGINE-322\r\n"
   11.73 +        "Message-ID: <4b2d328c-b284-e359-1c2c-fe136358b8a6@pep-project.org>\r\n"
   11.74 +        "Date: Thu, 28 Dec 2017 22:00:47 +0100\r\n"
   11.75 +        "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:52.0)\r\n"
   11.76 +        " Gecko/20100101 Thunderbird/52.5.0\r\n"
   11.77 +        "MIME-Version: 1.0\r\n"
   11.78 +        "Content-Type: text/plain; charset=utf-8\r\n"
   11.79 +        "Content-Language: en-US\r\n"
   11.80 +        "Content-Transfer-Encoding: 8bit\r\n"
   11.81 +        "\r\n"
   11.82 +        "-----BEGIN PGP MESSAGE-----\r\n"
   11.83 +        "Charset: utf-8\r\n"
   11.84 +        "\r\n"
   11.85 +        "hQEQA30SSxlFRbxRAQgggvPrko4vJ988ylqdGF7/Jtw/61VddHg7rjOTG7yZiq2J\r\n"
   11.86 +        "p0lXb0N9Bz8SON/m4NWWS5ij0Bj1wMdTgLowLxMz0PfCIyyiQIfqEBAXUcAOQh2f\r\n"
   11.87 +        "Pg2iZbynrQ1T4M/D0BlIn2bfXb790Cni+o1OmWTCx4wC6AKtGvlonLAIsH1hUfs+\r\n"
   11.88 +        "yKOyCCNaNSmyAPeF3F5v7iEO5Eez1R/UrtxcYj2QmCdVt5v0AuAlm5HVPJgj7wCd\r\n"
   11.89 +        "MeRmK4a1+sM51CcCf6Tk9uZbIVrr/XkyGVPmmHTK8E4QmvmL6PGeuIitwqKe80/L\r\n"
   11.90 +        "XH4ZYPXIxVU9o5HoSo3YJ3BSKLQzCoDRCD8JlCo08K6mrpuFAgwD42RJLbKIaR4B\r\n"
   11.91 +        "EADNgisKiIku4SrBmBkryyKMYmOTW0QKnY/wfNselpzuj5cMpKA4e60x/wEQRIvC\r\n"
   11.92 +        "m1ZO7LjhbVjNf6ws2FgytnTRf+8R/R8mp6/XIDeUvaBvUku5yoRjTeznFRwpj6yT\r\n"
   11.93 +        "WfQMlLojI2fe+y5fHKIIjTpW5HOQQv7sZ4UzE+jRpRErRVq4UI49l7yTBnG0j75w\r\n"
   11.94 +        "UZTt05OnJMQrCCiD7Fu9xDw5If3x884GehKpFGm6XqZ8V7NhwGk6mf62rZEouBQh\r\n"
   11.95 +        "AhTu/irkz30PpWY3gGj2YF0PIaQmweb9u2izox1kTfq2xRfPLg/4cOgBKy1/Xeea\r\n"
   11.96 +        "IVeaACAcoNdJaYuZCSe9CMbr5s7kusE22/6fB0L1itGr09EzhwGJS/+XSt0IwcJw\r\n"
   11.97 +        "7XDUGtmYXuTy08wUKU9McxXJ8nlUkXF9ZcswVxHKG36ZRfzx5eBPjzSnDo8EZHs2\r\n"
   11.98 +        "wr7wnS8s8J+AvB7kZYFChAct4KH9OwT3/2pSdhd8/sSCkj2zGtrB+8h2QkIE4csD\r\n"
   11.99 +        "rIHtBp4oWCJq1XOKYPvdGqWBxZ/7086kksB99Eyn+sy5C0iNTbEdUN4JkIYq1C0n\r\n"
  11.100 +        "DExbr+dqip65DEJRj7TPfwTJ5D28djPYutanSRfJS/niPqztWu0R1ISucw1TMdGU\r\n"
  11.101 +        "NcqsqQLPYzTV6xTq+bgBsi8DO4tXkcOpf7eDEP+5kDOncNLpAZGc9NUnVa/jpkYO\r\n"
  11.102 +        "XE+CNJ5SYQPdsGcir9JNXNTDgKAGSTI7OAU/ZxOcMCsmctJATcAZERFgvUy8YZN1\r\n"
  11.103 +        "3X4Ii6osc8u6shJrjL/detZs8LH8wSe6NYQdtipQo4ySAYQAO9tXdoRrfktXrYus\r\n"
  11.104 +        "eLh86toD19D5R9RxHnVEMQP5CdNWgvX7X4ngK94kJq18QCDa1bZXhHBKmWOnAtyL\r\n"
  11.105 +        "zpcUNnCWo2gml6GX2kyuL+5Ji6afwKHZg+iag8wBDLGQ+hoOMnzk1iP4DFeQ7iZN\r\n"
  11.106 +        "Qvd4mWWASd2BCnf9ulKiMw1wdzN2mpYRNo+nRHx0Zu50VUyj0xMm8VSyUZis5+YH\r\n"
  11.107 +        "I3Se7UEeS6ppLsiGcyaJDCMp/38xt5SU5NY4wAAubc6MJclECcvSkM1W/20wQ4di\r\n"
  11.108 +        "z5FhKHlqZaPTXN02h0P78wKDDwJr7fFvqtB8G2LgtwbXAkOUvn8vbomQLHBkQ+GH\r\n"
  11.109 +        "AuXqBGxKrIwyIEjLZf6hDz++0fDa/ACeFynpxNl1ehmvCl5CsEMcCiM+Ic2pZ/ML\r\n"
  11.110 +        "+Hle0GWEKej4WBzXi0j4pzR4WZFt9XCv5+yYAg+UHKc2Kn0Q+bC1AZYxhQDicTP9\r\n"
  11.111 +        "qNKTLBHRAeJoQ1y4vHXYGwRGH+penfJiKsQsyOOeoQlZar8tvRYR77K8FhxBtnYK\r\n"
  11.112 +        "Xrv+rb1BT/2Ey7P4jb8PiZpbic7ACu1MjFdmlPKrExe5+MY+Pr9ms+hxJrdBH736\r\n"
  11.113 +        "K6dojmWUQKpJRzue2lWsfESLxIVeB+vmbg2zU3PflCmMIsRNh2US7vZj2WdgqSqz\r\n"
  11.114 +        "wR2eTG4MgPVy4iiGOVT2JWS5t+KXm3kwUZTy9Twi6P1ebNm/B8KQwlutssdWip2q\r\n"
  11.115 +        "hON1aFYa4L601zrHgow592PdBkRPQZGiXNHffCvHgsxBHsj4G4JWZhmIkEK/cIWl\r\n"
  11.116 +        "RanlZdQG6UPHkoUomh7hauUUgcYe4FWt4NBKdiba36Y=\r\n"
  11.117 +        "=1lFj\r\n"
  11.118 +        "-----END PGP MESSAGE-----\r\n"
  11.119 +        "\r\n";
  11.120 +
  11.121 +	PEP_SESSION session;
  11.122 +	PEP_STATUS status1 = init(&session);
  11.123 +	assert(status1 == PEP_STATUS_OK);
  11.124 +	assert(session);
  11.125 +
  11.126 +	// import secret key
  11.127 +	identity_list* pk = NULL; 
  11.128 +	status1 = import_key( session, private_key.c_str(), private_key.size(), &pk );
  11.129 +	assert(status1 == PEP_STATUS_OK);
  11.130 +	std::cout << "Imported " << identity_list_length(pk) << " private key(s)." << endl;
  11.131 +	
  11.132 +	char* plaintext = nullptr;
  11.133 +	stringlist_t* keys_used = nullptr;
  11.134 +	PEP_rating rating;
  11.135 +	PEP_decrypt_flags_t dec_flags;
  11.136 +	
  11.137 +	PEP_STATUS status2 = MIME_decrypt_message(session, mimetext.c_str(), mimetext.length(),
  11.138 +		&plaintext, &keys_used, &rating, &dec_flags);
  11.139 +	
  11.140 +	std::cout << "MIME_decrypt_message returned " << std::dec << status2 << std::hex << " (0x" << status2 << ")" << std::dec << endl;
  11.141 +	
  11.142 +	assert(status2 == PEP_DECRYPTED);
  11.143 +	assert(plaintext);
  11.144 +	
  11.145 +	pEp_free(plaintext);
  11.146 +	
  11.147 +	identity_list* il = pk;
  11.148 +	while(il)
  11.149 +	{
  11.150 +		std::cout << "Delete test key \"" << il->ident->fpr << "\"" << endl;
  11.151 +		delete_keypair( session, il->ident->fpr );
  11.152 +		il = il->next;
  11.153 +	}
  11.154 +	free_identity_list(pk);
  11.155 +}
  11.156 +
  11.157 +
  11.158  int main() {
  11.159      cout << "\n*** message_api_test ***\n\n";
  11.160 +    test_MIME_decrypt_message();
  11.161  
  11.162      PEP_SESSION session;
  11.163      
  11.164 @@ -169,14 +321,35 @@
  11.165      
  11.166      cout << dec_msg << endl;
  11.167      
  11.168 +    cout << "\nTesting encrypt_message() with enc_format = PEP_enc_none\n\n";
  11.169 +
  11.170 +    message *msg7 = new_message(PEP_dir_outgoing);
  11.171 +    pEp_identity * me7 = new_identity("pep.test.alice@pep-project.org", NULL, PEP_OWN_USERID, "Alice Test");
  11.172 +    identity_list *to7 = new_identity_list(new_identity("pep.test.bob@pep-project.org", NULL, "42", "Bob Test"));
  11.173 +    msg7->from = me7;
  11.174 +    msg7->to = to7;
  11.175 +    msg7->shortmsg = strdup("My Subject");
  11.176 +    msg7->longmsg = strdup("This is some text.\n");
  11.177 +
  11.178 +    message *enc7 = nullptr;
  11.179 +    PEP_STATUS status9 = encrypt_message(session, msg7, NULL, &enc7, PEP_enc_none, 0);
  11.180 +	std::cout << "encrypt_message returned " << std::dec << status9 << std::hex << " (0x" << status9 << ")" << std::dec << endl;
  11.181 +    assert(status9 == PEP_UNENCRYPTED);
  11.182 +    assert(enc7 == nullptr);
  11.183 +    assert(msg7->shortmsg && msg7->longmsg);
  11.184 +    cout << msg7->shortmsg << "\n";
  11.185 +    cout << msg7->longmsg << "\n";
  11.186 +    assert(strcmp(msg7->shortmsg, "My Subject") == 0);
  11.187 +    assert(strcmp(msg7->longmsg, "This is some text.\n") == 0);
  11.188      
  11.189 -    cout << "freeing messages…\n";
  11.190 +    cout << "\nfreeing messages…\n";
  11.191 +    free_message(msg7);
  11.192 +    free_message(msg6);
  11.193 +    free_message(msg5);
  11.194      free_message(msg4);
  11.195      free_message(msg3);
  11.196      free_message(msg2);
  11.197      free_message(enc_msg2);
  11.198 -    free_message(msg6);
  11.199 -    free_message(msg5);
  11.200      cout << "done.\n";
  11.201  
  11.202      free(enc_msg);
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/test/python_tests/README.md	Mon Jan 15 17:07:05 2018 +0100
    12.3 @@ -0,0 +1,16 @@
    12.4 +# Usage
    12.5 +
    12.6 +To execute these tests, install p≡p Python adapter from
    12.7 +<https://letsencrypt.pep.foundation/dev/repos/pEpPythonAdapter/>
    12.8 +
    12.9 +These tests are meant to be run using py.test <https://pytest.org> and
   12.10 +pytest-xdist <https://pypi.python.org/pypi/pytest-xdist>
   12.11 +
   12.12 +You can run setup_test.py before running the tests if the initial setup is
   12.13 +failing.
   12.14 +
   12.15 +To remove all generated files run setup_test.py -r
   12.16 +
   12.17 +# License
   12.18 +
   12.19 +All documentation is under CC BY-SA 3.0.
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/test/python_tests/conftest.py	Mon Jan 15 17:07:05 2018 +0100
    13.3 @@ -0,0 +1,14 @@
    13.4 +# -*- coding: utf-8 -*-
    13.5 +
    13.6 +# this file is under GNU General Public License 3.0
    13.7 +# Copyleft 2017, p≡p foundation
    13.8 +
    13.9 +
   13.10 +from setup_test import create_homes
   13.11 +
   13.12 +
   13.13 +def pytest_runtest_setup(item):
   13.14 +    try:
   13.15 +        create_homes()
   13.16 +    except FileExistsError: # if concurrent process is already creating things
   13.17 +        pass
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/test/python_tests/pytest.ini	Mon Jan 15 17:07:05 2018 +0100
    14.3 @@ -0,0 +1,10 @@
    14.4 +# --boxed   run each test in an own process
    14.5 +# -v        verbose output
    14.6 +# -n 2      two parallel tasks
    14.7 +
    14.8 +# this file is under GNU General Public License 3.0
    14.9 +# Copyleft 2017, p≡p foundation
   14.10 +
   14.11 +[pytest]
   14.12 +addopts = --boxed -v -n 2 test_handshake.py
   14.13 +
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/test/python_tests/setup_test.py	Mon Jan 15 17:07:05 2018 +0100
    15.3 @@ -0,0 +1,126 @@
    15.4 +#!/usr/bin/env python3
    15.5 +# -*- coding: utf-8 -*-
    15.6 +
    15.7 +# this file is under GNU General Public License 3.0
    15.8 +# Copyleft 2017, p≡p foundation
    15.9 +
   15.10 +#import vimpdb; vimpdb.set_trace()
   15.11 +
   15.12 +
   15.13 +"""
   15.14 +This script is setting up the test environment by creating two home directories
   15.15 +for simulation of message exchange between two p≡p parties.
   15.16 +
   15.17 +The directories are created in the current directory.
   15.18 +"""
   15.19 +
   15.20 +
   15.21 +import os
   15.22 +import shutil
   15.23 +from multiprocessing import Process
   15.24 +from time import sleep
   15.25 +
   15.26 +
   15.27 +realhome = os.path.expanduser("~")
   15.28 +mydir = os.path.abspath(os.path.curdir)
   15.29 +
   15.30 +
   15.31 +def link_if_exists(dirname, arthome):
   15.32 +    "link directory from home to artificial home"
   15.33 +
   15.34 +    orig = os.path.join(realhome, dirname)
   15.35 +    if os.path.exists(orig):
   15.36 +        if not os.path.exists(dirname):
   15.37 +            os.symlink(orig, dirname, True)
   15.38 +
   15.39 +
   15.40 +def create_own_identities(mydir, arthome, username):
   15.41 +    "create own identities as part of the test setup"
   15.42 +
   15.43 +    os.environ["HOME"] = os.path.join(mydir, arthome)
   15.44 +    os.environ["GNUPGHOME"] = os.path.join(mydir, arthome, '.gnupg')
   15.45 +
   15.46 +    import pEp
   15.47 +    me = pEp.Identity()
   15.48 +    me.address = arthome + "@peptest.ch"
   15.49 +    me.username = username
   15.50 +
   15.51 +    pEp.myself(me)
   15.52 +    print(repr(me))
   15.53 +
   15.54 +
   15.55 +def link_file(filename):
   15.56 +    "sym-link file to version in parent directory"
   15.57 +
   15.58 +    src = os.path.join(os.pardir, filename)
   15.59 +    if not os.path.exists(filename):
   15.60 +        os.symlink(src, filename, False)
   15.61 +
   15.62 +
   15.63 +def create_home(mydir, arthome, username):
   15.64 +    "create an artificial home directory for testing"
   15.65 +
   15.66 +    os.chdir(mydir)
   15.67 +    os.makedirs(arthome, exist_ok=True)
   15.68 +
   15.69 +    os.chdir(arthome)
   15.70 +
   15.71 +    link_if_exists("bin", arthome)
   15.72 +    link_if_exists("include", arthome)
   15.73 +    link_if_exists("lib", arthome)
   15.74 +    link_if_exists("share", arthome)
   15.75 +    link_if_exists(".local", arthome)
   15.76 +    link_if_exists("Library", arthome) # this may exist on macOS
   15.77 +
   15.78 +    p = Process(target=create_own_identities, args=(mydir, arthome, username))
   15.79 +    p.start()
   15.80 +    p.join()
   15.81 +
   15.82 +    with open(".ready", "w"): pass
   15.83 +
   15.84 +
   15.85 +def create_homes():
   15.86 +    "create two artificial home directories for the two parties"
   15.87 +
   15.88 +    try:
   15.89 +        os.stat("test1")
   15.90 +    except FileNotFoundError:
   15.91 +        create_home(mydir, "test1", "Alice One")
   15.92 +        create_home(mydir, "test2", "Bob Two")
   15.93 +        os.chdir(mydir);
   15.94 +        os.makedirs("common", exist_ok=True) # common inbox for Sync tests
   15.95 +    else:
   15.96 +        while True:
   15.97 +            try:
   15.98 +                os.stat("test2/.ready")
   15.99 +            except:
  15.100 +                sleep(1)
  15.101 +            else:
  15.102 +                break
  15.103 +
  15.104 +
  15.105 +def remove_homes():
  15.106 +    """remove formerly created artificial home directories including their
  15.107 +    contents"""
  15.108 +
  15.109 +    os.chdir(mydir)
  15.110 +    shutil.rmtree("test1", ignore_errors=True)
  15.111 +    shutil.rmtree("test2", ignore_errors=True)
  15.112 +    shutil.rmtree("common", ignore_errors=True)
  15.113 +    shutil.rmtree("__pycache__", ignore_errors=True)
  15.114 +
  15.115 +
  15.116 +if __name__ == "__main__":
  15.117 +    import argparse
  15.118 +
  15.119 +    parser = argparse.ArgumentParser(description=__doc__)
  15.120 +    parser.add_argument('-r', '--remove', action="store_true",
  15.121 +            help=remove_homes.__doc__)
  15.122 +
  15.123 +    args = parser.parse_args()
  15.124 +
  15.125 +    if args.remove:
  15.126 +        remove_homes()
  15.127 +    else:
  15.128 +        create_homes()
  15.129 +
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/test/python_tests/test_handshake.py	Mon Jan 15 17:07:05 2018 +0100
    16.3 @@ -0,0 +1,127 @@
    16.4 +# -*- coding: utf-8 -*-
    16.5 +
    16.6 +# this file is under GNU General Public License 3.0
    16.7 +# Copyleft 2017, p≡p foundation
    16.8 +
    16.9 +
   16.10 +from transport import *
   16.11 +
   16.12 +
   16.13 +def setup_gnupg():
   16.14 +    assert os.environ["GNUPGHOME"] != ""
   16.15 +
   16.16 +
   16.17 +mydir = os.path.dirname(os.path.realpath(__file__))
   16.18 +
   16.19 +
   16.20 +class Test1:
   16.21 +
   16.22 +    def setup_method(self):
   16.23 +        arthome = "test1"
   16.24 +
   16.25 +        os.environ["HOME"] = os.path.join(mydir, arthome)
   16.26 +        os.environ["GNUPGHOME"] = os.path.join(mydir, arthome, '.gnupg')
   16.27 +
   16.28 +        os.chdir(os.path.join(mydir, arthome))
   16.29 +
   16.30 +    @property
   16.31 +    def me(self):
   16.32 +        # because of flaws of py.test these two statements are necessary
   16.33 +        setup_gnupg()   # work around a bug with initializing os.environ
   16.34 +        import pEp      # after that import pEp module, not before
   16.35 +
   16.36 +        i = pEp.Identity()
   16.37 +        i.address = "test1@peptest.ch"
   16.38 +        i.username = "Alice One"
   16.39 +        i.myself()
   16.40 +        return i
   16.41 +
   16.42 +    @property
   16.43 +    def you(self):
   16.44 +        setup_gnupg() ; import pEp
   16.45 +
   16.46 +        i = pEp.Identity()
   16.47 +        i.address = "test2@peptest.ch"
   16.48 +        i.username = "Bob Two"
   16.49 +        i.update()
   16.50 +        return i
   16.51 +
   16.52 +    def test_handshake(self):
   16.53 +        setup_gnupg() ; import pEp
   16.54 +
   16.55 +        msg = pEp.Message(1)
   16.56 +        msg.from_ = self.me
   16.57 +        msg.to = [self.you]
   16.58 +        msg.shortmsg = "Subject line"
   16.59 +        msg.longmsg = "Message Text\n"
   16.60 +
   16.61 +        enc = msg.encrypt()
   16.62 +        send_message("test2", str(enc))
   16.63 +
   16.64 +        txt = wait_for_message()
   16.65 +        enc = pEp.Message(txt)
   16.66 +        assert enc.from_.address == "test2@peptest.ch"
   16.67 +        inc, keys, rating, consumed, flags = enc.decrypt()
   16.68 +        assert rating == 6
   16.69 +
   16.70 +        msg = pEp.Message(1)
   16.71 +        msg.from_ = self.me
   16.72 +        msg.to = [self.you]
   16.73 +        msg.shortmsg = "Subject line complete"
   16.74 +        msg.longmsg = "Message Text complete\n"
   16.75 +
   16.76 +        enc = msg.encrypt()
   16.77 +        send_message("test2", str(enc))
   16.78 +
   16.79 +class Test2:
   16.80 +
   16.81 +    def setup_method(self):
   16.82 +        arthome = "test2"
   16.83 +
   16.84 +        os.environ["HOME"] = os.path.join(mydir, arthome)
   16.85 +        os.environ["GNUPGHOME"] = os.path.join(mydir, arthome, '.gnupg')
   16.86 +
   16.87 +        os.chdir(os.path.join(mydir, arthome))
   16.88 +
   16.89 +    @property
   16.90 +    def me(self):
   16.91 +        setup_gnupg() ; import pEp
   16.92 +
   16.93 +        i = pEp.Identity()
   16.94 +        i.address = "test2@peptest.ch"
   16.95 +        i.username = "Bob Two"
   16.96 +        i.myself()
   16.97 +        return i
   16.98 +
   16.99 +    @property
  16.100 +    def you(self):
  16.101 +        setup_gnupg() ; import pEp
  16.102 +
  16.103 +        i = pEp.Identity()
  16.104 +        i.address = "test1@peptest.ch"
  16.105 +        i.username = "Alice One"
  16.106 +        i.update()
  16.107 +        return i
  16.108 +
  16.109 +    def test_handshake(self):
  16.110 +        setup_gnupg() ; import pEp
  16.111 +
  16.112 +        txt = wait_for_message()
  16.113 +        msg = pEp.Message(txt)
  16.114 +        msg.decrypt()
  16.115 +        assert msg.from_.address == self.you.address
  16.116 +
  16.117 +        out = pEp.Message(1)
  16.118 +        out.from_ = self.me
  16.119 +        out.to = [self.you]
  16.120 +        out.shortmsg = "Subject Back"
  16.121 +        out.longmsg = "Text Back\n"
  16.122 +
  16.123 +        enc = out.encrypt()
  16.124 +        send_message("test1", str(enc))
  16.125 +
  16.126 +        txt = wait_for_message()
  16.127 +        msg = pEp.Message(txt)
  16.128 +        msg.decrypt()
  16.129 +        assert msg.from_.address == self.you.address
  16.130 +
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/test/python_tests/transport.py	Mon Jan 15 17:07:05 2018 +0100
    17.3 @@ -0,0 +1,70 @@
    17.4 +# -*- coding: utf-8 -*-
    17.5 +
    17.6 +# this file is under GNU General Public License 3.0
    17.7 +# Copyleft 2017, p≡p foundation
    17.8 +
    17.9 +
   17.10 +"""
   17.11 +This module is implementing a basic message transport. Messages are written
   17.12 +into the artificial home of the receiver and deleted when read.
   17.13 +"""
   17.14 +
   17.15 +
   17.16 +import os
   17.17 +import time
   17.18 +from glob import glob
   17.19 +
   17.20 +
   17.21 +timeout = 5
   17.22 +
   17.23 +
   17.24 +def send_message(to, msg):
   17.25 +    "send message by creating a file in recipient's artificial home"
   17.26 +
   17.27 +    recipient_dir = os.path.join(os.pardir, to)
   17.28 +    filename = '{:024x}'.format(int(time.monotonic() * 10000000000)) + \
   17.29 +            os.extsep + "eml"
   17.30 +    dotpath = os.path.join(recipient_dir, "." + filename)
   17.31 +    path = os.path.join(recipient_dir, filename)
   17.32 +
   17.33 +    with open(dotpath, "w") as file:
   17.34 +        file.write(msg)
   17.35 +    
   17.36 +    os.rename(dotpath, path)
   17.37 +
   17.38 +
   17.39 +def recv_message(inbox=None):
   17.40 +    """receive message by returning the first .eml files content in artificial
   17.41 +    home"""
   17.42 +
   17.43 +    if inbox:
   17.44 +        filename = glob(os.path.join(os.pardir, inbox, "*.eml"))[0]
   17.45 +    else:
   17.46 +        filename = glob("*.eml")[0]
   17.47 +
   17.48 +    with open(filename, "r") as file:
   17.49 +        msg = file.read()
   17.50 +
   17.51 +    os.remove(filename)
   17.52 +
   17.53 +    return msg
   17.54 +
   17.55 +
   17.56 +def wait_for_message():
   17.57 +    "wait until a message arrives and return the message"
   17.58 +
   17.59 +    found = False
   17.60 +    for i in range(timeout):
   17.61 +        try:
   17.62 +            msg = recv_message()
   17.63 +        except IndexError:
   17.64 +            time.sleep(1)
   17.65 +        else:
   17.66 +            found = True
   17.67 +            break
   17.68 +
   17.69 +    if not found:
   17.70 +        raise RuntimeError("timeout")
   17.71 +
   17.72 +    return msg
   17.73 +