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