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_ACCOUNTS: 378 be_roster->Launch("application/x-vnd.Haiku-Mail"); 379 break; 380 381 case M_EDIT_SIGNATURE: 382 if (fSigWindow) 383 fSigWindow->Activate(true); 384 else { 385 fSigWindow = new TSignatureWindow(fSignatureWindowFrame); 386 fSigWindow->Show(); 387 } 388 break; 389 390 case M_FONT: 391 FontChange(); 392 break; 393 394 case REFS_RECEIVED: 395 if (msg->HasPointer("window")) 396 { 397 msg->FindPointer("window", (void **)&window); 398 BMessage message(*msg); 399 window->PostMessage(&message, window); 400 } 401 break; 402 403 case WINDOW_CLOSED: 404 switch (msg->FindInt32("kind")) { 405 case MAIL_WINDOW: 406 { 407 TMailWindow *window; 408 if( msg->FindPointer( "window", (void **)&window ) == B_OK ) 409 fWindowList.RemoveItem(window); 410 fWindowCount--; 411 break; 412 } 413 414 case PREFS_WINDOW: 415 fPrefsWindow = NULL; 416 msg->FindPoint("window pos", &fPrefsWindowPos); 417 break; 418 419 case SIG_WINDOW: 420 fSigWindow = NULL; 421 msg->FindRect("window frame", &fSignatureWindowFrame); 422 break; 423 } 424 425 if (!fWindowCount && !fSigWindow && !fPrefsWindow) 426 be_app->PostMessage(B_QUIT_REQUESTED); 427 break; 428 429 case B_REFS_RECEIVED: 430 RefsReceived(msg); 431 break; 432 433 case B_PRINTER_CHANGED: 434 _ClearPrintSettings(); 435 break; 436 437 default: 438 BApplication::MessageReceived(msg); 439 } 440 } 441 442 443 bool 444 TMailApp::QuitRequested() 445 { 446 if (!BApplication::QuitRequested()) 447 return false; 448 449 fMailWindowFrame = fLastMailWindowFrame; 450 // Last closed window becomes standard window size. 451 452 // Shut down the spam server if it's still running. If the user has trained it on a message, it will stay 453 // open. This is actually a good thing if there's quite a bit of spam -- no waiting for the thing to start 454 // up for each message, but it has no business staying that way if the user isn't doing anything with e-mail. :) 455 if (be_roster->IsRunning(kSpamServerSignature)) { 456 team_id serverTeam = be_roster->TeamFor(kSpamServerSignature); 457 if (serverTeam >= 0) { 458 int32 errorCode = B_SERVER_NOT_FOUND; 459 BMessenger messengerToSpamServer(kSpamServerSignature, serverTeam, &errorCode); 460 if (messengerToSpamServer.IsValid()) { 461 BMessage quitMessage(B_QUIT_REQUESTED); 462 messengerToSpamServer.SendMessage(&quitMessage); 463 } 464 } 465 466 } 467 468 SaveSettings(); 469 return true; 470 } 471 472 473 void 474 TMailApp::ReadyToRun() 475 { 476 // Create needed indices for META:group, META:email, MAIL:draft, 477 // INDEX_SIGNATURE, INDEX_STATUS on the boot volume 478 479 BVolume volume; 480 BVolumeRoster().GetBootVolume(&volume); 481 482 fs_create_index(volume.Device(), "META:group", B_STRING_TYPE, 0); 483 fs_create_index(volume.Device(), "META:email", B_STRING_TYPE, 0); 484 fs_create_index(volume.Device(), "MAIL:draft", B_INT32_TYPE, 0); 485 fs_create_index(volume.Device(), INDEX_SIGNATURE, B_STRING_TYPE, 0); 486 fs_create_index(volume.Device(), INDEX_STATUS, B_STRING_TYPE, 0); 487 488 // Load dictionaries 489 BPath indexDir; 490 BPath dictionaryDir; 491 BPath dataPath; 492 BPath indexPath; 493 BDirectory directory; 494 BEntry entry; 495 496 // Locate user settings directory 497 find_directory(B_BEOS_ETC_DIRECTORY, &indexDir, true); 498 dictionaryDir = indexDir; 499 500 // Setup directory paths 501 indexDir.Append(kIndexDirectory); 502 dictionaryDir.Append(kDictDirectory); 503 504 // Create directories if needed 505 directory.CreateDirectory(indexDir.Path(), NULL); 506 directory.CreateDirectory(dictionaryDir.Path(), NULL); 507 508 dataPath = dictionaryDir; 509 dataPath.Append("words"); 510 511 // Only Load if Words Dictionary 512 if (BEntry(kWordsPath).Exists() || BEntry(dataPath.Path()).Exists()) { 513 // If "/boot/optional/goodies/words" exists but there is no 514 // system dictionary, copy words 515 if (!BEntry(dataPath.Path()).Exists() && BEntry(kWordsPath).Exists()) { 516 BFile words(kWordsPath, B_READ_ONLY); 517 BFile copy(dataPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); 518 char buffer[4096]; 519 ssize_t size; 520 521 while ((size = words.Read( buffer, 4096)) > 0) 522 copy.Write(buffer, size); 523 BNodeInfo(©).SetType("text/plain"); 524 } 525 526 // Create user dictionary if it does not exist 527 dataPath = dictionaryDir; 528 dataPath.Append("user"); 529 if (!BEntry(dataPath.Path()).Exists()) { 530 BFile user(dataPath.Path(), B_WRITE_ONLY | B_CREATE_FILE); 531 BNodeInfo(&user).SetType("text/plain"); 532 } 533 534 // Load dictionaries 535 directory.SetTo(dictionaryDir.Path()); 536 537 BString leafName; 538 gUserDict = -1; 539 540 while (gDictCount < MAX_DICTIONARIES 541 && directory.GetNextEntry(&entry) != B_ENTRY_NOT_FOUND) { 542 dataPath.SetTo(&entry); 543 544 // Identify the user dictionary 545 if (strcmp("user", dataPath.Leaf()) == 0) { 546 gUserDictFile = new BFile(dataPath.Path(), B_WRITE_ONLY | B_OPEN_AT_END); 547 gUserDict = gDictCount; 548 } 549 550 indexPath = indexDir; 551 leafName.SetTo(dataPath.Leaf()); 552 leafName.Append(kMetaphone); 553 indexPath.Append(leafName.String()); 554 gWords[gDictCount] = new Words(dataPath.Path(), indexPath.Path(), true); 555 556 indexPath = indexDir; 557 leafName.SetTo(dataPath.Leaf()); 558 leafName.Append(kExact); 559 indexPath.Append(leafName.String()); 560 gExactWords[gDictCount] = new Words(dataPath.Path(), indexPath.Path(), false); 561 gDictCount++; 562 } 563 } 564 565 // Create a new window if starting up without any extra arguments. 566 567 if (!fPrintHelpAndExit && !fWindowCount) { 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