xref: /haiku/src/kits/support/Url.cpp (revision f8da8f3477d3c18142e59d17d05a545982faa5a8)
1 /*
2  * Copyright 2007-2009 Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		François Revol, revol@free.fr
7  *		Jonas Sundström, jonas@kirilla.com
8  */
9 
10 /*! Url class for parsing an URL and opening it with its preferred handler. */
11 
12 
13 #include <Debug.h>
14 #include <MimeType.h>
15 #include <Roster.h>
16 #include <StorageDefs.h>
17 
18 #include <Url.h>
19 
20 
21 namespace BPrivate {
22 namespace Support {
23 
24 BUrl::BUrl(const char* url)
25 	: BString(url)
26 {
27 	fStatus = _ParseAndSplit();
28 }
29 
30 
31 BUrl::~BUrl()
32 {
33 }
34 
35 
36 status_t
37 BUrl::InitCheck() const
38 {
39 	return fStatus;
40 }
41 
42 
43 bool
44 BUrl::HasPreferredApplication() const
45 {
46 	BString appSignature = PreferredApplication();
47 	BMimeType mime(appSignature.String());
48 
49 	if (appSignature.IFindFirst("application/") == 0
50 		&& mime.IsValid())
51 		return true;
52 
53 	return false;
54 }
55 
56 
57 BString
58 BUrl::PreferredApplication() const
59 {
60 	BString appSignature;
61 	BMimeType mime(_UrlMimeType().String());
62 	mime.GetPreferredApp(appSignature.LockBuffer(B_MIME_TYPE_LENGTH));
63 	appSignature.UnlockBuffer();
64 
65 	return BString(appSignature);
66 }
67 
68 
69 status_t
70 BUrl::OpenWithPreferredApplication(bool onProblemAskUser) const
71 {
72 	status_t status = InitCheck();
73 	if (status != B_OK)
74 		return status;
75 
76 	if (Length() > B_PATH_NAME_LENGTH) {
77 		// TODO: BAlert
78 		//	if (onProblemAskUser)
79 		//		BAlert ... Too long URL!
80 #if DEBUG
81 		fprintf(stderr, "URL too long");
82 #endif
83 		return B_NAME_TOO_LONG;
84 	}
85 
86 	char* argv[] = {
87 		const_cast<char*>("BUrlInvokedApplication"),
88 		const_cast<char*>(String()),
89 		NULL
90 	};
91 
92 #if DEBUG
93 	if (HasPreferredApplication())
94 		printf("HasPreferredApplication() == true\n");
95 	else
96 		printf("HasPreferredApplication() == false\n");
97 #endif
98 
99 	status = be_roster->Launch(_UrlMimeType().String(), 1, argv+1);
100 	if (status != B_OK) {
101 #if DEBUG
102 		fprintf(stderr, "Opening URL failed: %s\n", strerror(status));
103 #endif
104 	}
105 
106 	return status;
107 }
108 
109 
110 status_t
111 BUrl::_ParseAndSplit()
112 {
113 	// proto:[//]user:pass@host:port/path
114 
115 	int32 v;
116 	BString left;
117 
118 	v = FindFirst(":");
119 	if (v < 0)
120 		return B_BAD_VALUE;
121 
122 	// TODO: proto and host should be lowercased.
123 	// see http://en.wikipedia.org/wiki/URL_normalization
124 
125 	CopyInto(fProto, 0, v);
126 	CopyInto(left, v + 1, Length() - v);
127 	// TODO: RFC1738 says the // part should indicate the uri follows the
128 	// u:p@h:p/path convention, so it should be used to check for special cases.
129 	if (left.FindFirst("//") == 0)
130 		left.RemoveFirst("//");
131 	fFull = left;
132 
133 	// path part
134 	// actually some apps handle file://[host]/path
135 	// but I have no idea what proto it implies...
136 	// or maybe it's just to emphasize on "localhost".
137 	v = left.FindFirst("/");
138 	if (v == 0 || fProto == "file") {
139 		fPath = left;
140 		return B_OK;
141 	}
142 	// some protos actually implies path if it's the only component
143 	if ((v < 0) && (fProto == "beshare" || fProto == "irc")) {
144 		fPath = left;
145 		return B_OK;
146 	}
147 
148 	if (v > -1) {
149 		left.MoveInto(fPath, v+1, left.Length()-v);
150 		left.Remove(v, 1);
151 	}
152 
153 	// user:pass@host
154 	v = left.FindFirst("@");
155 	if (v > -1) {
156 		left.MoveInto(fUser, 0, v);
157 		left.Remove(0, 1);
158 		v = fUser.FindFirst(":");
159 		if (v > -1) {
160 			fUser.MoveInto(fPass, v, fUser.Length() - v);
161 			fPass.Remove(0, 1);
162 		}
163 	} else if (fProto == "finger") {
164 		// single component implies user
165 		// see also: http://www.subir.com/lynx/lynx_help/lynx_url_support.html
166 		fUser = left;
167 		return B_OK;
168 	}
169 
170 	// host:port
171 	v = left.FindFirst(":");
172 	if (v > -1) {
173 		left.MoveInto(fPort, v + 1, left.Length() - v);
174 		left.Remove(v, 1);
175 	}
176 
177 	// not much left...
178 	fHost = left;
179 
180 	return B_OK;
181 }
182 
183 
184 BString
185 BUrl::_UrlMimeType() const
186 {
187 	BString mime;
188 	mime << "application/x-vnd.Be.URL." << fProto;
189 
190 	return BString(mime);
191 }
192 
193 
194 bool
195 BUrl::HasHost() const
196 {
197 	return fHost.Length();
198 }
199 
200 
201 bool
202 BUrl::HasPort() const
203 {
204 	return fPort.Length();
205 }
206 
207 
208 bool
209 BUrl::HasUser() const
210 {
211 	return fUser.Length();
212 }
213 
214 
215 bool
216 BUrl::HasPass() const
217 {
218 	return fPass.Length();
219 }
220 
221 
222 bool
223 BUrl::HasPath() const
224 {
225 	return fPath.Length();
226 }
227 
228 
229 const BString&
230 BUrl::Proto() const
231 {
232 	return fProto;
233 }
234 
235 
236 const BString&
237 BUrl::Full() const
238 {
239 	// RFC1738's "sheme-part"
240 	return fFull;
241 }
242 
243 
244 const BString&
245 BUrl::Host() const
246 {
247 	return fHost;
248 }
249 
250 
251 const BString&
252 BUrl::Port() const
253 {
254 	return fPort;
255 }
256 
257 
258 const BString&
259 BUrl::User() const
260 {
261 	return fUser;
262 }
263 
264 
265 const BString&
266 BUrl::Pass() const
267 {
268 	return fPass;
269 }
270 
271 
272 const BString&
273 BUrl::Path() const
274 {
275 	return fPath;
276 }
277 
278 
279 } // namespace Support
280 } // namespace BPrivate
281 
282