pEpObjCAdapter/PEPInternalSession.m
author Dirk Zimmermann <dirk@pep-project.org>
Wed, 16 May 2018 15:40:37 +0200
changeset 610 3b2e6bc63f51
parent 609 7f464ac46e7a
child 614 f1bf3f2761dc
permissions -rw-r--r--
IOSAD-93 formatting
     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         return nil;
   199     } else {
   200         PEPMessage *msg = [PEPMessage new];
   201         [msg setValuesForKeysWithDictionary:destDict];
   202         return msg;
   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     PEPMessage *encrypted = [PEPMessage new];
   319     [encrypted setValuesForKeysWithDictionary:encryptedDict];
   320     return encrypted;
   321 }
   322 
   323 - (PEPMessage * _Nullable)encryptMessage:(PEPMessage * _Nonnull)message
   324                                    extraKeys:(PEPStringList * _Nullable)extraKeys
   325                                   status:(PEP_STATUS * _Nullable)status
   326                                    error:(NSError * _Nullable * _Nullable)error
   327 {
   328     return [self
   329             encryptMessage:message
   330             extraKeys:extraKeys
   331             encFormat:PEP_enc_PEP
   332             status:status
   333             error:error];
   334 }
   335 
   336 - (PEPDict * _Nullable)encryptMessageDict:(PEPDict * _Nonnull)messageDict
   337                                   forSelf:(PEPIdentity * _Nonnull)ownIdentity
   338                                 extraKeys:(PEPStringList * _Nullable)extraKeys
   339                                    status:(PEP_STATUS * _Nullable)status
   340                                     error:(NSError * _Nullable * _Nullable)error
   341 {
   342     PEP_encrypt_flags_t flags = 0;
   343 
   344     message *_src = PEP_messageDictToStruct([self removeEmptyRecipients:messageDict]);
   345     pEp_identity *ident = PEP_identityToStruct(ownIdentity);
   346     message *_dst = NULL;
   347 
   348     stringlist_t *keysStringList = PEP_arrayToStringlist(extraKeys);
   349 
   350     [self lockWrite];
   351     PEP_STATUS theStatus = encrypt_message_for_self(_session,
   352                                                     ident,
   353                                                     _src,
   354                                                     keysStringList,
   355                                                     &_dst,
   356                                                     PEP_enc_PGP_MIME,
   357                                                     flags);
   358     [self unlockWrite];
   359 
   360     free_stringlist(keysStringList);
   361 
   362     if (status) {
   363         *status = theStatus;
   364     }
   365 
   366     if ([NSError setError:error fromPEPStatus:theStatus]) {
   367         return nil;
   368     }
   369 
   370     NSDictionary *dst_;
   371 
   372     if (_dst) {
   373         dst_ = PEP_messageDictFromStruct(_dst);
   374     }
   375     else {
   376         dst_ = PEP_messageDictFromStruct(_src);
   377     }
   378 
   379     free_message(_src);
   380     free_message(_dst);
   381     free_identity(ident);
   382 
   383     return dst_;
   384 }
   385 
   386 - (PEPMessage * _Nullable)encryptMessage:(PEPMessage * _Nonnull)message
   387                                  forSelf:(PEPIdentity * _Nonnull)ownIdentity
   388                                extraKeys:(PEPStringList * _Nullable)extraKeys
   389                                   status:(PEP_STATUS * _Nullable)status
   390                                    error:(NSError * _Nullable * _Nullable)error
   391 {
   392     PEPDict *target = [self
   393                        encryptMessageDict:message.dictionary
   394                        forSelf:ownIdentity
   395                        extraKeys:extraKeys
   396                        status:status
   397                        error:error];
   398 
   399     PEPMessage *encrypted = [PEPMessage new];
   400     [encrypted setValuesForKeysWithDictionary:target];
   401     return encrypted;
   402 }
   403 
   404 
   405 - (PEPDict * _Nullable)encryptMessageDict:(PEPDict * _Nonnull)messageDict
   406                                     toFpr:(NSString * _Nonnull)toFpr
   407                                 encFormat:(PEP_enc_format)encFormat
   408                                     flags:(PEP_decrypt_flags)flags
   409                                    status:(PEP_STATUS * _Nullable)status
   410                                     error:(NSError * _Nullable * _Nullable)error __deprecated
   411 {
   412     message *src = PEP_messageDictToStruct([self removeEmptyRecipients:messageDict]);
   413     message *dst = NULL;
   414 
   415     [self lockWrite];
   416     PEP_STATUS theStatus =
   417     encrypt_message_and_add_priv_key(_session, src, &dst,
   418                                      [[toFpr precomposedStringWithCanonicalMapping] UTF8String],
   419                                      encFormat, flags);
   420     [self unlockWrite];
   421 
   422     if (status) {
   423         *status = theStatus;
   424     }
   425 
   426     if ([NSError setError:error fromPEPStatus:theStatus]) {
   427         return nil;
   428     }
   429 
   430     if (dst) {
   431         return PEP_messageDictFromStruct(dst);
   432     }
   433 
   434     return nil;
   435 }
   436 
   437 - (PEPMessage * _Nullable)encryptMessage:(PEPMessage * _Nonnull)message
   438                                    toFpr:(NSString * _Nonnull)toFpr
   439                                encFormat:(PEP_enc_format)encFormat
   440                                    flags:(PEP_decrypt_flags)flags
   441                                   status:(PEP_STATUS * _Nullable)status
   442                                    error:(NSError * _Nullable * _Nullable)error
   443 {
   444     PEPDict *target = [self
   445                        encryptMessageDict:message.dictionary
   446                        toFpr:toFpr
   447                        encFormat:encFormat
   448                        flags:flags
   449                        status:status
   450                        error:error];
   451 
   452     PEPMessage *encrypted = [PEPMessage new];
   453     [encrypted setValuesForKeysWithDictionary:target];
   454     return encrypted;
   455 }
   456 
   457 - (NSNumber * _Nullable)outgoingRatingForMessageDict:(PEPDict * _Nonnull)messageDict
   458                                                error:(NSError * _Nullable * _Nullable)error
   459 {
   460     message *_msg = PEP_messageDictToStruct(messageDict);
   461     PEP_rating rating = PEP_rating_undefined;
   462 
   463     [self lockWrite];
   464     PEP_STATUS status = outgoing_message_rating(_session, _msg, &rating);
   465     [self unlockWrite];
   466 
   467     free_message(_msg);
   468 
   469     if ([NSError setError:error fromPEPStatus:status]) {
   470         return nil;
   471     }
   472 
   473     return [NSNumber numberWithPEPRating:rating];
   474 }
   475 
   476 - (NSNumber * _Nullable)outgoingRatingForMessage:(PEPMessage * _Nonnull)message
   477                                            error:(NSError * _Nullable * _Nullable)error
   478 {
   479     return [self outgoingRatingForMessageDict:(NSDictionary *) message error:error];
   480 }
   481 
   482 - (NSNumber * _Nullable)ratingForIdentity:(PEPIdentity * _Nonnull)identity
   483                                     error:(NSError * _Nullable * _Nullable)error
   484 {
   485     pEp_identity *ident = PEP_identityToStruct(identity);
   486     PEP_rating rating = PEP_rating_undefined;
   487 
   488     [self lockWrite];
   489     PEP_STATUS status = identity_rating(_session, ident, &rating);
   490     [self unlockWrite];
   491 
   492     free_identity(ident);
   493 
   494     if ([NSError setError:error fromPEPStatus:status]) {
   495         return nil;
   496     }
   497 
   498     return [NSNumber numberWithPEPRating:rating];
   499 }
   500 
   501 - (NSArray * _Nullable)trustwordsForFingerprint:(NSString * _Nonnull)fingerprint
   502                                      languageID:(NSString * _Nonnull)languageID
   503                                       shortened:(BOOL)shortened
   504                                           error:(NSError * _Nullable * _Nullable)error
   505 {
   506     NSMutableArray *array = [NSMutableArray array];
   507 
   508     for (int i = 0; i < [fingerprint length]; i += 4) {
   509         if (shortened && i >= 20)
   510             break;
   511 
   512         NSString *str = [fingerprint substringWithRange:NSMakeRange(i, 4)];
   513 
   514         unsigned int value;
   515         [[NSScanner scannerWithString:str] scanHexInt:&value];
   516 
   517         PEPAutoPointer *word = [PEPAutoPointer new];
   518         size_t size;
   519 
   520         PEP_STATUS status = trustword(_session,
   521                                       value,
   522                                       [languageID UTF8String],
   523                                       word.charPointerPointer,
   524                                       &size);
   525 
   526         if ([NSError setError:error fromPEPStatus:status]) {
   527             return nil;
   528         }
   529 
   530         [array addObject:[NSString stringWithUTF8String:word.charPointer]];
   531     }
   532 
   533     return array;
   534 }
   535 
   536 - (BOOL)mySelf:(PEPIdentity * _Nonnull)identity error:(NSError * _Nullable * _Nullable)error
   537 {
   538     pEp_identity *ident = PEP_identityToStruct(identity);
   539 
   540     [self lockWrite];
   541     PEP_STATUS status = myself(_session, ident);
   542     [self unlockWrite];
   543 
   544     if ([NSError setError:error fromPEPStatus:status]) {
   545         free_identity(ident);
   546         return NO;
   547     }
   548 
   549     [identity reset];
   550     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   551     free_identity(ident);
   552 
   553     return YES;
   554 }
   555 
   556 - (BOOL)updateIdentity:(PEPIdentity * _Nonnull)identity error:(NSError * _Nullable * _Nullable)error
   557 {
   558     if (identity.isOwn) {
   559         return [self mySelf:identity error:error];
   560     } else {
   561         pEp_identity *ident = PEP_identityToStruct(identity);
   562 
   563         [self lockWrite];
   564         PEP_STATUS status = update_identity(_session, ident);
   565         [self unlockWrite];
   566 
   567         if ([NSError setError:error fromPEPStatus:status]) {
   568             free_identity(ident);
   569             return NO;
   570         }
   571 
   572         [identity reset];
   573         [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   574         free_identity(ident);
   575 
   576         return YES;
   577     }
   578 }
   579 
   580 - (BOOL)trustPersonalKey:(PEPIdentity * _Nonnull)identity
   581                    error:(NSError * _Nullable * _Nullable)error
   582 {
   583     pEp_identity *ident = PEP_identityToStruct(identity);
   584 
   585     [self lockWrite];
   586     PEP_STATUS status = trust_personal_key(_session, ident);
   587     [self unlockWrite];
   588 
   589     if ([NSError setError:error fromPEPStatus:status]) {
   590         free_identity(ident);
   591         return NO;
   592     }
   593 
   594     [identity reset];
   595     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   596     free_identity(ident);
   597     return YES;
   598 }
   599 
   600 - (BOOL)keyMistrusted:(PEPIdentity *)identity error:(NSError * _Nullable * _Nullable)error
   601 {
   602     pEp_identity *ident = PEP_identityToStruct(identity);
   603 
   604     [self lockWrite];
   605     PEP_STATUS status = key_mistrusted(_session, ident);
   606     [self unlockWrite];
   607 
   608     if ([NSError setError:error fromPEPStatus:status]) {
   609         free_identity(ident);
   610         return NO;
   611     }
   612 
   613     [identity reset];
   614     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   615     free_identity(ident);
   616 
   617     return YES;
   618 }
   619 
   620 - (BOOL)keyResetTrust:(PEPIdentity * _Nonnull)identity
   621                 error:(NSError * _Nullable * _Nullable)error
   622 {
   623     pEp_identity *ident = PEP_identityToStruct(identity);
   624 
   625     [self lockWrite];
   626     PEP_STATUS status = key_reset_trust(_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 
   638     return YES;
   639 }
   640 
   641 - (BOOL)importKey:(NSString * _Nonnull)keydata error:(NSError * _Nullable * _Nullable)error
   642 {
   643     [self lockWrite];
   644     PEP_STATUS status = import_key(_session, [keydata UTF8String], [keydata length], NULL);
   645     [self unlockWrite];
   646 
   647     if ([NSError setError:error fromPEPStatus:status]) {
   648         return NO;
   649     }
   650 
   651     return YES;
   652 }
   653 
   654 - (BOOL)logTitle:(NSString * _Nonnull)title
   655           entity:(NSString * _Nonnull)entity
   656      description:(NSString * _Nullable)description
   657          comment:(NSString * _Nullable)comment
   658            error:(NSError * _Nullable * _Nullable)error
   659 {
   660     [self lockWrite];
   661     PEP_STATUS status = log_event(_session,
   662                                   [[title precomposedStringWithCanonicalMapping] UTF8String],
   663                                   [[entity precomposedStringWithCanonicalMapping] UTF8String],
   664                                   [[description precomposedStringWithCanonicalMapping] UTF8String],
   665                                   [[comment precomposedStringWithCanonicalMapping] UTF8String]);
   666     [self unlockWrite];
   667 
   668     if ([NSError setError:error fromPEPStatus:status]) {
   669         return NO;
   670     } else {
   671         return YES;
   672     }
   673 }
   674 
   675 - (NSString * _Nullable)getLogWithError:(NSError * _Nullable * _Nullable)error
   676 {
   677     char *theChars = NULL;
   678     PEP_STATUS status = get_crashdump_log(_session, 0, &theChars);
   679 
   680     if ([NSError setError:error fromPEPStatus:status]) {
   681         return nil;
   682     }
   683 
   684     if (theChars) {
   685         return [NSString stringWithUTF8String:theChars];
   686     } else {
   687         [NSError setError:error fromPEPStatus:PEP_UNKNOWN_ERROR];
   688         return nil;
   689     }
   690 }
   691 
   692 - (NSString * _Nullable)getTrustwordsIdentity1:(PEPIdentity * _Nonnull)identity1
   693                                      identity2:(PEPIdentity * _Nonnull)identity2
   694                                       language:(NSString * _Nullable)language
   695                                           full:(BOOL)full
   696                                          error:(NSError * _Nullable * _Nullable)error
   697 {
   698     pEp_identity *ident1 = PEP_identityToStruct(identity1);
   699     pEp_identity *ident2 = PEP_identityToStruct(identity2);
   700     PEP_STATUS status;
   701 
   702     PEPAutoPointer *trustwords = [PEPAutoPointer new];
   703     size_t sizeWritten = 0;
   704 
   705     [self lockWrite];
   706     status = get_trustwords(_session, ident1, ident2,
   707                             [[language precomposedStringWithCanonicalMapping]
   708                              UTF8String],
   709                             trustwords.charPointerPointer, &sizeWritten, full);
   710     [self unlockWrite];
   711 
   712     NSString *result = nil;
   713 
   714     if (![NSError setError:error fromPEPStatus:status]) {
   715         result = [NSString stringWithCString:trustwords.charPointer
   716                                     encoding:NSUTF8StringEncoding];
   717     }
   718 
   719     return result;
   720 }
   721 
   722 - (NSArray<PEPLanguage *> * _Nullable)languageListWithError:(NSError * _Nullable * _Nullable)error
   723 {
   724     PEPAutoPointer *chLangs = [PEPAutoPointer new];
   725     PEP_STATUS status = get_languagelist(_session, chLangs.charPointerPointer);
   726 
   727     if ([NSError setError:error fromPEPStatus:status]) {
   728         return nil;
   729     }
   730 
   731     NSString *parserInput = [NSString stringWithUTF8String:chLangs.charPointer];
   732 
   733     NSMutableArray<NSString *> *tokens = [NSMutableArray array];
   734     PEPCSVScanner *scanner = [[PEPCSVScanner alloc] initWithString:parserInput];
   735     while (YES) {
   736         NSString *token = [scanner nextString];
   737         if (!token) {
   738             break;
   739         }
   740         [tokens addObject:token];
   741     }
   742     
   743     NSArray *theTokens = [NSArray arrayWithArray:tokens];
   744     NSMutableArray<PEPLanguage *> *langs = [NSMutableArray new];
   745     while (YES) {
   746         ArrayTake *take = [theTokens takeOrNil:3];
   747         if (!take) {
   748             break;
   749         }
   750         NSArray *elements = take.elements;
   751         PEPLanguage *lang = [[PEPLanguage alloc]
   752                              initWithCode:[elements objectAtIndex:0]
   753                              name:[elements objectAtIndex:1]
   754                              sentence:[elements objectAtIndex:2]];
   755         [langs addObject:lang];
   756         theTokens = take.rest;
   757     }
   758     
   759     return [NSArray arrayWithArray:langs];
   760 }
   761 
   762 - (BOOL)undoLastMistrustWithError:(NSError * _Nullable * _Nullable)error;
   763 {
   764     [self lockWrite];
   765     PEP_STATUS status = undo_last_mistrust(_session);
   766     [self unlockWrite];
   767 
   768     if ([NSError setError:error fromPEPStatus:status]) {
   769         return NO;
   770     }
   771 
   772     return YES;
   773 }
   774 
   775 static NSDictionary *ratingToString;
   776 static NSDictionary *stringToRating;
   777 
   778 + (void)initialize
   779 {
   780     NSDictionary *ratingToStringIntern =
   781     @{
   782       [NSNumber numberWithInteger:PEP_rating_cannot_decrypt]: @"cannot_decrypt",
   783       [NSNumber numberWithInteger:PEP_rating_have_no_key]: @"have_no_key",
   784       [NSNumber numberWithInteger:PEP_rating_unencrypted]: @"unencrypted",
   785       [NSNumber numberWithInteger:PEP_rating_unencrypted_for_some]: @"unencrypted_for_some",
   786       [NSNumber numberWithInteger:PEP_rating_unreliable]: @"unreliable",
   787       [NSNumber numberWithInteger:PEP_rating_reliable]: @"reliable",
   788       [NSNumber numberWithInteger:PEP_rating_trusted]: @"trusted",
   789       [NSNumber numberWithInteger:PEP_rating_trusted_and_anonymized]: @"trusted_and_anonymized",
   790       [NSNumber numberWithInteger:PEP_rating_fully_anonymous]: @"fully_anonymous",
   791       [NSNumber numberWithInteger:PEP_rating_mistrust]: @"mistrust",
   792       [NSNumber numberWithInteger:PEP_rating_b0rken]: @"b0rken",
   793       [NSNumber numberWithInteger:PEP_rating_under_attack]: @"under_attack",
   794       [NSNumber numberWithInteger:PEP_rating_undefined]: @"undefined",
   795       };
   796     NSMutableDictionary *stringToRatingMutable = [NSMutableDictionary
   797                                                   dictionaryWithCapacity:
   798                                                   ratingToStringIntern.count];
   799     for (NSNumber *ratingNumber in ratingToStringIntern.allKeys) {
   800         NSString *ratingName = [ratingToStringIntern objectForKey:ratingNumber];
   801         [stringToRatingMutable setObject:ratingNumber forKey:ratingName];
   802     }
   803     ratingToString = ratingToStringIntern;
   804     stringToRating = [NSDictionary dictionaryWithDictionary:stringToRatingMutable];
   805 }
   806 
   807 - (PEP_rating)ratingFromString:(NSString * _Nonnull)string
   808 {
   809     NSNumber *num = [stringToRating objectForKey:string];
   810     if (num) {
   811         return (PEP_rating) [num integerValue];
   812     } else {
   813         return PEP_rating_undefined;
   814     }
   815 }
   816 
   817 - (NSString * _Nonnull)stringFromRating:(PEP_rating)rating
   818 {
   819     NSString *stringRating = [ratingToString objectForKey:[NSNumber numberWithInteger:rating]];
   820     if (stringRating) {
   821         return stringRating;
   822     } else {
   823         return @"undefined";
   824     }
   825 }
   826 
   827 - (NSNumber * _Nullable)isPEPUser:(PEPIdentity * _Nonnull)identity
   828                             error:(NSError * _Nullable * _Nullable)error
   829 {
   830     pEp_identity *ident = PEP_identityToStruct(identity);
   831     bool isPEP;
   832     PEP_STATUS status = is_pep_user(self.session, ident, &isPEP);
   833 
   834     if ([NSError setError:error fromPEPStatus:status]) {
   835         return nil;
   836     } else {
   837         return [NSNumber numberWithBool:isPEP];
   838     }
   839 }
   840 
   841 - (BOOL)setOwnKey:(PEPIdentity * _Nonnull)identity fingerprint:(NSString * _Nonnull)fingerprint
   842             error:(NSError * _Nullable * _Nullable)error
   843 {
   844     pEp_identity *ident = PEP_identityToStruct(identity);
   845     PEP_STATUS status = set_own_key(self.session, ident,
   846                                     [[fingerprint precomposedStringWithCanonicalMapping]
   847                                      UTF8String]);
   848     if (status == PEP_STATUS_OK) {
   849         return YES;
   850     } else {
   851         if (error) {
   852             *error = [NSError errorWithPEPStatus:status];
   853         }
   854         return NO;
   855     }
   856 }
   857 
   858 @end