2012-03-05 08:53:32 +00:00
|
|
|
//
|
|
|
|
// MPPasswordWindowController.m
|
|
|
|
// MasterPassword-Mac
|
|
|
|
//
|
|
|
|
// Created by Maarten Billemont on 04/03/12.
|
|
|
|
// Copyright (c) 2012 Lyndir. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#import "MPPasswordWindowController.h"
|
2013-04-25 01:23:53 +00:00
|
|
|
#import "MPMacAppDelegate.h"
|
2012-05-13 08:24:19 +00:00
|
|
|
#import "MPAppDelegate_Key.h"
|
|
|
|
#import "MPAppDelegate_Store.h"
|
2012-03-05 08:53:32 +00:00
|
|
|
|
2013-01-27 03:05:57 +00:00
|
|
|
#define MPAlertUnlockMP @"MPAlertUnlockMP"
|
|
|
|
#define MPAlertIncorrectMP @"MPAlertIncorrectMP"
|
|
|
|
|
2013-04-20 18:11:19 +00:00
|
|
|
@interface MPPasswordWindowController()
|
2013-01-27 03:05:57 +00:00
|
|
|
|
2013-04-20 18:11:19 +00:00
|
|
|
@property(nonatomic) BOOL inProgress;
|
|
|
|
@property(nonatomic) BOOL siteFieldPreventCompletion;
|
2012-03-05 21:19:05 +00:00
|
|
|
|
2012-03-05 08:53:32 +00:00
|
|
|
@end
|
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
@implementation MPPasswordWindowController {
|
|
|
|
NSManagedObjectID *_activeElementOID;
|
|
|
|
}
|
2012-03-05 08:53:32 +00:00
|
|
|
|
|
|
|
- (void)windowDidLoad {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-25 01:23:53 +00:00
|
|
|
if ([[MPMacConfig get].dialogStyleHUD boolValue])
|
|
|
|
self.window.styleMask = NSHUDWindowMask | NSTitledWindowMask | NSUtilityWindowMask | NSClosableWindowMask;
|
|
|
|
else
|
|
|
|
self.window.styleMask = NSTexturedBackgroundWindowMask | NSResizableWindowMask | NSTitledWindowMask | NSClosableWindowMask;
|
2013-04-27 04:34:28 +00:00
|
|
|
|
2012-05-08 11:41:54 +00:00
|
|
|
[self setContent:@""];
|
2012-05-04 22:15:51 +00:00
|
|
|
[self.tipField setStringValue:@""];
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-25 01:23:53 +00:00
|
|
|
[self.userLabel setStringValue:PearlString( @"%@'s password for:", [[MPMacAppDelegate get] activeUserForThread].name )];
|
|
|
|
// [[MPMacAppDelegate get] addObserverBlock:^(NSString *keyPath, id object, NSDictionary *change, void *context) {
|
|
|
|
// [MPMacAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *moc) {
|
|
|
|
// if (![MPAlgorithmDefault migrateUser:[[MPMacAppDelegate get] activeUserInContext:moc]])
|
2013-04-24 00:38:56 +00:00
|
|
|
// [NSAlert alertWithMessageText:@"Migration Needed" defaultButton:@"OK" alternateButton:nil otherButton:nil
|
|
|
|
// informativeTextWithFormat:@"Certain sites require explicit migration to get updated to the latest version of the "
|
|
|
|
// @"Master Password algorithm. For these sites, a migration button will appear. Migrating these sites will cause "
|
|
|
|
// @"their passwords to change. You'll need to update your profile for that site with the new password."];
|
|
|
|
// [moc saveToStore];
|
|
|
|
// }];
|
|
|
|
// } forKeyPath:@"key" options:NSKeyValueObservingOptionInitial context:nil];
|
2013-04-20 18:11:19 +00:00
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserverForName:NSWindowDidBecomeKeyNotification object:self.window queue:nil usingBlock:^(NSNotification *note) {
|
|
|
|
if (!self.inProgress)
|
|
|
|
[self unlock];
|
|
|
|
[self.siteField selectText:self];
|
|
|
|
}];
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserverForName:NSWindowWillCloseNotification object:self.window queue:nil usingBlock:^(NSNotification *note) {
|
|
|
|
[[NSApplication sharedApplication] hide:self];
|
|
|
|
}];
|
|
|
|
[[NSNotificationCenter defaultCenter]
|
|
|
|
addObserverForName:MPSignedOutNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
|
|
|
|
[self.window close];
|
|
|
|
}];
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2012-03-05 08:53:32 +00:00
|
|
|
[super windowDidLoad];
|
2012-03-05 21:19:05 +00:00
|
|
|
}
|
|
|
|
|
2012-05-08 11:41:54 +00:00
|
|
|
- (void)unlock {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-25 01:23:53 +00:00
|
|
|
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserForThread];
|
2013-04-21 21:05:59 +00:00
|
|
|
if (!activeUser)
|
2013-04-20 18:11:19 +00:00
|
|
|
// No user to sign in with.
|
2013-01-27 03:05:57 +00:00
|
|
|
return;
|
2013-04-25 01:23:53 +00:00
|
|
|
if ([MPMacAppDelegate get].key)
|
2013-04-20 18:11:19 +00:00
|
|
|
// Already logged in.
|
2013-01-27 03:05:57 +00:00
|
|
|
return;
|
2013-04-25 01:23:53 +00:00
|
|
|
if ([[MPMacAppDelegate get] signInAsUser:activeUser usingMasterPassword:nil])
|
2013-04-20 18:11:19 +00:00
|
|
|
// Load the key from the keychain.
|
2012-10-31 02:54:34 +00:00
|
|
|
return;
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-25 01:23:53 +00:00
|
|
|
if (![MPMacAppDelegate get].key)
|
2013-04-20 18:11:19 +00:00
|
|
|
// Ask the user to set the key through his master password.
|
|
|
|
dispatch_async( dispatch_get_main_queue(), ^{
|
2013-04-25 01:23:53 +00:00
|
|
|
if ([MPMacAppDelegate get].key)
|
2012-05-08 11:41:54 +00:00
|
|
|
return;
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-01-27 03:05:57 +00:00
|
|
|
self.content = @"";
|
|
|
|
[self.siteField setStringValue:@""];
|
|
|
|
[self.tipField setStringValue:@""];
|
|
|
|
|
2013-04-20 18:11:19 +00:00
|
|
|
NSAlert *alert = [NSAlert alertWithMessageText:@"Master Password is locked."
|
|
|
|
defaultButton:@"Unlock" alternateButton:@"Change" otherButton:@"Cancel"
|
|
|
|
informativeTextWithFormat:@"The master password is required to unlock the application for:\n\n%@",
|
2013-04-21 21:05:59 +00:00
|
|
|
activeUser.name];
|
2013-04-20 18:11:19 +00:00
|
|
|
NSSecureTextField *passwordField = [[NSSecureTextField alloc] initWithFrame:NSMakeRect( 0, 0, 200, 22 )];
|
2012-05-08 11:41:54 +00:00
|
|
|
[alert setAccessoryView:passwordField];
|
|
|
|
[alert layout];
|
|
|
|
[passwordField becomeFirstResponder];
|
|
|
|
[alert beginSheetModalForWindow:self.window modalDelegate:self
|
2013-01-27 03:05:57 +00:00
|
|
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertUnlockMP];
|
2013-04-20 18:11:19 +00:00
|
|
|
} );
|
2012-05-08 11:41:54 +00:00
|
|
|
}
|
|
|
|
|
2012-06-08 21:46:13 +00:00
|
|
|
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
|
|
|
|
|
2013-01-27 03:05:57 +00:00
|
|
|
if (contextInfo == MPAlertIncorrectMP) {
|
|
|
|
[self.window close];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (contextInfo == MPAlertUnlockMP) {
|
2013-04-25 01:23:53 +00:00
|
|
|
MPUserEntity *activeUser = [[MPMacAppDelegate get] activeUserForThread];
|
2013-01-27 03:05:57 +00:00
|
|
|
switch (returnCode) {
|
|
|
|
case NSAlertAlternateReturn:
|
|
|
|
// "Change" button.
|
2013-04-27 04:34:28 +00:00
|
|
|
{
|
|
|
|
NSInteger returnCode_ = [[NSAlert
|
|
|
|
alertWithMessageText:@"Changing Master Password" defaultButton:nil
|
|
|
|
alternateButton:[PearlStrings get].commonButtonCancel otherButton:nil informativeTextWithFormat:
|
|
|
|
@"This will allow you to log in with a different master password.\n\n"
|
|
|
|
@"Note that you will only see the sites and passwords for the master password you log in with.\n"
|
|
|
|
@"If you log in with a different master password, your current sites will be unavailable.\n\n"
|
|
|
|
@"You can always change back to your current master password later.\n"
|
|
|
|
@"Your current sites and passwords will then become available again."]
|
|
|
|
runModal];
|
|
|
|
|
|
|
|
if (returnCode_ == NSAlertDefaultReturn) {
|
2013-04-21 21:05:59 +00:00
|
|
|
activeUser.keyID = nil;
|
2013-04-25 01:23:53 +00:00
|
|
|
[[MPMacAppDelegate get] forgetSavedKeyFor:activeUser];
|
|
|
|
[[MPMacAppDelegate get] signOutAnimated:YES];
|
2013-01-27 03:05:57 +00:00
|
|
|
}
|
2013-04-27 04:34:28 +00:00
|
|
|
}
|
2013-01-27 03:05:57 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NSAlertOtherReturn:
|
|
|
|
// "Cancel" button.
|
|
|
|
[self.window close];
|
|
|
|
return;
|
|
|
|
|
|
|
|
case NSAlertDefaultReturn: {
|
|
|
|
// "Unlock" button.
|
|
|
|
self.contentContainer.alphaValue = 0;
|
|
|
|
[self.progressView startAnimation:nil];
|
|
|
|
self.inProgress = YES;
|
2013-04-20 18:11:19 +00:00
|
|
|
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_LOW, 0 ), ^{
|
2013-04-25 01:23:53 +00:00
|
|
|
BOOL success = [[MPMacAppDelegate get] signInAsUser:activeUser
|
2013-04-27 04:34:28 +00:00
|
|
|
usingMasterPassword:[(NSSecureTextField *)alert.accessoryView stringValue]];
|
2013-01-27 03:05:57 +00:00
|
|
|
self.inProgress = NO;
|
|
|
|
|
2013-04-20 18:11:19 +00:00
|
|
|
dispatch_async( dispatch_get_main_queue(), ^{
|
2013-01-27 03:05:57 +00:00
|
|
|
[self.progressView stopAnimation:nil];
|
|
|
|
|
|
|
|
if (success)
|
|
|
|
self.contentContainer.alphaValue = 1;
|
|
|
|
else {
|
|
|
|
[[NSAlert alertWithError:[NSError errorWithDomain:MPErrorDomain code:0 userInfo:@{
|
2013-04-20 18:11:19 +00:00
|
|
|
NSLocalizedDescriptionKey : PearlString( @"Incorrect master password for user %@",
|
2013-04-21 21:05:59 +00:00
|
|
|
activeUser.name )
|
2013-01-27 03:05:57 +00:00
|
|
|
}]] beginSheetModalForWindow:self.window modalDelegate:self
|
|
|
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:MPAlertIncorrectMP];
|
|
|
|
}
|
2013-04-20 18:11:19 +00:00
|
|
|
} );
|
|
|
|
} );
|
2013-01-27 03:05:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2012-10-31 02:54:34 +00:00
|
|
|
}
|
2013-01-17 05:37:20 +00:00
|
|
|
|
2013-01-27 03:05:57 +00:00
|
|
|
return;
|
2012-05-08 11:41:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-08 21:46:13 +00:00
|
|
|
- (NSArray *)control:(NSControl *)control textView:(NSTextView *)textView completions:(NSArray *)words
|
|
|
|
forPartialWordRange:(NSRange)charRange indexOfSelectedItem:(NSInteger *)index {
|
|
|
|
|
2012-03-05 21:19:05 +00:00
|
|
|
NSString *query = [[control stringValue] substringWithRange:charRange];
|
2013-04-25 01:23:53 +00:00
|
|
|
if (![query length] || ![MPMacAppDelegate get].key)
|
2012-05-04 22:15:51 +00:00
|
|
|
return nil;
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
__block NSMutableArray *mutableResults = [NSMutableArray array];
|
|
|
|
[MPMacAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
|
|
|
|
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPElementEntity class] )];
|
|
|
|
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"lastUsed" ascending:NO]];
|
|
|
|
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"(name BEGINSWITH[cd] %@) AND user == %@",
|
|
|
|
query, [[MPMacAppDelegate get] activeUserInContext:context]];
|
|
|
|
|
|
|
|
NSError *error = nil;
|
|
|
|
NSArray *siteResults = [context executeFetchRequest:fetchRequest error:&error];
|
|
|
|
if (error)
|
|
|
|
err(@"While fetching elements for completion: %@", error);
|
|
|
|
|
|
|
|
if (siteResults) {
|
|
|
|
for (MPElementEntity *element in siteResults)
|
|
|
|
[mutableResults addObject:element.name];
|
|
|
|
//[mutableResults addObject:query]; // For when the app should be able to create new sites.
|
|
|
|
}
|
|
|
|
}];
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
if ([mutableResults count] == 1) {
|
|
|
|
//[textView setString:[(MPElementEntity *)[siteResults objectAtIndex:0] name]];
|
|
|
|
//[textView setSelectedRange:NSMakeRange( [query length], [[textView string] length] - [query length] )];
|
|
|
|
[self trySiteAndCopyContent:NO];
|
|
|
|
}
|
2013-01-27 03:05:57 +00:00
|
|
|
|
2012-03-06 00:04:19 +00:00
|
|
|
return mutableResults;
|
2012-03-05 21:19:05 +00:00
|
|
|
}
|
|
|
|
|
2012-05-04 16:54:58 +00:00
|
|
|
- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2012-05-08 11:41:54 +00:00
|
|
|
if (commandSelector == @selector(cancel:)) {
|
2012-05-04 22:15:51 +00:00
|
|
|
[self.window close];
|
2012-05-08 11:41:54 +00:00
|
|
|
return YES;
|
|
|
|
}
|
2013-04-20 18:11:19 +00:00
|
|
|
if ((self.siteFieldPreventCompletion = [NSStringFromSelector( commandSelector ) hasPrefix:@"delete"]))
|
2013-01-27 03:05:57 +00:00
|
|
|
return NO;
|
2013-04-27 04:34:28 +00:00
|
|
|
if (commandSelector == @selector(insertNewline:)) {
|
|
|
|
[self trySiteAndCopyContent:YES];
|
2013-01-27 03:05:57 +00:00
|
|
|
return YES;
|
2012-05-04 22:15:51 +00:00
|
|
|
}
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2012-05-08 11:41:54 +00:00
|
|
|
return NO;
|
2012-05-04 16:54:58 +00:00
|
|
|
}
|
|
|
|
|
2013-01-27 03:05:57 +00:00
|
|
|
- (void)copyContents {
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)controlTextDidEndEditing:(NSNotification *)note {
|
|
|
|
|
|
|
|
if (note.object != self.siteField)
|
|
|
|
return;
|
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
[self trySiteAndCopyContent:NO];
|
2013-01-27 03:05:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)controlTextDidChange:(NSNotification *)note {
|
|
|
|
|
|
|
|
if (note.object != self.siteField)
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Update the site content as the site name changes.
|
2013-04-27 04:34:28 +00:00
|
|
|
BOOL enterPressed = [[NSApp currentEvent] type] == NSKeyDown &&
|
|
|
|
[[[NSApp currentEvent] charactersIgnoringModifiers] isEqualToString:@"\r"];
|
|
|
|
[self trySiteAndCopyContent:enterPressed];
|
2013-01-27 03:05:57 +00:00
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
if (enterPressed)
|
2013-01-27 03:05:57 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (self.siteFieldPreventCompletion) {
|
|
|
|
self.siteFieldPreventCompletion = NO;
|
|
|
|
return;
|
|
|
|
}
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-01-27 03:05:57 +00:00
|
|
|
self.siteFieldPreventCompletion = YES;
|
|
|
|
[(NSText *)[note.userInfo objectForKey:@"NSFieldEditor"] complete:self];
|
|
|
|
self.siteFieldPreventCompletion = NO;
|
2012-03-05 08:53:32 +00:00
|
|
|
}
|
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
- (MPElementEntity *)activeElementForThread {
|
|
|
|
|
2013-04-30 05:49:53 +00:00
|
|
|
return [self activeElementInContext:[MPMacAppDelegate managedObjectContextForThreadIfReady]];
|
|
|
|
}
|
2013-04-27 04:34:28 +00:00
|
|
|
|
2013-04-30 05:49:53 +00:00
|
|
|
- (MPElementEntity *)activeElementInContext:(NSManagedObjectContext *)moc {
|
|
|
|
|
|
|
|
if (!_activeElementOID)
|
2013-04-27 04:34:28 +00:00
|
|
|
return nil;
|
|
|
|
|
|
|
|
NSError *error;
|
|
|
|
MPElementEntity *activeElement = (MPElementEntity *)[moc existingObjectWithID:_activeElementOID error:&error];
|
|
|
|
if (!activeElement)
|
|
|
|
err(@"Couldn't retrieve active element: %@", error);
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
return activeElement;
|
2012-05-08 11:41:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)setContent:(NSString *)content {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2012-05-08 11:41:54 +00:00
|
|
|
NSMutableParagraphStyle *paragraph = [NSMutableParagraphStyle new];
|
|
|
|
paragraph.alignment = NSCenterTextAlignment;
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
[self.contentField setAttributedStringValue:[[NSAttributedString alloc] initWithString:content attributes:@{
|
|
|
|
NSParagraphStyleAttributeName : paragraph
|
|
|
|
}]];
|
2012-05-08 11:41:54 +00:00
|
|
|
}
|
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
- (void)trySiteAndCopyContent:(BOOL)copyContent {
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-27 04:34:28 +00:00
|
|
|
[self setContent:@""];
|
|
|
|
[self.tipField setStringValue:@"Generating..."];
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-20 18:11:19 +00:00
|
|
|
dispatch_async( dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0 ), ^{
|
2013-04-27 04:34:28 +00:00
|
|
|
NSString *content = [[self activeElementForThread].content description];
|
|
|
|
if (!content)
|
|
|
|
content = @"";
|
|
|
|
if (copyContent) {
|
|
|
|
[[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
|
|
|
|
if (![[NSPasteboard generalPasteboard] setString:content forType:NSPasteboardTypeString]) {
|
|
|
|
wrn(@"Couldn't copy password to pasteboard.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-04-30 05:49:53 +00:00
|
|
|
NSManagedObjectContext *moc = [MPMacAppDelegate managedObjectContextForThreadIfReady];
|
|
|
|
MPElementEntity *activeElement = [self activeElementInContext:moc];
|
2013-04-27 04:34:28 +00:00
|
|
|
[activeElement use];
|
2013-04-30 05:49:53 +00:00
|
|
|
[moc saveToStore];
|
2013-04-27 04:34:28 +00:00
|
|
|
}
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2013-04-20 18:11:19 +00:00
|
|
|
dispatch_async( dispatch_get_main_queue(), ^{
|
2013-04-27 04:34:28 +00:00
|
|
|
[self setContent:content];
|
|
|
|
|
2012-05-04 22:15:51 +00:00
|
|
|
self.tipField.alphaValue = 1;
|
2013-04-27 04:34:28 +00:00
|
|
|
if (!copyContent)
|
|
|
|
[self.tipField setStringValue:@"Hit ⌤ (ENTER) to copy the password."];
|
|
|
|
else {
|
|
|
|
[self.tipField setStringValue:@"Copied! Hit ⎋ (ESC) to close window."];
|
|
|
|
dispatch_time_t popTime = dispatch_time( DISPATCH_TIME_NOW, (int64_t)(5.0f * NSEC_PER_SEC) );
|
|
|
|
dispatch_after( popTime, dispatch_get_main_queue(), ^{
|
|
|
|
[NSAnimationContext beginGrouping];
|
|
|
|
[[NSAnimationContext currentContext] setDuration:0.2f];
|
|
|
|
[self.tipField.animator setAlphaValue:0];
|
|
|
|
[NSAnimationContext endGrouping];
|
|
|
|
} );
|
|
|
|
}
|
2013-04-20 18:11:19 +00:00
|
|
|
} );
|
|
|
|
} );
|
2012-06-08 21:46:13 +00:00
|
|
|
|
2012-05-04 22:15:51 +00:00
|
|
|
// For when the app should be able to create new sites.
|
|
|
|
/*
|
|
|
|
else
|
2013-04-25 01:23:53 +00:00
|
|
|
[[MPMacAppDelegate get].managedObjectContext performBlock:^{
|
2012-05-04 22:15:51 +00:00
|
|
|
MPElementEntity *element = [NSEntityDescription insertNewObjectForEntityForName:NSStringFromClass([MPElementGeneratedEntity class])
|
2013-04-25 01:23:53 +00:00
|
|
|
inManagedObjectContext:[MPMacAppDelegate get].managedObjectContext];
|
2012-05-04 22:15:51 +00:00
|
|
|
assert([element isKindOfClass:ClassFromMPElementType(element.type)]);
|
2013-04-25 01:23:53 +00:00
|
|
|
assert([MPMacAppDelegate get].keyID);
|
2012-05-04 22:15:51 +00:00
|
|
|
|
|
|
|
element.name = siteName;
|
2013-04-25 01:23:53 +00:00
|
|
|
element.keyID = [MPMacAppDelegate get].keyID;
|
2012-05-04 22:15:51 +00:00
|
|
|
|
2012-05-06 23:15:19 +00:00
|
|
|
NSString *description = [element.content description];
|
2012-05-04 22:15:51 +00:00
|
|
|
[element use];
|
|
|
|
|
|
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
2012-05-08 11:41:54 +00:00
|
|
|
[self setContent:description];
|
2012-05-04 22:15:51 +00:00
|
|
|
});
|
|
|
|
}];
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
2012-03-05 08:53:32 +00:00
|
|
|
@end
|