1 // MIMEManager.cpp 2 3 #include <Bitmap.h> 4 #include <ClassInfo.h> 5 #include <Message.h> 6 #include <Messenger.h> 7 #include <mime/CreateAppMetaMimeThread.h> 8 #include <mime/MimeSnifferAddonManager.h> 9 #include <mime/UpdateMimeInfoThread.h> 10 #include <Path.h> 11 #include <RegistrarDefs.h> 12 #include <String.h> 13 #include <TypeConstants.h> 14 15 #include <stdio.h> 16 #include <string> 17 18 using namespace std; 19 using namespace BPrivate; 20 21 #include "MIMEManager.h" 22 #include "TextSnifferAddon.h" 23 24 /*! 25 \class MIMEManager 26 \brief MIMEManager handles communication between BMimeType and the system-wide 27 MimeDatabase object for BMimeType's write and non-atomic read functions. 28 29 */ 30 31 // constructor 32 /*! \brief Creates and initializes a MIMEManager. 33 */ 34 MIMEManager::MIMEManager() 35 : BLooper("main_mime") 36 , fDatabase() 37 , fThreadManager() 38 { 39 AddHandler(&fThreadManager); 40 41 // prepare the MimeSnifferAddonManager and the built-in add-ons 42 status_t error = MimeSnifferAddonManager::CreateDefault(); 43 if (error == B_OK) { 44 MimeSnifferAddonManager* addonManager 45 = MimeSnifferAddonManager::Default(); 46 addonManager->AddMimeSnifferAddon(new(nothrow) TextSnifferAddon()); 47 } 48 } 49 50 // destructor 51 /*! \brief Frees all resources associate with this object. 52 */ 53 MIMEManager::~MIMEManager() 54 { 55 } 56 57 // MessageReceived 58 /*! \brief Overrides the super class version to handle the MIME specific 59 messages. 60 \param message The message to be handled 61 */ 62 void 63 MIMEManager::MessageReceived(BMessage *message) 64 { 65 BMessage reply; 66 status_t err; 67 68 switch (message->what) { 69 case B_REG_MIME_SET_PARAM: 70 HandleSetParam(message); 71 break; 72 73 case B_REG_MIME_DELETE_PARAM: 74 HandleDeleteParam(message); 75 break; 76 77 case B_REG_MIME_START_WATCHING: 78 case B_REG_MIME_STOP_WATCHING: 79 { 80 BMessenger messenger; 81 err = message->FindMessenger("target", &messenger); 82 if (!err) { 83 err = message->what == B_REG_MIME_START_WATCHING 84 ? fDatabase.StartWatching(messenger) 85 : fDatabase.StopWatching(messenger); 86 } 87 88 reply.what = B_REG_RESULT; 89 reply.AddInt32("result", err); 90 message->SendReply(&reply, this); 91 break; 92 } 93 94 case B_REG_MIME_INSTALL: 95 case B_REG_MIME_DELETE: 96 { 97 const char *type; 98 err = message->FindString("type", &type); 99 if (!err) 100 err = message->what == B_REG_MIME_INSTALL 101 ? fDatabase.Install(type) 102 : fDatabase.Delete(type); 103 104 reply.what = B_REG_RESULT; 105 reply.AddInt32("result", err); 106 message->SendReply(&reply, this); 107 break; 108 } 109 110 case B_REG_MIME_GET_INSTALLED_TYPES: 111 { 112 const char *supertype; 113 err = message->FindString("supertype", &supertype); 114 if (err == B_NAME_NOT_FOUND) 115 err = fDatabase.GetInstalledTypes(&reply); 116 else if (!err) 117 err = fDatabase.GetInstalledTypes(supertype, &reply); 118 119 reply.what = B_REG_RESULT; 120 reply.AddInt32("result", err); 121 message->SendReply(&reply, this); 122 break; 123 } 124 125 case B_REG_MIME_GET_INSTALLED_SUPERTYPES: 126 { 127 err = fDatabase.GetInstalledSupertypes(&reply); 128 129 reply.what = B_REG_RESULT; 130 reply.AddInt32("result", err); 131 message->SendReply(&reply, this); 132 break; 133 } 134 135 case B_REG_MIME_GET_SUPPORTING_APPS: 136 { 137 const char *type; 138 err = message->FindString("type", &type); 139 if (!err) 140 err = fDatabase.GetSupportingApps(type, &reply); 141 142 reply.what = B_REG_RESULT; 143 reply.AddInt32("result", err); 144 message->SendReply(&reply, this); 145 break; 146 } 147 148 case B_REG_MIME_GET_ASSOCIATED_TYPES: 149 { 150 const char *extension; 151 err = message->FindString("extension", &extension); 152 if (!err) 153 err = fDatabase.GetAssociatedTypes(extension, &reply); 154 155 reply.what = B_REG_RESULT; 156 reply.AddInt32("result", err); 157 message->SendReply(&reply, this); 158 break; 159 } 160 161 case B_REG_MIME_SNIFF: 162 { 163 BString str; 164 entry_ref ref; 165 const char *filename; 166 err = message->FindString("filename", &filename); 167 if (!err) 168 err = fDatabase.GuessMimeType(filename, &str); 169 else if (err == B_NAME_NOT_FOUND) { 170 err = message->FindRef("file ref", &ref); 171 if (!err) 172 err = fDatabase.GuessMimeType(&ref, &str); 173 else if (err == B_NAME_NOT_FOUND) { 174 const void *data; 175 int32 dataSize; 176 err = message->FindData("data", B_RAW_TYPE, &data, 177 &dataSize); 178 if (!err) 179 err = fDatabase.GuessMimeType(data, dataSize, &str); 180 } 181 } 182 if (!err) 183 err = reply.AddString("mime type", str); 184 185 reply.what = B_REG_RESULT; 186 reply.AddInt32("result", err); 187 message->SendReply(&reply, this); 188 break; 189 } 190 191 case B_REG_MIME_CREATE_APP_META_MIME: 192 case B_REG_MIME_UPDATE_MIME_INFO: 193 { 194 using BPrivate::Storage::Mime::MimeUpdateThread; 195 using BPrivate::Storage::Mime::CreateAppMetaMimeThread; 196 using BPrivate::Storage::Mime::UpdateMimeInfoThread; 197 198 entry_ref root; 199 bool recursive; 200 bool synchronous = false; 201 int32 force; 202 203 MimeUpdateThread *thread = NULL; 204 205 status_t threadStatus = B_NO_INIT; 206 bool messageIsDetached = false; 207 bool stillOwnThread = true; 208 209 // Gather our arguments 210 err = message->FindRef("entry", &root); 211 if (!err) 212 err = message->FindBool("recursive", &recursive); 213 if (!err) 214 err = message->FindBool("synchronous", &synchronous); 215 if (!err) 216 err = message->FindInt32("force", &force); 217 218 // Detach the message for synchronous calls 219 if (!err && synchronous) { 220 DetachCurrentMessage(); 221 messageIsDetached = true; 222 } 223 224 // Create the appropriate flavor of mime update thread 225 if (!err) { 226 switch (message->what) { 227 case B_REG_MIME_CREATE_APP_META_MIME: 228 thread = new(nothrow) CreateAppMetaMimeThread((synchronous ? 229 "create_app_meta_mime (s)" : "create_app_meta_mime (a)"), 230 B_NORMAL_PRIORITY, BMessenger(&fThreadManager), &root, recursive, 231 force, synchronous ? message : NULL); 232 break; 233 234 case B_REG_MIME_UPDATE_MIME_INFO: 235 thread = new(nothrow) UpdateMimeInfoThread((synchronous ? 236 "update_mime_info (s)" : "update_mime_info (a)"), 237 B_NORMAL_PRIORITY, BMessenger(&fThreadManager), &root, recursive, 238 force, synchronous ? message : NULL); 239 break; 240 241 default: 242 err = B_BAD_VALUE; 243 break; 244 } 245 } 246 if (!err) 247 err = thread ? B_OK : B_NO_MEMORY; 248 if (!err) 249 err = threadStatus = thread->InitCheck(); 250 251 // Launch the thread 252 if (!err) { 253 err = fThreadManager.LaunchThread(thread); 254 if (!err) { 255 stillOwnThread = false; 256 } 257 } 258 259 // If something went wrong, we need to notify the sender regardless. However, 260 // if this is a synchronous call, we've already detached the message, and must 261 // be careful that it gets deleted once and only once. Thus, if the MimeUpdateThread 262 // object was created successfully, we don't need to delete the message, as that 263 // object has assumed control of it. Otherwise, we are still responsible. 264 if (err || !synchronous) { 265 // Send the reply 266 reply.what = B_REG_RESULT; 267 reply.AddInt32("result", err); 268 message->SendReply(&reply, this); 269 } 270 // Delete the message if necessary 271 if (messageIsDetached && threadStatus != B_OK) 272 delete message; 273 // Delete the thread if necessary 274 if (stillOwnThread) 275 delete thread; 276 break; 277 } 278 279 default: 280 printf("MIMEMan: msg->what == %lx (%.4s)\n", message->what, 281 (char*)&(message->what)); 282 BLooper::MessageReceived(message); 283 break; 284 } 285 } 286 287 // HandleSetParam 288 //! Handles all B_REG_MIME_SET_PARAM messages 289 void 290 MIMEManager::HandleSetParam(BMessage *message) 291 { 292 status_t err; 293 int32 which; 294 const char *type; 295 296 err = message->FindString("type", &type); 297 if (!err) 298 err = message->FindInt32("which", &which); 299 if (!err) { 300 switch (which) { 301 case B_REG_MIME_APP_HINT: 302 { 303 entry_ref ref; 304 err = message->FindRef("app hint", &ref); 305 if (!err) 306 err = fDatabase.SetAppHint(type, &ref); 307 break; 308 } 309 310 case B_REG_MIME_ATTR_INFO: 311 { 312 BMessage info; 313 err = message->FindMessage("attr info", &info); 314 if (!err) 315 err = fDatabase.SetAttrInfo(type, &info); 316 break; 317 } 318 319 case B_REG_MIME_DESCRIPTION: 320 { 321 bool isLong; 322 const char *description; 323 err = message->FindBool("long", &isLong); 324 if (!err) 325 err = message->FindString("description", &description); 326 if (!err) 327 err = (isLong 328 ? fDatabase.SetLongDescription(type, description) 329 : fDatabase.SetShortDescription(type, description)); 330 break; 331 } 332 333 case B_REG_MIME_FILE_EXTENSIONS: 334 { 335 BMessage extensions; 336 err = message->FindMessage("extensions", &extensions); 337 if (!err) 338 err = fDatabase.SetFileExtensions(type, &extensions); 339 break; 340 } 341 342 case B_REG_MIME_ICON: 343 case B_REG_MIME_ICON_FOR_TYPE: 344 { 345 const void *data; 346 ssize_t dataSize; 347 int32 size; 348 err = message->FindData("icon data", B_RAW_TYPE, &data, &dataSize); 349 if (!err) 350 err = message->FindInt32("icon size", &size); 351 if (which == B_REG_MIME_ICON_FOR_TYPE) { 352 const char *fileType; 353 if (!err) 354 err = message->FindString("file type", &fileType); 355 if (!err) 356 err = size == -1 ? 357 fDatabase.SetIconForType(type, fileType, data, 358 dataSize) : 359 fDatabase.SetIconForType(type, fileType, data, 360 dataSize, (icon_size)size); 361 } else { 362 if (!err) 363 err = size == -1 ? 364 fDatabase.SetIcon(type, data, dataSize) : 365 fDatabase.SetIcon(type, data, dataSize, 366 (icon_size)size); 367 } 368 break; 369 // End temporary fix code 370 } 371 372 case B_REG_MIME_PREFERRED_APP: 373 { 374 const char *signature; 375 int32 verb; 376 err = message->FindString("signature", &signature); 377 if (!err) 378 err = message->FindInt32("app verb", &verb); 379 if (!err) 380 err = fDatabase.SetPreferredApp(type, signature, (app_verb)verb); 381 break; 382 } 383 384 case B_REG_MIME_SNIFFER_RULE: 385 { 386 const char *rule; 387 err = message->FindString("sniffer rule", &rule); 388 if (!err) 389 err = fDatabase.SetSnifferRule(type, rule); 390 break; 391 } 392 393 case B_REG_MIME_SUPPORTED_TYPES: 394 { 395 BMessage types; 396 bool fullSync = true; 397 err = message->FindMessage("types", &types); 398 if (!err) 399 err = message->FindBool("full sync", &fullSync); 400 if (!err) 401 err = fDatabase.SetSupportedTypes(type, &types, fullSync); 402 break; 403 } 404 405 default: 406 err = B_BAD_VALUE; 407 break; 408 } 409 } 410 411 BMessage reply(B_REG_RESULT); 412 reply.AddInt32("result", err); 413 message->SendReply(&reply, this); 414 } 415 416 // HandleSetParam 417 //! Handles all B_REG_MIME_SET_PARAM messages 418 void 419 MIMEManager::HandleDeleteParam(BMessage *message) 420 { 421 // using BPrivate::MimeDatabase; 422 423 status_t err; 424 int32 which; 425 const char *type; 426 427 err = message->FindString("type", &type); 428 if (!err) 429 err = message->FindInt32("which", &which); 430 if (!err) { 431 switch (which) { 432 case B_REG_MIME_APP_HINT: 433 err = fDatabase.DeleteAppHint(type); 434 break; 435 436 case B_REG_MIME_ATTR_INFO: 437 err = fDatabase.DeleteAttrInfo(type); 438 break; 439 440 case B_REG_MIME_DESCRIPTION: 441 { 442 bool isLong; 443 err = message->FindBool("long", &isLong); 444 if (!err) 445 err = isLong 446 ? fDatabase.DeleteLongDescription(type) 447 : fDatabase.DeleteShortDescription(type); 448 break; 449 } 450 451 case B_REG_MIME_FILE_EXTENSIONS: 452 err = fDatabase.DeleteFileExtensions(type); 453 break; 454 455 case B_REG_MIME_ICON: 456 case B_REG_MIME_ICON_FOR_TYPE: 457 { 458 int32 size; 459 err = message->FindInt32("icon size", &size); 460 if (which == B_REG_MIME_ICON_FOR_TYPE) { 461 const char *fileType; 462 if (!err) 463 err = message->FindString("file type", &fileType); 464 if (!err) 465 err = (size == -1) ? 466 fDatabase.DeleteIconForType(type, fileType) : 467 fDatabase.DeleteIconForType(type, fileType, (icon_size)size); 468 } else { 469 if (!err) 470 err = (size == -1) ? 471 fDatabase.DeleteIcon(type) : 472 fDatabase.DeleteIcon(type, (icon_size)size); 473 } 474 break; 475 } 476 477 case B_REG_MIME_PREFERRED_APP: 478 { 479 int32 verb; 480 err = message->FindInt32("app verb", &verb); 481 if (!err) 482 err = fDatabase.DeletePreferredApp(type, (app_verb)verb); 483 break; 484 } 485 486 case B_REG_MIME_SNIFFER_RULE: 487 err = fDatabase.DeleteSnifferRule(type); 488 break; 489 490 case B_REG_MIME_SUPPORTED_TYPES: 491 { 492 bool fullSync; 493 err = message->FindBool("full sync", &fullSync); 494 if (!err) 495 err = fDatabase.DeleteSupportedTypes(type, fullSync); 496 break; 497 } 498 499 default: 500 err = B_BAD_VALUE; 501 break; 502 } 503 } 504 505 BMessage reply(B_REG_RESULT); 506 reply.AddInt32("result", err); 507 message->SendReply(&reply, this); 508 } 509 510