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