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