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