mirror of
https://github.com/MacPass/MacPass.git
synced 2025-12-14 12:52:21 +00:00
Added support to save and load Attachemnts on KeePass2 Databases.
Support for Keepass1 DBs is still missing
This commit is contained in:
@@ -52,6 +52,7 @@
|
|||||||
4C2E381F16D11FF900037A9D /* 05_LanguagesTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C2E381C16D11FF900037A9D /* 05_LanguagesTemplate.pdf */; };
|
4C2E381F16D11FF900037A9D /* 05_LanguagesTemplate.pdf in Resources */ = {isa = PBXBuildFile; fileRef = 4C2E381C16D11FF900037A9D /* 05_LanguagesTemplate.pdf */; };
|
||||||
4C2E382316D1421B00037A9D /* MPIconHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2E382216D1421B00037A9D /* MPIconHelper.m */; };
|
4C2E382316D1421B00037A9D /* MPIconHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2E382216D1421B00037A9D /* MPIconHelper.m */; };
|
||||||
4C2E382616D1470200037A9D /* MPViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2E382516D1470200037A9D /* MPViewController.m */; };
|
4C2E382616D1470200037A9D /* MPViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C2E382516D1470200037A9D /* MPViewController.m */; };
|
||||||
|
4C3666411787327E00B249F1 /* MPDocument+Attachments.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C3666401787327E00B249F1 /* MPDocument+Attachments.m */; };
|
||||||
4C36E5B4177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C36E5B3177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m */; };
|
4C36E5B4177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C36E5B3177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m */; };
|
||||||
4C37A6731769393300AD0A40 /* HNHTableHeaderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C37A6721769393300AD0A40 /* HNHTableHeaderCell.m */; };
|
4C37A6731769393300AD0A40 /* HNHTableHeaderCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C37A6721769393300AD0A40 /* HNHTableHeaderCell.m */; };
|
||||||
4C37A84015B8B474005EF8EE /* MPOutlineDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C37A83F15B8B474005EF8EE /* MPOutlineDataSource.m */; };
|
4C37A84015B8B474005EF8EE /* MPOutlineDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C37A83F15B8B474005EF8EE /* MPOutlineDataSource.m */; };
|
||||||
@@ -284,6 +285,7 @@
|
|||||||
4C2E382216D1421B00037A9D /* MPIconHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPIconHelper.m; sourceTree = "<group>"; };
|
4C2E382216D1421B00037A9D /* MPIconHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPIconHelper.m; sourceTree = "<group>"; };
|
||||||
4C2E382416D1470200037A9D /* MPViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPViewController.h; sourceTree = "<group>"; };
|
4C2E382416D1470200037A9D /* MPViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPViewController.h; sourceTree = "<group>"; };
|
||||||
4C2E382516D1470200037A9D /* MPViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPViewController.m; sourceTree = "<group>"; };
|
4C2E382516D1470200037A9D /* MPViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPViewController.m; sourceTree = "<group>"; };
|
||||||
|
4C3666401787327E00B249F1 /* MPDocument+Attachments.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "MPDocument+Attachments.m"; sourceTree = "<group>"; };
|
||||||
4C36E5B2177CD4FB00152132 /* Kdb4Tree+KVOAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Kdb4Tree+KVOAdditions.h"; sourceTree = "<group>"; };
|
4C36E5B2177CD4FB00152132 /* Kdb4Tree+KVOAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Kdb4Tree+KVOAdditions.h"; sourceTree = "<group>"; };
|
||||||
4C36E5B3177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Kdb4Tree+KVOAdditions.m"; sourceTree = "<group>"; };
|
4C36E5B3177CD4FB00152132 /* Kdb4Tree+KVOAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Kdb4Tree+KVOAdditions.m"; sourceTree = "<group>"; };
|
||||||
4C37A6711769393300AD0A40 /* HNHTableHeaderCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HNHTableHeaderCell.h; sourceTree = "<group>"; };
|
4C37A6711769393300AD0A40 /* HNHTableHeaderCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HNHTableHeaderCell.h; sourceTree = "<group>"; };
|
||||||
@@ -851,6 +853,7 @@
|
|||||||
4CE5B549173AFBA700207B39 /* MPDocument.m */,
|
4CE5B549173AFBA700207B39 /* MPDocument.m */,
|
||||||
4C5EC300177B700D00DA955B /* MPRootAdapter.h */,
|
4C5EC300177B700D00DA955B /* MPRootAdapter.h */,
|
||||||
4C5EC301177B700D00DA955B /* MPRootAdapter.m */,
|
4C5EC301177B700D00DA955B /* MPRootAdapter.m */,
|
||||||
|
4C3666401787327E00B249F1 /* MPDocument+Attachments.m */,
|
||||||
);
|
);
|
||||||
name = Model;
|
name = Model;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -1520,6 +1523,7 @@
|
|||||||
4CC6727C1781D0D2006DEDCF /* KdbEntry+MPAdditions.m in Sources */,
|
4CC6727C1781D0D2006DEDCF /* KdbEntry+MPAdditions.m in Sources */,
|
||||||
4C5FE9AE17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m in Sources */,
|
4C5FE9AE17843CE20001D5A8 /* MPSelectedAttachmentTableCellView.m in Sources */,
|
||||||
4CF1F0CA1786B37900CD920E /* NSData+Gzip.m in Sources */,
|
4CF1F0CA1786B37900CD920E /* NSData+Gzip.m in Sources */,
|
||||||
|
4C3666411787327E00B249F1 /* MPDocument+Attachments.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -137,7 +137,6 @@
|
|||||||
<string key="NSFrameSize">{293, 30}</string>
|
<string key="NSFrameSize">{293, 30}</string>
|
||||||
<reference key="NSSuperview" ref="87082330"/>
|
<reference key="NSSuperview" ref="87082330"/>
|
||||||
<reference key="NSWindow"/>
|
<reference key="NSWindow"/>
|
||||||
<reference key="NSNextKeyView"/>
|
|
||||||
<string key="NSReuseIdentifierKey">_NS:9</string>
|
<string key="NSReuseIdentifierKey">_NS:9</string>
|
||||||
<string key="NSClassName">HNHGradientView</string>
|
<string key="NSClassName">HNHGradientView</string>
|
||||||
</object>
|
</object>
|
||||||
@@ -634,7 +633,6 @@
|
|||||||
<int key="NSvFlags">256</int>
|
<int key="NSvFlags">256</int>
|
||||||
<string key="NSFrame">{{236, 1}, {16, 332}}</string>
|
<string key="NSFrame">{{236, 1}, {16, 332}}</string>
|
||||||
<reference key="NSSuperview" ref="850153963"/>
|
<reference key="NSSuperview" ref="850153963"/>
|
||||||
<reference key="NSNextKeyView" ref="894571713"/>
|
|
||||||
<string key="NSReuseIdentifierKey">_NS:83</string>
|
<string key="NSReuseIdentifierKey">_NS:83</string>
|
||||||
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
|
<bool key="NSAllowsLogicalLayoutDirection">NO</bool>
|
||||||
<reference key="NSTarget" ref="850153963"/>
|
<reference key="NSTarget" ref="850153963"/>
|
||||||
@@ -1269,6 +1267,14 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">2068</int>
|
<int key="connectionID">2068</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBActionConnection" key="connection">
|
||||||
|
<string key="label">addAttachment:</string>
|
||||||
|
<reference key="source" ref="1001"/>
|
||||||
|
<reference key="destination" ref="394980328"/>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">2244</int>
|
||||||
|
</object>
|
||||||
<object class="IBConnectionRecord">
|
<object class="IBConnectionRecord">
|
||||||
<object class="IBOutletConnection" key="connection">
|
<object class="IBOutletConnection" key="connection">
|
||||||
<string key="label">imageView</string>
|
<string key="label">imageView</string>
|
||||||
@@ -1546,6 +1552,14 @@
|
|||||||
</object>
|
</object>
|
||||||
<int key="connectionID">2215</int>
|
<int key="connectionID">2215</int>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBConnectionRecord">
|
||||||
|
<object class="IBOutletConnection" key="connection">
|
||||||
|
<string key="label">saveButton</string>
|
||||||
|
<reference key="source" ref="421971283"/>
|
||||||
|
<reference key="destination" ref="121170874"/>
|
||||||
|
</object>
|
||||||
|
<int key="connectionID">2243</int>
|
||||||
|
</object>
|
||||||
</array>
|
</array>
|
||||||
<object class="IBMutableOrderedSet" key="objectRecords">
|
<object class="IBMutableOrderedSet" key="objectRecords">
|
||||||
<array key="orderedObjects">
|
<array key="orderedObjects">
|
||||||
@@ -4934,7 +4948,7 @@
|
|||||||
<nil key="activeLocalization"/>
|
<nil key="activeLocalization"/>
|
||||||
<dictionary class="NSMutableDictionary" key="localizations"/>
|
<dictionary class="NSMutableDictionary" key="localizations"/>
|
||||||
<nil key="sourceID"/>
|
<nil key="sourceID"/>
|
||||||
<int key="maxID">2241</int>
|
<int key="maxID">2244</int>
|
||||||
</object>
|
</object>
|
||||||
<object class="IBClassDescriber" key="IBDocument.Classes">
|
<object class="IBClassDescriber" key="IBDocument.Classes">
|
||||||
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
|
<array class="NSMutableArray" key="referencedPartialClassDescriptions">
|
||||||
@@ -5017,10 +5031,21 @@
|
|||||||
<string key="className">MPInspectorViewController</string>
|
<string key="className">MPInspectorViewController</string>
|
||||||
<string key="superclassName">MPViewController</string>
|
<string key="superclassName">MPViewController</string>
|
||||||
<dictionary class="NSMutableDictionary" key="actions">
|
<dictionary class="NSMutableDictionary" key="actions">
|
||||||
|
<string key="_popUpPasswordGenerator:">id</string>
|
||||||
|
<string key="addAttachment:">id</string>
|
||||||
<string key="addCustomField:">id</string>
|
<string key="addCustomField:">id</string>
|
||||||
<string key="removeCustomField:">id</string>
|
<string key="removeCustomField:">id</string>
|
||||||
|
<string key="saveAttachment:">id</string>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
<dictionary class="NSMutableDictionary" key="actionInfosByName">
|
<dictionary class="NSMutableDictionary" key="actionInfosByName">
|
||||||
|
<object class="IBActionInfo" key="_popUpPasswordGenerator:">
|
||||||
|
<string key="name">_popUpPasswordGenerator:</string>
|
||||||
|
<string key="candidateClassName">id</string>
|
||||||
|
</object>
|
||||||
|
<object class="IBActionInfo" key="addAttachment:">
|
||||||
|
<string key="name">addAttachment:</string>
|
||||||
|
<string key="candidateClassName">id</string>
|
||||||
|
</object>
|
||||||
<object class="IBActionInfo" key="addCustomField:">
|
<object class="IBActionInfo" key="addCustomField:">
|
||||||
<string key="name">addCustomField:</string>
|
<string key="name">addCustomField:</string>
|
||||||
<string key="candidateClassName">id</string>
|
<string key="candidateClassName">id</string>
|
||||||
@@ -5029,6 +5054,10 @@
|
|||||||
<string key="name">removeCustomField:</string>
|
<string key="name">removeCustomField:</string>
|
||||||
<string key="candidateClassName">id</string>
|
<string key="candidateClassName">id</string>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="IBActionInfo" key="saveAttachment:">
|
||||||
|
<string key="name">saveAttachment:</string>
|
||||||
|
<string key="candidateClassName">id</string>
|
||||||
|
</object>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
<dictionary class="NSMutableDictionary" key="outlets">
|
<dictionary class="NSMutableDictionary" key="outlets">
|
||||||
<string key="URLTextField">NSTextField</string>
|
<string key="URLTextField">NSTextField</string>
|
||||||
|
|||||||
@@ -15,5 +15,9 @@
|
|||||||
- (void)removeObjectFromStringFieldsAtIndex:(NSUInteger)anIndex;
|
- (void)removeObjectFromStringFieldsAtIndex:(NSUInteger)anIndex;
|
||||||
- (void)insertObject:(StringField *)stringfield inStringFieldsAtIndex:(NSUInteger)anIndex;
|
- (void)insertObject:(StringField *)stringfield inStringFieldsAtIndex:(NSUInteger)anIndex;
|
||||||
|
|
||||||
|
- (NSUInteger)countOfBinaries;
|
||||||
|
- (BinaryRef *)objectInBinariesAtIndex:(NSUInteger)index;
|
||||||
|
- (void)removeObjectFromBinariesAtIndex:(NSUInteger)index;
|
||||||
|
- (void)insertObject:(BinaryRef *)binary inBinariesAtIndex:(NSUInteger)index;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
|
|
||||||
@implementation Kdb4Entry (KVOAdditions)
|
@implementation Kdb4Entry (KVOAdditions)
|
||||||
|
|
||||||
|
/* Entries */
|
||||||
- (NSUInteger)countOfStringFields {
|
- (NSUInteger)countOfStringFields {
|
||||||
return [self.stringFields count];
|
return [self.stringFields count];
|
||||||
}
|
}
|
||||||
@@ -26,4 +27,21 @@
|
|||||||
[self.stringFields removeObjectAtIndex:anIndex];
|
[self.stringFields removeObjectAtIndex:anIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Binaries */
|
||||||
|
- (NSUInteger)countOfBinaries {
|
||||||
|
return [self.binaries count];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BinaryRef *)objectInBinariesAtIndex:(NSUInteger)index {
|
||||||
|
return (self.binaries)[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)insertObject:(BinaryRef *)binary inBinariesAtIndex:(NSUInteger)index {
|
||||||
|
[self.binaries insertObject:binary atIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)removeObjectFromBinariesAtIndex:(NSUInteger)index {
|
||||||
|
[self.binaries removeObjectAtIndex:index];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#import "Kdb.h"
|
#import "Kdb.h"
|
||||||
|
|
||||||
@class BinaryRef;
|
@class BinaryRef;
|
||||||
|
@class Binary;
|
||||||
|
|
||||||
@interface KdbTree (MPAdditions)
|
@interface KdbTree (MPAdditions)
|
||||||
|
|
||||||
@@ -16,10 +17,4 @@
|
|||||||
|
|
||||||
- (NSArray *)allGroups;
|
- (NSArray *)allGroups;
|
||||||
|
|
||||||
- (void)addAttachment:(NSURL *)location toEntry:(KdbEntry *)anEntry;
|
|
||||||
- (void)saveAttachmentFromEntry:(KdbEntry *)anEntry toLocation:(NSURL *)location;
|
|
||||||
- (void)saveAttachment:(BinaryRef *)reference toLocation:(NSURL *)location;
|
|
||||||
- (NSUInteger)nextBinaryId;
|
|
||||||
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
#import "KdbTree+MPAdditions.h"
|
#import "KdbTree+MPAdditions.h"
|
||||||
#import "KdbGroup+MPTreeTools.h"
|
#import "KdbGroup+MPTreeTools.h"
|
||||||
|
|
||||||
|
#import "NSMutableData+Base64.h"
|
||||||
#import "Kdb3Node.h"
|
#import "Kdb3Node.h"
|
||||||
#import "Kdb4Node.h"
|
#import "Kdb4Node.h"
|
||||||
|
|
||||||
@@ -22,61 +23,4 @@
|
|||||||
return [self.root childEntries];
|
return [self.root childEntries];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)addAttachment:(NSURL *)location toEntry:(KdbEntry *)anEntry {
|
|
||||||
NSError *error = nil;
|
|
||||||
NSString *fileName = [NSString stringWithFormat:@"%@.%@", [location lastPathComponent], [location pathExtension]];
|
|
||||||
if([anEntry isKindOfClass:[Kdb3Entry class]]) {
|
|
||||||
Kdb3Entry *entry = (Kdb3Entry *)anEntry;
|
|
||||||
NSData *binaryData = [NSData dataWithContentsOfURL:location options:NSDataReadingUncached error:&error];
|
|
||||||
if(!binaryData) {
|
|
||||||
[NSApp presentError:error];
|
|
||||||
binaryData = nil;
|
|
||||||
error = nil;
|
|
||||||
return; // failed
|
|
||||||
}
|
|
||||||
entry.binary = binaryData;
|
|
||||||
entry.binaryDesc = fileName;
|
|
||||||
}
|
|
||||||
if( [anEntry isKindOfClass:[Kdb4Entry class]]) {
|
|
||||||
Kdb4Entry *entry = (Kdb4Entry *)anEntry;
|
|
||||||
Kdb4Tree *tree = (Kdb4Tree *)self;
|
|
||||||
NSString *fileData = [NSString stringWithContentsOfURL:location usedEncoding:0 error:&error];
|
|
||||||
if(!fileData) {
|
|
||||||
[NSApp presentError:error];
|
|
||||||
fileData = nil;
|
|
||||||
error = nil;
|
|
||||||
return; // failed
|
|
||||||
}
|
|
||||||
Binary *binary = [[Binary alloc] init];
|
|
||||||
binary.binaryId = [self nextBinaryId];
|
|
||||||
binary.compressed = (tree.compressionAlgorithm == KPLCompressionGzip);
|
|
||||||
if(binary.compressed ) {
|
|
||||||
|
|
||||||
}
|
|
||||||
binary.data = fileData;
|
|
||||||
|
|
||||||
[tree.binaries addObject:binary];
|
|
||||||
BinaryRef *ref = [[BinaryRef alloc] init];
|
|
||||||
ref.key = fileName;
|
|
||||||
[entry.binaries addObject:ref];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)saveAttachment:(BinaryRef *)reference toLocation:(NSURL *)location {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)saveAttachmentFromEntry:(KdbEntry *)entry toLocation:(NSURL *)location {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSUInteger)nextBinaryId {
|
|
||||||
Kdb4Tree *tree = (Kdb4Tree *)self;
|
|
||||||
NSUInteger maxKey = 0;
|
|
||||||
for(Binary *binary in tree.binaries) {
|
|
||||||
maxKey = MAX(binary.binaryId, maxKey);
|
|
||||||
}
|
|
||||||
return (maxKey + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
135
MacPass/MPDocument+Attachments.m
Normal file
135
MacPass/MPDocument+Attachments.m
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
//
|
||||||
|
// MPDocument+Attachments.m
|
||||||
|
// MacPass
|
||||||
|
//
|
||||||
|
// Created by Michael Starke on 05.07.13.
|
||||||
|
// Copyright (c) 2013 HicknHack Software GmbH. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "MPDocument.h"
|
||||||
|
|
||||||
|
#import "NSMutableData+Base64.h"
|
||||||
|
#import "NSData+Gzip.h"
|
||||||
|
|
||||||
|
#import "Kdb3Node.h"
|
||||||
|
#import "Kdb4Node.h"
|
||||||
|
#import "Kdb4Entry+KVOAdditions.h"
|
||||||
|
|
||||||
|
@implementation MPDocument (Attachments)
|
||||||
|
|
||||||
|
- (void)addAttachment:(NSURL *)location toEntry:(KdbEntry *)anEntry {
|
||||||
|
NSError *error = nil;
|
||||||
|
NSString *fileName = [location lastPathComponent];
|
||||||
|
if([anEntry isKindOfClass:[Kdb3Entry class]]) {
|
||||||
|
Kdb3Entry *entry = (Kdb3Entry *)anEntry;
|
||||||
|
NSData *binaryData = [NSData dataWithContentsOfURL:location options:NSDataReadingUncached error:&error];
|
||||||
|
if(!binaryData) {
|
||||||
|
[NSApp presentError:error];
|
||||||
|
binaryData = nil;
|
||||||
|
error = nil;
|
||||||
|
return; // failed
|
||||||
|
}
|
||||||
|
entry.binary = binaryData;
|
||||||
|
entry.binaryDesc = fileName;
|
||||||
|
}
|
||||||
|
if( [anEntry isKindOfClass:[Kdb4Entry class]]) {
|
||||||
|
Kdb4Entry *entry = (Kdb4Entry *)anEntry;
|
||||||
|
NSStringEncoding encoding;
|
||||||
|
NSString *fileContents = [NSString stringWithContentsOfURL:location usedEncoding:&encoding error:&error];
|
||||||
|
if(!fileContents) {
|
||||||
|
[NSApp presentError:error];
|
||||||
|
fileContents = nil;
|
||||||
|
error = nil;
|
||||||
|
return; // failed
|
||||||
|
}
|
||||||
|
Binary *binary = [[Binary alloc] init];
|
||||||
|
NSUInteger nextId = [self nextBinaryId];
|
||||||
|
if(nextId == NSNotFound) {
|
||||||
|
binary = nil;
|
||||||
|
return; // No id found. Something went wrong
|
||||||
|
}
|
||||||
|
binary.binaryId = nextId;
|
||||||
|
binary.compressed = (self.treeV4.compressionAlgorithm != KPLCompressionNone);
|
||||||
|
NSData *encodedData;
|
||||||
|
NSData *fileData = [fileContents dataUsingEncoding:encoding];
|
||||||
|
if(binary.compressed) {
|
||||||
|
switch(self.treeV4.compressionAlgorithm) {
|
||||||
|
case KPLCompressionGzip: {
|
||||||
|
NSData *compressedData = [fileData gzipDeflate];
|
||||||
|
encodedData = [NSMutableData mutableDataWithBase64EncodedData:compressedData];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
NSAssert(NO, @"Unsupported Compression Algorithm");
|
||||||
|
binary = nil;
|
||||||
|
encodedData = nil;
|
||||||
|
fileData = nil;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
encodedData = fileData;
|
||||||
|
}
|
||||||
|
binary.data = [[NSString alloc] initWithData:encodedData encoding:NSASCIIStringEncoding];
|
||||||
|
|
||||||
|
[self.treeV4.binaries addObject:binary];
|
||||||
|
BinaryRef *ref = [[BinaryRef alloc] init];
|
||||||
|
ref.key = fileName;
|
||||||
|
ref.ref = binary.binaryId;
|
||||||
|
[entry insertObject:ref inBinariesAtIndex:[entry.binaries count]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (Binary *)findBinary:(BinaryRef *)reference {
|
||||||
|
if(self.version != MPDatabaseVersion4) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
|
||||||
|
Binary *binaryFile = evaluatedObject;
|
||||||
|
return (binaryFile.binaryId == reference.ref);
|
||||||
|
}];
|
||||||
|
NSArray *filteredBinary = [self.treeV4.binaries filteredArrayUsingPredicate:filterPredicate];
|
||||||
|
return [filteredBinary lastObject];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)saveAttachment:(BinaryRef *)reference toLocation:(NSURL *)location {
|
||||||
|
Binary *binary = [self findBinary:reference];
|
||||||
|
NSData *rawData = nil;
|
||||||
|
if(binary) {
|
||||||
|
if(binary.compressed) {
|
||||||
|
rawData = [NSMutableData mutableDataWithBase64DecodedData:[binary.data dataUsingEncoding:NSASCIIStringEncoding]];
|
||||||
|
rawData = [rawData gzipInflate];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
rawData = [NSMutableData mutableDataWithBase64DecodedData:[binary.data dataUsingEncoding:NSASCIIStringEncoding]];
|
||||||
|
}
|
||||||
|
NSError *error = nil;
|
||||||
|
if( ![rawData writeToURL:location options:0 error:&error] ) {
|
||||||
|
[NSApp presentError:error];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)saveAttachmentFromEntry:(KdbEntry *)anEntry toLocation:(NSURL *)location {
|
||||||
|
if([anEntry isKindOfClass:[Kdb3Entry class]]) {
|
||||||
|
Kdb3Entry *entry = (Kdb3Entry *)anEntry;
|
||||||
|
NSError *error = nil;
|
||||||
|
if(! [entry.binary writeToURL:location options:NSDataWritingWithoutOverwriting error:&error] ) {
|
||||||
|
[NSApp presentError:error];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return; //
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSUInteger)nextBinaryId {
|
||||||
|
if(self.version != MPDatabaseVersion4) {
|
||||||
|
return NSNotFound;
|
||||||
|
}
|
||||||
|
NSUInteger maxKey = 0;
|
||||||
|
for(Binary *binary in self.treeV4.binaries) {
|
||||||
|
maxKey = MAX(binary.binaryId, maxKey);
|
||||||
|
}
|
||||||
|
return (maxKey + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -57,10 +57,6 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey;
|
|||||||
*/
|
*/
|
||||||
- (KdbEntry *)findEntry:(UUID *)uuid;
|
- (KdbEntry *)findEntry:(UUID *)uuid;
|
||||||
- (KdbGroup *)findGroup:(UUID *)uuid;
|
- (KdbGroup *)findGroup:(UUID *)uuid;
|
||||||
/*
|
|
||||||
Return the Binary for the given BinaryRef. nil if none was found
|
|
||||||
*/
|
|
||||||
- (Binary *)binaryForRef:(BinaryRef *)binaryRef;
|
|
||||||
|
|
||||||
- (Kdb4Tree *)treeV4;
|
- (Kdb4Tree *)treeV4;
|
||||||
- (Kdb3Tree *)treeV3;
|
- (Kdb3Tree *)treeV3;
|
||||||
@@ -93,3 +89,13 @@ APPKIT_EXTERN NSString *const MPDocumentGroupKey;
|
|||||||
- (void)emptyTrash:(id)sender;
|
- (void)emptyTrash:(id)sender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
@interface MPDocument (Attachments)
|
||||||
|
|
||||||
|
- (void)addAttachment:(NSURL *)location toEntry:(KdbEntry *)anEntry;
|
||||||
|
- (void)saveAttachmentFromEntry:(KdbEntry *)anEntry toLocation:(NSURL *)location;
|
||||||
|
- (void)saveAttachment:(BinaryRef *)reference toLocation:(NSURL *)location;
|
||||||
|
- (NSUInteger)nextBinaryId;
|
||||||
|
- (Binary *)findBinary:(BinaryRef *)reference;
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -217,19 +217,6 @@ NSString *const MPDocumentGroupKey = @"MPDocumentGroupKey";
|
|||||||
return [self.root groupForUUID:uuid];
|
return [self.root groupForUUID:uuid];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Binary *)binaryForRef:(BinaryRef *)binaryRef {
|
|
||||||
if(self.version != MPDatabaseVersion4) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
NSPredicate *filterPredicate = [NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
|
|
||||||
Binary *binaryFile = evaluatedObject;
|
|
||||||
return (binaryFile.binaryId == binaryRef.ref);
|
|
||||||
}];
|
|
||||||
Kdb4Tree *tree = (Kdb4Tree *)self.tree;
|
|
||||||
NSArray *filteredBinary = [tree.binaries filteredArrayUsingPredicate:filterPredicate];
|
|
||||||
return [filteredBinary lastObject];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (Kdb3Tree *)treeV3 {
|
- (Kdb3Tree *)treeV3 {
|
||||||
switch (_version) {
|
switch (_version) {
|
||||||
case MPDatabaseVersion3:
|
case MPDatabaseVersion3:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#import "MPCustomFieldView.h"
|
#import "MPCustomFieldView.h"
|
||||||
#import "MPDatabaseVersion.h"
|
#import "MPDatabaseVersion.h"
|
||||||
#import "MPCustomFieldTableCellView.h"
|
#import "MPCustomFieldTableCellView.h"
|
||||||
|
#import "MPSelectedAttachmentTableCellView.h"
|
||||||
|
|
||||||
#import "KdbLib.h"
|
#import "KdbLib.h"
|
||||||
#import "Kdb4Node.h"
|
#import "Kdb4Node.h"
|
||||||
@@ -58,6 +59,8 @@ enum {
|
|||||||
|
|
||||||
- (IBAction)addCustomField:(id)sender;
|
- (IBAction)addCustomField:(id)sender;
|
||||||
- (IBAction)removeCustomField:(id)sender;
|
- (IBAction)removeCustomField:(id)sender;
|
||||||
|
- (IBAction)saveAttachment:(id)sender;
|
||||||
|
- (IBAction)addAttachment:(id)sender;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@@ -91,8 +94,8 @@ enum {
|
|||||||
|
|
||||||
[_infoTabControl bind:NSSelectedIndexBinding toObject:self withKeyPath:@"activeTab" options:nil];
|
[_infoTabControl bind:NSSelectedIndexBinding toObject:self withKeyPath:@"activeTab" options:nil];
|
||||||
[_tabView bind:NSSelectedIndexBinding toObject:self withKeyPath:@"activeTab" options:nil];
|
[_tabView bind:NSSelectedIndexBinding toObject:self withKeyPath:@"activeTab" options:nil];
|
||||||
|
|
||||||
/* Set background to clearcolor so we can draw in the scrollview */
|
/* Set background to clearcolor so we can draw in the scrollview */
|
||||||
[_attachmentTableView setBackgroundColor:[NSColor clearColor]];
|
[_attachmentTableView setBackgroundColor:[NSColor clearColor]];
|
||||||
[_attachmentTableView bind:NSContentBinding toObject:self.attachmentsController withKeyPath:@"arrangedObjects" options:nil];
|
[_attachmentTableView bind:NSContentBinding toObject:self.attachmentsController withKeyPath:@"arrangedObjects" options:nil];
|
||||||
[_attachmentTableView setDelegate:self];
|
[_attachmentTableView setDelegate:self];
|
||||||
@@ -256,7 +259,7 @@ enum {
|
|||||||
|
|
||||||
[self.infoTabControl setEnabled:enabled forSegment:MPNotesTab];
|
[self.infoTabControl setEnabled:enabled forSegment:MPNotesTab];
|
||||||
[self.infoTabControl setEnabled:enabled forSegment:MPAttachmentsTab];
|
[self.infoTabControl setEnabled:enabled forSegment:MPAttachmentsTab];
|
||||||
|
|
||||||
enabled &= [self.selectedEntry isKindOfClass:[Kdb4Entry class]];
|
enabled &= [self.selectedEntry isKindOfClass:[Kdb4Entry class]];
|
||||||
[self.infoTabControl setEnabled:enabled forSegment:MPCustomFieldsTab];
|
[self.infoTabControl setEnabled:enabled forSegment:MPCustomFieldsTab];
|
||||||
}
|
}
|
||||||
@@ -313,6 +316,38 @@ enum {
|
|||||||
[document entry:entry removeStringField:(entry.stringFields)[index]];
|
[document entry:entry removeStringField:(entry.stringFields)[index]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (IBAction)saveAttachment:(id)sender {
|
||||||
|
Kdb4Entry *entry = (Kdb4Entry *)self.selectedEntry;
|
||||||
|
BinaryRef *reference = entry.binaries[[sender tag]];
|
||||||
|
|
||||||
|
|
||||||
|
NSSavePanel *savePanel = [NSSavePanel savePanel];
|
||||||
|
[savePanel setCanCreateDirectories:YES];
|
||||||
|
[savePanel setNameFieldStringValue:reference.key];
|
||||||
|
|
||||||
|
[savePanel beginSheetModalForWindow:[[self windowController] window] completionHandler:^(NSInteger result) {
|
||||||
|
if(result == NSFileHandlingPanelOKButton) {
|
||||||
|
MPDocument *document = [[self windowController] document];
|
||||||
|
[document saveAttachment:reference toLocation:[savePanel URL]];
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (IBAction)addAttachment:(id)sender {
|
||||||
|
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
|
||||||
|
[openPanel setCanChooseDirectories:NO];
|
||||||
|
[openPanel setCanChooseFiles:YES];
|
||||||
|
[openPanel setAllowsMultipleSelection:YES];
|
||||||
|
[openPanel beginSheetModalForWindow:[[self windowController] window] completionHandler:^(NSInteger result) {
|
||||||
|
if(result == NSFileHandlingPanelOKButton) {
|
||||||
|
MPDocument *document = [[self windowController] document];
|
||||||
|
for (NSURL *attachmentURL in [openPanel URLs]) {
|
||||||
|
[document addAttachment:attachmentURL toEntry:self.selectedEntry];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark Notificiations
|
#pragma mark Notificiations
|
||||||
- (void)_didChangeCurrentItem:(NSNotification *)notification {
|
- (void)_didChangeCurrentItem:(NSNotification *)notification {
|
||||||
MPDocumentWindowController *sender = [notification object];
|
MPDocumentWindowController *sender = [notification object];
|
||||||
@@ -354,8 +389,17 @@ enum {
|
|||||||
- (NSView *)_viewForAttachmentTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
- (NSView *)_viewForAttachmentTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
|
||||||
/* Decide what view to use */
|
/* Decide what view to use */
|
||||||
NSIndexSet *selectedIndexes = [self.attachmentTableView selectedRowIndexes];
|
NSIndexSet *selectedIndexes = [self.attachmentTableView selectedRowIndexes];
|
||||||
NSString *viewIdentifyer = [selectedIndexes containsIndex:row] ? @"SelectedCell" : @"NormalCell";
|
NSTableCellView *view;
|
||||||
NSTableCellView *view = [_attachmentTableView makeViewWithIdentifier:viewIdentifyer owner:_attachmentTableView];
|
if([selectedIndexes containsIndex:row]) {
|
||||||
|
MPSelectedAttachmentTableCellView *cellView = [_attachmentTableView makeViewWithIdentifier:@"SelectedCell" owner:_attachmentTableView];
|
||||||
|
[cellView.saveButton setTag:row];
|
||||||
|
[cellView.saveButton setAction:@selector(saveAttachment:)];
|
||||||
|
[cellView.saveButton setTarget:self];
|
||||||
|
view = cellView;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
view = [_attachmentTableView makeViewWithIdentifier:@"NormalCell" owner:_attachmentTableView];
|
||||||
|
}
|
||||||
/* Bind view */
|
/* Bind view */
|
||||||
if([self.selectedEntry isKindOfClass:[Kdb4Entry class]]) {
|
if([self.selectedEntry isKindOfClass:[Kdb4Entry class]]) {
|
||||||
Kdb4Entry *entry = (Kdb4Entry *)self.selectedEntry;
|
Kdb4Entry *entry = (Kdb4Entry *)self.selectedEntry;
|
||||||
|
|||||||
@@ -44,11 +44,11 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.2.1</string>
|
<string>0.3</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1923</string>
|
<string>1955</string>
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ You should have received a copy of the GNU General Public License along with thi
|
|||||||
\b0 MacPass Icon von {\field{\*\fldinst{HYPERLINK "http://iiro.jappinen.me"}}{\fldrslt Iiro J\'e4ppinen}}
|
\b0 MacPass Icon von {\field{\*\fldinst{HYPERLINK "http://iiro.jappinen.me"}}{\fldrslt Iiro J\'e4ppinen}}
|
||||||
\b \
|
\b \
|
||||||
\
|
\
|
||||||
|
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
||||||
{\field{\*\fldinst{HYPERLINK "https://github.com/robbiehanson/KissXML"}}{\fldrslt
|
{\field{\*\fldinst{HYPERLINK "https://github.com/robbiehanson/KissXML"}}{\fldrslt
|
||||||
\b0 \cf2 KissXML}}
|
\b0 \cf2 KissXML}}
|
||||||
\b0 \cf3 \
|
\b0 \cf3 \
|
||||||
@@ -49,4 +50,9 @@ Copyright \'a9 2011, Alex Rozanski. Alle Rechte vorbehalten.\
|
|||||||
\
|
\
|
||||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
||||||
{\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/questions/11386876/how-to-encode-and-decode-files-as-base64-in-cocoa-objective-c"}}{\fldrslt \cf3 Base64 Encoding Category}}\
|
{\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/questions/11386876/how-to-encode-and-decode-files-as-base64-in-cocoa-objective-c"}}{\fldrslt \cf3 Base64 Encoding Category}}\
|
||||||
Copyright @2013, {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/users/200321/denis2342"}}{\fldrslt denis2342}}}
|
Copyright @2013, {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/users/200321/denis2342"}}{\fldrslt denis2342}}\
|
||||||
|
\
|
||||||
|
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
||||||
|
{\field{\*\fldinst{HYPERLINK "http://www.cocoadev.com/index.pl?NSDataCategory"}}{\fldrslt \cf3 NSData+Gzip}}\
|
||||||
|
Basierend auf dem Code im CocoaDev Wiki\
|
||||||
|
}
|
||||||
@@ -36,6 +36,7 @@ You should have received a copy of the GNU General Public License along with thi
|
|||||||
\cf0 MacPass\kerning1\expnd0\expndtw3
|
\cf0 MacPass\kerning1\expnd0\expndtw3
|
||||||
\kerning1\expnd0\expndtw0 Icon by {\field{\*\fldinst{HYPERLINK "http://iiro.jappinen.me"}}{\fldrslt Iiro J\'e4ppinen}}\cf2 \
|
\kerning1\expnd0\expndtw0 Icon by {\field{\*\fldinst{HYPERLINK "http://iiro.jappinen.me"}}{\fldrslt Iiro J\'e4ppinen}}\cf2 \
|
||||||
\
|
\
|
||||||
|
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
||||||
{\field{\*\fldinst{HYPERLINK "https://github.com/robbiehanson/KissXML"}}{\fldrslt \cf2 KissXML}}\cf3 \
|
{\field{\*\fldinst{HYPERLINK "https://github.com/robbiehanson/KissXML"}}{\fldrslt \cf2 KissXML}}\cf3 \
|
||||||
Copyright \'a9 2012 Robbie Hanson. All rights reserved.\
|
Copyright \'a9 2012 Robbie Hanson. All rights reserved.\
|
||||||
\
|
\
|
||||||
@@ -51,5 +52,10 @@ Copyright \'a9 2010 Qiang Yu. All rights reserved.\
|
|||||||
Copyright \'a9 2011, Alex Rozanski. All rights reserved.\
|
Copyright \'a9 2011, Alex Rozanski. All rights reserved.\
|
||||||
\
|
\
|
||||||
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
||||||
{\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/questions/11386876/how-to-encode-and-decode-files-as-base64-in-cocoa-objective-c"}}{\fldrslt \cf3 Base64 Encoding Category}}\
|
{\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/questions/11386876/how-to-encode-and-decode-files-as-base64-in-cocoa-objective-c"}}{\fldrslt \cf3 NSData+Base64}}\
|
||||||
Copyright @2013, {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/users/200321/denis2342"}}{\fldrslt denis2342}}}
|
Copyright @2013, {\field{\*\fldinst{HYPERLINK "http://stackoverflow.com/users/200321/denis2342"}}{\fldrslt denis2342}}\
|
||||||
|
\
|
||||||
|
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720
|
||||||
|
{\field{\*\fldinst{HYPERLINK "http://www.cocoadev.com/index.pl?NSDataCategory"}}{\fldrslt \cf3 NSData+Gzip}}\
|
||||||
|
Extracted from code on the CocoaDev Wiki\
|
||||||
|
}
|
||||||
Submodule MiniKeePassLib updated: 7d7685ba38...ee4352c9c5
Reference in New Issue
Block a user