Revision: 3567
          http://skim-app.svn.sourceforge.net/skim-app/?rev=3567&view=rev
Author:   hofman
Date:     2008-03-27 17:48:35 -0700 (Thu, 27 Mar 2008)

Log Message:
-----------
Merge SkimNotesAgent with skimnotes command line client.

Modified Paths:
--------------
    trunk/Skim.xcodeproj/project.pbxproj
    trunk/skimnotes.m

Added Paths:
-----------
    trunk/SKAgentListener.h
    trunk/SKAgentListener.m
    trunk/SKAgentListenerProtocol.h

Added: trunk/SKAgentListener.h
===================================================================
--- trunk/SKAgentListener.h                             (rev 0)
+++ trunk/SKAgentListener.h     2008-03-28 00:48:35 UTC (rev 3567)
@@ -0,0 +1,48 @@
+/*
+ *  SkimNotesAgent.h
+ *
+ *  Created by Adam Maxwell on 04/10/07.
+ *
+ This software is Copyright (c) 2007-2008
+ Adam Maxwell. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 
+ - Neither the name of Adam Maxwell nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ 
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+
[EMAIL PROTECTED] SKAgentListener : NSObject {
+    NSConnection *connection;
+}
+
+- (id)initWithServerName:(NSString *)serverName;
+- (void)destroyConnection;
+
[EMAIL PROTECTED]

Added: trunk/SKAgentListener.m
===================================================================
--- trunk/SKAgentListener.m                             (rev 0)
+++ trunk/SKAgentListener.m     2008-03-28 00:48:35 UTC (rev 3567)
@@ -0,0 +1,197 @@
+/*
+ *  SkimNotesAgent.m
+ *
+ *  Created by Adam Maxwell on 04/10/07.
+ *
+ This software is Copyright (c) 2007-2008
+ Adam Maxwell. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 
+ - Neither the name of Adam Maxwell nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ 
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "SKAgentListener.h"
+#import "SKAgentListenerProtocol.h"
+#import <AppKit/AppKit.h>
+#import "NSFileManager_ExtendedAttributes.h"
+
+
[EMAIL PROTECTED] SKAgentListener
+
+- (id)initWithServerName:(NSString *)serverName;
+{
+    self = [super init];
+    if (self) {
+        connection = [[NSConnection alloc] initWithReceivePort:[NSPort port] 
sendPort:nil];
+        NSProtocolChecker *checker = [NSProtocolChecker 
protocolCheckerWithTarget:self protocol:@protocol(SKAgentListenerProtocol)];
+        [connection setRootObject:checker];
+        [connection setDelegate:self];
+        
+        // user can pass nil, in which case we generate a server name to be 
read from standard output
+        if (nil == serverName)
+            serverName = [[NSProcessInfo processInfo] globallyUniqueString];
+
+        if ([connection registerName:serverName] == NO) {
+            fprintf(stderr, "SkimNotesAgent pid %d: unable to register 
connection name %s; another process must be running\n", getpid(), [serverName 
UTF8String]);
+            [self destroyConnection];
+            [self release];
+            self = nil;
+        }
+        NSFileHandle *fh = [NSFileHandle fileHandleWithStandardOutput];
+        [fh writeData:[serverName dataUsingEncoding:NSUTF8StringEncoding]];
+        [fh closeFile];
+    }
+    return self;
+}
+
+- (void)dealloc
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self];
+    [self destroyConnection];
+    [super dealloc];
+}
+
+- (NSString *)notesFileWithExtension:(NSString *)extension atPath:(NSString 
*)path error:(NSError **)error {
+    NSString *filePath = nil;
+    
+    if ([extension caseInsensitiveCompare:@"skim"] == NSOrderedSame) {
+        NSArray *files = [[NSFileManager defaultManager] subpathsAtPath:path];
+        NSString *filename = @"notes.skim";
+        if ([files containsObject:filename] == NO) {
+            filename = [[[path lastPathComponent] 
stringByDeletingPathExtension] stringByAppendingPathExtension:extension];
+            if ([files containsObject:filename] == NO) {
+                unsigned index = [[files 
valueForKeyPath:@"pathExtension.lowercaseString"] indexOfObject:@"skim"];
+                filename = index == NSNotFound ? nil : [files 
objectAtIndex:index];
+            }
+        }
+        if (filename)
+            filePath = [path stringByAppendingPathComponent:filename];
+    } else {
+        NSString *skimFile = [self notesFileWithExtension:@"skim" atPath:path 
error:error];
+        if (skimFile) {
+            filePath = [[skimFile stringByDeletingPathExtension] 
stringByAppendingPathExtension:extension];
+            if ([[NSFileManager defaultManager] fileExistsAtPath:filePath] == 
NO)
+                filePath = nil;
+        }
+    }
+    if (filePath == nil && error) 
+        *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:ENOENT 
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Notes file note found", 
NSLocalizedDescriptionKey, nil]];
+    return filePath;
+}
+
+- (bycopy NSData *)SkimNotesAtPath:(in bycopy NSString *)aFile;
+{
+    NSError *error;
+    NSData *data = nil;
+    NSString *extension = [[aFile pathExtension] lastPathComponent];
+    
+    if ([extension caseInsensitiveCompare:@"pdfd"] == NSOrderedSame) {
+        NSString *notePath = [self notesFileWithExtension:@"skim" atPath:aFile 
error:&error];
+        if (notePath)
+            data = [NSData dataWithContentsOfFile:notePath options:0 
error:&error];
+        if (nil == data)
+            fprintf(stderr, "SkimNotesAgent pid %d: error getting Skim notes 
(%s)\n", getpid(), [[error description] UTF8String]);
+    } else if ([extension caseInsensitiveCompare:@"skim"] == NSOrderedSame) {
+        data = [NSData dataWithContentsOfFile:aFile options:0 error:&error];
+        if (nil == data)
+            fprintf(stderr, "SkimNotesAgent pid %d: error getting Skim notes 
(%s)\n", getpid(), [[error description] UTF8String]);
+    } else {
+        data = [[NSFileManager defaultManager] 
extendedAttributeNamed:@"net_sourceforge_skim-app_notes" atPath:[aFile 
stringByStandardizingPath] traverseLink:YES error:&error];
+        if (nil == data && [error code] != ENOATTR)
+            fprintf(stderr, "SkimNotesAgent pid %d: error getting Skim notes 
(%s)\n", getpid(), [[error description] UTF8String]);
+    }
+    return data;
+}
+
+- (bycopy NSData *)RTFNotesAtPath:(in bycopy NSString *)aFile;
+{
+    NSError *error;
+    NSData *data = nil;
+    NSString *extension = [[aFile pathExtension] lastPathComponent];
+    
+    if ([extension caseInsensitiveCompare:@"pdfd"] == NSOrderedSame) {
+        NSString *notePath = [self notesFileWithExtension:@"rtf" atPath:aFile 
error:&error];
+        if (notePath)
+            data = [NSData dataWithContentsOfFile:notePath options:0 
error:&error];
+        if (nil == data)
+            fprintf(stderr, "SkimNotesAgent pid %d: error getting RTF notes 
(%s)\n", getpid(), [[error description] UTF8String]);
+    } else {
+        data = [[NSFileManager defaultManager] 
extendedAttributeNamed:@"net_sourceforge_skim-app_rtf_notes" atPath:[aFile 
stringByStandardizingPath] traverseLink:YES error:&error];
+        if (nil == data && [error code] != ENOATTR)
+            fprintf(stderr, "SkimNotesAgent pid %d: error getting RTF notes 
(%s)\n", getpid(), [[error description] UTF8String]);
+    }
+    return data;
+}
+
+- (bycopy NSData *)textNotesAtPath:(in bycopy NSString *)aFile 
encoding:(NSStringEncoding)encoding;
+{
+    NSError *error;
+    NSString *string = nil;
+    NSString *extension = [[aFile pathExtension] lastPathComponent];
+    
+    if ([extension caseInsensitiveCompare:@"pdfd"] == NSOrderedSame) {
+        NSString *notePath = [self notesFileWithExtension:@"txt" atPath:aFile 
error:&error];
+        if (notePath)
+            string = [NSString stringWithContentsOfFile:notePath 
encoding:NSUTF8StringEncoding error:&error];
+        if (nil == string)
+            fprintf(stderr, "SkimNotesAgent pid %d: error getting text notes 
(%s)\n", getpid(), [[error description] UTF8String]);
+    } else {
+        string = [[NSFileManager defaultManager] 
propertyListFromExtendedAttributeNamed:@"net_sourceforge_skim-app_text_notes" 
atPath:[aFile stringByStandardizingPath] traverseLink:YES error:&error];
+        if (nil == string && [[[error userInfo] 
objectForKey:NSUnderlyingErrorKey] code] != ENOATTR)
+            fprintf(stderr, "SkimNotesAgent pid %d: error getting text notes 
(%s)\n", getpid(), [[error description] UTF8String]);
+    }
+    // Returning the string directly can fail under some conditions.  For some 
strings with corrupt copy-paste characters (typical for notes), -[NSString 
canBeConvertedToEncoding:NSUTF8StringEncoding] returns YES but the actual 
conversion fails.  A result seems to be that encoding the string also fails, 
which causes the DO client to get a timeout.  Returning NSUnicodeStringEncoding 
data seems to work in those cases (and is safe since we're not going over the 
wire between big/little-endian systems).
+    return [string dataUsingEncoding:encoding];
+}
+
+- (void)destroyConnection;
+{
+    [connection registerName:nil];
+    [[connection receivePort] invalidate];
+    [[connection sendPort] invalidate];
+    [connection invalidate];
+    [connection release];
+    connection = nil;
+}
+
+- (void)portDied:(NSNotification *)notification
+{
+    [self destroyConnection];
+    fprintf(stderr, "SkimNotesAgent pid %d dying because port %s is 
invalid\n", getpid(), [[[notification object] description] UTF8String]);
+    exit(0);
+}
+
+// first app to connect will be the owner of this instance of the program; 
when the connection dies, so do we
+- (BOOL)makeNewConnection:(NSConnection *)newConnection sender:(NSConnection 
*)parentConnection
+{
+    [[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(portDied:) name:NSPortDidBecomeInvalidNotification 
object:[newConnection sendPort]];
+    fprintf(stderr, "SkimNotesAgent pid %d connection registered\n", getpid());
+    return YES;
+}
+
[EMAIL PROTECTED]

Added: trunk/SKAgentListenerProtocol.h
===================================================================
--- trunk/SKAgentListenerProtocol.h                             (rev 0)
+++ trunk/SKAgentListenerProtocol.h     2008-03-28 00:48:35 UTC (rev 3567)
@@ -0,0 +1,44 @@
+/*
+ *  SKAgentListenerProtocol.h
+ *
+ *  Created by Adam Maxwell on 04/10/07.
+ *
+ This software is Copyright (c) 2007-2008
+ Adam Maxwell. All rights reserved.
+ 
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ 
+ - Neither the name of Adam Maxwell nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+ 
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
[EMAIL PROTECTED] SKAgentListenerProtocol
+
+- (bycopy NSData *)SkimNotesAtPath:(in bycopy NSString *)aFile;
+- (bycopy NSData *)RTFNotesAtPath:(in bycopy NSString *)aFile;
+- (bycopy NSData *)textNotesAtPath:(in bycopy NSString *)aFile 
encoding:(NSStringEncoding)encoding;
+
[EMAIL PROTECTED]

Modified: trunk/Skim.xcodeproj/project.pbxproj
===================================================================
--- trunk/Skim.xcodeproj/project.pbxproj        2008-03-27 14:31:04 UTC (rev 
3566)
+++ trunk/Skim.xcodeproj/project.pbxproj        2008-03-28 00:48:35 UTC (rev 
3567)
@@ -205,6 +205,8 @@
                CEF7175F0B90DF10003A2771 /* SKReleaseNotesController.m in 
Sources */ = {isa = PBXBuildFile; fileRef = CEF7175E0B90DF10003A2771 /* 
SKReleaseNotesController.m */; };
                CEF839B30C77742A00A3AD51 /* Files_SKExtensions.m in Sources */ 
