Cocoa - Open File Package in Finder - cocoa

I am trying to open the Finder in a certain package.
I got this file, Example.backup, which is just a folder with an extension. In the finder, you can right click it (Show Package Contents) and I will be presented with the files. (there is no Contents folder).
I've tried opening it with NSWorkspace's methods but none open the finder at that directory, they either select the file or open it with the associated program.
Is there a way to do this in AppleScript maybe? Or Cocoa?
Thanks

Since no one answered yet, there might not be a one line solution.
All I could think of was a workaround: call /usr/bin/open with the -R option, which will reveal the given file in Finder. Since you want to show the contents of the package, you will have to reveal any file that is inside (not the package itself).
Downsides: won't work on empty package (but then you could just reveal the package), also the Finder window will show a selection on the last item.
NSString *pathToBundle = #"/tmp/test.app";
NSFileManager *fm = [[[NSFileManager alloc] init] autorelease];
// get the last file/directory in the package
// TODO: error handling / empty package
NSString *lastItemInBundle = [[fm contentsOfDirectoryAtPath:pathToBundle error:NULL] lastObject];
// reveal this file in Finder, by using /usr/bin/open
// see -R option in the manpage
NSTask *open = [[[NSTask alloc] init] autorelease];
[open setLaunchPath:#"/usr/bin/open"];
[open setCurrentDirectoryPath:pathToBundle];
[open setArguments:[NSArray arrayWithObjects:#"-R", lastItemInBundle, nil]];
[open launch];

Related

Letting macOS sandboxed apps write file created by my non-sandboxed app

I have a macOS/Objective-C/Cocoa application. We want to spawn external applications, like TextEdit, to edit files created by this app. I'm creating these files by copying it into my ~/Documents directory (eventually I'd like to put it elsewhere, but I'm trying to simplify) with:
NSFileManager *defaultManager = [NSFileManager defaultManager];
[defaultManager copyItemAtPath:srcPath toPath:destPath error:&err];
NSDate *sourceModified = [self lastModificationOfFile:srcPath];
NSDictionary * attr = #{ NSFileModificationDate : sourceModified,
NSFileImmutable : [NSNumber numberWithBool:NO],
NSFilePosixPermissions : [NSNumber numberWithUnsignedLong:0666],
};
[defaultManager setAttributes:attr ofItemAtPath:destPath error:nil];
When I open this file in TextEdit, the window header says "filename.txt - Locked". Editing the document gives me the "Are you sure you want to modify the document in place?" dialog. I select "Overwrite", but then attempts to save give me "The document "filename.txt" could not be saved. You don't have permission."
However, this writes a "filename.txt.sb-a69dcdc5-7V6D2g" (or similarly named) file into my Documents directory. And files created from the bash shell with "echo blablabla > filename.txt" in that same directory open just fine.
I have tried many variations on those attributes. I cannot see any difference between the files which work and those which display "... - Locked" using "ls -la# filename.txt" or "xattr", even side-by-side in the same directory.
Clearly I'm up against some sandboxing issue with the files I create, but all of my search results are about the other side of this problem.
Argh. I found this: Why does TextEdit open HTML files as locked. Apparently because of the content of my .txt file, TextEdit was interpreting it as an HTML document and treating it differently based on that. Replaced the content of the file with things that didn't look like HTML and I'm able to edit the document now.

NSFileManager's currentDirectoryPath returns root directory when .app is run at Desktop

I'm developing a basic web service, and am working on the login screen. When the user presses the "login" button, I want it to activate a NSTask that runs a binary which is bundled with the application (which performs the login with the given credentials). Right now, I get the working directory, and append the relative location of the binary to the working directory to run it. The binary runs fine when I just place the binary in a static location on my computer, but I would prefer to bundle the binary in the app's resources instead (unless this is a bad idea).
The gist of my code is available here.
Where is the best place to put a binary in the XCode project directory, so that I can bundle it in the folder "X.app/Contents"?
Currently, I am just getting the current working directory, and then appending the relative location of the binaries to this string. The following code is contained in an override of the - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil method:
NSFileManager *filemgr = [[NSFileManager alloc] init];
self.pathString = [[NSString alloc] initWithString:filemgr.currentDirectoryPath];
I launch the task with the following code (wrapped in a method in a subclassed NSViewController):
NSString *launchPath = [self.pathString stringByAppendingString:#"/X.app/Contents/Resources/loginFromClient"];
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: launchPath];
NSArray *arguments;
arguments = [NSArray arrayWithObjects:username, nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
This works when the application is run in the Debug folder.
HOWEVER, when I try to move it to a different location (ie, copying the X.app to Desktop), the filemgr reports that the currentDirectoryPath is the root directory ("/").
This brings me to two questions:
Why is the NSFileManager reporting that the current directory is "/", when it should be "/Users/stevenschmatz/Desktop/X.app"?
Is there any way just to refer to a subdirectory in the .app folder directly, so you can run a binary regardless of the app's location without finding the working directory at all?
Thank you in advance!
The currentDirectoryPath is dependent on the launch environment and has nothing to do with the location of your application.
To get data inside your app bundle, look at [NSBundle mainBundle]. An equivalent to your code above would be:
NSString *launchPath=[NSBundle.mainBundle
pathForResource:#"loginFromClient"
ofType:nil
];

Copy files to and from Application Support

I deal a lot with Lotus Notes in my company. I wrote a great application in C# to copy specific files to and from the user's Lotus Notes directory. Now I am wanting to write that application for OSX in Objective C. I have a handful of different files that need to be copied from ~/Library/Application Support/Lotus Notes Data/.
I am running into admin issues when I run a test to copy a single file. What is the best/easiest way(I am a beginner) to prompt the user for admin credentials and execute the file copy code with the newly acquired rights?
I did try implementing the BLAuthentication Class I found online, but it would not compile. I currently don't have access to my work computer to post the code.
Try like this below:-
NSString *path=[NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES)lastObject];
NSString *testUrl =[path stringByAppendingPathComponent:#"/LotusNotesData/source.rtf"];
//
if ([[NSFileManager defaultManager]fileExistsAtPath:testUrl]) {
NSLog(#"yes");
}
//Below destination is folder name which should be exist on your machine or else you can create programmatically as well
NSString *testUrl2 = #"/Users/home/Documents/destination";
NSLog(#"%#",testUrl);
NSLog(#"%#",testUrl2);
NSError *err=nil;
//Now we are copying the souce path to destination folder with appending file name (it can be any your name becuase file manager copy source file contents to your destination file contents)
//Here given file name is a source.rtf where you can give any your name. Also this is for copying source contents to destination contents
NSFileManager *fm=[NSFileManager defaultManager];
if ([fm copyItemAtPath:testUrl toPath:[testUrl2 stringByAppendingPathComponent:#"source.rtf"] error:&err])
{
NSLog(#"success");
}
else
{
NSLog(#"%#",[err localizedDescription]);
}
Use Apple Script to copy files with privilege access.
do shell script "cp source_path destination_path" with administrator privileges
where source path is path of file to be copied.
You may call the Apple script by adding a ".scpt" file with above script in your bundle and using code below:
- (void) runEmbeddedScriptFile: (NSString*)fileName
{
NSString* path = [[NSBundle bundleForClass:[self class]] pathForResource:fileName ofType:#"scpt"];
NSURL* url = [NSURL fileURLWithPath:path];
NSDictionary* errors = [NSDictionary dictionary];
NSAppleScript* appleScript = [[NSAppleScript alloc] initWithContentsOfURL:url error:&errors];
[appleScript executeAndReturnError:nil];
[appleScript release];
}

Why is an NSString making my Release version crash but inside of Xcode it works?

My program pulls in a C style string from a file, converts it to an NSString and places it in an NSMutableArray. Every time I run the program, either Debug or Release version, in XCode it runs perfectly. However every time I run it outside of XCode it crashes and the report says "-[NSPlaceholderString initWithString:]: nil argument'". This is the line of code where the problem occurs.
input = [[[NSString alloc] initWithString:[NSString stringWithUTF8String:data->acctNames]] mutableCopy];
I have also tried this:
input = [NSString stringWithUTF8String:data->acctNames];
Can anyone explain what is wrong with this?
Sounds like the file you are opening doesn't exist and the string is not being initialized. You should look at the file path and see if it is an absolute path. Maybe you are trying to open the file in a local directory and the file doesn't exist in the run directory after you have built the binary.

Why can I select aliases but not symbolic links in NSOpenPanel?

I want to create an NSOpenPanel that can select any kind of file, so I do this
NSOpenPanel* panel = [NSOpenPanel openPanel];
if([panel runModalForTypes:nil] == NSOKButton) {
// process files here
}
which lets me select all files except symbolic links.
They're simply not selectable and the obvious setResolvesAliases
does nothing.
What gives?
Update 1: I did some more testing and found that this strangeness
is present in Leopard (10.5.5) but not in Tiger (10.4.8).
Update 2: The code above can select mac aliases (persistent path
data that lives in the resource fork) but not symlinks (files created with ln -s).
I cannot reproduce this. I just tried it and it works just fine. If symlink points to a directory, it shows the directory content when I select the symlink and if the symlink points to a file, I can select it as well.
Of course if the symlink points to a directory, you can only select it if choosing directories is allowed
NSOpenPanel * panel = [NSOpenPanel openPanel];
[panel setCanChooseDirectories:YES];
if ([panel runModalForTypes:nil] == NSOKButton) {
NSLog(#"%#", [panel filenames]);
}
Your code sample worked for me, as well - I'm using 10.5.5 and XCode 3.1, if it matters.
If the alias is to a directory, I couldn't select the alias, since it resolved to the directory that it was pointing to, not the alias itself (the panel seems to resolve aliases by default). I was able to select an alias to a file, though.

Resources