IOSAD-92 merge into default
authorDirk Zimmermann <dirk@pep-project.org>
Thu, 03 May 2018 15:49:46 +0200
changeset 6041af0cfd35a84
parent 602 9a560dd0fd0c
parent 603 9b4e42283f66
child 605 0c6fc87450e5
IOSAD-92 merge into default
     1.1 --- a/pEpObjCAdapter.xcodeproj/project.pbxproj	Thu Apr 26 09:37:05 2018 +0200
     1.2 +++ b/pEpObjCAdapter.xcodeproj/project.pbxproj	Thu May 03 15:49:46 2018 +0200
     1.3 @@ -35,6 +35,8 @@
     1.4  		435665CC2080A6CB00EC5B10 /* NSNumber+PEPRating.m in Sources */ = {isa = PBXBuildFile; fileRef = 435665CB2080A6CB00EC5B10 /* NSNumber+PEPRating.m */; };
     1.5  		435796E31FB5E51A00395A9E /* PEPMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 435796E21FB5E51A00395A9E /* PEPMessage.m */; };
     1.6  		43676B661C57EA1A00233933 /* B623F674_sec.asc in Resources */ = {isa = PBXBuildFile; fileRef = 43676B641C57EA1A00233933 /* B623F674_sec.asc */; };
     1.7 +		439393E6208F375800EB1DBD /* NSObject+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 439393E5208F375800EB1DBD /* NSObject+Extension.m */; };
     1.8 +		439393F8208F5B5E00EB1DBD /* NSMutableDictionary+PEP.m in Sources */ = {isa = PBXBuildFile; fileRef = 439393F7208F5B5E00EB1DBD /* NSMutableDictionary+PEP.m */; };
     1.9  		439D91A5208479EE003F6AC2 /* PEPAttachment.m in Sources */ = {isa = PBXBuildFile; fileRef = 439D91A4208479EE003F6AC2 /* PEPAttachment.m */; };
    1.10  		43D27DE61F5DA7B700795687 /* NSDictionary+Extension.m in Sources */ = {isa = PBXBuildFile; fileRef = 43D27DE51F5DA7B700795687 /* NSDictionary+Extension.m */; };
    1.11  		43DED786203C25E200D45CD6 /* NSError+PEP.m in Sources */ = {isa = PBXBuildFile; fileRef = 43DED785203C25E200D45CD6 /* NSError+PEP.m */; };
    1.12 @@ -167,6 +169,10 @@
    1.13  		435796E21FB5E51A00395A9E /* PEPMessage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PEPMessage.m; sourceTree = "<group>"; };
    1.14  		43676B631C57EA1A00233933 /* 0xB623F674.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = 0xB623F674.asc; sourceTree = "<group>"; };
    1.15  		43676B641C57EA1A00233933 /* B623F674_sec.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = B623F674_sec.asc; sourceTree = "<group>"; };
    1.16 +		439393E4208F375800EB1DBD /* NSObject+Extension.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSObject+Extension.h"; sourceTree = "<group>"; };
    1.17 +		439393E5208F375800EB1DBD /* NSObject+Extension.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSObject+Extension.m"; sourceTree = "<group>"; };
    1.18 +		439393F6208F5B5E00EB1DBD /* NSMutableDictionary+PEP.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSMutableDictionary+PEP.h"; sourceTree = "<group>"; };
    1.19 +		439393F7208F5B5E00EB1DBD /* NSMutableDictionary+PEP.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSMutableDictionary+PEP.m"; sourceTree = "<group>"; };
    1.20  		439D91A3208479EE003F6AC2 /* PEPAttachment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PEPAttachment.h; sourceTree = "<group>"; };
    1.21  		439D91A4208479EE003F6AC2 /* PEPAttachment.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PEPAttachment.m; sourceTree = "<group>"; };
    1.22  		43D27DE41F5DA78700795687 /* NSDictionary+Extension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+Extension.h"; sourceTree = "<group>"; };
    1.23 @@ -315,6 +321,10 @@
    1.24  				434ED6D5207E27B8000A7590 /* PEPAutoPointer.m */,
    1.25  				435665CA2080A6CB00EC5B10 /* NSNumber+PEPRating.h */,
    1.26  				435665CB2080A6CB00EC5B10 /* NSNumber+PEPRating.m */,
    1.27 +				439393E4208F375800EB1DBD /* NSObject+Extension.h */,
    1.28 +				439393E5208F375800EB1DBD /* NSObject+Extension.m */,
    1.29 +				439393F6208F5B5E00EB1DBD /* NSMutableDictionary+PEP.h */,
    1.30 +				439393F7208F5B5E00EB1DBD /* NSMutableDictionary+PEP.m */,
    1.31  			);
    1.32  			path = pEpObjCAdapter;
    1.33  			sourceTree = "<group>";
    1.34 @@ -489,11 +499,13 @@
    1.35  				43209B3F1ECC2DB0007E7E2E /* PEPLanguage.m in Sources */,
    1.36  				434ED6D6207E27B8000A7590 /* PEPAutoPointer.m in Sources */,
    1.37  				439D91A5208479EE003F6AC2 /* PEPAttachment.m in Sources */,
    1.38 +				439393E6208F375800EB1DBD /* NSObject+Extension.m in Sources */,
    1.39  				43209B401ECC2DB4007E7E2E /* PEPMessageUtil.m in Sources */,
    1.40  				43209B3D1ECC2DA7007E7E2E /* NSArray+Extension.m in Sources */,
    1.41  				43209B3E1ECC2DAB007E7E2E /* PEPCSVScanner.m in Sources */,
    1.42  				43209B421ECC2DBC007E7E2E /* PEPQueue.m in Sources */,
    1.43  				435665CC2080A6CB00EC5B10 /* NSNumber+PEPRating.m in Sources */,
    1.44 +				439393F8208F5B5E00EB1DBD /* NSMutableDictionary+PEP.m in Sources */,
    1.45  				15206CC71F8E078B003FF880 /* PEPSession.m in Sources */,
    1.46  			);
    1.47  			runOnlyForDeploymentPostprocessing = 0;
     2.1 --- a/pEpObjCAdapter/NSError+PEP.m	Thu Apr 26 09:37:05 2018 +0200
     2.2 +++ b/pEpObjCAdapter/NSError+PEP.m	Thu May 03 15:49:46 2018 +0200
     2.3 @@ -135,6 +135,7 @@
     2.4          case PEP_OUT_OF_MEMORY: return @"PEP_OUT_OF_MEMORY";
     2.5          case PEP_UNKNOWN_ERROR: return @"PEP_UNKNOWN_ERROR";
     2.6          case PEP_VERSION_MISMATCH: return @"PEP_VERSION_MISMATCH";
     2.7 +        case PEP_CANNOT_REENCRYPT: return @"PEP_CANNOT_REENCRYPT";
     2.8      }
     2.9  }
    2.10  
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/pEpObjCAdapter/NSMutableDictionary+PEP.h	Thu May 03 15:49:46 2018 +0200
     3.3 @@ -0,0 +1,22 @@
     3.4 +//
     3.5 +//  NSMutableDictionary+PEP.h
     3.6 +//  pEpObjCAdapter
     3.7 +//
     3.8 +//  Created by Dirk Zimmermann on 24.04.18.
     3.9 +//  Copyright © 2018 p≡p. All rights reserved.
    3.10 +//
    3.11 +
    3.12 +#import <Foundation/Foundation.h>
    3.13 +
    3.14 +#import "message.h"
    3.15 +
    3.16 +void replaceDictionaryContentsWithMessage(NSMutableDictionary *dict, message *message);
    3.17 +
    3.18 +@interface NSMutableDictionary (PEP)
    3.19 +
    3.20 +/**
    3.21 + Replaces all content with `message`.
    3.22 + */
    3.23 +- (void)replaceWithMessage:(message *)message;
    3.24 +
    3.25 +@end
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/pEpObjCAdapter/NSMutableDictionary+PEP.m	Thu May 03 15:49:46 2018 +0200
     4.3 @@ -0,0 +1,103 @@
     4.4 +//
     4.5 +//  NSMutableDictionary+PEP.m
     4.6 +//  pEpObjCAdapter
     4.7 +//
     4.8 +//  Created by Dirk Zimmermann on 24.04.18.
     4.9 +//  Copyright © 2018 p≡p. All rights reserved.
    4.10 +//
    4.11 +
    4.12 +#import "NSMutableDictionary+PEP.h"
    4.13 +
    4.14 +#import "PEPMessageUtil.h"
    4.15 +
    4.16 +void replaceDictionaryContentsWithMessage(NSMutableDictionary *dict, message *message)
    4.17 +{
    4.18 +    [dict removeAllObjects];
    4.19 +    
    4.20 +    [dict setValue:(message->dir == PEP_dir_outgoing) ? @YES : @NO forKey:kPepOutgoing];
    4.21 +    
    4.22 +    if (message->id) {
    4.23 +        [dict setValue:[NSString stringWithUTF8String:message->id] forKey:kPepID];
    4.24 +    }
    4.25 +    
    4.26 +    if (message->shortmsg) {
    4.27 +        [dict setValue:[NSString stringWithUTF8String:message->shortmsg] forKey:kPepShortMessage];
    4.28 +    }
    4.29 +    
    4.30 +    if (message->sent) {
    4.31 +        [dict setValue:[NSDate dateWithTimeIntervalSince1970:timegm(message->sent)]
    4.32 +                forKey:kPepSent];
    4.33 +    }
    4.34 +    
    4.35 +    if (message->recv) {
    4.36 +        [dict setValue:[NSDate dateWithTimeIntervalSince1970:mktime(message->recv)]
    4.37 +                forKey:kPepReceived];
    4.38 +    }
    4.39 +    
    4.40 +    if (message->from) {
    4.41 +        [dict setValue:PEP_identityFromStruct(message->from) forKey:kPepFrom];
    4.42 +    }
    4.43 +    
    4.44 +    if (message->to && message->to->ident) {
    4.45 +        [dict setValue:PEP_identityArrayFromList(message->to) forKey:kPepTo];
    4.46 +    }
    4.47 +    
    4.48 +    if (message->recv_by) {
    4.49 +        [dict setValue:PEP_identityFromStruct(message->recv_by) forKey:kPepReceivedBy];
    4.50 +    }
    4.51 +    
    4.52 +    if (message->cc && message->cc->ident) {
    4.53 +        [dict setValue:PEP_identityArrayFromList(message->cc) forKey:kPepCC];
    4.54 +    }
    4.55 +    
    4.56 +    if (message->bcc && message->bcc->ident) {
    4.57 +        [dict setValue:PEP_identityArrayFromList(message->bcc) forKey:kPepBCC];
    4.58 +    }
    4.59 +    
    4.60 +    if (message->reply_to && message->reply_to->ident) {
    4.61 +        [dict setValue:PEP_identityArrayFromList(message->reply_to) forKey:kPepReplyTo];
    4.62 +    }
    4.63 +    
    4.64 +    if (message->in_reply_to) {
    4.65 +        [dict setValue:PEP_arrayFromStringlist(message->in_reply_to) forKey:kPepInReplyTo];
    4.66 +    }
    4.67 +    
    4.68 +    if (message->references && message->references->value) {
    4.69 +        [dict setValue:PEP_arrayFromStringlist(message->references) forKey:kPepReferences];
    4.70 +    }
    4.71 +    
    4.72 +    if (message->keywords && message->keywords->value) {
    4.73 +        [dict setValue:PEP_arrayFromStringlist(message->keywords) forKey:kPepKeywords];
    4.74 +    }
    4.75 +    
    4.76 +    if (message->opt_fields) {
    4.77 +        [dict setValue:PEP_arrayFromStringPairlist(message->opt_fields) forKey:kPepOptFields];
    4.78 +    }
    4.79 +    
    4.80 +    if (message->longmsg_formatted) {
    4.81 +        [dict setValue:[NSString stringWithUTF8String:message->longmsg_formatted]
    4.82 +                forKey:kPepLongMessageFormatted];
    4.83 +    }
    4.84 +    
    4.85 +    if (message->longmsg) {
    4.86 +        [dict setValue:[NSString stringWithUTF8String:message->longmsg] forKey:kPepLongMessage];
    4.87 +    }
    4.88 +    
    4.89 +    if (message->attachments && message->attachments->value) {
    4.90 +        [dict setValue: PEP_arrayFromBloblist(message->attachments) forKey:kPepAttachments];
    4.91 +    }
    4.92 +    
    4.93 +    if (message->rawmsg_size > 0 && *message->rawmsg_ref) {
    4.94 +        NSData *data = [NSData dataWithBytes:message->rawmsg_ref length:message->rawmsg_size];
    4.95 +        dict[kPepRawMessage] = data;
    4.96 +    }
    4.97 +}
    4.98 +
    4.99 +@implementation NSMutableDictionary (PEP)
   4.100 +
   4.101 +- (void)replaceWithMessage:(message *)message
   4.102 +{
   4.103 +    replaceDictionaryContentsWithMessage(self, message);
   4.104 +}
   4.105 +
   4.106 +@end
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/pEpObjCAdapter/NSObject+Extension.h	Thu May 03 15:49:46 2018 +0200
     5.3 @@ -0,0 +1,26 @@
     5.4 +//
     5.5 +//  NSObject+Extension.h
     5.6 +//  pEpObjCAdapter
     5.7 +//
     5.8 +//  Created by Dirk Zimmermann on 24.04.18.
     5.9 +//  Copyright © 2018 p≡p. All rights reserved.
    5.10 +//
    5.11 +
    5.12 +#import <Foundation/Foundation.h>
    5.13 +
    5.14 +@interface NSObject (Extension)
    5.15 +
    5.16 +/**
    5.17 + Invokes `[value1 isEqual:value2]` between all value pairs retrieved
    5.18 + from `self` and `other`, based on the list of keys.
    5.19 + @Note `nil` is considered equal to `nil`, in contrast to [NSObject isEqual:].
    5.20 + */
    5.21 +- (BOOL)isEqualToObject:(NSObject * _Nonnull)other
    5.22 +            basedOnKeys:(NSArray<NSString *> * _Nonnull)keys;
    5.23 +
    5.24 +/**
    5.25 + Calculates a hash based on the given `keys`.
    5.26 + */
    5.27 +- (NSUInteger)hashBasedOnKeys:(NSArray<NSString *> * _Nonnull)keys;
    5.28 +
    5.29 +@end
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/pEpObjCAdapter/NSObject+Extension.m	Thu May 03 15:49:46 2018 +0200
     6.3 @@ -0,0 +1,44 @@
     6.4 +//
     6.5 +//  NSObject+Extension.m
     6.6 +//  pEpObjCAdapter
     6.7 +//
     6.8 +//  Created by Dirk Zimmermann on 24.04.18.
     6.9 +//  Copyright © 2018 p≡p. All rights reserved.
    6.10 +//
    6.11 +
    6.12 +#import "NSObject+Extension.h"
    6.13 +
    6.14 +@implementation NSObject (Extension)
    6.15 +
    6.16 +- (BOOL)isEqualToObject:(NSObject * _Nonnull)other
    6.17 +            basedOnKeys:(NSArray<NSString *> * _Nonnull)keys
    6.18 +{
    6.19 +    for (NSString *theKey in keys) {
    6.20 +        NSObject *objSelf = [self valueForKey:theKey];
    6.21 +        NSObject *objOther = [other valueForKey:theKey];
    6.22 +
    6.23 +        if (objSelf == nil && objOther == nil) {
    6.24 +            // considered equal, continue
    6.25 +        } else if (![objSelf isEqual:objOther]) {
    6.26 +            // NSValue, NSArray, NSString all have correctly implemented isEqual, so this works
    6.27 +            return NO;
    6.28 +        }
    6.29 +    }
    6.30 +
    6.31 +    return YES;
    6.32 +}
    6.33 +
    6.34 +- (NSUInteger)hashBasedOnKeys:(NSArray<NSString *> * _Nonnull)keys
    6.35 +{
    6.36 +    NSUInteger prime = 31;
    6.37 +    NSUInteger result = 1;
    6.38 +
    6.39 +    for (NSString *theKey in keys) {
    6.40 +        NSObject *objSelf = [self valueForKey:theKey];
    6.41 +        result = prime * result + objSelf.hash;
    6.42 +    }
    6.43 +
    6.44 +    return result;
    6.45 +}
    6.46 +
    6.47 +@end
     7.1 --- a/pEpObjCAdapter/PEPIdentity.m	Thu Apr 26 09:37:05 2018 +0200
     7.2 +++ b/pEpObjCAdapter/PEPIdentity.m	Thu May 03 15:49:46 2018 +0200
     7.3 @@ -12,6 +12,8 @@
     7.4  #import "PEPMessageUtil.h"
     7.5  #import "PEPSession.h"
     7.6  
     7.7 +#import "NSObject+Extension.h"
     7.8 +
     7.9  @implementation PEPIdentity
    7.10  
    7.11  - (nonnull instancetype)initWithAddress:(NSString * _Nonnull)address
    7.12 @@ -108,19 +110,31 @@
    7.13  
    7.14  // MARK: - Equality
    7.15  
    7.16 -- (BOOL)isEqual:(id)other
    7.17 +/**
    7.18 + The keys that should be used to decide `isEqual` and compute the `hash`.
    7.19 + */
    7.20 +static NSArray *s_keys;
    7.21 +
    7.22 +- (BOOL)isEqualToPEPIdentity:(PEPIdentity * _Nonnull)identity
    7.23  {
    7.24 -    if (other == self) {
    7.25 -        return YES;
    7.26 -    } else {
    7.27 -        PEPIdentity *theOther = (PEPIdentity *) other;
    7.28 -        return [self.address isEqualToString:theOther.address] && self.isOwn == theOther.isOwn;
    7.29 -    }
    7.30 +    return [self isEqualToObject:identity basedOnKeys:s_keys];
    7.31  }
    7.32  
    7.33  - (NSUInteger)hash
    7.34  {
    7.35 -    return self.address.hash;
    7.36 +    return [self hashBasedOnKeys:s_keys];
    7.37 +}
    7.38 +
    7.39 +- (BOOL)isEqual:(id)object
    7.40 +{
    7.41 +    if (object == self) {
    7.42 +        return YES;
    7.43 +    }
    7.44 +    if (!object || ![object isKindOfClass:[self class]]) {
    7.45 +        return NO;
    7.46 +    }
    7.47 +
    7.48 +    return [self isEqualToPEPIdentity:object];
    7.49  }
    7.50  
    7.51  // MARK: - NSKeyValueCoding
    7.52 @@ -258,4 +272,11 @@
    7.53              (long) self.commType, self.language];
    7.54  }
    7.55  
    7.56 +// MARK: - Static Initialization
    7.57 +
    7.58 ++ (void)initialize
    7.59 +{
    7.60 +    s_keys = @[@"address"];
    7.61 +}
    7.62 +
    7.63  @end
     8.1 --- a/pEpObjCAdapter/PEPInternalSession.m	Thu Apr 26 09:37:05 2018 +0200
     8.2 +++ b/pEpObjCAdapter/PEPInternalSession.m	Thu May 03 15:49:46 2018 +0200
     8.3 @@ -19,6 +19,7 @@
     8.4  #import "NSError+PEP.h"
     8.5  #import "PEPAutoPointer.h"
     8.6  #import "NSNumber+PEPRating.h"
     8.7 +#import "NSMutableDictionary+PEP.h"
     8.8  
     8.9  @implementation PEPInternalSession
    8.10  
    8.11 @@ -98,7 +99,15 @@
    8.12  
    8.13  #pragma mark - PEPSessionProtocol
    8.14  
    8.15 -- (PEPDict * _Nullable)decryptMessageDict:(PEPDict * _Nonnull)messageDict
    8.16 +void decryptMessageDictFree(message *src, message *dst, stringlist_t *extraKeys)
    8.17 +{
    8.18 +    free_message(src);
    8.19 +    free_message(dst);
    8.20 +    free_stringlist(extraKeys);
    8.21 +}
    8.22 +
    8.23 +- (PEPDict * _Nullable)decryptMessageDict:(PEPMutableDict * _Nonnull)messageDict
    8.24 +                                    flags:(PEP_decrypt_flags * _Nullable)flags
    8.25                                     rating:(PEP_rating * _Nullable)rating
    8.26                                  extraKeys:(PEPStringList * _Nullable * _Nullable)extraKeys
    8.27                                     status:(PEP_STATUS * _Nullable)status
    8.28 @@ -111,12 +120,21 @@
    8.29      message *_src = PEP_messageDictToStruct(messageDict);
    8.30      message *_dst = NULL;
    8.31      stringlist_t *_keys = NULL;
    8.32 -    PEP_decrypt_flags_t flags = 0;
    8.33 +    PEP_decrypt_flags theFlags = 0;
    8.34 +
    8.35 +    if (flags) {
    8.36 +        theFlags = *flags;
    8.37 +    }
    8.38  
    8.39      PEP_rating internalRating = PEP_rating_undefined;
    8.40  
    8.41      [self lockWrite];
    8.42 -    PEP_STATUS theStatus = decrypt_message(_session, _src, &_dst, &_keys, &internalRating, &flags);
    8.43 +    PEP_STATUS theStatus = decrypt_message(_session,
    8.44 +                                           _src,
    8.45 +                                           &_dst,
    8.46 +                                           &_keys,
    8.47 +                                           &internalRating,
    8.48 +                                           &theFlags);
    8.49      [self unlockWrite];
    8.50  
    8.51      if (status) {
    8.52 @@ -124,9 +142,14 @@
    8.53      }
    8.54  
    8.55      if ([NSError setError:error fromPEPStatus:theStatus]) {
    8.56 +        decryptMessageDictFree(_src, _dst, _keys);
    8.57          return nil;
    8.58      }
    8.59  
    8.60 +    if (flags) {
    8.61 +        *flags = theFlags;
    8.62 +    }
    8.63 +
    8.64      NSDictionary *dst_;
    8.65  
    8.66      if (_dst) {
    8.67 @@ -136,12 +159,15 @@
    8.68      }
    8.69  
    8.70      NSArray *keys_ = nil;
    8.71 -    if (_keys)
    8.72 +    if (_keys) {
    8.73          keys_ = PEP_arrayFromStringlist(_keys);
    8.74 +    }
    8.75  
    8.76 -    free_message(_src);
    8.77 -    free_message(_dst);
    8.78 -    free_stringlist(_keys);
    8.79 +    if (theFlags & PEP_decrypt_flag_untrusted_server) {
    8.80 +        [messageDict replaceWithMessage:_src];
    8.81 +    }
    8.82 +
    8.83 +    decryptMessageDictFree(_src, _dst, _keys);
    8.84  
    8.85      if (extraKeys) {
    8.86          *extraKeys = keys_;
    8.87 @@ -155,16 +181,19 @@
    8.88  }
    8.89  
    8.90  - (PEPMessage * _Nullable)decryptMessage:(PEPMessage * _Nonnull)message
    8.91 +                                   flags:(PEP_decrypt_flags * _Nullable)flags
    8.92                                    rating:(PEP_rating * _Nullable)rating
    8.93                                 extraKeys:(PEPStringList * _Nullable * _Nullable)extraKeys
    8.94                                    status:(PEP_STATUS * _Nullable)status
    8.95                                     error:(NSError * _Nullable * _Nullable)error
    8.96  {
    8.97 -    PEPDict *destDict = [self decryptMessageDict:(PEPDict *)message
    8.98 -                                          rating:rating
    8.99 -                                       extraKeys:extraKeys
   8.100 -                                          status:status
   8.101 -                                           error:error];
   8.102 +    PEPDict *destDict = [self
   8.103 +                         decryptMessageDict:(PEPDict *)message
   8.104 +                         flags:flags
   8.105 +                         rating:rating
   8.106 +                         extraKeys:extraKeys
   8.107 +                         status:status
   8.108 +                         error:error];
   8.109  
   8.110      if (!destDict) {
   8.111          return nil;
   8.112 @@ -377,7 +406,7 @@
   8.113                                                 error:(NSError * _Nullable * _Nullable)error
   8.114  {
   8.115      message *_msg = PEP_messageDictToStruct(messageDict);
   8.116 -    PEP_rating rating = PEP_rating_b0rken;
   8.117 +    PEP_rating rating = PEP_rating_undefined;
   8.118  
   8.119      [self lockWrite];
   8.120      PEP_STATUS status = outgoing_message_rating(_session, _msg, &rating);
     9.1 --- a/pEpObjCAdapter/PEPMessage.m	Thu Apr 26 09:37:05 2018 +0200
     9.2 +++ b/pEpObjCAdapter/PEPMessage.m	Thu May 03 15:49:46 2018 +0200
     9.3 @@ -7,6 +7,10 @@
     9.4  //
     9.5  
     9.6  #import "PEPMessage.h"
     9.7 +#import "PEPIdentity.h"
     9.8 +
     9.9 +#import "NSObject+Extension.h"
    9.10 +#import "NSMutableDictionary+PEP.h"
    9.11  
    9.12  @implementation PEPMessage
    9.13  
    9.14 @@ -136,6 +140,35 @@
    9.15      return (PEPMutableDict *) self;
    9.16  }
    9.17  
    9.18 +- (void)removeAllObjects
    9.19 +{
    9.20 +    self.messageID = nil;
    9.21 +    self.from = nil;
    9.22 +    self.to = nil;
    9.23 +    self.cc = nil;
    9.24 +    self.bcc = nil;
    9.25 +    self.shortMessage = nil;
    9.26 +    self.longMessage = nil;
    9.27 +    self.longMessageFormatted = nil;
    9.28 +    self.replyTo = nil;
    9.29 +    self.inReplyTo = nil;
    9.30 +    self.references = nil;
    9.31 +    self.sentDate = nil;
    9.32 +    self.receivedDate = nil;
    9.33 +    self.attachments = nil;
    9.34 +    self.optionalFields = nil;
    9.35 +    self.keywords = nil;
    9.36 +    self.receivedBy = nil;
    9.37 +    self.direction = PEP_dir_incoming; // basically, 0
    9.38 +}
    9.39 +
    9.40 +// MARK: Faking the pEp directory extension
    9.41 +
    9.42 +- (void)replaceWithMessage:(message *)message
    9.43 +{
    9.44 +    replaceDictionaryContentsWithMessage(self.mutableDictionary, message);
    9.45 +}
    9.46 +
    9.47  // MARK: - NSDictionary - Helpers
    9.48  
    9.49  - (NSArray<NSArray<NSString *> *> *)keyValuePairs
    9.50 @@ -235,4 +268,59 @@
    9.51      return newMessage;
    9.52  }
    9.53  
    9.54 +// MARK: - Equality
    9.55 +
    9.56 +/**
    9.57 + The keys that should be used to decide `isEqual` and compute the `hash`.
    9.58 + */
    9.59 +static NSArray *s_keys;
    9.60 +
    9.61 +- (BOOL)isEqualToPEPMessage:(PEPMessage * _Nonnull)message
    9.62 +{
    9.63 +    return [self isEqualToObject:message basedOnKeys:s_keys];
    9.64 +}
    9.65 +
    9.66 +- (NSUInteger)hash
    9.67 +{
    9.68 +    return [self hashBasedOnKeys:s_keys];
    9.69 +}
    9.70 +
    9.71 +- (BOOL)isEqual:(id)object
    9.72 +{
    9.73 +    if (object == self) {
    9.74 +        return YES;
    9.75 +    }
    9.76 +    if (!object || ![object isKindOfClass:[self class]]) {
    9.77 +        return NO;
    9.78 +    }
    9.79 +
    9.80 +    return [self isEqualToPEPMessage:object];
    9.81 +}
    9.82 +
    9.83 +// MARK: - Static Initialization
    9.84 +
    9.85 ++ (void)initialize
    9.86 +{
    9.87 +    s_keys = @[
    9.88 +               @"attachments",
    9.89 +               @"bcc",
    9.90 +               @"cc",
    9.91 +               @"direction",
    9.92 +               @"from",
    9.93 +               @"inReplyTo",
    9.94 +               @"keywords",
    9.95 +               @"longMessage",
    9.96 +               @"longMessageFormatted",
    9.97 +               @"messageID",
    9.98 +               @"optionalFields",
    9.99 +               @"receivedBy",
   9.100 +               @"receivedDate",
   9.101 +               @"references",
   9.102 +               @"replyTo",
   9.103 +               @"sentDate",
   9.104 +               @"shortMessage",
   9.105 +               @"to",
   9.106 +               ];
   9.107 +}
   9.108 +
   9.109  @end
    10.1 --- a/pEpObjCAdapter/PEPMessageUtil.h	Thu Apr 26 09:37:05 2018 +0200
    10.2 +++ b/pEpObjCAdapter/PEPMessageUtil.h	Thu May 03 15:49:46 2018 +0200
    10.3 @@ -31,6 +31,10 @@
    10.4  message * _Nullable PEP_messageDictToStruct(NSDictionary * _Nullable dict);
    10.5  NSDictionary * _Nonnull PEP_messageDictFromStruct(message * _Nullable msg);
    10.6  
    10.7 +NSArray *PEP_identityArrayFromList(identity_list *il);
    10.8 +NSArray *PEP_arrayFromStringPairlist(stringpair_list_t *sl);
    10.9 +NSArray *PEP_arrayFromBloblist(bloblist_t *bl);
   10.10 +
   10.11  #pragma mark -- Constants
   10.12  
   10.13  /** The name of the user */
    11.1 --- a/pEpObjCAdapter/PEPMessageUtil.m	Thu Apr 26 09:37:05 2018 +0200
    11.2 +++ b/pEpObjCAdapter/PEPMessageUtil.m	Thu May 03 15:49:46 2018 +0200
    11.3 @@ -11,6 +11,7 @@
    11.4  #import "PEPIdentity.h"
    11.5  #import "PEPMessage.h"
    11.6  #import "PEPAttachment.h"
    11.7 +#import "NSMutableDictionary+PEP.h"
    11.8  
    11.9  #import "pEp_string.h"
   11.10  
   11.11 @@ -343,64 +344,7 @@
   11.12  {
   11.13      NSMutableDictionary *dict = [NSMutableDictionary new];
   11.14      if (msg && dict) {
   11.15 -        [dict setObject:(msg->dir==PEP_dir_outgoing)?@YES:@NO forKey:@"outgoing"];
   11.16 -
   11.17 -        if (msg->id)
   11.18 -            [dict setObject:[NSString stringWithUTF8String:msg->id] forKey:@"id"];
   11.19 -        
   11.20 -        if (msg->shortmsg)
   11.21 -            [dict setObject:[NSString stringWithUTF8String:msg->shortmsg] forKey:@"shortmsg"];
   11.22 -
   11.23 -        if (msg->sent)
   11.24 -            [dict setObject:[NSDate dateWithTimeIntervalSince1970:timegm(msg->sent)] forKey:@"sent"];
   11.25 -        
   11.26 -        if (msg->recv)
   11.27 -            [dict setObject:[NSDate dateWithTimeIntervalSince1970:mktime(msg->recv)] forKey:@"recv"];
   11.28 -        
   11.29 -        if (msg->from)
   11.30 -            [dict setObject:PEP_identityFromStruct(msg->from) forKey:kPepFrom];
   11.31 -        
   11.32 -        if (msg->to && msg->to->ident)
   11.33 -            [dict setObject:PEP_identityArrayFromList(msg->to) forKey:@"to"];
   11.34 -        
   11.35 -        if (msg->recv_by)
   11.36 -            [dict setObject:PEP_identityFromStruct(msg->recv_by) forKey:@"recv_by"];
   11.37 -        
   11.38 -        if (msg->cc && msg->cc->ident)
   11.39 -            [dict setObject:PEP_identityArrayFromList(msg->cc) forKey:@"cc"];
   11.40 -        
   11.41 -        if (msg->bcc && msg->bcc->ident)
   11.42 -            [dict setObject:PEP_identityArrayFromList(msg->bcc) forKey:@"bcc"];
   11.43 -        
   11.44 -        if (msg->reply_to && msg->reply_to->ident)
   11.45 -            [dict setObject:PEP_identityArrayFromList(msg->reply_to) forKey:@"reply_to"];
   11.46 -        
   11.47 -        if (msg->in_reply_to)
   11.48 -            [dict setObject:PEP_arrayFromStringlist(msg->in_reply_to) forKey:@"in_reply_to"];
   11.49 -
   11.50 -        if (msg->references && msg->references->value)
   11.51 -            [dict setObject:PEP_arrayFromStringlist(msg->references) forKey:kPepReferences];
   11.52 -
   11.53 -        if (msg->keywords && msg->keywords->value)
   11.54 -            [dict setObject:PEP_arrayFromStringlist(msg->keywords) forKey:@"keywords"];
   11.55 -
   11.56 -        if (msg->opt_fields)
   11.57 -            [dict setObject:PEP_arrayFromStringPairlist(msg->opt_fields) forKey:@"opt_fields"];
   11.58 -        
   11.59 -        if (msg->longmsg_formatted)
   11.60 -            [dict setObject:[NSString stringWithUTF8String:msg->longmsg_formatted]
   11.61 -                     forKey:@"longmsg_formatted"];
   11.62 -
   11.63 -        if (msg->longmsg)
   11.64 -            [dict setObject:[NSString stringWithUTF8String:msg->longmsg] forKey:@"longmsg"];
   11.65 -        
   11.66 -        if (msg->attachments && msg->attachments->value)
   11.67 -            [dict setObject: PEP_arrayFromBloblist(msg->attachments) forKey:@"attachments"];
   11.68 -
   11.69 -        if (msg->rawmsg_size > 0 && *msg->rawmsg_ref) {
   11.70 -            NSData *data = [NSData dataWithBytes:msg->rawmsg_ref length:msg->rawmsg_size];
   11.71 -            dict[kPepRawMessage] = data;
   11.72 -        }
   11.73 +        [dict replaceWithMessage:msg];
   11.74      }
   11.75      return dict;
   11.76  }
    12.1 --- a/pEpObjCAdapter/PEPSession.m	Thu Apr 26 09:37:05 2018 +0200
    12.2 +++ b/pEpObjCAdapter/PEPSession.m	Thu May 03 15:49:46 2018 +0200
    12.3 @@ -21,7 +21,8 @@
    12.4      [PEPSessionProvider cleanup];
    12.5  }
    12.6  
    12.7 -- (PEPDict * _Nullable)decryptMessageDict:(PEPDict * _Nonnull)messageDict
    12.8 +- (PEPDict * _Nullable)decryptMessageDict:(PEPMutableDict * _Nonnull)messageDict
    12.9 +                                    flags:(PEP_decrypt_flags * _Nullable)flags
   12.10                                     rating:(PEP_rating * _Nullable)rating
   12.11                                  extraKeys:(PEPStringList * _Nullable * _Nullable)extraKeys
   12.12                                     status:(PEP_STATUS * _Nullable)status
   12.13 @@ -30,6 +31,7 @@
   12.14      PEPInternalSession *session = [PEPSessionProvider session];
   12.15      return [session
   12.16              decryptMessageDict:messageDict
   12.17 +            flags:flags
   12.18              rating:rating
   12.19              extraKeys:extraKeys
   12.20              status:status
   12.21 @@ -37,6 +39,7 @@
   12.22  }
   12.23  
   12.24  - (PEPMessage * _Nullable)decryptMessage:(PEPMessage * _Nonnull)message
   12.25 +                                   flags:(PEP_decrypt_flags * _Nullable)flags
   12.26                                    rating:(PEP_rating * _Nullable)rating
   12.27                                 extraKeys:(PEPStringList * _Nullable * _Nullable)extraKeys
   12.28                                    status:(PEP_STATUS * _Nullable)status
   12.29 @@ -45,6 +48,7 @@
   12.30      PEPInternalSession *session = [PEPSessionProvider session];
   12.31      return [session
   12.32              decryptMessage:message
   12.33 +            flags:flags
   12.34              rating:rating
   12.35              extraKeys:extraKeys
   12.36              status:status
    13.1 --- a/pEpObjCAdapter/PEPSessionProtocol.h	Thu Apr 26 09:37:05 2018 +0200
    13.2 +++ b/pEpObjCAdapter/PEPSessionProtocol.h	Thu May 03 15:49:46 2018 +0200
    13.3 @@ -21,7 +21,8 @@
    13.4  @protocol PEPSessionProtocol <NSObject>
    13.5  
    13.6  /** Decrypt a message */
    13.7 -- (PEPDict * _Nullable)decryptMessageDict:(PEPDict * _Nonnull)messageDict
    13.8 +- (PEPDict * _Nullable)decryptMessageDict:(PEPMutableDict * _Nonnull)messageDict
    13.9 +                                    flags:(PEP_decrypt_flags * _Nullable)flags
   13.10                                     rating:(PEP_rating * _Nullable)rating
   13.11                                  extraKeys:(PEPStringList * _Nullable * _Nullable)extraKeys
   13.12                                     status:(PEP_STATUS * _Nullable)status
   13.13 @@ -29,6 +30,7 @@
   13.14  
   13.15  /** Decrypt a message */
   13.16  - (PEPMessage * _Nullable)decryptMessage:(PEPMessage * _Nonnull)message
   13.17 +                                   flags:(PEP_decrypt_flags * _Nullable)flags
   13.18                                    rating:(PEP_rating * _Nullable)rating
   13.19                                 extraKeys:(PEPStringList * _Nullable * _Nullable)extraKeys
   13.20                                    status:(PEP_STATUS * _Nullable)status
    14.1 --- a/pEpObjCTests/PEPSessionTest.m	Thu Apr 26 09:37:05 2018 +0200
    14.2 +++ b/pEpObjCTests/PEPSessionTest.m	Thu May 03 15:49:46 2018 +0200
    14.3 @@ -841,9 +841,10 @@
    14.4      NSArray *keys;
    14.5  
    14.6      error = nil;
    14.7 -    PEP_rating rating = PEP_rating_b0rken;
    14.8 +    PEP_rating rating = PEP_rating_undefined;
    14.9      PEPMessage *decmsg = [session
   14.10                            decryptMessage:encMsg
   14.11 +                          flags:nil
   14.12                            rating:&rating
   14.13                            extraKeys:&keys
   14.14                            status:nil
   14.15 @@ -853,7 +854,7 @@
   14.16      XCTAssertEqual(rating, PEP_rating_trusted_and_anonymized);
   14.17  }
   14.18  
   14.19 -- (void)testEncryptedMailFromMutt
   14.20 +- (void)testEncryptedMailFromMuttWithReencryption
   14.21  {
   14.22      PEPSession *session = [PEPSession new];
   14.23  
   14.24 @@ -888,17 +889,30 @@
   14.25      NSArray* keys;
   14.26      PEPMessage *msg = [PEPMessage new];
   14.27      [msg setValuesForKeysWithDictionary:msgDict];
   14.28 +    PEPMessage *msgOriginal = [PEPMessage new];
   14.29 +    [msgOriginal setValuesForKeysWithDictionary:msgDict];
   14.30  
   14.31 -    // Technically, the mail is encrypted, but the signatures don't match
   14.32 +    XCTAssertEqualObjects(msg, msgOriginal);
   14.33 +
   14.34 +    PEP_rating rating = PEP_rating_undefined;
   14.35 +    PEP_decrypt_flags flags = PEP_decrypt_flag_untrusted_server;
   14.36 +
   14.37      PEPMessage *pepDecryptedMail = [session
   14.38                                      decryptMessage:msg
   14.39 -                                    rating:nil
   14.40 +                                    flags:&flags
   14.41 +                                    rating:&rating
   14.42                                      extraKeys:&keys
   14.43                                      status:nil
   14.44                                      error:&error];
   14.45      XCTAssertNotNil(pepDecryptedMail);
   14.46      XCTAssertNil(error);
   14.47  
   14.48 +    // Technically, the mail is encrypted, but the signatures don't match
   14.49 +    XCTAssertEqual(rating, PEP_rating_unreliable);
   14.50 +
   14.51 +    // Since we're requesting re-encryption, src should have been changed
   14.52 +    XCTAssertNotEqualObjects(msg, msgOriginal);
   14.53 +
   14.54      XCTAssertNotNil(pepDecryptedMail.longMessage);
   14.55  }
   14.56  
   14.57 @@ -1075,6 +1089,7 @@
   14.58      error = nil;
   14.59      PEPMessage *decMsg = [session
   14.60                            decryptMessage:encMsg
   14.61 +                          flags:nil
   14.62                            rating:&pEpRating
   14.63                            extraKeys:&keys
   14.64                            status:nil
   14.65 @@ -1341,6 +1356,7 @@
   14.66      error = nil;
   14.67      PEPMessage *unencDict = [session
   14.68                               decryptMessage:encMessage
   14.69 +                             flags:nil
   14.70                               rating:&rating
   14.71                               extraKeys:keys
   14.72                               status:nil
   14.73 @@ -1425,6 +1441,7 @@
   14.74      error = nil;
   14.75      PEPMessage *decMsg = [session
   14.76                            decryptMessage:encMsg
   14.77 +                          flags:nil
   14.78                            rating:&pEpRating
   14.79                            extraKeys:&keys
   14.80                            status:nil