= {isa = PBXBuildFile; fileRef = CEF839B10C77742A00A3AD51 /* 
Files_SKExtensions.m */; };
                CEF84C630C78A89A00A3AD51 /* SmallPreferences.tiff in Resources 
*/ = {isa = PBXBuildFile; fileRef = CEF84C620C78A89900A3AD51 /* 
SmallPreferences.tiff */; };
+               CEFA61300D9C76A10003F152 /* SKAgentListener.m in Sources */ = 
{isa = PBXBuildFile; fileRef = CEFA61260D9C73920003F152 /* SKAgentListener.m 
*/; };
+               CEFA613A0D9C77740003F152 /* SKAgentListenerProtocol.h in 
CopyFiles */ = {isa = PBXBuildFile; fileRef = CEFA612E0D9C76300003F152 /* 
SKAgentListenerProtocol.h */; };
                CEFD68740C01D4080027B933 /* SkimImporter.mdimporter in 
CopyFiles */ = {isa = PBXBuildFile; fileRef = CEFD68690C01D3BB0027B933 /* 
SkimImporter.mdimporter */; };
                CEFDF8BE0B3848C40091C61A /* SKNavigationWindow.m in Sources */ 
= {isa = PBXBuildFile; fileRef = CEFDF8BD0B3848C40091C61A /* 
SKNavigationWindow.m */; };
                F92DB5AC0B36FE1F002A26E9 /* BDSKHeaderPopUpButtonCell.m in 
Sources */ = {isa = PBXBuildFile; fileRef = F92DB5A90B36FE1F002A26E9 /* 
BDSKHeaderPopUpButtonCell.m */; };
@@ -336,6 +338,7 @@
                                CE48BC330C08B58700A166C6 /* notesTemplate.txt 
in CopyFiles */,
                                CE48BC320C08B58700A166C6 /* notesTemplate.rtf 
in CopyFiles */,
                                CE20B1600C9EFC29007C72F9 /* notesTemplate.rtfd 
in CopyFiles */,
+                               CEFA613A0D9C77740003F152 /* 
SKAgentListenerProtocol.h in CopyFiles */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
@@ -810,6 +813,9 @@
                CEF839B00C77742A00A3AD51 /* Files_SKExtensions.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
Files_SKExtensions.h; sourceTree = "<group>"; };
                CEF839B10C77742A00A3AD51 /* Files_SKExtensions.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= Files_SKExtensions.m; sourceTree = "<group>"; };
                CEF84C620C78A89900A3AD51 /* SmallPreferences.tiff */ = {isa = 
PBXFileReference; lastKnownFileType = image.tiff; name = SmallPreferences.tiff; 
path = Images/SmallPreferences.tiff; sourceTree = "<group>"; };
+               CEFA61250D9C73920003F152 /* SKAgentListener.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
SKAgentListener.h; sourceTree = "<group>"; };
+               CEFA61260D9C73920003F152 /* SKAgentListener.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= SKAgentListener.m; sourceTree = "<group>"; };
+               CEFA612E0D9C76300003F152 /* SKAgentListenerProtocol.h */ = {isa 
= PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path 
= SKAgentListenerProtocol.h; sourceTree = "<group>"; };
                CEFD68610C01D3BB0027B933 /* SkimImporter.xcodeproj */ = {isa = 
PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = 
SkimImporter.xcodeproj; path = SkimImporter/SkimImporter.xcodeproj; sourceTree 
= "<group>"; };
                CEFDF8BC0B3848C40091C61A /* SKNavigationWindow.h */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 
