xref: /haiku/src/kits/support/Url.cpp (revision a1163de83ea633463a79de234b8742ee106531b2)
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 		fprintf(stderr, "URL too long");
81 		return B_NAME_TOO_LONG;
82 	}
83 
84 	char* argv[] = {
85 		const_cast<char*>("BUrlInvokedApplication"),
86 		const_cast<char*>(String()),
87 		NULL
88 	};
89 
90 #if DEBUG
91 	if (HasPreferredApplication())
92 		printf("HasPreferredApplication() == true\n");
93 	else
94 		printf("HasPreferredApplication() == false\n");
95 #endif
96 
97 	status = be_roster->Launch(_UrlMimeType().String(), 1, argv+1);
98 	if (status != B_OK) {
99 		fprintf(stderr, "Opening URL failed: %s\n", strerror(status));
100 	}
101 
102 	return status;
103 }
104 
105 
106 status_t
107 BUrl::_ParseAndSplit()
108 {
109 	// proto:[//]user:pass@host:port/path
110 
111 	int32 v;
112 	BString left;
113 
114 	v = FindFirst(":");
115 	if (v < 0)
116 		return B_BAD_VALUE;
117 
118 	// TODO: proto and host should be lowercased.
119 	// see http://en.wikipedia.org/wiki/URL_normalization
120 
121 	CopyInto(fProto, 0, v);
122 	CopyInto(left, v + 1, Length() - v);
123 	// TODO: RFC1738 says the // part should indicate the uri follows the
124 	// u:p@h:p/path convention, so it should be used to check for special cases.
125 	if (left.FindFirst("//") == 0)
126 		left.RemoveFirst("//");
127 	fFull = left;
128 
129 	// path part
130 	// actually some apps handle file://[host]/path
131 	// but I have no idea what proto it implies...
132 	// or maybe it's just to emphasize on "localhost".
133 	v = left.FindFirst("/");
134 	if (v == 0 || fProto == "file") {
135 		fPath = left;
136 		return B_OK;
137 	}
138 	// some protos actually implies path if it's the only component
139 	if ((v < 0) && (fProto == "beshare" || fProto == "irc")) {
140 		fPath = left;
141 		return B_OK;
142 	}
143 
144 	if (v > -1) {
145 		left.MoveInto(fPath, v+1, left.Length()-v);
146 		left.Remove(v, 1);
147 	}
148 
149 	// user:pass@host
150 	v = left.FindFirst("@");
151 	if (v > -1) {
152 		left.MoveInto(fUser, 0, v);
153 		left.Remove(0, 1);
154 		v = fUser.FindFirst(":");
155 		if (v > -1) {
156 			fUser.MoveInto(fPass, v, fUser.Length() - v);
157 			fPass.Remove(0, 1);
158 		}
159 	} else if (fProto == "finger") {
160 		// single component implies user
161 		// see also: http://www.subir.com/lynx/lynx_help/lynx_url_support.html
162 		fUser = left;
163 		return B_OK;
164 	}
165 
166 	// host:port
167 	v = left.FindFirst(":");
168 	if (v > -1) {
169 		left.MoveInto(fPort, v + 1, left.Length() - v);
170 		left.Remove(v, 1);
171 	}
172 
173 	// not much left...
174 	fHost = left;
175 
176 	return B_OK;
177 }
178 
179 
180 BString
181 BUrl::_UrlMimeType() const
182 {
183 	BString mime;
184 	mime << "application/x-vnd.Be.URL." << fProto;
185 
186 	return BString(mime);
187 }
188 
189 
190 bool
191 BUrl::HasHost() const
192 {
193 	return fHost.Length();
194 }
195 
196 
197 bool
198 BUrl::HasPort() const
199 {
200 	return fPort.Length();
201 }
202 
203 
204 bool
205 BUrl::HasUser() const
206 {
207 	return fUser.Length();
208 }
209 
210 
211 bool
212 BUrl::HasPass() const
213 {
214 	return fPass.Length();
215 }
216 
217 
218 bool
219 BUrl::HasPath() const
220 {
221 	return fPath.Length();
222 }
223 
224 
225 const BString&
226 BUrl::Proto() const
227 {
228 	return fProto;
229 }
230 
231 
232 const BString&
233 BUrl::Full() const
234 {
235 	// RFC1738's "sheme-part"
236 	return fFull;
237 }
238 
239 
240 const BString&
241 BUrl::Host() const
242 {
243 	return fHost;
244 }
245 
246 
247 const BString&
248 BUrl::Port() const
249 {
250 	return fPort;
251 }
252 
253 
254 const BString&
255 BUrl::User() const
256 {
257 	return fUser;
258 }
259 
260 
261 const BString&
262 BUrl::Pass() const
263 {
264 	return fPass;
265 }
266 
267 
268 const BString&
269 BUrl::Path() const
270 {
271 	return fPath;
272 }
273 
274 
275 } // namespace Support
276 } // namespace BPrivate
277 
278