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; 190 bool synchronous = false; 191 int32 force; 192 193 MimeUpdateThread *thread = NULL; 194 195 status_t threadStatus = B_NO_INIT; 196 bool messageIsDetached = false; 197 bool stillOwnThread = true; 198 199 // Gather our arguments 200 err = message->FindRef("entry", &root); 201 if (!err) 202 err = message->FindBool("recursive", &recursive); 203 if (!err) 204 err = message->FindBool("synchronous", &synchronous); 205 if (!err) 206 err = message->FindInt32("force", &force); 207 208 // Detach the message for synchronous calls 209 if (!err && synchronous) { 210 DetachCurrentMessage(); 211 messageIsDetached = true; 212 } 213 214 // Create the appropriate flavor of mime update thread 215 if (!err) { 216 switch (message->what) { 217 case B_REG_MIME_CREATE_APP_META_MIME: 218 thread = new(nothrow) CreateAppMetaMimeThread((synchronous ? 219 "create_app_meta_mime (s)" : "create_app_meta_mime (a)"), 220 B_NORMAL_PRIORITY, BMessenger(&fThreadManager), &root, recursive, 221 force, synchronous ? message : NULL); 222 break; 223 224 case B_REG_MIME_UPDATE_MIME_INFO: 225 thread = new(nothrow) UpdateMimeInfoThread((synchronous ? 226 "update_mime_info (s)" : "update_mime_info (a)"), 227 B_NORMAL_PRIORITY, BMessenger(&fThreadManager), &root, recursive, 228 force, synchronous ? message : NULL); 229 break; 230 231 default: 232 err = B_BAD_VALUE; 233 break; 234 } 235 } 236 if (!err) 237 err = thread ? B_OK : B_NO_MEMORY; 238 if (!err) 239 err = threadStatus = thread->InitCheck(); 240 241 // Launch the thread 242 if (!err) { 243 err = fThreadManager.LaunchThread(thread); 244 if (!err) { 245 stillOwnThread = false; 246 } 247 } 248 249 // If something went wrong, we need to notify the sender regardless. However, 250 // if this is a synchronous call, we've already detached the message, and must 251 // be careful that it gets deleted once and only once. Thus, if the MimeUpdateThread 252 // object was created successfully, we don't need to delete the message, as that 253 // object has assumed control of it. Otherwise, we are still responsible. 254 if (err || !synchronous) { 255 // Send the reply 256 reply.what = B_REG_RESULT; 257 reply.AddInt32("result", err); 258 message->SendReply(&reply, this); 259 } 260 // Delete the message if necessary 261 if (messageIsDetached && threadStatus != B_OK) 262 delete message; 263 // Delete the thread if necessary 264 if (stillOwnThread) 265 delete thread; 266 break; 267 } 268 269 default: 270 printf("MIMEMan: msg->what == %lx (%.4s)\n", message->what, 271 (char*)&(message->what)); 272 BLooper::MessageReceived(message); 273 break; 274 } 275 } 276 277 // HandleSetParam 278 //! Handles all B_REG_MIME_SET_PARAM messages 279 void 280 MIMEManager::HandleSetParam(BMessage *message) 281 { 282 status_t err; 283 int32 which; 284 const char *type; 285 286 err = message->FindString("type", &type); 287 if (!err) 288 err = message->FindInt32("which", &which); 289 if (!err) { 290 switch (which) { 291 case B_REG_MIME_APP_HINT: 292 { 293 entry_ref ref; 294 err = message->FindRef("app hint", &ref); 295 if (!err) 296 err = fDatabase.SetAppHint(type, &ref); 297 break; 298 } 299 300 case B_REG_MIME_ATTR_INFO: 301 { 302 BMessage info; 303 err = message->FindMessage("attr info", &info); 304 if (!err) 305 err = fDatabase.SetAttrInfo(type, &info); 306 break; 307 } 308 309 case B_REG_MIME_DESCRIPTION: 310 { 311 bool isLong; 312 const char *description; 313 err = message->FindBool("long", &isLong); 314 if (!err) 315 err = message->FindString("description", &description); 316 if (!err) 317 err = (isLong 318 ? fDatabase.SetLongDescription(type, description) 319 : fDatabase.SetShortDescription(type, description)); 320 break; 321 } 322 323 case B_REG_MIME_FILE_EXTENSIONS: 324 { 325 BMessage extensions; 326 err = message->FindMessage("extensions", &extensions); 327 if (!err) 328 err = fDatabase.SetFileExtensions(type, &extensions); 329 break; 330 } 331 332 case B_REG_MIME_ICON: 333 case B_REG_MIME_ICON_FOR_TYPE: 334 { 335 const void *data; 336 ssize_t dataSize; 337 int32 size; 338 err = message->FindData("icon data", B_RAW_TYPE, &data, &dataSize); 339 if (!err) 340 err = message->FindInt32("icon size", &size); 341 if (which == B_REG_MIME_ICON_FOR_TYPE) { 342 const char *fileType; 343 if (!err) 344 err = message->FindString("file type", &fileType); 345 if (!err) 346 err = fDatabase.SetIconForType(type, fileType, data, 347 dataSize, (icon_size)size); 348 } else { 349 if (!err) 350 err = fDatabase.SetIcon(type, data, dataSize, 351 (icon_size)size); 352 } 353 break; 354 // End temporary fix code 355 } 356 357 case B_REG_MIME_PREFERRED_APP: 358 { 359 const char *signature; 360 int32 verb; 361 err = message->FindString("signature", &signature); 362 if (!err) 363 err = message->FindInt32("app verb", &verb); 364 if (!err) 365 err = fDatabase.SetPreferredApp(type, signature, (app_verb)verb); 366 break; 367 } 368 369 case B_REG_MIME_SNIFFER_RULE: 370 { 371 const char *rule; 372 err = message->FindString("sniffer rule", &rule); 373 if (!err) 374 err = fDatabase.SetSnifferRule(type, rule); 375 break; 376 } 377 378 case B_REG_MIME_SUPPORTED_TYPES: 379 { 380 BMessage types; 381 bool fullSync = true; 382 err = message->FindMessage("types", &types); 383 if (!err) 384 err = message->FindBool("full sync", &fullSync); 385 if (!err) 386 err = fDatabase.SetSupportedTypes(type, &types, fullSync); 387 break; 388 } 389 390 default: 391 err = B_BAD_VALUE; 392 break; 393 } 394 } 395 396 BMessage reply(B_REG_RESULT); 397 reply.AddInt32("result", err); 398 message->SendReply(&reply, this); 399 } 400 401 // HandleSetParam 402 //! Handles all B_REG_MIME_SET_PARAM messages 403 void 404 MIMEManager::HandleDeleteParam(BMessage *message) 405 { 406 // using BPrivate::MimeDatabase; 407 408 status_t err; 409 int32 which; 410 const char *type; 411 412 err = message->FindString("type", &type); 413 if (!err) 414 err = message->FindInt32("which", &which); 415 if (!err) { 416 switch (which) { 417 case B_REG_MIME_APP_HINT: 418 err = fDatabase.DeleteAppHint(type); 419 break; 420 421 case B_REG_MIME_ATTR_INFO: 422 err = fDatabase.DeleteAttrInfo(type); 423 break; 424 425 case B_REG_MIME_DESCRIPTION: 426 { 427 bool isLong; 428 err = message->FindBool("long", &isLong); 429 if (!err) 430 err = isLong 431 ? fDatabase.DeleteLongDescription(type) 432 : fDatabase.DeleteShortDescription(type); 433 break; 434 } 435 436 case B_REG_MIME_FILE_EXTENSIONS: 437 err = fDatabase.DeleteFileExtensions(type); 438 break; 439 440 case B_REG_MIME_ICON: 441 case B_REG_MIME_ICON_FOR_TYPE: 442 { 443 int32 size; 444 err = message->FindInt32("icon size", &size); 445 if (which == B_REG_MIME_ICON_FOR_TYPE) { 446 const char *fileType; 447 if (!err) 448 err = message->FindString("file type", &fileType); 449 if (!err) 450 err = fDatabase.DeleteIconForType(type, fileType, (icon_size)size); 451 } else { 452 if (!err) 453 err = fDatabase.DeleteIcon(type, (icon_size)size); 454 } 455 break; 456 } 457 458 case B_REG_MIME_PREFERRED_APP: 459 { 460 int32 verb; 461 err = message->FindInt32("app verb", &verb); 462 if (!err) 463 err = fDatabase.DeletePreferredApp(type, (app_verb)verb); 464 break; 465 } 466 467 case B_REG_MIME_SNIFFER_RULE: 468 err = fDatabase.DeleteSnifferRule(type); 469 break; 470 471 case B_REG_MIME_SUPPORTED_TYPES: 472 { 473 bool fullSync; 474 err = message->FindBool("full sync", &fullSync); 475 if (!err) 476 err = fDatabase.DeleteSupportedTypes(type, fullSync); 477 break; 478 } 479 480 default: 481 err = B_BAD_VALUE; 482 break; 483 } 484 } 485 486 BMessage reply(B_REG_RESULT); 487 reply.AddInt32("result", err); 488 message->SendReply(&reply, this); 489 } 490 491