RemoteDrawingEngine: Reduce RP_READ_BITMAP result timeout.
[haiku.git] / src / apps / mail / MailApp.cpp
blobc8791fa57c750ed230549c286a053dfd1b969857
1 /*
2 Open Tracker License
4 Terms and Conditions
6 Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
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:
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.
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
23 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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.
29 BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or
30 registered trademarks of Be Incorporated in the United States and other
31 countries. Other brand product names are registered trademarks or trademarks
32 of their respective holders. All rights reserved.
36 #include "MailApp.h"
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>
46 #include <Autolock.h>
47 #include <Catalog.h>
48 #include <CharacterSet.h>
49 #include <CharacterSetRoster.h>
50 #include <Clipboard.h>
51 #include <Debug.h>
52 #include <E-mail.h>
53 #include <InterfaceKit.h>
54 #include <Locale.h>
55 #include <Roster.h>
56 #include <Screen.h>
57 #include <StorageKit.h>
58 #include <String.h>
59 #include <TextView.h>
60 #include <UTF8.h>
62 #include <fs_index.h>
63 #include <fs_info.h>
65 #include <MailMessage.h>
66 #include <MailSettings.h>
67 #include <MailDaemon.h>
68 #include <mail_util.h>
70 #include <CharacterSetRoster.h>
72 using namespace BPrivate ;
74 #include "Content.h"
75 #include "Enclosures.h"
76 #include "FieldMsg.h"
77 #include "FindWindow.h"
78 #include "Header.h"
79 #include "MailSupport.h"
80 #include "MailWindow.h"
81 #include "Messages.h"
82 #include "Prefs.h"
83 #include "QueryMenu.h"
84 #include "Signature.h"
85 #include "Status.h"
86 #include "String.h"
87 #include "Utilities.h"
88 #include "Words.h"
91 #define B_TRANSLATION_CONTEXT "Mail"
94 static const char *kDictDirectory = "word_dictionary";
95 static const char *kIndexDirectory = "word_index";
96 static const char *kWordsPath = "/boot/optional/goodies/words";
97 static const char *kExact = ".exact";
98 static const char *kMetaphone = ".metaphone";
101 TMailApp::TMailApp()
103 BApplication("application/x-vnd.Be-MAIL"),
104 fWindowCount(0),
105 fPrefsWindow(NULL),
106 fSigWindow(NULL),
108 fPrintSettings(NULL),
109 fPrintHelpAndExit(false),
111 fWrapMode(true),
112 fAttachAttributes(true),
113 fColoredQuotes(true),
114 fShowToolBar(true),
115 fWarnAboutUnencodableCharacters(true),
116 fStartWithSpellCheckOn(false),
117 fShowSpamGUI(true),
118 fMailCharacterSet(B_MAIL_UTF8_CONVERSION),
119 fContentFont(be_fixed_font),
121 fPeople(fPeopleQueryList),
122 fPeopleGroups(fPeopleQueryList)
124 // set default values
125 fAutoMarkRead = true;
126 fSignature = (char*)malloc(strlen(B_TRANSLATE("None")) + 1);
127 strcpy(fSignature, B_TRANSLATE("None"));
128 fReplyPreamble = strdup(B_TRANSLATE("%e wrote:\\n"));
130 fMailWindowFrame.Set(0, 0, 0, 0);
132 const BCharacterSet* defaultComposeEncoding
133 = BCharacterSetRoster::FindCharacterSetByName(B_TRANSLATE_COMMENT(
134 "UTF-8", "This string is used as a key to set default message "
135 "compose encoding. It must be correct IANA name from "
136 "http://cgit.haiku-os.org/haiku/tree/src/kits/textencoding"
137 "/character_sets.cpp Translate it only if you want to change "
138 "default message compose encoding for your locale. If you don't "
139 "know what is it and why it may needs changing, just leave "
140 "\"UTF-8\"."));
141 if (defaultComposeEncoding != NULL)
142 fMailCharacterSet = defaultComposeEncoding->GetConversionID();
144 // Find and read settings file.
145 LoadSettings();
147 _CheckForSpamFilterExistence();
148 fContentFont.SetSpacing(B_BITMAP_SPACING);
149 fLastMailWindowFrame = fMailWindowFrame;
153 TMailApp::~TMailApp()
158 void
159 TMailApp::ArgvReceived(int32 argc, char **argv)
161 BEntry entry;
162 BString names;
163 BString ccNames;
164 BString bccNames;
165 BString subject;
166 BString body;
167 BMessage enclosure(B_REFS_RECEIVED);
168 // a "mailto:" with no name should open an empty window
169 // so remember if we got a "mailto:" even if there isn't a name
170 // that goes along with it (this allows deskbar replicant to open
171 // an empty message even when Mail is already running)
172 bool gotmailto = false;
174 for (int32 loop = 1; loop < argc; loop++)
176 if (strcmp(argv[loop], "-h") == 0
177 || strcmp(argv[loop], "--help") == 0)
179 printf(" usage: %s [ mailto:<address> ] [ -subject \"<text>\" ] [ ccto:<address> ] [ bccto:<address> ] "
180 "[ -body \"<body text>\" ] [ enclosure:<path> ] [ <message to read> ...] \n",
181 argv[0]);
182 fPrintHelpAndExit = true;
183 be_app->PostMessage(B_QUIT_REQUESTED);
184 return;
186 else if (strncmp(argv[loop], "mailto:", 7) == 0)
188 if (names.Length())
189 names += ", ";
190 char *options;
191 if ((options = strchr(argv[loop],'?')) != NULL)
193 names.Append(argv[loop] + 7, options - argv[loop] - 7);
194 if (!strncmp(++options,"subject=",8))
195 subject = options + 8;
197 else
198 names += argv[loop] + 7;
199 gotmailto = true;
201 else if (strncmp(argv[loop], "ccto:", 5) == 0)
203 if (ccNames.Length())
204 ccNames += ", ";
205 ccNames += argv[loop] + 5;
207 else if (strncmp(argv[loop], "bccto:", 6) == 0)
209 if (bccNames.Length())
210 bccNames += ", ";
211 bccNames += argv[loop] + 6;
213 else if (strcmp(argv[loop], "-subject") == 0)
214 subject = argv[++loop];
215 else if (strcmp(argv[loop], "-body") == 0 && argv[loop + 1])
216 body = argv[++loop];
217 else if (strncmp(argv[loop], "enclosure:", 10) == 0)
219 BEntry tmp(argv[loop] + 10, true);
220 if (tmp.InitCheck() == B_OK && tmp.Exists())
222 entry_ref ref;
223 tmp.GetRef(&ref);
224 enclosure.AddRef("refs", &ref);
227 else if (entry.SetTo(argv[loop]) == B_NO_ERROR)
229 BMessage msg(B_REFS_RECEIVED);
230 entry_ref ref;
231 entry.GetRef(&ref);
232 msg.AddRef("refs", &ref);
233 RefsReceived(&msg);
237 if (gotmailto || names.Length() || ccNames.Length() || bccNames.Length() || subject.Length()
238 || body.Length() || enclosure.HasRef("refs"))
240 TMailWindow *window = NewWindow(NULL, names.String());
241 window->SetTo(names.String(), subject.String(), ccNames.String(), bccNames.String(),
242 &body, &enclosure);
243 window->Show();
248 void
249 TMailApp::MessageReceived(BMessage *msg)
251 TMailWindow *window = NULL;
252 entry_ref ref;
254 switch (msg->what) {
255 case M_NEW:
257 int32 type;
258 msg->FindInt32("type", &type);
259 switch (type) {
260 case M_NEW:
261 window = NewWindow();
262 break;
264 case M_RESEND:
266 msg->FindRef("ref", &ref);
267 BNode file(&ref);
268 BString string;
270 if (file.InitCheck() == B_OK)
271 file.ReadAttrString(B_MAIL_ATTR_TO, &string);
273 window = NewWindow(&ref, string.String(), true);
274 break;
276 case M_FORWARD:
277 case M_FORWARD_WITHOUT_ATTACHMENTS:
279 TMailWindow *sourceWindow;
280 if (msg->FindPointer("window", (void **)&sourceWindow) < B_OK
281 || !sourceWindow->Lock())
282 break;
284 msg->FindRef("ref", &ref);
285 window = NewWindow();
286 if (window->Lock()) {
287 window->Forward(&ref, sourceWindow, type == M_FORWARD);
288 window->Unlock();
290 sourceWindow->Unlock();
291 break;
294 case M_REPLY:
295 case M_REPLY_TO_SENDER:
296 case M_REPLY_ALL:
297 case M_COPY_TO_NEW:
299 TMailWindow *sourceWindow;
300 if (msg->FindPointer("window", (void **)&sourceWindow) < B_OK
301 || !sourceWindow->Lock())
302 break;
303 msg->FindRef("ref", &ref);
304 window = NewWindow();
305 if (window->Lock()) {
306 if (type == M_COPY_TO_NEW)
307 window->CopyMessage(&ref, sourceWindow);
308 else
309 window->Reply(&ref, sourceWindow, type);
310 window->Unlock();
312 sourceWindow->Unlock();
313 break;
316 if (window)
317 window->Show();
318 break;
321 case M_PREFS:
322 if (fPrefsWindow)
323 fPrefsWindow->Activate(true);
324 else {
325 fPrefsWindow = new TPrefsWindow(fPrefsWindowPos,
326 &fContentFont, NULL, &fWrapMode, &fAttachAttributes,
327 &fColoredQuotes, &fDefaultAccount, &fUseAccountFrom,
328 &fReplyPreamble, &fSignature, &fMailCharacterSet,
329 &fWarnAboutUnencodableCharacters,
330 &fStartWithSpellCheckOn, &fAutoMarkRead,
331 &fShowToolBar);
332 if (fPrefsWindowPos.x <= 0 || fPrefsWindowPos.y <= 0) {
333 TMailWindow* window = _ActiveWindow();
334 if (window != NULL)
335 fPrefsWindow->CenterIn(window->Frame());
336 else
337 fPrefsWindow->CenterOnScreen();
339 fPrefsWindow->MoveOnScreen();
340 fPrefsWindow->Show();
342 break;
344 case PREFS_CHANGED:
346 // Notify all Mail windows
347 for (int32 i = 0; i < fWindowList.CountItems(); i++) {
348 TMailWindow* window = (TMailWindow*)fWindowList.ItemAt(i);
349 window->Lock();
350 window->UpdatePreferences();
351 window->UpdateViews();
352 window->Unlock();
354 break;
357 case M_ACCOUNTS:
358 be_roster->Launch("application/x-vnd.Haiku-Mail");
359 break;
361 case M_EDIT_SIGNATURE:
362 if (fSigWindow != NULL)
363 fSigWindow->Activate(true);
364 else {
365 fSigWindow = new TSignatureWindow(fSignatureWindowFrame);
366 if (!fSignatureWindowFrame.IsValid()) {
367 TMailWindow* window = _ActiveWindow();
368 if (window != NULL)
369 fSigWindow->CenterIn(window->Frame());
370 else
371 fSigWindow->CenterOnScreen();
373 fSigWindow->MoveOnScreen();
374 fSigWindow->Show();
376 break;
378 case M_FONT:
379 FontChange();
380 break;
382 case REFS_RECEIVED:
383 if (msg->HasPointer("window")) {
384 msg->FindPointer("window", (void**)&window);
385 BMessage message(*msg);
386 window->PostMessage(&message, window);
388 break;
390 case WINDOW_CLOSED:
391 switch (msg->FindInt32("kind")) {
392 case MAIL_WINDOW:
394 TMailWindow* window;
395 if( msg->FindPointer("window", (void**)&window) == B_OK)
396 fWindowList.RemoveItem(window);
397 fWindowCount--;
398 break;
401 case PREFS_WINDOW:
402 fPrefsWindow = NULL;
403 msg->FindPoint("window pos", &fPrefsWindowPos);
404 break;
406 case SIG_WINDOW:
407 fSigWindow = NULL;
408 msg->FindRect("window frame", &fSignatureWindowFrame);
409 break;
412 if (!fWindowCount && !fSigWindow && !fPrefsWindow)
413 be_app->PostMessage(B_QUIT_REQUESTED);
414 break;
416 case B_REFS_RECEIVED:
417 RefsReceived(msg);
418 break;
420 case B_PRINTER_CHANGED:
421 _ClearPrintSettings();
422 break;
424 default:
425 BApplication::MessageReceived(msg);
430 bool
431 TMailApp::QuitRequested()
433 if (!BApplication::QuitRequested())
434 return false;
436 fMailWindowFrame = fLastMailWindowFrame;
437 // Last closed window becomes standard window size.
439 // Shut down the spam server if it's still running. If the user has trained it on a message, it will stay
440 // open. This is actually a good thing if there's quite a bit of spam -- no waiting for the thing to start
441 // up for each message, but it has no business staying that way if the user isn't doing anything with e-mail. :)
442 if (be_roster->IsRunning(kSpamServerSignature)) {
443 team_id serverTeam = be_roster->TeamFor(kSpamServerSignature);
444 if (serverTeam >= 0) {
445 int32 errorCode = B_SERVER_NOT_FOUND;
446 BMessenger messengerToSpamServer(kSpamServerSignature, serverTeam, &errorCode);
447 if (messengerToSpamServer.IsValid()) {
448 BMessage quitMessage(B_QUIT_REQUESTED);
449 messengerToSpamServer.SendMessage(&quitMessage);
455 SaveSettings();
456 return true;
460 void
461 TMailApp::ReadyToRun()
463 // Create needed indices for META:group, META:email, MAIL:draft,
464 // INDEX_SIGNATURE, INDEX_STATUS on the boot volume
466 BVolume volume;
467 BVolumeRoster().GetBootVolume(&volume);
469 fs_create_index(volume.Device(), "META:group", B_STRING_TYPE, 0);
470 fs_create_index(volume.Device(), "META:email", B_STRING_TYPE, 0);
471 fs_create_index(volume.Device(), "MAIL:draft", B_INT32_TYPE, 0);
472 fs_create_index(volume.Device(), INDEX_SIGNATURE, B_STRING_TYPE, 0);
473 fs_create_index(volume.Device(), INDEX_STATUS, B_STRING_TYPE, 0);
474 fs_create_index(volume.Device(), B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0);
476 // Start people queries
477 fPeopleQueryList.Init("META:email=**");
479 // Load dictionaries
480 BPath indexDir;
481 BPath dictionaryDir;
482 BPath userDictionaryDir;
483 BPath userIndexDir;
484 BPath dataPath;
485 BPath indexPath;
486 BDirectory directory;
487 BEntry entry;
489 // Locate dictionaries directory
490 find_directory(B_SYSTEM_DATA_DIRECTORY, &indexDir, true);
491 indexDir.Append("spell_check");
492 dictionaryDir = indexDir;
494 //Locate user dictionary directory
495 find_directory(B_USER_CONFIG_DIRECTORY, &userIndexDir, true);
496 userIndexDir.Append("data/spell_check");
497 userDictionaryDir = userIndexDir;
499 // Create directory if needed
500 directory.CreateDirectory(userIndexDir.Path(), NULL);
502 // Setup directory paths
503 indexDir.Append(kIndexDirectory);
504 dictionaryDir.Append(kDictDirectory);
505 userIndexDir.Append(kIndexDirectory);
506 userDictionaryDir.Append(kDictDirectory);
508 // Create directories if needed
509 directory.CreateDirectory(indexDir.Path(), NULL);
510 directory.CreateDirectory(dictionaryDir.Path(), NULL);
511 directory.CreateDirectory(userIndexDir.Path(), NULL);
512 directory.CreateDirectory(userDictionaryDir.Path(), NULL);
514 dataPath = dictionaryDir;
515 dataPath.Append("words");
517 // Only Load if Words Dictionary
518 if (BEntry(kWordsPath).Exists() || BEntry(dataPath.Path()).Exists()) {
519 // If "/boot/optional/goodies/words" exists but there is no
520 // system dictionary, copy words
521 if (!BEntry(dataPath.Path()).Exists() && BEntry(kWordsPath).Exists()) {
522 BFile words(kWordsPath, B_READ_ONLY);
523 BFile copy(dataPath.Path(), B_WRITE_ONLY | B_CREATE_FILE);
524 char buffer[4096];
525 ssize_t size;
527 while ((size = words.Read( buffer, 4096)) > 0)
528 copy.Write(buffer, size);
529 BNodeInfo(&copy).SetType("text/plain");
532 // Load dictionaries
533 directory.SetTo(dictionaryDir.Path());
535 BString leafName;
536 gUserDict = -1;
538 while (gDictCount < MAX_DICTIONARIES
539 && directory.GetNextEntry(&entry) != B_ENTRY_NOT_FOUND) {
540 dataPath.SetTo(&entry);
542 indexPath = indexDir;
543 leafName.SetTo(dataPath.Leaf());
544 leafName.Append(kMetaphone);
545 indexPath.Append(leafName.String());
546 gWords[gDictCount] = new Words(dataPath.Path(), indexPath.Path(), true);
548 indexPath = indexDir;
549 leafName.SetTo(dataPath.Leaf());
550 leafName.Append(kExact);
551 indexPath.Append(leafName.String());
552 gExactWords[gDictCount] = new Words(dataPath.Path(), indexPath.Path(), false);
553 gDictCount++;
556 // Create user dictionary if it does not exist
557 dataPath = userDictionaryDir;
558 dataPath.Append("user");
559 if (!BEntry(dataPath.Path()).Exists()) {
560 BFile user(dataPath.Path(), B_WRITE_ONLY | B_CREATE_FILE);
561 BNodeInfo(&user).SetType("text/plain");
564 // Load user dictionary
565 if (BEntry(userDictionaryDir.Path()).Exists()) {
566 gUserDictFile = new BFile(dataPath.Path(), B_WRITE_ONLY | B_OPEN_AT_END);
567 gUserDict = gDictCount;
569 indexPath = userIndexDir;
570 leafName.SetTo(dataPath.Leaf());
571 leafName.Append(kMetaphone);
572 indexPath.Append(leafName.String());
573 gWords[gDictCount] = new Words(dataPath.Path(), indexPath.Path(), true);
575 indexPath = userIndexDir;
576 leafName.SetTo(dataPath.Leaf());
577 leafName.Append(kExact);
578 indexPath.Append(leafName.String());
579 gExactWords[gDictCount] = new Words(dataPath.Path(), indexPath.Path(), false);
580 gDictCount++;
584 // Create a new window if starting up without any extra arguments.
586 if (!fPrintHelpAndExit && !fWindowCount) {
587 TMailWindow *window;
588 window = NewWindow();
589 window->Show();
594 void
595 TMailApp::RefsReceived(BMessage *msg)
597 bool have_names = false;
598 BString names;
599 char type[B_FILE_NAME_LENGTH];
600 int32 item = 0;
601 BFile file;
602 TMailWindow *window;
603 entry_ref ref;
606 // If a tracker window opened me, get a messenger from it.
608 BMessenger messenger;
609 if (msg->HasMessenger("TrackerViewToken"))
610 msg->FindMessenger("TrackerViewToken", &messenger);
612 while (msg->HasRef("refs", item)) {
613 msg->FindRef("refs", item++, &ref);
614 if ((window = FindWindow(ref)) != NULL)
615 window->Activate(true);
616 else {
617 file.SetTo(&ref, O_RDONLY);
618 if (file.InitCheck() == B_NO_ERROR) {
619 BNodeInfo node(&file);
620 node.GetType(type);
621 if (strcmp(type, B_MAIL_TYPE) == 0
622 || strcmp(type, B_PARTIAL_MAIL_TYPE) == 0) {
623 window = NewWindow(&ref, NULL, false, &messenger);
624 window->Show();
625 } else if(strcmp(type, "application/x-person") == 0) {
626 /* Got a People contact info file, see if it has an Email address. */
627 BString name;
628 BString email;
629 attr_info info;
630 char *attrib;
632 if (file.GetAttrInfo("META:email", &info) == B_NO_ERROR) {
633 attrib = (char *) malloc(info.size + 1);
634 file.ReadAttr("META:email", B_STRING_TYPE, 0, attrib, info.size);
635 attrib[info.size] = 0; // Just in case it wasn't NUL terminated.
636 email << attrib;
637 free(attrib);
639 /* we got something... */
640 if (email.Length() > 0) {
641 /* see if we can get a username as well */
642 if(file.GetAttrInfo("META:name", &info) == B_NO_ERROR) {
643 attrib = (char *) malloc(info.size + 1);
644 file.ReadAttr("META:name", B_STRING_TYPE, 0, attrib, info.size);
645 attrib[info.size] = 0; // Just in case it wasn't NUL terminated.
646 name << "\"" << attrib << "\" ";
647 email.Prepend("<");
648 email.Append(">");
649 free(attrib);
652 if (names.Length() == 0) {
653 names << name << email;
654 } else {
655 names << ", " << name << email;
657 have_names = true;
658 email.SetTo("");
659 name.SetTo("");
663 else if (strcmp(type, kDraftType) == 0) {
664 window = NewWindow();
666 // If it's a draft message, open it
667 window->OpenMessage(&ref);
668 window->Show();
670 } /* end of else(file.InitCheck() == B_NO_ERROR */
674 if (have_names) {
675 window = NewWindow(NULL, names.String());
676 window->Show();
681 TMailWindow *
682 TMailApp::FindWindow(const entry_ref &ref)
684 BEntry entry(&ref);
685 if (entry.InitCheck() < B_OK)
686 return NULL;
688 node_ref nodeRef;
689 if (entry.GetNodeRef(&nodeRef) < B_OK)
690 return NULL;
692 BWindow *window;
693 int32 index = 0;
694 while ((window = WindowAt(index++)) != NULL) {
695 TMailWindow *mailWindow = dynamic_cast<TMailWindow *>(window);
696 if (mailWindow == NULL)
697 continue;
699 node_ref mailNodeRef;
700 if (mailWindow->GetMailNodeRef(mailNodeRef) == B_OK
701 && mailNodeRef == nodeRef)
702 return mailWindow;
705 return NULL;
709 void
710 TMailApp::_CheckForSpamFilterExistence()
712 // Looks at the filter settings to see if the user is using a spam filter.
713 // If there is one there, set fShowSpamGUI to TRUE, otherwise to FALSE.
715 int32 addonNameIndex;
716 const char *addonNamePntr;
717 BDirectory inChainDir;
718 BPath path;
719 BEntry settingsEntry;
720 BFile settingsFile;
721 BMessage settingsMessage;
723 fShowSpamGUI = false;
725 if (find_directory(B_USER_SETTINGS_DIRECTORY, &path) != B_OK)
726 return;
727 // TODO use new settings
728 path.Append("Mail/chains/inbound");
729 if (inChainDir.SetTo(path.Path()) != B_OK)
730 return;
732 while (inChainDir.GetNextEntry (&settingsEntry, true /* traverse */) == B_OK) {
733 if (!settingsEntry.IsFile())
734 continue;
735 if (settingsFile.SetTo (&settingsEntry, B_READ_ONLY) != B_OK)
736 continue;
737 if (settingsMessage.Unflatten (&settingsFile) != B_OK)
738 continue;
739 for (addonNameIndex = 0; B_OK == settingsMessage.FindString (
740 "filter_addons", addonNameIndex, &addonNamePntr);
741 addonNameIndex++) {
742 if (strstr (addonNamePntr, "Spam Filter") != NULL) {
743 fShowSpamGUI = true; // Found it!
744 return;
751 TMailWindow*
752 TMailApp::_ActiveWindow()
754 for (int32 i = 0; i < fWindowList.CountItems(); i++) {
755 TMailWindow* window = (TMailWindow*)fWindowList.ItemAt(i);
756 if (window->IsActive())
757 return window;
759 return NULL;
763 void
764 TMailApp::SetPrintSettings(const BMessage* printSettings)
766 BAutolock _(this);
768 if (printSettings == fPrintSettings)
769 return;
771 delete fPrintSettings;
772 if (printSettings)
773 fPrintSettings = new BMessage(*printSettings);
774 else
775 fPrintSettings = NULL;
779 bool
780 TMailApp::HasPrintSettings()
782 BAutolock _(this);
783 return fPrintSettings != NULL;
787 BMessage
788 TMailApp::PrintSettings()
790 BAutolock _(this);
791 return BMessage(*fPrintSettings);
795 void
796 TMailApp::_ClearPrintSettings()
798 delete fPrintSettings;
799 fPrintSettings = NULL;
803 void
804 TMailApp::SetLastWindowFrame(BRect frame)
806 BAutolock _(this);
807 fLastMailWindowFrame = frame;
811 status_t
812 TMailApp::GetSettingsPath(BPath &path)
814 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
815 if (status != B_OK)
816 return status;
818 path.Append("Mail");
819 return create_directory(path.Path(), 0755);
823 status_t
824 TMailApp::LoadOldSettings()
826 BPath path;
827 status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
828 if (status != B_OK)
829 return status;
831 path.Append("Mail_data");
833 BFile file;
834 status = file.SetTo(path.Path(), B_READ_ONLY);
835 if (status != B_OK)
836 return status;
838 file.Read(&fMailWindowFrame, sizeof(BRect));
839 // file.Read(&level, sizeof(level));
841 font_family fontFamily;
842 font_style fontStyle;
843 float size;
844 file.Read(&fontFamily, sizeof(font_family));
845 file.Read(&fontStyle, sizeof(font_style));
846 file.Read(&size, sizeof(float));
847 if (size >= 9)
848 fContentFont.SetSize(size);
850 if (fontFamily[0] && fontStyle[0])
851 fContentFont.SetFamilyAndStyle(fontFamily, fontStyle);
853 file.Read(&fSignatureWindowFrame, sizeof(BRect));
854 file.Seek(1, SEEK_CUR); // ignore (bool) show header
855 file.Read(&fWrapMode, sizeof(bool));
856 file.Read(&fPrefsWindowPos, sizeof(BPoint));
858 int32 length;
859 if (file.Read(&length, sizeof(int32)) < (ssize_t)sizeof(int32))
860 return B_IO_ERROR;
862 free(fSignature);
863 fSignature = NULL;
865 if (length > 0) {
866 fSignature = (char *)malloc(length);
867 if (fSignature == NULL)
868 return B_NO_MEMORY;
870 file.Read(fSignature, length);
873 file.Read(&fMailCharacterSet, sizeof(int32));
874 if (fMailCharacterSet != B_MAIL_UTF8_CONVERSION
875 && fMailCharacterSet != B_MAIL_US_ASCII_CONVERSION
876 && BCharacterSetRoster::GetCharacterSetByConversionID(fMailCharacterSet) == NULL)
877 fMailCharacterSet = B_MS_WINDOWS_CONVERSION;
879 if (file.Read(&length, sizeof(int32)) == (ssize_t)sizeof(int32)) {
880 char *findString = (char *)malloc(length + 1);
881 if (findString == NULL)
882 return B_NO_MEMORY;
884 file.Read(findString, length);
885 findString[length] = '\0';
886 FindWindow::SetFindString(findString);
887 free(findString);
889 if (file.Read(&fShowToolBar, sizeof(uint8)) < (ssize_t)sizeof(uint8))
890 fShowToolBar = true;
891 if (file.Read(&fUseAccountFrom, sizeof(int32)) < (ssize_t)sizeof(int32)
892 || fUseAccountFrom < ACCOUNT_USE_DEFAULT
893 || fUseAccountFrom > ACCOUNT_FROM_MAIL)
894 fUseAccountFrom = ACCOUNT_USE_DEFAULT;
895 if (file.Read(&fColoredQuotes, sizeof(bool)) < (ssize_t)sizeof(bool))
896 fColoredQuotes = true;
898 if (file.Read(&length, sizeof(int32)) == (ssize_t)sizeof(int32)) {
899 free(fReplyPreamble);
900 fReplyPreamble = (char *)malloc(length + 1);
901 if (fReplyPreamble == NULL)
902 return B_NO_MEMORY;
904 file.Read(fReplyPreamble, length);
905 fReplyPreamble[length] = '\0';
908 file.Read(&fAttachAttributes, sizeof(bool));
909 file.Read(&fWarnAboutUnencodableCharacters, sizeof(bool));
911 return B_OK;
915 status_t
916 TMailApp::SaveSettings()
918 BMailSettings accountSettings;
920 if (fDefaultAccount != ~0L) {
921 accountSettings.SetDefaultOutboundAccount(fDefaultAccount);
922 accountSettings.Save();
925 BPath path;
926 status_t status = GetSettingsPath(path);
927 if (status != B_OK)
928 return status;
930 path.Append("BeMail Settings~");
932 BFile file;
933 status = file.SetTo(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
934 if (status != B_OK)
935 return status;
937 BMessage settings('BeMl');
938 settings.AddRect("MailWindowSize", fMailWindowFrame);
939 // settings.AddInt32("ExperienceLevel", level);
941 font_family fontFamily;
942 font_style fontStyle;
943 fContentFont.GetFamilyAndStyle(&fontFamily, &fontStyle);
945 settings.AddString("FontFamily", fontFamily);
946 settings.AddString("FontStyle", fontStyle);
947 settings.AddFloat("FontSize", fContentFont.Size());
949 settings.AddRect("SignatureWindowSize", fSignatureWindowFrame);
950 settings.AddBool("WordWrapMode", fWrapMode);
951 settings.AddPoint("PreferencesWindowLocation", fPrefsWindowPos);
952 settings.AddBool("AutoMarkRead", fAutoMarkRead);
953 settings.AddString("SignatureText", fSignature);
954 settings.AddInt32("CharacterSet", fMailCharacterSet);
955 settings.AddString("FindString", FindWindow::GetFindString());
956 settings.AddInt8("ShowButtonBar", fShowToolBar);
957 settings.AddInt32("UseAccountFrom", fUseAccountFrom);
958 settings.AddBool("ColoredQuotes", fColoredQuotes);
959 settings.AddString("ReplyPreamble", fReplyPreamble);
960 settings.AddBool("AttachAttributes", fAttachAttributes);
961 settings.AddBool("WarnAboutUnencodableCharacters", fWarnAboutUnencodableCharacters);
962 settings.AddBool("StartWithSpellCheck", fStartWithSpellCheckOn);
964 BEntry entry;
965 status = entry.SetTo(path.Path());
966 if (status != B_OK)
967 return status;
969 status = settings.Flatten(&file);
970 if (status == B_OK) {
971 // replace original settings file
972 status = entry.Rename("BeMail Settings", true);
973 } else
974 entry.Remove();
976 return status;
980 status_t
981 TMailApp::LoadSettings()
983 BMailSettings accountSettings;
984 fDefaultAccount = accountSettings.DefaultOutboundAccount();
986 BPath path;
987 status_t status = GetSettingsPath(path);
988 if (status != B_OK)
989 return status;
991 path.Append("BeMail Settings");
993 BFile file;
994 status = file.SetTo(path.Path(), B_READ_ONLY);
995 if (status != B_OK)
996 return LoadOldSettings();
998 BMessage settings;
999 status = settings.Unflatten(&file);
1000 if (status < B_OK || settings.what != 'BeMl') {
1001 // the current settings are corrupted, try old ones
1002 return LoadOldSettings();
1005 BRect rect;
1006 if (settings.FindRect("MailWindowSize", &rect) == B_OK)
1007 fMailWindowFrame = rect;
1009 int32 int32Value;
1010 // if (settings.FindInt32("ExperienceLevel", &int32Value) == B_OK)
1011 // level = int32Value;
1013 const char *fontFamily;
1014 if (settings.FindString("FontFamily", &fontFamily) == B_OK) {
1015 const char *fontStyle;
1016 if (settings.FindString("FontStyle", &fontStyle) == B_OK) {
1017 float size;
1018 if (settings.FindFloat("FontSize", &size) == B_OK) {
1019 if (size >= 7)
1020 fContentFont.SetSize(size);
1022 if (fontFamily[0] && fontStyle[0]) {
1023 fContentFont.SetFamilyAndStyle(fontFamily[0] ? fontFamily : NULL,
1024 fontStyle[0] ? fontStyle : NULL);
1030 if (settings.FindRect("SignatureWindowSize", &rect) == B_OK)
1031 fSignatureWindowFrame = rect;
1033 bool boolValue;
1034 if (settings.FindBool("WordWrapMode", &boolValue) == B_OK)
1035 fWrapMode = boolValue;
1037 BPoint point;
1038 if (settings.FindPoint("PreferencesWindowLocation", &point) == B_OK)
1039 fPrefsWindowPos = point;
1041 if (settings.FindBool("AutoMarkRead", &boolValue) == B_OK)
1042 fAutoMarkRead = boolValue;
1044 const char *string;
1045 if (settings.FindString("SignatureText", &string) == B_OK) {
1046 free(fSignature);
1047 fSignature = strdup(string);
1050 if (settings.FindInt32("CharacterSet", &int32Value) == B_OK)
1051 fMailCharacterSet = int32Value;
1052 if (fMailCharacterSet != B_MAIL_UTF8_CONVERSION
1053 && fMailCharacterSet != B_MAIL_US_ASCII_CONVERSION
1054 && BCharacterSetRoster::GetCharacterSetByConversionID(fMailCharacterSet) == NULL)
1055 fMailCharacterSet = B_MS_WINDOWS_CONVERSION;
1057 if (settings.FindString("FindString", &string) == B_OK)
1058 FindWindow::SetFindString(string);
1060 int8 int8Value;
1061 if (settings.FindInt8("ShowButtonBar", &int8Value) == B_OK)
1062 fShowToolBar = int8Value;
1064 if (settings.FindInt32("UseAccountFrom", &int32Value) == B_OK)
1065 fUseAccountFrom = int32Value;
1066 if (fUseAccountFrom < ACCOUNT_USE_DEFAULT
1067 || fUseAccountFrom > ACCOUNT_FROM_MAIL)
1068 fUseAccountFrom = ACCOUNT_USE_DEFAULT;
1070 if (settings.FindBool("ColoredQuotes", &boolValue) == B_OK)
1071 fColoredQuotes = boolValue;
1073 if (settings.FindString("ReplyPreamble", &string) == B_OK) {
1074 free(fReplyPreamble);
1075 fReplyPreamble = strdup(string);
1078 if (settings.FindBool("AttachAttributes", &boolValue) == B_OK)
1079 fAttachAttributes = boolValue;
1081 if (settings.FindBool("WarnAboutUnencodableCharacters", &boolValue) == B_OK)
1082 fWarnAboutUnencodableCharacters = boolValue;
1084 if (settings.FindBool("StartWithSpellCheck", &boolValue) == B_OK)
1085 fStartWithSpellCheckOn = boolValue;
1087 return B_OK;
1091 void
1092 TMailApp::FontChange()
1094 int32 index = 0;
1095 BMessage msg;
1096 BWindow *window;
1098 msg.what = CHANGE_FONT;
1099 msg.AddPointer("font", &fContentFont);
1101 for (;;) {
1102 window = WindowAt(index++);
1103 if (!window)
1104 break;
1106 window->PostMessage(&msg);
1111 TMailWindow*
1112 TMailApp::NewWindow(const entry_ref* ref, const char* to, bool resend,
1113 BMessenger* trackerMessenger)
1115 float fontFactor = be_plain_font->Size() / 12.0f;
1116 BRect r;
1117 if (fMailWindowFrame.Width() < 64 || fMailWindowFrame.Height() < 20) {
1118 // default size
1119 r.Set(40 * fontFactor, 40 * fontFactor, fontFactor * (40 + WIND_WIDTH),
1120 fontFactor * (40 + WIND_HEIGHT));
1121 } else
1122 r = fMailWindowFrame;
1124 // cascading windows
1125 r.OffsetBy(fontFactor * (((fWindowCount + 5) % 10) * 15 - 75),
1126 fontFactor * (((fWindowCount + 5) % 10) * 15 - 75));
1128 fWindowCount++;
1130 BString title;
1131 BFile file;
1132 if (!resend && ref && file.SetTo(ref, O_RDONLY) == B_OK) {
1133 BString name;
1134 if (file.ReadAttrString(B_MAIL_ATTR_NAME, &name) == B_OK) {
1135 title << name;
1136 BString subject;
1137 if (file.ReadAttrString(B_MAIL_ATTR_SUBJECT, &subject) == B_OK)
1138 title << " -> " << subject;
1141 if (title == "")
1142 title = B_TRANSLATE_SYSTEM_NAME("Mail");
1144 TMailWindow* window = new TMailWindow(r, title.String(), this, ref, to,
1145 &fContentFont, resend, trackerMessenger);
1146 fWindowList.AddItem(window);
1148 window->MoveOnScreen();
1149 return window;
1153 // #pragma mark - settings
1156 bool
1157 TMailApp::AutoMarkRead()
1159 BAutolock _(this);
1160 return fAutoMarkRead;
1164 BString
1165 TMailApp::Signature()
1167 BAutolock _(this);
1168 return BString(fSignature);
1172 BString
1173 TMailApp::ReplyPreamble()
1175 BAutolock _(this);
1176 return BString(fReplyPreamble);
1180 bool
1181 TMailApp::WrapMode()
1183 BAutolock _(this);
1184 return fWrapMode;
1188 bool
1189 TMailApp::AttachAttributes()
1191 BAutolock _(this);
1192 return fAttachAttributes;
1196 bool
1197 TMailApp::ColoredQuotes()
1199 BAutolock _(this);
1200 return fColoredQuotes;
1204 uint8
1205 TMailApp::ShowToolBar()
1207 BAutolock _(this);
1208 return fShowToolBar;
1212 bool
1213 TMailApp::WarnAboutUnencodableCharacters()
1215 BAutolock _(this);
1216 return fWarnAboutUnencodableCharacters;
1220 bool
1221 TMailApp::StartWithSpellCheckOn()
1223 BAutolock _(this);
1224 return fStartWithSpellCheckOn;
1228 void
1229 TMailApp::SetDefaultAccount(int32 account)
1231 BAutolock _(this);
1232 fDefaultAccount = account;
1236 int32
1237 TMailApp::DefaultAccount()
1239 BAutolock _(this);
1240 return fDefaultAccount;
1244 int32
1245 TMailApp::UseAccountFrom()
1247 BAutolock _(this);
1248 return fUseAccountFrom;
1252 uint32
1253 TMailApp::MailCharacterSet()
1255 BAutolock _(this);
1256 return fMailCharacterSet;
1260 BFont
1261 TMailApp::ContentFont()
1263 BAutolock _(this);
1264 return fContentFont;
1268 // #pragma mark -
1272 main()
1274 tzset();
1276 TMailApp().Run();
1277 return B_OK;