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