pEpObjCAdapter/PEPInternalSession.m
author Dirk Zimmermann <dz@pep.security>
Fri, 20 Sep 2019 10:01:48 +0200
branchIOSAD-141
changeset 1250 b6a4d30abd26
parent 1247 ec96c9c3248e
permissions -rw-r--r--
IOSAD-141 Test for "hammering" the engine.
     1 //
     2 //  PEPSession.m
     3 //  pEpiOSAdapter
     4 //
     5 //  Created by Volker Birk on 08.07.15.
     6 //  Copyright (c) 2015 p≡p. All rights reserved.
     7 //
     8 
     9 #import "PEPInternalSession.h"
    10 
    11 #import "PEPConstants.h"
    12 
    13 #import "PEPObjCAdapter.h"
    14 #import "PEPObjCAdapter+Internal.h"
    15 #import "PEPMessageUtil.h"
    16 #import "PEPLanguage.h"
    17 #import "PEPCSVScanner.h"
    18 #import "NSArray+Extension.h"
    19 #import "NSDictionary+CommType.h"
    20 #import "NSDictionary+Debug.h"
    21 #import "PEPIdentity.h"
    22 #import "PEPMessage.h"
    23 #import "NSError+PEP+Internal.h"
    24 #import "PEPAutoPointer.h"
    25 #import "NSNumber+PEPRating.h"
    26 #import "NSMutableDictionary+PEP.h"
    27 #import "PEPSync_Internal.h"
    28 #import "PEPInternalConstants.h"
    29 
    30 #import "key_reset.h"
    31 
    32 @implementation PEPInternalSession
    33 
    34 - (_Nullable instancetype)init
    35 {
    36     self = [super init];
    37     if (self) {
    38         [PEPInternalSession setupTrustWordsDB];
    39 
    40         NSError *error = nil;
    41         _session = [PEPSync createSession:&error];
    42 
    43         if (error) {
    44             return nil;
    45         }
    46     }
    47     return self;
    48 }
    49 
    50 - (void)dealloc
    51 {
    52     if (_session != nil) {
    53         release(_session);
    54     }
    55 }
    56 
    57 #pragma mark - CONFIG
    58 
    59 - (void)configUnEncryptedSubjectEnabled:(BOOL)enabled;
    60 {
    61     config_unencrypted_subject(self.session, enabled);
    62 }
    63 
    64 #pragma mark - INTERNAL
    65 
    66 + (void)setupTrustWordsDB
    67 {
    68     static dispatch_once_t once;
    69     dispatch_once(&once, ^{
    70         [PEPObjCAdapter setupTrustWordsDB:[NSBundle bundleForClass:[self class]]];
    71     });
    72 }
    73 
    74 #pragma mark - DEBUG UTILS
    75 
    76 /**
    77  Saves the given message dict as a plist to the local filesystem
    78  (directly under NSApplicationSupportDirectory).
    79  Since the complete output file will be logged by `debugSaveToFilePath`,
    80  you can get access to the files easily when it's the simulator.
    81  */
    82 - (void)debugOutPutMessageDict:(PEPDict * _Nonnull)src
    83 {
    84     NSString *from = src[kPepFrom][kPepAddress];
    85     NSArray *tos = src[kPepTo];
    86     NSString *to = tos[0][kPepAddress];
    87     NSString *msgID = src[kPepID];
    88     NSString *fileName = [NSString stringWithFormat:@"%@_from(%@)_%@",
    89                           to, from, msgID];
    90     [src debugSaveToFilePath:fileName];
    91 }
    92 
    93 #pragma mark - PEPSessionProtocol
    94 
    95 void decryptMessageDictFree(message *src, message *dst, stringlist_t *extraKeys)
    96 {
    97     free_message(src);
    98     free_message(dst);
    99     free_stringlist(extraKeys);
   100 }
   101 
   102 - (PEPDict * _Nullable)decryptMessageDict:(PEPMutableDict * _Nonnull)messageDict
   103                                     flags:(PEPDecryptFlags * _Nullable)flags
   104                                    rating:(PEPRating * _Nullable)rating
   105                                 extraKeys:(PEPStringList * _Nullable * _Nullable)extraKeys
   106                                    status:(PEPStatus * _Nullable)status
   107                                     error:(NSError * _Nullable * _Nullable)error
   108 {
   109     if (rating) {
   110         *rating = PEPRatingUndefined;
   111     }
   112 
   113     message *_src = PEP_messageDictToStruct(messageDict);
   114     message *_dst = NULL;
   115     stringlist_t *theKeys = NULL;
   116     PEPDecryptFlags theFlags = 0;
   117 
   118     if (flags) {
   119         theFlags = *flags;
   120     }
   121 
   122     if (extraKeys && [*extraKeys count]) {
   123         theKeys = PEP_arrayToStringlist(*extraKeys);
   124     }
   125 
   126     PEPRating internalRating = PEPRatingUndefined;
   127 
   128     PEPStatus theStatus = (PEPStatus) decrypt_message(_session,
   129                                                       _src,
   130                                                       &_dst,
   131                                                       &theKeys,
   132                                                       (PEP_rating *) &internalRating,
   133                                                       (PEP_decrypt_flags *) &theFlags);
   134 
   135     if (status) {
   136         *status = theStatus;
   137     }
   138 
   139     if ([NSError setError:error fromPEPStatus:theStatus]) {
   140         decryptMessageDictFree(_src, _dst, theKeys);
   141         return nil;
   142     }
   143 
   144     if (flags) {
   145         *flags = theFlags;
   146     }
   147 
   148     NSDictionary *dst_;
   149 
   150     if (_dst) {
   151         dst_ = PEP_messageDictFromStruct(_dst);
   152     } else {
   153         dst_ = PEP_messageDictFromStruct(_src);
   154     }
   155 
   156     if (theFlags & PEP_decrypt_flag_untrusted_server) {
   157         [messageDict replaceWithMessage:_src];
   158     }
   159 
   160     if (extraKeys) {
   161         *extraKeys = PEP_arrayFromStringlist(theKeys);
   162     }
   163 
   164     decryptMessageDictFree(_src, _dst, theKeys);
   165 
   166     if (rating) {
   167         *rating = internalRating;
   168     }
   169 
   170     return dst_;
   171 }
   172 
   173 - (PEPMessage * _Nullable)decryptMessage:(PEPMessage * _Nonnull)message
   174                                    flags:(PEPDecryptFlags * _Nullable)flags
   175                                   rating:(PEPRating * _Nullable)rating
   176                                extraKeys:(PEPStringList * _Nullable * _Nullable)extraKeys
   177                                   status:(PEPStatus * _Nullable)status
   178                                    error:(NSError * _Nullable * _Nullable)error
   179 {
   180     PEPDict *destDict = [self
   181                          decryptMessageDict:message.mutableDictionary
   182                          flags:flags
   183                          rating:rating
   184                          extraKeys:extraKeys
   185                          status:status
   186                          error:error];
   187 
   188     if (destDict) {
   189         PEPMessage *msg = [PEPMessage new];
   190         [msg setValuesForKeysWithDictionary:destDict];
   191         return msg;
   192     } else {
   193         return nil;
   194     }
   195 }
   196 
   197 - (BOOL)reEvaluateMessageDict:(PEPDict * _Nonnull)messageDict
   198                      xKeyList:(PEPStringList * _Nullable)xKeyList
   199                        rating:(PEPRating * _Nonnull)rating
   200                        status:(PEPStatus * _Nullable)status
   201                         error:(NSError * _Nullable * _Nullable)error
   202 {
   203     message *_src = PEP_messageDictToStruct(messageDict);
   204 
   205     stringlist_t *theKeys = NULL;
   206     if ([xKeyList count]) {
   207         theKeys = PEP_arrayToStringlist(xKeyList);
   208     }
   209 
   210     PEPStatus theStatus = (PEPStatus) re_evaluate_message_rating(_session,
   211                                                                  _src,
   212                                                                  theKeys,
   213                                                                  (PEP_rating) *rating,
   214                                                                  (PEP_rating *) rating);
   215 
   216     free_message(_src);
   217     free_stringlist(theKeys);
   218 
   219     if (status) {
   220         *status = theStatus;
   221     }
   222 
   223     if ([NSError setError:error fromPEPStatus:theStatus]) {
   224         return NO;
   225     } else {
   226         return YES;
   227     }
   228 }
   229 
   230 - (BOOL)reEvaluateMessage:(PEPMessage * _Nonnull)message
   231                  xKeyList:(PEPStringList * _Nullable)xKeyList
   232                    rating:(PEPRating * _Nonnull)rating
   233                    status:(PEPStatus * _Nullable)status
   234                     error:(NSError * _Nullable * _Nullable)error
   235 {
   236     return [self reEvaluateMessageDict:(PEPDict *) message
   237                               xKeyList:xKeyList
   238                                 rating:rating
   239                                 status:status
   240                                  error:error];
   241 }
   242 
   243 - (void)removeEmptyArrayKey:(NSString *)key inDict:(PEPMutableDict *)dict
   244 {
   245     if ([[dict objectForKey:key] count] == 0) {
   246         [dict removeObjectForKey:key];
   247     }
   248 }
   249 
   250 - (NSDictionary *)removeEmptyRecipients:(PEPDict *)src
   251 {
   252     NSMutableDictionary *dest = src.mutableCopy;
   253 
   254     [self removeEmptyArrayKey:kPepTo inDict:dest];
   255     [self removeEmptyArrayKey:kPepCC inDict:dest];
   256     [self removeEmptyArrayKey:kPepBCC inDict:dest];
   257 
   258     return dest;
   259 }
   260 
   261 - (PEPDict * _Nullable)encryptMessageDict:(PEPDict * _Nonnull)messageDict
   262                                 extraKeys:(PEPStringList * _Nullable)extraKeys
   263                                 encFormat:(PEPEncFormat)encFormat
   264                                    status:(PEPStatus * _Nullable)status
   265                                     error:(NSError * _Nullable * _Nullable)error
   266 {
   267     PEP_encrypt_flags_t flags = 0;
   268 
   269     message *_src = PEP_messageDictToStruct([self removeEmptyRecipients:messageDict]);
   270     message *_dst = NULL;
   271     stringlist_t *_keys = PEP_arrayToStringlist(extraKeys);
   272 
   273     PEPStatus theStatus = (PEPStatus) encrypt_message(
   274                                                       _session,
   275                                                       _src,
   276                                                       _keys,
   277                                                       &_dst,
   278                                                       (PEP_enc_format) encFormat,
   279                                                       flags);
   280 
   281     if (status) {
   282         *status = theStatus;
   283     }
   284 
   285     if ([NSError setError:error fromPEPStatus:theStatus]) {
   286         return nil;
   287     }
   288 
   289     NSDictionary *dst_;
   290 
   291     if (_dst) {
   292         dst_ = PEP_messageDictFromStruct(_dst);
   293     }
   294     else {
   295         dst_ = PEP_messageDictFromStruct(_src);
   296     }
   297 
   298     free_message(_src);
   299     free_message(_dst);
   300     free_stringlist(_keys);
   301 
   302     return dst_;
   303 }
   304 
   305 - (PEPMessage * _Nullable)encryptMessage:(PEPMessage * _Nonnull)message
   306                                extraKeys:(PEPStringList * _Nullable)extraKeys
   307                                encFormat:(PEPEncFormat)encFormat
   308                                   status:(PEPStatus * _Nullable)status
   309                                    error:(NSError * _Nullable * _Nullable)error
   310 {
   311     PEPDict *encryptedDict = [self encryptMessageDict:(NSDictionary *) message
   312                                             extraKeys:extraKeys
   313                                             encFormat:encFormat
   314                                                status:status
   315                                                 error:error];
   316     if (encryptedDict) {
   317         PEPMessage *encrypted = [PEPMessage new];
   318         [encrypted setValuesForKeysWithDictionary:encryptedDict];
   319         return encrypted;
   320     } else {
   321         return nil;
   322     }
   323 }
   324 
   325 - (PEPMessage * _Nullable)encryptMessage:(PEPMessage * _Nonnull)message
   326                                extraKeys:(PEPStringList * _Nullable)extraKeys
   327                                   status:(PEPStatus * _Nullable)status
   328                                    error:(NSError * _Nullable * _Nullable)error
   329 {
   330     return [self
   331             encryptMessage:message
   332             extraKeys:extraKeys
   333             encFormat:PEPEncFormatPEP
   334             status:status
   335             error:error];
   336 }
   337 
   338 - (PEPDict * _Nullable)encryptMessageDict:(PEPDict * _Nonnull)messageDict
   339                                   forSelf:(PEPIdentity * _Nonnull)ownIdentity
   340                                 extraKeys:(PEPStringList * _Nullable)extraKeys
   341                                    status:(PEPStatus * _Nullable)status
   342                                     error:(NSError * _Nullable * _Nullable)error
   343 {
   344     PEP_encrypt_flags_t flags = 0;
   345 
   346     message *_src = PEP_messageDictToStruct([self removeEmptyRecipients:messageDict]);
   347     pEp_identity *ident = PEP_identityToStruct(ownIdentity);
   348     message *_dst = NULL;
   349 
   350     stringlist_t *keysStringList = PEP_arrayToStringlist(extraKeys);
   351 
   352     PEPStatus theStatus = (PEPStatus) encrypt_message_for_self(_session,
   353                                                                ident,
   354                                                                _src,
   355                                                                keysStringList,
   356                                                                &_dst,
   357                                                                PEP_enc_PGP_MIME,
   358                                                                flags);
   359 
   360     free_stringlist(keysStringList);
   361 
   362     if (status) {
   363         *status = theStatus;
   364     }
   365 
   366     if ([NSError setError:error fromPEPStatus:theStatus]) {
   367         return nil;
   368     }
   369 
   370     NSDictionary *dst_;
   371 
   372     if (_dst) {
   373         dst_ = PEP_messageDictFromStruct(_dst);
   374     }
   375     else {
   376         dst_ = PEP_messageDictFromStruct(_src);
   377     }
   378 
   379     free_message(_src);
   380     free_message(_dst);
   381     free_identity(ident);
   382 
   383     return dst_;
   384 }
   385 
   386 - (PEPMessage * _Nullable)encryptMessage:(PEPMessage * _Nonnull)message
   387                                  forSelf:(PEPIdentity * _Nonnull)ownIdentity
   388                                extraKeys:(PEPStringList * _Nullable)extraKeys
   389                                   status:(PEPStatus * _Nullable)status
   390                                    error:(NSError * _Nullable * _Nullable)error
   391 {
   392     PEPDict *target = [self
   393                        encryptMessageDict:message.dictionary
   394                        forSelf:ownIdentity
   395                        extraKeys:extraKeys
   396                        status:status
   397                        error:error];
   398 
   399     if (target) {
   400         PEPMessage *encrypted = [PEPMessage new];
   401         [encrypted setValuesForKeysWithDictionary:target];
   402         return encrypted;
   403     } else {
   404         return nil;
   405     }
   406 }
   407 
   408 
   409 - (PEPDict * _Nullable)encryptMessageDict:(PEPDict * _Nonnull)messageDict
   410                                     toFpr:(NSString * _Nonnull)toFpr
   411                                 encFormat:(PEPEncFormat)encFormat
   412                                     flags:(PEPDecryptFlags)flags
   413                                    status:(PEPStatus * _Nullable)status
   414                                     error:(NSError * _Nullable * _Nullable)error __deprecated
   415 {
   416     message *src = PEP_messageDictToStruct([self removeEmptyRecipients:messageDict]);
   417     message *dst = NULL;
   418 
   419     PEPStatus theStatus = (PEPStatus)
   420     encrypt_message_and_add_priv_key(_session, src, &dst,
   421                                      [[toFpr precomposedStringWithCanonicalMapping] UTF8String],
   422                                      (PEP_enc_format) encFormat, flags);
   423 
   424     if (status) {
   425         *status = theStatus;
   426     }
   427 
   428     if ([NSError setError:error fromPEPStatus:theStatus]) {
   429         return nil;
   430     }
   431 
   432     if (dst) {
   433         return PEP_messageDictFromStruct(dst);
   434     }
   435 
   436     return nil;
   437 }
   438 
   439 - (PEPMessage * _Nullable)encryptMessage:(PEPMessage * _Nonnull)message
   440                                    toFpr:(NSString * _Nonnull)toFpr
   441                                encFormat:(PEPEncFormat)encFormat
   442                                    flags:(PEPDecryptFlags)flags
   443                                   status:(PEPStatus * _Nullable)status
   444                                    error:(NSError * _Nullable * _Nullable)error
   445 {
   446     PEPDict *target = [self
   447                        encryptMessageDict:message.dictionary
   448                        toFpr:toFpr
   449                        encFormat:encFormat
   450                        flags:flags
   451                        status:status
   452                        error:error];
   453 
   454     if (target) {
   455         PEPMessage *encrypted = [PEPMessage new];
   456         [encrypted setValuesForKeysWithDictionary:target];
   457         return encrypted;
   458     } else {
   459         return nil;
   460     }
   461 }
   462 
   463 typedef PEP_STATUS (* rating_function_type)(PEP_SESSION session, message *msg, PEP_rating *rating);
   464 
   465 - (NSNumber * _Nullable)helperOutgoingRatingForMessage:(PEPMessage * _Nonnull)theMessage
   466                                         ratingFunction:(rating_function_type)ratingFunction
   467                                                  error:(NSError * _Nullable * _Nullable)error
   468 {
   469     message *_msg = PEP_messageToStruct(theMessage);
   470     PEPRating rating = PEPRatingUndefined;
   471 
   472     PEPStatus status = (PEPStatus) ratingFunction(_session, _msg, (PEP_rating *) &rating);
   473 
   474     free_message(_msg);
   475 
   476     if ([NSError setError:error fromPEPStatus:status]) {
   477         return nil;
   478     }
   479 
   480     return [NSNumber numberWithPEPRating:rating];
   481 }
   482 
   483 - (NSNumber * _Nullable)outgoingRatingForMessage:(PEPMessage * _Nonnull)theMessage
   484                                            error:(NSError * _Nullable * _Nullable)error
   485 {
   486     return [self
   487             helperOutgoingRatingForMessage:theMessage
   488             ratingFunction:&outgoing_message_rating
   489             error:error];
   490 }
   491 
   492 - (NSNumber * _Nullable)outgoingRatingPreviewForMessage:(PEPMessage * _Nonnull)theMessage
   493                                                   error:(NSError * _Nullable * _Nullable)error
   494 {
   495     return [self
   496             helperOutgoingRatingForMessage:theMessage
   497             ratingFunction:&outgoing_message_rating_preview
   498             error:error];
   499 }
   500 
   501 - (NSNumber * _Nullable)ratingForIdentity:(PEPIdentity * _Nonnull)identity
   502                                     error:(NSError * _Nullable * _Nullable)error
   503 {
   504     pEp_identity *ident = PEP_identityToStruct(identity);
   505     PEPRating rating = PEPRatingUndefined;
   506 
   507     PEPStatus status = (PEPStatus) identity_rating(_session, ident, (PEP_rating *) &rating);
   508 
   509     free_identity(ident);
   510 
   511     if ([NSError setError:error fromPEPStatus:status]) {
   512         return nil;
   513     }
   514 
   515     return [NSNumber numberWithPEPRating:rating];
   516 }
   517 
   518 - (NSArray * _Nullable)trustwordsForFingerprint:(NSString * _Nonnull)fingerprint
   519                                      languageID:(NSString * _Nonnull)languageID
   520                                       shortened:(BOOL)shortened
   521                                           error:(NSError * _Nullable * _Nullable)error
   522 {
   523     NSMutableArray *array = [NSMutableArray array];
   524 
   525     for (int i = 0; i < [fingerprint length]; i += 4) {
   526         if (shortened && i >= 20)
   527             break;
   528 
   529         NSString *str = [fingerprint substringWithRange:NSMakeRange(i, 4)];
   530 
   531         unsigned int value;
   532         [[NSScanner scannerWithString:str] scanHexInt:&value];
   533 
   534         PEPAutoPointer *word = [PEPAutoPointer new];
   535         size_t size;
   536 
   537         PEPStatus status = (PEPStatus) trustword(_session,
   538                                                  value,
   539                                                  [[languageID precomposedStringWithCanonicalMapping]
   540                                                   UTF8String],
   541                                                  word.charPointerPointer,
   542                                                  &size);
   543 
   544         if ([NSError setError:error fromPEPStatus:status]) {
   545             return nil;
   546         }
   547 
   548         [array addObject:[NSString stringWithUTF8String:word.charPointer]];
   549     }
   550 
   551     return array;
   552 }
   553 
   554 - (BOOL)mySelf:(PEPIdentity * _Nonnull)identity error:(NSError * _Nullable * _Nullable)error
   555 {
   556     pEp_identity *ident = PEP_identityToStruct(identity);
   557 
   558     PEPStatus status = (PEPStatus) myself(_session, ident);
   559 
   560     if ([NSError setError:error fromPEPStatus:status]) {
   561         free_identity(ident);
   562         return NO;
   563     }
   564 
   565     [identity reset];
   566     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   567     free_identity(ident);
   568 
   569     return YES;
   570 }
   571 
   572 - (BOOL)updateIdentity:(PEPIdentity * _Nonnull)identity error:(NSError * _Nullable * _Nullable)error
   573 {
   574     if (identity.isOwn) {
   575         return [self mySelf:identity error:error];
   576     } else {
   577         pEp_identity *ident = PEP_identityToStruct(identity);
   578 
   579         PEPStatus status = (PEPStatus) update_identity(_session, ident);
   580         
   581         if ([NSError setError:error fromPEPStatus:status]) {
   582             free_identity(ident);
   583             return NO;
   584         }
   585 
   586         [identity reset];
   587         [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   588         free_identity(ident);
   589 
   590         return YES;
   591     }
   592 }
   593 
   594 - (BOOL)trustPersonalKey:(PEPIdentity * _Nonnull)identity
   595                    error:(NSError * _Nullable * _Nullable)error
   596 {
   597     pEp_identity *ident = PEP_identityToStruct(identity);
   598 
   599     PEPStatus status = (PEPStatus) trust_personal_key(_session, ident);
   600 
   601     if ([NSError setError:error fromPEPStatus:status]) {
   602         free_identity(ident);
   603         return NO;
   604     }
   605 
   606     [identity reset];
   607     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   608     free_identity(ident);
   609     return YES;
   610 }
   611 
   612 - (BOOL)keyMistrusted:(PEPIdentity *)identity error:(NSError * _Nullable * _Nullable)error
   613 {
   614     pEp_identity *ident = PEP_identityToStruct(identity);
   615 
   616     PEPStatus status = (PEPStatus) key_mistrusted(_session, ident);
   617 
   618     if ([NSError setError:error fromPEPStatus:status]) {
   619         free_identity(ident);
   620         return NO;
   621     }
   622 
   623     [identity reset];
   624     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   625     free_identity(ident);
   626 
   627     return YES;
   628 }
   629 
   630 - (BOOL)keyResetTrust:(PEPIdentity * _Nonnull)identity
   631                 error:(NSError * _Nullable * _Nullable)error
   632 {
   633     pEp_identity *ident = PEP_identityToStruct(identity);
   634 
   635     PEPStatus status = (PEPStatus) key_reset_trust(_session, ident);
   636 
   637     if ([NSError setError:error fromPEPStatus:status]) {
   638         free_identity(ident);
   639         return NO;
   640     }
   641 
   642     [identity reset];
   643     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   644     free_identity(ident);
   645 
   646     return YES;
   647 }
   648 
   649 - (BOOL)enableSyncForIdentity:(PEPIdentity * _Nonnull)identity
   650                         error:(NSError * _Nullable * _Nullable)error
   651 {
   652     if (!identity.isOwn) {
   653         [NSError setError:error fromPEPStatus:PEPStatusIllegalValue];
   654         return NO;
   655     }
   656 
   657     pEp_identity *ident = PEP_identityToStruct(identity);
   658 
   659     PEPStatus status = (PEPStatus) enable_identity_for_sync(_session, ident);
   660 
   661     if ([NSError setError:error fromPEPStatus:status]) {
   662         free_identity(ident);
   663         return NO;
   664     }
   665 
   666     free_identity(ident);
   667 
   668     return YES;
   669 }
   670 
   671 - (BOOL)disableSyncForIdentity:(PEPIdentity * _Nonnull)identity
   672                          error:(NSError * _Nullable * _Nullable)error
   673 {
   674     if (!identity.isOwn) {
   675         [NSError setError:error fromPEPStatus:PEPStatusIllegalValue];
   676         return NO;
   677     }
   678 
   679     pEp_identity *ident = PEP_identityToStruct(identity);
   680 
   681     PEPStatus status = (PEPStatus) disable_identity_for_sync(_session, ident);
   682 
   683     if ([NSError setError:error fromPEPStatus:status]) {
   684         free_identity(ident);
   685         return NO;
   686     }
   687 
   688     free_identity(ident);
   689 
   690     return YES;
   691 }
   692 
   693 - (NSNumber * _Nullable)queryKeySyncEnabledForIdentity:(PEPIdentity * _Nonnull)identity
   694                                                  error:(NSError * _Nullable * _Nullable)error
   695 {
   696     pEp_identity *ident = PEP_identityToStruct(identity);
   697 
   698     if (!identity.isOwn) {
   699         [NSError setError:error fromPEPStatus:PEPStatusIllegalValue];
   700         return nil;
   701     }
   702 
   703     PEPStatus status = (PEPStatus) myself(_session, ident);
   704 
   705     if ([NSError setError:error fromPEPStatus:status]) {
   706         free_identity(ident);
   707         return nil;
   708     }
   709 
   710     identity_flags_t flags = ident->flags;
   711 
   712     free_identity(ident);
   713 
   714     if (flags & PEP_idf_not_for_sync) {
   715         return [NSNumber numberWithBool:NO];
   716     } else {
   717         return [NSNumber numberWithBool:YES];
   718     }
   719 }
   720 
   721 - (NSArray<PEPIdentity *> * _Nullable)importKey:(NSString * _Nonnull)keydata
   722                                           error:(NSError * _Nullable * _Nullable)error
   723 {
   724     identity_list *identList = NULL;
   725 
   726     PEPStatus status = (PEPStatus) import_key(_session,
   727                                               [[keydata precomposedStringWithCanonicalMapping] UTF8String],
   728                                               [keydata length], &identList);
   729 
   730     if ([NSError setError:error fromPEPStatus:status]) {
   731         free(identList);
   732         return nil;
   733     }
   734 
   735     NSArray *idents = PEP_arrayFromIdentityList(identList);
   736     free(identList);
   737 
   738     return idents;
   739 }
   740 
   741 - (BOOL)logTitle:(NSString * _Nonnull)title
   742           entity:(NSString * _Nonnull)entity
   743      description:(NSString * _Nullable)description
   744          comment:(NSString * _Nullable)comment
   745            error:(NSError * _Nullable * _Nullable)error
   746 {
   747     PEPStatus status = (PEPStatus) log_event(_session,
   748                                              [[title precomposedStringWithCanonicalMapping]
   749                                               UTF8String],
   750                                              [[entity precomposedStringWithCanonicalMapping]
   751                                               UTF8String],
   752                                              [[description precomposedStringWithCanonicalMapping]
   753                                               UTF8String],
   754                                              [[comment precomposedStringWithCanonicalMapping]
   755                                               UTF8String]);
   756 
   757     if ([NSError setError:error fromPEPStatus:status]) {
   758         return NO;
   759     } else {
   760         return YES;
   761     }
   762 }
   763 
   764 - (NSString * _Nullable)getLogWithError:(NSError * _Nullable * _Nullable)error
   765 {
   766     char *theChars = NULL;
   767     PEPStatus status = (PEPStatus) get_crashdump_log(_session, 0, &theChars);
   768 
   769     if ([NSError setError:error fromPEPStatus:status]) {
   770         return nil;
   771     }
   772 
   773     if (theChars) {
   774         return [NSString stringWithUTF8String:theChars];
   775     } else {
   776         [NSError setError:error fromPEPStatusInternal:PEP_UNKNOWN_ERROR];
   777         return nil;
   778     }
   779 }
   780 
   781 - (NSString * _Nullable)getTrustwordsIdentity1:(PEPIdentity * _Nonnull)identity1
   782                                      identity2:(PEPIdentity * _Nonnull)identity2
   783                                       language:(NSString * _Nullable)language
   784                                           full:(BOOL)full
   785                                          error:(NSError * _Nullable * _Nullable)error
   786 {
   787     pEp_identity *ident1 = PEP_identityToStruct(identity1);
   788     pEp_identity *ident2 = PEP_identityToStruct(identity2);
   789     PEPStatus status;
   790 
   791     PEPAutoPointer *trustwords = [PEPAutoPointer new];
   792     size_t sizeWritten = 0;
   793 
   794     status = (PEPStatus) get_trustwords(_session, ident1, ident2,
   795                                         [[language precomposedStringWithCanonicalMapping]
   796                                          UTF8String],
   797                                         trustwords.charPointerPointer, &sizeWritten, full);
   798 
   799     free_identity(ident1);
   800     free_identity(ident2);
   801 
   802     NSString *result = nil;
   803 
   804     if (![NSError setError:error fromPEPStatus:status]) {
   805         result = [NSString stringWithUTF8String:trustwords.charPointer];
   806     }
   807 
   808     return result;
   809 }
   810 
   811 - (NSString * _Nullable)getTrustwordsFpr1:(NSString * _Nonnull)fpr1
   812                                      fpr2:(NSString * _Nonnull)fpr2
   813                                  language:(NSString * _Nullable)language
   814                                      full:(BOOL)full
   815                                     error:(NSError * _Nullable * _Nullable)error
   816 {
   817     const char *_fpr1 = [fpr1 UTF8String]; // fprs are NFC normalized anyway
   818     const char *_fpr2 = [fpr2 UTF8String];
   819     
   820     PEPStatus status;
   821     
   822     PEPAutoPointer *trustwords = [PEPAutoPointer new];
   823     size_t sizeWritten = 0;
   824 
   825     status = (PEPStatus) get_trustwords_for_fprs(_session, _fpr1, _fpr2,
   826                                                  [[language precomposedStringWithCanonicalMapping]
   827                                                   UTF8String],
   828                                                  trustwords.charPointerPointer, &sizeWritten, full);
   829     
   830     NSString *result = nil;
   831     
   832     if (![NSError setError:error fromPEPStatus:status]) {
   833         result = [NSString stringWithUTF8String:trustwords.charPointer];
   834     }
   835     
   836     return result;
   837 }
   838 
   839 - (NSArray<PEPLanguage *> * _Nullable)languageListWithError:(NSError * _Nullable * _Nullable)error
   840 {
   841     PEPAutoPointer *chLangs = [PEPAutoPointer new];
   842     PEPStatus status = (PEPStatus) get_languagelist(_session, chLangs.charPointerPointer);
   843 
   844     if ([NSError setError:error fromPEPStatus:status]) {
   845         return nil;
   846     }
   847 
   848     NSString *parserInput = [NSString stringWithUTF8String:chLangs.charPointer];
   849 
   850     NSMutableArray<NSString *> *tokens = [NSMutableArray array];
   851     PEPCSVScanner *scanner = [[PEPCSVScanner alloc] initWithString:parserInput];
   852     while (YES) {
   853         NSString *token = [scanner nextString];
   854         if (!token) {
   855             break;
   856         }
   857         [tokens addObject:token];
   858     }
   859     
   860     NSArray *theTokens = [NSArray arrayWithArray:tokens];
   861     NSMutableArray<PEPLanguage *> *langs = [NSMutableArray new];
   862     while (YES) {
   863         ArrayTake *take = [theTokens takeOrNil:3];
   864         if (!take) {
   865             break;
   866         }
   867         NSArray *elements = take.elements;
   868         PEPLanguage *lang = [[PEPLanguage alloc]
   869                              initWithCode:[elements objectAtIndex:0]
   870                              name:[elements objectAtIndex:1]
   871                              sentence:[elements objectAtIndex:2]];
   872         [langs addObject:lang];
   873         theTokens = take.rest;
   874     }
   875     
   876     return [NSArray arrayWithArray:langs];
   877 }
   878 
   879 static NSDictionary *ratingToString;
   880 static NSDictionary *stringToRating;
   881 
   882 + (void)initialize
   883 {
   884     NSDictionary *ratingToStringIntern =
   885     @{
   886       [NSNumber numberWithInteger:PEPRatingCannotDecrypt]: @"cannot_decrypt",
   887       [NSNumber numberWithInteger:PEPRatingHaveNoKey]: @"have_no_key",
   888       [NSNumber numberWithInteger:PEPRatingUnencrypted]: @"unencrypted",
   889       [NSNumber numberWithInteger:PEPRatingUnencryptedForSome]: @"unencrypted_for_some",
   890       [NSNumber numberWithInteger:PEPRatingUnreliable]: @"unreliable",
   891       [NSNumber numberWithInteger:PEPRatingReliable]: @"reliable",
   892       [NSNumber numberWithInteger:PEPRatingTrusted]: @"trusted",
   893       [NSNumber numberWithInteger:PEPRatingTrustedAndAnonymized]: @"trusted_and_anonymized",
   894       [NSNumber numberWithInteger:PEPRatingFullyAnonymous]: @"fully_anonymous",
   895       [NSNumber numberWithInteger:PEPRatingMistrust]: @"mistrust",
   896       [NSNumber numberWithInteger:PEPRatingB0rken]: @"b0rken",
   897       [NSNumber numberWithInteger:PEPRatingUnderAttack]: @"under_attack",
   898       [NSNumber numberWithInteger:PEPRatingUndefined]: kUndefined,
   899       };
   900     NSMutableDictionary *stringToRatingMutable = [NSMutableDictionary
   901                                                   dictionaryWithCapacity:
   902                                                   ratingToStringIntern.count];
   903     for (NSNumber *ratingNumber in ratingToStringIntern.allKeys) {
   904         NSString *ratingName = [ratingToStringIntern objectForKey:ratingNumber];
   905         [stringToRatingMutable setObject:ratingNumber forKey:ratingName];
   906     }
   907     ratingToString = ratingToStringIntern;
   908     stringToRating = [NSDictionary dictionaryWithDictionary:stringToRatingMutable];
   909 }
   910 
   911 - (PEPRating)ratingFromString:(NSString * _Nonnull)string
   912 {
   913     NSNumber *num = [stringToRating objectForKey:string];
   914     if (num) {
   915         return (PEPRating) [num integerValue];
   916     } else {
   917         return PEPRatingUndefined;
   918     }
   919 }
   920 
   921 - (NSString * _Nonnull)stringFromRating:(PEPRating)rating
   922 {
   923     NSString *stringRating = [ratingToString objectForKey:[NSNumber numberWithInteger:rating]];
   924     if (stringRating) {
   925         return stringRating;
   926     } else {
   927         return kUndefined;
   928     }
   929 }
   930 
   931 - (NSNumber * _Nullable)isPEPUser:(PEPIdentity * _Nonnull)identity
   932                             error:(NSError * _Nullable * _Nullable)error
   933 {
   934     pEp_identity *ident = PEP_identityToStruct(identity);
   935     bool isPEP;
   936     PEPStatus status = (PEPStatus) is_pEp_user(self.session, ident, &isPEP);
   937 
   938     free_identity(ident);
   939 
   940     if ([NSError setError:error fromPEPStatus:status]) {
   941         return nil;
   942     } else {
   943         return [NSNumber numberWithBool:isPEP];
   944     }
   945 }
   946 
   947 - (BOOL)setOwnKey:(PEPIdentity * _Nonnull)identity fingerprint:(NSString * _Nonnull)fingerprint
   948             error:(NSError * _Nullable * _Nullable)error
   949 {
   950     pEp_identity *ident = PEP_identityToStruct(identity);
   951     PEPStatus status = (PEPStatus) set_own_key(self.session, ident,
   952                                                [[fingerprint precomposedStringWithCanonicalMapping]
   953                                                 UTF8String]);
   954     free_identity(ident);
   955 
   956     if (status == PEPStatusOK) {
   957         return YES;
   958     } else {
   959         if (error) {
   960             *error = [NSError errorWithPEPStatus:status];
   961         }
   962         return NO;
   963     }
   964 }
   965 
   966 - (void)configurePassiveModeEnabled:(BOOL)enabled
   967 {
   968     config_passive_mode(_session, enabled);
   969 }
   970 
   971 - (BOOL)setFlags:(PEPIdentityFlags)flags
   972      forIdentity:(PEPIdentity *)identity
   973            error:(NSError * _Nullable * _Nullable)error
   974 {
   975     pEp_identity *ident = PEP_identityToStruct(identity);
   976     PEPStatus status = (PEPStatus) set_identity_flags(self.session, ident, flags);
   977     free_identity(ident);
   978 
   979     if (status == PEPStatusOK) {
   980         return YES;
   981     } else {
   982         if (error) {
   983             *error = [NSError errorWithPEPStatus:status];
   984         }
   985         return NO;
   986     }
   987 }
   988 
   989 - (BOOL)deliverHandshakeResult:(PEPSyncHandshakeResult)result
   990              identitiesSharing:(NSArray<PEPIdentity *> * _Nullable)identitiesSharing
   991                          error:(NSError * _Nullable * _Nullable)error;
   992 {
   993     identity_list *identitiesSharingData = NULL;
   994 
   995     if (identitiesSharing) {
   996         identitiesSharingData = PEP_identityArrayToList(identitiesSharing);
   997     }
   998 
   999     PEPStatus status = (PEPStatus) deliverHandshakeResult(self.session,
  1000                                                           (sync_handshake_result) result,
  1001                                                           identitiesSharingData);
  1002 
  1003     free(identitiesSharingData);
  1004 
  1005     if (status == PEPStatusOK) {
  1006         return YES;
  1007     } else {
  1008         if (error) {
  1009             *error = [NSError errorWithPEPStatus:status];
  1010         }
  1011         return NO;
  1012     }
  1013 }
  1014 
  1015 - (BOOL)trustOwnKeyIdentity:(PEPIdentity * _Nonnull)identity
  1016                       error:(NSError * _Nullable * _Nullable)error
  1017 {
  1018     pEp_identity *ident = PEP_identityToStruct(identity);
  1019     PEPStatus status = (PEPStatus) trust_own_key(self.session, ident);
  1020     free_identity(ident);
  1021 
  1022     if (status == PEPStatusOK) {
  1023         return YES;
  1024     } else {
  1025         if (error) {
  1026             *error = [NSError errorWithPEPStatus:status];
  1027         }
  1028         return NO;
  1029     }
  1030 }
  1031 
  1032 - (PEPColor)colorFromRating:(PEPRating)rating
  1033 {
  1034     return (PEPColor) color_from_rating((PEP_rating) rating);
  1035 }
  1036 
  1037 
  1038 - (BOOL)keyReset:(PEPIdentity * _Nonnull)identity
  1039      fingerprint:(NSString * _Nullable)fingerprint
  1040            error:(NSError * _Nullable * _Nullable)error
  1041 {
  1042     pEp_identity *ident = PEP_identityToStruct(identity);
  1043     const char *fpr = [[fingerprint precomposedStringWithCanonicalMapping] UTF8String];
  1044 
  1045     PEPStatus status = (PEPStatus) key_reset_identity(self.session, ident, fpr);
  1046 
  1047     free_identity(ident);
  1048 
  1049     if (status == PEPStatusOK) {
  1050         return YES;
  1051     } else {
  1052         if (error) {
  1053             *error = [NSError errorWithPEPStatus:status];
  1054         }
  1055         return NO;
  1056     }
  1057 }
  1058 
  1059 - (BOOL)leaveDeviceGroupError:(NSError * _Nullable * _Nullable)error
  1060 {
  1061     PEPStatus status = (PEPStatus) leave_device_group(self.session);
  1062 
  1063     if (status == PEPStatusOK) {
  1064         return YES;
  1065     } else {
  1066         if (error) {
  1067             *error = [NSError errorWithPEPStatus:status];
  1068         }
  1069         return NO;
  1070     }
  1071 }
  1072 
  1073 @end