1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2001, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 36 #include "MailApp.h" 37 38 #include <fcntl.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <sys/stat.h> 43 #include <sys/utsname.h> 44 #include <unistd.h> 45 46 #include <Autolock.h> 47 #include <Clipboard.h> 48 #include <Debug.h> 49 #include <E-mail.h> 50 #include <InterfaceKit.h> 51 #include <Roster.h> 52 #include <Screen.h> 53 #include <StorageKit.h> 54 #include <String.h> 55 #include <TextView.h> 56 #include <UTF8.h> 57 58 #include <fs_index.h> 59 #include <fs_info.h> 60 61 #include <MailMessage.h> 62 #include <MailSettings.h> 63 #include <MailDaemon.h> 64 #include <mail_util.h> 65 #include <MDRLanguage.h> 66 67 #include <CharacterSetRoster.h> 68 69 using namespace BPrivate ; 70 71 #ifdef HAIKU_TARGET_PLATFORM_BEOS 72 #include <netdb.h> 73 #endif 74 75 #include "ButtonBar.h" 76 #include "Content.h" 77 #include "Enclosures.h" 78 #include "FieldMsg.h" 79 #include "FindWindow.h" 80 #include "Header.h" 81 #include "MailSupport.h" 82 #include "MailWindow.h" 83 #include "Messages.h" 84 #include "Prefs.h" 85 #include "QueryMenu.h" 86 #include "Signature.h" 87 #include "Status.h" 88 #include "String.h" 89 #include "Utilities.h" 90 #include "Words.h" 91 92 93 static const char *kDictDirectory = "word_dictionary"; 94 static const char *kIndexDirectory = "word_index"; 95 static const char *kWordsPath = "/boot/optional/goodies/words"; 96 static const char *kExact = ".exact"; 97 static const char *kMetaphone = ".metaphone"; 98 99 100 // #pragma mark - 101 int 102 main() 103 { 104 TMailApp().Run(); 105 return B_OK; 106 } 107 108 109 // #pragma mark - 110 111 112 TMailApp::TMailApp() 113 : BApplication("application/x-vnd.Be-MAIL"), 114 fWindowCount(0), 115 fPrefsWindow(NULL), 116 fSigWindow(NULL), 117 118 fPrintSettings(NULL), 119 fPrintHelpAndExit(false), 120 121 fWrapMode(true), 122 fShowHeader(false), 123 fAttachAttributes(true), 124 fColoredQuotes(true), 125 fShowButtonBar(true), 126 fWarnAboutUnencodableCharacters(true), 127 fStartWithSpellCheckOn(false), 128 fShowSpamGUI(true), 129 fMailCharacterSet(B_MS_WINDOWS_CONVERSION), 130 fContentFont(be_fixed_font) 131 { 132 // set default values 133 fContentFont.SetSize(12.0); 134 fSignature = (char *)malloc(strlen(SIG_NONE) + 1); 135 strcpy(fSignature, SIG_NONE); 136 fReplyPreamble = (char *)malloc(1); 137 fReplyPreamble[0] = '\0'; 138 139 fMailWindowFrame.Set(0, 0, 0, 0); 140 fSignatureWindowFrame.Set(6, TITLE_BAR_HEIGHT, 6 + kSigWidth, TITLE_BAR_HEIGHT + kSigHeight); 141 fPrefsWindowPos.Set(6, TITLE_BAR_HEIGHT); 142 143 // Find and read settings file. 144 LoadSettings(); 145 146 _CheckForSpamFilterExistence(); 147 fContentFont.SetSpacing(B_BITMAP_SPACING); 148 fLastMailWindowFrame = fMailWindowFrame; 149 } 150 151 152 TMailApp::~TMailApp() 153 { 154 } 155 156 157 void 158 TMailApp::AboutRequested() 159 { 160 BAlert *alert = new BAlert("about", "Mail\n\n" 161 "written by Robert Polic\n" 162 "enhanced by the Dr. Zoidberg crew\n\n" 163 "Copyright 2007, Haiku.\n", "Ok"); 164 BTextView *view = alert->TextView(); 165 BFont font; 166 167 view->SetStylable(true); 168 169 view->GetFont(&font); 170 font.SetSize(font.Size() + 7.0f); 171 font.SetFace(B_BOLD_FACE); 172 view->SetFontAndColor(0, 4, &font); 173 174 alert->Go(); 175 } 176 177 178 void 179 TMailApp::ArgvReceived(int32 argc, char **argv) 180 { 181 BEntry entry; 182 BString names; 183 BString ccNames; 184 BString bccNames; 185 BString subject; 186 BString body; 187 BMessage enclosure(B_REFS_RECEIVED); 188 // a "mailto:" with no name should open an empty window 189 // so remember if we got a "mailto:" even if there isn't a name 190 // that goes along with it (this allows deskbar replicant to open 191 // an empty message even when Mail is already running) 192 bool gotmailto = false; 193 194 for (int32 loop = 1; loop < argc; loop++) 195 { 196 if (strcmp(argv[loop], "-h") == 0 197 || strcmp(argv[loop], "--help") == 0) 198 { 199 printf(" usage: %s [ mailto:<address> ] [ -subject \"<text>\" ] [ ccto:<address> ] [ bccto:<address> ] " 200 "[ -body \"<body text\" ] [ enclosure:<path> ] [ <message to read> ...] \n", 201 argv[0]); 202 fPrintHelpAndExit = true; 203 be_app->PostMessage(B_QUIT_REQUESTED); 204 return; 205 } 206 else if (strncmp(argv[loop], "mailto:", 7) == 0) 207 { 208 if (names.Length()) 209 names += ", "; 210 char *options; 211 if ((options = strchr(argv[loop],'?')) != NULL) 212 { 213 names.Append(argv[loop] + 7, options - argv[loop] - 7); 214 if (!strncmp(++options,"subject=",8)) 215 subject = options + 8; 216 } 217 else 218 names += argv[loop] + 7; 219 gotmailto = true; 220 } 221 else if (strncmp(argv[loop], "ccto:", 5) == 0) 222 { 223 if (ccNames.Length()) 224 ccNames += ", "; 225 ccNames += argv[loop] + 5; 226 } 227 else if (strncmp(argv[loop], "bccto:", 6) == 0) 228 { 229 if (bccNames.Length()) 230 bccNames += ", "; 231 bccNames += argv[loop] + 6; 232 } 233 else if (strcmp(argv[loop], "-subject") == 0) 234 subject = argv[++loop]; 235 else if (strcmp(argv[loop], "-body") == 0 && argv[loop + 1]) 236 body = argv[++loop]; 237 else if (strncmp(argv[loop], "enclosure:", 10) == 0) 238 { 239 BEntry tmp(argv[loop] + 10, true); 240 if (tmp.InitCheck() == B_OK && tmp.Exists()) 241 { 242 entry_ref ref; 243 tmp.GetRef(&ref); 244 enclosure.AddRef("refs", &ref); 245 } 246 } 247 else if (entry.SetTo(argv[loop]) == B_NO_ERROR) 248 { 249 BMessage msg(B_REFS_RECEIVED); 250 entry_ref ref; 251 entry.GetRef(&ref); 252 msg.AddRef("refs", &ref); 253 RefsReceived(&msg); 254 } 255 } 256 257 if (gotmailto || names.Length() || ccNames.Length() || bccNames.Length() || subject.Length() 258 || body.Length() || enclosure.HasRef("refs")) 259 { 260 TMailWindow *window = NewWindow(NULL, names.String()); 261 window->SetTo(names.String(), subject.String(), ccNames.String(), bccNames.String(), 262 &body, &enclosure); 263 window->Show(); 264 } 265 } 266 267 268 void 269 TMailApp::MessageReceived(BMessage *msg) 270 { 271 TMailWindow *window = NULL; 272 entry_ref ref; 273 274 switch (msg->what) 275 { 276 case M_NEW: 277 { 278 int32 type; 279 msg->FindInt32("type", &type); 280 switch (type) 281 { 282 case M_NEW: 283 window = NewWindow(); 284 break; 285 286 case M_RESEND: 287 { 288 msg->FindRef("ref", &ref); 289 BNode file(&ref); 290 BString string = ""; 291 292 if (file.InitCheck() == B_OK) 293 ReadAttrString(&file, B_MAIL_ATTR_TO, &string); 294 295 window = NewWindow(&ref, string.String(), true); 296 break; 297 } 298 case M_FORWARD: 299 case M_FORWARD_WITHOUT_ATTACHMENTS: 300 { 301 TMailWindow *sourceWindow; 302 if (msg->FindPointer("window", (void **)&sourceWindow) < B_OK 303 || !sourceWindow->Lock()) 304 break; 305 306 msg->FindRef("ref", &ref); 307 window = NewWindow(); 308 if (window->Lock()) { 309 window->Forward(&ref, sourceWindow, type == M_FORWARD); 310 window->Unlock(); 311 } 312 sourceWindow->Unlock(); 313 break; 314 } 315 316 case M_REPLY: 317 case M_REPLY_TO_SENDER: 318 case M_REPLY_ALL: 319 case M_COPY_TO_NEW: 320 { 321 TMailWindow *sourceWindow; 322 if (msg->FindPointer("window", (void **)&sourceWindow) < B_OK 323 || !sourceWindow->Lock()) 324 break; 325 msg->FindRef("ref", &ref); 326 window = NewWindow(); 327 if (window->Lock()) { 328 if (type == M_COPY_TO_NEW) 329 window->CopyMessage(&ref, sourceWindow); 330 else 331 window->Reply(&ref, sourceWindow, type); 332 window->Unlock(); 333 } 334 sourceWindow->Unlock(); 335 break; 336 } 337 } 338 if (window) 339 window->Show(); 340 break; 341 } 342 343 case M_PREFS: 344 if (fPrefsWindow) 345 fPrefsWindow->Activate(true); 346 else 347 { 348 fPrefsWindow = new TPrefsWindow(BRect(fPrefsWindowPos.x, 349 fPrefsWindowPos.y, fPrefsWindowPos.x + PREF_WIDTH, 350 fPrefsWindowPos.y + PREF_HEIGHT), 351 &fContentFont, NULL, &fWrapMode, &fAttachAttributes, 352 &fColoredQuotes, &fDefaultChain, &fUseAccountFrom, 353 &fReplyPreamble, &fSignature, &fMailCharacterSet, 354 &fWarnAboutUnencodableCharacters, 355 &fStartWithSpellCheckOn, &fShowButtonBar); 356 fPrefsWindow->Show(); 357 fPreviousShowButtonBar = fShowButtonBar; 358 } 359 break; 360 361 case PREFS_CHANGED: 362 { 363 // Do we need to update the state of the button bars? 364 if (fPreviousShowButtonBar != fShowButtonBar) { 365 // Notify all Mail windows 366 TMailWindow *window; 367 for (int32 i = 0; (window=(TMailWindow *)fWindowList.ItemAt(i)) != NULL; i++) { 368 window->Lock(); 369 window->UpdateViews(); 370 window->Unlock(); 371 } 372 fPreviousShowButtonBar = fShowButtonBar; 373 } 374 break; 375 } 376 377 case M_EDIT_SIGNATURE: 378 if (fSigWindow) 379 fSigWindow->Activate(true); 380 else { 381 fSigWindow = new TSignatureWindow(fSignatureWindowFrame); 382 fSigWindow->Show(); 383 } 384 break; 385 386 case M_FONT: 387 FontChange(); 388 break; 389 390 case REFS_RECEIVED: 391 if (msg->HasPointer("window")) 392 { 393 msg->FindPointer("window", (void **)&window); 394 BMessage message(*msg); 395 window->PostMessage(&message, window); 396 } 397 break; 398 399 case WINDOW_CLOSED: 400 switch (msg->FindInt32("kind")) { 401 case MAIL_WINDOW: 402 { 403 TMailWindow *window; 404 if( msg->FindPointer( "window", (void **)&window ) == B_OK ) 405 fWindowList.RemoveItem(window); 406 fWindowCount--; 407 break; 408 } 409 410 case PREFS_WINDOW: 411 fPrefsWindow = NULL; 412 msg->FindPoint("window pos", &fPrefsWindowPos); 413 break; 414 415 case SIG_WINDOW: 416 fSigWindow = NULL; 417 msg->FindRect("window frame", &fSignatureWindowFrame); 418 break; 419 } 420 421 if (!fWindowCount && !fSigWindow && !fPrefsWindow) 422 be_app->PostMessage(B_QUIT_REQUESTED); 423 break; 424 425 case B_REFS_RECEIVED: 426 RefsReceived(msg); 427 break; 428 429 case B_PRINTER_CHANGED: 430 _ClearPrintSettings(); 431 break; 432 433 default: 434 BApplication::MessageReceived(msg); 435 } 436 } 437 438 439 bool 440 TMailApp::QuitRequested() 441 { 442 if (!BApplication::QuitRequested()) 443 return false; 444 445 fMailWindowFrame = fLastMailWindowFrame; 446 // Last closed window becomes standard window size. 447 448 // Shut down the spam server if it's still running. If the user has trained it on a message, it will stay 449 // open. This is actually a good thing if there's quite a bit of spam -- no waiting for the thing to start 450 // up for each message, but it has no business staying that way if the user isn't doing anything with e-mail. :) 451 if (be_roster->IsRunning(kSpamServerSignature)) { 452 team_id serverTeam = be_roster->TeamFor(kSpamServerSignature); 453 if (serverTeam >= 0) { 454 int32 errorCode = B_SERVER_NOT_FOUND; 455 BMessenger messengerToSpamServer(kSpamServerSignature, serverTeam, &errorCode); 456 if (messengerToSpamServer.IsValid()) { 457 BMessage quitMessage(B_QUIT_REQUESTED); 458 messengerToSpamServer.SendMessage(&quitMessage); 459 } 460 } 461 462 } 463 464 SaveSettings(); 465 return true; 466 } 467 468 469 void 470 TMailApp::ReadyToRun() 471 { 472 // Create needed indices for META:group, META:email, MAIL:draft, 473 // INDEX_SIGNATURE, INDEX_STATUS on the boot volume 474 475 BVolume volume; 476 BVolumeRoster().GetBootVolume(&volume); 477 478 fs_create_index(volume.Device(), "META:group", B_STRING_TYPE, 0); 479 fs_create_index(volume.Device(), "META:email", B_STRING_TYPE, 0); 480 fs_create_index(volume.Device(), "MAIL:draft", B_INT32_TYPE, 0); 481 fs_create_index(volume.Device(), INDEX_SIGNATURE, B_STRING_TYPE, 0); 482 fs_create_index(volume.Device(), INDEX_STATUS, B_STRING_TYPE, 0); 483 484 // Load dictionaries 485 BPath indexDir; 486 BPath dictionaryDir; 487 BPath dataPath; 488 BPath indexPath; 489 BDirectory directory; 490 BEntry entry; 491 492 // Locate user settings directory 493 find_directory(B_BEOS_ETC_DIRECTORY, &indexDir, true); 494 dictionaryDir = indexDir; 495 496 // Setup directory paths 497 indexDir.Append(kIndexDirectory); 498 dictionaryDir.Append(kDictDirectory); 499 500 // Create directories if needed 501 directory.CreateDirectory(indexDir.Path(), NULL); 502 directory.CreateDirectory(dictionaryDir.Path(), NULL); 503 504 dataPath = dictionaryDir; 505 dataPath.Append("words"); 506 507 // Only Load if Words Dictionary 508 if (BEntry(kWordsPath).Exists() || BEntry(dataPath.Path()).Exists()) { 509 // If "/boot/optional/goodies/words" exists but there is no 510 // system dictionary, copy words 511 if (!BEntry(dataPath.Path()).Exists() && BEntry(kWordsPath).Exists()) { 512 BFile words(kWordsPath, B_READ_ONLY); 513 BFile copy(dataPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); 514 char buffer[4096]; 515 ssize_t size; 516 517 while ((size = words.Read( buffer, 4096)) > 0) 518 copy.Write(buffer, size); 519 BNodeInfo(©).SetType("text/plain"); 520 } 521 522 // Create user dictionary if it does not exist 523 dataPath = dictionaryDir; 524 dataPath.Append("user"); 525 if (!BEntry(dataPath.Path()).Exists()) { 526 BFile user(dataPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); 527 BNodeInfo(&user).SetType("text/plain"); 528 } 529 530 // Load dictionaries 531 directory.SetTo(dictionaryDir.Path()); 532 533 BString leafName; 534 gUserDict = -1; 535 536 while (gDictCount < MAX_DICTIONARIES 537 && directory.GetNextEntry(&entry) != B_ENTRY_NOT_FOUND) { 538 dataPath.SetTo(&entry); 539 540 // Identify the user dictionary 541 if (strcmp("user", dataPath.Leaf()) == 0) { 542 gUserDictFile = new BFile(dataPath.Path(), B_WRITE_ONLY | B_OPEN_AT_END); 543 gUserDict = gDictCount; 544 } 545 546 indexPath = indexDir; 547 leafName.SetTo(dataPath.Leaf()); 548 leafName.Append(kMetaphone); 549 indexPath.Append(leafName.String()); 550 gWords[gDictCount] = new Words(dataPath.Path(), indexPath.Path(), true); 551 552 indexPath = indexDir; 553 leafName.SetTo(dataPath.Leaf()); 554 leafName.Append(kExact); 555 indexPath.Append(leafName.String()); 556 gExactWords[gDictCount] = new Words(dataPath.Path(), indexPath.Path(), false); 557 gDictCount++; 558 } 559 } 560 561 // Create a new window if starting up without any extra arguments. 562 563 if (!fPrintHelpAndExit && !fWindowCount) { 564 TMailWindow *window; 565 window = NewWindow(); 566 window->Show(); 567 } 568 } 569 570 571 void 572 TMailApp::RefsReceived(BMessage *msg) 573 { 574 bool have_names = false; 575 BString names; 576 char type[B_FILE_NAME_LENGTH]; 577 int32 item = 0; 578 BFile file; 579 TMailWindow *window; 580 entry_ref ref; 581 582 // 583 // If a tracker window opened me, get a messenger from it. 584 // 585 BMessenger messenger; 586 if (msg->HasMessenger("TrackerViewToken")) 587 msg->FindMessenger("TrackerViewToken", &messenger); 588 589 while (msg->HasRef("refs", item)) { 590 msg->FindRef("refs", item++, &ref); 591 if ((window = FindWindow(ref)) != NULL) 592 window->Activate(true); 593 else { 594 file.SetTo(&ref, O_RDONLY); 595 if (file.InitCheck() == B_NO_ERROR) { 596 BNodeInfo node(&file); 597 node.GetType(type); 598 if (!strcmp(type, B_MAIL_TYPE)) { 599 window = NewWindow(&ref, NULL, false, &messenger); 600 window->Show(); 601 } else if(!strcmp(type, "application/x-person")) { 602 /* Got a People contact info file, see if it has an Email address. */ 603 BString name; 604 BString email; 605 attr_info info; 606 char *attrib; 607 608 if (file.GetAttrInfo("META:email", &info) == B_NO_ERROR) { 609 attrib = (char *) malloc(info.size + 1); 610 file.ReadAttr("META:email", B_STRING_TYPE, 0, attrib, info.size); 611 attrib[info.size] = 0; // Just in case it wasn't NUL terminated. 612 email << attrib; 613 free(attrib); 614 615 /* we got something... */ 616 if (email.Length() > 0) { 617 /* see if we can get a username as well */ 618 if(file.GetAttrInfo("META:name", &info) == B_NO_ERROR) { 619 attrib = (char *) malloc(info.size + 1); 620 file.ReadAttr("META:name", B_STRING_TYPE, 0, attrib, info.size); 621 attrib[info.size] = 0; // Just in case it wasn't NUL terminated. 622 name << "\"" << attrib << "\" "; 623 email.Prepend("<"); 624 email.Append(">"); 625 free(attrib); 626 } 627 628 if (names.Length() == 0) { 629 names << name << email; 630 } else { 631 names << ", " << name << email; 632 } 633 have_names = true; 634 email.SetTo(""); 635 name.SetTo(""); 636 } 637 } 638 } 639 else if (!strcmp(type, kDraftType)) 640 { 641 window = NewWindow(); 642 643 // If it's a draft message, open it 644 window->OpenMessage(&ref); 645 window->Show(); 646 } 647 } /* end of else(file.InitCheck() == B_NO_ERROR */ 648 } 649 } 650 651 if (have_names) { 652 window = NewWindow(NULL, names.String()); 653 window->Show(); 654 } 655 } 656 657 658 TMailWindow * 659 TMailApp::FindWindow(const entry_ref &ref) 660 { 661 BEntry entry(&ref); 662 if (entry.InitCheck() < B_OK) 663 return NULL; 664 665 node_ref nodeRef; 666 if (entry.GetNodeRef(&nodeRef) < B_OK) 667 return NULL; 668 669 BWindow *window; 670 int32 index = 0; 671 while ((window = WindowAt(index++)) != NULL) { 672 TMailWindow *mailWindow = dynamic_cast<TMailWindow *>(window); 673 if (mailWindow == NULL) 674 continue; 675 676 node_ref mailNodeRef; 677 if (mailWindow->GetMailNodeRef(mailNodeRef) == B_OK 678 && mailNodeRef == nodeRef) 679 return mailWindow; 680 } 681 682 return NULL; 683 } 684 685 686 void 687 TMailApp::_CheckForSpamFilterExistence() 688 { 689 // Looks at the filter settings to see if the user is using a spam filter. 690 // If there is one there, set fShowSpamGUI to TRUE, otherwise to FALSE. 691 692 int32 addonNameIndex; 693 const char *addonNamePntr; 694 BDirectory inChainDir; 695 BPath path; 696 BEntry settingsEntry; 697 BFile settingsFile; 698 BMessage settingsMessage; 699 700 fShowSpamGUI = false; 701 702 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK) 703 return; 704 path.Append("Mail/chains/inbound"); 705 if (inChainDir.SetTo(path.Path()) != B_OK) 706 return; 707 708 while (inChainDir.GetNextEntry (&settingsEntry, true /* traverse */) == B_OK) { 709 if (!settingsEntry.IsFile()) 710 continue; 711 if (settingsFile.SetTo (&settingsEntry, B_READ_ONLY) != B_OK) 712 continue; 713 if (settingsMessage.Unflatten (&settingsFile) != B_OK) 714 continue; 715 for (addonNameIndex = 0; B_OK == settingsMessage.FindString ( 716 "filter_addons", addonNameIndex, &addonNamePntr); 717 addonNameIndex++) { 718 if (strstr (addonNamePntr, "Spam Filter") != NULL) { 719 fShowSpamGUI = true; // Found it! 720 return; 721 } 722 } 723 } 724 } 725 726 727 void 728 TMailApp::SetPrintSettings(const BMessage* printSettings) 729 { 730 BAutolock _(this); 731 732 if (printSettings == fPrintSettings) 733 return; 734 735 delete fPrintSettings; 736 if (printSettings) 737 fPrintSettings = new BMessage(*printSettings); 738 else 739 fPrintSettings = NULL; 740 } 741 742 743 bool 744 TMailApp::HasPrintSettings() 745 { 746 BAutolock _(this); 747 return fPrintSettings != NULL; 748 } 749 750 751 BMessage 752 TMailApp::PrintSettings() 753 { 754 BAutolock _(this); 755 return BMessage(*fPrintSettings); 756 } 757 758 759 void 760 TMailApp::_ClearPrintSettings() 761 { 762 delete fPrintSettings; 763 fPrintSettings = NULL; 764 } 765 766 767 void 768 TMailApp::SetLastWindowFrame(BRect frame) 769 { 770 BAutolock _(this); 771 fLastMailWindowFrame = frame; 772 } 773 774 775 status_t 776 TMailApp::GetSettingsPath(BPath &path) 777 { 778 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 779 if (status != B_OK) 780 return status; 781 782 path.Append("Mail"); 783 return create_directory(path.Path(), 0755); 784 } 785 786 787 status_t 788 TMailApp::LoadOldSettings() 789 { 790 BPath path; 791 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); 792 if (status != B_OK) 793 return status; 794 795 path.Append("Mail_data"); 796 797 BFile file; 798 status = file.SetTo(path.Path(), B_READ_ONLY); 799 if (status != B_OK) 800 return status; 801 802 file.Read(&fMailWindowFrame, sizeof(BRect)); 803 // file.Read(&level, sizeof(level)); 804 805 font_family fontFamily; 806 font_style fontStyle; 807 float size; 808 file.Read(&fontFamily, sizeof(font_family)); 809 file.Read(&fontStyle, sizeof(font_style)); 810 file.Read(&size, sizeof(float)); 811 if (size >= 9) 812 fContentFont.SetSize(size); 813 814 if (fontFamily[0] && fontStyle[0]) 815 fContentFont.SetFamilyAndStyle(fontFamily, fontStyle); 816 817 file.Read(&fSignatureWindowFrame, sizeof(BRect)); 818 file.Read(&fShowHeader, sizeof(bool)); 819 file.Read(&fWrapMode, sizeof(bool)); 820 file.Read(&fPrefsWindowPos, sizeof(BPoint)); 821 822 int32 length; 823 if (file.Read(&length, sizeof(int32)) < (ssize_t)sizeof(int32)) 824 return B_IO_ERROR; 825 826 free(fSignature); 827 fSignature = NULL; 828 829 if (length > 0) { 830 fSignature = (char *)malloc(length); 831 if (fSignature == NULL) 832 return B_NO_MEMORY; 833 834 file.Read(fSignature, length); 835 } 836 837 file.Read(&fMailCharacterSet, sizeof(int32)); 838 if (fMailCharacterSet != B_MAIL_UTF8_CONVERSION 839 && fMailCharacterSet != B_MAIL_US_ASCII_CONVERSION 840 && BCharacterSetRoster::GetCharacterSetByConversionID(fMailCharacterSet) == NULL) 841 fMailCharacterSet = B_MS_WINDOWS_CONVERSION; 842 843 if (file.Read(&length, sizeof(int32)) == (ssize_t)sizeof(int32)) { 844 char *findString = (char *)malloc(length + 1); 845 if (findString == NULL) 846 return B_NO_MEMORY; 847 848 file.Read(findString, length); 849 findString[length] = '\0'; 850 FindWindow::SetFindString(findString); 851 free(findString); 852 } 853 if (file.Read(&fShowButtonBar, sizeof(uint8)) < (ssize_t)sizeof(uint8)) 854 fShowButtonBar = true; 855 if (file.Read(&fUseAccountFrom, sizeof(int32)) < (ssize_t)sizeof(int32) 856 || fUseAccountFrom < ACCOUNT_USE_DEFAULT 857 || fUseAccountFrom > ACCOUNT_FROM_MAIL) 858 fUseAccountFrom = ACCOUNT_USE_DEFAULT; 859 if (file.Read(&fColoredQuotes, sizeof(bool)) < (ssize_t)sizeof(bool)) 860 fColoredQuotes = true; 861 862 if (file.Read(&length, sizeof(int32)) == (ssize_t)sizeof(int32)) { 863 free(fReplyPreamble); 864 fReplyPreamble = (char *)malloc(length + 1); 865 if (fReplyPreamble == NULL) 866 return B_NO_MEMORY; 867 868 file.Read(fReplyPreamble, length); 869 fReplyPreamble[length] = '\0'; 870 } 871 872 file.Read(&fAttachAttributes, sizeof(bool)); 873 file.Read(&fWarnAboutUnencodableCharacters, sizeof(bool)); 874 875 return B_OK; 876 } 877 878 879 status_t 880 TMailApp::SaveSettings() 881 { 882 BMailSettings chainSettings; 883 884 if (fDefaultChain != ~0UL) { 885 chainSettings.SetDefaultOutboundChainID(fDefaultChain); 886 chainSettings.Save(); 887 } 888 889 BPath path; 890 status_t status = GetSettingsPath(path); 891 if (status != B_OK) 892 return status; 893 894 path.Append("BeMail Settings~"); 895 896 BFile file; 897 status = file.SetTo(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 898 if (status != B_OK) 899 return status; 900 901 BMessage settings('BeMl'); 902 settings.AddRect("MailWindowSize", fMailWindowFrame); 903 // settings.AddInt32("ExperienceLevel", level); 904 905 font_family fontFamily; 906 font_style fontStyle; 907 fContentFont.GetFamilyAndStyle(&fontFamily, &fontStyle); 908 909 settings.AddString("FontFamily", fontFamily); 910 settings.AddString("FontStyle", fontStyle); 911 settings.AddFloat("FontSize", fContentFont.Size()); 912 913 settings.AddRect("SignatureWindowSize", fSignatureWindowFrame); 914 settings.AddBool("ShowHeadersMode", fShowHeader); 915 settings.AddBool("WordWrapMode", fWrapMode); 916 settings.AddPoint("PreferencesWindowLocation", fPrefsWindowPos); 917 settings.AddString("SignatureText", fSignature); 918 settings.AddInt32("CharacterSet", fMailCharacterSet); 919 settings.AddString("FindString", FindWindow::GetFindString()); 920 settings.AddInt8("ShowButtonBar", fShowButtonBar); 921 settings.AddInt32("UseAccountFrom", fUseAccountFrom); 922 settings.AddBool("ColoredQuotes", fColoredQuotes); 923 settings.AddString("ReplyPreamble", fReplyPreamble); 924 settings.AddBool("AttachAttributes", fAttachAttributes); 925 settings.AddBool("WarnAboutUnencodableCharacters", fWarnAboutUnencodableCharacters); 926 settings.AddBool("StartWithSpellCheck", fStartWithSpellCheckOn); 927 928 BEntry entry; 929 status = entry.SetTo(path.Path()); 930 if (status != B_OK) 931 return status; 932 933 status = settings.Flatten(&file); 934 if (status == B_OK) { 935 // replace original settings file 936 status = entry.Rename("BeMail Settings", true); 937 } else 938 entry.Remove(); 939 940 return status; 941 } 942 943 944 status_t 945 TMailApp::LoadSettings() 946 { 947 BMailSettings chainSettings; 948 fDefaultChain = chainSettings.DefaultOutboundChainID(); 949 950 BPath path; 951 status_t status = GetSettingsPath(path); 952 if (status != B_OK) 953 return status; 954 955 path.Append("BeMail Settings"); 956 957 BFile file; 958 status = file.SetTo(path.Path(), B_READ_ONLY); 959 if (status != B_OK) 960 return LoadOldSettings(); 961 962 BMessage settings; 963 status = settings.Unflatten(&file); 964 if (status < B_OK || settings.what != 'BeMl') { 965 // the current settings are corrupted, try old ones 966 return LoadOldSettings(); 967 } 968 969 BRect rect; 970 if (settings.FindRect("MailWindowSize", &rect) == B_OK) 971 fMailWindowFrame = rect; 972 973 int32 int32Value; 974 // if (settings.FindInt32("ExperienceLevel", &int32Value) == B_OK) 975 // level = int32Value; 976 977 const char *fontFamily; 978 if (settings.FindString("FontFamily", &fontFamily) == B_OK) { 979 const char *fontStyle; 980 if (settings.FindString("FontStyle", &fontStyle) == B_OK) { 981 float size; 982 if (settings.FindFloat("FontSize", &size) == B_OK) { 983 if (size >= 7) 984 fContentFont.SetSize(size); 985 986 if (fontFamily[0] && fontStyle[0]) { 987 fContentFont.SetFamilyAndStyle(fontFamily[0] ? fontFamily : NULL, 988 fontStyle[0] ? fontStyle : NULL); 989 } 990 } 991 } 992 } 993 994 if (settings.FindRect("SignatureWindowSize", &rect) == B_OK) 995 fSignatureWindowFrame = rect; 996 997 bool boolValue; 998 if (settings.FindBool("ShowHeadersMode", &boolValue) == B_OK) 999 fShowHeader = boolValue; 1000 1001 if (settings.FindBool("WordWrapMode", &boolValue) == B_OK) 1002 fWrapMode = boolValue; 1003 1004 BPoint point; 1005 if (settings.FindPoint("PreferencesWindowLocation", &point) == B_OK) 1006 fPrefsWindowPos = point; 1007 1008 const char *string; 1009 if (settings.FindString("SignatureText", &string) == B_OK) { 1010 free(fSignature); 1011 fSignature = strdup(string); 1012 } 1013 1014 if (settings.FindInt32("CharacterSet", &int32Value) == B_OK) 1015 fMailCharacterSet = int32Value; 1016 if (fMailCharacterSet != B_MAIL_UTF8_CONVERSION 1017 && fMailCharacterSet != B_MAIL_US_ASCII_CONVERSION 1018 && BCharacterSetRoster::GetCharacterSetByConversionID(fMailCharacterSet) == NULL) 1019 fMailCharacterSet = B_MS_WINDOWS_CONVERSION; 1020 1021 if (settings.FindString("FindString", &string) == B_OK) 1022 FindWindow::SetFindString(string); 1023 1024 int8 int8Value; 1025 if (settings.FindInt8("ShowButtonBar", &int8Value) == B_OK) 1026 fShowButtonBar = int8Value; 1027 1028 if (settings.FindInt32("UseAccountFrom", &int32Value) == B_OK) 1029 fUseAccountFrom = int32Value; 1030 if (fUseAccountFrom < ACCOUNT_USE_DEFAULT 1031 || fUseAccountFrom > ACCOUNT_FROM_MAIL) 1032 fUseAccountFrom = ACCOUNT_USE_DEFAULT; 1033 1034 if (settings.FindBool("ColoredQuotes", &boolValue) == B_OK) 1035 fColoredQuotes = boolValue; 1036 1037 if (settings.FindString("ReplyPreamble", &string) == B_OK) { 1038 free(fReplyPreamble); 1039 fReplyPreamble = strdup(string); 1040 } 1041 1042 if (settings.FindBool("AttachAttributes", &boolValue) == B_OK) 1043 fAttachAttributes = boolValue; 1044 1045 if (settings.FindBool("WarnAboutUnencodableCharacters", &boolValue) == B_OK) 1046 fWarnAboutUnencodableCharacters = boolValue; 1047 1048 if (settings.FindBool("StartWithSpellCheck", &boolValue) == B_OK) 1049 fStartWithSpellCheckOn = boolValue; 1050 1051 return B_OK; 1052 } 1053 1054 1055 void 1056 TMailApp::FontChange() 1057 { 1058 int32 index = 0; 1059 BMessage msg; 1060 BWindow *window; 1061 1062 msg.what = CHANGE_FONT; 1063 msg.AddPointer("font", &fContentFont); 1064 1065 for (;;) { 1066 window = WindowAt(index++); 1067 if (!window) 1068 break; 1069 1070 window->PostMessage(&msg); 1071 } 1072 } 1073 1074 1075 TMailWindow * 1076 TMailApp::NewWindow(const entry_ref *ref, const char *to, bool resend, 1077 BMessenger *trackerMessenger) 1078 { 1079 BScreen screen(B_MAIN_SCREEN_ID); 1080 BRect screen_frame = screen.Frame(); 1081 1082 BRect r; 1083 if ((fMailWindowFrame.Width() > 1) && (fMailWindowFrame.Height() > 1)) 1084 r = fMailWindowFrame; 1085 else 1086 r.Set(6, TITLE_BAR_HEIGHT, 6 + WIND_WIDTH, TITLE_BAR_HEIGHT + WIND_HEIGHT); 1087 1088 r.OffsetBy(fWindowCount * 20, fWindowCount * 20); 1089 1090 if ((r.left - 6) < screen_frame.left) 1091 r.OffsetTo(screen_frame.left + 8, r.top); 1092 1093 if ((r.left + 20) > screen_frame.right) 1094 r.OffsetTo(6, r.top); 1095 1096 if ((r.top - 26) < screen_frame.top) 1097 r.OffsetTo(r.left, screen_frame.top + 26); 1098 1099 if ((r.top + 20) > screen_frame.bottom) 1100 r.OffsetTo(r.left, TITLE_BAR_HEIGHT); 1101 1102 if (r.Width() < WIND_WIDTH) 1103 r.right = r.left + WIND_WIDTH; 1104 1105 fWindowCount++; 1106 1107 BString title; 1108 BFile file; 1109 if (!resend && ref && file.SetTo(ref, O_RDONLY) == B_NO_ERROR) { 1110 BString name; 1111 if (ReadAttrString(&file, B_MAIL_ATTR_NAME, &name) == B_NO_ERROR) { 1112 title << name; 1113 BString subject; 1114 if (ReadAttrString(&file, B_MAIL_ATTR_SUBJECT, &subject) == B_NO_ERROR) 1115 title << " -> " << subject; 1116 } 1117 } 1118 if (title == "") 1119 title = "Mail"; 1120 1121 TMailWindow *window = new TMailWindow(r, title.String(), this, ref, to, 1122 &fContentFont, resend, trackerMessenger); 1123 fWindowList.AddItem(window); 1124 1125 return window; 1126 } 1127 1128 1129 // #pragma mark - settings 1130 1131 1132 BString 1133 TMailApp::Signature() 1134 { 1135 BAutolock _(this); 1136 return BString(fSignature); 1137 } 1138 1139 1140 BString 1141 TMailApp::ReplyPreamble() 1142 { 1143 BAutolock _(this); 1144 return BString(fReplyPreamble); 1145 } 1146 1147 1148 bool 1149 TMailApp::WrapMode() 1150 { 1151 BAutolock _(this); 1152 return fWrapMode; 1153 } 1154 1155 1156 void 1157 TMailApp::SetShowHeader(bool show) 1158 { 1159 BAutolock _(this); 1160 fShowHeader = show; 1161 } 1162 1163 1164 bool 1165 TMailApp::ShowHeader() 1166 { 1167 BAutolock _(this); 1168 return fShowHeader; 1169 } 1170 1171 1172 bool 1173 TMailApp::AttachAttributes() 1174 { 1175 BAutolock _(this); 1176 return fAttachAttributes; 1177 } 1178 1179 1180 bool 1181 TMailApp::ColoredQuotes() 1182 { 1183 BAutolock _(this); 1184 return fColoredQuotes; 1185 } 1186 1187 1188 uint8 1189 TMailApp::ShowButtonBar() 1190 { 1191 BAutolock _(this); 1192 return fShowButtonBar; 1193 } 1194 1195 1196 bool 1197 TMailApp::WarnAboutUnencodableCharacters() 1198 { 1199 BAutolock _(this); 1200 return fWarnAboutUnencodableCharacters; 1201 } 1202 1203 1204 bool 1205 TMailApp::StartWithSpellCheckOn() 1206 { 1207 BAutolock _(this); 1208 return fStartWithSpellCheckOn; 1209 } 1210 1211 1212 void 1213 TMailApp::SetDefaultChain(uint32 chain) 1214 { 1215 BAutolock _(this); 1216 fDefaultChain = chain; 1217 } 1218 1219 1220 uint32 1221 TMailApp::DefaultChain() 1222 { 1223 BAutolock _(this); 1224 return fDefaultChain; 1225 } 1226 1227 1228 int32 1229 TMailApp::UseAccountFrom() 1230 { 1231 BAutolock _(this); 1232 return fUseAccountFrom; 1233 } 1234 1235 1236 uint32 1237 TMailApp::MailCharacterSet() 1238 { 1239 BAutolock _(this); 1240 return fMailCharacterSet; 1241 } 1242 1243 1244 BFont 1245 TMailApp::ContentFont() 1246 { 1247 BAutolock _(this); 1248 return fContentFont; 1249 } 1250 1251