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.
43 #include <sys/utsname.h>
48 #include <CharacterSet.h>
49 #include <CharacterSetRoster.h>
50 #include <Clipboard.h>
53 #include <InterfaceKit.h>
57 #include <StorageKit.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
;
75 #include "Enclosures.h"
77 #include "FindWindow.h"
79 #include "MailSupport.h"
80 #include "MailWindow.h"
83 #include "QueryMenu.h"
84 #include "Signature.h"
87 #include "Utilities.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";
103 BApplication("application/x-vnd.Be-MAIL"),
108 fPrintSettings(NULL
),
109 fPrintHelpAndExit(false),
112 fAttachAttributes(true),
113 fColoredQuotes(true),
115 fWarnAboutUnencodableCharacters(true),
116 fStartWithSpellCheckOn(false),
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 "
141 if (defaultComposeEncoding
!= NULL
)
142 fMailCharacterSet
= defaultComposeEncoding
->GetConversionID();
144 // Find and read settings file.
147 _CheckForSpamFilterExistence();
148 fContentFont
.SetSpacing(B_BITMAP_SPACING
);
149 fLastMailWindowFrame
= fMailWindowFrame
;
153 TMailApp::~TMailApp()
159 TMailApp::ArgvReceived(int32 argc
, char **argv
)
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",
182 fPrintHelpAndExit
= true;
183 be_app
->PostMessage(B_QUIT_REQUESTED
);
186 else if (strncmp(argv
[loop
], "mailto:", 7) == 0)
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;
198 names
+= argv
[loop
] + 7;
201 else if (strncmp(argv
[loop
], "ccto:", 5) == 0)
203 if (ccNames
.Length())
205 ccNames
+= argv
[loop
] + 5;
207 else if (strncmp(argv
[loop
], "bccto:", 6) == 0)
209 if (bccNames
.Length())
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])
217 else if (strncmp(argv
[loop
], "enclosure:", 10) == 0)
219 BEntry
tmp(argv
[loop
] + 10, true);
220 if (tmp
.InitCheck() == B_OK
&& tmp
.Exists())
224 enclosure
.AddRef("refs", &ref
);
227 else if (entry
.SetTo(argv
[loop
]) == B_NO_ERROR
)
229 BMessage
msg(B_REFS_RECEIVED
);
232 msg
.AddRef("refs", &ref
);
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(),
249 TMailApp::MessageReceived(BMessage
*msg
)
251 TMailWindow
*window
= NULL
;
258 msg
->FindInt32("type", &type
);
261 window
= NewWindow();
266 msg
->FindRef("ref", &ref
);
270 if (file
.InitCheck() == B_OK
)
271 file
.ReadAttrString(B_MAIL_ATTR_TO
, &string
);
273 window
= NewWindow(&ref
, string
.String(), true);
277 case M_FORWARD_WITHOUT_ATTACHMENTS
:
279 TMailWindow
*sourceWindow
;
280 if (msg
->FindPointer("window", (void **)&sourceWindow
) < B_OK
281 || !sourceWindow
->Lock())
284 msg
->FindRef("ref", &ref
);
285 window
= NewWindow();
286 if (window
->Lock()) {
287 window
->Forward(&ref
, sourceWindow
, type
== M_FORWARD
);
290 sourceWindow
->Unlock();
295 case M_REPLY_TO_SENDER
:
299 TMailWindow
*sourceWindow
;
300 if (msg
->FindPointer("window", (void **)&sourceWindow
) < B_OK
301 || !sourceWindow
->Lock())
303 msg
->FindRef("ref", &ref
);
304 window
= NewWindow();
305 if (window
->Lock()) {
306 if (type
== M_COPY_TO_NEW
)
307 window
->CopyMessage(&ref
, sourceWindow
);
309 window
->Reply(&ref
, sourceWindow
, type
);
312 sourceWindow
->Unlock();
323 fPrefsWindow
->Activate(true);
325 fPrefsWindow
= new TPrefsWindow(fPrefsWindowPos
,
326 &fContentFont
, NULL
, &fWrapMode
, &fAttachAttributes
,
327 &fColoredQuotes
, &fDefaultAccount
, &fUseAccountFrom
,
328 &fReplyPreamble
, &fSignature
, &fMailCharacterSet
,
329 &fWarnAboutUnencodableCharacters
,
330 &fStartWithSpellCheckOn
, &fAutoMarkRead
,
332 if (fPrefsWindowPos
.x
<= 0 || fPrefsWindowPos
.y
<= 0) {
333 TMailWindow
* window
= _ActiveWindow();
335 fPrefsWindow
->CenterIn(window
->Frame());
337 fPrefsWindow
->CenterOnScreen();
339 fPrefsWindow
->MoveOnScreen();
340 fPrefsWindow
->Show();
346 // Notify all Mail windows
347 for (int32 i
= 0; i
< fWindowList
.CountItems(); i
++) {
348 TMailWindow
* window
= (TMailWindow
*)fWindowList
.ItemAt(i
);
350 window
->UpdatePreferences();
351 window
->UpdateViews();
358 be_roster
->Launch("application/x-vnd.Haiku-Mail");
361 case M_EDIT_SIGNATURE
:
362 if (fSigWindow
!= NULL
)
363 fSigWindow
->Activate(true);
365 fSigWindow
= new TSignatureWindow(fSignatureWindowFrame
);
366 if (!fSignatureWindowFrame
.IsValid()) {
367 TMailWindow
* window
= _ActiveWindow();
369 fSigWindow
->CenterIn(window
->Frame());
371 fSigWindow
->CenterOnScreen();
373 fSigWindow
->MoveOnScreen();
383 if (msg
->HasPointer("window")) {
384 msg
->FindPointer("window", (void**)&window
);
385 BMessage
message(*msg
);
386 window
->PostMessage(&message
, window
);
391 switch (msg
->FindInt32("kind")) {
395 if( msg
->FindPointer("window", (void**)&window
) == B_OK
)
396 fWindowList
.RemoveItem(window
);
403 msg
->FindPoint("window pos", &fPrefsWindowPos
);
408 msg
->FindRect("window frame", &fSignatureWindowFrame
);
412 if (!fWindowCount
&& !fSigWindow
&& !fPrefsWindow
)
413 be_app
->PostMessage(B_QUIT_REQUESTED
);
416 case B_REFS_RECEIVED
:
420 case B_PRINTER_CHANGED
:
421 _ClearPrintSettings();
425 BApplication::MessageReceived(msg
);
431 TMailApp::QuitRequested()
433 if (!BApplication::QuitRequested())
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
);
461 TMailApp::ReadyToRun()
463 // Create needed indices for META:group, META:email, MAIL:draft,
464 // INDEX_SIGNATURE, INDEX_STATUS on the boot 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=**");
482 BPath userDictionaryDir
;
486 BDirectory directory
;
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
);
527 while ((size
= words
.Read( buffer
, 4096)) > 0)
528 copy
.Write(buffer
, size
);
529 BNodeInfo(©
).SetType("text/plain");
533 directory
.SetTo(dictionaryDir
.Path());
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);
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);
584 // Create a new window if starting up without any extra arguments.
586 if (!fPrintHelpAndExit
&& !fWindowCount
) {
588 window
= NewWindow();
595 TMailApp::RefsReceived(BMessage
*msg
)
597 bool have_names
= false;
599 char type
[B_FILE_NAME_LENGTH
];
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);
617 file
.SetTo(&ref
, O_RDONLY
);
618 if (file
.InitCheck() == B_NO_ERROR
) {
619 BNodeInfo
node(&file
);
621 if (strcmp(type
, B_MAIL_TYPE
) == 0
622 || strcmp(type
, B_PARTIAL_MAIL_TYPE
) == 0) {
623 window
= NewWindow(&ref
, NULL
, false, &messenger
);
625 } else if(strcmp(type
, "application/x-person") == 0) {
626 /* Got a People contact info file, see if it has an Email address. */
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.
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
<< "\" ";
652 if (names
.Length() == 0) {
653 names
<< name
<< email
;
655 names
<< ", " << name
<< email
;
663 else if (strcmp(type
, kDraftType
) == 0) {
664 window
= NewWindow();
666 // If it's a draft message, open it
667 window
->OpenMessage(&ref
);
670 } /* end of else(file.InitCheck() == B_NO_ERROR */
675 window
= NewWindow(NULL
, names
.String());
682 TMailApp::FindWindow(const entry_ref
&ref
)
685 if (entry
.InitCheck() < B_OK
)
689 if (entry
.GetNodeRef(&nodeRef
) < B_OK
)
694 while ((window
= WindowAt(index
++)) != NULL
) {
695 TMailWindow
*mailWindow
= dynamic_cast<TMailWindow
*>(window
);
696 if (mailWindow
== NULL
)
699 node_ref mailNodeRef
;
700 if (mailWindow
->GetMailNodeRef(mailNodeRef
) == B_OK
701 && mailNodeRef
== nodeRef
)
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
;
719 BEntry settingsEntry
;
721 BMessage settingsMessage
;
723 fShowSpamGUI
= false;
725 if (find_directory(B_USER_SETTINGS_DIRECTORY
, &path
) != B_OK
)
727 // TODO use new settings
728 path
.Append("Mail/chains/inbound");
729 if (inChainDir
.SetTo(path
.Path()) != B_OK
)
732 while (inChainDir
.GetNextEntry (&settingsEntry
, true /* traverse */) == B_OK
) {
733 if (!settingsEntry
.IsFile())
735 if (settingsFile
.SetTo (&settingsEntry
, B_READ_ONLY
) != B_OK
)
737 if (settingsMessage
.Unflatten (&settingsFile
) != B_OK
)
739 for (addonNameIndex
= 0; B_OK
== settingsMessage
.FindString (
740 "filter_addons", addonNameIndex
, &addonNamePntr
);
742 if (strstr (addonNamePntr
, "Spam Filter") != NULL
) {
743 fShowSpamGUI
= true; // Found it!
752 TMailApp::_ActiveWindow()
754 for (int32 i
= 0; i
< fWindowList
.CountItems(); i
++) {
755 TMailWindow
* window
= (TMailWindow
*)fWindowList
.ItemAt(i
);
756 if (window
->IsActive())
764 TMailApp::SetPrintSettings(const BMessage
* printSettings
)
768 if (printSettings
== fPrintSettings
)
771 delete fPrintSettings
;
773 fPrintSettings
= new BMessage(*printSettings
);
775 fPrintSettings
= NULL
;
780 TMailApp::HasPrintSettings()
783 return fPrintSettings
!= NULL
;
788 TMailApp::PrintSettings()
791 return BMessage(*fPrintSettings
);
796 TMailApp::_ClearPrintSettings()
798 delete fPrintSettings
;
799 fPrintSettings
= NULL
;
804 TMailApp::SetLastWindowFrame(BRect frame
)
807 fLastMailWindowFrame
= frame
;
812 TMailApp::GetSettingsPath(BPath
&path
)
814 status_t status
= find_directory(B_USER_SETTINGS_DIRECTORY
, &path
);
819 return create_directory(path
.Path(), 0755);
824 TMailApp::LoadOldSettings()
827 status_t status
= find_directory(B_USER_SETTINGS_DIRECTORY
, &path
);
831 path
.Append("Mail_data");
834 status
= file
.SetTo(path
.Path(), B_READ_ONLY
);
838 file
.Read(&fMailWindowFrame
, sizeof(BRect
));
839 // file.Read(&level, sizeof(level));
841 font_family fontFamily
;
842 font_style fontStyle
;
844 file
.Read(&fontFamily
, sizeof(font_family
));
845 file
.Read(&fontStyle
, sizeof(font_style
));
846 file
.Read(&size
, sizeof(float));
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
));
859 if (file
.Read(&length
, sizeof(int32
)) < (ssize_t
)sizeof(int32
))
866 fSignature
= (char *)malloc(length
);
867 if (fSignature
== NULL
)
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
)
884 file
.Read(findString
, length
);
885 findString
[length
] = '\0';
886 FindWindow::SetFindString(findString
);
889 if (file
.Read(&fShowToolBar
, sizeof(uint8
)) < (ssize_t
)sizeof(uint8
))
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
)
904 file
.Read(fReplyPreamble
, length
);
905 fReplyPreamble
[length
] = '\0';
908 file
.Read(&fAttachAttributes
, sizeof(bool));
909 file
.Read(&fWarnAboutUnencodableCharacters
, sizeof(bool));
916 TMailApp::SaveSettings()
918 BMailSettings accountSettings
;
920 if (fDefaultAccount
!= ~0L) {
921 accountSettings
.SetDefaultOutboundAccount(fDefaultAccount
);
922 accountSettings
.Save();
926 status_t status
= GetSettingsPath(path
);
930 path
.Append("BeMail Settings~");
933 status
= file
.SetTo(path
.Path(), B_READ_WRITE
| B_CREATE_FILE
| B_ERASE_FILE
);
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
);
965 status
= entry
.SetTo(path
.Path());
969 status
= settings
.Flatten(&file
);
970 if (status
== B_OK
) {
971 // replace original settings file
972 status
= entry
.Rename("BeMail Settings", true);
981 TMailApp::LoadSettings()
983 BMailSettings accountSettings
;
984 fDefaultAccount
= accountSettings
.DefaultOutboundAccount();
987 status_t status
= GetSettingsPath(path
);
991 path
.Append("BeMail Settings");
994 status
= file
.SetTo(path
.Path(), B_READ_ONLY
);
996 return LoadOldSettings();
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();
1006 if (settings
.FindRect("MailWindowSize", &rect
) == B_OK
)
1007 fMailWindowFrame
= rect
;
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
) {
1018 if (settings
.FindFloat("FontSize", &size
) == B_OK
) {
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
;
1034 if (settings
.FindBool("WordWrapMode", &boolValue
) == B_OK
)
1035 fWrapMode
= boolValue
;
1038 if (settings
.FindPoint("PreferencesWindowLocation", &point
) == B_OK
)
1039 fPrefsWindowPos
= point
;
1041 if (settings
.FindBool("AutoMarkRead", &boolValue
) == B_OK
)
1042 fAutoMarkRead
= boolValue
;
1045 if (settings
.FindString("SignatureText", &string
) == B_OK
) {
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
);
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
;
1092 TMailApp::FontChange()
1098 msg
.what
= CHANGE_FONT
;
1099 msg
.AddPointer("font", &fContentFont
);
1102 window
= WindowAt(index
++);
1106 window
->PostMessage(&msg
);
1112 TMailApp::NewWindow(const entry_ref
* ref
, const char* to
, bool resend
,
1113 BMessenger
* trackerMessenger
)
1115 float fontFactor
= be_plain_font
->Size() / 12.0f
;
1117 if (fMailWindowFrame
.Width() < 64 || fMailWindowFrame
.Height() < 20) {
1119 r
.Set(40 * fontFactor
, 40 * fontFactor
, fontFactor
* (40 + WIND_WIDTH
),
1120 fontFactor
* (40 + WIND_HEIGHT
));
1122 r
= fMailWindowFrame
;
1124 // cascading windows
1125 r
.OffsetBy(fontFactor
* (((fWindowCount
+ 5) % 10) * 15 - 75),
1126 fontFactor
* (((fWindowCount
+ 5) % 10) * 15 - 75));
1132 if (!resend
&& ref
&& file
.SetTo(ref
, O_RDONLY
) == B_OK
) {
1134 if (file
.ReadAttrString(B_MAIL_ATTR_NAME
, &name
) == B_OK
) {
1137 if (file
.ReadAttrString(B_MAIL_ATTR_SUBJECT
, &subject
) == B_OK
)
1138 title
<< " -> " << subject
;
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();
1153 // #pragma mark - settings
1157 TMailApp::AutoMarkRead()
1160 return fAutoMarkRead
;
1165 TMailApp::Signature()
1168 return BString(fSignature
);
1173 TMailApp::ReplyPreamble()
1176 return BString(fReplyPreamble
);
1181 TMailApp::WrapMode()
1189 TMailApp::AttachAttributes()
1192 return fAttachAttributes
;
1197 TMailApp::ColoredQuotes()
1200 return fColoredQuotes
;
1205 TMailApp::ShowToolBar()
1208 return fShowToolBar
;
1213 TMailApp::WarnAboutUnencodableCharacters()
1216 return fWarnAboutUnencodableCharacters
;
1221 TMailApp::StartWithSpellCheckOn()
1224 return fStartWithSpellCheckOn
;
1229 TMailApp::SetDefaultAccount(int32 account
)
1232 fDefaultAccount
= account
;
1237 TMailApp::DefaultAccount()
1240 return fDefaultAccount
;
1245 TMailApp::UseAccountFrom()
1248 return fUseAccountFrom
;
1253 TMailApp::MailCharacterSet()
1256 return fMailCharacterSet
;
1261 TMailApp::ContentFont()
1264 return fContentFont
;