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