···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+2121+#include <LaunchServices/LaunchServices.h>
2222+#include <CoreServices/MacErrors.h>
2323+#include <stdio.h>
2424+2525+OSStatus
2626+LSFindApplicationForInfo(
2727+ OSType inCreator,
2828+ CFStringRef inBundleID,
2929+ CFStringRef inName,
3030+ FSRef * outAppRef,
3131+ CFURLRef * outAppURL)
3232+{
3333+ puts("LSFindApplicationForInfo STUB");
3434+ return unimpErr;
3535+}
3636+3737+OSStatus
3838+LSGetApplicationForInfo(
3939+ OSType inType,
4040+ OSType inCreator,
4141+ CFStringRef inExtension,
4242+ LSRolesMask inRoleMask,
4343+ FSRef * outAppRef,
4444+ CFURLRef * outAppURL)
4545+{
4646+ puts("LSGetApplicationForInfo STUB");
4747+ return unimpErr;
4848+}
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+2121+#include <LaunchServices/LaunchServices.h>
2222+#include <CoreServices/MacErrors.h>
2323+#include <stdio.h>
2424+2525+OSStatus
2626+LSOpenURLsWithRole(
2727+ CFArrayRef inURLs,
2828+ LSRolesMask inRole,
2929+ const AEKeyDesc * inAEParam,
3030+ const LSApplicationParameters * inAppParams,
3131+ ProcessSerialNumber * outPSNs,
3232+ CFIndex inMaxPSNCount)
3333+{
3434+ puts("LSOpenURLsWithRole STUB");
3535+ return unimpErr;
3636+}
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#ifndef _LSD_BUNDLE_H
2121+#define _LSD_BUNDLE_H
2222+#import <Foundation/NSObject.h>
2323+#include <CoreFoundation/CFBundle.h>
2424+2525+@interface LSBundle : NSObject
2626+{
2727+ CFBundleRef _bundle;
2828+ int _bundleId;
2929+}
3030+-(id) initWithBundle:(CFBundleRef) bundle;
3131+-(void)dealloc;
3232+-(void)process;
3333+3434+@property (readonly) int bundleId;
3535+3636++(void)scanForBundles;
3737++(void)watchForBundles;
3838+@end
3939+4040+#endif
4141+
···11+/*
22+This file is part of Darling.
33+44+Copyright (C) 2020 Lubos Dolezel
55+66+Darling is free software: you can redistribute it and/or modify
77+it under the terms of the GNU General Public License as published by
88+the Free Software Foundation, either version 3 of the License, or
99+(at your option) any later version.
1010+1111+Darling is distributed in the hope that it will be useful,
1212+but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+GNU General Public License for more details.
1515+1616+You should have received a copy of the GNU General Public License
1717+along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#include <xpc/xpc.h>
2121+#include <dispatch/dispatch.h>
2222+#include "LSBundle.h"
2323+2424+static void connectionCallback(xpc_connection_t connection);
2525+static void handleMessage(xpc_connection_t connection, xpc_object_t msg);
2626+2727+dispatch_queue_t g_serverQueue;
2828+2929+int main(int argc, const char** argv)
3030+{
3131+ g_serverQueue = dispatch_queue_create("service queue", NULL);
3232+3333+ [LSBundle scanForBundles];
3434+ [LSBundle watchForBundles];
3535+3636+ // xpc_main(connectionCallback);
3737+ // Our xpc_main() isn't done yet, so we do this manually
3838+3939+ xpc_connection_t listener = xpc_connection_create_mach_service("com.apple.coreservices.launchservicesd",
4040+ g_serverQueue, XPC_CONNECTION_MACH_SERVICE_LISTENER);
4141+4242+ xpc_connection_set_event_handler(listener, ^(xpc_object_t peer) {
4343+ if (xpc_get_type(peer) == XPC_TYPE_CONNECTION)
4444+ connectionCallback((xpc_connection_t) peer);
4545+ });
4646+ xpc_connection_resume(listener);
4747+4848+ dispatch_main();
4949+ return 0;
5050+}
5151+5252+static void connectionCallback(xpc_connection_t connection)
5353+{
5454+ pid_t pid = xpc_connection_get_pid(connection);
5555+ xpc_connection_set_event_handler(connection, ^(xpc_object_t msg) {
5656+ handleMessage(connection, msg);
5757+ });
5858+ xpc_connection_resume(connection);
5959+}
6060+6161+static void handleMessage(xpc_connection_t connection, xpc_object_t msg)
6262+{
6363+ xpc_type_t type = xpc_get_type(msg);
6464+6565+ if (type == XPC_TYPE_DICTIONARY)
6666+ {
6767+ xpc_object_t reply = xpc_dictionary_create_reply(msg);
6868+6969+ xpc_connection_send_message(connection, reply);
7070+ }
7171+}
···11-/*
22- This file is part of Darling.
33-44- Copyright (C) 2019 Lubos Dolezel
55-66- Darling is free software: you can redistribute it and/or modify
77- it under the terms of the GNU General Public License as published by
88- the Free Software Foundation, either version 3 of the License, or
99- (at your option) any later version.
1010-1111- Darling is distributed in the hope that it will be useful,
1212- but WITHOUT ANY WARRANTY; without even the implied warranty of
1313- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414- GNU General Public License for more details.
1515-1616- You should have received a copy of the GNU General Public License
1717- along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818-*/
1919-2020-#include <stdio.h>
2121-#include <string.h>
2222-#include <sys/types.h>
2323-#include <sys/stat.h>
2424-#include <unistd.h>
2525-#include <stdlib.h>
2626-2727-#include <CoreFoundation/CoreFoundation.h>
2828-#include <ApplicationServices/ApplicationServices.h>
2929-3030-static void usage(void);
3131-3232-/* TODO: Options */
3333-int main(int argc, char *argv[])
3434-{
3535- CFStringRef url_or_path;
3636- CFURLRef url;
3737- struct stat path_stat;
3838- if (argc != 2)
3939- {
4040- usage();
4141- return EXIT_FAILURE;
4242- }
4343- url_or_path = CFStringCreateWithFileSystemRepresentation(kCFAllocatorDefault, argv[1]);
4444- /* TODO: What is the URL is not a file URL? (http:, ftp:, etc) */
4545- /* url = CFURLCreateWithString(kCFAllocatorDefault, url_or_path, NULL); */
4646- url = NULL;
4747-4848- if (url == NULL)
4949- {
5050- if (lstat(argv[1], &path_stat))
5151- {
5252- perror(argv[1]);
5353- return EXIT_FAILURE;
5454- }
5555- url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, url_or_path, kCFURLPOSIXPathStyle, path_stat.st_mode & S_IFDIR);
5656- if (url == NULL)
5757- {
5858- printf("Failed to create file url: %s\n", argv[1]);
5959- return EXIT_FAILURE;
6060- }
6161- }
6262-6363- LSOpenCFURLRef(url, NULL);
6464-6565- CFRelease(url);
6666-6767- return EXIT_SUCCESS;
6868-}
6969-7070-static void usage(void)
7171-{
7272- printf("Usage: open [filenames]\n"
7373- "Help: Use open to open files, folders, and URLs from the command line.\n");
7474-}
+235
src/tools/open.m
···11+/*
22+ This file is part of Darling.
33+44+ Copyright (C) 2019-2020 Lubos Dolezel
55+66+ Darling is free software: you can redistribute it and/or modify
77+ it under the terms of the GNU General Public License as published by
88+ the Free Software Foundation, either version 3 of the License, or
99+ (at your option) any later version.
1010+1111+ Darling is distributed in the hope that it will be useful,
1212+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1313+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1414+ GNU General Public License for more details.
1515+1616+ You should have received a copy of the GNU General Public License
1717+ along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818+*/
1919+2020+#include <stdio.h>
2121+#include <string.h>
2222+#include <sys/types.h>
2323+#include <sys/stat.h>
2424+#include <unistd.h>
2525+#include <stdlib.h>
2626+#include <getopt.h>
2727+#include <stdbool.h>
2828+2929+#import <Foundation/NSArray.h>
3030+#import <Foundation/NSString.h>
3131+#import <Foundation/NSURL.h>
3232+#import <AppKit/NSWorkspace.h>
3333+#include <CoreServices/CoreServices.h>
3434+3535+static void usage(void);
3636+3737+int main(int argc, char *argv[])
3838+{
3939+ bool fresh = false;
4040+ bool reveal = false;
4141+ bool wait = false;
4242+ bool _new = false;
4343+ bool hide = false;
4444+ bool background = false;
4545+ bool header = false;
4646+ bool useDefTextEditor = false;
4747+ bool readStdin = false;
4848+4949+ const char* sdk = NULL;
5050+ const char* bundle = NULL;
5151+ const char* appname = NULL;
5252+ NSArray<NSString*>* arguments = nil;
5353+ NSArray<NSURL*>* filenames = nil;
5454+ FSRef fsref;
5555+ bool hasFSRef = false;
5656+ CFURLRef appURL = NULL;
5757+5858+ for (int i = 1; i < argc; i++)
5959+ {
6060+ if (strcmp(argv[i], "--args") == 0)
6161+ {
6262+ int count = argc-i-1;
6363+ NSString** strings = (NSString**) malloc(count * sizeof(NSString*));
6464+6565+ for (int j = 0; j < count; j++)
6666+ strings[j] = [NSString stringWithCString: argv[j+i+1] encoding: NSUTF8StringEncoding];
6767+6868+ arguments = [NSArray arrayWithObjects: strings count: count];
6969+ free(strings);
7070+7171+ argv[i] = NULL;
7272+ argc = i;
7373+ break;
7474+ }
7575+ }
7676+7777+ while (true)
7878+ {
7979+ static struct option long_options[] = {
8080+ { "fresh", no_argument, 0, 'F' },
8181+ { "reveal", no_argument, 0, 'R' },
8282+ { "wait-apps", no_argument, 0, 'W' },
8383+ { "new", no_argument, 0, 'n' },
8484+ { "hide", no_argument, 0, 'j' },
8585+ { "background", no_argument, 0, 'g' },
8686+ { "header", no_argument, 0, 'h' },
8787+ { NULL, 0, 0, 0 }
8888+ };
8989+ int c = getopt_long(argc, argv, "a:b:etfFRWnjghs:", long_options, NULL);
9090+9191+ if (c == -1)
9292+ break;
9393+9494+ switch (c)
9595+ {
9696+ case 'a':
9797+ appname = optarg;
9898+ break;
9999+ case 'b':
100100+ bundle = optarg;
101101+ break;
102102+ case 'e':
103103+ bundle = "com.apple.TextEdit";
104104+ break;
105105+ case 't':
106106+ useDefTextEditor = true;
107107+ break;
108108+ case 'f':
109109+ readStdin = true;
110110+ break;
111111+ case 'F':
112112+ fresh = true;
113113+ break;
114114+ case 'R':
115115+ reveal = true;
116116+ break;
117117+ case 'W':
118118+ wait = true;
119119+ break;
120120+ case 'n':
121121+ _new = true;
122122+ break;
123123+ case 'j':
124124+ hide = true;
125125+ break;
126126+ case 'g':
127127+ background = true;
128128+ break;
129129+ case 'h':
130130+ header = true;
131131+ break;
132132+ case 's':
133133+ sdk = optarg;
134134+ break;
135135+ default:
136136+ usage();
137137+ return EXIT_FAILURE;
138138+ }
139139+ }
140140+141141+ if (header || reveal || readStdin)
142142+ {
143143+ fprintf(stderr, "This operation is not implemented yet. Sorry.\n");
144144+ return EXIT_FAILURE;
145145+ }
146146+147147+ if (optind < argc)
148148+ {
149149+ int count = argc - optind;
150150+ NSURL** urls = (NSURL**) malloc(count * sizeof(NSURL*));
151151+152152+ for (int i = 0; i < count; i++)
153153+ urls[i] = [NSURL URLWithString:[NSString stringWithCString: argv[optind+i] encoding: NSUTF8StringEncoding]];
154154+155155+ filenames = [NSArray arrayWithObjects: urls count: count];
156156+ free(urls);
157157+ }
158158+159159+ OSStatus result = noErr;
160160+ if (useDefTextEditor)
161161+ {
162162+ result = LSGetApplicationForInfo(kLSUnknownType, kLSUnknownCreator, CFSTR("txt"), kLSRolesEditor, &fsref, &appURL);
163163+ hasFSRef = true;
164164+ }
165165+ else if (bundle != NULL)
166166+ {
167167+ result = LSFindApplicationForInfo(kLSUnknownCreator, (CFStringRef) [NSString stringWithCString:bundle encoding:NSUTF8StringEncoding], NULL, &fsref, &appURL);
168168+ hasFSRef = true;
169169+ }
170170+ else if (appname != NULL)
171171+ {
172172+ NSString* appPath = [[NSWorkspace sharedWorkspace] fullPathForApplication: [NSString stringWithCString:appname encoding:NSUTF8StringEncoding]];
173173+ if (appPath == nil)
174174+ {
175175+ fprintf(stderr, "Cannot find required application: %s\n", appname);
176176+ return EXIT_FAILURE;
177177+ }
178178+179179+ appURL = (CFURLRef) [NSURL URLWithString: appPath];
180180+ result = FSPathMakeRef((const UInt8*) [appPath UTF8String], &fsref, NULL);
181181+ }
182182+183183+ if (result != noErr)
184184+ {
185185+ fprintf(stderr, "Cannot find required application: %d\n", result);
186186+ return EXIT_FAILURE;
187187+ }
188188+189189+ NSArray<NSURL*>* urlsToOpen;
190190+ LSApplicationParameters params;
191191+192192+ memset(¶ms, 0, sizeof(params));
193193+194194+ if (hasFSRef)
195195+ params.application = &fsref;
196196+ params.argv = (CFArrayRef) arguments;
197197+198198+ if (_new)
199199+ params.flags |= kLSLaunchNewInstance;
200200+ if (background)
201201+ params.flags |= kLSLaunchDontSwitch;
202202+ if (hide)
203203+ params.flags |= kLSLaunchAndHide;
204204+205205+ if (filenames)
206206+ {
207207+ urlsToOpen = filenames;
208208+ }
209209+ else if (appURL)
210210+ {
211211+ urlsToOpen = [NSArray arrayWithObjects: (const id*) &appURL count: 1];
212212+ }
213213+ else
214214+ {
215215+ usage();
216216+ return EXIT_FAILURE;
217217+ }
218218+219219+ // TODO: Apple Events, PSNs (for waiting)
220220+ result = LSOpenURLsWithRole((CFArrayRef) urlsToOpen, kLSRolesAll, NULL, ¶ms, NULL, 0);
221221+222222+ if (result != noErr)
223223+ {
224224+ fprintf(stderr, "Failed to launch: %d\n", result);
225225+ return EXIT_FAILURE;
226226+ }
227227+228228+ return EXIT_SUCCESS;
229229+}
230230+231231+static void usage(void)
232232+{
233233+ printf("Usage: open [filenames]\n"
234234+ "Help: Use open to open files, folders, and URLs from the command line.\n");
235235+}