SKNavigationWindow.h; sourceTree = "<group>"; };
                CEFDF8BD0B3848C40091C61A /* SKNavigationWindow.m */ = {isa = 
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path 
= SKNavigationWindow.m; sourceTree = "<group>"; };
@@ -1391,6 +1397,9 @@
                        isa = PBXGroup;
                        children = (
                                CEF3BF850B99CAD300E12E3D /* skimnotes.m */,
+                               CEFA61250D9C73920003F152 /* SKAgentListener.h 
*/,
+                               CEFA61260D9C73920003F152 /* SKAgentListener.m 
*/,
+                               CEFA612E0D9C76300003F152 /* 
SKAgentListenerProtocol.h */,
                        );
                        name = Skimnotes;
                        sourceTree = "<group>";
@@ -1883,6 +1892,7 @@
                        files = (
                                CEF3BF860B99CAD300E12E3D /* skimnotes.m in 
Sources */,
                                CEF3C0AE0B9A15E800E12E3D /* 
NSFileManager_ExtendedAttributes.m in Sources */,
+                               CEFA61300D9C76A10003F152 /* SKAgentListener.m 
in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };

Modified: trunk/skimnotes.m
===================================================================
--- trunk/skimnotes.m   2008-03-27 14:31:04 UTC (rev 3566)
+++ trunk/skimnotes.m   2008-03-28 00:48:35 UTC (rev 3567)
@@ -1,17 +1,19 @@
 #import <Foundation/Foundation.h>
 #import "NSFileManager_ExtendedAttributes.h"
+#import "SKAgentListener.h"
 
 #define SKIM_NOTES_KEY @"net_sourceforge_skim-app_notes"
 #define SKIM_RTF_NOTES_KEY @"net_sourceforge_skim-app_rtf_notes"
 #define SKIM_TEXT_NOTES_KEY @"net_sourceforge_skim-app_text_notes"
 
-static char *usageStr = "Usage:\n skimnotes set PDF_FILE [SKIM_FILE|-]\n 
skimnotes get [-format skim|text|rtf] PDF_FILE 
[SKIM_FILE|RTF_FILE|TEXT_FILE|-]\n skimnotes remove PDF_FILE\n skimnotes help";
-static char *versionStr = "SkimNotes command-line client, version 1.0.";
+static char *usageStr = "Usage:\n skimnotes set PDF_FILE [SKIM_FILE|-]\n 
skimnotes get [-format skim|text|rtf] PDF_FILE 
[SKIM_FILE|RTF_FILE|TEXT_FILE|-]\n skimnotes remove PDF_FILE\n skimnotes agent 
[SERVER_NAME]\n skimnotes help";
+static char *versionStr = "SkimNotes command-line client, version 2.0.";
 
 enum {
     SKNActionGet,
     SKNActionSet,
-    SKNActionRemove
+    SKNActionRemove,
+    SKNActionAgent
 };
 
 enum {
@@ -59,117 +61,145 @@
         action = SKNActionSet;
     } else if ([actionString caseInsensitiveCompare:@"remove"] == 
NSOrderedSame) {
         action = SKNActionRemove;
+    } else if ([actionString caseInsensitiveCompare:@"agent"] == 
NSOrderedSame) {
+        action = SKNActionAgent;
     } else {
         SKNWriteUsageAndVersion();
         exit (1);
     }
     
-    NSString *formatString = nil;
-    int format = SKNFormatAuto;
-    int offset = 2;
-    
-    if ([[args objectAtIndex:2] isEqualToString:@"-format"]) {
-        if (argc < 5) {
-            SKNWriteUsageAndVersion();
-            exit (1);
-        }
-        offset = 4;
-        formatString = [args objectAtIndex:3];
-        if ([formatString caseInsensitiveCompare:@"skim"] == NSOrderedSame)
-            format = SKNFormatSkim;
-        if ([formatString caseInsensitiveCompare:@"text"] == NSOrderedSame || 
[formatString caseInsensitiveCompare:@"txt"] == NSOrderedSame)
-            format = SKNFormatText;
-        if ([formatString caseInsensitiveCompare:@"rtf"] == NSOrderedSame)
-            format = SKNFormatRTF;
-    }
-    
-    NSFileManager *fm = [NSFileManager defaultManager];
     BOOL success = NO;
-    NSString *currentDir = [fm currentDirectoryPath];
-    NSString *pdfPath = SKNNormalizedPath([args objectAtIndex:offset], 
currentDir);
-    NSString *notesPath = argc < offset + 2 ? nil : SKNNormalizedPath([args 
objectAtIndex:offset + 1], currentDir);
-    BOOL isDir = NO;
-    NSError *error = nil;
     
-    if (action != SKNActionRemove && notesPath == nil) {
-        notesPath = [[pdfPath stringByDeletingPathExtension] 
stringByAppendingPathExtension:format == SKNFormatText ? @"txt" : format == 
SKNFormatRTF ? @"rtf" : @"skim"];
-    }
-    
-    if ([[pdfPath pathExtension] caseInsensitiveCompare:@"pdf"] == 
NSOrderedSame && 
-        ([fm fileExistsAtPath:pdfPath isDirectory:&isDir] == NO || isDir))
-        pdfPath = [pdfPath stringByAppendingPathExtension:@"pdf"];
-    
-    if ([fm fileExistsAtPath:pdfPath isDirectory:&isDir] == NO || isDir) {
-        error = [NSError errorWithDomain:NSPOSIXErrorDomain code:ENOENT 
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"PDF 
file does not exist", @"Error description"), NSLocalizedDescriptionKey, nil]];
-    } else if (action == SKNActionGet) {
-        NSData *data = nil;
-        if (format == SKNFormatAuto) {
-            NSString *extension = [notesPath pathExtension];
-            if ([extension caseInsensitiveCompare:@"rtf"] == NSOrderedSame)
+    if (action == SKNActionAgent) {
+        
+        NSString *serverName = [args count] > 2 ? [args lastObject] : nil;
+        SKAgentListener *listener = [[SKAgentListener alloc] 
initWithServerName:serverName];
+
+        NSRunLoop *rl = [NSRunLoop currentRunLoop];
+        BOOL didRun;
+        NSDate *distantFuture = [NSDate distantFuture];
+        NSAutoreleasePool *runpool = [NSAutoreleasePool new];
+        
+        do {
+            [runpool release];
+            runpool = [NSAutoreleasePool new];
+            didRun = [rl runMode:NSDefaultRunLoopMode 
beforeDate:distantFuture];
+        } while (listener && didRun);
+        [runpool release];
+        
+        [listener release];
+        
+        success = YES;
+        
+    } else {
+        
+        NSString *formatString = nil;
+        int format = SKNFormatAuto;
+        int offset = 2;
+        
+        if ([[args objectAtIndex:2] isEqualToString:@"-format"]) {
+            if (argc < 5) {
+                SKNWriteUsageAndVersion();
+                exit (1);
+            }
+            offset = 4;
+            formatString = [args objectAtIndex:3];
+            if ([formatString caseInsensitiveCompare:@"skim"] == NSOrderedSame)
+                format = SKNFormatSkim;
+            if ([formatString caseInsensitiveCompare:@"text"] == NSOrderedSame 
|| [formatString caseInsensitiveCompare:@"txt"] == NSOrderedSame)
+                format = SKNFormatText;
+            if ([formatString caseInsensitiveCompare:@"rtf"] == NSOrderedSame)
                 format = SKNFormatRTF;
-            else if ([[notesPath pathExtension] caseInsensitiveCompare:@"txt"] 
== NSOrderedSame || [[notesPath pathExtension] caseInsensitiveCompare:@"text"] 
== NSOrderedSame)
-                format = SKNFormatText;
-            else
-                format = SKNFormatSkim;
         }
-        if (format == SKNFormatSkim) {
-            data = [fm extendedAttributeNamed:SKIM_NOTES_KEY atPath:pdfPath 
traverseLink:YES error:&error];
-            if (data == nil && [error code] == ENOATTR)
-                data = [NSData data];
-        } else if (format == SKNFormatText) {
-            NSString *string = [fm 
propertyListFromExtendedAttributeNamed:SKIM_TEXT_NOTES_KEY atPath:pdfPath 
traverseLink:YES error:&error];
-            data = [string dataUsingEncoding:NSUTF8StringEncoding];
-            if (string == nil && [error code] == ENOATTR)
-                data = [NSData data];
-        } else if (format == SKNFormatRTF) {
-            data = [fm extendedAttributeNamed:SKIM_RTF_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
-            if (data == nil && [error code] == ENOATTR)
-                data = [NSData data];
+        
+        NSFileManager *fm = [NSFileManager defaultManager];
+        NSString *currentDir = [fm currentDirectoryPath];
+        NSString *pdfPath = SKNNormalizedPath([args objectAtIndex:offset], 
currentDir);
+        NSString *notesPath = argc < offset + 2 ? nil : 
SKNNormalizedPath([args objectAtIndex:offset + 1], currentDir);
+        BOOL isDir = NO;
+        NSError *error = nil;
+        
+        if (action != SKNActionRemove && notesPath == nil) {
+            notesPath = [[pdfPath stringByDeletingPathExtension] 
stringByAppendingPathExtension:format == SKNFormatText ? @"txt" : format == 
SKNFormatRTF ? @"rtf" : @"skim"];
         }
-        if (data) {
-            if ([notesPath isEqualToString:@"-"]) {
-                if ([data length])
-                    [(NSFileHandle *)[NSFileHandle 
fileHandleWithStandardOutput] writeData:data];
-                success = YES;
-            } else {
-                if ([data length]) {
-                    success = [data writeToFile:notesPath 
options:NSAtomicWrite error:&error];
-                } else if ([fm fileExistsAtPath:notesPath isDirectory:&isDir] 
&& isDir == NO) {
-                    success = [fm removeFileAtPath:notesPath handler:nil];
-                    if (success = NO)
-                        error = [NSError errorWithDomain:NSPOSIXErrorDomain 
code:EACCES userInfo:[NSDictionary 
dictionaryWithObjectsAndKeys:NSLocalizedString(@"Unable to remove file", 
@"Error description"), NSLocalizedDescriptionKey, nil]];
+        
+        if ([[pdfPath pathExtension] caseInsensitiveCompare:@"pdf"] == 
NSOrderedSame && 
+            ([fm fileExistsAtPath:pdfPath isDirectory:&isDir] == NO || isDir))
+            pdfPath = [pdfPath stringByAppendingPathExtension:@"pdf"];
+        
+        if ([fm fileExistsAtPath:pdfPath isDirectory:&isDir] == NO || isDir) {
+            error = [NSError errorWithDomain:NSPOSIXErrorDomain code:ENOENT 
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:NSLocalizedString(@"PDF 
file does not exist", @"Error description"), NSLocalizedDescriptionKey, nil]];
+        } else if (action == SKNActionGet) {
+            NSData *data = nil;
+            if (format == SKNFormatAuto) {
+                NSString *extension = [notesPath pathExtension];
+                if ([extension caseInsensitiveCompare:@"rtf"] == NSOrderedSame)
+                    format = SKNFormatRTF;
+                else if ([[notesPath pathExtension] 
caseInsensitiveCompare:@"txt"] == NSOrderedSame || [[notesPath pathExtension] 
caseInsensitiveCompare:@"text"] == NSOrderedSame)
+                    format = SKNFormatText;
+                else
+                    format = SKNFormatSkim;
+            }
+            if (format == SKNFormatSkim) {
+                data = [fm extendedAttributeNamed:SKIM_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
+                if (data == nil && [error code] == ENOATTR)
+                    data = [NSData data];
+            } else if (format == SKNFormatText) {
+                NSString *string = [fm 
propertyListFromExtendedAttributeNamed:SKIM_TEXT_NOTES_KEY atPath:pdfPath 
traverseLink:YES error:&error];
+                data = [string dataUsingEncoding:NSUTF8StringEncoding];
+                if (string == nil && [error code] == ENOATTR)
+                    data = [NSData data];
+            } else if (format == SKNFormatRTF) {
+                data = [fm extendedAttributeNamed:SKIM_RTF_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
+                if (data == nil && [error code] == ENOATTR)
+                    data = [NSData data];
+            }
+            if (data) {
+                if ([notesPath isEqualToString:@"-"]) {
+                    if ([data length])
+                        [(NSFileHandle *)[NSFileHandle 
fileHandleWithStandardOutput] writeData:data];
+                    success = YES;
                 } else {
-                    success = YES;
+                    if ([data length]) {
+                        success = [data writeToFile:notesPath 
options:NSAtomicWrite error:&error];
+                    } else if ([fm fileExistsAtPath:notesPath 
isDirectory:&isDir] && isDir == NO) {
+                        success = [fm removeFileAtPath:notesPath handler:nil];
+                        if (success = NO)
+                            error = [NSError 
errorWithDomain:NSPOSIXErrorDomain code:EACCES userInfo:[NSDictionary 
dictionaryWithObjectsAndKeys:NSLocalizedString(@"Unable to remove file", 
@"Error description"), NSLocalizedDescriptionKey, nil]];
+                    } else {
+                        success = YES;
+                    }
                 }
             }
+        } else if (action == SKNActionSet && notesPath && ([notesPath 
isEqualToString:@"-"] || ([fm fileExistsAtPath:notesPath isDirectory:&isDir] && 
isDir == NO))) {
+            NSData *data = nil;
+            if ([notesPath isEqualToString:@"-"])
+                data = [[NSFileHandle fileHandleWithStandardInput] 
readDataToEndOfFile];
+            else
+                data = [NSData dataWithContentsOfFile:notesPath];
+            if (data) {
+                success = [fm removeExtendedAttribute:SKIM_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error] || [error code] == ENOATTR;
+                if (success && [data length])
+                    success = [fm setExtendedAttributeNamed:SKIM_NOTES_KEY 
toValue:data atPath:pdfPath options:0 error:&error];
+            }
+        } else if (action == SKNActionRemove) {
+            BOOL success1 = [fm removeExtendedAttribute:SKIM_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
+            if (success1 == NO && [error code] == ENOATTR)
+                success1 = YES;
+            BOOL success2 = [fm removeExtendedAttribute:SKIM_RTF_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
+            if (success2 == NO && [error code] == ENOATTR)
+                success2 = YES;
+            BOOL success3 = [fm removeExtendedAttribute:SKIM_TEXT_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
+            if (success3 == NO && [error code] == ENOATTR)
+                success3 = YES;
+            success = success1 && success2 && success3;
         }
-    } else if (action == SKNActionSet && notesPath && ([notesPath 
isEqualToString:@"-"] || ([fm fileExistsAtPath:notesPath isDirectory:&isDir] && 
isDir == NO))) {
-        NSData *data = nil;
-        if ([notesPath isEqualToString:@"-"])
-            data = [[NSFileHandle fileHandleWithStandardInput] 
readDataToEndOfFile];
-        else
-            data = [NSData dataWithContentsOfFile:notesPath];
-        if (data) {
-            success = [fm removeExtendedAttribute:SKIM_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error] || [error code] == ENOATTR;
-            if (success && [data length])
-                success = [fm setExtendedAttributeNamed:SKIM_NOTES_KEY 
toValue:data atPath:pdfPath options:0 error:&error];
-        }
-    } else if (action == SKNActionRemove) {
-        BOOL success1 = [fm removeExtendedAttribute:SKIM_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
-        if (success1 == NO && [error code] == ENOATTR)
-            success1 = YES;
-        BOOL success2 = [fm removeExtendedAttribute:SKIM_RTF_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
-        if (success2 == NO && [error code] == ENOATTR)
-            success2 = YES;
-        BOOL success3 = [fm removeExtendedAttribute:SKIM_TEXT_NOTES_KEY 
atPath:pdfPath traverseLink:YES error:&error];
-        if (success3 == NO && [error code] == ENOATTR)
-            success3 = YES;
-        success = success1 && success2 && success3;
+        
+        if (success == NO && error)
+            [(NSFileHandle *)[NSFileHandle fileHandleWithStandardError] 
writeData:[[error localizedDescription] 
dataUsingEncoding:NSUTF8StringEncoding]];
+        
     }
     
-    if (success == NO && error)
-        [(NSFileHandle *)[NSFileHandle fileHandleWithStandardError] 
writeData:[[error localizedDescription] 
dataUsingEncoding:NSUTF8StringEncoding]];
-    
     [pool release];
     
     return success ? 0 : 1;


This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit

Reply via email to