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