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