pEpObjCAdapter/PEPInternalSession.m
author Dirk Zimmermann <dz@pep.security>
Thu, 12 Sep 2019 16:41:52 +0200
branchIOSAD-141
changeset 1245 cd15ff3a40b9
parent 1241 3b625296d61e
child 1247 ec96c9c3248e
permissions -rw-r--r--
IOSAD-141 Don't share session between threads.
     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) outgoing_message_rating(_session,
   473                                                            _msg,
   474                                                            (PEP_rating *) &rating);
   475 
   476     free_message(_msg);
   477 
   478     if ([NSError setError:error fromPEPStatus:status]) {
   479         return nil;
   480     }
   481 
   482     return [NSNumber numberWithPEPRating:rating];
   483 }
   484 
   485 - (NSNumber * _Nullable)outgoingRatingForMessage:(PEPMessage * _Nonnull)theMessage
   486                                            error:(NSError * _Nullable * _Nullable)error
   487 {
   488     return [self
   489             helperOutgoingRatingForMessage:theMessage
   490             ratingFunction:&outgoing_message_rating
   491             error:error];
   492 }
   493 
   494 - (NSNumber * _Nullable)outgoingRatingPreviewForMessage:(PEPMessage * _Nonnull)theMessage
   495                                                   error:(NSError * _Nullable * _Nullable)error
   496 {
   497     return [self
   498             helperOutgoingRatingForMessage:theMessage
   499             ratingFunction:&outgoing_message_rating_preview
   500             error:error];
   501 }
   502 
   503 - (NSNumber * _Nullable)ratingForIdentity:(PEPIdentity * _Nonnull)identity
   504                                     error:(NSError * _Nullable * _Nullable)error
   505 {
   506     pEp_identity *ident = PEP_identityToStruct(identity);
   507     PEPRating rating = PEPRatingUndefined;
   508 
   509     PEPStatus status = (PEPStatus) identity_rating(_session, ident, (PEP_rating *) &rating);
   510 
   511     free_identity(ident);
   512 
   513     if ([NSError setError:error fromPEPStatus:status]) {
   514         return nil;
   515     }
   516 
   517     return [NSNumber numberWithPEPRating:rating];
   518 }
   519 
   520 - (NSArray * _Nullable)trustwordsForFingerprint:(NSString * _Nonnull)fingerprint
   521                                      languageID:(NSString * _Nonnull)languageID
   522                                       shortened:(BOOL)shortened
   523                                           error:(NSError * _Nullable * _Nullable)error
   524 {
   525     NSMutableArray *array = [NSMutableArray array];
   526 
   527     for (int i = 0; i < [fingerprint length]; i += 4) {
   528         if (shortened && i >= 20)
   529             break;
   530 
   531         NSString *str = [fingerprint substringWithRange:NSMakeRange(i, 4)];
   532 
   533         unsigned int value;
   534         [[NSScanner scannerWithString:str] scanHexInt:&value];
   535 
   536         PEPAutoPointer *word = [PEPAutoPointer new];
   537         size_t size;
   538 
   539         PEPStatus status = (PEPStatus) trustword(_session,
   540                                                  value,
   541                                                  [[languageID precomposedStringWithCanonicalMapping]
   542                                                   UTF8String],
   543                                                  word.charPointerPointer,
   544                                                  &size);
   545 
   546         if ([NSError setError:error fromPEPStatus:status]) {
   547             return nil;
   548         }
   549 
   550         [array addObject:[NSString stringWithUTF8String:word.charPointer]];
   551     }
   552 
   553     return array;
   554 }
   555 
   556 - (BOOL)mySelf:(PEPIdentity * _Nonnull)identity error:(NSError * _Nullable * _Nullable)error
   557 {
   558     pEp_identity *ident = PEP_identityToStruct(identity);
   559 
   560     PEPStatus status = (PEPStatus) myself(_session, ident);
   561 
   562     if ([NSError setError:error fromPEPStatus:status]) {
   563         free_identity(ident);
   564         return NO;
   565     }
   566 
   567     [identity reset];
   568     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   569     free_identity(ident);
   570 
   571     return YES;
   572 }
   573 
   574 - (BOOL)updateIdentity:(PEPIdentity * _Nonnull)identity error:(NSError * _Nullable * _Nullable)error
   575 {
   576     if (identity.isOwn) {
   577         return [self mySelf:identity error:error];
   578     } else {
   579         pEp_identity *ident = PEP_identityToStruct(identity);
   580 
   581         PEPStatus status = (PEPStatus) update_identity(_session, ident);
   582         
   583         if ([NSError setError:error fromPEPStatus:status]) {
   584             free_identity(ident);
   585             return NO;
   586         }
   587 
   588         [identity reset];
   589         [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   590         free_identity(ident);
   591 
   592         return YES;
   593     }
   594 }
   595 
   596 - (BOOL)trustPersonalKey:(PEPIdentity * _Nonnull)identity
   597                    error:(NSError * _Nullable * _Nullable)error
   598 {
   599     pEp_identity *ident = PEP_identityToStruct(identity);
   600 
   601     PEPStatus status = (PEPStatus) trust_personal_key(_session, ident);
   602 
   603     if ([NSError setError:error fromPEPStatus:status]) {
   604         free_identity(ident);
   605         return NO;
   606     }
   607 
   608     [identity reset];
   609     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   610     free_identity(ident);
   611     return YES;
   612 }
   613 
   614 - (BOOL)keyMistrusted:(PEPIdentity *)identity error:(NSError * _Nullable * _Nullable)error
   615 {
   616     pEp_identity *ident = PEP_identityToStruct(identity);
   617 
   618     PEPStatus status = (PEPStatus) key_mistrusted(_session, ident);
   619 
   620     if ([NSError setError:error fromPEPStatus:status]) {
   621         free_identity(ident);
   622         return NO;
   623     }
   624 
   625     [identity reset];
   626     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   627     free_identity(ident);
   628 
   629     return YES;
   630 }
   631 
   632 - (BOOL)keyResetTrust:(PEPIdentity * _Nonnull)identity
   633                 error:(NSError * _Nullable * _Nullable)error
   634 {
   635     pEp_identity *ident = PEP_identityToStruct(identity);
   636 
   637     PEPStatus status = (PEPStatus) key_reset_trust(_session, ident);
   638 
   639     if ([NSError setError:error fromPEPStatus:status]) {
   640         free_identity(ident);
   641         return NO;
   642     }
   643 
   644     [identity reset];
   645     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   646     free_identity(ident);
   647 
   648     return YES;
   649 }
   650 
   651 - (BOOL)enableSyncForIdentity:(PEPIdentity * _Nonnull)identity
   652                         error:(NSError * _Nullable * _Nullable)error
   653 {
   654     if (!identity.isOwn) {
   655         [NSError setError:error fromPEPStatus:PEPStatusIllegalValue];
   656         return NO;
   657     }
   658 
   659     pEp_identity *ident = PEP_identityToStruct(identity);
   660 
   661     PEPStatus status = (PEPStatus) enable_identity_for_sync(_session, ident);
   662 
   663     if ([NSError setError:error fromPEPStatus:status]) {
   664         free_identity(ident);
   665         return NO;
   666     }
   667 
   668     free_identity(ident);
   669 
   670     return YES;
   671 }
   672 
   673 - (BOOL)disableSyncForIdentity:(PEPIdentity * _Nonnull)identity
   674                          error:(NSError * _Nullable * _Nullable)error
   675 {
   676     if (!identity.isOwn) {
   677         [NSError setError:error fromPEPStatus:PEPStatusIllegalValue];
   678         return NO;
   679     }
   680 
   681     pEp_identity *ident = PEP_identityToStruct(identity);
   682 
   683     PEPStatus status = (PEPStatus) disable_identity_for_sync(_session, ident);
   684 
   685     if ([NSError setError:error fromPEPStatus:status]) {
   686         free_identity(ident);
   687         return NO;
   688     }
   689 
   690     free_identity(ident);
   691 
   692     return YES;
   693 }
   694 
   695 - (NSNumber * _Nullable)queryKeySyncEnabledForIdentity:(PEPIdentity * _Nonnull)identity
   696                                                  error:(NSError * _Nullable * _Nullable)error
   697 {
   698     pEp_identity *ident = PEP_identityToStruct(identity);
   699 
   700     if (!identity.isOwn) {
   701         [NSError setError:error fromPEPStatus:PEPStatusIllegalValue];
   702         return nil;
   703     }
   704 
   705     PEPStatus status = (PEPStatus) myself(_session, ident);
   706 
   707     if ([NSError setError:error fromPEPStatus:status]) {
   708         free_identity(ident);
   709         return nil;
   710     }
   711 
   712     identity_flags_t flags = ident->flags;
   713 
   714     free_identity(ident);
   715 
   716     if (flags & PEP_idf_not_for_sync) {
   717         return [NSNumber numberWithBool:NO];
   718     } else {
   719         return [NSNumber numberWithBool:YES];
   720     }
   721 }
   722 
   723 - (NSArray<PEPIdentity *> * _Nullable)importKey:(NSString * _Nonnull)keydata
   724                                           error:(NSError * _Nullable * _Nullable)error
   725 {
   726     identity_list *identList = NULL;
   727 
   728     PEPStatus status = (PEPStatus) import_key(_session,
   729                                               [[keydata precomposedStringWithCanonicalMapping] UTF8String],
   730                                               [keydata length], &identList);
   731 
   732     if ([NSError setError:error fromPEPStatus:status]) {
   733         free(identList);
   734         return nil;
   735     }
   736 
   737     NSArray *idents = PEP_arrayFromIdentityList(identList);
   738     free(identList);
   739 
   740     return idents;
   741 }
   742 
   743 - (BOOL)logTitle:(NSString * _Nonnull)title
   744           entity:(NSString * _Nonnull)entity
   745      description:(NSString * _Nullable)description
   746          comment:(NSString * _Nullable)comment
   747            error:(NSError * _Nullable * _Nullable)error
   748 {
   749     PEPStatus status = (PEPStatus) log_event(_session,
   750                                              [[title precomposedStringWithCanonicalMapping]
   751                                               UTF8String],
   752                                              [[entity precomposedStringWithCanonicalMapping]
   753                                               UTF8String],
   754                                              [[description precomposedStringWithCanonicalMapping]
   755                                               UTF8String],
   756                                              [[comment precomposedStringWithCanonicalMapping]
   757                                               UTF8String]);
   758 
   759     if ([NSError setError:error fromPEPStatus:status]) {
   760         return NO;
   761     } else {
   762         return YES;
   763     }
   764 }
   765 
   766 - (NSString * _Nullable)getLogWithError:(NSError * _Nullable * _Nullable)error
   767 {
   768     char *theChars = NULL;
   769     PEPStatus status = (PEPStatus) get_crashdump_log(_session, 0, &theChars);
   770 
   771     if ([NSError setError:error fromPEPStatus:status]) {
   772         return nil;
   773     }
   774 
   775     if (theChars) {
   776         return [NSString stringWithUTF8String:theChars];
   777     } else {
   778         [NSError setError:error fromPEPStatusInternal:PEP_UNKNOWN_ERROR];
   779         return nil;
   780     }
   781 }
   782 
   783 - (NSString * _Nullable)getTrustwordsIdentity1:(PEPIdentity * _Nonnull)identity1
   784                                      identity2:(PEPIdentity * _Nonnull)identity2
   785                                       language:(NSString * _Nullable)language
   786                                           full:(BOOL)full
   787                                          error:(NSError * _Nullable * _Nullable)error
   788 {
   789     pEp_identity *ident1 = PEP_identityToStruct(identity1);
   790     pEp_identity *ident2 = PEP_identityToStruct(identity2);
   791     PEPStatus status;
   792 
   793     PEPAutoPointer *trustwords = [PEPAutoPointer new];
   794     size_t sizeWritten = 0;
   795 
   796     status = (PEPStatus) get_trustwords(_session, ident1, ident2,
   797                                         [[language precomposedStringWithCanonicalMapping]
   798                                          UTF8String],
   799                                         trustwords.charPointerPointer, &sizeWritten, full);
   800 
   801     free_identity(ident1);
   802     free_identity(ident2);
   803 
   804     NSString *result = nil;
   805 
   806     if (![NSError setError:error fromPEPStatus:status]) {
   807         result = [NSString stringWithUTF8String:trustwords.charPointer];
   808     }
   809 
   810     return result;
   811 }
   812 
   813 - (NSString * _Nullable)getTrustwordsFpr1:(NSString * _Nonnull)fpr1
   814                                      fpr2:(NSString * _Nonnull)fpr2
   815                                  language:(NSString * _Nullable)language
   816                                      full:(BOOL)full
   817                                     error:(NSError * _Nullable * _Nullable)error
   818 {
   819     const char *_fpr1 = [fpr1 UTF8String]; // fprs are NFC normalized anyway
   820     const char *_fpr2 = [fpr2 UTF8String];
   821     
   822     PEPStatus status;
   823     
   824     PEPAutoPointer *trustwords = [PEPAutoPointer new];
   825     size_t sizeWritten = 0;
   826 
   827     status = (PEPStatus) get_trustwords_for_fprs(_session, _fpr1, _fpr2,
   828                                                  [[language precomposedStringWithCanonicalMapping]
   829                                                   UTF8String],
   830                                                  trustwords.charPointerPointer, &sizeWritten, full);
   831     
   832     NSString *result = nil;
   833     
   834     if (![NSError setError:error fromPEPStatus:status]) {
   835         result = [NSString stringWithUTF8String:trustwords.charPointer];
   836     }
   837     
   838     return result;
   839 }
   840 
   841 - (NSArray<PEPLanguage *> * _Nullable)languageListWithError:(NSError * _Nullable * _Nullable)error
   842 {
   843     PEPAutoPointer *chLangs = [PEPAutoPointer new];
   844     PEPStatus status = (PEPStatus) get_languagelist(_session, chLangs.charPointerPointer);
   845 
   846     if ([NSError setError:error fromPEPStatus:status]) {
   847         return nil;
   848     }
   849 
   850     NSString *parserInput = [NSString stringWithUTF8String:chLangs.charPointer];
   851 
   852     NSMutableArray<NSString *> *tokens = [NSMutableArray array];
   853     PEPCSVScanner *scanner = [[PEPCSVScanner alloc] initWithString:parserInput];
   854     while (YES) {
   855         NSString *token = [scanner nextString];
   856         if (!token) {
   857             break;
   858         }
   859         [tokens addObject:token];
   860     }
   861     
   862     NSArray *theTokens = [NSArray arrayWithArray:tokens];
   863     NSMutableArray<PEPLanguage *> *langs = [NSMutableArray new];
   864     while (YES) {
   865         ArrayTake *take = [theTokens takeOrNil:3];
   866         if (!take) {
   867             break;
   868         }
   869         NSArray *elements = take.elements;
   870         PEPLanguage *lang = [[PEPLanguage alloc]
   871                              initWithCode:[elements objectAtIndex:0]
   872                              name:[elements objectAtIndex:1]
   873                              sentence:[elements objectAtIndex:2]];
   874         [langs addObject:lang];
   875         theTokens = take.rest;
   876     }
   877     
   878     return [NSArray arrayWithArray:langs];
   879 }
   880 
   881 static NSDictionary *ratingToString;
   882 static NSDictionary *stringToRating;
   883 
   884 + (void)initialize
   885 {
   886     NSDictionary *ratingToStringIntern =
   887     @{
   888       [NSNumber numberWithInteger:PEPRatingCannotDecrypt]: @"cannot_decrypt",
   889       [NSNumber numberWithInteger:PEPRatingHaveNoKey]: @"have_no_key",
   890       [NSNumber numberWithInteger:PEPRatingUnencrypted]: @"unencrypted",
   891       [NSNumber numberWithInteger:PEPRatingUnencryptedForSome]: @"unencrypted_for_some",
   892       [NSNumber numberWithInteger:PEPRatingUnreliable]: @"unreliable",
   893       [NSNumber numberWithInteger:PEPRatingReliable]: @"reliable",
   894       [NSNumber numberWithInteger:PEPRatingTrusted]: @"trusted",
   895       [NSNumber numberWithInteger:PEPRatingTrustedAndAnonymized]: @"trusted_and_anonymized",
   896       [NSNumber numberWithInteger:PEPRatingFullyAnonymous]: @"fully_anonymous",
   897       [NSNumber numberWithInteger:PEPRatingMistrust]: @"mistrust",
   898       [NSNumber numberWithInteger:PEPRatingB0rken]: @"b0rken",
   899       [NSNumber numberWithInteger:PEPRatingUnderAttack]: @"under_attack",
   900       [NSNumber numberWithInteger:PEPRatingUndefined]: kUndefined,
   901       };
   902     NSMutableDictionary *stringToRatingMutable = [NSMutableDictionary
   903                                                   dictionaryWithCapacity:
   904                                                   ratingToStringIntern.count];
   905     for (NSNumber *ratingNumber in ratingToStringIntern.allKeys) {
   906         NSString *ratingName = [ratingToStringIntern objectForKey:ratingNumber];
   907         [stringToRatingMutable setObject:ratingNumber forKey:ratingName];
   908     }
   909     ratingToString = ratingToStringIntern;
   910     stringToRating = [NSDictionary dictionaryWithDictionary:stringToRatingMutable];
   911 }
   912 
   913 - (PEPRating)ratingFromString:(NSString * _Nonnull)string
   914 {
   915     NSNumber *num = [stringToRating objectForKey:string];
   916     if (num) {
   917         return (PEPRating) [num integerValue];
   918     } else {
   919         return PEPRatingUndefined;
   920     }
   921 }
   922 
   923 - (NSString * _Nonnull)stringFromRating:(PEPRating)rating
   924 {
   925     NSString *stringRating = [ratingToString objectForKey:[NSNumber numberWithInteger:rating]];
   926     if (stringRating) {
   927         return stringRating;
   928     } else {
   929         return kUndefined;
   930     }
   931 }
   932 
   933 - (NSNumber * _Nullable)isPEPUser:(PEPIdentity * _Nonnull)identity
   934                             error:(NSError * _Nullable * _Nullable)error
   935 {
   936     pEp_identity *ident = PEP_identityToStruct(identity);
   937     bool isPEP;
   938     PEPStatus status = (PEPStatus) is_pEp_user(self.session, ident, &isPEP);
   939 
   940     free_identity(ident);
   941 
   942     if ([NSError setError:error fromPEPStatus:status]) {
   943         return nil;
   944     } else {
   945         return [NSNumber numberWithBool:isPEP];
   946     }
   947 }
   948 
   949 - (BOOL)setOwnKey:(PEPIdentity * _Nonnull)identity fingerprint:(NSString * _Nonnull)fingerprint
   950             error:(NSError * _Nullable * _Nullable)error
   951 {
   952     pEp_identity *ident = PEP_identityToStruct(identity);
   953     PEPStatus status = (PEPStatus) set_own_key(self.session, ident,
   954                                                [[fingerprint precomposedStringWithCanonicalMapping]
   955                                                 UTF8String]);
   956     free_identity(ident);
   957 
   958     if (status == PEPStatusOK) {
   959         return YES;
   960     } else {
   961         if (error) {
   962             *error = [NSError errorWithPEPStatus:status];
   963         }
   964         return NO;
   965     }
   966 }
   967 
   968 - (void)configurePassiveModeEnabled:(BOOL)enabled
   969 {
   970     config_passive_mode(_session, enabled);
   971 }
   972 
   973 - (BOOL)setFlags:(PEPIdentityFlags)flags
   974      forIdentity:(PEPIdentity *)identity
   975            error:(NSError * _Nullable * _Nullable)error
   976 {
   977     pEp_identity *ident = PEP_identityToStruct(identity);
   978     PEPStatus status = (PEPStatus) set_identity_flags(self.session, ident, flags);
   979     free_identity(ident);
   980 
   981     if (status == PEPStatusOK) {
   982         return YES;
   983     } else {
   984         if (error) {
   985             *error = [NSError errorWithPEPStatus:status];
   986         }
   987         return NO;
   988     }
   989 }
   990 
   991 - (BOOL)deliverHandshakeResult:(PEPSyncHandshakeResult)result
   992              identitiesSharing:(NSArray<PEPIdentity *> * _Nullable)identitiesSharing
   993                          error:(NSError * _Nullable * _Nullable)error;
   994 {
   995     identity_list *identitiesSharingData = NULL;
   996 
   997     if (identitiesSharing) {
   998         identitiesSharingData = PEP_identityArrayToList(identitiesSharing);
   999     }
  1000 
  1001     PEPStatus status = (PEPStatus) deliverHandshakeResult(self.session,
  1002                                                           (sync_handshake_result) result,
  1003                                                           identitiesSharingData);
  1004 
  1005     free(identitiesSharingData);
  1006 
  1007     if (status == PEPStatusOK) {
  1008         return YES;
  1009     } else {
  1010         if (error) {
  1011             *error = [NSError errorWithPEPStatus:status];
  1012         }
  1013         return NO;
  1014     }
  1015 }
  1016 
  1017 - (BOOL)trustOwnKeyIdentity:(PEPIdentity * _Nonnull)identity
  1018                       error:(NSError * _Nullable * _Nullable)error
  1019 {
  1020     pEp_identity *ident = PEP_identityToStruct(identity);
  1021     PEPStatus status = (PEPStatus) trust_own_key(self.session, ident);
  1022     free_identity(ident);
  1023 
  1024     if (status == PEPStatusOK) {
  1025         return YES;
  1026     } else {
  1027         if (error) {
  1028             *error = [NSError errorWithPEPStatus:status];
  1029         }
  1030         return NO;
  1031     }
  1032 }
  1033 
  1034 - (PEPColor)colorFromRating:(PEPRating)rating
  1035 {
  1036     return (PEPColor) color_from_rating((PEP_rating) rating);
  1037 }
  1038 
  1039 
  1040 - (BOOL)keyReset:(PEPIdentity * _Nonnull)identity
  1041      fingerprint:(NSString * _Nullable)fingerprint
  1042            error:(NSError * _Nullable * _Nullable)error
  1043 {
  1044     pEp_identity *ident = PEP_identityToStruct(identity);
  1045     const char *fpr = [[fingerprint precomposedStringWithCanonicalMapping] UTF8String];
  1046 
  1047     PEPStatus status = (PEPStatus) key_reset_identity(self.session, ident, fpr);
  1048 
  1049     free_identity(ident);
  1050 
  1051     if (status == PEPStatusOK) {
  1052         return YES;
  1053     } else {
  1054         if (error) {
  1055             *error = [NSError errorWithPEPStatus:status];
  1056         }
  1057         return NO;
  1058     }
  1059 }
  1060 
  1061 - (BOOL)leaveDeviceGroupError:(NSError * _Nullable * _Nullable)error
  1062 {
  1063     PEPStatus status = (PEPStatus) leave_device_group(self.session);
  1064 
  1065     if (status == PEPStatusOK) {
  1066         return YES;
  1067     } else {
  1068         if (error) {
  1069             *error = [NSError errorWithPEPStatus:status];
  1070         }
  1071         return NO;
  1072     }
  1073 }
  1074 
  1075 @end