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