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