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; } -