From 1af4fa4ba62ba7e49fc47d60a3a89083b6f51c6f Mon Sep 17 00:00:00 2001 From: Clemens Zeidler Date: Wed, 9 Feb 2011 01:49:01 +0000 Subject: [PATCH] Major restructuring of the mail server: Accounts are now stored in a separate file. Previously they where somehow magically assembled from the chain ids. Now its possible to remove a account temporary by removing the account file form the account folder. Each account could have an inbound protocol, an outbound protocol and some filters. Mails are now associated with an account and not with a chain. This required to replace the chain id attribute by an account attribute. Replace BMailFilter and BMailChain by a less general approach. Basically the chain had a list of filters and call the ProcessMailMessage for each filter. This made it sometime difficult to understand what is going on, e.g. sometimes a filter used information gathered by another filters. The new MailProtocol and MailFilter classes are calling more dedicated hook functions, e.g. HeaderFetched or MessageReadyToSend. As before all MailProtocol's (plus their filters) are running in their own thread. Cleaned up the error and status window a bit. Abstracted the interface to these windows. Should be easy to write a BNotification api back-end now. Parsing of mail headers is much faster now. Fetching the headers of a large mailbox takes ~min and not ~hour now! Initial checkout time is in the same order like Opera. The problem was the massive use of fgets in parse_header (mail_util.cpp) now the complete header is read in one go. Furthermore, only interesting fields are extracted. Remove some unused files, BeOS relicts... Feel free to translate the mail server and remove the own language system (headers/private/mail/MDRLanguage.h). Sorry for the remaining old (and new) coding style issues, sometime just ignore them, to many :( git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40397 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- build/jam/HaikuImage | 4 +- headers/os/add-ons/mail_daemon/ChainRunner.h | 98 -- headers/os/add-ons/mail_daemon/MailAddon.h | 111 +- headers/os/add-ons/mail_daemon/MailProtocol.h | 308 +++-- .../add-ons/mail_daemon/ProtocolConfigView.h | 67 +- .../mail_daemon/RemoteStorageProtocol.h | 41 - headers/os/mail/E-mail.h | 21 - headers/os/mail/MailDaemon.h | 40 +- headers/os/mail/MailMessage.h | 7 +- headers/os/mail/MailSettings.h | 291 +++-- headers/private/mail/FileConfigView.h | 4 +- headers/private/mail/crypt.h | 2 +- headers/private/mail/mail_util.h | 2 + src/kits/mail/ChainRunner.cpp | 610 --------- src/kits/mail/FileConfigView.cpp | 2 +- src/kits/mail/HaikuMailFormatFilter.cpp | 204 +++ src/kits/mail/HaikuMailFormatFilter.h | 35 + src/kits/mail/Jamfile | 19 +- src/kits/mail/MailAddon.cpp | 27 - src/kits/mail/MailChain.cpp | 512 -------- src/kits/mail/MailDaemon.cpp | 98 +- src/kits/mail/MailMessage.cpp | 90 +- src/kits/mail/MailProtocol.cpp | 1118 ++++++++++------- src/kits/mail/MailSettings.cpp | 659 ++++++++-- src/kits/mail/ProtocolConfigView.cpp | 124 +- src/kits/mail/RemoteStorageProtocol.cpp | 438 ------- src/kits/mail/b_mail_message.cpp | 138 -- src/kits/mail/c_mail_api.cpp | 141 --- src/kits/mail/cpp_abi_base64.c | 28 - src/kits/mail/crypt.cpp | 2 +- src/kits/mail/mail_util.cpp | 50 + src/servers/mail/DeskbarView.cpp | 34 +- src/{kits => servers}/mail/ErrorLogWindow.cpp | 42 +- src/{kits => servers}/mail/ErrorLogWindow.h | 5 +- src/servers/mail/Jamfile | 4 + src/servers/mail/MailDaemon.cpp | 860 +++++++++++++ src/servers/mail/MailDaemon.h | 114 ++ src/servers/mail/Notifier.cpp | 99 ++ src/servers/mail/Notifier.h | 44 + src/{kits => servers}/mail/StatusWindow.cpp | 119 +- .../servers/mail/StatusWindow.h | 47 +- src/servers/mail/main.cpp | 795 +----------- 42 files changed, 3498 insertions(+), 3956 deletions(-) delete mode 100644 headers/os/add-ons/mail_daemon/ChainRunner.h delete mode 100644 headers/os/add-ons/mail_daemon/RemoteStorageProtocol.h delete mode 100644 src/kits/mail/ChainRunner.cpp create mode 100644 src/kits/mail/HaikuMailFormatFilter.cpp create mode 100644 src/kits/mail/HaikuMailFormatFilter.h delete mode 100644 src/kits/mail/MailAddon.cpp delete mode 100644 src/kits/mail/MailChain.cpp delete mode 100644 src/kits/mail/RemoteStorageProtocol.cpp delete mode 100644 src/kits/mail/b_mail_message.cpp delete mode 100644 src/kits/mail/c_mail_api.cpp delete mode 100644 src/kits/mail/cpp_abi_base64.c rename src/{kits => servers}/mail/ErrorLogWindow.cpp (84%) rename src/{kits => servers}/mail/ErrorLogWindow.h (92%) create mode 100644 src/servers/mail/MailDaemon.cpp create mode 100644 src/servers/mail/MailDaemon.h create mode 100644 src/servers/mail/Notifier.cpp create mode 100644 src/servers/mail/Notifier.h rename src/{kits => servers}/mail/StatusWindow.cpp (82%) rename headers/private/mail/status.h => src/servers/mail/StatusWindow.h (60%) diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 0089971c21..c4c5cdced2 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -524,10 +524,8 @@ AddFilesToHaikuHybridImage system add-ons locale catalogs AddFilesToHaikuImage system add-ons mail_daemon inbound_protocols : POP3 IMAP ; AddFilesToHaikuImage system add-ons mail_daemon outbound_protocols : SMTP ; AddFilesToHaikuImage system add-ons mail_daemon inbound_filters - : Match\ Header Spam\ Filter R5\ Daemon\ Filter ; + : MatchHeader SpamFilter NewMailNotification ; AddFilesToHaikuImage system add-ons mail_daemon outbound_filters : Fortune ; -AddFilesToHaikuImage system add-ons mail_daemon system_filters - : Inbox New\ mail\ notification Outbox Message\ Parser ; AddFilesToHaikuImage system add-ons media : $(SYSTEM_ADD_ONS_MEDIA) ; AddFilesToHaikuImage system add-ons media plugins : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ; diff --git a/headers/os/add-ons/mail_daemon/ChainRunner.h b/headers/os/add-ons/mail_daemon/ChainRunner.h deleted file mode 100644 index 91ea4ebd34..0000000000 --- a/headers/os/add-ons/mail_daemon/ChainRunner.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef ZOIDBERG_MAIL_CHAIN_RUNNER_H -#define ZOIDBERG_MAIL_CHAIN_RUNNER_H -/* ChainRunner - runs the mail inbound and outbound chains -** -** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. -*/ - - -#include -#include -#include - -class BStringList; -class BMailStatusWindow; -class BMailStatusView; -class BMailChain; - -class BMailChainCallback { - public: - virtual void Callback(status_t result) = 0; - // Called by the callback routines in ChainRunner - // result is the message that ended the chain - // (MD_HANDLED, MD_DISCARD, MD_NO_MORE_MESSAGES) - // Obviously, for process callbacks, result is - // gauranteed to be MD_NO_MORE_MESSAGES. -}; - -class BMailChainRunner : public BLooper { - public: - BMailChainRunner(BMailChain *chain, BMailStatusWindow *status, - bool self_destruct_when_done = true, bool save_chain_when_done = false, - bool destruct_chain_when_done = false); - ~BMailChainRunner(); - - //----Callback functions. Callback objects will be deleted for you. - - void RegisterMessageCallback(BMailChainCallback *callback); - // Your callback->Callback() function will be called when - // the current message is done being processed. - - void RegisterProcessCallback(BMailChainCallback *callback); - // Your callback->Callback() function will be called when - // a filter returns MD_PASS_COMPLETE and before we go back - // to waiting for new messages, or when the fetch list - // runs out. - - void RegisterChainCallback(BMailChainCallback *callback); - // Your callback->Callback() function will be called when - // a filter returns MD_ALL_PASSES_DONE and before everything - // is unloaded and sent home. - - void Stop(bool immediately = false); - void ReportProgress(int bytes, int messages, const char *message = NULL); - void ResetProgress(const char *message = NULL); - - void GetMessages(BStringList *list, int32 bytes); - void GetSingleMessage(const char *uid, int32 length, BPath *into); - // The bytes or length field is the total size, used for updating the - // progress bar. Use -1 for unknown maximum size. - - bool QuitRequested(); - - void ShowError(const char *error); - void ShowMessage(const char *message); - - BMailChain *Chain(); - - //----The big, bad asynchronous RunChain() function. Pretty harmless looking, huh? - status_t RunChain(bool asynchronous = true); - - void MessageReceived (BMessage *msg); - - private: - void CallCallbacksFor(BList &list, status_t code); - void get_messages(BStringList *list); - status_t Init(); - #if USE_NASTY_SYNC_THREAD_HACK - static int32 thread_sync_func(void *arg); - status_t init_addons(); - #endif - - BMailChain *_chain; - BList message_cb, process_cb, chain_cb; - - bool destroy_self, destroy_chain, save_chain; - - BMailStatusWindow *_status; - BMailStatusView *_statview; - BList addons; - - bool suicide; - uint8 _other_reserved[3]; - uint32 _reserved[4]; -}; - -BMailChainRunner *GetMailChainRunner(int32 chain_id, BMailStatusWindow *status, bool selfDestruct = true); - -#endif /* ZOIDBERG_MAIL_CHAIN_RUNNER_H */ diff --git a/headers/os/add-ons/mail_daemon/MailAddon.h b/headers/os/add-ons/mail_daemon/MailAddon.h index abe3f80cbb..eaf816dbaa 100644 --- a/headers/os/add-ons/mail_daemon/MailAddon.h +++ b/headers/os/add-ons/mail_daemon/MailAddon.h @@ -1,116 +1,39 @@ -#ifndef ZOIDBERG_MAIL_ADDON_H -#define ZOIDBERG_MAIL_ADDON_H /* Filter - the base class for all mail filters ** ** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. */ +#ifndef ZOIDBERG_MAIL_ADDON_H +#define ZOIDBERG_MAIL_ADDON_H + + +#include "MailProtocol.h" +#include "MailSettings.h" -class BMessage; class BView; -class BPositionIO; -class BEntry; -class BPath; -class BView; -class BString; -class BPositionIO; -class BEntry; - -enum { - B_MAIL_DISCARD = B_MAIL_ERROR_BASE + 8, - //--- This terminates the chain and removes the message being processed - // both from disk and from the server. - B_MAIL_END_FETCH, - //--- Terminates the current operation - B_MAIL_END_CHAIN - //--- This is for yikes errors, like an unreachable server. -}; - -class BMailStatusView; -class BMailChainRunner; - -class BMailFilter -{ - public: - BMailFilter(BMessage* settings); - // How to support queueing messages until a time of the - // day/week/month/year? The settings will contain a - // persistent ChainID field, the same for all Filters - // on the same "chain". - - virtual ~BMailFilter(); - // This will be called when the settings for this Filter - // are changed, or there are no new messages to consume - // after settings->FindInt32("timeout") seconds. - - virtual status_t InitCheck(BString* out_message = NULL) = 0; - // Returns B_OK if the Filter was constructed success- - // fully. Otherwise it returns an error code. If it is - // passed a valid BString*, it may add an error message - // to the end of that BString iff it returns an error. - // If it returns an error code then the MailFilter will - // probably be deleted and the error shown to the user. - - virtual status_t ProcessMailMessage - ( - BPositionIO** io_message, BEntry* io_entry, - BMessage* io_headers, BPath* io_folder, const char *io_uid - ) = 0; - // Filters a message. On input and output, the arguments - // are expected to be as below; however it is allowed for - // the MailFilter to alter any of these values as nece- - // ssary, so long as the constraints are as described when - // the function returns: - // - // * io_message - a PositionIO that contains the message - // data, pointing to the first byte of the message's - // header. This can be swapped if, eg, the message - // is copied across volume boundries. When the chain - // begins this is a file in /tmp. - // * io_entry - The entry for the PositionIO above. - // * io_headers - a list of attributes that will be added - // to the message file. - // * io_folder - The message's "folder"---may be com- - // pletely unrelated to its on-disk Entry. - // * io_uid - The unique ID provided by the message's - // Protocol - // - // At most one Filter::ProcessMailMessage() for a given - // chain (and thus ChainID) will be called at a time. - - private: - virtual void _ReservedFilter1(); - virtual void _ReservedFilter2(); - virtual void _ReservedFilter3(); - virtual void _ReservedFilter4(); -}; // // The addon interface: export instantiate_mailfilter() // and instantiate_mailconfig() to create a Filter addon // -extern "C" _EXPORT BView* instantiate_config_panel(BMessage *settings,BMessage *metadata); -// return a view that configures the MailProtocol or MailFilter +extern "C" _EXPORT InboundProtocol* instantiate_inbound_protocol( + BMailAccountSettings* settings); +extern "C" _EXPORT OutboundProtocol* instantiate_outbound_protocol( + BMailAccountSettings* settings); +extern "C" _EXPORT BView* instantiate_config_panel(MailAddonSettings&, + BMailAccountSettings&); +// return a view that configures the MailProtocol // returned by the functions below. BView::Archive(foo,true) // produces this addon's settings, which are passed to the in- // stantiate_* functions and stored persistently. This function // should gracefully handle empty and NULL settings. -// A note on the metadata argument: The metadata pointer is -// guaranteed to remain valid as long as this view exists. As it is -// a pointer to the chain's metadata, your view can save any -// chain-global settings to it in its Archive() function. Note that -// you must cache this pointer yourself! You will never get it again. -// Also note that it is possible for it to be NULL. -extern "C" _EXPORT BMailFilter* instantiate_mailfilter(BMessage *settings, - BMailChainRunner *runner); -// Return a MailProtocol or MailFilter ready to do its thing, -// based on settings produced by archiving your config panel. -// Note that a Mail::Protocol is a Mail::Filter, so use -// instantiate_mailfilter to start things up. +extern "C" _EXPORT BView* instantiate_filter_config_panel(AddonSettings&); +extern "C" _EXPORT MailFilter* instantiate_mailfilter(MailProtocol& protocol, + AddonSettings* settings); -extern "C" _EXPORT status_t descriptive_name(BMessage *msg, char *buffer); +extern "C" _EXPORT BString descriptive_name(); // the config panel will show this name in the chains filter // list if this function returns B_OK. // The buffer is as big as B_FILE_NAME_LENGTH. diff --git a/headers/os/add-ons/mail_daemon/MailProtocol.h b/headers/os/add-ons/mail_daemon/MailProtocol.h index c150435e38..547738cf3e 100644 --- a/headers/os/add-ons/mail_daemon/MailProtocol.h +++ b/headers/os/add-ons/mail_daemon/MailProtocol.h @@ -1,107 +1,225 @@ -#ifndef ZOIDBERG_MAIL_PROTOCOL_H -#define ZOIDBERG_MAIL_PROTOCOL_H /* Protocol - the base class for protocol filters -** -** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. + * + * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. + * Copyright 2011 Clemens Zeidler. All rights reserved. */ +#ifndef MAIL_PROTOCOL_H +#define MAIL_PROTOCOL_H +#include +#include + +#include +#include #include +#include +#include +#include -#include +#include -class BHandler; -class BStringList; -class BMailChainRunner; +class MailNotifier { +public: + virtual ~MailNotifier() {} -class BMailProtocol : public BMailFilter -{ - public: - BMailProtocol(BMessage* settings, BMailChainRunner *runner); - // Open a connection based on 'settings'. 'settings' will - // contain a persistent uint32 ChainID field. At most one - // Protocol per ChainID will exist at a given time. - // The constructor of Mail::Protocol initializes manifest. - // It is your responsibility to fill in unique_ids, *and - // to keep it updated* in the course of whatever nefarious - // things your protocol does. - - virtual ~BMailProtocol(); - // Close the connection and clean up. This will be cal- - // led after FetchMessage() or FetchNewMessage() returns - // B_TIMED_OUT or B_ERROR, or when the settings for this - // Protocol are changed. - - virtual status_t GetMessage( - const char* uid, - BPositionIO** out_file, BMessage* out_headers, - BPath* out_folder_location - )=0; - // Downloads the message with id uid, writing the message's - // RFC2822 contents to *out_file and storing any headers it - // wants to add other than those from the message itself into - // out_headers. It may store a path (if this type of account - // supports folders) in *out_folder_location. - // - // Returns B_OK if the message is now available in out_file, - // B_NAME_NOT_FOUND if there is no message with id 'uid' on - // the server, or another error if the connection failed. - // - // B_OK will cause the message to be stored and processed. - // B_NAME_NOT_FOUND will cause appropriate recovery to be - // taken (if such exists) but not cause the connection to - // be terminated. Any other error will cause anything writen - // to be discarded and and the connection closed. - - // OBS: - // The Protocol may replace *out_file with a custom (read- - // only) BPositionIO-derived object that preserves the il- - // lusion that the message is writen to *out_file, but in - // fact only reads from the server and writes to *out_file - // on demand. This BPositionIO must guarantee that any - // data returned by Read() has also been writen to *out_- - // file. It must return a read error if reading from the - // network or writing to *out_file fails. - // - // The mail_daemon will delete *out_file before invoking - // FetchMessage() or FetchNewMessage() again. - - virtual status_t DeleteMessage(const char* uid)=0; - // Removes the message from the server. After this, it's - // assumed (but not required) that GetMessage(uid,...) - // et al will fail with B_NAME_NOT_FOUND. - - void CheckForDeletedMessages(); - // You can call this to trigger a sweep for deleted messages. - // Automatically called at the beginning of the chain. - - //------MailFilter calls - virtual status_t ProcessMailMessage - ( - BPositionIO** io_message, BEntry* io_entry, - BMessage* io_headers, BPath* io_folder, const char* io_uid - ); - - protected: - BStringList *manifest, *unique_ids; - BMessage *settings; - - BMailChainRunner *runner; - private: - inline void error_alert(const char *process, status_t error); - virtual void _ReservedProtocol1(); - virtual void _ReservedProtocol2(); - virtual void _ReservedProtocol3(); - virtual void _ReservedProtocol4(); - virtual void _ReservedProtocol5(); + virtual MailNotifier* Clone() = 0; - friend class DeletePass; - - BHandler *trash_monitor; - BStringList *uids_on_disk; - - uint32 _reserved[3]; + virtual void ShowError(const char* error) = 0; + virtual void ShowMessage(const char* message) = 0; + + virtual void SetTotalItems(int32 items) = 0; + virtual void SetTotalItemsSize(int32 size) = 0; + virtual void ReportProgress(int bytes, int messages, + const char* message = NULL) = 0; + virtual void ResetProgress(const char* message = NULL) = 0; }; -#endif // ZOIDBERG_MAIL_PROTOCOL_H + +class MailProtocol; + + +class MailFilter { +public: + MailFilter(MailProtocol& protocol, + AddonSettings* settings); + virtual ~MailFilter(); + + //! Message hooks if filter is installed to a inbound protocol + virtual void HeaderFetched(const entry_ref& ref, + BFile* file); + virtual void BodyFetched(const entry_ref& ref, BFile* file); + virtual void MailboxSynced(status_t status); + + //! Message hooks if filter is installed to a outbound protocol + virtual void MessageReadyToSend(const entry_ref& ref, + BFile* file); + virtual void MessageSent(const entry_ref& ref, + BFile* file); +protected: + MailProtocol& fMailProtocol; + AddonSettings* fAddonSettings; +}; + + +class MailProtocolThread; + + +class MailProtocol { +public: + MailProtocol(BMailAccountSettings* settings); + virtual ~MailProtocol(); + + virtual void SetStopNow() {} + + BMailAccountSettings& AccountSettings(); + + void SetProtocolThread( + MailProtocolThread* protocolThread); + virtual void AddedToLooper() {} + MailProtocolThread* Looper(); + /*! Add handler to the handler list. The handler is installed / + removed to the according BLooper automatically. */ + bool AddHandler(BHandler* handler); + //! Does not delete handler + bool RemoveHandler(BHandler* handler); + + void SetMailNotifier(MailNotifier* mailNotifier); + + virtual void ShowError(const char* error); + virtual void ShowMessage(const char* message); + virtual void SetTotalItems(int32 items); + virtual void SetTotalItemsSize(int32 size); + virtual void ReportProgress(int bytes, int messages, + const char* message = NULL); + virtual void ResetProgress(const char* message = NULL); + + //! MailProtocol takes ownership of the filters + bool AddFilter(MailFilter* filter); + int32 CountFilter(); + MailFilter* FilterAt(int32 index); + MailFilter* RemoveFilter(int32 index); + bool RemoveFilter(MailFilter* filter); + + void NotifyNewMessagesToFetch(int32 nMessages); + void NotifyHeaderFetched(const entry_ref& ref, + BFile* mail); + void NotifyBodyFetched(const entry_ref& ref, + BFile* mail); + void NotifyMessageReadyToSend(const entry_ref& ref, + BFile* mail); + void NotifyMessageSent(const entry_ref& ref, + BFile* mail); + + //! mail storage operations + virtual status_t MoveMessage(const entry_ref& ref, + BDirectory& dir); + virtual status_t DeleteMessage(const entry_ref& ref); + + virtual void FileRenamed(const entry_ref& from, + const entry_ref& to); + virtual void FileDeleted(const node_ref& node); + +protected: + void LoadFilters(MailAddonSettings& settings); + + BMailAccountSettings fAccountSettings; + MailNotifier* fMailNotifier; + +private: + MailFilter* _LoadFilter(AddonSettings* filterSettings); + + MailProtocolThread* fProtocolThread; + BObjectList fHandlerList; + BObjectList fFilterList; + std::map fFilterImages; +}; + + +class InboundProtocol : public MailProtocol { +public: + InboundProtocol(BMailAccountSettings* settings); + virtual ~InboundProtocol(); + + virtual status_t SyncMessages() = 0; + virtual status_t FetchBody(const entry_ref& ref) = 0; + virtual status_t MarkMessageAsRead(const entry_ref& ref, + bool read = true); + virtual status_t DeleteMessage(const entry_ref& ref) = 0; + virtual status_t AppendMessage(const entry_ref& ref); +}; + + +class OutboundProtocol : public MailProtocol { +public: + OutboundProtocol( + BMailAccountSettings* settings); + virtual ~OutboundProtocol(); + + virtual status_t SendMessages(const std::vector& + mails, size_t totalBytes) = 0; +}; + + +class MailProtocolThread : public BLooper { +public: + MailProtocolThread(MailProtocol* protocol); + virtual void MessageReceived(BMessage* message); + + MailProtocol* Protocol() { return fMailProtocol; } + + void SetStopNow(); + /*! These function post a message to the loop to trigger the action. + */ + void TriggerFileMove(const entry_ref& ref, + BDirectory& dir); + void TriggerFileDeletion(const entry_ref& ref); + + void TriggerFileRenamed(const entry_ref& from, + const entry_ref& to); + void TriggerFileDeleted(const node_ref& node); +private: + MailProtocol* fMailProtocol; +}; + + +class InboundProtocolThread : public MailProtocolThread { +public: + InboundProtocolThread( + InboundProtocol* protocol); + ~InboundProtocolThread(); + + void MessageReceived(BMessage* message); + + void SyncMessages(); + void FetchBody(const entry_ref& ref, + bool launch = false); + void MarkMessageAsRead(const entry_ref& ref, + bool read = true); + void DeleteMessage(const entry_ref& ref); + void AppendMessage(const entry_ref& ref); +private: + void _NotiyMailboxSynced(status_t status); + + InboundProtocol* fProtocol; +}; + + +class OutboundProtocolThread : public MailProtocolThread { +public: + OutboundProtocolThread( + OutboundProtocol* protocol); + ~OutboundProtocolThread(); + + void MessageReceived(BMessage* message); + + void SendMessages(const std::vector& + mails, size_t totalBytes); + +private: + OutboundProtocol* fProtocol; +}; + + +#endif // MAIL_PROTOCOL_H diff --git a/headers/os/add-ons/mail_daemon/ProtocolConfigView.h b/headers/os/add-ons/mail_daemon/ProtocolConfigView.h index aa36e67fb9..045c257f5d 100644 --- a/headers/os/add-ons/mail_daemon/ProtocolConfigView.h +++ b/headers/os/add-ons/mail_daemon/ProtocolConfigView.h @@ -1,38 +1,69 @@ -#ifndef ZOIDBERG_PROTOCOL_CONFIG_VIEW_H -#define ZOIDBERG_PROTOCOL_CONFIG_VIEW_H /* ProtocolConfigView - the standard config view for all protocols ** ** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. */ +#ifndef ZOIDBERG_PROTOCOL_CONFIG_VIEW_H +#define ZOIDBERG_PROTOCOL_CONFIG_VIEW_H + +#include +#include +#include #include +#include "MailSettings.h" + + +class BodyDownloadConfig : public BView { +public: + BodyDownloadConfig(); + + void SetTo(MailAddonSettings& settings); + + void MessageReceived(BMessage *msg); + void AttachedToWindow(); + void GetPreferredSize(float *width, float *height); + status_t Archive(BMessage *into, bool) const; +private: + BTextControl* fSizeBox; + BCheckBox* fPartialBox; + BStringView* fBytesLabel; +}; + + typedef enum { B_MAIL_PROTOCOL_HAS_AUTH_METHODS = 1, B_MAIL_PROTOCOL_HAS_FLAVORS = 2, B_MAIL_PROTOCOL_HAS_USERNAME = 4, B_MAIL_PROTOCOL_HAS_PASSWORD = 8, B_MAIL_PROTOCOL_HAS_HOSTNAME = 16, - B_MAIL_PROTOCOL_CAN_LEAVE_MAIL_ON_SERVER = 32 + B_MAIL_PROTOCOL_CAN_LEAVE_MAIL_ON_SERVER = 32, + B_MAIL_PROTOCOL_PARTIAL_DOWNLOAD = 64 } b_mail_protocol_config_options; -class BMailProtocolConfigView : public BView { - public: - BMailProtocolConfigView(uint32 options_mask = B_MAIL_PROTOCOL_HAS_FLAVORS | B_MAIL_PROTOCOL_HAS_USERNAME | B_MAIL_PROTOCOL_HAS_PASSWORD | B_MAIL_PROTOCOL_HAS_HOSTNAME); - virtual ~BMailProtocolConfigView(); - - void SetTo(BMessage *archive); - - void AddFlavor(const char *label); - void AddAuthMethod(const char *label,bool needUserPassword = true); - virtual status_t Archive(BMessage *into, bool deep = true) const; - virtual void GetPreferredSize(float *width, float *height); - virtual void AttachedToWindow(); - virtual void MessageReceived(BMessage *msg); +class BMailProtocolConfigView : public BView { +public: + BMailProtocolConfigView(uint32 options_mask + = B_MAIL_PROTOCOL_HAS_FLAVORS + | B_MAIL_PROTOCOL_HAS_USERNAME + | B_MAIL_PROTOCOL_HAS_PASSWORD + | B_MAIL_PROTOCOL_HAS_HOSTNAME); + virtual ~BMailProtocolConfigView(); + + void SetTo(MailAddonSettings& archive); + + void AddFlavor(const char *label); + void AddAuthMethod(const char *label, + bool needUserPassword = true); + + virtual status_t Archive(BMessage *into, bool deep = true) const; + virtual void GetPreferredSize(float *width, float *height); + virtual void AttachedToWindow(); + virtual void MessageReceived(BMessage *msg); - private: - uint32 _reserved[5]; +private: + BodyDownloadConfig* fBodyDownloadConfig; }; #endif /* ZOIDBERG_PROTOCOL_CONFIG_VIEW_H */ diff --git a/headers/os/add-ons/mail_daemon/RemoteStorageProtocol.h b/headers/os/add-ons/mail_daemon/RemoteStorageProtocol.h deleted file mode 100644 index 9064cbbe5b..0000000000 --- a/headers/os/add-ons/mail_daemon/RemoteStorageProtocol.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef ZOIDBERG_MAIL_REMOTESTORAGEPROTOCOL_H -#define ZOIDBERG_MAIL_REMOTESTORAGEPROTOCOL_H -/* RemoteStorageProtocol - the base class for protocol filters -** -** Copyright 2003 Dr. Zoidberg Enterprises. All rights reserved. -*/ - -#include -#include - -class BRemoteMailStorageProtocol : public BMailProtocol { - public: - BRemoteMailStorageProtocol(BMessage *settings, BMailChainRunner *runner); - virtual ~BRemoteMailStorageProtocol(); - - virtual status_t GetMessage(const char *mailbox, const char *message, BPositionIO **, BMessage *headers) = 0; - virtual status_t AddMessage(const char *mailbox, BPositionIO *data, BString *id) = 0; - - virtual status_t DeleteMessage(const char *mailbox, const char *message) = 0; - virtual status_t CopyMessage(const char *mailbox, const char *to_mailbox, BString *message) = 0; - - virtual status_t CreateMailbox(const char *mailbox) = 0; - virtual status_t DeleteMailbox(const char *mailbox) = 0; - - void SyncMailbox(const char *mailbox); - - //----Mail::Protocol stuff - virtual status_t GetMessage( - const char* uid, - BPositionIO** out_file, BMessage* out_headers, - BPath* out_folder_location); - virtual status_t DeleteMessage(const char* uid); - - //---Data members - BStringList mailboxes; - - private: - BHandler *handler; -}; - -#endif // ZOIDBERG_MAIL_REMOTESTORAGEPROTOCOL_H diff --git a/headers/os/mail/E-mail.h b/headers/os/mail/E-mail.h index a3024c961a..5b9252c747 100644 --- a/headers/os/mail/E-mail.h +++ b/headers/os/mail/E-mail.h @@ -92,27 +92,6 @@ typedef struct { } mail_notification; -// #pragma mark - global functions - - -int32 count_pop_accounts(void); -status_t get_pop_account(mail_pop_account*, int32 index = 0); -status_t set_pop_account(mail_pop_account*, int32 index = 0, - bool save = true); -status_t get_smtp_host(char*); -status_t set_smtp_host(char*, bool save = true); -status_t get_mail_notification(mail_notification*); -status_t set_mail_notification(mail_notification*, bool save = true); - -status_t check_for_mail(int32* incoming_count = NULL); -status_t send_queued_mail(void); -status_t forward_mail(entry_ref*, const char* recipients, bool now = true); - -ssize_t decode_base64(char* out, char* in, off_t length, - bool replace_cr = false); -ssize_t encode_base64(char* out, char* in, off_t length); - - // #pragma mark - BMailMessage class BMailMessage { diff --git a/headers/os/mail/MailDaemon.h b/headers/os/mail/MailDaemon.h index f76b29820a..2ec4317843 100644 --- a/headers/os/mail/MailDaemon.h +++ b/headers/os/mail/MailDaemon.h @@ -1,18 +1,34 @@ -#ifndef ZOIDBERG_MAIL_DAEMON_H -#define ZOIDBERG_MAIL_DAEMON_H +#ifndef MAIL_DAEMON_H +#define MAIL_DAEMON_H /* Daemon - talking to the mail daemon -** -** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. + * + * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. + * Copyright 2011, Clemens Zeidler */ -class BMailDaemon { - public: - static status_t CheckMail(bool send_queued_mail = true,const char *account = NULL); - static status_t SendQueuedMail(); - static int32 CountNewMessages(bool wait_for_fetch_completion = false); - static status_t Quit(); +const uint32 kMsgCheckAndSend = 'mbth'; +const uint32 kMsgCheckMessage = 'mnow'; +const uint32 kMsgSendMessages = 'msnd'; +const uint32 kMsgSettingsUpdated = 'mrrs'; +const uint32 kMsgAccountsChanged = 'macc'; +const uint32 kMsgSetStatusWindowMode = 'shst'; +const uint32 kMsgCountNewMessages = 'mnum'; +const uint32 kMsgMarkMessageAsRead = 'mmar'; + + +class BMailDaemon { +public: + //! accountID = -1 means check all accounts + static status_t CheckMail(int32 accountID = -1); + static status_t CheckAndSendQueuedMail(int32 accountID = -1); + static status_t SendQueuedMail(); + static int32 CountNewMessages( + bool waitForFetchCompletion = false); + static status_t MarkAsRead(int32 account, const entry_ref& ref, + bool read = true); + + static status_t Quit(); }; -#endif /* ZOIDBERG_MAIL_DAEMON_H */ - +#endif // MAIL_DAEMON_H diff --git a/headers/os/mail/MailMessage.h b/headers/os/mail/MailMessage.h index 84f7a786c4..db44191271 100644 --- a/headers/os/mail/MailMessage.h +++ b/headers/os/mail/MailMessage.h @@ -25,7 +25,8 @@ enum mail_reply_to_mode { class BEmailMessage : public BMailContainer { public: BEmailMessage(BPositionIO *mail_file = NULL, bool own = false, uint32 defaultCharSet = B_MAIL_NULL_CONVERSION); - BEmailMessage(entry_ref *ref, uint32 defaultCharSet = B_MAIL_NULL_CONVERSION); + BEmailMessage(const entry_ref *ref, + uint32 defaultCharSet = B_MAIL_NULL_CONVERSION); virtual ~BEmailMessage(); status_t InitCheck() const; @@ -60,7 +61,7 @@ class BEmailMessage : public BMailContainer { void SendViaAccountFrom(BEmailMessage *message); void SendViaAccount(const char *account_name); - void SendViaAccount(int32 chain_id); + void SendViaAccount(int32 account); int32 Account() const; status_t GetAccountName(char *account,int32 maxLength) const; status_t GetAccountName(BString *account) const; @@ -99,7 +100,7 @@ class BEmailMessage : public BMailContainer { BPositionIO *fData; status_t _status; - int32 _chain_id; + int32 _account_id; char *_bcc; int32 _num_components; diff --git a/headers/os/mail/MailSettings.h b/headers/os/mail/MailSettings.h index b5248e7e9f..af5e814ed5 100644 --- a/headers/os/mail/MailSettings.h +++ b/headers/os/mail/MailSettings.h @@ -1,17 +1,25 @@ -#ifndef ZOIDBERG_MAIL_SETTINGS_H -#define ZOIDBERG_MAIL_SETTINGS_H -/* Settings - the mail daemon's settings -** -** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. -*/ +/* + * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. + * Copyright 2011 Clemens Zeidler. + * Distributed under the terms of the MIT License. + */ +#ifndef MAIL_SETTINGS_H +#define MAIL_SETTINGS_H +#include + #include +#include #include #include +#include +#include + class BPath; + typedef enum { B_MAIL_SHOW_STATUS_WINDOW_NEVER = 0, @@ -20,6 +28,7 @@ typedef enum B_MAIL_SHOW_STATUS_WINDOW_ALWAYS = 3 } b_mail_status_window_option; + typedef enum { B_MAIL_STATUS_LOOK_TITLED = 0, @@ -29,126 +38,170 @@ typedef enum B_MAIL_STATUS_LOOK_NO_BORDER = 4 } b_mail_status_window_look; -typedef enum { - inbound, - outbound -} b_mail_chain_direction; - -class BMailStatusWindow; -class BMailChain; - -BMailChain* NewMailChain(); -BMailChain* GetMailChain(uint32 id); - -status_t GetOutboundMailChains(BList* list); -status_t GetInboundMailChains(BList* list); - - -class BMailChain : public BArchivable { -public: - BMailChain(uint32 id); - BMailChain(BMessage*); - virtual ~BMailChain(); - - virtual status_t Archive(BMessage*, bool) const; - static BArchivable* Instantiate(BMessage*); - - status_t Save(bigtime_t timeout = B_INFINITE_TIMEOUT); - status_t Delete() const; - status_t Reload(); - status_t InitCheck() const; - - uint32 ID() const; - - b_mail_chain_direction ChainDirection() const; - void SetChainDirection(b_mail_chain_direction); - - const char* Name() const; - status_t SetName(const char*); - - BMessage* MetaData() const; - - // "Filter" below refers to the settings message for a MailFilter - int32 CountFilters() const; - status_t GetFilter(int32 index, BMessage* out_settings, entry_ref* addon = NULL) const; - status_t SetFilter(int32 index, const BMessage&, const entry_ref&); - - status_t AddFilter(const BMessage&, const entry_ref&); // at end - status_t AddFilter(int32 index, const BMessage&, const entry_ref&); - status_t RemoveFilter(int32 index); - - void RunChain(BMailStatusWindow* window, - bool async = true, - bool save_when_done = true, - bool delete_when_done = false); - - private: - status_t GetPath(BPath& path) const; - status_t Load(BMessage*); - - int32 fId; - char fName[B_FILE_NAME_LENGTH]; - BMessage* fMetaData; - - status_t fStatus; - - b_mail_chain_direction fDirection; - - int32 fSettingsCount; - int32 fAddonsCount; - BList fFilterSettings; - BList fFilterAddons; - - uint32 _reserved[5]; -}; - class BMailSettings { - public: - BMailSettings(); - ~BMailSettings(); - - status_t Save(bigtime_t timeout = B_INFINITE_TIMEOUT); - status_t Reload(); - status_t InitCheck() const; - - // Global settings - int32 WindowFollowsCorner(); - void SetWindowFollowsCorner(int32 which_corner); - - uint32 ShowStatusWindow(); - void SetShowStatusWindow(uint32 mode); - - bool DaemonAutoStarts(); - void SetDaemonAutoStarts(bool does_it); +public: + BMailSettings(); + ~BMailSettings(); - void SetConfigWindowFrame(BRect frame); - BRect ConfigWindowFrame(); + status_t Save(bigtime_t timeout = B_INFINITE_TIMEOUT); + status_t Reload(); + status_t InitCheck() const; - void SetStatusWindowFrame(BRect frame); - BRect StatusWindowFrame(); + // Global settings + int32 WindowFollowsCorner(); + void SetWindowFollowsCorner(int32 which_corner); - int32 StatusWindowWorkspaces(); - void SetStatusWindowWorkspaces(int32 workspaces); + uint32 ShowStatusWindow(); + void SetShowStatusWindow(uint32 mode); + + bool DaemonAutoStarts(); + void SetDaemonAutoStarts(bool does_it); - int32 StatusWindowLook(); - void SetStatusWindowLook(int32 look); - - bigtime_t AutoCheckInterval(); - void SetAutoCheckInterval(bigtime_t); - - bool CheckOnlyIfPPPUp(); - void SetCheckOnlyIfPPPUp(bool yes); - - bool SendOnlyIfPPPUp(); - void SetSendOnlyIfPPPUp(bool yes); - - uint32 DefaultOutboundChainID(); - void SetDefaultOutboundChainID(uint32 to); + void SetConfigWindowFrame(BRect frame); + BRect ConfigWindowFrame(); - private: - BMessage fData; - uint32 _reserved[4]; + void SetStatusWindowFrame(BRect frame); + BRect StatusWindowFrame(); + + int32 StatusWindowWorkspaces(); + void SetStatusWindowWorkspaces(int32 workspaces); + + int32 StatusWindowLook(); + void SetStatusWindowLook(int32 look); + + bigtime_t AutoCheckInterval(); + void SetAutoCheckInterval(bigtime_t); + + bool CheckOnlyIfPPPUp(); + void SetCheckOnlyIfPPPUp(bool yes); + + bool SendOnlyIfPPPUp(); + void SetSendOnlyIfPPPUp(bool yes); + + int32 DefaultOutboundAccount(); + void SetDefaultOutboundAccount(int32 to); + +private: + BMessage fData; + uint32 _reserved[4]; }; + +class AddonSettings +{ +public: + AddonSettings(); + + bool Load(const BMessage& message); + bool Save(BMessage& message); + + void SetAddonRef(const entry_ref& ref); + const entry_ref& AddonRef() const; + + const BMessage& Settings() const; + BMessage& EditSettings(); + + bool HasBeenModified(); +private: + BMessage fSettings; + entry_ref fAddonRef; + + bool fModified; +}; + + +class MailAddonSettings : public AddonSettings +{ +public: + bool Load(const BMessage& message); + bool Save(BMessage& message); + + int32 CountFilterSettings(); + int32 AddFilterSettings(const entry_ref* ref = NULL); + bool RemoveFilterSettings(int32 index); + bool MoveFilterSettings(int32 from, int32 to); + AddonSettings* FilterSettingsAt(int32 index); + + bool HasBeenModified(); +private: + std::vector fFiltersSettings; +}; + + +class BMailAccountSettings +{ + public: + BMailAccountSettings(); + BMailAccountSettings(BEntry account); + ~BMailAccountSettings(); + + status_t InitCheck() { return fStatus; } + + void SetAccountID(int32 id); + int32 AccountID(); + + void SetName(const char* name); + const char* Name() const; + + void SetRealName(const char* realName); + const char* RealName() const; + + void SetReturnAddress(const char* returnAddress); + const char* ReturnAddress() const; + + bool SetInboundAddon(const char* name); + bool SetOutboundAddon(const char* name); + const entry_ref& InboundPath() const; + const entry_ref& OutboundPath() const; + + MailAddonSettings& InboundSettings(); + MailAddonSettings& OutboundSettings(); + + bool HasInbound(); + bool HasOutbound(); + + status_t Reload(); + status_t Save(); + status_t Delete(); + + bool HasBeenModified(); + + const BEntry& AccountFile(); +private: + status_t _CreateAccountFile(); + + status_t fStatus; + BEntry fAccountFile; + + int32 fAccountID; + + BString fAccountName; + BString fRealName; + BString fReturnAdress; + + MailAddonSettings fInboundSettings; + MailAddonSettings fOutboundSettings; + + bool fModified; +}; + + +class BMailAccounts { +public: + BMailAccounts(); + ~BMailAccounts(); + + static status_t AccountsPath(BPath& path); + + int32 CountAccounts(); + BMailAccountSettings* AccountAt(int32 index); + + BMailAccountSettings* AccountByID(int32 id); + BMailAccountSettings* AccountByName(const char* name); +private: + BObjectList fAccounts; +}; + + #endif /* ZOIDBERG_MAIL_SETTINGS_H */ diff --git a/headers/private/mail/FileConfigView.h b/headers/private/mail/FileConfigView.h index 9e4ee913d5..ef13597d2e 100644 --- a/headers/private/mail/FileConfigView.h +++ b/headers/private/mail/FileConfigView.h @@ -42,8 +42,8 @@ class BMailFileConfigView : public BFileControl public: BMailFileConfigView(const char *label,const char *name,bool useMeta = false,const char *defaultPath = NULL,uint32 flavors = B_DIRECTORY_NODE); - void SetTo(BMessage *archive,BMessage *metadata); - virtual status_t Archive(BMessage *into,bool deep = true) const; + void SetTo(const BMessage *archive, BMessage *metadata); + virtual status_t Archive(BMessage *into, bool deep = true) const; private: BMessage *fMeta; diff --git a/headers/private/mail/crypt.h b/headers/private/mail/crypt.h index 8cfcfc0586..1d74059661 100644 --- a/headers/private/mail/crypt.h +++ b/headers/private/mail/crypt.h @@ -9,7 +9,7 @@ #define PASSWORD_LENGTH 32 -char *get_passwd(BMessage *msg,const char *name); +char *get_passwd(const BMessage *msg,const char *name); bool set_passwd(BMessage *msg,const char *name,const char *password); void passwd_crypt(char *in,char *out,int length); diff --git a/headers/private/mail/mail_util.h b/headers/private/mail/mail_util.h index 8c736ff1c6..a20981167a 100644 --- a/headers/private/mail/mail_util.h +++ b/headers/private/mail/mail_util.h @@ -72,6 +72,8 @@ ssize_t readfoldedline(BPositionIO &in, char **buffer, size_t *buflen); // start with a buffer of size *buflen status_t parse_header(BMessage &headers, BPositionIO &input); +status_t extract_from_header(const BString& header, const BString& field, + BString& target); void extract_address(BString &address); // retrieves the mail address only from an address header formatted field diff --git a/src/kits/mail/ChainRunner.cpp b/src/kits/mail/ChainRunner.cpp deleted file mode 100644 index ffa78ec384..0000000000 --- a/src/kits/mail/ChainRunner.cpp +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved. - */ - - -//! Runs the mail inbound and outbound chains - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -class _EXPORT BMailChainRunner; - -#include -#include -#include -#include "ErrorLogWindow.h" - -struct filter_image { - BMessage *settings; - BMailFilter *filter; - image_id id; -}; - -BLocker list_lock("mdr_chainrunner_lock"); -BList running_chains, running_chain_pointers; - - -static void -show_error(alert_type type, const char *message, const char *tag) -{ - static ErrorLogWindow *window = NULL; - static BLocker lock("error window"); - - lock.Lock(); - - if (window == NULL) { - window = new ErrorLogWindow(BRect(200, 200, 500, 250), - "Mail daemon status log", B_TITLED_WINDOW); - } - - lock.Unlock(); - - window->AddError(type, message, tag); -} - - -// #pragma mark - - - -_EXPORT BMailChainRunner * -GetMailChainRunner(int32 chain_id, BMailStatusWindow *status, bool selfDestruct) -{ - list_lock.Lock(); - if (running_chains.HasItem((void *)(chain_id))) { - BMailChainRunner *runner = (BMailChainRunner *)running_chain_pointers.ItemAt(running_chains.IndexOf((void *)(chain_id))); - list_lock.Unlock(); - return runner; - } - list_lock.Unlock(); - - BMailChainRunner *runner = new BMailChainRunner(GetMailChain(chain_id), status, - selfDestruct, false, selfDestruct); - - runner->RunChain(); - return runner; -} - - -class DeathFilter : public BMessageFilter { - public: - DeathFilter() - : BMessageFilter(B_QUIT_REQUESTED) - { - } - - virtual filter_result Filter(BMessage *, BHandler **) - { - be_app->MessageReceived(new BMessage('enda')); //---Stop new chains from starting - - list_lock.Lock(); - for (int32 i = 0; i < running_chain_pointers.CountItems(); i++) - ((BMailChainRunner *)(running_chain_pointers.ItemAt(i)))->Stop(); - list_lock.Unlock(); - - while(running_chains.CountItems() > 0) - snooze(10000); // 1/100th of a second to avoid wasting CPU. - - return B_DISPATCH_MESSAGE; - } -}; - - -BMailChainRunner::BMailChainRunner(BMailChain *chain, BMailStatusWindow *status, - bool selfDestruct, bool saveChain, bool destructChain) - : BLooper(chain->Name()), - _chain(chain), - destroy_self(selfDestruct), - destroy_chain(destructChain), - save_chain(saveChain), - _status(status), - _statview(NULL), - suicide(false) -{ - static DeathFilter *filter = NULL; - - if (filter == NULL) - be_app->AddFilter(filter = new DeathFilter); - - list_lock.Lock(); - if (running_chains.HasItem((void *)(_chain->ID()))) - suicide = true; - running_chains.AddItem((void *)(_chain->ID())); - running_chain_pointers.AddItem(this); - list_lock.Unlock(); -} - - -BMailChainRunner::~BMailChainRunner() -{ - //--- Delete any remaining callbacks - for (int32 i = message_cb.CountItems();i-- > 0;) - delete (BMailChainCallback *)message_cb.ItemAt(i); - for (int32 i = process_cb.CountItems();i-- > 0;) - delete (BMailChainCallback *)process_cb.ItemAt(i); - for (int32 i = chain_cb.CountItems();i-- > 0;) - delete (BMailChainCallback *)chain_cb.ItemAt(i); - - //--- Delete any filter images - for (int32 i = 0; i < addons.CountItems(); i++) { - filter_image *image = (filter_image *)(addons.ItemAt(i)); - delete image->filter; - delete image->settings; - - unload_add_on(image->id); - - delete image; - } - - //--- Remove ourselves from the window if we haven't been already - if ((_status != NULL) && (_statview != NULL)) { - _status->Lock(); - if (_statview->Window()) - _status->RemoveView(_statview); - - delete _statview; - _status->Unlock(); - } - - //--- Remove ourselves from the lists - list_lock.Lock(); - running_chains.RemoveItem((void *)(_chain->ID())); - running_chain_pointers.RemoveItem(this); - list_lock.Unlock(); - - //--- And delete our chain - if (destroy_chain) - delete _chain; -} - - -void -BMailChainRunner::RegisterMessageCallback(BMailChainCallback *callback) -{ - message_cb.AddItem(callback); -} - - -void -BMailChainRunner::RegisterProcessCallback(BMailChainCallback *callback) -{ - process_cb.AddItem(callback); -} - - -void -BMailChainRunner::RegisterChainCallback(BMailChainCallback *callback) -{ - chain_cb.AddItem(callback); -} - - -BMailChain * -BMailChainRunner::Chain() -{ - return _chain; -} - - -status_t -BMailChainRunner::RunChain(bool asynchronous) -{ - if (suicide) { - Quit(); - return B_NAME_IN_USE; - } - - Run(); - - PostMessage('INIT'); - - if (!asynchronous) { - status_t result; - wait_for_thread(Thread(),&result); - return result; - } - - return B_OK; -} - - -void -BMailChainRunner::CallCallbacksFor(BList &list, status_t code) -{ - for (int32 i = 0; i < list.CountItems(); i++) { - BMailChainCallback *callback = static_cast(list.ItemAt(i)); - - callback->Callback(code); - delete callback; - } - list.MakeEmpty(); -} - - -status_t -BMailChainRunner::Init() -{ - status_t big_err = B_OK; - BString desc; - entry_ref addon; - - MDR_DIALECT_CHOICE ( - desc << ((_chain->ChainDirection() == inbound) ? "Fetching" : "Sending") << " mail for " << _chain->Name(), - desc << _chain->Name() << ((_chain->ChainDirection() == inbound) ? "より受信中..." : "へ送信中...") - ); - - _status->Lock(); - _statview = _status->NewStatusView(desc.String(), _chain->ChainDirection() == outbound); - _status->Unlock(); - - BMessage settings; - for (int32 i = 0; _chain->GetFilter(i, &settings, &addon) >= B_OK; i++) { - BPath path(&addon); - BMailFilter *(*instantiate)(BMessage*, BMailChainRunner*); - - image_id imageId = load_add_on(path.Path()); - - if (imageId < B_OK) { - BString error; - MDR_DIALECT_CHOICE ( - error << "Error loading the mail addon " - << path.Path() << " from chain " << _chain->Name() - << ": " << strerror(imageId); - ShowError(error.String());, - error << "メールアドオン " << path.Path() - << " を " << _chain->Name() - << "から読み込む際にエラーが発生しました: " - << strerror(imageId); - - ShowError(error.String()); - ) - return imageId; - } - - status_t err = get_image_symbol(imageId, - "instantiate_mailfilter", B_SYMBOL_TYPE_TEXT, - (void **)&instantiate); - if (err < B_OK) { - BString error; - MDR_DIALECT_CHOICE ( - error << "Error loading the mail addon " << path.Path() - << " from chain " << _chain->Name() - << ": the addon does not seem to be a mail addon (missing symbol instantiate_mailfilter)."; - ShowError(error.String());, - error << "メールアドオン " << path.Path() << " を " - << _chain->Name() << "から読み込む際にエラーが発生しました" - << ": そのアドオンはメールアドオンではないようです(instantiate_mailfilterシンボルがありません)"; - ShowError(error.String()); - ) - - err = -1; - - // TODO: unload_add_on() ? - return err; - } - - filter_image* image = new filter_image; - - image->id = imageId; - image->settings = new BMessage(settings); - image->settings->AddInt32("chain", _chain->ID()); - image->filter = (*instantiate)(image->settings, this); - - addons.AddItem(image); - - if ((big_err = image->filter->InitCheck()) != B_OK) { - //printf("InitCheck() failed (%s) in add-on %s\n",strerror(big_err),path.Path()); - break; - } - } - return big_err; -} - - -void -BMailChainRunner::MessageReceived(BMessage *msg) -{ - switch (msg->what) { - case 'INIT': - if (Init() == B_OK) - break; - case B_QUIT_REQUESTED: - { - CallCallbacksFor(chain_cb, B_OK); - // who knows what the code was? - - BMessage settings; - entry_ref addon; - - for (int32 i = 0; i < addons.CountItems(); i++) { - filter_image *image = (filter_image *)(addons.ItemAt(i)); - delete image->filter; - - if (save_chain) { - image->settings->RemoveName("chain"); - _chain->GetFilter(i,&settings,&addon); - _chain->SetFilter(i,*(image->settings),addon); - } - - delete image->settings; - - unload_add_on(image->id); - - delete image; - } - - addons.MakeEmpty(); - - if ((_status != NULL) && (_statview != NULL)) { - _status->Lock(); - if (_statview->Window()) - _status->RemoveView(_statview); - else - delete _statview; - - _statview = NULL; - _status->Unlock(); - } - - /*list_lock.Lock(); - running_chains.RemoveItem((void *)(_chain->ID())); - running_chain_pointers.RemoveItem(this); - list_lock.Unlock();*/ - - if (save_chain) - _chain->Save(); - - if (destroy_self) - Quit(); - break; - } - case 'GETM': - { - BStringList list; - msg->FindFlat("messages",&list); - _statview->SetTotalItems(list.CountItems()); - _statview->SetMaximum(msg->FindInt32("bytes")); - get_messages(&list); - break; - } - case 'GTSM': - { - const char *uid; - status_t err = B_OK; - msg->FindString("uid",&uid); - BEntry *entry = new BEntry(msg->FindString("into")); - _statview->SetTotalItems(1); - _statview->SetMaximum(msg->FindInt32("bytes")); - BPositionIO *file = new BFile(entry, B_READ_WRITE | B_CREATE_FILE); - BPath *folder = new BPath; - BMessage *headers = new BMessage; - headers->AddBool("ENTIRE_MESSAGE",true); - - for (int32 j = 0; j < addons.CountItems(); j++) { - struct filter_image *current = (struct filter_image *)(addons.ItemAt(j)); - - err = current->filter->ProcessMailMessage(&file,entry,headers,folder,uid); - if (err != B_OK) - break; - } - - CallCallbacksFor(message_cb, err); - - delete file; - delete entry; - delete headers; - delete folder; - - CallCallbacksFor(process_cb, err); - - if (save_chain) { - entry_ref addon; - BMessage settings; - for (int32 i = 0; i < addons.CountItems(); i++) { - filter_image *image = (filter_image *)(addons.ItemAt(i)); - - BMessage *temp = new BMessage(*(image->settings)); - temp->RemoveName("chain"); - _chain->GetFilter(i, &settings, &addon); - _chain->SetFilter(i, *temp, addon); - - delete temp; - } - - _chain->Save(); - } - - ResetProgress(); - break; - } - } -} - - -bool -BMailChainRunner::QuitRequested() -{ - Stop(); - return true; -} - - -void -BMailChainRunner::get_messages(BStringList *list) -{ - const char *uid; - - status_t err = B_OK; - const char *glort; - bool using_tmp = (_chain->MetaData()->FindString("path",&glort) < B_OK); - - BDirectory tmp(using_tmp ? "/tmp" : glort); - - for (int i = 0; i < list->CountItems(); i++) { - uid = (*list)[i]; - - char *path; - if (using_tmp) - path = tempnam("/tmp","mail_temp_"); - else { - BPath pathy(glort); - pathy.Append("Downloading"); - path = (char *)malloc(B_PATH_NAME_LENGTH); - sprintf(path,"%s (%s: %ld)...",pathy.Path(), _chain->Name(), _chain->ID()); - } - - BEntry *entry = new BEntry(path); - free(path); - BPositionIO *file = (_chain->ChainDirection() == inbound) ? new BFile(entry, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE) : NULL; - BPath *folder = new BPath; - BMessage *headers = new BMessage; - - for (int32 j = 0; j < addons.CountItems(); j++) { - struct filter_image *current = (struct filter_image *)(addons.ItemAt(j)); - - err = current->filter->ProcessMailMessage(&file,entry,headers,folder,uid); - - if (err != B_OK) - break; - } - - CallCallbacksFor(message_cb, err); - - if (err == B_MAIL_DISCARD) - entry->Remove(); - - delete file; - delete entry; - delete headers; - delete folder; - - if (err == B_MAIL_END_FETCH || err == B_MAIL_END_CHAIN) - break; - } - - CallCallbacksFor(process_cb, err); - - if (save_chain) { - - entry_ref addon; - BMessage settings; - for (int32 i = 0; i < addons.CountItems(); i++) { - filter_image *image = (filter_image *)(addons.ItemAt(i)); - - BMessage *temp = new BMessage(*(image->settings)); - temp->RemoveName("chain"); - _chain->GetFilter(i,&settings,&addon); - _chain->SetFilter(i,*temp,addon); - - delete temp; - } - - _chain->Save(); - } - - ResetProgress(); - - if (err == B_MAIL_END_CHAIN) - Stop(); - -} - - -void -BMailChainRunner::Stop(bool kill) -{ - if (kill) { - BMessageQueue *looper_queue = MessageQueue(); - looper_queue->Lock(); - BMessage *msg; - while ((msg = looper_queue->NextMessage())) - delete msg; //-- Ensure STOP makes the front of the queue - - PostMessage(B_QUIT_REQUESTED); - looper_queue->Unlock(); - } else { - PostMessage(B_QUIT_REQUESTED); - } -} - - -void -BMailChainRunner::GetMessages(BStringList *list, int32 bytes) -{ - if (list->CountItems() < 1) - return; - - BMessage msg('GETM'); - msg.AddFlat("messages",list); - msg.AddInt32("bytes",bytes); - PostMessage(&msg); -} - - -void -BMailChainRunner::GetSingleMessage(const char *uid, int32 length, BPath *into) -{ - BMessage msg('GTSM'); - msg.AddString("uid",uid); - msg.AddInt32("bytes",length); - msg.AddString("into",into->Path()); - PostMessage(&msg); -} - - -void -BMailChainRunner::ReportProgress(int bytes, int messages, const char *message) -{ - if (bytes != 0) - _statview->AddProgress(bytes); - - for (int i = 0; i < messages; i++) - _statview->AddItem(); - - if (message != NULL) - _statview->SetMessage(message); -} - - -void -BMailChainRunner::ResetProgress(const char *message) -{ - _statview->Reset(); - if (message != NULL) - _statview->SetMessage(message); -} - - -void -BMailChainRunner::ShowError(const char *error) -{ - BString tag = Chain()->Name(); - tag << ": "; - show_error(B_WARNING_ALERT, error, tag.String()); -} - - -void -BMailChainRunner::ShowMessage(const char *error) -{ - BString tag = Chain()->Name(); - tag << ": "; - show_error(B_INFO_ALERT, error, tag.String()); -} diff --git a/src/kits/mail/FileConfigView.cpp b/src/kits/mail/FileConfigView.cpp index dcaa777407..039fe7562a 100644 --- a/src/kits/mail/FileConfigView.cpp +++ b/src/kits/mail/FileConfigView.cpp @@ -145,7 +145,7 @@ BMailFileConfigView::BMailFileConfigView(const char *label,const char *name,bool } -void BMailFileConfigView::SetTo(BMessage *archive, BMessage *meta) +void BMailFileConfigView::SetTo(const BMessage *archive, BMessage *meta) { fMeta = meta; BString path = (fUseMeta ? meta : archive)->FindString(fName); diff --git a/src/kits/mail/HaikuMailFormatFilter.cpp b/src/kits/mail/HaikuMailFormatFilter.cpp new file mode 100644 index 0000000000..a5590a6042 --- /dev/null +++ b/src/kits/mail/HaikuMailFormatFilter.cpp @@ -0,0 +1,204 @@ +/* + * Copyright 2011, Haiku, Inc. All rights reserved. + * Copyright 2011, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ + + +#include "HaikuMailFormatFilter.h" + +#include + +#include +#include + +#include +#include + + +struct mail_header_field +{ + const char *rfc_name; + + const char *attr_name; + type_code attr_type; + // currently either B_STRING_TYPE and B_TIME_TYPE +}; + + +static const mail_header_field gDefaultFields[] = +{ + { "To", B_MAIL_ATTR_TO, B_STRING_TYPE }, + { "From", B_MAIL_ATTR_FROM, B_STRING_TYPE }, + { "Cc", B_MAIL_ATTR_CC, B_STRING_TYPE }, + { "Date", B_MAIL_ATTR_WHEN, B_TIME_TYPE }, + { "Delivery-Date", B_MAIL_ATTR_WHEN, B_TIME_TYPE }, + { "Reply-To", B_MAIL_ATTR_REPLY, B_STRING_TYPE }, + { "Subject", B_MAIL_ATTR_SUBJECT, B_STRING_TYPE }, + { "X-Priority", B_MAIL_ATTR_PRIORITY, B_STRING_TYPE }, // Priorities with prefered + { "Priority", B_MAIL_ATTR_PRIORITY, B_STRING_TYPE }, // one first - the numeric + { "X-Msmail-Priority", B_MAIL_ATTR_PRIORITY, B_STRING_TYPE }, // one (has more levels). + { "Mime-Version", B_MAIL_ATTR_MIME, B_STRING_TYPE }, + { "STATUS", B_MAIL_ATTR_STATUS, B_STRING_TYPE }, + { "THREAD", "MAIL:thread", B_STRING_TYPE }, //---Not supposed to be used for this (we add it in Parser), but why not? + { "NAME", B_MAIL_ATTR_NAME, B_STRING_TYPE }, + { NULL, NULL, 0 } +}; + + +HaikuMailFormatFilter::HaikuMailFormatFilter(MailProtocol& protocol, + BMailAccountSettings* settings) + : + MailFilter(protocol, NULL), + + fAccountId(settings->AccountID()) +{ + const BMessage* outboundSettings = &settings->OutboundSettings().Settings(); + outboundSettings->FindString("destination", &fOutboundDirectory); +} + + +void +HaikuMailFormatFilter::HeaderFetched(const entry_ref& ref, BFile* file) +{ + file->Seek(0, SEEK_SET); + + BMessage attributes; + // TODO attributes.AddInt32(B_MAIL_ATTR_CONTENT, length); + attributes.AddInt32("MAIL:account", fAccountId); + + BString header; + off_t size; + if (file->GetSize(&size) == B_OK) { + char* buffer = header.LockBuffer(size); + file->Read(buffer, size); + header.UnlockBuffer(size); + } + + for (int i = 0; gDefaultFields[i].rfc_name; ++i) { + BString target; + status_t status = extract_from_header(header, + gDefaultFields[i].rfc_name, target); + if (status != B_OK) + continue; + switch (gDefaultFields[i].attr_type){ + case B_STRING_TYPE: + attributes.AddString(gDefaultFields[i].attr_name, target); + break; + + case B_TIME_TYPE: + { + time_t when; + when = ParseDateWithTimeZone(target); + if (when == -1) + when = time(NULL); // Use current time if it's undecodable. + attributes.AddData(B_MAIL_ATTR_WHEN, B_TIME_TYPE, &when, + sizeof(when)); + break; + } + } + } + + (*file) << attributes; + + + // Generate a file name for the incoming message. See also + // Message::RenderTo which does a similar thing for outgoing messages. + + BString name = attributes.FindString("MAIL:subject"); + SubjectToThread(name); // Extract the core subject words. + if (name.Length() <= 0) + name = "No Subject"; + if (name[0] == '.') + name.Prepend ("_"); // Avoid hidden files, starting with a dot. + + // Convert the date into a year-month-day fixed digit width format, so that + // sorting by file name will give all the messages with the same subject in + // order of date. + time_t dateAsTime = 0; + const time_t* datePntr; + ssize_t dateSize; + char numericDateString [40]; + struct tm timeFields; + + if (attributes.FindData(B_MAIL_ATTR_WHEN, B_TIME_TYPE, + (const void**)&datePntr, &dateSize) == B_OK) + dateAsTime = *datePntr; + localtime_r(&dateAsTime, &timeFields); + sprintf(numericDateString, "%04d%02d%02d%02d%02d%02d", + timeFields.tm_year + 1900, + timeFields.tm_mon + 1, + timeFields.tm_mday, + timeFields.tm_hour, + timeFields.tm_min, + timeFields.tm_sec); + name << " " << numericDateString; + + BString worker = attributes.FindString("MAIL:from"); + extract_address_name(worker); + name << " " << worker; + + name.Truncate(222); // reserve space for the uniquer + + // Get rid of annoying characters which are hard to use in the shell. + name.ReplaceAll('/', '_'); + name.ReplaceAll('\'', '_'); + name.ReplaceAll('"', '_'); + name.ReplaceAll('!', '_'); + name.ReplaceAll('<', '_'); + name.ReplaceAll('>', '_'); + while (name.FindFirst(" ") >= 0) // Remove multiple spaces. + name.Replace(" " /* Old */, " " /* New */, 1024 /* Count */); + + worker = name; + int32 identicalNumber = 1; + status_t status = _SetFileName(ref, worker); + while (status == B_FILE_EXISTS) { + identicalNumber++; + + worker = name; + worker << "_" << identicalNumber; + status = _SetFileName(ref, worker); + } + if (status < B_OK) + printf("FolderFilter::ProcessMailMessage: could not rename mail (%s)! " + "(should be: %s)\n",strerror(status), worker.String()); + else { + entry_ref to(ref.device, ref.directory, worker); + fMailProtocol.FileRenamed(ref, to); + } + + BNodeInfo info(file); + info.SetType("text/x-partial-email"); +} + + +void +HaikuMailFormatFilter::BodyFetched(const entry_ref& ref, BFile* file) +{ + BNodeInfo info(file); + info.SetType(B_MAIL_TYPE); +} + + +void +HaikuMailFormatFilter::MessageSent(const entry_ref& ref, BFile* file) +{ + mail_flags flags = B_MAIL_SENT; + file->WriteAttr(B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0, &flags, sizeof(int32)); + file->WriteAttr(B_MAIL_ATTR_STATUS, B_STRING_TYPE, 0, "Sent", 5); + + if (fOutboundDirectory == "") + return; + create_directory(fOutboundDirectory, 755); + BDirectory dir(fOutboundDirectory); + fMailProtocol.Looper()->TriggerFileMove(ref, dir); +} + + +status_t +HaikuMailFormatFilter::_SetFileName(const entry_ref& ref, const BString& name) +{ + BEntry entry(&ref); + return entry.Rename(name); +} diff --git a/src/kits/mail/HaikuMailFormatFilter.h b/src/kits/mail/HaikuMailFormatFilter.h new file mode 100644 index 0000000000..adde70acc4 --- /dev/null +++ b/src/kits/mail/HaikuMailFormatFilter.h @@ -0,0 +1,35 @@ +/* + * Copyright 2011, Haiku, Inc. All rights reserved. + * Copyright 2011, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ +#ifndef IMAP_LISTENER_H +#define IMAP_LISTENER_H + + +#include "MailProtocol.h" + +#include + + +class HaikuMailFormatFilter : public MailFilter { +public: + HaikuMailFormatFilter(MailProtocol& protocol, + BMailAccountSettings* settings); + + void HeaderFetched(const entry_ref& ref, + BFile* file); + void BodyFetched(const entry_ref& ref, BFile* file); + + void MessageSent(const entry_ref& ref, + BFile* file); +private: + status_t _SetFileName(const entry_ref& ref, + const BString& name); + + int32 fAccountId; + BString fOutboundDirectory; +}; + + +#endif // IMAP_LISTENER_H diff --git a/src/kits/mail/Jamfile b/src/kits/mail/Jamfile index ebcb4ecb6e..8232ad6865 100644 --- a/src/kits/mail/Jamfile +++ b/src/kits/mail/Jamfile @@ -1,10 +1,5 @@ SubDir HAIKU_TOP src kits mail ; -SetSubDirSupportedPlatformsBeOSCompatible ; - -if $(TARGET_PLATFORM) != haiku { - UsePublicHeaders mail ; -} UsePrivateHeaders mail shared ; UsePublicHeaders [ FDirName add-ons mail_daemon ] ; @@ -17,19 +12,13 @@ SubDirC++Flags -D_BUILDING_mail=1 ; UsePrivateHeaders textencoding ; SharedLibrary libmail.so : - b_mail_message.cpp - c_mail_api.cpp - ChainRunner.cpp - cpp_abi_base64.c crypt.cpp des.c - ErrorLogWindow.cpp FileConfigView.cpp + HaikuMailFormatFilter.cpp mail_encoding.c mail_util.cpp - MailAddon.cpp MailAttachment.cpp - MailChain.cpp MailComponent.cpp MailContainer.cpp MailDaemon.cpp @@ -39,8 +28,6 @@ SharedLibrary libmail.so : NodeMessage.cpp numailkit.cpp ProtocolConfigView.cpp - RemoteStorageProtocol.cpp - StatusWindow.cpp StringList.cpp : be @@ -50,7 +37,3 @@ SharedLibrary libmail.so : $(TARGET_NETWORK_LIBS) $(TARGET_SELECT_UNAME_ETC_LIB) ; - -Package haiku-maildaemon-cvs : - libmail.so : - boot beos system lib ; diff --git a/src/kits/mail/MailAddon.cpp b/src/kits/mail/MailAddon.cpp deleted file mode 100644 index 638baf74ab..0000000000 --- a/src/kits/mail/MailAddon.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* Filter - the base class for all mail filters -** -** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. -*/ - - -#include - -class _EXPORT BMailFilter; - -#include - -BMailFilter::BMailFilter(BMessage *) -{ - //----do nothing----- -} - -BMailFilter::~BMailFilter() -{ -} - - -void BMailFilter::_ReservedFilter1() {} -void BMailFilter::_ReservedFilter2() {} -void BMailFilter::_ReservedFilter3() {} -void BMailFilter::_ReservedFilter4() {} - diff --git a/src/kits/mail/MailChain.cpp b/src/kits/mail/MailChain.cpp deleted file mode 100644 index f39ff2feda..0000000000 --- a/src/kits/mail/MailChain.cpp +++ /dev/null @@ -1,512 +0,0 @@ -/* BMailChain - the mail account's inbound and outbound chain -** -** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -class BMailChain; - -namespace MailInternal { - status_t WriteMessageFile(const BMessage& archive, - const BPath& path, const char* name); -} - -#include -#include -#include - - -BMailChain::BMailChain(uint32 i) - : - fId(i), - fMetaData(NULL), - fStatus(B_OK), - fDirection(inbound), - fSettingsCount(0), - fAddonsCount(0) -{ - fName[0] = 0; - Reload(); -} - - -BMailChain::BMailChain(BMessage* settings) - : - fId(settings->FindInt32("id")), - fMetaData(NULL), - fStatus(B_OK), - fDirection(inbound), - fSettingsCount(0), - fAddonsCount(0) -{ - fName[0] = 0; - Load(settings); -} - - -BMailChain::~BMailChain() -{ - delete fMetaData; - - for (int32 i = 0; fFilterSettings.ItemAt(i); i++) - delete (BMessage*)fFilterSettings.ItemAt(i); - - for (int32 i = 0; fFilterAddons.ItemAt(i); i++) - delete (entry_ref*)fFilterAddons.ItemAt(i); -} - - -status_t -BMailChain::Load(BMessage* settings) -{ - delete fMetaData; - - fMetaData = new BMessage; - if (settings->HasMessage("meta_data")) - settings->FindMessage("meta_data", fMetaData); - - const char* n; - status_t ret = settings->FindString("name", &n); - if (ret == B_OK) - strncpy(fName, n, sizeof(fName)); - else - fName[0] = '\0'; - - type_code t; - settings->GetInfo("filter_settings", &t, (int32*)(&fSettingsCount)); - settings->GetInfo("filter_addons", &t, (int32*)(&fAddonsCount)); - if (fSettingsCount != fAddonsCount) - return B_MISMATCHED_VALUES; - - for (int i = 0; i < fSettingsCount; i++) { - BMessage* filter = new BMessage(); - entry_ref* ref = new entry_ref(); - char* addon_path; - - if (settings->FindMessage("filter_settings", i, filter) < B_OK - || ((settings->FindString("filter_addons", i, (const char**)&addon_path) < B_OK - || get_ref_for_path(addon_path, ref) < B_OK) - && settings->FindRef("filter_addons", i, ref) < B_OK)) { - delete filter; - delete ref; - return B_NO_MEMORY; - } - - if (!fFilterSettings.AddItem(filter)) { - delete filter; - delete ref; - return B_NO_MEMORY; - } - - if (!fFilterAddons.AddItem(ref)) { - fFilterSettings.RemoveItem(filter); - delete filter; - delete ref; - return B_NO_MEMORY; - } - } - - return B_OK; -} - - -status_t -BMailChain::InitCheck() const -{ - if (fSettingsCount != fAddonsCount) - return B_MISMATCHED_VALUES; - if (fFilterSettings.CountItems() != fSettingsCount - || fFilterAddons.CountItems() != fAddonsCount) - return B_NO_MEMORY; - if (fStatus < B_OK) - return fStatus; - - return B_OK; -} - - -status_t -BMailChain::Archive(BMessage* archive, bool deep) const -{ - status_t ret = InitCheck(); - - if (ret != B_OK && ret != B_FILE_ERROR) - return ret; - - ret = BArchivable::Archive(archive, deep); - if (ret != B_OK) - return ret; - - ret = archive->AddString("class", "BMailChain"); - if (ret != B_OK) - return ret; - - ret = archive->AddInt32("id", fId); - if (ret != B_OK) - return ret; - - ret = archive->AddString("name", fName); - if (ret != B_OK) - return ret; - - ret = archive->AddMessage("meta_data", fMetaData); - if (ret != B_OK) - return ret; - - if (ret == B_OK && deep) { - BMessage* settings; - entry_ref* ref; - - int32 i; - for (i = 0;((settings = (BMessage*)fFilterSettings.ItemAt(i)) != NULL) - && ((ref = (entry_ref*)fFilterAddons.ItemAt(i)) != NULL); - ++i) { - ret = archive->AddMessage("filter_settings", settings); - if (ret < B_OK) - return ret; - - BPath path(ref); - if ((ret = path.InitCheck()) < B_OK) - return ret; - ret = archive->AddString("filter_addons", path.Path()); - if (ret < B_OK) - return ret; - } - if (i != fSettingsCount) - return B_MISMATCHED_VALUES; - } - - return B_OK; -} - - -BArchivable* -BMailChain::Instantiate(BMessage* archive) -{ - return validate_instantiation(archive, "BMailChain") ? - new BMailChain(archive) : NULL; -} - - -status_t -BMailChain::GetPath(BPath& path) const -{ - status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - if (status < B_OK) { - fprintf(stderr, "Couldn't find user settings directory: %s\n", - strerror(status)); - return status; - } - - path.Append("Mail/chains"); - - if (ChainDirection() == outbound) - path.Append("outbound"); - else - path.Append("inbound"); - - BString leaf; - leaf << fId; - path.Append(leaf.String()); - - return B_OK; -} - - -status_t -BMailChain::Save(bigtime_t /*timeout*/) -{ - BMessage archive; - status_t ret = Archive(&archive, true); - if (ret != B_OK) { - fprintf(stderr, "Couldn't archive chain %ld: %s\n", - fId, strerror(ret)); - return ret; - } - - BPath path; - if ((ret = GetPath(path)) < B_OK) - return ret; - - BPath directory; - if ((ret = path.GetParent(&directory)) < B_OK) - return ret; - - return MailInternal::WriteMessageFile(archive, directory, - path.Leaf()/*, timeout*/); -} - - -status_t -BMailChain::Delete() const -{ - status_t status; - BPath path; - if ((status = GetPath(path)) < B_OK) - return status; - - BEntry entry(path.Path()); - if ((status = entry.InitCheck()) < B_OK) - return status; - - return entry.Remove(); -} - - -b_mail_chain_direction -BMailChain::ChainDirection() const -{ - return fDirection; -} - - -void -BMailChain::SetChainDirection(b_mail_chain_direction dir) -{ - fDirection = dir; -} - - -status_t -BMailChain::Reload() -{ - BPath path; - status_t ret = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - if (ret != B_OK) { - fprintf(stderr, "Couldn't find user settings directory: %s\n", - strerror(ret)); - fStatus = ret; - return ret; - } - - path.Append("Mail/chains"); - { - //---Determine whether chain is outbound or inbound and glean full path. - BPath working = path; - working.Append("inbound"); - BString leaf; - leaf << fId; - - //puts(path.Path()); - //puts(leaf.String()); - - if (BDirectory(working.Path()).Contains(leaf.String())) { - path = working; - fDirection = inbound; - } else { - working = path; - working.Append("outbound"); - if (BDirectory(working.Path()).Contains(leaf.String())) { - path = working; - fDirection = outbound; - } - } - - //puts(path.Path()); - - path.Append(leaf.String()); - - //puts(path.Path()); - } - - // open - BFile settings(path.Path(),B_READ_ONLY); - ret = settings.InitCheck(); - - if (ret != B_OK) { - BMessage empty; - fprintf(stderr, "Couldn't open chain settings file '%s': %s\n", - path.Path(), strerror(ret)); - Load(&empty); - fStatus = B_FILE_ERROR; - return ret; - } - - // read settings - BMessage tmp; - ret = tmp.Unflatten(&settings); - if (ret != B_OK) { - fprintf(stderr, "Couldn't read settings from '%s': %s\n", - path.Path(), strerror(ret)); - Load(&tmp); - fStatus = ret; - return ret; - } - - // clobber old settings - fStatus = ret = Load(&tmp); - return ret; -} - - -uint32 -BMailChain::ID() const -{ - return fId; -} - - -const char* -BMailChain::Name() const -{ - return fName; -} - - -status_t -BMailChain::SetName(const char* n) -{ - if (n) - strncpy(fName, n, sizeof(fName)); - else - fName[0] = '\0'; - - return B_OK; -} - - -BMessage* -BMailChain::MetaData() const -{ - return fMetaData; -} - - -int32 -BMailChain::CountFilters() const -{ - return fFilterSettings.CountItems(); -} - - -status_t -BMailChain::GetFilter(int32 index, BMessage* out_settings, - entry_ref* addon) const -{ - if (index >= fFilterSettings.CountItems()) - return B_BAD_INDEX; - - BMessage* settings = (BMessage*)fFilterSettings.ItemAt(index); - if (settings) - *out_settings = *settings; - else - return B_BAD_INDEX; - - if (addon) { - entry_ref* ref = (entry_ref*)fFilterAddons.ItemAt(index); - if (ref) - *addon = *ref; - else - return B_BAD_INDEX; - } - return B_OK; -} - - -status_t -BMailChain::SetFilter(int32 index, const BMessage& s, - const entry_ref& addon) -{ - BMessage* settings = (BMessage*)fFilterSettings.ItemAt(index); - if (settings) - *settings = s; - else - return B_BAD_INDEX; - - entry_ref* ref = (entry_ref*)fFilterAddons.ItemAt(index); - if (ref) - *ref = addon; - else - return B_BAD_INDEX; - - return B_OK; -} - - -status_t -BMailChain::AddFilter(const BMessage& settings, const entry_ref& addon) -{ - BMessage* s = new BMessage(settings); - entry_ref* a = new entry_ref(addon); - - if (!fFilterSettings.AddItem(s)) { - delete s; - delete a; - return B_BAD_INDEX; - } - - if (!fFilterAddons.AddItem(a)) { - fFilterSettings.RemoveItem(fSettingsCount); - delete s; - delete a; - return B_BAD_INDEX; - } - // else - - ++fSettingsCount; - ++fAddonsCount; - - return B_OK; -} - - -status_t -BMailChain::AddFilter(int32 index, const BMessage& settings, - const entry_ref& addon) -{ - BMessage* s = new BMessage(settings); - entry_ref* a = new entry_ref(addon); - - if (!fFilterSettings.AddItem(s, index)) { - delete s; - delete a; - return B_BAD_INDEX; - } - - if (!fFilterAddons.AddItem(a, index)) { - fFilterSettings.RemoveItem(index); - delete s; - delete a; - return B_BAD_INDEX; - } - ++fSettingsCount; - ++fAddonsCount; - - return B_OK; -} - - -status_t -BMailChain::RemoveFilter(int32 index) -{ - BMessage* s = (BMessage*)fFilterSettings.RemoveItem(index); - delete s; - - entry_ref* a = (entry_ref*)fFilterAddons.RemoveItem(index); - delete a; - - --fSettingsCount; - --fAddonsCount; - - return s || a ? B_OK : B_BAD_INDEX; -} - - -void -BMailChain::RunChain(BMailStatusWindow *window, bool async, - bool save_when_done, bool delete_when_done) -{ - (new BMailChainRunner(this, window, true, save_when_done, - delete_when_done))->RunChain(async); -} diff --git a/src/kits/mail/MailDaemon.cpp b/src/kits/mail/MailDaemon.cpp index 99c1e2355b..1e42eb78e4 100644 --- a/src/kits/mail/MailDaemon.cpp +++ b/src/kits/mail/MailDaemon.cpp @@ -13,79 +13,85 @@ #include -_EXPORT status_t -BMailDaemon::CheckMail(bool send_queued_mail,const char *account) + +status_t +BMailDaemon::CheckMail(int32 accountID) { BMessenger daemon("application/x-vnd.Be-POST"); if (!daemon.IsValid()) return B_MAIL_NO_DAEMON; - BMessage message(send_queued_mail ? 'mbth' : 'mnow'); - if (account != NULL) { - BList list; - - GetInboundMailChains(&list); - for (int32 i = list.CountItems();i-- > 0;) { - BMailChain *chain = (BMailChain *)list.ItemAt(i); - - if (!strcmp(chain->Name(),account)) - message.AddInt32("chain",chain->ID()); - - delete chain; - } - - if (send_queued_mail) { - list.MakeEmpty(); - GetOutboundMailChains(&list); - for (int32 i = list.CountItems();i-- > 0;) { - BMailChain *chain = (BMailChain *)list.ItemAt(i); - - if (!strcmp(chain->Name(),account)) - message.AddInt32("chain",chain->ID()); - - delete chain; - } - } - } - daemon.SendMessage(&message); - - return B_OK; + BMessage message(kMsgCheckMessage); + message.AddInt32("account", accountID); + return daemon.SendMessage(&message); } -_EXPORT status_t BMailDaemon::SendQueuedMail() { +status_t +BMailDaemon::CheckAndSendQueuedMail(int32 accountID) +{ + BMessenger daemon("application/x-vnd.Be-POST"); + if (!daemon.IsValid()) + return B_MAIL_NO_DAEMON; + + BMessage message(kMsgCheckAndSend); + message.AddInt32("account", accountID); + return daemon.SendMessage(&message); +} + + +status_t +BMailDaemon::SendQueuedMail() +{ BMessenger daemon("application/x-vnd.Be-POST"); if (!daemon.IsValid()) return B_MAIL_NO_DAEMON; - daemon.SendMessage('msnd'); - - return B_OK; + return daemon.SendMessage(kMsgSendMessages); } -_EXPORT int32 BMailDaemon::CountNewMessages(bool wait_for_fetch_completion) { + +int32 +BMailDaemon::CountNewMessages(bool wait_for_fetch_completion) +{ BMessenger daemon("application/x-vnd.Be-POST"); if (!daemon.IsValid()) return B_MAIL_NO_DAEMON; - + BMessage reply; - BMessage first('mnum'); - + BMessage first(kMsgCountNewMessages); + if (wait_for_fetch_completion) first.AddBool("wait_for_fetch_done",true); - daemon.SendMessage(&first,&reply); + daemon.SendMessage(&first, &reply); return reply.FindInt32("num_new_messages"); } -_EXPORT status_t BMailDaemon::Quit() { + +status_t +BMailDaemon::MarkAsRead(int32 account, const entry_ref& ref, bool read) +{ + BMessenger daemon("application/x-vnd.Be-POST"); + if (!daemon.IsValid()) + return B_MAIL_NO_DAEMON; + + BMessage message(kMsgMarkMessageAsRead); + message.AddInt32("account", account); + message.AddRef("ref", &ref); + message.AddBool("read", read); + + return daemon.SendMessage(&message); +} + + +status_t +BMailDaemon::Quit() +{ BMessenger daemon("application/x-vnd.Be-POST"); if (!daemon.IsValid()) return B_MAIL_NO_DAEMON; - daemon.SendMessage(B_QUIT_REQUESTED); - - return B_OK; + return daemon.SendMessage(B_QUIT_REQUESTED); } - diff --git a/src/kits/mail/MailMessage.cpp b/src/kits/mail/MailMessage.cpp index 10a4f9f6e7..51da5c00c6 100644 --- a/src/kits/mail/MailMessage.cpp +++ b/src/kits/mail/MailMessage.cpp @@ -65,7 +65,7 @@ BEmailMessage::BEmailMessage(BPositionIO *file, bool own, uint32 defaultCharSet) _text_body(NULL) { BMailSettings settings; - _chain_id = settings.DefaultOutboundChainID(); + _account_id = settings.DefaultOutboundAccount(); if (own) fData = file; @@ -75,16 +75,16 @@ BEmailMessage::BEmailMessage(BPositionIO *file, bool own, uint32 defaultCharSet) } -BEmailMessage::BEmailMessage(entry_ref *ref, uint32 defaultCharSet) +BEmailMessage::BEmailMessage(const entry_ref *ref, uint32 defaultCharSet) : - BMailContainer (defaultCharSet), + BMailContainer(defaultCharSet), _bcc(NULL), _num_components(0), _body(NULL), _text_body(NULL) { BMailSettings settings; - _chain_id = settings.DefaultOutboundChainID(); + _account_id = settings.DefaultOutboundAccount(); fData = new BFile(); _status = static_cast(fData)->SetTo(ref,B_READ_ONLY); @@ -126,7 +126,11 @@ BEmailMessage::ReplyMessage(mail_reply_to_mode replyTo, bool accountFromMail, get_address_list(list, To(), extract_address); // Filter out the sender - BString sender = BMailChain(Account()).MetaData()->FindString("reply_to"); + BMailAccounts accounts; + BMailAccountSettings* account = accounts.AccountByID(Account()); + BString sender; + if (account) + sender = account->ReturnAddress(); extract_address(sender); BString cc; @@ -391,52 +395,42 @@ BEmailMessage::SendViaAccountFrom(BEmailMessage *message) return; } - BList chains; - GetOutboundMailChains(&chains); - for (int32 i = chains.CountItems();i-- > 0;) { - BMailChain *chain = (BMailChain *)chains.ItemAt(i); - if (!strcmp(chain->Name(), name)) - SendViaAccount(chain->ID()); - - delete chain; - } + SendViaAccount(name); } void BEmailMessage::SendViaAccount(const char *account_name) { - BList chains; - GetOutboundMailChains(&chains); - - for (int32 i = 0; i < chains.CountItems(); i++) { - if (strcmp(((BMailChain *)(chains.ItemAt(i)))->Name(),account_name) == 0) { - SendViaAccount(((BMailChain *)(chains.ItemAt(i)))->ID()); - break; - } - } - - while (chains.CountItems() > 0) - delete (BMailChain *)chains.RemoveItem(0L); + BMailAccounts accounts; + BMailAccountSettings* account = accounts.AccountByName(account_name); + if (!account) + return; + SendViaAccount(account->AccountID()); } void -BEmailMessage::SendViaAccount(int32 chain_id) +BEmailMessage::SendViaAccount(int32 account) { - _chain_id = chain_id; + _account_id = account; + + BMailAccounts accounts; + BMailAccountSettings* accountSettings = accounts.AccountByID(_account_id); - BMailChain chain(_chain_id); BString from; - from << '\"' << chain.MetaData()->FindString("real_name") << "\" <" << chain.MetaData()->FindString("reply_to") << '>'; - SetFrom(from.String()); + if (accountSettings) { + from << '\"' << accountSettings->RealName() << "\" <" + << accountSettings->ReturnAddress() << '>'; + } + SetFrom(from); } int32 BEmailMessage::Account() const { - return _chain_id; + return _account_id; } @@ -650,7 +644,7 @@ status_t BEmailMessage::SetToRFC822(BPositionIO *mail_file, size_t length, bool parse_now) { if (BFile *file = dynamic_cast(mail_file)) - file->ReadAttr("MAIL:chain",B_INT32_TYPE,0,&_chain_id,sizeof(_chain_id)); + file->ReadAttr("MAIL:account",B_INT32_TYPE,0,&_account_id,sizeof(_account_id)); mail_file->Seek(0,SEEK_END); length = mail_file->Position(); @@ -711,7 +705,7 @@ BEmailMessage::RenderToRFC822(BPositionIO *file) if (From() == NULL) { // set the "From:" string - SendViaAccount(_chain_id); + SendViaAccount(_account_id); } BList recipientList; @@ -807,14 +801,19 @@ BEmailMessage::RenderToRFC822(BPositionIO *file) attributed->WriteAttrString(B_MAIL_ATTR_STATUS,&attr); attr = "1.0"; attributed->WriteAttrString(B_MAIL_ATTR_MIME,&attr); - attr = BMailChain(_chain_id).Name(); + BMailAccounts accounts; + BMailAccountSettings* account = accounts.AccountByID(_account_id); + if (account) + attr = account->Name(); + else + attr = ""; attributed->WriteAttrString(B_MAIL_ATTR_ACCOUNT,&attr); attributed->WriteAttr(B_MAIL_ATTR_WHEN,B_TIME_TYPE,0,&creationTime,sizeof(int32)); int32 flags = B_MAIL_PENDING | B_MAIL_SAVE; attributed->WriteAttr(B_MAIL_ATTR_FLAGS,B_INT32_TYPE,0,&flags,sizeof(int32)); - attributed->WriteAttr("MAIL:chain",B_INT32_TYPE,0,&_chain_id,sizeof(int32)); + attributed->WriteAttr("MAIL:account",B_INT32_TYPE,0,&_account_id,sizeof(int32)); } return B_OK; @@ -902,15 +901,19 @@ BEmailMessage::RenderTo(BDirectory *dir, BEntry *msg) status_t BEmailMessage::Send(bool send_now) { - BMailChain *via = new BMailChain(_chain_id); - if ((via->InitCheck() != B_OK) || (via->ChainDirection() != outbound)) { - delete via; - via = new BMailChain(BMailSettings().DefaultOutboundChainID()); - SendViaAccount(via->ID()); + BMailAccounts accounts; + BMailAccountSettings* account = accounts.AccountByID(_account_id); + if (!account || !account->HasOutbound()) { + account = accounts.AccountByID( + BMailSettings().DefaultOutboundAccount()); + if (!account) + return B_ERROR; + SendViaAccount(account->AccountID()); } BString path; - if (via->MetaData()->FindString("path", &path) != B_OK) { + if (account->OutboundSettings().Settings().FindString("path", &path) + != B_OK) { BPath defaultMailOutPath; if (find_directory(B_USER_DIRECTORY, &defaultMailOutPath) != B_OK || defaultMailOutPath.Append("mail/out") != B_OK) @@ -925,7 +928,6 @@ BEmailMessage::Send(bool send_now) BEntry message; status_t status = RenderTo(&directory, &message); - delete via; if (status >= B_OK && send_now) { BMailSettings settings_file; if (settings_file.SendOnlyIfPPPUp()) { @@ -955,7 +957,7 @@ BEmailMessage::Send(bool send_now) return B_MAIL_NO_DAEMON; BMessage msg('msnd'); - msg.AddInt32("chain",_chain_id); + msg.AddInt32("account",_account_id); BPath path; message.GetPath(&path); msg.AddString("message_path",path.Path()); diff --git a/src/kits/mail/MailProtocol.cpp b/src/kits/mail/MailProtocol.cpp index db81e908af..6b1674383a 100644 --- a/src/kits/mail/MailProtocol.cpp +++ b/src/kits/mail/MailProtocol.cpp @@ -18,450 +18,714 @@ #include #include #include +#include #include #include #include #include -class BMailProtocol; - +#include #include -#include -#include +#include -namespace { +#include "HaikuMailFormatFilter.h" -class ManifestAdder : public BMailChainCallback { - public: - ManifestAdder(BStringList *list,BStringList **list2, const char *id) : manifest(list), uids_on_disk(list2), uid(id) {} - virtual void Callback(status_t result) { - if (result == B_OK) { - (*manifest) += uid; - if (*uids_on_disk != NULL) - (**uids_on_disk) += uid; - } - } - private: - BStringList *manifest,**uids_on_disk; - const char *uid; -}; +using std::map; -class MessageDeletion : public BMailChainCallback { - public: - MessageDeletion(BMailProtocol *home, const char *uid, BEntry *io_entry, bool delete_anyway); - virtual void Callback(status_t result); - private: - BMailProtocol *us; - bool always; - const char *message_id; - BEntry *entry; -}; - -} // unnamed namspace - -inline void -BMailProtocol::error_alert(const char *process, status_t error) -{ - BString string; - MDR_DIALECT_CHOICE ( - string << "Error while " << process << ": " << strerror(error); - runner->ShowError(string.String()); - , - string << process << "中にエラーが発生しました: " << strerror(error); - runner->ShowError(string.String()); - ) -} - - -namespace { - - -class DeleteHandler : public BHandler { - public: - DeleteHandler(BMailProtocol *a) - : us(a) - { - } - - void MessageReceived(BMessage *msg) - { - if ((msg->what == 'DELE') && (us->InitCheck() == B_OK)) { - us->CheckForDeletedMessages(); - Looper()->RemoveHandler(this); - delete this; - } - } - - private: - BMailProtocol *us; -}; - - -class TrashMonitor : public BHandler { - public: - TrashMonitor(BMailProtocol *a, int32 chain_id) - : us(a), messages_for_us(0), id(chain_id) - { - } - - ~TrashMonitor() - { - stop_watching(this); - } - - void MessageReceived(BMessage *msg) - { - if (msg->what == 'INIT') { - BVolumeRoster volumes; - BVolume volume; - while (volumes.GetNextVolume(&volume) == B_OK) { - BPath trashPath; - if (find_directory(B_TRASH_DIRECTORY, &trashPath, - false, &volume) == B_OK) { - // watch this trash directory - BNode node(trashPath.Path()); - node_ref to_watch; - node.GetNodeRef(&to_watch); - watch_node(&to_watch, B_WATCH_DIRECTORY, this); - } - } - // Also watch for new volume - watch_node(NULL, B_WATCH_MOUNT, this); - return; - } - - if (msg->what != B_NODE_MONITOR || (us->InitCheck() != B_OK)) - return; - - int32 opcode; - if (msg->FindInt32("opcode",&opcode) < B_OK) - return; - - if (opcode == B_DEVICE_MOUNTED) { - dev_t device; - if (msg->FindInt32("new device", &device) != B_OK) - return; - BVolume volume(device); - BPath trashPath; - if (find_directory(B_TRASH_DIRECTORY, &trashPath, - false, &volume) == B_OK) { - // watch also this new volume's trash directory - BNode node(trashPath.Path()); - node_ref to_watch; - node.GetNodeRef(&to_watch); - watch_node(&to_watch, B_WATCH_DIRECTORY, this); - } - return; - } - - if (opcode == B_ENTRY_MOVED) { - entry_ref ref; - const char* name; - msg->FindInt64("to directory", &ref.directory); - msg->FindInt32("device", &ref.device); - msg->FindString("name", &name); - ref.set_name(name); - - BNode node(&ref); - int32 chain; - - // check it's a mail - if (node.ReadAttr("MAIL:chain",B_INT32_TYPE,0,&chain,sizeof(chain)) < B_OK) - return; - - // check it's a mail for us - if (chain != id) - return; - - // check if it was moved to trash - bool moved_to_trash = false; - BPath trashPath; - BEntry entry(&ref); - BVolume volume(ref.device); - if (find_directory(B_TRASH_DIRECTORY, &trashPath, - false, &volume) == B_OK) { - BDirectory trash(trashPath.Path()); - moved_to_trash = trash.Contains(&entry); - } - - messages_for_us += (moved_to_trash) ? 1 : -1; - if (messages_for_us < 0) { - // Guard against weirdness - messages_for_us = 0; - return; - } - } - - if (opcode != B_ENTRY_REMOVED) - return; - - // Check if this (trash) entry removal made one trash now empty - - bool someTrashIsEmpty = false; - BVolumeRoster volumes; - BVolume volume; - while (volumes.GetNextVolume(&volume) == B_OK) { - BPath trashPath; - if (find_directory(B_TRASH_DIRECTORY, &trashPath, - false, &volume) != B_OK) { - continue; - } - BDirectory trash(trashPath.Path()); - if (trash.CountEntries() == 0) { - someTrashIsEmpty = true; - break; - } - } - - if (someTrashIsEmpty) { - // One trash is empty, check for deleted messages - if (messages_for_us > 0) - us->CheckForDeletedMessages(); - - messages_for_us = 0; - } - } - - private: - BMailProtocol *us; - int32 messages_for_us; - int32 id; -}; - -} // unnamed namespace - - -// #pragma mark BMailProtocol - - -BMailProtocol::BMailProtocol(BMessage *settings, BMailChainRunner *run) - : BMailFilter(settings), - runner(run), trash_monitor(NULL), uids_on_disk(NULL) -{ - unique_ids = new BStringList; - BMailProtocol::settings = settings; - - manifest = new BStringList; - - { - BString attr_name = "MAIL:"; - attr_name << runner->Chain()->ID() << ":manifest"; //--- In case someone puts multiple accounts in the same directory - - if (runner->Chain()->MetaData()->HasString("path")) { - BNode node(runner->Chain()->MetaData()->FindString("path")); - if (node.InitCheck() >= B_OK) { - // We already have a directory so we can try to read metadata - // from it. Note that it is normal for this directory not to - // be found on the first run as it will be later created by - // the INBOX system filter. - attr_info info; - if (node.GetAttrInfo(attr_name.String(),&info) < B_OK) { - if (runner->Chain()->MetaData()->FindFlat("manifest", manifest) == B_OK) { - runner->Chain()->MetaData()->RemoveName("manifest"); - runner->Chain()->Save(); //--- Not having this code made an earlier version of MDR delete all my *(&(*& mail - } - } else { - void *flatmanifest = malloc(info.size); - node.ReadAttr(attr_name.String(),manifest->TypeCode(),0,flatmanifest,info.size); - manifest->Unflatten(manifest->TypeCode(),flatmanifest,info.size); - free(flatmanifest); - } - } - } else runner->ShowError("Error while reading account manifest: no destination directory exists."); - } - - uids_on_disk = new BStringList; - BVolumeRoster volumes; - BVolume volume; - while (volumes.GetNextVolume(&volume) == B_OK) { - BQuery fido; - entry_ref entry; - - fido.SetVolume(&volume); - fido.PushAttr("MAIL:chain"); - fido.PushInt32(settings->FindInt32("chain")); - fido.PushOp(B_EQ); - fido.PushAttr("MAIL:pending_chain"); - fido.PushInt32(settings->FindInt32("chain")); - fido.PushOp(B_EQ); - fido.PushOp(B_OR); - if (!settings->FindBool("leave_mail_on_server")) { - fido.PushAttr("BEOS:type"); - fido.PushString("text/x-partial-email"); - fido.PushOp(B_EQ); - fido.PushOp(B_AND); - } - fido.Fetch(); - - BString uid; - while (fido.GetNextRef(&entry) == B_OK) { - BNode(&entry).ReadAttrString("MAIL:unique_id",&uid); - uids_on_disk->AddItem(uid.String()); - } - } - - (*manifest) |= (*uids_on_disk); - - if (!settings->FindBool("login_and_do_nothing_else_of_any_importance")) { - DeleteHandler *h = new DeleteHandler(this); - runner->AddHandler(h); - runner->PostMessage('DELE',h); - - trash_monitor = new TrashMonitor(this,runner->Chain()->ID()); - runner->AddHandler(trash_monitor); - runner->PostMessage('INIT',trash_monitor); - } -} - - -BMailProtocol::~BMailProtocol() -{ - if (manifest != NULL) { - BMessage *meta_data = runner->Chain()->MetaData(); - meta_data->RemoveName("manifest"); - BString attr_name = "MAIL:"; - attr_name << runner->Chain()->ID() << ":manifest"; //--- In case someone puts multiple accounts in the same directory - if (meta_data->HasString("path")) { - BNode node(meta_data->FindString("path")); - if (node.InitCheck() >= B_OK) { - node.RemoveAttr(attr_name.String()); - ssize_t manifestsize = manifest->FlattenedSize(); - void *flatmanifest = malloc(manifestsize); - manifest->Flatten(flatmanifest,manifestsize); - if (status_t err = node.WriteAttr(attr_name.String(),manifest->TypeCode(),0,flatmanifest,manifestsize) < B_OK) { - BString error = "Error while saving account manifest: "; - error << strerror(err); - runner->ShowError(error.String()); - } - free(flatmanifest); - } else runner->ShowError("Error while saving account manifest: cannot use destination directory."); - } else runner->ShowError("Error while saving account manifest: no destination directory exists."); - } - delete unique_ids; - delete manifest; - delete trash_monitor; - delete uids_on_disk; -} - - -#define dump_stringlist(a) printf("BStringList %s:\n",#a); \ - for (int32 i = 0; i < (a)->CountItems(); i++)\ - puts((a)->ItemAt(i)); \ - puts("Done\n"); - -status_t -BMailProtocol::ProcessMailMessage(BPositionIO **io_message, BEntry *io_entry, - BMessage *io_headers, BPath *io_folder, const char *io_uid) -{ - status_t error; - - if (io_uid == NULL) - return B_ERROR; - - error = GetMessage(io_uid, io_message, io_headers, io_folder); - if (error < B_OK) { - if (error != B_MAIL_END_FETCH) { - MDR_DIALECT_CHOICE ( - error_alert("getting a message",error);, - error_alert("新しいメッセージヲ取得中にエラーが発生しました",error); - ); - } - return B_MAIL_END_FETCH; - } - - runner->RegisterMessageCallback(new ManifestAdder(manifest, &uids_on_disk, io_uid)); - runner->RegisterMessageCallback(new MessageDeletion(this, io_uid, io_entry, !settings->FindBool("leave_mail_on_server"))); - - return B_OK; -} - -void BMailProtocol::CheckForDeletedMessages() { - { - //---Delete things from the manifest no longer on the server - BStringList temp; - manifest->NotThere(*unique_ids, &temp); - (*manifest) -= temp; - } - - if (((settings->FindBool("delete_remote_when_local")) || !(settings->FindBool("leave_mail_on_server"))) && (manifest->CountItems() > 0)) { - BStringList to_delete; - - if (uids_on_disk == NULL) { - BStringList query_contents; - BVolumeRoster volumes; - BVolume volume; - - while (volumes.GetNextVolume(&volume) == B_OK) { - BQuery fido; - entry_ref entry; - - fido.SetVolume(&volume); - fido.PushAttr("MAIL:chain"); - fido.PushInt32(settings->FindInt32("chain")); - fido.PushOp(B_EQ); - fido.PushAttr("MAIL:pending_chain"); - fido.PushInt32(settings->FindInt32("chain")); - fido.PushOp(B_EQ); - fido.PushOp(B_OR); - fido.Fetch(); - - BString uid; - while (fido.GetNextRef(&entry) == B_OK) { - BNode(&entry).ReadAttrString("MAIL:unique_id",&uid); - query_contents.AddItem(uid.String()); - } - } - - query_contents.NotHere(*manifest,&to_delete); - } else { - uids_on_disk->NotHere(*manifest,&to_delete); - delete uids_on_disk; - uids_on_disk = NULL; - } - - for (int32 i = 0; i < to_delete.CountItems(); i++) - DeleteMessage(to_delete[i]); - - //*(unique_ids) -= to_delete; --- This line causes bad things to - // happen (POP3 client uses the wrong indices to retrieve - // messages). Without it, bad things don't happen. - *(manifest) -= to_delete; - } -} - -void BMailProtocol::_ReservedProtocol1() {} -void BMailProtocol::_ReservedProtocol2() {} -void BMailProtocol::_ReservedProtocol3() {} -void BMailProtocol::_ReservedProtocol4() {} -void BMailProtocol::_ReservedProtocol5() {} - - -// #pragma mark - - - -MessageDeletion::MessageDeletion(BMailProtocol *home, const char *uid, - BEntry *io_entry, bool delete_anyway) +MailFilter::MailFilter(MailProtocol& protocol, AddonSettings* settings) : - us(home), - always(delete_anyway), - message_id(uid), entry(io_entry) + fMailProtocol(protocol), + fAddonSettings(settings) { + +} + + +MailFilter::~MailFilter() +{ + } void -MessageDeletion::Callback(status_t result) +MailFilter::HeaderFetched(const entry_ref& ref, BFile* file) { - #if DEBUG - printf("Deleting %s\n", message_id); - #endif - BNode node(entry); - BNodeInfo info(&node); - char type[255]; - info.GetType(type); - if ((always && strcmp(B_MAIL_TYPE,type) == 0) || result == B_MAIL_DISCARD) - us->DeleteMessage(message_id); + +} + + +void +MailFilter::BodyFetched(const entry_ref& ref, BFile* file) +{ + +} + + +void +MailFilter::MailboxSynced(status_t status) +{ + +} + + +void +MailFilter::MessageReadyToSend(const entry_ref& ref, BFile* file) +{ + +} + + +void +MailFilter::MessageSent(const entry_ref& ref, BFile* file) +{ + +} + + +MailProtocol::MailProtocol(BMailAccountSettings* settings) + : + fMailNotifier(NULL), + fProtocolThread(NULL) +{ + fAccountSettings = *settings; + + AddFilter(new HaikuMailFormatFilter(*this, settings)); +} + + +MailProtocol::~MailProtocol() +{ + delete fMailNotifier; + + for (int i = 0; i < fFilterList.CountItems(); i++) + delete fFilterList.ItemAt(i); + + map::iterator it = fFilterImages.begin(); + for (; it != fFilterImages.end(); it++) + unload_add_on(it->second); +} + + +BMailAccountSettings& +MailProtocol::AccountSettings() +{ + return fAccountSettings; +} + + +void +MailProtocol::SetProtocolThread(MailProtocolThread* protocolThread) +{ + if (fProtocolThread) { + fProtocolThread->Lock(); + for (int i = 0; i < fHandlerList.CountItems(); i++) + fProtocolThread->RemoveHandler(fHandlerList.ItemAt(i)); + fProtocolThread->Unlock(); + } + + fProtocolThread = protocolThread; + + if (!fProtocolThread) + return; + + fProtocolThread->Lock(); + for (int i = 0; i < fHandlerList.CountItems(); i++) + fProtocolThread->AddHandler(fHandlerList.ItemAt(i)); + fProtocolThread->Unlock(); + + AddedToLooper(); +} + + +MailProtocolThread* +MailProtocol::Looper() +{ + return fProtocolThread; +} + + +bool +MailProtocol::AddHandler(BHandler* handler) +{ + if (!fHandlerList.AddItem(handler)) + return false; + if (fProtocolThread) { + fProtocolThread->Lock(); + fProtocolThread->AddHandler(handler); + fProtocolThread->Unlock(); + } + return true; +} + + +bool +MailProtocol::RemoveHandler(BHandler* handler) +{ + if (!fHandlerList.RemoveItem(handler)) + return false; + if (fProtocolThread) { + fProtocolThread->Lock(); + fProtocolThread->RemoveHandler(handler); + fProtocolThread->Unlock(); + } + return true; +} + + +void +MailProtocol::SetMailNotifier(MailNotifier* mailNotifier) +{ + delete fMailNotifier; + fMailNotifier = mailNotifier; +} + + +void +MailProtocol::ShowError(const char* error) +{ + if (fMailNotifier) + fMailNotifier->ShowError(error); +} + + +void +MailProtocol::ShowMessage(const char* message) +{ + if (fMailNotifier) + fMailNotifier->ShowMessage(message); +} + + +void +MailProtocol::SetTotalItems(int32 items) +{ + if (fMailNotifier) + fMailNotifier->SetTotalItems(items); +} + + +void +MailProtocol::SetTotalItemsSize(int32 size) +{ + if (fMailNotifier) + fMailNotifier->SetTotalItemsSize(size); +} + + +void +MailProtocol::ReportProgress(int bytes, int messages, const char* message) +{ + if (fMailNotifier) + fMailNotifier->ReportProgress(bytes, messages, message); +} + + +void +MailProtocol::ResetProgress(const char* message) +{ + if (fMailNotifier) + fMailNotifier->ResetProgress(message); +} + + +bool +MailProtocol::AddFilter(MailFilter* filter) +{ + return fFilterList.AddItem(filter); +} + + +int32 +MailProtocol::CountFilter() +{ + return fFilterList.CountItems(); +} + + +MailFilter* +MailProtocol::FilterAt(int32 index) +{ + return fFilterList.ItemAt(index); +} + + +MailFilter* +MailProtocol::RemoveFilter(int32 index) +{ + return fFilterList.RemoveItemAt(index); +} + + +bool +MailProtocol::RemoveFilter(MailFilter* filter) +{ + return fFilterList.RemoveItem(filter); +} + + +void +MailProtocol::NotifyNewMessagesToFetch(int32 nMessages) +{ + ResetProgress(); + SetTotalItems(nMessages); +} + + +void +MailProtocol::NotifyHeaderFetched(const entry_ref& ref, BFile* data) +{ + for (int i = 0; i < fFilterList.CountItems(); i++) + fFilterList.ItemAt(i)->HeaderFetched(ref, data); + + ReportProgress(0, 1); +} + + +void +MailProtocol::NotifyBodyFetched(const entry_ref& ref, BFile* data) +{ + for (int i = 0; i < fFilterList.CountItems(); i++) + fFilterList.ItemAt(i)->BodyFetched(ref, data); +} + + +void +MailProtocol::NotifyMessageReadyToSend(const entry_ref& ref, BFile* data) +{ + for (int i = 0; i < fFilterList.CountItems(); i++) + fFilterList.ItemAt(i)->MessageReadyToSend(ref, data); +} + + +void +MailProtocol::NotifyMessageSent(const entry_ref& ref, BFile* data) +{ + for (int i = 0; i < fFilterList.CountItems(); i++) + fFilterList.ItemAt(i)->MessageSent(ref, data); +} + + +status_t +MailProtocol::MoveMessage(const entry_ref& ref, BDirectory& dir) +{ + BEntry entry(&ref); + return entry.MoveTo(&dir); +} + + +status_t +MailProtocol::DeleteMessage(const entry_ref& ref) +{ + BEntry entry(&ref); + return entry.Remove(); +} + + +void +MailProtocol::FileRenamed(const entry_ref& from, const entry_ref& to) +{ + +} + + +void +MailProtocol::FileDeleted(const node_ref& node) +{ + +} + + +void +MailProtocol::LoadFilters(MailAddonSettings& settings) +{ + for (int i = 0; i < settings.CountFilterSettings(); i++) { + AddonSettings* filterSettings = settings.FilterSettingsAt(i); + MailFilter* filter = _LoadFilter(filterSettings); + if (!filter) + continue; + AddFilter(filter); + } +} + + +MailFilter* +MailProtocol::_LoadFilter(AddonSettings* filterSettings) +{ + const entry_ref& ref = filterSettings->AddonRef(); + map::iterator it = fFilterImages.find(ref); + image_id image; + if (it != fFilterImages.end()) + image = it->second; + else { + BEntry entry(&ref); + BPath path(&entry); + image = load_add_on(path.Path()); + } + if (image < 0) + return NULL; + + MailFilter* (*instantiate_mailfilter)(MailProtocol& protocol, + AddonSettings* settings); + if (get_image_symbol(image, "instantiate_mailfilter", + B_SYMBOL_TYPE_TEXT, (void **)&instantiate_mailfilter) + != B_OK) { + unload_add_on(image); + return NULL; + } + + fFilterImages[ref] = image; + return (*instantiate_mailfilter)(*this, filterSettings); +} + + +InboundProtocol::InboundProtocol(BMailAccountSettings* settings) + : + MailProtocol(settings) +{ + LoadFilters(fAccountSettings.InboundSettings()); +} + + +InboundProtocol::~InboundProtocol() +{ + +} + + +status_t +InboundProtocol::AppendMessage(const entry_ref& ref) +{ + return false; +} + + +status_t +InboundProtocol::MarkMessageAsRead(const entry_ref& ref, bool read) +{ + BNode node(&ref); + BString statusString = (read == true) ? "Read" : "New"; + if (node.WriteAttr("MAIL:status", B_STRING_TYPE, 0, statusString.String(), + statusString.Length()) < 0) + return B_ERROR; + return B_OK; +} + + +OutboundProtocol::OutboundProtocol(BMailAccountSettings* settings) + : + MailProtocol(settings) +{ + LoadFilters(fAccountSettings.OutboundSettings()); +} + + +OutboundProtocol::~OutboundProtocol() +{ + +} + + +const uint32 kMsgMoveFile = '&MoF'; +const uint32 kMsgDeleteFile = '&DeF'; +const uint32 kMsgFileRenamed = '&FiR'; +const uint32 kMsgFileDeleted = '&FDe'; +const uint32 kMsgInit = '&Ini'; + + +MailProtocolThread::MailProtocolThread(MailProtocol* protocol) + : + fMailProtocol(protocol) +{ + PostMessage(kMsgInit); +} + + +void +MailProtocolThread::SetStopNow() +{ + fMailProtocol->SetStopNow(); +} + + +void +MailProtocolThread::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgInit: + fMailProtocol->SetProtocolThread(this); + break; + + case kMsgMoveFile: + { + entry_ref file; + message->FindRef("file", &file); + entry_ref dir; + message->FindRef("directory", &dir); + BDirectory directory(&dir); + fMailProtocol->MoveMessage(file, directory); + break; + } + + case kMsgDeleteFile: + { + entry_ref file; + message->FindRef("file", &file); + fMailProtocol->DeleteMessage(file); + break; + } + + case kMsgFileRenamed: + { + entry_ref from; + message->FindRef("from", &from); + entry_ref to; + message->FindRef("to", &to); + fMailProtocol->FileRenamed(from, to); + } + + case kMsgFileDeleted: + { + node_ref node; + message->FindInt32("device",&node.device); + message->FindInt64("node", &node.node); + fMailProtocol->FileDeleted(node); + } + + default: + BLooper::MessageReceived(message); + } +} + + +void +MailProtocolThread::TriggerFileMove(const entry_ref& ref, BDirectory& dir) +{ + BMessage message(kMsgMoveFile); + message.AddRef("file", &ref); + BEntry entry; + dir.GetEntry(&entry); + entry_ref dirRef; + entry.GetRef(&dirRef); + message.AddRef("directory", &dirRef); + PostMessage(&message); +} + + +void +MailProtocolThread::TriggerFileDeletion(const entry_ref& ref) +{ + BMessage message(kMsgDeleteFile); + message.AddRef("file", &ref); + PostMessage(&message); +} + + +void +MailProtocolThread::TriggerFileRenamed(const entry_ref& from, + const entry_ref& to) +{ + BMessage message(kMsgFileRenamed); + message.AddRef("from", &from); + message.AddRef("to", &to); + PostMessage(&message); +} + + +void +MailProtocolThread::TriggerFileDeleted(const node_ref& node) +{ + BMessage message(kMsgFileDeleted); + message.AddInt32("device", node.device); + message.AddInt64("node", node.node); + PostMessage(&message); +} + + +const uint32 kMsgSyncMessages = '&SyM'; +const uint32 kMsgFetchBody = '&FeB'; +const uint32 kMsgMarkMessageAsRead = '&MaR'; +const uint32 kMsgDeleteMessage = '&DeM'; +const uint32 kMsgAppendMessage = '&ApM'; + + +InboundProtocolThread::InboundProtocolThread(InboundProtocol* protocol) + : + MailProtocolThread(protocol), + fProtocol(protocol) +{ + +} + + +InboundProtocolThread::~InboundProtocolThread() +{ + fProtocol->SetProtocolThread(NULL); +} + + +void +InboundProtocolThread::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgSyncMessages: + { + status_t status = fProtocol->SyncMessages(); + _NotiyMailboxSynced(status); + break; + } + + case kMsgFetchBody: + { + entry_ref ref; + message->FindRef("ref", &ref); + status_t status = fProtocol->FetchBody(ref); + if (status != B_OK || !message->FindBool("launch")) + break; + BMessage argv(B_ARGV_RECEIVED); + BPath path(&ref); + argv.AddString("argv", "E-mail"); + argv.AddString("argv", path.Path()); + argv.AddInt32("argc", 2); + be_roster->Launch("text/x-email", &argv); + break; + } + + case kMsgMarkMessageAsRead: + { + entry_ref ref; + message->FindRef("ref", &ref); + bool read = message->FindBool("read"); + fProtocol->MarkMessageAsRead(ref, read); + break; + } + + case kMsgDeleteMessage: + { + entry_ref ref; + message->FindRef("ref", &ref); + fProtocol->DeleteMessage(ref); + break; + } + + case kMsgAppendMessage: + { + entry_ref ref; + message->FindRef("ref", &ref); + fProtocol->AppendMessage(ref); + break; + } + + default: + MailProtocolThread::MessageReceived(message); + } +} + + +void +InboundProtocolThread::SyncMessages() +{ + PostMessage(kMsgSyncMessages); +} + + +void +InboundProtocolThread::FetchBody(const entry_ref& ref, bool launch) +{ + BMessage message(kMsgFetchBody); + message.AddRef("ref", &ref); + message.AddBool("launch", launch); + PostMessage(&message); +} + + +void +InboundProtocolThread::MarkMessageAsRead(const entry_ref& ref, bool read) +{ + BMessage message(kMsgMarkMessageAsRead); + message.AddRef("ref", &ref); + message.AddBool("read", read); + PostMessage(&message); +} + + +void +InboundProtocolThread::DeleteMessage(const entry_ref& ref) +{ + BMessage message(kMsgDeleteMessage); + message.AddRef("ref", &ref); + PostMessage(&message); +} + + +void +InboundProtocolThread::AppendMessage(const entry_ref& ref) +{ + BMessage message(kMsgAppendMessage); + message.AddRef("ref", &ref); + PostMessage(&message); +} + + +void +InboundProtocolThread::_NotiyMailboxSynced(status_t status) +{ + for (int i = 0; i < fProtocol->CountFilter(); i++) + fProtocol->FilterAt(i)->MailboxSynced(status); +} + + +const uint32 kMsgSendMessage = '&SeM'; + + +OutboundProtocolThread::OutboundProtocolThread(OutboundProtocol* protocol) + : + MailProtocolThread(protocol), + fProtocol(protocol) +{ + +} + + +OutboundProtocolThread::~OutboundProtocolThread() +{ + fProtocol->SetProtocolThread(NULL); +} + + +void +OutboundProtocolThread::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgSendMessage: + { + std::vector mails; + for (int32 i = 0; ;i++) { + entry_ref ref; + if (message->FindRef("ref", i, &ref) != B_OK) + break; + mails.push_back(ref); + } + size_t size = message->FindInt32("size"); + fProtocol->SendMessages(mails, size); + break; + } + + default: + MailProtocolThread::MessageReceived(message); + } +} + + +void +OutboundProtocolThread::SendMessages(const std::vector& mails, + size_t totalBytes) +{ + BMessage message(kMsgSendMessage); + for (unsigned int i = 0; i < mails.size(); i++) + message.AddRef("ref", &mails[i]); + message.AddInt32("size", totalBytes); + PostMessage(&message); } diff --git a/src/kits/mail/MailSettings.cpp b/src/kits/mail/MailSettings.cpp index 4eae38d241..8f36495255 100644 --- a/src/kits/mail/MailSettings.cpp +++ b/src/kits/mail/MailSettings.cpp @@ -25,120 +25,12 @@ #include -class BMailSettings; - namespace MailInternal { status_t WriteMessageFile(const BMessage& archive, const BPath& path, const char* name); } -// #pragma mark - Chain methods - - -// TODO! -BMailChain* -NewMailChain() -{ - // attempted solution: use time(NULL) and hope it's unique. Is there a better idea? - // note that two chains in two second is quite possible. how to fix this? - // maybe we could | in some bigtime_t as well. hrrm... - - // This is to fix a problem with generating the correct id for chains. - // Basically if the chains dir does not exist, the first time you create - // an account both the inbound and outbound chains will be called 0. - create_directory("/boot/home/config/settings/Mail/chains",0777); - - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY, &path); - path.Append("Mail/chains"); - BDirectory chain_dir(path.Path()); - BDirectory outbound_dir(&chain_dir,"outbound"), inbound_dir(&chain_dir,"inbound"); - - // TODO(bga): A better way to do all this anyway is to write the chain - // information to the settings message (a new field would be added). - - // Lock Chain directory to avoid concurrent access. - chain_dir.Lock(); - - int32 id = -1; //-----When inc'ed, we start with 0---- - chain_dir.ReadAttr("last_issued_chain_id",B_INT32_TYPE,0,&id,sizeof(id)); - - BString string_id; - - do { - id++; - string_id = ""; - string_id << id; - } while ((outbound_dir.Contains(string_id.String())) - || (inbound_dir.Contains(string_id.String()))); - - chain_dir.WriteAttr("last_issued_chain_id",B_INT32_TYPE,0,&id,sizeof(id)); - - return new BMailChain(id); -} - - -BMailChain* -GetMailChain(uint32 id) -{ - return new BMailChain(id); -} - - -status_t -GetInboundMailChains(BList *list) -{ - BPath path; - status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - if (status != B_OK) { - fprintf(stderr, "Couldn't find user settings directory: %s\n", - strerror(status)); - return status; - } - - path.Append("Mail/chains/inbound"); - BDirectory chainDirectory(path.Path()); - entry_ref ref; - - while (chainDirectory.GetNextRef(&ref) == B_OK) { - char *end; - uint32 id = strtoul(ref.name, &end, 10); - - if (!end || *end == '\0') - list->AddItem((void*)new BMailChain(id)); - } - - return B_OK; -} - - -status_t -GetOutboundMailChains(BList *list) -{ - BPath path; - status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); - if (status != B_OK) { - fprintf(stderr, "Couldn't find user settings directory: %s\n", - strerror(status)); - return status; - } - - path.Append("Mail/chains/outbound"); - BDirectory chainDirectory(path.Path()); - entry_ref ref; - - while (chainDirectory.GetNextRef(&ref) == B_OK) { - char *end; - uint32 id = strtoul(ref.name, &end, 10); - if (!end || *end == '\0') - list->AddItem((void*)new BMailChain(id)); - } - - return B_OK; -} - - // #pragma mark - BMailSettings @@ -398,16 +290,555 @@ BMailSettings::SetSendOnlyIfPPPUp(bool yes) } -uint32 -BMailSettings::DefaultOutboundChainID() +int32 +BMailSettings::DefaultOutboundAccount() { - return fData.FindInt32("DefaultOutboundChainID"); + return fData.FindInt32("DefaultOutboundAccount"); } void -BMailSettings::SetDefaultOutboundChainID(uint32 to) +BMailSettings::SetDefaultOutboundAccount(int32 to) { - if (fData.ReplaceInt32("DefaultOutboundChainID",to)) - fData.AddInt32("DefaultOutboundChainID",to); + if (fData.ReplaceInt32("DefaultOutboundAccount",to)) + fData.AddInt32("DefaultOutboundAccount",to); +} + + +BMailAccounts::BMailAccounts() +{ + BPath path; + status_t status = AccountsPath(path); + if (status != B_OK) + return; + + BDirectory dir(path.Path()); + if (dir.InitCheck() != B_OK) + return; + BEntry entry; + while (dir.GetNextEntry(&entry) != B_ENTRY_NOT_FOUND) { + BMailAccountSettings* account = new BMailAccountSettings(entry); + if (account->InitCheck() != B_OK) + continue; + fAccounts.AddItem(account); + } +} + + +status_t +BMailAccounts::AccountsPath(BPath& path) +{ + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if (status != B_OK) + return status; + return path.Append("Mail/accounts"); +} + + +BMailAccounts::~BMailAccounts() +{ + for (int i = 0; i < fAccounts.CountItems(); i++) + delete fAccounts.ItemAt(i); +} + + +int32 +BMailAccounts::CountAccounts() +{ + return fAccounts.CountItems(); +} + + +BMailAccountSettings* +BMailAccounts::AccountAt(int32 index) +{ + return fAccounts.ItemAt(index); +} + + +BMailAccountSettings* +BMailAccounts::AccountByID(int32 id) +{ + for (int i = 0; i < fAccounts.CountItems(); i++) { + BMailAccountSettings* account = fAccounts.ItemAt(i); + if (account->AccountID() == id) + return account; + } + return NULL; +} + + +BMailAccountSettings* +BMailAccounts::AccountByName(const char* name) +{ + for (int i = 0; i < fAccounts.CountItems(); i++) { + BMailAccountSettings* account = fAccounts.ItemAt(i); + if (strcmp(account->Name(), name) == 0) + return account; + } + return NULL; +} + + +using std::vector; + + +AddonSettings::AddonSettings() + : + fModified(false) +{ + +} + + +bool +AddonSettings::Load(const BMessage& message) +{ + if (message.FindRef("ref", &fAddonRef) != B_OK) + return false; + if (message.FindMessage("settings", &fSettings) != B_OK) + return false; + fModified = false; + return true; +} + + +bool +AddonSettings::Save(BMessage& message) +{ + message.AddRef("ref", &fAddonRef); + message.AddMessage("settings", &fSettings); + fModified = false; + return true; +} + + +void +AddonSettings::SetAddonRef(const entry_ref& ref) +{ + fAddonRef = ref; +} + + +const entry_ref& +AddonSettings::AddonRef() const +{ + return fAddonRef; +} + + +const BMessage& +AddonSettings::Settings() const +{ + return fSettings; +} + + +BMessage& +AddonSettings::EditSettings() +{ + fModified = true; + return fSettings; +} + + +bool +AddonSettings::HasBeenModified() +{ + return fModified; +} + + +bool +MailAddonSettings::Load(const BMessage& message) +{ + if (!AddonSettings::Load(message)) + return false; + + type_code typeFound; + int32 countFound; + message.GetInfo("filters", &typeFound, &countFound); + if (typeFound != B_MESSAGE_TYPE) + return false; + + for (int i = 0; i < countFound; i++) { + int32 index = AddFilterSettings(); + AddonSettings& filterSettings = fFiltersSettings[index]; + BMessage filterMessage; + message.FindMessage("filters", i, &filterMessage); + if (!filterSettings.Load(filterMessage)) + RemoveFilterSettings(index); + } + return true; +} + + +bool +MailAddonSettings::Save(BMessage& message) +{ + if (!AddonSettings::Save(message)) + return false; + + for (int i = 0; i < CountFilterSettings(); i++) { + BMessage filter; + AddonSettings& filterSettings = fFiltersSettings[i]; + filterSettings.Save(filter); + message.AddMessage("filters", &filter); + } + return true; +} + + +int32 +MailAddonSettings::CountFilterSettings() +{ + return fFiltersSettings.size(); +} + + +int32 +MailAddonSettings::AddFilterSettings(const entry_ref* ref) +{ + AddonSettings filterSettings; + if (ref != NULL) + filterSettings.SetAddonRef(*ref); + fFiltersSettings.push_back(filterSettings); + return fFiltersSettings.size() - 1; +} + + +bool +MailAddonSettings::RemoveFilterSettings(int32 index) +{ + fFiltersSettings.erase(fFiltersSettings.begin() + index); + return true; +} + + +bool +MailAddonSettings::MoveFilterSettings(int32 from, int32 to) +{ + if (from < 0 || from >= (int32)fFiltersSettings.size() || to < 0 + || to >= (int32)fFiltersSettings.size()) + return false; + AddonSettings fromSettings = fFiltersSettings[from]; + fFiltersSettings.erase(fFiltersSettings.begin() + from); + if (to == (int32)fFiltersSettings.size()) + fFiltersSettings.push_back(fromSettings); + else { + std::vector::iterator it = fFiltersSettings.begin() + to; + fFiltersSettings.insert(it, fromSettings); + } + return true; +} + + +AddonSettings* +MailAddonSettings::FilterSettingsAt(int32 index) +{ + if (index < 0 || index >= (int32)fFiltersSettings.size()) + return NULL; + return &fFiltersSettings[index]; +} + + +bool +MailAddonSettings::HasBeenModified() +{ + if (AddonSettings::HasBeenModified()) + return true; + for (unsigned int i = 0; i < fFiltersSettings.size(); i++) { + if (fFiltersSettings[i].HasBeenModified()) + return true; + } + return false; +} + + +// #pragma mark - + + +BMailAccountSettings::BMailAccountSettings() + : + fStatus(B_OK), + fModified(true) +{ + fAccountID = real_time_clock(); +} + + +BMailAccountSettings::BMailAccountSettings(BEntry account) + : + fAccountFile(account), + fModified(false) +{ + fStatus = Reload(); +} + + +BMailAccountSettings::~BMailAccountSettings() +{ + +} + + +void +BMailAccountSettings::SetAccountID(int32 id) +{ + fModified = true; + fAccountID = id; +} + + +int32 +BMailAccountSettings::AccountID() +{ + return fAccountID; +} + + +void +BMailAccountSettings::SetName(const char* name) +{ + fModified = true; + fAccountName = name; +} + + +const char* +BMailAccountSettings::Name() const +{ + return fAccountName; +} + + +void +BMailAccountSettings::SetRealName(const char* realName) +{ + fModified = true; + fRealName = realName; +} + + +const char* +BMailAccountSettings::RealName() const +{ + return fRealName; +} + + +void +BMailAccountSettings::SetReturnAddress(const char* returnAddress) +{ + fModified = true; + fReturnAdress = returnAddress; +} + + +const char* +BMailAccountSettings::ReturnAddress() const +{ + return fReturnAdress; +} + + +bool +BMailAccountSettings::SetInboundAddon(const char* name) +{ + BPath path; + status_t status = find_directory(B_BEOS_ADDONS_DIRECTORY, &path); + if (status != B_OK) + return false; + path.Append("mail_daemon"); + path.Append("inbound_protocols"); + path.Append(name); + entry_ref ref; + get_ref_for_path(path.Path(), &ref); + fInboundSettings.SetAddonRef(ref); + + fModified = true; + return true; +} + + +bool +BMailAccountSettings::SetOutboundAddon(const char* name) +{ + BPath path; + status_t status = find_directory(B_BEOS_ADDONS_DIRECTORY, &path); + if (status != B_OK) + return false; + path.Append("mail_daemon"); + path.Append("outbound_protocols"); + path.Append(name); + entry_ref ref; + get_ref_for_path(path.Path(), &ref); + fOutboundSettings.SetAddonRef(ref); + + fModified = true; + return true; +} + + +const entry_ref& +BMailAccountSettings::InboundPath() const +{ + return fInboundSettings.AddonRef(); +} + + +const entry_ref& +BMailAccountSettings::OutboundPath() const +{ + return fOutboundSettings.AddonRef(); +} + + +MailAddonSettings& +BMailAccountSettings::InboundSettings() +{ + return fInboundSettings; +} + + +MailAddonSettings& +BMailAccountSettings::OutboundSettings() +{ + return fOutboundSettings; +} + + +bool +BMailAccountSettings::HasInbound() +{ + return BEntry(&fInboundSettings.AddonRef()).Exists(); +} + + +bool +BMailAccountSettings::HasOutbound() +{ + return BEntry(&fOutboundSettings.AddonRef()).Exists(); +} + + +status_t +BMailAccountSettings::Reload() +{ + BFile file(&fAccountFile, B_READ_ONLY); + status_t status = file.InitCheck(); + if (status != B_OK) + return status; + BMessage settings; + settings.Unflatten(&file); + + int32 id; + if (settings.FindInt32("id", &id) == B_OK) + fAccountID = id; + settings.FindString("name", &fAccountName); + settings.FindString("real_name", &fRealName); + settings.FindString("return_address", &fReturnAdress); + + BMessage inboundSettings; + settings.FindMessage("inbound", &inboundSettings); + fInboundSettings.Load(inboundSettings); + BMessage outboundSettings; + settings.FindMessage("outbound", &outboundSettings); + fOutboundSettings.Load(outboundSettings); + + fModified = false; + return B_OK; +} + + +status_t +BMailAccountSettings::Save() +{ + fModified = false; + + BMessage settings; + settings.AddInt32("id", fAccountID); + settings.AddString("name", fAccountName); + settings.AddString("real_name", fRealName); + settings.AddString("return_address", fReturnAdress); + + BMessage inboundSettings; + fInboundSettings.Save(inboundSettings); + settings.AddMessage("inbound", &inboundSettings); + BMessage outboundSettings; + fOutboundSettings.Save(outboundSettings); + settings.AddMessage("outbound", &outboundSettings); + + BEntry oldEntry = fAccountFile; + status_t status = _CreateAccountFile(); + if (status != B_OK) + return status; + oldEntry.Remove(); + + BPath path; + fAccountFile.GetPath(&path); + + BFile file(&fAccountFile, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); + status = file.InitCheck(); + if (status != B_OK) + return status; + return settings.Flatten(&file); +} + + +status_t +BMailAccountSettings::Delete() +{ + return fAccountFile.Remove(); +} + + +bool +BMailAccountSettings::HasBeenModified() +{ + if (fInboundSettings.HasBeenModified()) + return true; + if (fOutboundSettings.HasBeenModified()) + return true; + return fModified; +} + + +const BEntry& +BMailAccountSettings::AccountFile() +{ + return fAccountFile; +} + + +status_t +BMailAccountSettings::_CreateAccountFile() +{ + BPath path; + status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + if (status != B_OK) + return status; + path.Append("Mail/accounts"); + create_directory(path.Path(), 777); + + BString fileName = fAccountName; + if (fileName == "") + fileName << fAccountID; + for (int i = 0; ; i++) { + BString testFileName = fileName; + if (i != 0) { + testFileName += "_"; + testFileName << i; + } + BPath testPath(path); + testPath.Append(testFileName); + BEntry testEntry(testPath.Path()); + if (!testEntry.Exists()) { + fileName = testFileName; + break; + } + } + + path.Append(fileName); + return fAccountFile.SetTo(path.Path()); } diff --git a/src/kits/mail/ProtocolConfigView.cpp b/src/kits/mail/ProtocolConfigView.cpp index a261119756..2cf0cf5c15 100644 --- a/src/kits/mail/ProtocolConfigView.cpp +++ b/src/kits/mail/ProtocolConfigView.cpp @@ -24,6 +24,89 @@ class _EXPORT BMailProtocolConfigView; #include "ProtocolConfigView.h" +const char* kPartialDownloadLimit = "partial_download_limit"; + + +BodyDownloadConfig::BodyDownloadConfig() + : + BView(BRect(0,0,50,50), "body_config", B_FOLLOW_ALL_SIDES, 0) +{ + const char *partial_text = MDR_DIALECT_CHOICE ( + "Partially download messages larger than", + "部分ダウンロードする"); + + BRect r(0, 0, 280, 15); + fPartialBox = new BCheckBox(r, "size_if", partial_text, + new BMessage('SIZF')); + fPartialBox->ResizeToPreferred(); + + r = fPartialBox->Frame(); + r.OffsetBy(17,r.Height() + 1); + r.right = r.left + be_plain_font->StringWidth("0000") + 10; + fSizeBox = new BTextControl(r, "size", "", "", NULL); + + r.OffsetBy(r.Width() + 5,0); + fBytesLabel = new BStringView(r, "kb", "KB"); + AddChild(fBytesLabel); + fSizeBox->SetDivider(0); + + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + AddChild(fPartialBox); + AddChild(fSizeBox); + ResizeToPreferred(); +} + + +void +BodyDownloadConfig::SetTo(MailAddonSettings& addonSettings) +{ + const BMessage* settings = &addonSettings.Settings(); + + if (settings->HasInt32(kPartialDownloadLimit)) { + BString kb; + kb << int32(settings->FindInt32(kPartialDownloadLimit)/1024); + fSizeBox->SetText(kb.String()); + fPartialBox->SetValue(B_CONTROL_ON); + } else + fSizeBox->SetEnabled(true); +} + + +void +BodyDownloadConfig::MessageReceived(BMessage *msg) +{ + if (msg->what != 'SIZF') + return BView::MessageReceived(msg); + fSizeBox->SetEnabled(fPartialBox->Value()); +} + + +void +BodyDownloadConfig::AttachedToWindow() +{ + fPartialBox->SetTarget(this); + fPartialBox->ResizeToPreferred(); +} + + +void +BodyDownloadConfig::GetPreferredSize(float *width, float *height) +{ + *height = fSizeBox->Frame().bottom + 5; + *width = 200; +} + + +status_t +BodyDownloadConfig::Archive(BMessage* into, bool) const +{ + into->RemoveName(kPartialDownloadLimit); + if (fPartialBox->Value()) + into->AddInt32(kPartialDownloadLimit, atoi(fSizeBox->Text()) * 1024); + return B_OK; +} + + namespace { //--------------------Support functions and #defines--------------- @@ -48,7 +131,7 @@ TextControl(BView *parent,const char *name) BTextControl * -AddTextField (BRect &rect, const char *name, const char *label) +AddTextField(BRect &rect, const char *name, const char *label) { BTextControl *text_control = new BTextControl(rect,name,label,"",NULL,B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); // text_control->SetDivider(be_plain_font->StringWidth(label)); @@ -104,7 +187,9 @@ FindWidestLabel(BView *view) //----------------Real code---------------------- BMailProtocolConfigView::BMailProtocolConfigView(uint32 options_mask) : - BView (BRect(0,0,100,20), "protocol_config_view", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW) + BView (BRect(0,0,100,20), "protocol_config_view", B_FOLLOW_LEFT + | B_FOLLOW_TOP, B_WILL_DRAW), + fBodyDownloadConfig(NULL) { BRect rect(5,5,245,25); SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); @@ -147,6 +232,12 @@ BMailProtocolConfigView::BMailProtocolConfigView(uint32 options_mask) AddChild(box); } + if (options_mask & B_MAIL_PROTOCOL_PARTIAL_DOWNLOAD) { + fBodyDownloadConfig = new BodyDownloadConfig(); + fBodyDownloadConfig->MoveBy(0, rect.bottom + 5); + AddChild(fBodyDownloadConfig); + } + // resize views float height; GetPreferredSize(&width,&height); @@ -165,21 +256,23 @@ BMailProtocolConfigView::~BMailProtocolConfigView() void -BMailProtocolConfigView::SetTo(BMessage *archive) +BMailProtocolConfigView::SetTo(MailAddonSettings& settings) { + const BMessage* archive = &settings.Settings(); + BString host = archive->FindString("server"); if (archive->HasInt32("port")) host << ':' << archive->FindInt32("port"); - SetTextControl(this,"host",host.String()); - SetTextControl(this,"user",archive->FindString("username")); + SetTextControl(this,"host", host.String()); + SetTextControl(this,"user", archive->FindString("username")); - char *password = get_passwd(archive,"cpasswd"); + char *password = get_passwd(archive, "cpasswd"); if (password) { - SetTextControl(this,"pass",password); + SetTextControl(this,"pass", password); delete[] password; } else - SetTextControl(this,"pass",archive->FindString("password")); + SetTextControl(this,"pass", archive->FindString("password")); if (archive->HasInt32("flavor")) { BMenuField *menu = (BMenuField *)(FindView("flavor")); @@ -216,6 +309,9 @@ BMailProtocolConfigView::SetTo(BMessage *archive) else box->SetEnabled(false); } + + if (fBodyDownloadConfig) + fBodyDownloadConfig->SetTo(settings); } @@ -286,7 +382,7 @@ BMailProtocolConfigView::MessageReceived(BMessage *msg) status_t -BMailProtocolConfigView::Archive(BMessage *into, bool) const +BMailProtocolConfigView::Archive(BMessage *into, bool deep) const { const char *host = TextControl((BView *)this,"host"); int32 port = -1; @@ -348,7 +444,9 @@ BMailProtocolConfigView::Archive(BMessage *into, bool) const if (into->ReplaceBool("delete_remote_when_local",false) != B_OK) into->AddBool("delete_remote_when_local",false); } - + + if (fBodyDownloadConfig) + fBodyDownloadConfig->Archive(into, deep); return B_OK; } @@ -365,5 +463,11 @@ BMailProtocolConfigView::GetPreferredSize(float *width, float *height) minWidth = 250; *width = minWidth + 10; *height = (CountChildren() * sItemHeight) + 5; + + if (fBodyDownloadConfig) { + float bodyW, bodyH; + fBodyDownloadConfig->GetPreferredSize(&bodyW, &bodyH); + *height+= bodyH; + } } diff --git a/src/kits/mail/RemoteStorageProtocol.cpp b/src/kits/mail/RemoteStorageProtocol.cpp deleted file mode 100644 index 5d3c3918c4..0000000000 --- a/src/kits/mail/RemoteStorageProtocol.cpp +++ /dev/null @@ -1,438 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -class _EXPORT BRemoteMailStorageProtocol; - -#include -#include -#include - -using std::map; - -namespace { - -void GetSubFolders(BDirectory *of, BStringList *folders, const char *prepend = ""); - -class UpdateHandler : public BHandler { - public: - UpdateHandler(BRemoteMailStorageProtocol *prot, const char *dest) - : fProtocol(prot), fDestination(dest) - { - node_ref ref; - fDestination.GetNodeRef(&ref); - fDestinationNode = ref.node; - } - - virtual ~UpdateHandler() - { - stop_watching(this); - } - - void MessageReceived(BMessage *msg) - { - switch (msg->what) { - case 'INIT': { - if (fProtocol->InitCheck() < B_OK) - return; - - ((BMailChainRunner *)(Looper()))->ReportProgress(0, 0, - "Synchronizing Mailboxes"); - - BStringList subdirs; - GetSubFolders(&fDestination, &subdirs); - BStringList to_delete; - BStringList to_add; - subdirs.NotThere(fProtocol->mailboxes, &to_add); - if (subdirs.CountItems() != 0) { - // If it's a virgin mailfolder, the user probably just configured - // his machine and probably *doesn't* want all his mail folders deleted :) - subdirs.NotHere(fProtocol->mailboxes, &to_delete); - } - for (int32 i = 0; i < to_add.CountItems(); i++) { - if (fProtocol->CreateMailbox(to_add[i]) != B_OK) - continue; - - fProtocol->mailboxes += to_add[i]; - fProtocol->SyncMailbox(to_add[i]); - } - - fProtocol->CheckForDeletedMessages(); - // Refresh the manifest list, delete messages in locally deleted folders - - for (int32 i = 0; i < to_delete.CountItems(); i++) { - if (to_delete[i][0] == 0) - continue; - if (fProtocol->DeleteMailbox(to_delete[i]) == B_OK) - fProtocol->mailboxes -= to_delete[i]; - } - - entry_ref ref; - BEntry entry; - fDestination.GetEntry(&entry); - entry.GetRef(&ref); - BPath path(&ref), work_path(path); - BNode node(&ref); - node_ref watcher; - node.GetNodeRef(&watcher); - watch_node(&watcher,B_WATCH_DIRECTORY,this); - - for (int32 i = 0; i < fProtocol->mailboxes.CountItems(); i++) { - work_path = path; - work_path.Append(fProtocol->mailboxes[i]); - node.SetTo(work_path.Path()); - node.GetNodeRef(&watcher); - fNodes[watcher.node] = strdup(fProtocol->mailboxes[i]); - if (fProtocol->mailboxes[i][0] == 0) { - // We've covered this in the parent monitor - continue; - } - watch_node(&watcher, B_WATCH_DIRECTORY, this); - fProtocol->SyncMailbox(fProtocol->mailboxes[i]); - } - ((BMailChainRunner *)(Looper()))->ResetProgress(); - break; - } - - case B_NODE_MONITOR: { - int32 opcode; - if (msg->FindInt32("opcode", &opcode) < B_OK) - break; - - int64 directory, node(msg->FindInt64("node")); - dev_t device(msg->FindInt32("device")); - - bool is_dir; - { - node_ref item_ref; - item_ref.node = node; - item_ref.device = device; - BDirectory dir(&item_ref); - is_dir = (dir.InitCheck() == B_OK); - } - - if (opcode == B_ENTRY_MOVED) { - ino_t from, to; - msg->FindInt64("from directory", &from); - msg->FindInt64("to directory", &to); - const char *from_mb(fNodes[from]), *to_mb(fNodes[to]); - if (to == fDestinationNode) - to_mb = ""; - if (from == fDestinationNode) - from_mb = ""; - if (from_mb == NULL) { - msg->AddInt64("directory", to); - opcode = B_ENTRY_CREATED; - } else if (to_mb == NULL) { - msg->AddInt64("directory", from); - if (is_dir) - opcode = B_ENTRY_REMOVED; - } else { - if (!is_dir) { - { - node_ref item_ref; - item_ref.node = to; - item_ref.device = device; - BDirectory dir(&item_ref); - BNode node(&dir,msg->FindString("name")); - // Why in HELL can't you make a BNode from a node_ref? - - if (node.InitCheck() != B_OK) { - // We're late, it's already gone elsewhere. Ignore for now. - break; - } - - BString id; - node.ReadAttrString("MAIL:unique_id", &id); - id.Truncate(id.FindLast('/')); - if (id == to_mb) { - // Already where it belongs, no need to do anything - break; - } - } - - snooze(uint64(5e5)); - fProtocol->SyncMailbox(to_mb); - - //node.WriteAttrString("MAIL:unique_id",&id); - - fProtocol->CheckForDeletedMessages(); - } else { - BString mb; - if (to_mb[0] == 0) - mb = msg->FindString("name"); - else { - mb = to_mb; - mb << '/' << msg->FindString("name"); - } - if (strcmp(mb.String(), fNodes[node]) == 0) - break; - if (fProtocol->CreateMailbox(mb.String()) < B_OK) - break; - fProtocol->mailboxes += mb.String(); - fProtocol->SyncMailbox(mb.String()); - fProtocol->CheckForDeletedMessages(); - fProtocol->DeleteMailbox(fNodes[node]); - fProtocol->mailboxes -= fNodes[node]; - free((void *)fNodes[node]); - fNodes[node] = strdup(mb.String()); - } - break; - } - } - - msg->FindInt64("directory", &directory); - switch (opcode) { - case B_ENTRY_CREATED: - if (!is_dir) { - const char *dir = fNodes[directory]; - snooze(500000); - // half a second - - if (dir == NULL) - dir = ""; - - if (!fProtocol->mailboxes.HasItem(dir)) - break; - - { - node_ref nodeRef; - nodeRef.node = directory; - nodeRef.device = device; - BDirectory dir(&nodeRef); - - BNode node(&dir, msg->FindString("name")); - if (node.InitCheck() != B_OK) - break; //-- We're late, it's already gone elsewhere. Ignore for now. - } - - fProtocol->SyncMailbox(fNodes[directory]); - } else { - BString mb; - if (directory == fDestinationNode) - mb = msg->FindString("name"); - else { - mb = fNodes[directory]; - mb << '/' << msg->FindString("name"); - } - if (fProtocol->CreateMailbox(mb.String()) < B_OK) - break; - - fNodes[node] = strdup(mb.String()); - fProtocol->mailboxes += mb.String(); - fProtocol->SyncMailbox(mb.String()); - node_ref ref; - ref.device = device; - ref.node = node; - watch_node(&ref, B_WATCH_DIRECTORY, this); - } - break; - case B_ENTRY_REMOVED: - fProtocol->CheckForDeletedMessages(); - if ((is_dir) && (fNodes[node] != NULL)) { - fProtocol->DeleteMailbox(fNodes[node]); - fProtocol->mailboxes -= fNodes[node]; - free((void *)fNodes[node]); - fNodes[node] = NULL; - node_ref ref; - ref.device = device; - ref.node = node; - watch_node(&ref, B_STOP_WATCHING, this); - } - break; - } - } - break; - } - } - - private: - BRemoteMailStorageProtocol *fProtocol; - BDirectory fDestination; - - map fNodes; - ino_t fDestinationNode; -}; - - -void -GetSubFolders(BDirectory *of, BStringList *folders, const char *prepend) -{ - of->Rewind(); - - BEntry entry; - while (of->GetNextEntry(&entry) == B_OK) { - if (!entry.IsDirectory()) - continue; - - BDirectory subDirectory(&entry); - - char buffer[B_FILE_NAME_LENGTH]; - entry.GetName(buffer); - - BString path = prepend; - path << buffer << '/'; - GetSubFolders(&subDirectory, folders, path.String()); - path = prepend; - path << buffer; - *folders += path.String(); - } -} - -} // unnamed namspace - - -BRemoteMailStorageProtocol::BRemoteMailStorageProtocol(BMessage *settings, - BMailChainRunner *runner) - : BMailProtocol(settings, runner) -{ - handler = new UpdateHandler(this, runner->Chain()->MetaData()->FindString("path")); - runner->AddHandler(handler); - runner->PostMessage('INIT', handler); -} - - -BRemoteMailStorageProtocol::~BRemoteMailStorageProtocol() -{ - delete handler; -} - - -//----BMailProtocol stuff - - -status_t -BRemoteMailStorageProtocol::GetMessage(const char *uid, - BPositionIO **outFile, BMessage *outHeaders, - BPath *outFolderLocation) -{ - BString folder(uid), id; - { - BString raw(uid); - folder.Truncate(raw.FindLast('/')); - raw.CopyInto(id, raw.FindLast('/') + 1, raw.Length()); - } - - *outFolderLocation = folder.String(); - return GetMessage(folder.String(), id.String(), outFile, outHeaders); -} - - -status_t -BRemoteMailStorageProtocol::DeleteMessage(const char *uid) -{ - BString folder(uid), id; - { - BString raw(uid); - int32 j = raw.FindLast('/'); - folder.Truncate(j); - raw.CopyInto(id, j + 1, raw.Length()); - } - - status_t err; - if ((err = DeleteMessage(folder.String(), id.String())) < B_OK) - return err; - - *unique_ids -= uid; - return B_OK; -} - - -void -BRemoteMailStorageProtocol::SyncMailbox(const char *mailbox) -{ - BPath path(runner->Chain()->MetaData()->FindString("path")); - path.Append(mailbox); - - BDirectory folder(path.Path()); - - BEntry entry; - BString string; - uint32 chain; - bool append; - - if (!mailboxes.HasItem(mailbox)) - return; // -- Basic Sanity Checking - - while (folder.GetNextEntry(&entry) == B_OK) { - if (!entry.IsFile()) - continue; - - BFile file; - while (file.SetTo(&entry, B_READ_WRITE) == B_BUSY) - snooze(100); - append = false; - - while (file.Lock() != B_OK) - snooze(100); - file.Unlock(); - - if (file.ReadAttr("MAIL:chain", B_INT32_TYPE, 0, &chain, sizeof(chain)) < B_OK) - append = true; - - if (chain != runner->Chain()->ID()) { - uint32 pendingChain(~0UL), flags(0); - file.ReadAttr("MAIL:pending_chain", B_INT32_TYPE, 0, &pendingChain, sizeof(chain)); - file.ReadAttr("MAIL:flags", B_INT32_TYPE, 0, &flags, sizeof(flags)); - - if (pendingChain == runner->Chain()->ID() - && BMailChain(chain).ChainDirection() == outbound - && (flags & B_MAIL_PENDING) != 0) { - // Ignore this message, recode the chain attribute at the next SyncMailbox() - continue; - } - - if (pendingChain == runner->Chain()->ID()) { - chain = runner->Chain()->ID(); - file.WriteAttr("MAIL:chain", B_INT32_TYPE, 0, &chain, sizeof(chain)); - append = false; - } else - append = true; - } - if (file.ReadAttrString("MAIL:unique_id", &string) < B_OK) - append = true; - - BString folder(string), id(""); - int32 j = string.FindLast('/'); - if (!append && j >= 0) { - folder.Truncate(j); - string.CopyInto(id, j + 1, string.Length()); - if (folder == mailbox) - continue; - } else - append = true; - - if (append) { - // ToDo: We should check for partial messages here - AddMessage(mailbox, &file, &id); - } else - CopyMessage(folder.String(), mailbox, &id); - - string = mailbox; - string << '/' << id; - /*file.RemoveAttr("MAIL:unique_id"); - file.RemoveAttr("MAIL:chain");*/ - chain = runner->Chain()->ID(); - - int32 flags = 0; - file.ReadAttr("MAIL:flags", B_INT32_TYPE, 0, &flags, sizeof(flags)); - - if (flags & B_MAIL_PENDING) - file.WriteAttr("MAIL:pending_chain", B_INT32_TYPE, 0, &chain, sizeof(chain)); - else - file.WriteAttr("MAIL:chain", B_INT32_TYPE, 0, &chain, sizeof(chain)); - file.WriteAttrString("MAIL:unique_id", &string); - *manifest += string.String(); - *unique_ids += string.String(); - string = runner->Chain()->Name(); - file.WriteAttrString("MAIL:account", &string); - } -} - diff --git a/src/kits/mail/b_mail_message.cpp b/src/kits/mail/b_mail_message.cpp deleted file mode 100644 index 89a579330e..0000000000 --- a/src/kits/mail/b_mail_message.cpp +++ /dev/null @@ -1,138 +0,0 @@ -/* BMailMessage - compatibility wrapper to our mail message class -** -** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. -*/ - - -//------This entire document is a horrible, horrible hack. I apologize. -#include - -class _EXPORT BMailMessage; - -#include - -#include -#include - -#include - -struct CharsetConversionEntry -{ - const char *charset; - uint32 flavor; -}; - -extern const CharsetConversionEntry mail_charsets[]; - - -BMailMessage::BMailMessage(void) - : fFields((BList *)(new BEmailMessage())) -{ -} - -BMailMessage::~BMailMessage(void) -{ - delete ((BEmailMessage *)(fFields)); -} - -status_t BMailMessage::AddContent(const char *text, int32 length, - uint32 encoding, bool /*clobber*/) -{ - BTextMailComponent *comp = new BTextMailComponent; - BMemoryIO io(text,length); - comp->SetDecodedData(&io); - - comp->SetEncoding(quoted_printable,encoding); - - //if (clobber) - ((BEmailMessage *)(fFields))->AddComponent(comp); - - return B_OK; -} - -status_t BMailMessage::AddContent(const char *text, int32 length, - const char *encoding, bool /*clobber*/) -{ - BTextMailComponent *comp = new BTextMailComponent(); - BMemoryIO io(text,length); - comp->SetDecodedData(&io); - - uint32 encode = B_ISO1_CONVERSION; - //-----I'm assuming that encoding is one of the RFC charsets - //-----there are no docs. Am I right? - if (encoding != NULL) { - for (int32 i = 0; mail_charsets[i].charset != NULL; i++) { - if (strcasecmp(encoding,mail_charsets[i].charset) == 0) { - encode = mail_charsets[i].flavor; - break; - } - } - } - - comp->SetEncoding(quoted_printable,encode); - - //if (clobber) - ((BEmailMessage *)(fFields))->AddComponent(comp); - - return B_OK; -} - -status_t BMailMessage::AddEnclosure(entry_ref *ref, bool /*clobber*/) -{ - ((BEmailMessage *)(fFields))->Attach(ref); - return B_OK; -} - -status_t BMailMessage::AddEnclosure(const char *path, bool /*clobber*/) -{ - BEntry entry(path); - status_t status; - if ((status = entry.InitCheck()) < B_OK) - return status; - - entry_ref ref; - if ((status = entry.GetRef(&ref)) < B_OK) - return status; - - ((BEmailMessage *)(fFields))->Attach(&ref); - return B_OK; -} - -status_t BMailMessage::AddEnclosure(const char *MIME_type, void *data, int32 len, - bool /*clobber*/) -{ - BSimpleMailAttachment *attach = new BSimpleMailAttachment; - attach->SetDecodedData(data,len); - attach->SetHeaderField("Content-Type",MIME_type); - - ((BEmailMessage *)(fFields))->AddComponent(attach); - return B_OK; -} - -status_t BMailMessage::AddHeaderField(uint32 /*encoding*/, const char *field_name, const char *str, - bool /*clobber*/) -{ - //printf("First AddHeaderField. Args are %s%s\n",field_name,str); - - BString string = field_name; - string.Truncate(string.Length() - 2); //----BMailMessage includes the ": " - ((BEmailMessage *)(fFields))->SetHeaderField(string.String(),str); - return B_OK; -} - -status_t BMailMessage::AddHeaderField(const char *field_name, const char *str, - bool /*clobber*/) -{ - //printf("Second AddHeaderField. Args are %s%s\n",field_name,str); - BString string = field_name; - string.Truncate(string.Length() - 2); //----BMailMessage includes the ": " - ((BEmailMessage *)(fFields))->SetHeaderField(string.String(),str); - return B_OK; -} - -status_t BMailMessage::Send(bool send_now, - bool /*remove_when_I_have_completed_sending_this_message_to_your_preferred_SMTP_server*/) -{ - return ((BEmailMessage *)(fFields))->Send(send_now); -} - diff --git a/src/kits/mail/c_mail_api.cpp b/src/kits/mail/c_mail_api.cpp deleted file mode 100644 index 2589472a4e..0000000000 --- a/src/kits/mail/c_mail_api.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* C-mail API - compatibility function (stubs) for the old mail kit -** -** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. -*/ - - -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - - -_EXPORT status_t check_for_mail(int32 * incoming_count) -{ - status_t err = BMailDaemon::CheckMail(true); - if (err < B_OK) - return err; - - if (incoming_count != NULL) - *incoming_count = BMailDaemon::CountNewMessages(true); - - return B_OK; -} - -_EXPORT status_t send_queued_mail(void) -{ - return BMailDaemon::SendQueuedMail(); -} - -_EXPORT int32 count_pop_accounts(void) -{ - BPath path; - status_t status = find_directory(B_USER_SETTINGS_DIRECTORY,&path); - if (status < B_OK) - return 0; - - path.Append("Mail/chains/inbound"); - BDirectory dir(path.Path()); - return dir.CountEntries(); -} - -_EXPORT status_t get_mail_notification(mail_notification *notification) -{ - notification->alert = true; - notification->beep = false; - return B_OK; -} - -_EXPORT status_t set_mail_notification(mail_notification *, bool) -{ - return B_NO_REPLY; -} - -_EXPORT status_t get_pop_account(mail_pop_account* account, int32 index) -{ - status_t err = B_OK; - const char *password, *passwd; - BMessage settings; - - BList chains; - GetInboundMailChains(&chains); - - BMailChain *chain = (BMailChain *)(chains.ItemAt(index)); - if (chain == NULL) { - err = B_BAD_INDEX; - goto clean_up; //------Eek! A goto! - } - - chain->GetFilter(0,&settings); - strcpy(account->pop_name,settings.FindString("username")); - strcpy(account->pop_host,settings.FindString("server")); - strcpy(account->real_name,chain->MetaData()->FindString("real_name")); - strcpy(account->reply_to,chain->MetaData()->FindString("reply_to")); - - password = settings.FindString("password"); - passwd = get_passwd(&settings,"cpasswd"); - if (passwd) - password = passwd; - strcpy(account->pop_password,password); - - //-------Note that we don't do the scheduling flags - - clean_up: - for (int32 i = 0; i < chains.CountItems(); i++) - delete (BMailChain *)chains.ItemAt(i); - - return err; -} - -_EXPORT status_t set_pop_account(mail_pop_account *, int32, bool) -{ - return B_NO_REPLY; -} - -_EXPORT status_t get_smtp_host(char* buffer) -{ - BMailChain chain(BMailSettings().DefaultOutboundChainID()); - status_t err = chain.InitCheck(); - if (err < B_OK) - return err; - - BMessage settings; - err = chain.GetFilter(chain.CountFilters() - 1,&settings); - if (err < B_OK) - return err; - - if (settings.HasString("server")) - strcpy(buffer,settings.FindString("server")); - else - return B_NAME_NOT_FOUND; - - return B_OK; -} - -_EXPORT status_t set_smtp_host(char * /* host */, bool /* save */) -{ - return B_NO_REPLY; -} - -_EXPORT status_t forward_mail(entry_ref *ref, const char *recipients, bool now) -{ - BFile file(ref, O_RDONLY); - status_t status = file.InitCheck(); - if (status < B_OK) - return status; - - BEmailMessage mail(&file); - mail.SetTo(recipients); - - return mail.Send(now); -} - diff --git a/src/kits/mail/cpp_abi_base64.c b/src/kits/mail/cpp_abi_base64.c deleted file mode 100644 index cf31cc2da8..0000000000 --- a/src/kits/mail/cpp_abi_base64.c +++ /dev/null @@ -1,28 +0,0 @@ -#include - -#if __MWERKS__ - #define encode_base64__local_abi encode_base64__FPcPcx - #define decode_base64__local_abi decode_base64__FPcPcxb - #define USETHISFILEATALL 1 -#elif __GNUC__ <= 2 - #define encode_base64__local_abi encode_base64__FPcT0x - #define decode_base64__local_abi decode_base64__FPcT0xb - #define USETHISFILEATALL 1 -#endif - -#if USETHISFILEATALL /* If we are using GCC >= 3 or something else, we clearly have given up on binary compat anyway */ - -ssize_t encode_base64__local_abi(char *out, char *in, off_t length); -ssize_t decode_base64__local_abi(char *out, char *in, off_t length, char); - -_EXPORT ssize_t encode_base64__local_abi(char *out, char *in, off_t length) { - return encode_base64(out,in,length,0 /* headerMode */); -} - -_EXPORT ssize_t decode_base64__local_abi(char *out, char *in, off_t length, char nothing) { - nothing = '\0'; - return decode_base64(out,in,length); -} - -#endif - diff --git a/src/kits/mail/crypt.cpp b/src/kits/mail/crypt.cpp index 27a2126e5a..bc56c90aba 100644 --- a/src/kits/mail/crypt.cpp +++ b/src/kits/mail/crypt.cpp @@ -13,7 +13,7 @@ static const char key[PASSWORD_LENGTH + 1] = "Dr. Zoidberg Enterprises, BeMail"; -_EXPORT char *get_passwd(BMessage *msg,const char *name) +_EXPORT char *get_passwd(const BMessage *msg,const char *name) { char *encryptedPassword; ssize_t length; diff --git a/src/kits/mail/mail_util.cpp b/src/kits/mail/mail_util.cpp index cc3282670f..1733dc2207 100644 --- a/src/kits/mail/mail_util.cpp +++ b/src/kits/mail/mail_util.cpp @@ -1376,6 +1376,56 @@ parse_header(BMessage &headers, BPositionIO &input) } +_EXPORT status_t +extract_from_header(const BString& header, const BString& field, + BString& target) +{ + int32 headerLength = header.Length(); + int32 fieldEndPos = 0; + while (true) { + int32 pos = header.IFindFirst(field, fieldEndPos); + if (pos < 0) + return B_BAD_VALUE; + fieldEndPos = pos + field.Length(); + + if (pos != 0 && header.ByteAt(pos - 1) != '\n') + continue; + if (header.ByteAt(fieldEndPos) == ':') + break; + } + fieldEndPos++; + + int32 crPos = fieldEndPos; + while (true) { + fieldEndPos = crPos; + crPos = header.FindFirst('\n', crPos); + if (crPos < 0) + crPos = headerLength; + BString temp; + header.CopyInto(temp, fieldEndPos, crPos - fieldEndPos); + if (header.ByteAt(crPos - 1) == '\r') { + temp.Truncate(temp.Length() - 1); + temp += " "; + } + target += temp; + crPos++; + if (crPos >= headerLength) + break; + char nextByte = header.ByteAt(crPos); + if (nextByte != ' ' && nextByte != '\t') + break; + crPos++; + } + + size_t bufferSize = target.Length(); + char* buffer = target.LockBuffer(bufferSize); + size_t length = rfc2047_to_utf8(&buffer, &bufferSize, bufferSize); + target.UnlockBuffer(length); + + return B_OK; +} + + _EXPORT void extract_address(BString &address) { diff --git a/src/servers/mail/DeskbarView.cpp b/src/servers/mail/DeskbarView.cpp index 2a62712542..eb14123d77 100644 --- a/src/servers/mail/DeskbarView.cpp +++ b/src/servers/mail/DeskbarView.cpp @@ -222,10 +222,10 @@ DeskbarView::MessageReceived(BMessage* message) case MD_CHECK_SEND_NOW: // also happens in DeskbarView::MouseUp() with // B_TERTIARY_MOUSE_BUTTON pressed - BMailDaemon::CheckMail(true); + BMailDaemon::CheckAndSendQueuedMail(); break; case MD_CHECK_FOR_MAILS: - BMailDaemon::CheckMail(false,message->FindString("account")); + BMailDaemon::CheckMail(message->FindInt32("account")); break; case MD_SEND_MAILS: BMailDaemon::SendQueuedMail(); @@ -365,7 +365,7 @@ DeskbarView::MouseUp(BPoint pos) } if (fLastButtons & B_TERTIARY_MOUSE_BUTTON) - BMailDaemon::CheckMail(true); + BMailDaemon::CheckMail(); } @@ -556,32 +556,30 @@ DeskbarView::_BuildMenu() item->SetEnabled(false); } - BList list; - GetInboundMailChains(&list); - + BMailAccounts accounts; if (modifiers() & B_SHIFT_KEY) { - BMenu *chainMenu = new BMenu( + BMenu *accountMenu = new BMenu( MDR_DIALECT_CHOICE ("Check for mails only","R) メール受信のみ")); BFont font; menu->GetFont(&font); - chainMenu->SetFont(&font); + accountMenu->SetFont(&font); - for (int32 i = 0; i < list.CountItems(); i++) { - BMailChain* chain = (BMailChain*)list.ItemAt(i); + for (int32 i = 0; i < accounts.CountAccounts(); i++) { + BMailAccountSettings* account = accounts.AccountAt(i); BMessage* message = new BMessage(MD_CHECK_FOR_MAILS); - message->AddString("account", chain->Name()); + message->AddInt32("account", account->AccountID()); - chainMenu->AddItem(new BMenuItem(chain->Name(), message)); - delete chain; + accountMenu->AddItem(new BMenuItem(account->Name(), message)); } - if (list.IsEmpty()) { + if (accounts.CountAccounts() == 0) { item = new BMenuItem("", NULL); item->SetEnabled(false); - chainMenu->AddItem(item); + accountMenu->AddItem(item); } - chainMenu->SetTargetForItems(this); - menu->AddItem(new BMenuItem(chainMenu, new BMessage(MD_CHECK_FOR_MAILS))); + accountMenu->SetTargetForItems(this); + menu->AddItem(new BMenuItem(accountMenu, + new BMessage(MD_CHECK_FOR_MAILS))); // Not used: // menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE ( @@ -593,7 +591,7 @@ DeskbarView::_BuildMenu() menu->AddItem(item = new BMenuItem( MDR_DIALECT_CHOICE ("Check for mail now", "C) メールチェック"), new BMessage(MD_CHECK_SEND_NOW))); - if (list.IsEmpty()) + if (accounts.CountAccounts() == 0) item->SetEnabled(false); } diff --git a/src/kits/mail/ErrorLogWindow.cpp b/src/servers/mail/ErrorLogWindow.cpp similarity index 84% rename from src/kits/mail/ErrorLogWindow.cpp rename to src/servers/mail/ErrorLogWindow.cpp index 3c407c298e..0cdeddba9e 100644 --- a/src/kits/mail/ErrorLogWindow.cpp +++ b/src/servers/mail/ErrorLogWindow.cpp @@ -53,14 +53,18 @@ class ErrorPanel : public BView { ErrorLogWindow::ErrorLogWindow(BRect rect, const char *name, window_type type) - : BWindow(rect, name, type, - B_NO_WORKSPACE_ACTIVATION | B_NOT_MINIMIZABLE | B_ASYNCHRONOUS_CONTROLS) + : + BWindow(rect, name, type, B_NO_WORKSPACE_ACTIVATION | B_NOT_MINIMIZABLE + | B_ASYNCHRONOUS_CONTROLS), + fIsRunning(false) { rect = Bounds(); rect.right -= B_V_SCROLL_BAR_WIDTH; view = new ErrorPanel(rect); AddChild(new BScrollView("ErrorScroller", view, B_FOLLOW_ALL_SIDES, 0, false, true)); + Show(); + Hide(); } @@ -69,6 +73,12 @@ ErrorLogWindow::AddError(alert_type type, const char *message, const char *tag, { ErrorPanel *panel = (ErrorPanel *)view; + // first call? + if (!fIsRunning) { + fIsRunning = true; + Show(); + } + Lock(); Error *newError = new Error(BRect(0, panel->add_next_at, panel->Bounds().right, @@ -101,8 +111,11 @@ ErrorLogWindow::QuitRequested() { Hide(); - while (view->CountChildren() != 0) - view->RemoveChild(view->ChildAt(0)); + while (view->CountChildren() != 0) { + BView* child = view->ChildAt(0); + view->RemoveChild(child); + delete child; + } ErrorPanel *panel = (ErrorPanel *)(view); panel->add_next_at = 0; @@ -135,7 +148,13 @@ ErrorLogWindow::FrameResized(float newWidth, float newHeight) // #pragma mark - -Error::Error(BRect rect,alert_type atype,const char *tag,const char *message,bool timestamp,rgb_color bkg) : BView(rect,"error",B_FOLLOW_LEFT | B_FOLLOW_RIGHT | B_FOLLOW_TOP,B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS), type(atype) { +Error::Error(BRect rect, alert_type atype, const char *tag, const char *message, + bool timestamp,rgb_color bkg) + : + BView(rect,"error",B_FOLLOW_LEFT | B_FOLLOW_RIGHT + | B_FOLLOW_TOP,B_NAVIGABLE | B_WILL_DRAW | B_FRAME_EVENTS), + type(atype) +{ SetViewColor(bkg); SetLowColor(bkg); @@ -148,16 +167,21 @@ Error::Error(BRect rect,alert_type atype,const char *tag,const char *message,boo BString msgString(message); msgString.RemoveAll("\r"); - BTextView *view = new BTextView(BRect(20,0,rect.Width(),rect.Height()),"error_display",BRect(0,3,rect.Width() - 20 - 3,LONG_MAX),B_FOLLOW_ALL_SIDES); + BTextView *view = new BTextView(BRect(20, 0, rect.Width(), rect.Height()), + "error_display", BRect(0,3,rect.Width() - 20 - 3, LONG_MAX), + B_FOLLOW_ALL_SIDES); view->SetLowColor(bkg); view->SetViewColor(bkg); view->SetText(msgString.String()); view->MakeSelectable(true); view->SetStylable(true); view->MakeEditable(false); - - if (tag != NULL) - view->Insert(0,tag,strlen(tag),&array); + + if (tag != NULL) { + BString tagString(tag); + tagString += " "; + view->Insert(0, tagString.String(), tagString.Length(), &array); + } if (timestamp) { array.runs[0].color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),B_DARKEN_2_TINT); diff --git a/src/kits/mail/ErrorLogWindow.h b/src/servers/mail/ErrorLogWindow.h similarity index 92% rename from src/kits/mail/ErrorLogWindow.h rename to src/servers/mail/ErrorLogWindow.h index 0f8ca3f43b..3e79953a91 100644 --- a/src/kits/mail/ErrorLogWindow.h +++ b/src/servers/mail/ErrorLogWindow.h @@ -5,7 +5,7 @@ #include class ErrorLogWindow : public BWindow { - public: +public: ErrorLogWindow(BRect rect, const char *name, window_type type); void AddError(alert_type type,const char *message,const char *tag = NULL,bool timestamp = true); @@ -13,8 +13,9 @@ class ErrorLogWindow : public BWindow { bool QuitRequested(); void FrameResized(float new_width, float new_height); - private: +private: BView *view; + bool fIsRunning; }; #endif // ZOIDBERG_MAIL_ERRORLOGWINDOW_H diff --git a/src/servers/mail/Jamfile b/src/servers/mail/Jamfile index 4e77dd696b..4eb4772382 100644 --- a/src/servers/mail/Jamfile +++ b/src/servers/mail/Jamfile @@ -17,8 +17,12 @@ AddResources mail_daemon : mail_daemon.rdef DeskbarViewIcons.rdef ; Server mail_daemon : DeskbarView.cpp + ErrorLogWindow.cpp LEDAnimation.cpp + MailDaemon.cpp main.cpp + Notifier.cpp + StatusWindow.cpp ; LinkAgainst mail_daemon : be libmail.so tracker $(TARGET_LIBSTDC++) $(TARGET_NETWORK_LIBS) ; diff --git a/src/servers/mail/MailDaemon.cpp b/src/servers/mail/MailDaemon.cpp new file mode 100644 index 0000000000..d1c318f7b4 --- /dev/null +++ b/src/servers/mail/MailDaemon.cpp @@ -0,0 +1,860 @@ +/* + * Copyright 2007-2011, Haiku, Inc. All rights reserved. + * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved. + * Copyright 2011, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ + + +#include "MailDaemon.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +void +makeIndices() +{ + const char* stringIndices[] = { + B_MAIL_ATTR_CC, B_MAIL_ATTR_FROM, B_MAIL_ATTR_NAME, + B_MAIL_ATTR_PRIORITY, B_MAIL_ATTR_REPLY, B_MAIL_ATTR_STATUS, + B_MAIL_ATTR_SUBJECT, B_MAIL_ATTR_TO, B_MAIL_ATTR_THREAD, + NULL + }; + + // add mail indices for all devices capable of querying + + int32 cookie = 0; + dev_t device; + while ((device = next_dev(&cookie)) >= B_OK) { + fs_info info; + if (fs_stat_dev(device, &info) < 0 + || (info.flags & B_FS_HAS_QUERY) == 0) + continue; + + for (int32 i = 0; stringIndices[i]; i++) + fs_create_index(device, stringIndices[i], B_STRING_TYPE, 0); + + fs_create_index(device, "MAIL:draft", B_INT32_TYPE, 0); + fs_create_index(device, B_MAIL_ATTR_WHEN, B_INT32_TYPE, 0); + fs_create_index(device, B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0); + fs_create_index(device, B_MAIL_ATTR_ACCOUNT, B_INT32_TYPE, 0); + } +} + + +void +addAttribute(BMessage& msg, const char* name, const char* publicName, + int32 type = B_STRING_TYPE, bool viewable = true, bool editable = false, + int32 width = 200) +{ + msg.AddString("attr:name", name); + msg.AddString("attr:public_name", publicName); + msg.AddInt32("attr:type", type); + msg.AddBool("attr:viewable", viewable); + msg.AddBool("attr:editable", editable); + msg.AddInt32("attr:width", width); + msg.AddInt32("attr:alignment", B_ALIGN_LEFT); +} + + +// #pragma mark - + + +using std::map; +using std::vector; + + +MailDaemonApp::MailDaemonApp() + : + BApplication("application/x-vnd.Be-POST"), + + fAutoCheckRunner(NULL) +{ + fErrorLogWindow = new ErrorLogWindow(BRect(200, 200, 500, 250), + "Mail daemon status log", B_TITLED_WINDOW); + fMailStatusWindow = new MailStatusWindow(BRect(40, 400, 360, 400), + "Mail Status", fSettingsFile.ShowStatusWindow()); + // install MimeTypes, attributes, indices, and the + // system beep add startup + MakeMimeTypes(); + makeIndices(); + add_system_beep_event("New E-mail"); +} + + +MailDaemonApp::~MailDaemonApp() +{ + delete fAutoCheckRunner; + + for (int32 i = 0; i < fQueries.CountItems(); i++) + delete fQueries.ItemAt(i); + + delete fLEDAnimation; + + AccountMap::const_iterator it = fAccounts.begin(); + for (; it != fAccounts.end(); it++) + _RemoveAccount(it); +} + + +void +MailDaemonApp::ReadyToRun() +{ + InstallDeskbarIcon(); + + _InitAccounts(); + _UpdateAutoCheck(fSettingsFile.AutoCheckInterval()); + + BVolume volume; + BVolumeRoster roster; + + fNewMessages = 0; + + while (roster.GetNextVolume(&volume) == B_OK) { + //{char name[255];volume.GetName(name);printf("Volume: %s\n",name);} + + BQuery* query = new BQuery; + + query->SetTarget(this); + query->SetVolume(&volume); + query->PushAttr(B_MAIL_ATTR_STATUS); + query->PushString("New"); + query->PushOp(B_EQ); + query->PushAttr("BEOS:TYPE"); + query->PushString("text/x-email"); + query->PushOp(B_EQ); + query->PushAttr("BEOS:TYPE"); + query->PushString("text/x-partial-email"); + query->PushOp(B_EQ); + query->PushOp(B_OR); + query->PushOp(B_AND); + query->Fetch(); + + BEntry entry; + while (query->GetNextEntry(&entry) == B_OK) + fNewMessages++; + + fQueries.AddItem(query); + } + + BString string; + MDR_DIALECT_CHOICE( + if (fNewMessages > 0) + string << fNewMessages; + else + string << "No"; + if (fNewMessages != 1) + string << " new messages."; + else + string << " new message.";, + if (fNewMessages > 0) + string << fNewMessages << " 通の未読メッセージがあります "; + else + string << "未読メッセージはありません"; + ); + fCentralBeep = false; + fMailStatusWindow->SetDefaultMessage(string); + + fLEDAnimation = new LEDAnimation; + SetPulseRate(1000000); +} + + +void +MailDaemonApp::RefsReceived(BMessage* message) +{ + fMailStatusWindow->Activate(true); + + entry_ref ref; + for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { + BNode node(&ref); + if (node.InitCheck() < B_OK) + continue; + + int32 account; + if (node.ReadAttr("MAIL:account", B_INT32_TYPE, 0, &account, + sizeof(account)) < 0) + continue; + + InboundProtocolThread* protocol = _FindInboundProtocol(account); + if (!protocol) + continue; + bool launch = true; + protocol->FetchBody(ref, launch); + } +} + + +void +MailDaemonApp::_InitAccounts() +{ + BMailAccounts accounts; + for (int i = 0; i < accounts.CountAccounts(); i++) + _InitAccount(*accounts.AccountAt(i)); +} + + +void +MailDaemonApp::_InitAccount(BMailAccountSettings& settings) +{ + account_protocols account; + account.inboundProtocol = _CreateInboundProtocol(settings, + account.inboundImage); + if (account.inboundProtocol) { + DefaultNotifier* notifier = new DefaultNotifier(settings.Name(), true, + fErrorLogWindow, fMailStatusWindow); + account.inboundProtocol->SetMailNotifier(notifier); + + account.inboundThread = new InboundProtocolThread( + account.inboundProtocol); + account.inboundThread->Run(); + } + + account.outboundProtocol = _CreateOutboundProtocol(settings, + account.outboundImage); + if (account.outboundProtocol) { + DefaultNotifier* notifier = new DefaultNotifier(settings.Name(), false, + fErrorLogWindow, fMailStatusWindow); + account.outboundProtocol->SetMailNotifier(notifier); + + account.outboundThread = new OutboundProtocolThread( + account.outboundProtocol); + account.outboundThread->Run(); + } + + printf("account name %s, id %i, in %p, out %p\n", settings.Name(), + (int)settings.AccountID(), account.inboundProtocol, + account.outboundProtocol); + if (!account.inboundProtocol && !account.outboundProtocol) + return; + fAccounts[settings.AccountID()] = account; +} + + + +void +MailDaemonApp::_ReloadAccounts(BMessage* message) +{ + type_code typeFound; + int32 countFound; + message->GetInfo("account", &typeFound, &countFound); + if (typeFound != B_INT32_TYPE) + return; + + // reload accounts + BMailAccounts accounts; + + for (int i = 0; i < countFound; i++) { + int32 account = message->FindInt32("account", i); + AccountMap::const_iterator it = fAccounts.find(account); + if (it != fAccounts.end()) + _RemoveAccount(it); + BMailAccountSettings* settings = accounts.AccountByID(account); + if (settings) + _InitAccount(*settings); + } +} + + +void +MailDaemonApp::_RemoveAccount(AccountMap::const_iterator it) +{ + BMessage reply; + if (it->second.inboundThread) { + it->second.inboundThread->SetStopNow(); + BMessenger(it->second.inboundThread).SendMessage(B_QUIT_REQUESTED, + &reply); + } + if (it->second.outboundThread) { + it->second.outboundThread->SetStopNow(); + BMessenger(it->second.outboundThread).SendMessage(B_QUIT_REQUESTED, + &reply); + } + delete it->second.inboundProtocol; + delete it->second.outboundProtocol; + unload_add_on(it->second.inboundImage); + unload_add_on(it->second.outboundImage); +} + + +InboundProtocol* +MailDaemonApp::_CreateInboundProtocol(BMailAccountSettings& settings, + image_id& image) +{ + const entry_ref& entry = settings.InboundPath(); + + InboundProtocol* (*instantiate_protocol)(BMailAccountSettings*); + + BPath path(&entry); + image = load_add_on(path.Path()); + if (image < 0) + return NULL; + if (get_image_symbol(image, "instantiate_inbound_protocol", + B_SYMBOL_TYPE_TEXT, (void **)&instantiate_protocol) != B_OK) { + unload_add_on(image); + image = -1; + return NULL; + } + InboundProtocol* protocol = (*instantiate_protocol)(&settings); + return protocol; +} + + +OutboundProtocol* +MailDaemonApp::_CreateOutboundProtocol(BMailAccountSettings& settings, + image_id& image) +{ + const entry_ref& entry = settings.OutboundPath(); + + OutboundProtocol* (*instantiate_protocol)(BMailAccountSettings*); + + BPath path(&entry); + image = load_add_on(path.Path()); + if (image < 0) + return NULL; + if (get_image_symbol(image, "instantiate_outbound_protocol", + B_SYMBOL_TYPE_TEXT, (void **)&instantiate_protocol) != B_OK) { + unload_add_on(image); + image = -1; + return NULL; + } + OutboundProtocol* protocol = (*instantiate_protocol)(&settings); + return protocol; +} + + +InboundProtocolThread* +MailDaemonApp::_FindInboundProtocol(int32 account) +{ + AccountMap::iterator it = fAccounts.find(account); + if (it == fAccounts.end()) + return NULL; + return it->second.inboundThread; +} + + +OutboundProtocolThread* +MailDaemonApp::_FindOutboundProtocol(int32 account) +{ + if (account < 0) + account = BMailSettings().DefaultOutboundAccount(); + + AccountMap::iterator it = fAccounts.find(account); + if (it == fAccounts.end()) + return NULL; + return it->second.outboundThread; +} + + +void +MailDaemonApp::_UpdateAutoCheck(bigtime_t interval) +{ + if (interval > 0) { + if (fAutoCheckRunner != NULL) { + fAutoCheckRunner->SetInterval(interval); + fAutoCheckRunner->SetCount(-1); + } else + fAutoCheckRunner = new BMessageRunner(be_app_messenger, + new BMessage('moto'), interval); + } else { + delete fAutoCheckRunner; + fAutoCheckRunner = NULL; + } +} + + +void +MailDaemonApp::MessageReceived(BMessage* msg) +{ + switch (msg->what) { + case 'moto': + if (fSettingsFile.CheckOnlyIfPPPUp()) { + // TODO: check whether internet is up and running! + } + // supposed to fall through + case kMsgCheckAndSend: // check & send messages + msg->what = kMsgSendMessages; + PostMessage(msg); + // supposed to fall trough + case kMsgCheckMessage: // check messages + GetNewMessages(msg); + break; + + case kMsgSendMessages: // send messages + SendPendingMessages(msg); + break; + + case kMsgSettingsUpdated: + fSettingsFile.Reload(); + _UpdateAutoCheck(fSettingsFile.AutoCheckInterval()); + fMailStatusWindow->SetShowCriterion(fSettingsFile.ShowStatusWindow()); + break; + + case kMsgAccountsChanged: + _ReloadAccounts(msg); + break; + + case kMsgSetStatusWindowMode: // when to show the status window + { + int32 mode; + if (msg->FindInt32("ShowStatusWindow", &mode) == B_OK) + fMailStatusWindow->SetShowCriterion(mode); + break; + } + + case kMsgMarkMessageAsRead: + { + int32 account = msg->FindInt32("account"); + entry_ref ref; + if (msg->FindRef("ref", &ref) != B_OK) + break; + bool read = msg->FindBool("read"); + AccountMap::iterator it = fAccounts.find(account); + if (it == fAccounts.end()) + break; + InboundProtocol* inboundProtocol = it->second.inboundProtocol; + inboundProtocol->MarkMessageAsRead(ref, read); + break; + } + + case 'lkch': // status window look changed + case 'wsch': // workspace changed + fMailStatusWindow->PostMessage(msg); + break; + + case 'stwg': // Status window gone + { + BMessage reply('mnuc'); + reply.AddInt32("num_new_messages", fNewMessages); + + while ((msg = fFetchDoneRespondents.RemoveItemAt(0))) { + msg->SendReply(&reply); + delete msg; + } + + if (fAlertString != B_EMPTY_STRING) { + fAlertString.Truncate(fAlertString.Length() - 1); + BAlert* alert = new BAlert(MDR_DIALECT_CHOICE("New Messages", + "新着メッセージ"), fAlertString.String(), "OK", NULL, NULL, + B_WIDTH_AS_USUAL); + alert->SetFeel(B_NORMAL_WINDOW_FEEL); + alert->Go(NULL); + fAlertString = B_EMPTY_STRING; + } + + if (fCentralBeep) { + system_beep("New E-mail"); + fCentralBeep = false; + } + break; + } + + case 'mcbp': + if (fNewMessages > 0) + fCentralBeep = true; + break; + + case kMsgCountNewMessages: // Number of new messages + { + BMessage reply('mnuc'); // Mail New message Count + if (msg->FindBool("wait_for_fetch_done")) { + fFetchDoneRespondents.AddItem(DetachCurrentMessage()); + break; + } + + reply.AddInt32("num_new_messages", fNewMessages); + msg->SendReply(&reply); + break; + } + + case 'mblk': // Mail Blink + if (fNewMessages > 0) + fLEDAnimation->Start(); + break; + + case 'enda': // End Auto Check + delete fAutoCheckRunner; + fAutoCheckRunner = NULL; + break; + + case 'numg': + { + int32 numMessages = msg->FindInt32("num_messages"); + MDR_DIALECT_CHOICE( + fAlertString << numMessages << " new message"; + if (numMessages > 1) + fAlertString << 's'; + + fAlertString << " for " << msg->FindString("name") + << '\n';, + + fAlertString << msg->FindString("name") << "より\n" + << numMessages << " 通のメッセージが届きました  "; + ); + break; + } + + case B_QUERY_UPDATE: + { + int32 what; + msg->FindInt32("opcode", &what); + switch (what) { + case B_ENTRY_CREATED: + fNewMessages++; + break; + case B_ENTRY_REMOVED: + fNewMessages--; + break; + } + + BString string; + + MDR_DIALECT_CHOICE( + if (fNewMessages > 0) + string << fNewMessages; + else + string << "No"; + if (fNewMessages != 1) + string << " new messages."; + else + string << " new message.";, + + if (fNewMessages > 0) + string << fNewMessages << " 通の未読メッセージがあります"; + else + string << "未読メッセージはありません"; + ); + + fMailStatusWindow->SetDefaultMessage(string.String()); + break; + } + + default: + BApplication::MessageReceived(msg); + break; + } +} + + +void +MailDaemonApp::InstallDeskbarIcon() +{ + BDeskbar deskbar; + + if (!deskbar.HasItem("mail_daemon")) { + BRoster roster; + entry_ref ref; + + status_t status = roster.FindApp("application/x-vnd.Be-POST", &ref); + if (status < B_OK) { + fprintf(stderr, "Can't find application to tell deskbar: %s\n", + strerror(status)); + return; + } + + status = deskbar.AddItem(&ref); + if (status < B_OK) { + fprintf(stderr, "Can't add deskbar replicant: %s\n", strerror(status)); + return; + } + } +} + + +void +MailDaemonApp::RemoveDeskbarIcon() +{ + BDeskbar deskbar; + if (deskbar.HasItem("mail_daemon")) + deskbar.RemoveItem("mail_daemon"); +} + + +bool +MailDaemonApp::QuitRequested() +{ + RemoveDeskbarIcon(); + + return true; +} + + +void +MailDaemonApp::GetNewMessages(BMessage* msg) +{ + int32 account = -1; + if (msg->FindInt32("account", &account) == B_OK && account >= 0) { + InboundProtocolThread* protocol = _FindInboundProtocol(account); + if (!protocol) + return; + protocol->SyncMessages(); + return; + } + + // else check all accounts + AccountMap::const_iterator it = fAccounts.begin(); + for (; it != fAccounts.end(); it++) { + InboundProtocolThread* protocol = it->second.inboundThread; + if (!protocol) + continue; + protocol->SyncMessages(); + } +} + + +void +MailDaemonApp::MakeMimeTypes(bool remakeMIMETypes) +{ + // Add MIME database entries for the e-mail file types we handle. Either + // do a full rebuild from nothing, or just add on the new attributes that + // we support which the regular BeOS mail daemon didn't have. + + const char* types[2] = {"text/x-email", "text/x-partial-email"}; + BMimeType mime; + BMessage info; + + for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); i++) { + info.MakeEmpty(); + mime.SetTo(types[i]); + if (mime.InitCheck() != B_OK) { + fputs("could not init mime type.\n", stderr); + return; + } + + if (!mime.IsInstalled() || remakeMIMETypes) { + // install the full mime type + mime.Delete (); + mime.Install(); + + // Set up the list of e-mail related attributes that Tracker will + // let you display in columns for e-mail messages. + addAttribute(info, B_MAIL_ATTR_NAME, "Name"); + addAttribute(info, B_MAIL_ATTR_SUBJECT, "Subject"); + addAttribute(info, B_MAIL_ATTR_TO, "To"); + addAttribute(info, B_MAIL_ATTR_CC, "Cc"); + addAttribute(info, B_MAIL_ATTR_FROM, "From"); + addAttribute(info, B_MAIL_ATTR_REPLY, "Reply To"); + addAttribute(info, B_MAIL_ATTR_STATUS, "Status"); + addAttribute(info, B_MAIL_ATTR_PRIORITY, "Priority", B_STRING_TYPE, + true, true, 40); + addAttribute(info, B_MAIL_ATTR_WHEN, "When", B_TIME_TYPE, true, + false, 150); + addAttribute(info, B_MAIL_ATTR_THREAD, "Thread"); + addAttribute(info, B_MAIL_ATTR_ACCOUNT, "Account", B_STRING_TYPE, + true, false, 100); + mime.SetAttrInfo(&info); + + if (i == 0) { + mime.SetShortDescription("E-mail"); + mime.SetLongDescription("Electronic Mail Message"); + mime.SetPreferredApp("application/x-vnd.Be-MAIL"); + } else { + mime.SetShortDescription("Partial E-mail"); + mime.SetLongDescription("A Partially Downloaded E-mail"); + mime.SetPreferredApp("application/x-vnd.Be-POST"); + } + } else { + // Just add the e-mail related attribute types we use to the MIME + // system. + mime.GetAttrInfo(&info); + bool hasAccount = false; + bool hasThread = false; + bool hasSize = false; + const char* result; + for (int32 index = 0; info.FindString("attr:name", index, &result) + == B_OK; index++) { + if (!strcmp(result, B_MAIL_ATTR_ACCOUNT)) + hasAccount = true; + if (!strcmp(result, B_MAIL_ATTR_THREAD)) + hasThread = true; + if (!strcmp(result, "MAIL:fullsize")) + hasSize = true; + } + + if (!hasAccount) { + addAttribute(info, B_MAIL_ATTR_ACCOUNT, "Account", + B_STRING_TYPE, true, false, 100); + } + if (!hasThread) + addAttribute(info, B_MAIL_ATTR_THREAD, "Thread"); + /*if (!hasSize) + addAttribute(info,"MAIL:fullsize","Message Size",B_SIZE_T_TYPE,true,false,100);*/ + // TODO: Tracker can't display SIZT attributes. What a pain. + if (!hasAccount || !hasThread/* || !hasSize*/) + mime.SetAttrInfo(&info); + } + mime.Unset(); + } +} + + +struct send_mails_info { + send_mails_info() + { + totalSize = 0; + } + vector files; + off_t totalSize; +}; + + +void +MailDaemonApp::SendPendingMessages(BMessage* msg) +{ + BVolumeRoster roster; + BVolume volume; + + map messages; + + + int32 account = -1; + if (msg->FindInt32("account", &account) != B_OK) + account = -1; + + if (!msg->HasString("message_path")) { + while (roster.GetNextVolume(&volume) == B_OK) { + BQuery query; + query.SetVolume(&volume); + query.PushAttr(B_MAIL_ATTR_FLAGS); + query.PushInt32(B_MAIL_PENDING); + query.PushOp(B_EQ); + + query.PushAttr(B_MAIL_ATTR_FLAGS); + query.PushInt32(B_MAIL_PENDING | B_MAIL_SAVE); + query.PushOp(B_EQ); + + if (account >= 0) { + query.PushAttr("MAIL:account"); + query.PushInt32(account); + query.PushOp(B_EQ); + query.PushOp(B_AND); + } + + query.PushOp(B_OR); + query.Fetch(); + BEntry entry; + while (query.GetNextEntry(&entry) == B_OK) { + if (_IsEntryInTrash(entry)) + continue; + + BNode node; + while (node.SetTo(&entry) == B_BUSY) + snooze(1000); + if (!_IsPending(node)) + continue; + + int32 messageAccount; + if (node.ReadAttr("MAIL:account", B_INT32_TYPE, 0, + &messageAccount, sizeof(int32)) < 0) + messageAccount = -1; + + off_t size = 0; + node.GetSize(&size); + entry_ref ref; + entry.GetRef(&ref); + + messages[messageAccount].files.push_back(ref); + messages[messageAccount].totalSize += size; + } + } + } else { + const char* path; + if (msg->FindString("message_path", &path) != B_OK) + return; + + off_t size = 0; + if (BNode(path).GetSize(&size) != B_OK) + return; + BEntry entry(path); + entry_ref ref; + entry.GetRef(&ref); + + messages[account].files.push_back(ref); + messages[account].totalSize += size; + } + + map::iterator iter = messages.begin(); + for (; iter != messages.end(); iter++) { + OutboundProtocolThread* protocolThread = _FindOutboundProtocol( + iter->first); + if (!protocolThread) + continue; + + send_mails_info& info = iter->second; + if (info.files.size() == 0) + continue; + + MailProtocol* protocol = protocolThread->Protocol(); + + protocolThread->Lock(); + protocol->SetTotalItems(info.files.size()); + protocol->SetTotalItemsSize(info.totalSize); + protocolThread->Unlock(); + + protocolThread->SendMessages(iter->second.files, info.totalSize); + } + +} + + +void +MailDaemonApp::Pulse() +{ + bigtime_t idle = idle_time(); + if (fLEDAnimation->IsRunning() && idle < 100000) + fLEDAnimation->Stop(); +} + + +/*! Work-around for a broken index that contains out-of-date information. +*/ + +/* static */ +bool +MailDaemonApp::_IsPending(BNode& node) +{ + int32 flags; + if (node.ReadAttr(B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0, &flags, sizeof(int32)) + != (ssize_t)sizeof(int32)) + return false; + + return (flags & B_MAIL_PENDING) != 0; +} + + +/* static */ +bool +MailDaemonApp::_IsEntryInTrash(BEntry& entry) +{ + entry_ref ref; + entry.GetRef(&ref); + + BVolume volume(ref.device); + BPath path; + if (volume.InitCheck() != B_OK + || find_directory(B_TRASH_DIRECTORY, &path, false, &volume) != B_OK) + return false; + + BDirectory trash(path.Path()); + return trash.Contains(&entry); +} diff --git a/src/servers/mail/MailDaemon.h b/src/servers/mail/MailDaemon.h new file mode 100644 index 0000000000..82a0721d80 --- /dev/null +++ b/src/servers/mail/MailDaemon.h @@ -0,0 +1,114 @@ +/* + * Copyright 2007-2011, Haiku, Inc. All rights reserved. + * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved. + * Copyright 2011, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ +#ifndef MAIL_DAEMON_APP_H +#define MAIL_DAEMON_APP_H + + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "LEDAnimation.h" +#include "Notifier.h" + + +struct account_protocols { + account_protocols() { + inboundImage = -1; + inboundThread = NULL; + inboundProtocol = NULL; + outboundImage = -1; + outboundThread = NULL; + outboundProtocol = NULL; + } + image_id inboundImage; + InboundProtocolThread* inboundThread; + InboundProtocol* inboundProtocol; + image_id outboundImage; + OutboundProtocolThread* outboundThread; + OutboundProtocol* outboundProtocol; +}; + + +typedef std::map AccountMap; + + +class MailDaemonApp : public BApplication { +public: + MailDaemonApp(); + virtual ~MailDaemonApp(); + + virtual void MessageReceived(BMessage* message); + virtual void RefsReceived(BMessage* message); + + virtual void Pulse(); + virtual bool QuitRequested(); + virtual void ReadyToRun(); + + void InstallDeskbarIcon(); + void RemoveDeskbarIcon(); + + void SendPendingMessages(BMessage* message); + void GetNewMessages(BMessage* message); + + void MakeMimeTypes(bool remakeMIMETypes = false); + +private: + void _InitAccounts(); + void _InitAccount(BMailAccountSettings& settings); + void _ReloadAccounts(BMessage* message); + void _RemoveAccount(AccountMap::const_iterator it); + + InboundProtocol* _CreateInboundProtocol( + BMailAccountSettings& settings, + image_id& image); + OutboundProtocol* _CreateOutboundProtocol( + BMailAccountSettings& settings, + image_id& image); + + InboundProtocolThread* _FindInboundProtocol(int32 account); + OutboundProtocolThread* _FindOutboundProtocol(int32 account); + + void _UpdateAutoCheck(bigtime_t interval); + static bool _IsPending(BNode& node); + static bool _IsEntryInTrash(BEntry& entry); + +private: + BMessageRunner* fAutoCheckRunner; + BMailSettings fSettingsFile; + + int32 fNewMessages; + bool fCentralBeep; + // TRUE to do a beep when the status window closes. This happens + // when all mail has been received, so you get one beep for + // everything rather than individual beeps for each mail + // account. + // Set to TRUE by the 'mcbp' message that the mail Notification + // filter sends us, cleared when the beep is done. + BObjectList fFetchDoneRespondents; + BObjectList fQueries; + + LEDAnimation* fLEDAnimation; + + BString fAlertString; + + AccountMap fAccounts; + + ErrorLogWindow* fErrorLogWindow; + MailStatusWindow* fMailStatusWindow; +}; + + +#endif // MAIL_DAEMON_APP_H diff --git a/src/servers/mail/Notifier.cpp b/src/servers/mail/Notifier.cpp new file mode 100644 index 0000000000..76851bf67e --- /dev/null +++ b/src/servers/mail/Notifier.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2011, Haiku, Inc. All rights reserved. + * Copyright 2011, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ + + +#include "Notifier.h" + + +DefaultNotifier::DefaultNotifier(const char* accountName, bool inbound, + ErrorLogWindow* errorWindow, MailStatusWindow* statusWindow) + : + fAccountName(accountName), + fIsInbound(inbound), + fErrorWindow(errorWindow), + fStatusWindow(statusWindow) +{ + BString desc; + desc += (fIsInbound == true) ? "Fetching" : "Sending"; + desc += " mail for "; + desc += fAccountName; + + fStatusWindow->Lock(); + fStatusView = fStatusWindow->NewStatusView(desc, fIsInbound != false); + fStatusWindow->Unlock(); +} + + +DefaultNotifier::~DefaultNotifier() +{ + fStatusWindow->Lock(); + if (fStatusView->Window()) + fStatusWindow->RemoveView(fStatusView); + delete fStatusView; + fStatusWindow->Unlock(); +} + + +MailNotifier* +DefaultNotifier::Clone() +{ + return new DefaultNotifier(fAccountName, fIsInbound, fErrorWindow, + fStatusWindow); +} + + +void +DefaultNotifier::ShowError(const char* error) +{ + fErrorWindow->AddError(B_WARNING_ALERT, error, fAccountName); +} + + +void +DefaultNotifier::ShowMessage(const char* message) +{ + fErrorWindow->AddError(B_INFO_ALERT, message, fAccountName); +} + + +void +DefaultNotifier::SetTotalItems(int32 items) +{ + fStatusView->SetTotalItems(items); +} + + +void +DefaultNotifier::SetTotalItemsSize(int32 size) +{ + fStatusView->SetMaximum(size); +} + + +void +DefaultNotifier::ReportProgress(int bytes, int messages, const char* message) +{ + if (bytes != 0) + fStatusView->AddProgress(bytes); + + for (int i = 0; i < messages; i++) + fStatusView->AddItem(); + + if (message != NULL) + fStatusView->SetMessage(message); + + if (fStatusView->ItemsNow() == fStatusView->CountTotalItems()) + fStatusView->Reset(); +} + + +void +DefaultNotifier::ResetProgress(const char* message) +{ + fStatusView->Reset(); + if (message != NULL) + fStatusView->SetMessage(message); +} diff --git a/src/servers/mail/Notifier.h b/src/servers/mail/Notifier.h new file mode 100644 index 0000000000..edd9043e60 --- /dev/null +++ b/src/servers/mail/Notifier.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011, Haiku, Inc. All rights reserved. + * Copyright 2011, Clemens Zeidler + * Distributed under the terms of the MIT License. + */ +#ifndef NOTIFIER_H +#define NOTIFIER_H + + +#include + +#include "MailProtocol.h" + +#include "ErrorLogWindow.h" +#include "StatusWindow.h" + + +class DefaultNotifier : public MailNotifier { +public: + DefaultNotifier(const char* accountName, + bool inbound, ErrorLogWindow* errorWindow, + MailStatusWindow* statusWindow); + ~DefaultNotifier(); + + MailNotifier* Clone(); + + void ShowError(const char* error); + void ShowMessage(const char* message); + + void SetTotalItems(int32 items); + void SetTotalItemsSize(int32 size); + void ReportProgress(int bytes, int messages, + const char* message = NULL); + void ResetProgress(const char* message = NULL); + +private: + BString fAccountName; + bool fIsInbound; + ErrorLogWindow* fErrorWindow; + MailStatusWindow* fStatusWindow; + MailStatusView* fStatusView; +}; + +#endif //NOTIFIER_H diff --git a/src/kits/mail/StatusWindow.cpp b/src/servers/mail/StatusWindow.cpp similarity index 82% rename from src/kits/mail/StatusWindow.cpp rename to src/servers/mail/StatusWindow.cpp index 9e42170c1a..1cb9362c7f 100644 --- a/src/kits/mail/StatusWindow.cpp +++ b/src/servers/mail/StatusWindow.cpp @@ -9,7 +9,8 @@ //! The status window while fetching/sending mails -#include "status.h" +#include "StatusWindow.h" + #include "MailSettings.h" #include @@ -36,9 +37,10 @@ static BLocker sLock; -BMailStatusWindow::BMailStatusWindow(BRect rect, const char *name, +MailStatusWindow::MailStatusWindow(BRect rect, const char *name, uint32 showMode) - : BWindow(rect, name, B_MODAL_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, + : + BWindow(rect, name, B_MODAL_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, B_NOT_CLOSABLE | B_NO_WORKSPACE_ACTIVATION | B_NOT_V_RESIZABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AVOID_FRONT), fShowMode(showMode), @@ -118,10 +120,8 @@ BMailStatusWindow::BMailStatusWindow(BRect rect, const char *name, fFrame = Frame(); BPath path; - status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); + status_t status = BMailAccounts::AccountsPath(path); if (status == B_OK) { - path.Append("Mail/chains/inbound"); - create_directory(path.Path(), 0755); BDirectory chainDirectory(path.Path()); if (chainDirectory.GetNodeRef(&fChainDirectory) == B_OK) { // Watch this directory for changes @@ -137,10 +137,10 @@ BMailStatusWindow::BMailStatusWindow(BRect rect, const char *name, } -BMailStatusWindow::~BMailStatusWindow() +MailStatusWindow::~MailStatusWindow() { // remove all status_views, so we don't accidentally delete them - while (BMailStatusView *status_view = (BMailStatusView *)fStatusViews.RemoveItem(0L)) + while (MailStatusView *status_view = (MailStatusView *)fStatusViews.RemoveItem(0L)) RemoveView(status_view); BMailSettings general; @@ -157,19 +157,23 @@ BMailStatusWindow::~BMailStatusWindow() //! Activate the "Check Now" button only if there are inbound accounts void -BMailStatusWindow::_CheckChains() +MailStatusWindow::_CheckChains() { - BDirectory directory(&fChainDirectory); + bool hasInbound = false; + BMailAccounts accounts; + for (int32 i = 0; i < accounts.CountAccounts(); i++) { + if (accounts.AccountAt(i)->HasInbound()) { + hasInbound = true; + break; + } + } - entry_ref ref; - bool isEmpty = directory.GetNextRef(&ref) != B_OK; - - fCheckNowButton->SetEnabled(!isEmpty); + fCheckNowButton->SetEnabled(hasInbound); } void -BMailStatusWindow::FrameMoved(BPoint /*origin*/) +MailStatusWindow::FrameMoved(BPoint /*origin*/) { if (fLastWorkspace == current_workspace()) fFrame = Frame(); @@ -177,7 +181,7 @@ BMailStatusWindow::FrameMoved(BPoint /*origin*/) void -BMailStatusWindow::WorkspaceActivated(int32 workspace, bool active) +MailStatusWindow::WorkspaceActivated(int32 workspace, bool active) { if (!active) return; @@ -195,7 +199,7 @@ BMailStatusWindow::WorkspaceActivated(int32 workspace, bool active) void -BMailStatusWindow::MessageReceived(BMessage *msg) +MailStatusWindow::MessageReceived(BMessage *msg) { switch (msg->what) { case 'lkch': @@ -232,7 +236,7 @@ BMailStatusWindow::MessageReceived(BMessage *msg) void -BMailStatusWindow::SetDefaultMessage(const BString &message) +MailStatusWindow::SetDefaultMessage(const BString &message) { if (Lock()) { fMessageView->SetText(message.String()); @@ -241,8 +245,8 @@ BMailStatusWindow::SetDefaultMessage(const BString &message) } -BMailStatusView * -BMailStatusWindow::NewStatusView(const char *description, bool upstream) +MailStatusView * +MailStatusWindow::NewStatusView(const char *description, bool upstream) { if (!Lock()) return NULL; @@ -250,7 +254,7 @@ BMailStatusWindow::NewStatusView(const char *description, bool upstream) BRect rect = Bounds(); rect.top = fStatusViews.CountItems() * (fMinHeight + 1); rect.bottom = rect.top + fMinHeight; - BMailStatusView *status = new BMailStatusView(rect, description, upstream); + MailStatusView *status = new MailStatusView(rect, description, upstream); status->window = this; Unlock(); @@ -259,7 +263,7 @@ BMailStatusWindow::NewStatusView(const char *description, bool upstream) void -BMailStatusWindow::ActuallyAddStatusView(BMailStatusView *status) +MailStatusWindow::ActuallyAddStatusView(MailStatusView *status) { if (!Lock()) return; @@ -307,7 +311,7 @@ BMailStatusWindow::ActuallyAddStatusView(BMailStatusView *status) void -BMailStatusWindow::RemoveView(BMailStatusView *view) +MailStatusWindow::RemoveView(MailStatusView *view) { if (!view || !Lock()) return; @@ -324,7 +328,7 @@ BMailStatusWindow::RemoveView(BMailStatusView *view) fStatusViews.RemoveItem((void *)view); if (RemoveChild(view)) { - while ((view = (BMailStatusView *)fStatusViews.ItemAt(i++)) != NULL) + while ((view = (MailStatusView *)fStatusViews.ItemAt(i++)) != NULL) view->MoveBy(0, -fMinHeight - 1); // the view will be deleted in the ChainRunner @@ -360,14 +364,14 @@ BMailStatusWindow::RemoveView(BMailStatusView *view) int32 -BMailStatusWindow::CountVisibleItems() +MailStatusWindow::CountVisibleItems() { if (fShowMode != B_MAIL_SHOW_STATUS_WINDOW_WHEN_SENDING) return fStatusViews.CountItems(); int32 count = 0; for (int32 i = fStatusViews.CountItems(); i-- > 0;) { - BMailStatusView *view = (BMailStatusView *)fStatusViews.ItemAt(i); + MailStatusView *view = (MailStatusView *)fStatusViews.ItemAt(i); if (view->is_upstream) count++; } @@ -376,14 +380,14 @@ BMailStatusWindow::CountVisibleItems() bool -BMailStatusWindow::HasItems(void) +MailStatusWindow::HasItems(void) { return CountVisibleItems() > 0; } void -BMailStatusWindow::SetShowCriterion(uint32 when) +MailStatusWindow::SetShowCriterion(uint32 when) { if (!Lock()) return; @@ -403,7 +407,7 @@ BMailStatusWindow::SetShowCriterion(uint32 when) void -BMailStatusWindow::SetBorderStyle(int32 look) +MailStatusWindow::SetBorderStyle(int32 look) { switch (look) { case B_MAIL_STATUS_LOOK_TITLED: @@ -429,12 +433,12 @@ BMailStatusWindow::SetBorderStyle(int32 look) // #pragma mark - //------------------------------------------------ // -// BMailStatusView +// MailStatusView // //------------------------------------------------ -BMailStatusView::BMailStatusView(BRect rect, const char *description,bool upstream) +MailStatusView::MailStatusView(BRect rect, const char *description,bool upstream) : BBox(rect, description, B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, B_PLAIN_BORDER) @@ -454,16 +458,18 @@ BMailStatusView::BMailStatusView(BRect rect, const char *description,bool upstre total_items = 0; pre_text[0] = 0; is_upstream = upstream; + + by_bytes = false; } -BMailStatusView::~BMailStatusView() +MailStatusView::~MailStatusView() { } void -BMailStatusView::AddProgress(int32 how_much) +MailStatusView::AddProgress(int32 how_much) { AddSelfToWindow(); @@ -484,7 +490,7 @@ BMailStatusView::AddProgress(int32 how_much) void -BMailStatusView::SetMessage(const char *msg) +MailStatusView::SetMessage(const char *msg) { AddSelfToWindow(); @@ -496,31 +502,34 @@ BMailStatusView::SetMessage(const char *msg) void -BMailStatusView::Reset(bool hide) +MailStatusView::Reset(bool hide) { - if (LockLooper()) { - char old[255]; - if ((pre_text[0] == 0) && !hide) - strcpy(pre_text, status->TrailingText()); - if (hide) - pre_text[0] = 0; + if (!LockLooper()) + return; - strcpy(old,status->Label()); - status->Reset(old); - status->SetTrailingText(pre_text); - status->Draw(status->Bounds()); + char old[255]; + if ((pre_text[0] == 0) && !hide) + strcpy(pre_text, status->TrailingText()); + if (hide) pre_text[0] = 0; - total_items = 0; - items_now = 0; - UnlockLooper(); - } + + strcpy(old,status->Label()); + status->Reset(old); + status->SetTrailingText(pre_text); + status->Draw(status->Bounds()); + pre_text[0] = 0; + total_items = 0; + items_now = 0; + + UnlockLooper(); + if (hide && Window()) window->RemoveView(this); } void -BMailStatusView::SetMaximum(int32 max_bytes) +MailStatusView::SetMaximum(int32 max_bytes) { AddSelfToWindow(); @@ -538,22 +547,24 @@ BMailStatusView::SetMaximum(int32 max_bytes) void -BMailStatusView::SetTotalItems(int32 items) +MailStatusView::SetTotalItems(int32 items) { AddSelfToWindow(); total_items = items; + if (!by_bytes) + SetMaximum(-1); } int32 -BMailStatusView::CountTotalItems() +MailStatusView::CountTotalItems() { return total_items; } void -BMailStatusView::AddItem(void) +MailStatusView::AddItem(void) { AddSelfToWindow(); items_now++; @@ -564,7 +575,7 @@ BMailStatusView::AddItem(void) void -BMailStatusView::AddSelfToWindow() +MailStatusView::AddSelfToWindow() { if (Window() != NULL) return; diff --git a/headers/private/mail/status.h b/src/servers/mail/StatusWindow.h similarity index 60% rename from headers/private/mail/status.h rename to src/servers/mail/StatusWindow.h index a1214311dd..988c3f9e73 100644 --- a/headers/private/mail/status.h +++ b/src/servers/mail/StatusWindow.h @@ -16,19 +16,19 @@ class BStatusBar; class BStringView; -class BMailStatusView; +class MailStatusView; -class BMailStatusWindow : public BWindow { +class MailStatusWindow : public BWindow { public: - BMailStatusWindow(BRect rect, const char *name, uint32 showMode); - ~BMailStatusWindow(); + MailStatusWindow(BRect rect, const char *name, uint32 showMode); + ~MailStatusWindow(); virtual void FrameMoved(BPoint origin); virtual void WorkspaceActivated(int32 workspace, bool active); virtual void MessageReceived(BMessage *msg); - BMailStatusView *NewStatusView(const char *description, bool upstream); - void RemoveView(BMailStatusView *view); + MailStatusView *NewStatusView(const char *description, bool upstream); + void RemoveView(MailStatusView *view); int32 CountVisibleItems(); bool HasItems(void); @@ -36,11 +36,11 @@ class BMailStatusWindow : public BWindow { void SetDefaultMessage(const BString &message); private: - friend class BMailStatusView; + friend class MailStatusView; void _CheckChains(); void SetBorderStyle(int32 look); - void ActuallyAddStatusView(BMailStatusView *status); + void ActuallyAddStatusView(MailStatusView *status); node_ref fChainDirectory; BButton* fCheckNowButton; @@ -57,26 +57,27 @@ class BMailStatusWindow : public BWindow { uint32 _reserved[5]; }; -class BMailStatusView : public BBox { - public: - void AddProgress(int32 how_much); - void SetMessage(const char *msg); - void SetMaximum(int32 max_bytes); - int32 CountTotalItems(); - void SetTotalItems(int32 items); - void AddItem(void); - void Reset(bool hide = true); - - virtual ~BMailStatusView(); +class MailStatusView : public BBox { +public: + ~MailStatusView(); - private: - friend class BMailStatusWindow; + void AddProgress(int32 how_much); + void SetMessage(const char *msg); + void SetMaximum(int32 max_bytes); + int32 CountTotalItems(); + void SetTotalItems(int32 items); + void AddItem(void); + void Reset(bool hide = true); + int32 ItemsNow() { return items_now; } + +private: + friend class MailStatusWindow; - BMailStatusView(BRect rect,const char *description,bool upstream); + MailStatusView(BRect rect,const char *description,bool upstream); void AddSelfToWindow(); BStatusBar *status; - BMailStatusWindow *window; + MailStatusWindow *window; int32 items_now; int32 total_items; bool is_upstream; diff --git a/src/servers/mail/main.cpp b/src/servers/mail/main.cpp index c8991c6c2b..e2c9c57326 100644 --- a/src/servers/mail/main.cpp +++ b/src/servers/mail/main.cpp @@ -1,786 +1,12 @@ /* - * Copyright 2009-2010, Axel Dörfler, axeld@pinc-software.de. - * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. - * + * Copyright 2007-2011, Haiku, Inc. All rights reserved. + * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved. + * Copyright 2011, Clemens Zeidler * Distributed under the terms of the MIT License. */ -//! The daemon's inner workings - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "DeskbarView.h" -#include "LEDAnimation.h" - -#include - - -using std::map; - -typedef struct glorbal { - size_t bytes; - BStringList msgs; -} snuzzwut; - - -static BMailStatusWindow* sStatus; - - -class MailDaemonApp : public BApplication { -public: - MailDaemonApp(); - virtual ~MailDaemonApp(); - - virtual void MessageReceived(BMessage* message); - virtual void RefsReceived(BMessage* message); - - virtual void Pulse(); - virtual bool QuitRequested(); - virtual void ReadyToRun(); - - void InstallDeskbarIcon(); - void RemoveDeskbarIcon(); - - void RunChains(BList& list, BMessage* message); - void SendPendingMessages(BMessage* message); - void GetNewMessages(BMessage* message); - -private: - void _UpdateAutoCheck(bigtime_t interval); - static bool _IsPending(BNode& node); - static bool _IsEntryInTrash(BEntry& entry); - -private: - BMessageRunner* fAutoCheckRunner; - BMailSettings fSettingsFile; - - int32 fNewMessages; - bool fCentralBeep; - // TRUE to do a beep when the status window closes. This happens - // when all mail has been received, so you get one beep for - // everything rather than individual beeps for each mail - // account. - // Set to TRUE by the 'mcbp' message that the mail Notification - // filter sends us, cleared when the beep is done. - BList fFetchDoneRespondents; - BList fQueries; - - LEDAnimation* fLEDAnimation; - - BString fAlertString; -}; - - -MailDaemonApp::MailDaemonApp() - : - BApplication("application/x-vnd.Be-POST") -{ - sStatus = new BMailStatusWindow(BRect(40, 400, 360, 400), "Mail Status", - fSettingsFile.ShowStatusWindow()); - fAutoCheckRunner = NULL; -} - - -MailDaemonApp::~MailDaemonApp() -{ - delete fAutoCheckRunner; - - for (int32 i = 0; i < fQueries.CountItems(); i++) - delete (BQuery*)fQueries.ItemAt(i); - - delete fLEDAnimation; -} - - -void -MailDaemonApp::ReadyToRun() -{ - InstallDeskbarIcon(); - - _UpdateAutoCheck(fSettingsFile.AutoCheckInterval()); - - BVolume volume; - BVolumeRoster roster; - - fNewMessages = 0; - - while (roster.GetNextVolume(&volume) == B_OK) { - //{char name[255];volume.GetName(name);printf("Volume: %s\n",name);} - - BQuery* query = new BQuery; - - query->SetTarget(this); - query->SetVolume(&volume); - query->PushAttr(B_MAIL_ATTR_STATUS); - query->PushString("New"); - query->PushOp(B_EQ); - query->PushAttr("BEOS:TYPE"); - query->PushString("text/x-email"); - query->PushOp(B_EQ); - query->PushAttr("BEOS:TYPE"); - query->PushString("text/x-partial-email"); - query->PushOp(B_EQ); - query->PushOp(B_OR); - query->PushOp(B_AND); - query->Fetch(); - - BEntry entry; - while (query->GetNextEntry(&entry) == B_OK) - fNewMessages++; - - fQueries.AddItem(query); - } - - BString string; - MDR_DIALECT_CHOICE( - if (fNewMessages > 0) - string << fNewMessages; - else - string << "No"; - if (fNewMessages != 1) - string << " new messages."; - else - string << " new message.";, - if (fNewMessages > 0) - string << fNewMessages << " 通の未読メッセージがあります "; - else - string << "未読メッセージはありません"; - ); - fCentralBeep = false; - sStatus->SetDefaultMessage(string); - - fLEDAnimation = new LEDAnimation; - SetPulseRate(1000000); -} - - -void -MailDaemonApp::RefsReceived(BMessage* message) -{ - sStatus->Activate(true); - - entry_ref ref; - for (int32 i = 0; message->FindRef("refs", i, &ref) == B_OK; i++) { - BNode node(&ref); - if (node.InitCheck() < B_OK) - continue; - - BString uid; - if (node.ReadAttrString("MAIL:unique_id", &uid) < 0) - continue; - - int32 id; - if (node.ReadAttr("MAIL:chain", B_INT32_TYPE, 0, &id, sizeof(id)) < 0) - continue; - - int32 size; - if (node.ReadAttr("MAIL:fullsize", B_SIZE_T_TYPE, 0, &size, - sizeof(size)) < 0) { - size = -1; - } - - BPath path(&ref); - BMailChainRunner* runner = GetMailChainRunner(id, sStatus); - if (runner != NULL) - runner->GetSingleMessage(uid.String(), size, &path); - } -} - - -void -MailDaemonApp::_UpdateAutoCheck(bigtime_t interval) -{ - if (interval > 0) { - if (fAutoCheckRunner != NULL) { - fAutoCheckRunner->SetInterval(interval); - fAutoCheckRunner->SetCount(-1); - } else - fAutoCheckRunner = new BMessageRunner(be_app_messenger, - new BMessage('moto'), interval); - } else { - delete fAutoCheckRunner; - fAutoCheckRunner = NULL; - } -} - - -void -MailDaemonApp::MessageReceived(BMessage* msg) -{ - switch (msg->what) { - case 'moto': - if (fSettingsFile.CheckOnlyIfPPPUp()) { - // TODO: check whether internet is up and running! - } - // supposed to fall through - case 'mbth': // check & send messages - msg->what = 'msnd'; - PostMessage(msg); - // supposed to fall trough - case 'mnow': // check messages - GetNewMessages(msg); - break; - - case 'msnd': // send messages - SendPendingMessages(msg); - break; - - case 'mrrs': - fSettingsFile.Reload(); - _UpdateAutoCheck(fSettingsFile.AutoCheckInterval()); - sStatus->SetShowCriterion(fSettingsFile.ShowStatusWindow()); - break; - case 'shst': // when to show the status window - { - int32 mode; - if (msg->FindInt32("ShowStatusWindow", &mode) == B_OK) - sStatus->SetShowCriterion(mode); - break; - } - - case 'lkch': // status window look changed - case 'wsch': // workspace changed - sStatus->PostMessage(msg); - break; - - case 'stwg': // Status window gone - { - BMessage reply('mnuc'); - reply.AddInt32("num_new_messages", fNewMessages); - - while ((msg = (BMessage*)fFetchDoneRespondents.RemoveItem(0L))) { - msg->SendReply(&reply); - delete msg; - } - - if (fAlertString != B_EMPTY_STRING) { - fAlertString.Truncate(fAlertString.Length() - 1); - BAlert* alert = new BAlert(MDR_DIALECT_CHOICE("New Messages", - "新着メッセージ"), fAlertString.String(), "OK", NULL, NULL, - B_WIDTH_AS_USUAL); - alert->SetFeel(B_NORMAL_WINDOW_FEEL); - alert->Go(NULL); - fAlertString = B_EMPTY_STRING; - } - - if (fCentralBeep) { - system_beep("New E-mail"); - fCentralBeep = false; - } - break; - } - - case 'mcbp': - if (fNewMessages > 0) - fCentralBeep = true; - break; - - case 'mnum': // Number of new messages - { - BMessage reply('mnuc'); // Mail New message Count - if (msg->FindBool("wait_for_fetch_done")) { - fFetchDoneRespondents.AddItem(DetachCurrentMessage()); - break; - } - - reply.AddInt32("num_new_messages", fNewMessages); - msg->SendReply(&reply); - break; - } - - case 'mblk': // Mail Blink - if (fNewMessages > 0) - fLEDAnimation->Start(); - break; - - case 'enda': // End Auto Check - delete fAutoCheckRunner; - fAutoCheckRunner = NULL; - break; - - case 'numg': - { - int32 numMessages = msg->FindInt32("num_messages"); - MDR_DIALECT_CHOICE( - fAlertString << numMessages << " new message"; - if (numMessages > 1) - fAlertString << 's'; - - fAlertString << " for " << msg->FindString("chain_name") - << '\n';, - - fAlertString << msg->FindString("chain_name") << "より\n" - << numMessages << " 通のメッセージが届きました  "; - ); - break; - } - - case B_QUERY_UPDATE: - { - int32 what; - msg->FindInt32("opcode", &what); - switch (what) { - case B_ENTRY_CREATED: - fNewMessages++; - break; - case B_ENTRY_REMOVED: - fNewMessages--; - break; - } - - BString string; - - MDR_DIALECT_CHOICE( - if (fNewMessages > 0) - string << fNewMessages; - else - string << "No"; - if (fNewMessages != 1) - string << " new messages."; - else - string << " new message.";, - - if (fNewMessages > 0) - string << fNewMessages << " 通の未読メッセージがあります"; - else - string << "未読メッセージはありません"; - ); - - sStatus->SetDefaultMessage(string.String()); - break; - } - - default: - BApplication::MessageReceived(msg); - break; - } -} - - -void -MailDaemonApp::InstallDeskbarIcon() -{ - BDeskbar deskbar; - - if (!deskbar.HasItem("mail_daemon")) { - BRoster roster; - entry_ref ref; - - status_t status = roster.FindApp("application/x-vnd.Be-POST", &ref); - if (status < B_OK) { - fprintf(stderr, "Can't find application to tell deskbar: %s\n", - strerror(status)); - return; - } - - status = deskbar.AddItem(&ref); - if (status < B_OK) { - fprintf(stderr, "Can't add deskbar replicant: %s\n", strerror(status)); - return; - } - } -} - - -void -MailDaemonApp::RemoveDeskbarIcon() -{ - BDeskbar deskbar; - if (deskbar.HasItem("mail_daemon")) - deskbar.RemoveItem("mail_daemon"); -} - - -bool -MailDaemonApp::QuitRequested() -{ - RemoveDeskbarIcon(); - - return true; -} - - -void -MailDaemonApp::RunChains(BList& list, BMessage* msg) -{ - BMailChain* chain; - - int32 index = 0, id; - for (; msg->FindInt32("chain", index, &id) == B_OK; index++) { - for (int32 i = 0; i < list.CountItems(); i++) { - chain = (BMailChain*)list.ItemAt(i); - - if (chain->ID() == (unsigned)id) { - chain->RunChain(sStatus, true, false, true); - list.RemoveItem(i); // the chain runner deletes the chain - break; - } - } - } - - if (index == 0) { - // invoke all chains - for (int32 i = 0; i < list.CountItems(); i++) { - chain = (BMailChain*)list.ItemAt(i); - - chain->RunChain(sStatus, true, false, true); - } - } else { - // delete unused chains - for (int32 i = list.CountItems(); i-- > 0;) - delete (BMailChain*)list.RemoveItem(i); - } -} - - -void -MailDaemonApp::GetNewMessages(BMessage* msg) -{ - BList list; - GetInboundMailChains(&list); - - RunChains(list, msg); -} - - -void -MailDaemonApp::SendPendingMessages(BMessage* msg) -{ - BVolumeRoster roster; - BVolume volume; - - while (roster.GetNextVolume(&volume) == B_OK) { - BQuery query; - query.SetVolume(&volume); - query.PushAttr(B_MAIL_ATTR_FLAGS); - query.PushInt32(B_MAIL_PENDING); - query.PushOp(B_EQ); - - query.PushAttr(B_MAIL_ATTR_FLAGS); - query.PushInt32(B_MAIL_PENDING | B_MAIL_SAVE); - query.PushOp(B_EQ); - - query.PushOp(B_OR); - - int32 chainID = -1; - - if (msg->FindInt32("chain", &chainID) == B_OK) { - query.PushAttr("MAIL:chain"); - query.PushInt32(chainID); - query.PushOp(B_EQ); - query.PushOp(B_AND); - } else - chainID = -1; - - if (!msg->HasString("message_path")) { - if (chainID == -1) { - map messages; - - query.Fetch(); - BEntry entry; - BPath path; - BNode node; - int32 chain; - int32 defaultChain(BMailSettings().DefaultOutboundChainID()); - off_t size; - - while (query.GetNextEntry(&entry) == B_OK) { - if (_IsEntryInTrash(entry)) - continue; - - while (node.SetTo(&entry) == B_BUSY) - snooze(1000); - if (!_IsPending(node)) - continue; - - if (node.ReadAttr("MAIL:chain", B_INT32_TYPE, 0, &chain, 4) - < B_OK) - chain = defaultChain; - entry.GetPath(&path); - node.GetSize(&size); - if (messages[chain] == NULL) { - messages[chain] = new snuzzwut; - messages[chain]->bytes = 0; - } - - messages[chain]->msgs += path.Path(); - messages[chain]->bytes += size; - } - - map::iterator iter = messages.begin(); - map::iterator end = messages.end(); - while (iter != end) { - if (iter->first > 0 && BMailChain(iter->first) - .ChainDirection() == outbound) { - BMailChainRunner* runner - = GetMailChainRunner(iter->first, sStatus); - runner->GetMessages(&messages[iter->first]->msgs, - messages[iter->first]->bytes); - delete messages[iter->first]; - runner->Stop(); - } - - iter++; - } - } else { - BStringList ids; - size_t bytes = 0; - - query.Fetch(); - BEntry entry; - BPath path; - BNode node; - off_t size; - - while (query.GetNextEntry(&entry) == B_OK) { - if (_IsEntryInTrash(entry)) - continue; - - node.SetTo(&entry); - if (!_IsPending(node)) - continue; - - entry.GetPath(&path); - node.GetSize(&size); - ids += path.Path(); - bytes += size; - } - - BMailChainRunner* runner - = GetMailChainRunner(chainID, sStatus); - runner->GetMessages(&ids, bytes); - runner->Stop(); - } - } else { - const char* path; - if (msg->FindString("message_path", &path) != B_OK) - return; - - off_t size; - if (BNode(path).GetSize(&size) != B_OK) - return; - - BStringList ids; - ids += path; - - BMailChainRunner* runner = GetMailChainRunner(chainID, sStatus); - runner->GetMessages(&ids, size); - runner->Stop(); - } - } -} - - -void -MailDaemonApp::Pulse() -{ - bigtime_t idle = idle_time(); - if (fLEDAnimation->IsRunning() && idle < 100000) - fLEDAnimation->Stop(); -} - - -/*! Work-around for a broken index that contains out-of-date information. -*/ - -/* static */ -bool -MailDaemonApp::_IsPending(BNode& node) -{ - int32 flags; - if (node.ReadAttr(B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0, &flags, sizeof(int32)) - != (ssize_t)sizeof(int32)) - return false; - - return (flags & B_MAIL_PENDING) != 0; -} - - -/* static */ -bool -MailDaemonApp::_IsEntryInTrash(BEntry& entry) -{ - entry_ref ref; - entry.GetRef(&ref); - - BVolume volume(ref.device); - BPath path; - if (volume.InitCheck() != B_OK - || find_directory(B_TRASH_DIRECTORY, &path, false, &volume) != B_OK) - return false; - - BDirectory trash(path.Path()); - return trash.Contains(&entry); -} - - -// #pragma mark - - - -void -makeIndices() -{ - const char* stringIndices[] = { - B_MAIL_ATTR_ACCOUNT, B_MAIL_ATTR_CC, B_MAIL_ATTR_FROM, B_MAIL_ATTR_NAME, - B_MAIL_ATTR_PRIORITY, B_MAIL_ATTR_REPLY, B_MAIL_ATTR_STATUS, - B_MAIL_ATTR_SUBJECT, B_MAIL_ATTR_TO, B_MAIL_ATTR_THREAD, - NULL - }; - - // add mail indices for all devices capable of querying - - int32 cookie = 0; - dev_t device; - while ((device = next_dev(&cookie)) >= B_OK) { - fs_info info; - if (fs_stat_dev(device, &info) < 0 - || (info.flags & B_FS_HAS_QUERY) == 0) - continue; - - for (int32 i = 0; stringIndices[i]; i++) - fs_create_index(device, stringIndices[i], B_STRING_TYPE, 0); - - fs_create_index(device, "MAIL:draft", B_INT32_TYPE, 0); - fs_create_index(device, B_MAIL_ATTR_WHEN, B_INT32_TYPE, 0); - fs_create_index(device, B_MAIL_ATTR_FLAGS, B_INT32_TYPE, 0); - fs_create_index(device, "MAIL:chain", B_INT32_TYPE, 0); - fs_create_index(device, "MAIL:pending_chain", B_INT32_TYPE, 0); - } -} - - -void -addAttribute(BMessage& msg, const char* name, const char* publicName, - int32 type = B_STRING_TYPE, bool viewable = true, bool editable = false, - int32 width = 200) -{ - msg.AddString("attr:name", name); - msg.AddString("attr:public_name", publicName); - msg.AddInt32("attr:type", type); - msg.AddBool("attr:viewable", viewable); - msg.AddBool("attr:editable", editable); - msg.AddInt32("attr:width", width); - msg.AddInt32("attr:alignment", B_ALIGN_LEFT); -} - - -void -makeMimeType(bool remakeMIMETypes) -{ - // Add MIME database entries for the e-mail file types we handle. Either - // do a full rebuild from nothing, or just add on the new attributes that - // we support which the regular BeOS mail daemon didn't have. - - const char* types[2] = {"text/x-email", "text/x-partial-email"}; - BMimeType mime; - BMessage info; - - for (size_t i = 0; i < sizeof(types) / sizeof(types[0]); i++) { - info.MakeEmpty(); - mime.SetTo(types[i]); - if (mime.InitCheck() != B_OK) { - fputs("could not init mime type.\n", stderr); - return; - } - - if (!mime.IsInstalled() || remakeMIMETypes) { - // install the full mime type - mime.Delete (); - mime.Install(); - - // Set up the list of e-mail related attributes that Tracker will - // let you display in columns for e-mail messages. - addAttribute(info, B_MAIL_ATTR_NAME, "Name"); - addAttribute(info, B_MAIL_ATTR_SUBJECT, "Subject"); - addAttribute(info, B_MAIL_ATTR_TO, "To"); - addAttribute(info, B_MAIL_ATTR_CC, "Cc"); - addAttribute(info, B_MAIL_ATTR_FROM, "From"); - addAttribute(info, B_MAIL_ATTR_REPLY, "Reply To"); - addAttribute(info, B_MAIL_ATTR_STATUS, "Status"); - addAttribute(info, B_MAIL_ATTR_PRIORITY, "Priority", B_STRING_TYPE, - true, true, 40); - addAttribute(info, B_MAIL_ATTR_WHEN, "When", B_TIME_TYPE, true, - false, 150); - addAttribute(info, B_MAIL_ATTR_THREAD, "Thread"); - addAttribute(info, B_MAIL_ATTR_ACCOUNT, "Account", B_STRING_TYPE, - true, false, 100); - mime.SetAttrInfo(&info); - - if (i == 0) { - mime.SetShortDescription("E-mail"); - mime.SetLongDescription("Electronic Mail Message"); - mime.SetPreferredApp("application/x-vnd.Be-MAIL"); - } else { - mime.SetShortDescription("Partial E-mail"); - mime.SetLongDescription("A Partially Downloaded E-mail"); - mime.SetPreferredApp("application/x-vnd.Be-POST"); - } - } else { - // Just add the e-mail related attribute types we use to the MIME - // system. - mime.GetAttrInfo(&info); - bool hasAccount = false; - bool hasThread = false; - bool hasSize = false; - const char* result; - for (int32 index = 0; info.FindString("attr:name", index, &result) - == B_OK; index++) { - if (!strcmp(result, B_MAIL_ATTR_ACCOUNT)) - hasAccount = true; - if (!strcmp(result, B_MAIL_ATTR_THREAD)) - hasThread = true; - if (!strcmp(result, "MAIL:fullsize")) - hasSize = true; - } - - if (!hasAccount) { - addAttribute(info, B_MAIL_ATTR_ACCOUNT, "Account", - B_STRING_TYPE, true, false, 100); - } - if (!hasThread) - addAttribute(info, B_MAIL_ATTR_THREAD, "Thread"); - /*if (!hasSize) - addAttribute(info,"MAIL:fullsize","Message Size",B_SIZE_T_TYPE,true,false,100);*/ - // TODO: Tracker can't display SIZT attributes. What a pain. - if (!hasAccount || !hasThread/* || !hasSize*/) - mime.SetAttrInfo(&info); - } - mime.Unset(); - } -} +#include "MailDaemon.h" int @@ -799,15 +25,8 @@ main(int argc, const char** argv) } MailDaemonApp app; - - // install MimeTypes, attributes, indices, and the - // system beep add startup - - makeMimeType(remakeMIMETypes); - makeIndices(); - add_system_beep_event("New E-mail"); - - be_app->Run(); + if (remakeMIMETypes) + app.MakeMimeTypes(true); + app.Run(); return 0; } -