Major restructuring of the mail server:

Accounts are now stored in a separate file. Previously they where somehow magically assembled from the chain ids. Now its possible to remove a account temporary by removing the account file form the account folder.

Each account could have an inbound protocol, an outbound protocol and some filters.

Mails are now associated with an account and not with a chain. This required to replace the chain id attribute by an account attribute.

Replace BMailFilter and BMailChain by a less general approach. Basically the chain had a list of filters and call the ProcessMailMessage for each filter. This made it sometime difficult to understand what is going on, e.g. sometimes a filter used information gathered by another filters. The new MailProtocol and MailFilter classes are calling more dedicated hook functions, e.g. HeaderFetched or MessageReadyToSend.

As before all MailProtocol's (plus their filters) are running in their own thread.

Cleaned up the error and status window a bit. Abstracted the interface to these windows. Should be easy to write a BNotification api back-end now.

Parsing of mail headers is much faster now. Fetching the headers of a large mailbox takes ~min and not ~hour now! Initial checkout time is in the same order like Opera. The problem was the massive use of fgets in parse_header (mail_util.cpp) now the complete header is read in one go. Furthermore, only interesting fields are extracted.

Remove some unused files, BeOS relicts... Feel free to translate the mail server and remove the own language system (headers/private/mail/MDRLanguage.h).

