pEpObjCAdapter/PEPSession.m
author Edouard Tisserant <edouard@pep-project.org>
Wed, 27 Sep 2017 17:34:37 +0200
changeset 249 08abeb4fb445
parent 248 a7b17433ebc2
child 250 371630c05842
permissions -rw-r--r--
IOSAD-34 disabled init() / release() critical section, despite of the fact that ++init_count in pEpEngine.c init() is _really_ not thread safe, whatever nonsense comment above says.
     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 "PEPSession.h"
    10 #import "PEPSession+Internal.h"
    11 #import "PEPObjCAdapter.h"
    12 #import "PEPObjCAdapter+Internal.h"
    13 #import "PEPMessage.h"
    14 #import "PEPLanguage.h"
    15 #import "PEPCSVScanner.h"
    16 #import "NSArray+Extension.h"
    17 #import "NSDictionary+Extension.h"
    18 
    19 @implementation PEPSession
    20 
    21 // serialize all session access
    22 + (dispatch_queue_t)sharedSessionQueue
    23 {
    24     static dispatch_once_t once;
    25     static dispatch_queue_t sharedSessionQueue;
    26     dispatch_once(&once, ^{
    27         sharedSessionQueue = dispatch_queue_create("pEp session queue", DISPATCH_QUEUE_CONCURRENT);
    28     });
    29     return sharedSessionQueue;
    30 }
    31 
    32 + (PEPSession *)session
    33 {
    34     PEPSession *_session = [[PEPSession alloc] init];
    35     return _session;
    36 }
    37 
    38 + (void)dispatchAsyncOnSession:(PEPSessionBlock)block
    39 {
    40     dispatch_async([self sharedSessionQueue], ^{
    41         PEPSession *pepSession = [[PEPSession alloc] init];
    42         block(pepSession);
    43     });
    44 }
    45 
    46 + (void)dispatchSyncOnSession:(PEPSessionBlock)block
    47 {
    48     PEPSession *pepSession = [[PEPSession alloc] init];
    49     block(pepSession);
    50 }
    51 
    52 + (void)setupTrustWordsDB
    53 {
    54     static dispatch_once_t once;
    55     dispatch_once(&once, ^{
    56         [PEPObjCAdapter setupTrustWordsDB:[NSBundle bundleForClass:[self class]]];
    57     });
    58 }
    59 
    60 static NSString *threadCountKey = @"PEPSession.threadCount";
    61 //static NSObject *sessionInitLock = nil;
    62 //static dispatch_once_t sessionInitLockOnce;
    63 
    64 - (id)init
    65 {
    66     [PEPSession setupTrustWordsDB];
    67     
    68     // dispatch_once(&sessionInitLockOnce, ^{
    69     //     sessionInitLock = [[NSObject alloc] init];
    70     // });
    71     // @synchronized (sessionInitLock)
    72     {
    73 
    74         PEP_STATUS status = init(&_session);
    75 
    76         if (status != PEP_STATUS_OK) {
    77             return nil;
    78         }
    79 
    80         [PEPObjCAdapter bindSession:self];
    81     }
    82     return self;
    83 }
    84 
    85 - (void)dealloc
    86 {
    87     [PEPObjCAdapter unbindSession:self];
    88 
    89     // @synchronized (sessionInitLock)
    90     {
    91         release(_session);
    92     }
    93 }
    94 
    95 /**
    96  Saves the given message dict as a plist to the local filesystem
    97  (directly under NSApplicationSupportDirectory).
    98  Since the complete output file will be logged by `debugSaveToFilePath`,
    99  you can get access to the files easily when it's the simulator.
   100  */
   101 - (void)debugOutPutMessageDict:(nonnull PEPDict *)src
   102 {
   103     NSString *from = src[kPepFrom][kPepAddress];
   104     NSArray *tos = src[kPepTo];
   105     NSString *to = tos[0][kPepAddress];
   106     NSString *msgID = src[kPepID];
   107     NSString *fileName = [NSString stringWithFormat:@"%@_from(%@)_%@",
   108                           to, from, msgID];
   109     [src debugSaveToFilePath:fileName];
   110 }
   111 
   112 - (PEP_rating)decryptMessageDict:(nonnull PEPDict *)src
   113                             dest:(PEPDict * _Nullable * _Nullable)dst
   114                             keys:(PEPStringList * _Nullable * _Nullable)keys
   115 {
   116     message * _src = PEP_messageDictToStruct(src);
   117     message * _dst = NULL;
   118     stringlist_t * _keys = NULL;
   119     PEP_rating color = PEP_rating_undefined;
   120     PEP_decrypt_flags_t flags = 0;
   121 
   122     @synchronized (self) {
   123         decrypt_message(_session, _src, &_dst, &_keys, &color, &flags);
   124     }
   125 
   126     NSDictionary * dst_;
   127 
   128     if (_dst) {
   129         dst_ = PEP_messageDictFromStruct(_dst);
   130     }
   131     else {
   132         dst_ = PEP_messageDictFromStruct(_src);
   133     }
   134 
   135     NSArray * keys_ = nil;
   136     if (_keys)
   137         keys_ = PEP_arrayFromStringlist(_keys);
   138 
   139     free_message(_src);
   140     free_message(_dst);
   141     free_stringlist(_keys);
   142 
   143     if (dst) {
   144         *dst = dst_;
   145     }
   146     if (keys) {
   147         *keys = keys_;
   148     }
   149     return color;
   150 }
   151 
   152 - (PEP_rating)reEvaluateMessageRating:(nonnull PEPDict *)src
   153 {
   154     message * _src = PEP_messageDictToStruct(src);
   155     PEP_rating color = PEP_rating_undefined;
   156 
   157     @synchronized (self) {
   158         re_evaluate_message_rating(_session, _src, NULL, PEP_rating_undefined, &color);
   159     }
   160 
   161     free_message(_src);
   162 
   163     return color;
   164 }
   165 
   166 - (void)removeEmptyArrayKey:(NSString *)key inDict:(PEPMutableDict *)dict
   167 {
   168     if ([[dict objectForKey:key] count] == 0) {
   169         [dict removeObjectForKey:key];
   170     }
   171 }
   172 
   173 - (NSDictionary *)removeEmptyRecipients:(PEPDict *)src
   174 {
   175     NSMutableDictionary *dest = src.mutableCopy;
   176 
   177     [self removeEmptyArrayKey:kPepTo inDict:dest];
   178     [self removeEmptyArrayKey:kPepCC inDict:dest];
   179     [self removeEmptyArrayKey:kPepBCC inDict:dest];
   180 
   181     return [NSDictionary dictionaryWithDictionary:dest];
   182 }
   183 
   184 - (PEP_STATUS)encryptMessageDict:(nonnull PEPDict *)src
   185                            extra:(nullable NSArray *)keys
   186                             dest:(PEPDict * _Nullable * _Nullable)dst
   187 {
   188     PEP_STATUS status;
   189     PEP_encrypt_flags_t flags = 0;
   190 
   191     message * _src = PEP_messageDictToStruct([self removeEmptyRecipients:src]);
   192     message * _dst = NULL;
   193     stringlist_t * _keys = PEP_arrayToStringlist(keys);
   194 
   195     @synchronized (self) {
   196         status = encrypt_message(_session, _src, _keys, &_dst, PEP_enc_PGP_MIME, flags);
   197     }
   198 
   199     NSDictionary * dst_;
   200 
   201     if (_dst) {
   202         dst_ = PEP_messageDictFromStruct(_dst);
   203     }
   204     else {
   205         dst_ = PEP_messageDictFromStruct(_src);
   206     }
   207     if (dst) {
   208         *dst = dst_;
   209     }
   210 
   211     free_message(_src);
   212     free_message(_dst);
   213     free_stringlist(_keys);
   214 
   215     return status;
   216 }
   217 
   218 - (PEP_STATUS)encryptMessageDict:(nonnull PEPDict *)src
   219                         identity:(nonnull PEPDict *)identity
   220                             dest:(PEPDict * _Nullable * _Nullable)dst
   221 {
   222     PEP_STATUS status;
   223     PEP_encrypt_flags_t flags = 0;
   224 
   225     message * _src = PEP_messageDictToStruct([self removeEmptyRecipients:src]);
   226     pEp_identity *ident = PEP_identityDictToStruct(identity);
   227     message * _dst = NULL;
   228 
   229     @synchronized (self) {
   230         status = encrypt_message_for_self(_session, ident, _src, &_dst, PEP_enc_PGP_MIME, flags);
   231     }
   232 
   233     NSDictionary * dst_;
   234 
   235     if (_dst) {
   236         dst_ = PEP_messageDictFromStruct(_dst);
   237     }
   238     else {
   239         dst_ = PEP_messageDictFromStruct(_src);
   240     }
   241 
   242     if (dst) {
   243         *dst = dst_;
   244     }
   245 
   246     free_message(_src);
   247     free_message(_dst);
   248     free_identity(ident);
   249 
   250     return status;
   251 }
   252 
   253 - (PEP_rating)outgoingMessageColor:(PEPDict *)msg
   254 {
   255     message * _msg = PEP_messageDictToStruct(msg);
   256     PEP_rating color = PEP_rating_undefined;
   257 
   258     @synchronized (self) {
   259         outgoing_message_rating(_session, _msg, &color);
   260     }
   261 
   262     free_message(_msg);
   263 
   264     return color;
   265 }
   266 
   267 - (PEP_rating)identityRating:(nonnull PEPDict *)identity
   268 {
   269     pEp_identity *ident = PEP_identityDictToStruct(identity);
   270     PEP_rating color = PEP_rating_undefined;
   271 
   272     @synchronized (self) {
   273         identity_rating(_session, ident, &color);
   274     }
   275 
   276     free_identity(ident);
   277 
   278     return color;
   279 }
   280 
   281 DYNAMIC_API PEP_STATUS identity_rating(PEP_SESSION session, pEp_identity *ident, PEP_rating *color);
   282 
   283 
   284 - (NSArray *)trustwords:(NSString *)fpr forLanguage:(NSString *)languageID shortened:(BOOL)shortened
   285 {
   286     NSMutableArray *array = [NSMutableArray array];
   287 
   288     for (int i = 0; i < [fpr length]; i += 4) {
   289         if (shortened && i >= 20)
   290             break;
   291 
   292         NSString *str = [fpr substringWithRange:NSMakeRange(i, 4)];
   293 
   294         unsigned int value;
   295         [[NSScanner scannerWithString:str] scanHexInt:&value];
   296 
   297         char *word;
   298         size_t size;
   299 
   300         @synchronized (self) {
   301             trustword(_session, value, [languageID UTF8String], &word, &size);
   302         }
   303 
   304         [array addObject:[NSString stringWithUTF8String:word]];
   305         free(word);
   306     }
   307 
   308     return array;
   309 }
   310 
   311 - (void)mySelf:(PEPMutableDict *)identity
   312 {
   313     [identity removeObjectForKey:kPepUserID];
   314 
   315     pEp_identity *ident = PEP_identityDictToStruct(identity);
   316 
   317     @synchronized(self) {
   318         myself(_session, ident);
   319     }
   320 
   321     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   322     free_identity(ident);
   323 }
   324 
   325 - (void)updateIdentity:(PEPMutableDict *)identity
   326 {
   327     pEp_identity *ident = PEP_identityDictToStruct(identity);
   328 
   329     @synchronized(self) {
   330         update_identity(_session, ident);
   331     }
   332 
   333     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   334     free_identity(ident);
   335 }
   336 
   337 - (void)trustPersonalKey:(PEPMutableDict *)identity
   338 {
   339     pEp_identity *ident = PEP_identityDictToStruct(identity);
   340 
   341     @synchronized(self) {
   342         trust_personal_key(_session, ident);
   343     }
   344 
   345     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   346     free_identity(ident);
   347 }
   348 
   349 - (void)keyResetTrust:(PEPMutableDict *)identity
   350 {
   351     pEp_identity *ident = PEP_identityDictToStruct(identity);
   352 
   353     @synchronized(self) {
   354         key_reset_trust(_session, ident);
   355     }
   356 
   357     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   358     free_identity(ident);
   359 }
   360 
   361 - (void)keyMistrusted:(PEPMutableDict *)identity
   362 {
   363     pEp_identity *ident = PEP_identityDictToStruct(identity);
   364 
   365     @synchronized(self) {
   366         key_mistrusted(_session, ident);
   367     }
   368 
   369     [identity setValuesForKeysWithDictionary:PEP_identityDictFromStruct(ident)];
   370     free_identity(ident);
   371 }
   372 
   373 - (void)importKey:(NSString *)keydata
   374 {
   375     @synchronized(self) {
   376         import_key(_session, [keydata UTF8String], [keydata length], NULL);
   377     }
   378 
   379 }
   380 
   381 - (void)logTitle:(nonnull NSString *)title entity:(nonnull NSString *)entity
   382      description:(nullable NSString *)description comment:(nullable NSString *)comment
   383 {
   384     @synchronized(self) {
   385 
   386         log_event(_session, [[title precomposedStringWithCanonicalMapping] UTF8String],
   387                   [[entity precomposedStringWithCanonicalMapping] UTF8String],
   388                   [[description precomposedStringWithCanonicalMapping] UTF8String],
   389                   [[comment precomposedStringWithCanonicalMapping] UTF8String]);
   390 
   391     }
   392 }
   393 
   394 - (nonnull NSString *)getLog
   395 {
   396     char *data;
   397     get_crashdump_log(self.session, 0, &data);
   398     NSString *logString = [NSString stringWithUTF8String:data];
   399     return logString;
   400 }
   401 
   402 - (nullable NSString *)getTrustwordsIdentity1:(nonnull PEPDict *)identity1
   403                                     identity2:(nonnull PEPDict *)identity2
   404                                      language:(nullable NSString *)language
   405                                          full:(BOOL)full
   406 {
   407     NSString *result = nil;
   408     char *trustwords = nil;
   409     size_t sizeWritten = 0;
   410 
   411     pEp_identity *ident1 = PEP_identityDictToStruct(identity1);
   412     pEp_identity *ident2 = PEP_identityDictToStruct(identity2);
   413     PEP_STATUS status;
   414     @synchronized(self) {
   415 
   416         status = get_trustwords(_session, ident1, ident2,
   417                                            [[language precomposedStringWithCanonicalMapping]
   418                                             UTF8String],
   419                                            &trustwords, &sizeWritten, full);
   420     }
   421     if (status == PEP_STATUS_OK) {
   422         result = [NSString stringWithCString:trustwords
   423                                     encoding:NSUTF8StringEncoding];
   424     }
   425     if (trustwords) {
   426         free(trustwords);
   427     }
   428     return result;
   429 }
   430 
   431 - (nullable NSString *)getTrustwordsMessageDict:(nonnull PEPDict *)messageDict
   432                                    receiverDict:(nonnull PEPDict *)receiverDict
   433                                       keysArray:(PEPStringList * _Nullable)keysArray
   434                                        language:(nullable NSString *)language
   435                                            full:(BOOL)full
   436                                 resultingStatus:(PEP_STATUS * _Nullable)resultingStatus
   437 {
   438     NSString *result = nil;
   439     char *trustwords = nil;
   440 
   441     message *theMessage = PEP_messageDictToStruct(messageDict);
   442 
   443     stringlist_t *keyList = nil;
   444     if (keysArray) {
   445         keyList = PEP_arrayToStringlist(keysArray);
   446     }
   447 
   448     pEp_identity *receiver = PEP_identityDictToStruct(receiverDict);
   449     PEP_STATUS status;
   450     @synchronized(self) {
   451         status = get_message_trustwords(_session, theMessage, keyList, receiver,
   452                                         [[language
   453                                           precomposedStringWithCanonicalMapping] UTF8String],
   454                                         &trustwords, full);
   455     }
   456     
   457     if (resultingStatus) {
   458         *resultingStatus = status;
   459     }
   460 
   461     if (status == PEP_STATUS_OK) {
   462         result = [NSString stringWithCString:trustwords
   463                                     encoding:NSUTF8StringEncoding];
   464     }
   465     if (trustwords) {
   466         free(trustwords);
   467     }
   468     return result;
   469 }
   470 
   471 - (NSArray<PEPLanguage *> * _Nonnull)languageList
   472 {
   473     char *chLangs;
   474     get_languagelist(self.session, &chLangs);
   475     NSString *parserInput = [NSString stringWithUTF8String:chLangs];
   476 
   477     NSMutableArray<NSString *> *tokens = [NSMutableArray array];
   478     PEPCSVScanner *scanner = [[PEPCSVScanner alloc] initWithString:parserInput];
   479     while (YES) {
   480         NSString *token = [scanner nextString];
   481         if (!token) {
   482             break;
   483         }
   484         [tokens addObject:token];
   485     }
   486 
   487     NSArray *theTokens = [NSArray arrayWithArray:tokens];
   488     NSMutableArray<PEPLanguage *> *langs = [NSMutableArray new];
   489     while (YES) {
   490         ArrayTake *take = [theTokens takeOrNil:3];
   491         if (!take) {
   492             break;
   493         }
   494         NSArray *elements = take.elements;
   495         PEPLanguage *lang = [[PEPLanguage alloc]
   496                              initWithCode:[elements objectAtIndex:0]
   497                              name:[elements objectAtIndex:1]
   498                              sentence:[elements objectAtIndex:2]];
   499         [langs addObject:lang];
   500         theTokens = take.rest;
   501     }
   502     
   503     return [NSArray arrayWithArray:langs];
   504 }
   505 
   506 @end