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