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