Sorry for the remaining old (and new) coding style issues, sometime just ignore them, to many :(



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@40397 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Clemens Zeidler
2011-02-09 01:49:01 +00:00
parent f9ac5fc8f5
commit 1af4fa4ba6
42 changed files with 3498 additions and 3956 deletions
+1 -3
View File
@@ -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 inbound_protocols : POP3 IMAP ;
AddFilesToHaikuImage system add-ons mail_daemon outbound_protocols : SMTP ; AddFilesToHaikuImage system add-ons mail_daemon outbound_protocols : SMTP ;
AddFilesToHaikuImage system add-ons mail_daemon inbound_filters 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 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 : $(SYSTEM_ADD_ONS_MEDIA) ;
AddFilesToHaikuImage system add-ons media plugins AddFilesToHaikuImage system add-ons media plugins
: $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ; : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ;
@@ -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 <MailAddon.h>
#include <MailSettings.h>
#include <Looper.h>
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 */
+17 -94
View File
@@ -1,116 +1,39 @@
#ifndef ZOIDBERG_MAIL_ADDON_H
#define ZOIDBERG_MAIL_ADDON_H
/* Filter - the base class for all mail filters /* Filter - the base class for all mail filters
** **
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. ** 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 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() // The addon interface: export instantiate_mailfilter()
// and instantiate_mailconfig() to create a Filter addon // and instantiate_mailconfig() to create a Filter addon
// //
extern "C" _EXPORT BView* instantiate_config_panel(BMessage *settings,BMessage *metadata); extern "C" _EXPORT InboundProtocol* instantiate_inbound_protocol(
// return a view that configures the MailProtocol or MailFilter 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) // returned by the functions below. BView::Archive(foo,true)
// produces this addon's settings, which are passed to the in- // produces this addon's settings, which are passed to the in-
// stantiate_* functions and stored persistently. This function // stantiate_* functions and stored persistently. This function
// should gracefully handle empty and NULL settings. // 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, extern "C" _EXPORT BView* instantiate_filter_config_panel(AddonSettings&);
BMailChainRunner *runner); extern "C" _EXPORT MailFilter* instantiate_mailfilter(MailProtocol& protocol,
// Return a MailProtocol or MailFilter ready to do its thing, AddonSettings* settings);
// 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 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 // the config panel will show this name in the chains filter
// list if this function returns B_OK. // list if this function returns B_OK.
// The buffer is as big as B_FILE_NAME_LENGTH. // The buffer is as big as B_FILE_NAME_LENGTH.
+213 -95
View File
@@ -1,107 +1,225 @@
#ifndef ZOIDBERG_MAIL_PROTOCOL_H
#define ZOIDBERG_MAIL_PROTOCOL_H
/* Protocol - the base class for protocol filters /* 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 <map>
#include <vector>
#include <Handler.h>
#include <Looper.h>
#include <OS.h> #include <OS.h>
#include <ObjectList.h>
#include <Entry.h>
#include <File.h>
#include <MailAddon.h> #include <MailSettings.h>
class BHandler; class MailNotifier {
class BStringList; public:
class BMailChainRunner; virtual ~MailNotifier() {}
class BMailProtocol : public BMailFilter virtual MailNotifier* Clone() = 0;
{
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();
friend class DeletePass; virtual void ShowError(const char* error) = 0;
virtual void ShowMessage(const char* message) = 0;
BHandler *trash_monitor;
BStringList *uids_on_disk; virtual void SetTotalItems(int32 items) = 0;
virtual void SetTotalItemsSize(int32 size) = 0;
uint32 _reserved[3]; 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<BHandler> fHandlerList;
BObjectList<MailFilter> fFilterList;
std::map<entry_ref, image_id> 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<entry_ref>&
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<entry_ref>&
mails, size_t totalBytes);
private:
OutboundProtocol* fProtocol;
};
#endif // MAIL_PROTOCOL_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 /* ProtocolConfigView - the standard config view for all protocols
** **
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. ** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
*/ */
#ifndef ZOIDBERG_PROTOCOL_CONFIG_VIEW_H
#define ZOIDBERG_PROTOCOL_CONFIG_VIEW_H
#include <CheckBox.h>
#include <StringView.h>
#include <TextControl.h>
#include <View.h> #include <View.h>
#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 { typedef enum {
B_MAIL_PROTOCOL_HAS_AUTH_METHODS = 1, B_MAIL_PROTOCOL_HAS_AUTH_METHODS = 1,
B_MAIL_PROTOCOL_HAS_FLAVORS = 2, B_MAIL_PROTOCOL_HAS_FLAVORS = 2,
B_MAIL_PROTOCOL_HAS_USERNAME = 4, B_MAIL_PROTOCOL_HAS_USERNAME = 4,
B_MAIL_PROTOCOL_HAS_PASSWORD = 8, B_MAIL_PROTOCOL_HAS_PASSWORD = 8,
B_MAIL_PROTOCOL_HAS_HOSTNAME = 16, 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; } 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; class BMailProtocolConfigView : public BView {
virtual void GetPreferredSize(float *width, float *height); public:
virtual void AttachedToWindow(); BMailProtocolConfigView(uint32 options_mask
virtual void MessageReceived(BMessage *msg); = 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: private:
uint32 _reserved[5]; BodyDownloadConfig* fBodyDownloadConfig;
}; };
#endif /* ZOIDBERG_PROTOCOL_CONFIG_VIEW_H */ #endif /* ZOIDBERG_PROTOCOL_CONFIG_VIEW_H */
@@ -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 <MailProtocol.h>
#include <StringList.h>
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
-21
View File
@@ -92,27 +92,6 @@ typedef struct {
} mail_notification; } 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 // #pragma mark - BMailMessage
class BMailMessage { class BMailMessage {
+28 -12
View File
@@ -1,18 +1,34 @@
#ifndef ZOIDBERG_MAIL_DAEMON_H #ifndef MAIL_DAEMON_H
#define ZOIDBERG_MAIL_DAEMON_H #define MAIL_DAEMON_H
/* Daemon - talking to the mail daemon /* 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 <[email protected]>
*/ */
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
+4 -3
View File
@@ -25,7 +25,8 @@ enum mail_reply_to_mode {
class BEmailMessage : public BMailContainer { class BEmailMessage : public BMailContainer {
public: public:
BEmailMessage(BPositionIO *mail_file = NULL, bool own = false, uint32 defaultCharSet = B_MAIL_NULL_CONVERSION); 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(); virtual ~BEmailMessage();
status_t InitCheck() const; status_t InitCheck() const;
@@ -60,7 +61,7 @@ class BEmailMessage : public BMailContainer {
void SendViaAccountFrom(BEmailMessage *message); void SendViaAccountFrom(BEmailMessage *message);
void SendViaAccount(const char *account_name); void SendViaAccount(const char *account_name);
void SendViaAccount(int32 chain_id); void SendViaAccount(int32 account);
int32 Account() const; int32 Account() const;
status_t GetAccountName(char *account,int32 maxLength) const; status_t GetAccountName(char *account,int32 maxLength) const;
status_t GetAccountName(BString *account) const; status_t GetAccountName(BString *account) const;
@@ -99,7 +100,7 @@ class BEmailMessage : public BMailContainer {
BPositionIO *fData; BPositionIO *fData;
status_t _status; status_t _status;
int32 _chain_id; int32 _account_id;
char *_bcc; char *_bcc;
int32 _num_components; int32 _num_components;
+172 -119
View File
@@ -1,17 +1,25 @@
#ifndef ZOIDBERG_MAIL_SETTINGS_H /*
#define ZOIDBERG_MAIL_SETTINGS_H * Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
/* Settings - the mail daemon's settings * Copyright 2011 Clemens Zeidler.
** * Distributed under the terms of the MIT License.
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. */
*/ #ifndef MAIL_SETTINGS_H
#define MAIL_SETTINGS_H
#include <vector>
#include <Archivable.h> #include <Archivable.h>
#include <Entry.h>
#include <List.h> #include <List.h>
#include <Message.h> #include <Message.h>
#include <ObjectList.h>
#include <String.h>
class BPath; class BPath;
typedef enum typedef enum
{ {
B_MAIL_SHOW_STATUS_WINDOW_NEVER = 0, B_MAIL_SHOW_STATUS_WINDOW_NEVER = 0,
@@ -20,6 +28,7 @@ typedef enum
B_MAIL_SHOW_STATUS_WINDOW_ALWAYS = 3 B_MAIL_SHOW_STATUS_WINDOW_ALWAYS = 3
} b_mail_status_window_option; } b_mail_status_window_option;
typedef enum typedef enum
{ {
B_MAIL_STATUS_LOOK_TITLED = 0, B_MAIL_STATUS_LOOK_TITLED = 0,
@@ -29,126 +38,170 @@ typedef enum
B_MAIL_STATUS_LOOK_NO_BORDER = 4 B_MAIL_STATUS_LOOK_NO_BORDER = 4
} b_mail_status_window_look; } 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 { class BMailSettings {
public: public:
BMailSettings(); BMailSettings();
~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);
void SetConfigWindowFrame(BRect frame); status_t Save(bigtime_t timeout = B_INFINITE_TIMEOUT);
BRect ConfigWindowFrame(); status_t Reload();
status_t InitCheck() const;
void SetStatusWindowFrame(BRect frame); // Global settings
BRect StatusWindowFrame(); int32 WindowFollowsCorner();
void SetWindowFollowsCorner(int32 which_corner);
int32 StatusWindowWorkspaces(); uint32 ShowStatusWindow();
void SetStatusWindowWorkspaces(int32 workspaces); void SetShowStatusWindow(uint32 mode);
bool DaemonAutoStarts();
void SetDaemonAutoStarts(bool does_it);
int32 StatusWindowLook(); void SetConfigWindowFrame(BRect frame);
void SetStatusWindowLook(int32 look); BRect ConfigWindowFrame();
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);
private: void SetStatusWindowFrame(BRect frame);
BMessage fData; BRect StatusWindowFrame();
uint32 _reserved[4];
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<AddonSettings> 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<BMailAccountSettings> fAccounts;
};
#endif /* ZOIDBERG_MAIL_SETTINGS_H */ #endif /* ZOIDBERG_MAIL_SETTINGS_H */
+2 -2
View File
@@ -42,8 +42,8 @@ class BMailFileConfigView : public BFileControl
public: public:
BMailFileConfigView(const char *label,const char *name,bool useMeta = false,const char *defaultPath = NULL,uint32 flavors = B_DIRECTORY_NODE); 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); void SetTo(const BMessage *archive, BMessage *metadata);
virtual status_t Archive(BMessage *into,bool deep = true) const; virtual status_t Archive(BMessage *into, bool deep = true) const;
private: private:
BMessage *fMeta; BMessage *fMeta;
+1 -1
View File
@@ -9,7 +9,7 @@
#define PASSWORD_LENGTH 32 #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); bool set_passwd(BMessage *msg,const char *name,const char *password);
void passwd_crypt(char *in,char *out,int length); void passwd_crypt(char *in,char *out,int length);
+2
View File
@@ -72,6 +72,8 @@ ssize_t readfoldedline(BPositionIO &in, char **buffer, size_t *buflen);
// start with a buffer of size *buflen // start with a buffer of size *buflen
status_t parse_header(BMessage &headers, BPositionIO &input); 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); void extract_address(BString &address);
// retrieves the mail address only from an address header formatted field // retrieves the mail address only from an address header formatted field
-610
View File
@@ -1,610 +0,0 @@
/*
* Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
*/
//! Runs the mail inbound and outbound chains
#include <List.h>
#include <OS.h>
#include <Path.h>
#include <image.h>
#include <Entry.h>
#include <File.h>
#include <String.h>
#include <Alert.h>
#include <Directory.h>
#include <Application.h>
#include <Locker.h>
#include <MessageQueue.h>
#include <MessageFilter.h>
#include <stdio.h>
#include <stdlib.h>
#include <MDRLanguage.h>
class _EXPORT BMailChainRunner;
#include <ChainRunner.h>
#include <status.h>
#include <StringList.h>
#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<BMailChainCallback *>(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());
}
+1 -1
View File
@@ -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; fMeta = meta;
BString path = (fUseMeta ? meta : archive)->FindString(fName); BString path = (fUseMeta ? meta : archive)->FindString(fName);
+204
View File
@@ -0,0 +1,204 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#include "HaikuMailFormatFilter.h"
#include <Directory.h>
#include <E-mail.h>
#include <NodeInfo.h>
#include <mail_util.h>
#include <NodeMessage.h>
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);
}
+35
View File
@@ -0,0 +1,35 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <[email protected]>
* Distributed under the terms of the MIT License.
*/
#ifndef IMAP_LISTENER_H
#define IMAP_LISTENER_H
#include "MailProtocol.h"
#include <String.h>
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
+1 -18
View File
@@ -1,10 +1,5 @@
SubDir HAIKU_TOP src kits mail ; SubDir HAIKU_TOP src kits mail ;
SetSubDirSupportedPlatformsBeOSCompatible ;
if $(TARGET_PLATFORM) != haiku {
UsePublicHeaders mail ;
}
UsePrivateHeaders mail shared ; UsePrivateHeaders mail shared ;
UsePublicHeaders [ FDirName add-ons mail_daemon ] ; UsePublicHeaders [ FDirName add-ons mail_daemon ] ;
@@ -17,19 +12,13 @@ SubDirC++Flags -D_BUILDING_mail=1 ;
UsePrivateHeaders textencoding ; UsePrivateHeaders textencoding ;
SharedLibrary libmail.so : SharedLibrary libmail.so :
b_mail_message.cpp
c_mail_api.cpp
ChainRunner.cpp
cpp_abi_base64.c
crypt.cpp crypt.cpp
des.c des.c
ErrorLogWindow.cpp
FileConfigView.cpp FileConfigView.cpp
HaikuMailFormatFilter.cpp
mail_encoding.c mail_encoding.c
mail_util.cpp mail_util.cpp
MailAddon.cpp
MailAttachment.cpp MailAttachment.cpp
MailChain.cpp
MailComponent.cpp MailComponent.cpp
MailContainer.cpp MailContainer.cpp
MailDaemon.cpp MailDaemon.cpp
@@ -39,8 +28,6 @@ SharedLibrary libmail.so :
NodeMessage.cpp NodeMessage.cpp
numailkit.cpp numailkit.cpp
ProtocolConfigView.cpp ProtocolConfigView.cpp
RemoteStorageProtocol.cpp
StatusWindow.cpp
StringList.cpp StringList.cpp
: :
be be
@@ -50,7 +37,3 @@ SharedLibrary libmail.so :
$(TARGET_NETWORK_LIBS) $(TARGET_NETWORK_LIBS)
$(TARGET_SELECT_UNAME_ETC_LIB) $(TARGET_SELECT_UNAME_ETC_LIB)
; ;
Package haiku-maildaemon-cvs :
libmail.so :
boot beos system lib ;
-27
View File
@@ -1,27 +0,0 @@
/* Filter - the base class for all mail filters
**
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
*/
#include <String.h>
class _EXPORT BMailFilter;
#include <MailAddon.h>
BMailFilter::BMailFilter(BMessage *)
{
//----do nothing-----
}
BMailFilter::~BMailFilter()
{
}
void BMailFilter::_ReservedFilter1() {}
void BMailFilter::_ReservedFilter2() {}
void BMailFilter::_ReservedFilter3() {}
void BMailFilter::_ReservedFilter4() {}
-512
View File
@@ -1,512 +0,0 @@
/* BMailChain - the mail account's inbound and outbound chain
**
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
*/
#include <Message.h>
#include <FindDirectory.h>
#include <Directory.h>
#include <File.h>
#include <Entry.h>
#include <Path.h>
#include <String.h>
#include <string.h>
#include <stdio.h>
class BMailChain;
namespace MailInternal {
status_t WriteMessageFile(const BMessage& archive,
const BPath& path, const char* name);
}
#include <MailSettings.h>
#include <ChainRunner.h>
#include <status.h>
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);
}
+52 -46
View File
@@ -13,79 +13,85 @@
#include <string.h> #include <string.h>
_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"); BMessenger daemon("application/x-vnd.Be-POST");
if (!daemon.IsValid()) if (!daemon.IsValid())
return B_MAIL_NO_DAEMON; return B_MAIL_NO_DAEMON;
BMessage message(send_queued_mail ? 'mbth' : 'mnow'); BMessage message(kMsgCheckMessage);
if (account != NULL) { message.AddInt32("account", accountID);
BList list; return daemon.SendMessage(&message);
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;
} }
_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"); BMessenger daemon("application/x-vnd.Be-POST");
if (!daemon.IsValid()) if (!daemon.IsValid())
return B_MAIL_NO_DAEMON; return B_MAIL_NO_DAEMON;
daemon.SendMessage('msnd'); return daemon.SendMessage(kMsgSendMessages);
return B_OK;
} }
_EXPORT int32 BMailDaemon::CountNewMessages(bool wait_for_fetch_completion) {
int32
BMailDaemon::CountNewMessages(bool wait_for_fetch_completion)
{
BMessenger daemon("application/x-vnd.Be-POST"); BMessenger daemon("application/x-vnd.Be-POST");
if (!daemon.IsValid()) if (!daemon.IsValid())
return B_MAIL_NO_DAEMON; return B_MAIL_NO_DAEMON;
BMessage reply; BMessage reply;
BMessage first('mnum'); BMessage first(kMsgCountNewMessages);
if (wait_for_fetch_completion) if (wait_for_fetch_completion)
first.AddBool("wait_for_fetch_done",true); first.AddBool("wait_for_fetch_done",true);
daemon.SendMessage(&first,&reply); daemon.SendMessage(&first, &reply);
return reply.FindInt32("num_new_messages"); 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"); BMessenger daemon("application/x-vnd.Be-POST");
if (!daemon.IsValid()) if (!daemon.IsValid())
return B_MAIL_NO_DAEMON; return B_MAIL_NO_DAEMON;
daemon.SendMessage(B_QUIT_REQUESTED); return daemon.SendMessage(B_QUIT_REQUESTED);
return B_OK;
} }
+46 -44
View File
@@ -65,7 +65,7 @@ BEmailMessage::BEmailMessage(BPositionIO *file, bool own, uint32 defaultCharSet)
_text_body(NULL) _text_body(NULL)
{ {
BMailSettings settings; BMailSettings settings;
_chain_id = settings.DefaultOutboundChainID(); _account_id = settings.DefaultOutboundAccount();
if (own) if (own)
fData = file; 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), _bcc(NULL),
_num_components(0), _num_components(0),
_body(NULL), _body(NULL),
_text_body(NULL) _text_body(NULL)
{ {
BMailSettings settings; BMailSettings settings;
_chain_id = settings.DefaultOutboundChainID(); _account_id = settings.DefaultOutboundAccount();
fData = new BFile(); fData = new BFile();
_status = static_cast<BFile *>(fData)->SetTo(ref,B_READ_ONLY); _status = static_cast<BFile *>(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); get_address_list(list, To(), extract_address);
// Filter out the sender // 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); extract_address(sender);
BString cc; BString cc;
@@ -391,52 +395,42 @@ BEmailMessage::SendViaAccountFrom(BEmailMessage *message)
return; return;
} }
BList chains; SendViaAccount(name);
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;
}
} }
void void
BEmailMessage::SendViaAccount(const char *account_name) BEmailMessage::SendViaAccount(const char *account_name)
{ {
BList chains; BMailAccounts accounts;
GetOutboundMailChains(&chains); BMailAccountSettings* account = accounts.AccountByName(account_name);
if (!account)
for (int32 i = 0; i < chains.CountItems(); i++) { return;
if (strcmp(((BMailChain *)(chains.ItemAt(i)))->Name(),account_name) == 0) { SendViaAccount(account->AccountID());
SendViaAccount(((BMailChain *)(chains.ItemAt(i)))->ID());
break;
}
}
while (chains.CountItems() > 0)
delete (BMailChain *)chains.RemoveItem(0L);
} }
void 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; BString from;
from << '\"' << chain.MetaData()->FindString("real_name") << "\" <" << chain.MetaData()->FindString("reply_to") << '>'; if (accountSettings) {
SetFrom(from.String()); from << '\"' << accountSettings->RealName() << "\" <"
<< accountSettings->ReturnAddress() << '>';
}
SetFrom(from);
} }
int32 int32
BEmailMessage::Account() const 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) BEmailMessage::SetToRFC822(BPositionIO *mail_file, size_t length, bool parse_now)
{ {
if (BFile *file = dynamic_cast<BFile *>(mail_file)) if (BFile *file = dynamic_cast<BFile *>(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); mail_file->Seek(0,SEEK_END);
length = mail_file->Position(); length = mail_file->Position();
@@ -711,7 +705,7 @@ BEmailMessage::RenderToRFC822(BPositionIO *file)
if (From() == NULL) { if (From() == NULL) {
// set the "From:" string // set the "From:" string
SendViaAccount(_chain_id); SendViaAccount(_account_id);
} }
BList recipientList; BList recipientList;
@@ -807,14 +801,19 @@ BEmailMessage::RenderToRFC822(BPositionIO *file)
attributed->WriteAttrString(B_MAIL_ATTR_STATUS,&attr); attributed->WriteAttrString(B_MAIL_ATTR_STATUS,&attr);
attr = "1.0"; attr = "1.0";
attributed->WriteAttrString(B_MAIL_ATTR_MIME,&attr); 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->WriteAttrString(B_MAIL_ATTR_ACCOUNT,&attr);
attributed->WriteAttr(B_MAIL_ATTR_WHEN,B_TIME_TYPE,0,&creationTime,sizeof(int32)); attributed->WriteAttr(B_MAIL_ATTR_WHEN,B_TIME_TYPE,0,&creationTime,sizeof(int32));
int32 flags = B_MAIL_PENDING | B_MAIL_SAVE; int32 flags = B_MAIL_PENDING | B_MAIL_SAVE;
attributed->WriteAttr(B_MAIL_ATTR_FLAGS,B_INT32_TYPE,0,&flags,sizeof(int32)); 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; return B_OK;
@@ -902,15 +901,19 @@ BEmailMessage::RenderTo(BDirectory *dir, BEntry *msg)
status_t status_t
BEmailMessage::Send(bool send_now) BEmailMessage::Send(bool send_now)
{ {
BMailChain *via = new BMailChain(_chain_id); BMailAccounts accounts;
if ((via->InitCheck() != B_OK) || (via->ChainDirection() != outbound)) { BMailAccountSettings* account = accounts.AccountByID(_account_id);
delete via; if (!account || !account->HasOutbound()) {
via = new BMailChain(BMailSettings().DefaultOutboundChainID()); account = accounts.AccountByID(
SendViaAccount(via->ID()); BMailSettings().DefaultOutboundAccount());
if (!account)
return B_ERROR;
SendViaAccount(account->AccountID());
} }
BString path; BString path;
if (via->MetaData()->FindString("path", &path) != B_OK) { if (account->OutboundSettings().Settings().FindString("path", &path)
!= B_OK) {
BPath defaultMailOutPath; BPath defaultMailOutPath;
if (find_directory(B_USER_DIRECTORY, &defaultMailOutPath) != B_OK if (find_directory(B_USER_DIRECTORY, &defaultMailOutPath) != B_OK
|| defaultMailOutPath.Append("mail/out") != B_OK) || defaultMailOutPath.Append("mail/out") != B_OK)
@@ -925,7 +928,6 @@ BEmailMessage::Send(bool send_now)
BEntry message; BEntry message;
status_t status = RenderTo(&directory, &message); status_t status = RenderTo(&directory, &message);
delete via;
if (status >= B_OK && send_now) { if (status >= B_OK && send_now) {
BMailSettings settings_file; BMailSettings settings_file;
if (settings_file.SendOnlyIfPPPUp()) { if (settings_file.SendOnlyIfPPPUp()) {
@@ -955,7 +957,7 @@ BEmailMessage::Send(bool send_now)
return B_MAIL_NO_DAEMON; return B_MAIL_NO_DAEMON;
BMessage msg('msnd'); BMessage msg('msnd');
msg.AddInt32("chain",_chain_id); msg.AddInt32("account",_account_id);
BPath path; BPath path;
message.GetPath(&path); message.GetPath(&path);
msg.AddString("message_path",path.Path()); msg.AddString("message_path",path.Path());
File diff suppressed because it is too large Load Diff
+545 -114
View File
@@ -25,120 +25,12 @@
#include <stdlib.h> #include <stdlib.h>
class BMailSettings;
namespace MailInternal { namespace MailInternal {
status_t WriteMessageFile(const BMessage& archive, const BPath& path, status_t WriteMessageFile(const BMessage& archive, const BPath& path,
const char* name); 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 // #pragma mark - BMailSettings
@@ -398,16 +290,555 @@ BMailSettings::SetSendOnlyIfPPPUp(bool yes)
} }
uint32 int32
BMailSettings::DefaultOutboundChainID() BMailSettings::DefaultOutboundAccount()
{ {
return fData.FindInt32("DefaultOutboundChainID"); return fData.FindInt32("DefaultOutboundAccount");
} }
void void
BMailSettings::SetDefaultOutboundChainID(uint32 to) BMailSettings::SetDefaultOutboundAccount(int32 to)
{ {
if (fData.ReplaceInt32("DefaultOutboundChainID",to)) if (fData.ReplaceInt32("DefaultOutboundAccount",to))
fData.AddInt32("DefaultOutboundChainID",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<AddonSettings>::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());
} }
+114 -10
View File
@@ -24,6 +24,89 @@ class _EXPORT BMailProtocolConfigView;
#include "ProtocolConfigView.h" #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 { namespace {
//--------------------Support functions and #defines--------------- //--------------------Support functions and #defines---------------
@@ -48,7 +131,7 @@ TextControl(BView *parent,const char *name)
BTextControl * 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); BTextControl *text_control = new BTextControl(rect,name,label,"",NULL,B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
// text_control->SetDivider(be_plain_font->StringWidth(label)); // text_control->SetDivider(be_plain_font->StringWidth(label));
@@ -104,7 +187,9 @@ FindWidestLabel(BView *view)
//----------------Real code---------------------- //----------------Real code----------------------
BMailProtocolConfigView::BMailProtocolConfigView(uint32 options_mask) 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); BRect rect(5,5,245,25);
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
@@ -147,6 +232,12 @@ BMailProtocolConfigView::BMailProtocolConfigView(uint32 options_mask)
AddChild(box); AddChild(box);
} }
if (options_mask & B_MAIL_PROTOCOL_PARTIAL_DOWNLOAD) {
fBodyDownloadConfig = new BodyDownloadConfig();
fBodyDownloadConfig->MoveBy(0, rect.bottom + 5);
AddChild(fBodyDownloadConfig);
}
// resize views // resize views
float height; float height;
GetPreferredSize(&width,&height); GetPreferredSize(&width,&height);
@@ -165,21 +256,23 @@ BMailProtocolConfigView::~BMailProtocolConfigView()
void void
BMailProtocolConfigView::SetTo(BMessage *archive) BMailProtocolConfigView::SetTo(MailAddonSettings& settings)
{ {
const BMessage* archive = &settings.Settings();
BString host = archive->FindString("server"); BString host = archive->FindString("server");
if (archive->HasInt32("port")) if (archive->HasInt32("port"))
host << ':' << archive->FindInt32("port"); host << ':' << archive->FindInt32("port");
SetTextControl(this,"host",host.String()); SetTextControl(this,"host", host.String());
SetTextControl(this,"user",archive->FindString("username")); SetTextControl(this,"user", archive->FindString("username"));
char *password = get_passwd(archive,"cpasswd"); char *password = get_passwd(archive, "cpasswd");
if (password) { if (password) {
SetTextControl(this,"pass",password); SetTextControl(this,"pass", password);
delete[] password; delete[] password;
} else } else
SetTextControl(this,"pass",archive->FindString("password")); SetTextControl(this,"pass", archive->FindString("password"));
if (archive->HasInt32("flavor")) { if (archive->HasInt32("flavor")) {
BMenuField *menu = (BMenuField *)(FindView("flavor")); BMenuField *menu = (BMenuField *)(FindView("flavor"));
@@ -216,6 +309,9 @@ BMailProtocolConfigView::SetTo(BMessage *archive)
else else
box->SetEnabled(false); box->SetEnabled(false);
} }
if (fBodyDownloadConfig)
fBodyDownloadConfig->SetTo(settings);
} }
@@ -286,7 +382,7 @@ BMailProtocolConfigView::MessageReceived(BMessage *msg)
status_t status_t
BMailProtocolConfigView::Archive(BMessage *into, bool) const BMailProtocolConfigView::Archive(BMessage *into, bool deep) const
{ {
const char *host = TextControl((BView *)this,"host"); const char *host = TextControl((BView *)this,"host");
int32 port = -1; int32 port = -1;
@@ -348,7 +444,9 @@ BMailProtocolConfigView::Archive(BMessage *into, bool) const
if (into->ReplaceBool("delete_remote_when_local",false) != B_OK) if (into->ReplaceBool("delete_remote_when_local",false) != B_OK)
into->AddBool("delete_remote_when_local",false); into->AddBool("delete_remote_when_local",false);
} }
if (fBodyDownloadConfig)
fBodyDownloadConfig->Archive(into, deep);
return B_OK; return B_OK;
} }
@@ -365,5 +463,11 @@ BMailProtocolConfigView::GetPreferredSize(float *width, float *height)
minWidth = 250; minWidth = 250;
*width = minWidth + 10; *width = minWidth + 10;
*height = (CountChildren() * sItemHeight) + 5; *height = (CountChildren() * sItemHeight) + 5;
if (fBodyDownloadConfig) {
float bodyW, bodyH;
fBodyDownloadConfig->GetPreferredSize(&bodyW, &bodyH);
*height+= bodyH;
}
} }
-438
View File
@@ -1,438 +0,0 @@
#include <NodeMonitor.h>
#include <Handler.h>
#include <Directory.h>
#include <Entry.h>
#include <Path.h>
#include <String.h>
#include <File.h>
#include <map>
#include <stdlib.h>
class _EXPORT BRemoteMailStorageProtocol;
#include <RemoteStorageProtocol.h>
#include <ChainRunner.h>
#include <E-mail.h>
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<int64, const char *> 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);
}
}
-138
View File
@@ -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 <Entry.h>
class _EXPORT BMailMessage;
#include <E-mail.h>
#include <MailAttachment.h>
#include <MailMessage.h>
#include <stdio.h>
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);
}
-141
View File
@@ -1,141 +0,0 @@
/* C-mail API - compatibility function (stubs) for the old mail kit
**
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
*/
#include <E-mail.h>
#include <FindDirectory.h>
#include <Path.h>
#include <File.h>
#include <Directory.h>
#include <List.h>
#include <string.h>
#include <MailDaemon.h>
#include <MailSettings.h>
#include <MailMessage.h>
#include <crypt.h>
_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);
}
-28
View File
@@ -1,28 +0,0 @@
#include <mail_encoding.h>
#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
+1 -1
View File
@@ -13,7 +13,7 @@
static const char key[PASSWORD_LENGTH + 1] = "Dr. Zoidberg Enterprises, BeMail"; 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; char *encryptedPassword;
ssize_t length; ssize_t length;
+50
View File
@@ -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 _EXPORT void
extract_address(BString &address) extract_address(BString &address)
{ {
+16 -18
View File
@@ -222,10 +222,10 @@ DeskbarView::MessageReceived(BMessage* message)
case MD_CHECK_SEND_NOW: case MD_CHECK_SEND_NOW:
// also happens in DeskbarView::MouseUp() with // also happens in DeskbarView::MouseUp() with
// B_TERTIARY_MOUSE_BUTTON pressed // B_TERTIARY_MOUSE_BUTTON pressed
BMailDaemon::CheckMail(true); BMailDaemon::CheckAndSendQueuedMail();
break; break;
case MD_CHECK_FOR_MAILS: case MD_CHECK_FOR_MAILS:
BMailDaemon::CheckMail(false,message->FindString("account")); BMailDaemon::CheckMail(message->FindInt32("account"));
break; break;
case MD_SEND_MAILS: case MD_SEND_MAILS:
BMailDaemon::SendQueuedMail(); BMailDaemon::SendQueuedMail();
@@ -365,7 +365,7 @@ DeskbarView::MouseUp(BPoint pos)
} }
if (fLastButtons & B_TERTIARY_MOUSE_BUTTON) if (fLastButtons & B_TERTIARY_MOUSE_BUTTON)
BMailDaemon::CheckMail(true); BMailDaemon::CheckMail();
} }
@@ -556,32 +556,30 @@ DeskbarView::_BuildMenu()
item->SetEnabled(false); item->SetEnabled(false);
} }
BList list; BMailAccounts accounts;
GetInboundMailChains(&list);
if (modifiers() & B_SHIFT_KEY) { if (modifiers() & B_SHIFT_KEY) {
BMenu *chainMenu = new BMenu( BMenu *accountMenu = new BMenu(
MDR_DIALECT_CHOICE ("Check for mails only","R) メール受信のみ")); MDR_DIALECT_CHOICE ("Check for mails only","R) メール受信のみ"));
BFont font; BFont font;
menu->GetFont(&font); menu->GetFont(&font);
chainMenu->SetFont(&font); accountMenu->SetFont(&font);
for (int32 i = 0; i < list.CountItems(); i++) { for (int32 i = 0; i < accounts.CountAccounts(); i++) {
BMailChain* chain = (BMailChain*)list.ItemAt(i); BMailAccountSettings* account = accounts.AccountAt(i);
BMessage* message = new BMessage(MD_CHECK_FOR_MAILS); 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)); accountMenu->AddItem(new BMenuItem(account->Name(), message));
delete chain;
} }
if (list.IsEmpty()) { if (accounts.CountAccounts() == 0) {
item = new BMenuItem("<no accounts>", NULL); item = new BMenuItem("<no accounts>", NULL);
item->SetEnabled(false); item->SetEnabled(false);
chainMenu->AddItem(item); accountMenu->AddItem(item);
} }
chainMenu->SetTargetForItems(this); accountMenu->SetTargetForItems(this);
menu->AddItem(new BMenuItem(chainMenu, new BMessage(MD_CHECK_FOR_MAILS))); menu->AddItem(new BMenuItem(accountMenu,
new BMessage(MD_CHECK_FOR_MAILS)));
// Not used: // Not used:
// menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE ( // menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE (
@@ -593,7 +591,7 @@ DeskbarView::_BuildMenu()
menu->AddItem(item = new BMenuItem( menu->AddItem(item = new BMenuItem(
MDR_DIALECT_CHOICE ("Check for mail now", "C) メールチェック"), MDR_DIALECT_CHOICE ("Check for mail now", "C) メールチェック"),
new BMessage(MD_CHECK_SEND_NOW))); new BMessage(MD_CHECK_SEND_NOW)));
if (list.IsEmpty()) if (accounts.CountAccounts() == 0)
item->SetEnabled(false); item->SetEnabled(false);
} }
@@ -53,14 +53,18 @@ class ErrorPanel : public BView {
ErrorLogWindow::ErrorLogWindow(BRect rect, const char *name, window_type type) 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 = Bounds();
rect.right -= B_V_SCROLL_BAR_WIDTH; rect.right -= B_V_SCROLL_BAR_WIDTH;
view = new ErrorPanel(rect); view = new ErrorPanel(rect);
AddChild(new BScrollView("ErrorScroller", view, B_FOLLOW_ALL_SIDES, 0, false, true)); 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; ErrorPanel *panel = (ErrorPanel *)view;
// first call?
if (!fIsRunning) {
fIsRunning = true;
Show();
}
Lock(); Lock();
Error *newError = new Error(BRect(0, panel->add_next_at, panel->Bounds().right, Error *newError = new Error(BRect(0, panel->add_next_at, panel->Bounds().right,
@@ -101,8 +111,11 @@ ErrorLogWindow::QuitRequested()
{ {
Hide(); Hide();
while (view->CountChildren() != 0) while (view->CountChildren() != 0) {
view->RemoveChild(view->ChildAt(0)); BView* child = view->ChildAt(0);
view->RemoveChild(child);
delete child;
}
ErrorPanel *panel = (ErrorPanel *)(view); ErrorPanel *panel = (ErrorPanel *)(view);
panel->add_next_at = 0; panel->add_next_at = 0;
@@ -135,7 +148,13 @@ ErrorLogWindow::FrameResized(float newWidth, float newHeight)
// #pragma mark - // #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); SetViewColor(bkg);
SetLowColor(bkg); SetLowColor(bkg);
@@ -148,16 +167,21 @@ Error::Error(BRect rect,alert_type atype,const char *tag,const char *message,boo
BString msgString(message); BString msgString(message);
msgString.RemoveAll("\r"); 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->SetLowColor(bkg);
view->SetViewColor(bkg); view->SetViewColor(bkg);
view->SetText(msgString.String()); view->SetText(msgString.String());
view->MakeSelectable(true); view->MakeSelectable(true);
view->SetStylable(true); view->SetStylable(true);
view->MakeEditable(false); view->MakeEditable(false);
if (tag != NULL) if (tag != NULL) {
view->Insert(0,tag,strlen(tag),&array); BString tagString(tag);
tagString += " ";
view->Insert(0, tagString.String(), tagString.Length(), &array);
}
if (timestamp) { if (timestamp) {
array.runs[0].color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),B_DARKEN_2_TINT); array.runs[0].color = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),B_DARKEN_2_TINT);
@@ -5,7 +5,7 @@
#include <Alert.h> #include <Alert.h>
class ErrorLogWindow : public BWindow { class ErrorLogWindow : public BWindow {
public: public:
ErrorLogWindow(BRect rect, const char *name, window_type type); ErrorLogWindow(BRect rect, const char *name, window_type type);
void AddError(alert_type type,const char *message,const char *tag = NULL,bool timestamp = true); 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(); bool QuitRequested();
void FrameResized(float new_width, float new_height); void FrameResized(float new_width, float new_height);
private: private:
BView *view; BView *view;
bool fIsRunning;
}; };
#endif // ZOIDBERG_MAIL_ERRORLOGWINDOW_H #endif // ZOIDBERG_MAIL_ERRORLOGWINDOW_H
+4
View File
@@ -17,8 +17,12 @@ AddResources mail_daemon : mail_daemon.rdef DeskbarViewIcons.rdef ;
Server mail_daemon : Server mail_daemon :
DeskbarView.cpp DeskbarView.cpp
ErrorLogWindow.cpp
LEDAnimation.cpp LEDAnimation.cpp
MailDaemon.cpp
main.cpp main.cpp
Notifier.cpp
StatusWindow.cpp
; ;
LinkAgainst mail_daemon : be libmail.so tracker $(TARGET_LIBSTDC++) $(TARGET_NETWORK_LIBS) ; LinkAgainst mail_daemon : be libmail.so tracker $(TARGET_LIBSTDC++) $(TARGET_NETWORK_LIBS) ;
+860
View File
@@ -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 <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License.
*/
#include "MailDaemon.h"
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <Beep.h>
#include <Deskbar.h>
#include <Directory.h>
#include <Entry.h>
#include <FindDirectory.h>
#include <fs_index.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <Roster.h>
#include <StringList.h>
#include <VolumeRoster.h>
#include <E-mail.h>
#include <MailDaemon.h>
#include <MailMessage.h>
#include <MailSettings.h>
#include <MDRLanguage.h>
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<entry_ref> files;
off_t totalSize;
};
void
MailDaemonApp::SendPendingMessages(BMessage* msg)
{
BVolumeRoster roster;
BVolume volume;
map<int32, send_mails_info> 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<int32, send_mails_info>::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);
}
+114
View File
@@ -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 <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License.
*/
#ifndef MAIL_DAEMON_APP_H
#define MAIL_DAEMON_APP_H
#include <map>
#include <Application.h>
#include <ObjectList.h>
#include <Message.h>
#include <MessageRunner.h>
#include <Node.h>
#include <Query.h>
#include <String.h>
#include <MailProtocol.h>
#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<int32, account_protocols> 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<BMessage> fFetchDoneRespondents;
BObjectList<BQuery> fQueries;
LEDAnimation* fLEDAnimation;
BString fAlertString;
AccountMap fAccounts;
ErrorLogWindow* fErrorLogWindow;
MailStatusWindow* fMailStatusWindow;
};
#endif // MAIL_DAEMON_APP_H
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
* 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);
}
+44
View File
@@ -0,0 +1,44 @@
/*
* Copyright 2011, Haiku, Inc. All rights reserved.
* Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License.
*/
#ifndef NOTIFIER_H
#define NOTIFIER_H
#include <String.h>
#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
@@ -9,7 +9,8 @@
//! The status window while fetching/sending mails //! The status window while fetching/sending mails
#include "status.h" #include "StatusWindow.h"
#include "MailSettings.h" #include "MailSettings.h"
#include <MDRLanguage.h> #include <MDRLanguage.h>
@@ -36,9 +37,10 @@
static BLocker sLock; static BLocker sLock;
BMailStatusWindow::BMailStatusWindow(BRect rect, const char *name, MailStatusWindow::MailStatusWindow(BRect rect, const char *name,
uint32 showMode) 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_CLOSABLE | B_NO_WORKSPACE_ACTIVATION | B_NOT_V_RESIZABLE
| B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AVOID_FRONT), | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AVOID_FRONT),
fShowMode(showMode), fShowMode(showMode),
@@ -118,10 +120,8 @@ BMailStatusWindow::BMailStatusWindow(BRect rect, const char *name,
fFrame = Frame(); fFrame = Frame();
BPath path; BPath path;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path); status_t status = BMailAccounts::AccountsPath(path);
if (status == B_OK) { if (status == B_OK) {
path.Append("Mail/chains/inbound");
create_directory(path.Path(), 0755);
BDirectory chainDirectory(path.Path()); BDirectory chainDirectory(path.Path());
if (chainDirectory.GetNodeRef(&fChainDirectory) == B_OK) { if (chainDirectory.GetNodeRef(&fChainDirectory) == B_OK) {
// Watch this directory for changes // 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 // 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); RemoveView(status_view);
BMailSettings general; BMailSettings general;
@@ -157,19 +157,23 @@ BMailStatusWindow::~BMailStatusWindow()
//! Activate the "Check Now" button only if there are inbound accounts //! Activate the "Check Now" button only if there are inbound accounts
void 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; fCheckNowButton->SetEnabled(hasInbound);
bool isEmpty = directory.GetNextRef(&ref) != B_OK;
fCheckNowButton->SetEnabled(!isEmpty);
} }
void void
BMailStatusWindow::FrameMoved(BPoint /*origin*/) MailStatusWindow::FrameMoved(BPoint /*origin*/)
{ {
if (fLastWorkspace == current_workspace()) if (fLastWorkspace == current_workspace())
fFrame = Frame(); fFrame = Frame();
@@ -177,7 +181,7 @@ BMailStatusWindow::FrameMoved(BPoint /*origin*/)
void void
BMailStatusWindow::WorkspaceActivated(int32 workspace, bool active) MailStatusWindow::WorkspaceActivated(int32 workspace, bool active)
{ {
if (!active) if (!active)
return; return;
@@ -195,7 +199,7 @@ BMailStatusWindow::WorkspaceActivated(int32 workspace, bool active)
void void
BMailStatusWindow::MessageReceived(BMessage *msg) MailStatusWindow::MessageReceived(BMessage *msg)
{ {
switch (msg->what) { switch (msg->what) {
case 'lkch': case 'lkch':
@@ -232,7 +236,7 @@ BMailStatusWindow::MessageReceived(BMessage *msg)
void void
BMailStatusWindow::SetDefaultMessage(const BString &message) MailStatusWindow::SetDefaultMessage(const BString &message)
{ {
if (Lock()) { if (Lock()) {
fMessageView->SetText(message.String()); fMessageView->SetText(message.String());
@@ -241,8 +245,8 @@ BMailStatusWindow::SetDefaultMessage(const BString &message)
} }
BMailStatusView * MailStatusView *
BMailStatusWindow::NewStatusView(const char *description, bool upstream) MailStatusWindow::NewStatusView(const char *description, bool upstream)
{ {
if (!Lock()) if (!Lock())
return NULL; return NULL;
@@ -250,7 +254,7 @@ BMailStatusWindow::NewStatusView(const char *description, bool upstream)
BRect rect = Bounds(); BRect rect = Bounds();
rect.top = fStatusViews.CountItems() * (fMinHeight + 1); rect.top = fStatusViews.CountItems() * (fMinHeight + 1);
rect.bottom = rect.top + fMinHeight; rect.bottom = rect.top + fMinHeight;
BMailStatusView *status = new BMailStatusView(rect, description, upstream); MailStatusView *status = new MailStatusView(rect, description, upstream);
status->window = this; status->window = this;
Unlock(); Unlock();
@@ -259,7 +263,7 @@ BMailStatusWindow::NewStatusView(const char *description, bool upstream)
void void
BMailStatusWindow::ActuallyAddStatusView(BMailStatusView *status) MailStatusWindow::ActuallyAddStatusView(MailStatusView *status)
{ {
if (!Lock()) if (!Lock())
return; return;
@@ -307,7 +311,7 @@ BMailStatusWindow::ActuallyAddStatusView(BMailStatusView *status)
void void
BMailStatusWindow::RemoveView(BMailStatusView *view) MailStatusWindow::RemoveView(MailStatusView *view)
{ {
if (!view || !Lock()) if (!view || !Lock())
return; return;
@@ -324,7 +328,7 @@ BMailStatusWindow::RemoveView(BMailStatusView *view)
fStatusViews.RemoveItem((void *)view); fStatusViews.RemoveItem((void *)view);
if (RemoveChild(view)) { if (RemoveChild(view)) {
while ((view = (BMailStatusView *)fStatusViews.ItemAt(i++)) != NULL) while ((view = (MailStatusView *)fStatusViews.ItemAt(i++)) != NULL)
view->MoveBy(0, -fMinHeight - 1); view->MoveBy(0, -fMinHeight - 1);
// the view will be deleted in the ChainRunner // the view will be deleted in the ChainRunner
@@ -360,14 +364,14 @@ BMailStatusWindow::RemoveView(BMailStatusView *view)
int32 int32
BMailStatusWindow::CountVisibleItems() MailStatusWindow::CountVisibleItems()
{ {
if (fShowMode != B_MAIL_SHOW_STATUS_WINDOW_WHEN_SENDING) if (fShowMode != B_MAIL_SHOW_STATUS_WINDOW_WHEN_SENDING)
return fStatusViews.CountItems(); return fStatusViews.CountItems();
int32 count = 0; int32 count = 0;
for (int32 i = fStatusViews.CountItems(); i-- > 0;) { for (int32 i = fStatusViews.CountItems(); i-- > 0;) {
BMailStatusView *view = (BMailStatusView *)fStatusViews.ItemAt(i); MailStatusView *view = (MailStatusView *)fStatusViews.ItemAt(i);
if (view->is_upstream) if (view->is_upstream)
count++; count++;
} }
@@ -376,14 +380,14 @@ BMailStatusWindow::CountVisibleItems()
bool bool
BMailStatusWindow::HasItems(void) MailStatusWindow::HasItems(void)
{ {
return CountVisibleItems() > 0; return CountVisibleItems() > 0;
} }
void void
BMailStatusWindow::SetShowCriterion(uint32 when) MailStatusWindow::SetShowCriterion(uint32 when)
{ {
if (!Lock()) if (!Lock())
return; return;
@@ -403,7 +407,7 @@ BMailStatusWindow::SetShowCriterion(uint32 when)
void void
BMailStatusWindow::SetBorderStyle(int32 look) MailStatusWindow::SetBorderStyle(int32 look)
{ {
switch (look) { switch (look) {
case B_MAIL_STATUS_LOOK_TITLED: case B_MAIL_STATUS_LOOK_TITLED:
@@ -429,12 +433,12 @@ BMailStatusWindow::SetBorderStyle(int32 look)
// #pragma mark - // #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, : BBox(rect, description, B_FOLLOW_LEFT_RIGHT,
B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP, B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE_JUMP,
B_PLAIN_BORDER) B_PLAIN_BORDER)
@@ -454,16 +458,18 @@ BMailStatusView::BMailStatusView(BRect rect, const char *description,bool upstre
total_items = 0; total_items = 0;
pre_text[0] = 0; pre_text[0] = 0;
is_upstream = upstream; is_upstream = upstream;
by_bytes = false;
} }
BMailStatusView::~BMailStatusView() MailStatusView::~MailStatusView()
{ {
} }
void void
BMailStatusView::AddProgress(int32 how_much) MailStatusView::AddProgress(int32 how_much)
{ {
AddSelfToWindow(); AddSelfToWindow();
@@ -484,7 +490,7 @@ BMailStatusView::AddProgress(int32 how_much)
void void
BMailStatusView::SetMessage(const char *msg) MailStatusView::SetMessage(const char *msg)
{ {
AddSelfToWindow(); AddSelfToWindow();
@@ -496,31 +502,34 @@ BMailStatusView::SetMessage(const char *msg)
void void
BMailStatusView::Reset(bool hide) MailStatusView::Reset(bool hide)
{ {
if (LockLooper()) { if (!LockLooper())
char old[255]; return;
if ((pre_text[0] == 0) && !hide)
strcpy(pre_text, status->TrailingText());
if (hide)
pre_text[0] = 0;
strcpy(old,status->Label()); char old[255];
status->Reset(old); if ((pre_text[0] == 0) && !hide)
status->SetTrailingText(pre_text); strcpy(pre_text, status->TrailingText());
status->Draw(status->Bounds()); if (hide)
pre_text[0] = 0; pre_text[0] = 0;
total_items = 0;
items_now = 0; strcpy(old,status->Label());
UnlockLooper(); 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()) if (hide && Window())
window->RemoveView(this); window->RemoveView(this);
} }
void void
BMailStatusView::SetMaximum(int32 max_bytes) MailStatusView::SetMaximum(int32 max_bytes)
{ {
AddSelfToWindow(); AddSelfToWindow();
@@ -538,22 +547,24 @@ BMailStatusView::SetMaximum(int32 max_bytes)
void void
BMailStatusView::SetTotalItems(int32 items) MailStatusView::SetTotalItems(int32 items)
{ {
AddSelfToWindow(); AddSelfToWindow();
total_items = items; total_items = items;
if (!by_bytes)
SetMaximum(-1);
} }
int32 int32
BMailStatusView::CountTotalItems() MailStatusView::CountTotalItems()
{ {
return total_items; return total_items;
} }
void void
BMailStatusView::AddItem(void) MailStatusView::AddItem(void)
{ {
AddSelfToWindow(); AddSelfToWindow();
items_now++; items_now++;
@@ -564,7 +575,7 @@ BMailStatusView::AddItem(void)
void void
BMailStatusView::AddSelfToWindow() MailStatusView::AddSelfToWindow()
{ {
if (Window() != NULL) if (Window() != NULL)
return; return;
@@ -16,19 +16,19 @@
class BStatusBar; class BStatusBar;
class BStringView; class BStringView;
class BMailStatusView; class MailStatusView;
class BMailStatusWindow : public BWindow { class MailStatusWindow : public BWindow {
public: public:
BMailStatusWindow(BRect rect, const char *name, uint32 showMode); MailStatusWindow(BRect rect, const char *name, uint32 showMode);
~BMailStatusWindow(); ~MailStatusWindow();
virtual void FrameMoved(BPoint origin); virtual void FrameMoved(BPoint origin);
virtual void WorkspaceActivated(int32 workspace, bool active); virtual void WorkspaceActivated(int32 workspace, bool active);
virtual void MessageReceived(BMessage *msg); virtual void MessageReceived(BMessage *msg);
BMailStatusView *NewStatusView(const char *description, bool upstream); MailStatusView *NewStatusView(const char *description, bool upstream);
void RemoveView(BMailStatusView *view); void RemoveView(MailStatusView *view);
int32 CountVisibleItems(); int32 CountVisibleItems();
bool HasItems(void); bool HasItems(void);
@@ -36,11 +36,11 @@ class BMailStatusWindow : public BWindow {
void SetDefaultMessage(const BString &message); void SetDefaultMessage(const BString &message);
private: private:
friend class BMailStatusView; friend class MailStatusView;
void _CheckChains(); void _CheckChains();
void SetBorderStyle(int32 look); void SetBorderStyle(int32 look);
void ActuallyAddStatusView(BMailStatusView *status); void ActuallyAddStatusView(MailStatusView *status);
node_ref fChainDirectory; node_ref fChainDirectory;
BButton* fCheckNowButton; BButton* fCheckNowButton;
@@ -57,26 +57,27 @@ class BMailStatusWindow : public BWindow {
uint32 _reserved[5]; uint32 _reserved[5];
}; };
class BMailStatusView : public BBox { class MailStatusView : public BBox {
public: public:
void AddProgress(int32 how_much); ~MailStatusView();
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();
private: void AddProgress(int32 how_much);
friend class BMailStatusWindow; 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(); void AddSelfToWindow();
BStatusBar *status; BStatusBar *status;
BMailStatusWindow *window; MailStatusWindow *window;
int32 items_now; int32 items_now;
int32 total_items; int32 total_items;
bool is_upstream; bool is_upstream;
+7 -788
View File
@@ -1,786 +1,12 @@
/* /*
* Copyright 2009-2010, Axel Dörfler, axeld@pinc-software.de. * Copyright 2007-2011, Haiku, Inc. All rights reserved.
* Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved. * Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
* * Copyright 2011, Clemens Zeidler <haiku@clemens-zeidler.de>
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
//! The daemon's inner workings #include "MailDaemon.h"
#include <Application.h>
#include <Beep.h>
#include <Button.h>
#include <ChainRunner.h>
#include <Deskbar.h>
#include <Directory.h>
#include <File.h>
#include <FindDirectory.h>
#include <fs_index.h>
#include <fs_info.h>
#include <Message.h>
#include <MessageRunner.h>
#include <Mime.h>
#include <NodeMonitor.h>
#include <Path.h>
#include <Query.h>
#include <Roster.h>
#include <String.h>
#include <StringView.h>
#include <VolumeRoster.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <map>
#include <E-mail.h>
#include <MailSettings.h>
#include <MailMessage.h>
#include <status.h>
#include <StringList.h>
#include "DeskbarView.h"
#include "LEDAnimation.h"
#include <MDRLanguage.h>
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<int32, snuzzwut*> 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<int32, snuzzwut*>::iterator iter = messages.begin();
map<int32, snuzzwut*>::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();
}
}
int int
@@ -799,15 +25,8 @@ main(int argc, const char** argv)
} }
MailDaemonApp app; MailDaemonApp app;
if (remakeMIMETypes)
// install MimeTypes, attributes, indices, and the app.MakeMimeTypes(true);
// system beep add startup app.Run();
makeMimeType(remakeMIMETypes);
makeIndices();
add_system_beep_event("New E-mail");
be_app->Run();
return 0; return 0;
} }