source: branches/CoreData/SapphireFrappliance/FRAppliance/SapphireImportHelper.m @ 616

Revision 616, 10.4 KB checked in by gbooker, 6 years ago (diff)

Don't merge changes as it doesn't actualy read from the disk at all!!!! We need to make sure we are saved up at all times and then make all merge changes to NO

Line 
1/*
2 * SapphireImportHelper.m
3 * Sapphire
4 *
5 * Created by Graham Booker on Dec. 8, 2007.
6 * Copyright 2007 Sapphire Development Team and/or www.nanopi.net
7 * All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License as published by the Free Software Foundation; either version 3 of the License,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
14 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 * Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along with this program; if not,
18 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21#import <Security/Security.h>
22#include <sys/stat.h>
23#include <sys/mount.h>
24
25#import "SapphireImportHelper.h"
26#import "SapphireMetaData.h"
27#import "SapphireAllImporter.h"
28#import "SapphireFileDataImporter.h"
29#import "SapphireTVShowImporter.h"
30#import "SapphireMovieImporter.h"
31#import "SapphireFileMetaData.h"
32
33#define CONNECTION_NAME @"Sapphire Server"
34
35@interface SapphireImportFile : NSObject <SapphireImportFileProtocol>{
36        NSString                                                                *path;
37        id <SapphireImporterBackgroundProtocol> informer;
38        ImportType                                                              type;
39}
40- (id)initWithPath:(NSString *)aPath informer:(id <SapphireImporterBackgroundProtocol>)aInformer type:(ImportType)aType;
41@end
42
43@interface SapphireImportHelperServer (private)
44- (void)startClient;
45@end
46
47@implementation SapphireImportHelper
48
49static SapphireImportHelper *shared = nil;
50
51+ (SapphireImportHelper *)sharedHelperForContext:(NSManagedObjectContext *)moc
52{
53        if(shared == nil)
54                shared = [[SapphireImportHelperServer alloc] initWithContext:moc];
55
56        return shared;
57}
58
59+ (void)relinquishHelper
60{
61        if(shared != nil)
62                [shared relinquishHelper];
63}
64
65- (void)relinquishHelper
66{
67}
68
69- (void)importFileData:(SapphireFileMetaData *)file inform:(id <SapphireImporterBackgroundProtocol>)inform;
70{
71}
72
73- (void)importAllData:(SapphireFileMetaData *)file inform:(id <SapphireImporterBackgroundProtocol>)inform;
74{
75}
76
77- (void)removeObjectsWithInform:(id <SapphireImporterBackgroundProtocol>)inform
78{
79}
80
81@end
82
83@implementation SapphireImportHelperClient
84
85- (id)initWithContext:(NSManagedObjectContext *)context
86{
87        self = [super init];
88        if(!self)
89                return nil;
90       
91        moc = [context retain];
92        SapphireFileDataImporter *fileImp = [[SapphireFileDataImporter alloc] init];
93        SapphireTVShowImporter *tvImp = [[SapphireTVShowImporter alloc] initWithContext:moc];
94        SapphireMovieImporter *movImp = [[SapphireMovieImporter alloc] initWithContext:moc];
95        allImporter = [[SapphireAllImporter alloc] initWithImporters:[NSArray arrayWithObjects:tvImp,movImp,fileImp,nil]];
96        [fileImp release];
97        [tvImp release];
98        [movImp release];
99        keepRunning = YES;
100       
101        return self;
102}
103- (void) dealloc
104{
105        [server release];
106        [allImporter release];
107        [moc release];
108        [super dealloc];
109}
110
111- (void)importFileData:(SapphireFileMetaData *)file inform:(id <SapphireImporterBackgroundProtocol>)inform;
112{
113        updateMetaData(file);
114}
115
116- (void)startChild
117{
118        /*Child here*/
119        @try {
120                NSConnection *connection = [NSConnection connectionWithRegisteredName:CONNECTION_NAME host:nil];
121                id serverobj = [[connection rootProxy] retain];
122                [serverobj setProtocolForProxy:@protocol(SapphireImportServer)];
123                shared = self;
124                [serverobj setClient:(SapphireImportHelperClient *)shared];
125                server = serverobj;     
126                [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectionDidDie:) name:NSConnectionDidDieNotification object:nil];           
127        }
128        @catch (NSException * e) {
129                keepRunning = NO;
130        }
131}
132
133- (BOOL)keepRunning
134{
135        return keepRunning;
136}
137
138- (void)connectionDidDie:(NSNotification *)note
139{
140        [self exitChild];
141}
142
143- (oneway void)exitChild
144{
145        keepRunning = NO;
146}
147
148- (oneway void)startQueue
149{
150        id <SapphireImportFileProtocol> file = nil;
151        while((file = [server nextFile]) != nil)
152        {
153                NSAutoreleasePool *singleImportPool = [[NSAutoreleasePool alloc] init];
154                ImportType type = [file importType];
155                BOOL ret;
156                NSString *path = [file path];
157                SapphireFileMetaData *file = [SapphireFileMetaData fileWithPath:path inContext:moc];
158                [moc refreshObject:file mergeChanges:NO];
159                if(type == IMPORT_TYPE_FILE_DATA)
160                        ret = updateMetaData(file);
161                else
162                        ret = ([allImporter importMetaData:file] == IMPORT_STATE_UPDATED);
163                NSError *error = nil;
164                [moc save:&error];
165                [server importComplete:ret];
166                [singleImportPool release];
167        }
168}
169@end
170
171@implementation SapphireImportHelperServer
172
173- (id)initWithContext:(NSManagedObjectContext *)context
174{
175        self = [super init];
176        if (self == nil)
177                return nil;
178       
179        queue = [[NSMutableArray alloc] init];
180        queueSuspended = NO;
181       
182        serverConnection = [NSConnection defaultConnection];
183        [serverConnection setRootObject:self];
184        if([serverConnection registerName:CONNECTION_NAME] == NO)
185                NSLog(@"Register failed");
186       
187        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(connectionDidDie:) name:NSConnectionDidDieNotification object:nil];
188        moc = [context retain];
189       
190        [self startClient];
191       
192        return self;
193}
194
195- (void) dealloc
196{
197        [[NSNotificationCenter defaultCenter] removeObserver:self];
198        [client release];
199        [moc release];
200        [queue release];
201        [currentImporting release];
202        [super dealloc];
203}
204
205- (void)relinquishHelper
206{
207        [client exitChild];
208        [serverConnection registerName:nil];
209        [serverConnection setRootObject:nil];
210        [shared autorelease];
211        shared = nil;
212}
213
214- (BOOL)isSlashReadOnly
215{
216        struct statfs *mntbufp;
217       
218    int i, mountCount = getmntinfo(&mntbufp, MNT_NOWAIT);
219        for(i=0; i<mountCount; i++)
220        {
221                if(!strcmp(mntbufp[i].f_mntonname, "/"))
222                        return (mntbufp[i].f_flags & MNT_RDONLY) ? YES : NO;
223        }
224       
225        return NO;
226}
227
228- (BOOL)fixClientPermissions:(NSString *)path
229{
230        /* Permissions are incorrect */
231        AuthorizationItem authItems[2] = {
232                {kAuthorizationEnvironmentUsername, strlen("frontrow"), "frontrow", 0},
233                {kAuthorizationEnvironmentPassword, strlen("frontrow"), "frontrow", 0},
234        };
235        AuthorizationEnvironment environ = {2, authItems};
236        AuthorizationItem rightSet[] = {{kAuthorizationRightExecute, 0, NULL, 0}};
237        AuthorizationRights rights = {1, rightSet};
238        AuthorizationRef auth;
239        OSStatus result = AuthorizationCreate(&rights, &environ, kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights, &auth);
240        if(result == errAuthorizationSuccess)
241        {
242                BOOL roslash = [self isSlashReadOnly];
243                if(roslash)
244                {
245                        char *command = "mount -uw /";
246                        char *arguments[] = {"-c", command, NULL};
247                        AuthorizationExecuteWithPrivileges(auth, "/bin/sh", kAuthorizationFlagDefaults, arguments, NULL);
248                }
249                char *command = "chmod +rx \"$HELP\"";
250                setenv("HELP", [path fileSystemRepresentation], 1);
251                char *arguments[] = {"-c", command, NULL};
252                result = AuthorizationExecuteWithPrivileges(auth, "/bin/sh", kAuthorizationFlagDefaults, arguments, NULL);
253                unsetenv("HELP");
254                if(roslash)
255                {
256                        char *command = "mount -ur /";
257                        char *arguments[] = {"-c", command, NULL};
258                        AuthorizationExecuteWithPrivileges(auth, "/bin/sh", kAuthorizationFlagDefaults, arguments, NULL);
259                }
260        }
261        if(result != errAuthorizationSuccess)
262                return NO;
263       
264        return YES;
265}
266
267- (void)startClient
268{
269        NSString *path = [[NSBundle bundleForClass:[SapphireImportHelper class]] pathForResource:@"ImportHelper" ofType:@""];
270        NSDictionary *attrs = [[NSFileManager defaultManager] fileAttributesAtPath:path traverseLink:YES];
271        if(([[attrs objectForKey:NSFilePosixPermissions] intValue] | S_IXOTH) || [self fixClientPermissions:path])
272        {
273                @try {
274                        [NSTask launchedTaskWithLaunchPath:path arguments:[NSArray array]];
275                }
276                @catch (NSException * e) {
277                        NSLog(@"Could not launch helper because of exception %@ launching %@.  Make this file executable", e, path);
278                }               
279        }
280        else
281                NSLog(@"Could not correct helper permissions on %@.  Make this file executable!", path);
282}
283
284- (void)connectionDidDie:(NSNotification *)note
285{
286        [client release];
287        client = nil;
288        /*Inform that import completed (since it crashed, no update done)*/
289        [self importComplete:NO];
290        if(shared != nil)
291                /* Don't start it again if we are shutting down*/
292                [self startClient];
293}
294
295- (void)itemAdded
296{
297        if(!queueSuspended)
298                return;
299        queueSuspended = NO;
300        NSError *error = nil;
301        [moc save:&error];
302        [client startQueue];
303}
304
305- (void)importFileData:(SapphireFileMetaData *)file inform:(id <SapphireImporterBackgroundProtocol>)inform;
306{
307        SapphireImportFile *item = [[SapphireImportFile alloc] initWithPath:[file path] informer:inform  type:IMPORT_TYPE_FILE_DATA];
308        [queue addObject:item];
309        [item release];
310        [self itemAdded];
311}
312
313- (void)importAllData:(SapphireFileMetaData *)file inform:(id <SapphireImporterBackgroundProtocol>)inform;
314{
315        SapphireImportFile *item = [[SapphireImportFile alloc] initWithPath:[file path] informer:inform  type:IMPORT_TYPE_ALL_DATA];
316        [queue addObject:item];
317        [item release];
318        [self itemAdded];
319}
320
321- (void)removeObjectsWithInform:(id <SapphireImporterBackgroundProtocol>)inform
322{
323        if(inform == nil)
324                return;
325       
326        int i, count=[queue count];
327        for(i=0; i<count; i++)
328        {
329                id <SapphireImportFileProtocol> file = [queue objectAtIndex:i];
330                if([file informer] == inform)
331                {
332                        [queue removeObjectAtIndex:i];
333                        i--;
334                        count--;
335                }
336        }
337}
338
339- (id <SapphireImportFileProtocol>)nextFile
340{
341        if(![queue count])
342        {
343                queueSuspended = YES;
344                return nil;
345        }
346        [currentImporting release];
347        currentImporting = [[queue objectAtIndex:0] retain];
348        [queue removeObjectAtIndex:0];
349        return currentImporting;
350}
351
352- (oneway void)setClient:(id <SapphireImportClient>)aClient
353{
354        if(shared == nil)
355        {
356                [aClient exitChild];
357                return;
358        }
359        client = [aClient retain];
360        if([queue count])
361        {
362                queueSuspended = NO;
363                [client startQueue];
364        }
365}
366
367- (oneway void)importComplete:(BOOL)updated
368{
369        if(currentImporting == nil)
370                return;
371        NSString *path = [currentImporting path];
372        SapphireFileMetaData *file = [SapphireFileMetaData fileWithPath:path inContext:moc];
373        if(file != nil)
374                [moc refreshObject:file mergeChanges:NO];
375        [[currentImporting informer] informComplete:updated];
376        [currentImporting release];
377        currentImporting = nil;
378}
379
380@end
381
382@implementation SapphireImportFile
383- (id)initWithPath:(NSString *)aPath informer:(id <SapphireImporterBackgroundProtocol>)aInformer type:(ImportType)aType;
384{
385        self = [super init];
386        if(!self)
387                return nil;
388       
389        path = [aPath retain];
390        informer = [aInformer retain];
391        type = aType;
392       
393        return self;
394}
395- (void) dealloc
396{
397        [path release];
398        [informer release];
399        [super dealloc];
400}
401
402- (bycopy NSString *)path
403{
404        return path;
405}
406- (id <SapphireImporterBackgroundProtocol>)informer
407{
408        return informer;
409}
410
411- (ImportType)importType
412{
413        return type;
414}
415
416@end
Note: See TracBrowser for help on using the repository browser.