1/*
2 * Copyright 2003-2007, Axel D��rfler, axeld@pinc-software.de.
3 * Copyright 2005-2007, Fran��ois Revol, revol@free.fr.
4 * Copyright 2009, Jonas Sundstr��m, jonas@kirilla.com.
5 * Copyright 2014 Haiku, Inc. All rights reserved.
6 *
7 * Distributed under the terms of the MIT License.
8 *
9 * Authors:
10 *		Axel D��rfler, axeld@pinc-software.de
11 *		Fran��ois Revol, revol@free.fr
12 *		John Scipione, jscipione@gmail.com
13 *		Jonas Sundstr��m, jonas@kirilla.com
14 */
15
16/*! Launches an application/document from the shell */
17
18
19#include <errno.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <strings.h>
23
24#include <Entry.h>
25#include <List.h>
26#include <Mime.h>
27#include <Roster.h>
28#include <String.h>
29#include <Url.h>
30
31#include <tracker_private.h>
32
33
34status_t
35open_file(const char* openWith, BEntry& entry, int32 line = -1, int32 col = -1)
36{
37	entry_ref ref;
38	status_t result = entry.GetRef(&ref);
39	if (result != B_OK)
40		return result;
41
42	BMessenger target(openWith != NULL ? openWith : kTrackerSignature);
43	if (!target.IsValid())
44		return be_roster->Launch(&ref);
45
46	BMessage message(B_REFS_RECEIVED);
47	message.AddRef("refs", &ref);
48	if (line > -1)
49		message.AddInt32("be:line", line);
50
51	if (col > -1)
52		message.AddInt32("be:column", col);
53
54	// tell the app to open the file
55	return target.SendMessage(&message);
56}
57
58
59int
60main(int argc, char** argv)
61{
62	int exitCode = EXIT_SUCCESS;
63	const char* openWith = NULL;
64
65	char* progName = argv[0];
66	if (strrchr(progName, '/'))
67		progName = strrchr(progName, '/') + 1;
68
69	if (argc < 2) {
70		fprintf(stderr,"usage: %s <file[:line[:column]] or url or application "
71			"signature> ...\n", progName);
72	}
73
74	while (*++argv) {
75		status_t result = B_OK;
76		argc--;
77
78		BEntry entry(*argv);
79		if ((result = entry.InitCheck()) == B_OK && entry.Exists()) {
80			result = open_file(openWith, entry);
81		} else if (!strncasecmp("application/", *argv, 12)) {
82			// maybe it's an application-mimetype?
83
84			// subsequent files are open with that app
85			openWith = *argv;
86
87			// in the case the app is already started,
88			// don't start it twice if we have other args
89			BList teams;
90			if (argc > 1)
91				be_roster->GetAppList(*argv, &teams);
92
93			if (teams.IsEmpty())
94				result = be_roster->Launch(*argv);
95			else
96				result = B_OK;
97		} else if (strchr(*argv, ':')) {
98			// try to open it as an URI
99			BUrl url(*argv);
100			result = url.OpenWithPreferredApplication();
101			if (result == B_OK || result == B_ALREADY_RUNNING)
102				continue;
103
104			// maybe it's "file:line" or "file:line:col"
105			int line = 0, col = 0, i;
106			result = B_ENTRY_NOT_FOUND;
107			// remove gcc error's last :
108			BString arg(*argv);
109			if (arg[arg.Length() - 1] == ':')
110				arg.Truncate(arg.Length() - 1);
111
112			i = arg.FindLast(':');
113			if (i > 0) {
114				line = atoi(arg.String() + i + 1);
115				arg.Truncate(i);
116
117				result = entry.SetTo(arg.String());
118				if (result == B_OK && entry.Exists()) {
119					result = open_file(openWith, entry, line);
120					if (result == B_OK)
121						continue;
122				}
123
124				// get the column
125				col = line;
126				i = arg.FindLast(':');
127				line = atoi(arg.String() + i + 1);
128				arg.Truncate(i);
129
130				result = entry.SetTo(arg.String());
131				if (result == B_OK && entry.Exists())
132					result = open_file(openWith, entry, line, col);
133			}
134		} else
135			result = B_ENTRY_NOT_FOUND;
136
137		if (result != B_OK && result != B_ALREADY_RUNNING) {
138			fprintf(stderr, "%s: \"%s\": %s\n", progName, *argv,
139				strerror(result));
140			// make sure the shell knows this
141			exitCode = EXIT_FAILURE;
142		}
143	}
144
145	return exitCode;
146}
147