Imported MDR. Some code still not entirely functional -- I haven't been able to figure out how to detect SSL, so IMAP and POP have it turned off. PPP auto-detect is also not functional at the moment. Other than that, it seems to work beautifully. Packaging will come later.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9016 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
#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>
|
||||
#include <status.h>
|
||||
|
||||
class BStringList;
|
||||
class BMailStatusWindow;
|
||||
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();
|
||||
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 */
|
||||
@@ -0,0 +1,151 @@
|
||||
#ifndef ZOIDBERG_MAIL_ADDON_H
|
||||
#define ZOIDBERG_MAIL_ADDON_H
|
||||
/* Filter - the base class for all mail filters
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
class BMessage;
|
||||
class BView;
|
||||
class BPositionIO;
|
||||
class BEntry;
|
||||
class BPath;
|
||||
class BView;
|
||||
class BString;
|
||||
class BPositionIO;
|
||||
class BEntry;
|
||||
|
||||
enum {
|
||||
B_MAIL_DISCARD = B_MAIL_ERROR_BASE + 8,
|
||||
//--- This terminates the chain and removes the message being processed
|
||||
// both from disk and from the server.
|
||||
B_MAIL_END_FETCH,
|
||||
//--- Terminates the current operation
|
||||
B_MAIL_END_CHAIN
|
||||
//--- This is for yikes errors, like an unreachable server.
|
||||
};
|
||||
|
||||
class BMailStatusView;
|
||||
class BMailChainRunner;
|
||||
|
||||
class BMailFilter
|
||||
{
|
||||
public:
|
||||
BMailFilter(BMessage* settings);
|
||||
// How to support queueing messages until a time of the
|
||||
// day/week/month/year? The settings will contain a
|
||||
// persistent ChainID field, the same for all Filters
|
||||
// on the same "chain".
|
||||
|
||||
virtual ~BMailFilter();
|
||||
// This will be called when the settings for this Filter
|
||||
// are changed, or there are no new messages to consume
|
||||
// after settings->FindInt32("timeout") seconds.
|
||||
|
||||
virtual status_t InitCheck(BString* out_message = NULL) = 0;
|
||||
// Returns B_OK if the Filter was constructed success-
|
||||
// fully. Otherwise it returns an error code. If it is
|
||||
// passed a valid BString*, it may add an error message
|
||||
// to the end of that BString iff it returns an error.
|
||||
// If it returns an error code then the MailFilter will
|
||||
// probably be deleted and the error shown to the user.
|
||||
|
||||
virtual status_t ProcessMailMessage
|
||||
(
|
||||
BPositionIO** io_message, BEntry* io_entry,
|
||||
BMessage* io_headers, BPath* io_folder, const char *io_uid
|
||||
) = 0;
|
||||
// Filters a message. On input and output, the arguments
|
||||
// are expected to be as below; however it is allowed for
|
||||
// the MailFilter to alter any of these values as nece-
|
||||
// ssary, so long as the constraints are as described when
|
||||
// the function returns:
|
||||
//
|
||||
// * io_message - a PositionIO that contains the message
|
||||
// data, pointing to the first byte of the message's
|
||||
// header. This can be swapped if, eg, the message
|
||||
// is copied across volume boundries. When the chain
|
||||
// begins this is a file in /tmp.
|
||||
// * io_entry - The entry for the PositionIO above.
|
||||
// * io_headers - a list of attributes that will be added
|
||||
// to the message file.
|
||||
// * io_folder - The message's "folder"---may be com-
|
||||
// pletely unrelated to its on-disk Entry.
|
||||
// * io_uid - The unique ID provided by the message's
|
||||
// Protocol
|
||||
//
|
||||
// At most one Filter::ProcessMailMessage() for a given
|
||||
// chain (and thus ChainID) will be called at a time.
|
||||
|
||||
private:
|
||||
virtual void _ReservedFilter1();
|
||||
virtual void _ReservedFilter2();
|
||||
virtual void _ReservedFilter3();
|
||||
virtual void _ReservedFilter4();
|
||||
};
|
||||
|
||||
//
|
||||
// The addon interface: export instantiate_mailfilter()
|
||||
// and instantiate_mailconfig() to create a Filter addon
|
||||
//
|
||||
|
||||
extern "C" _EXPORT BView* instantiate_config_panel(BMessage *settings,BMessage *metadata);
|
||||
// return a view that configures the MailProtocol or MailFilter
|
||||
// returned by the functions below. BView::Archive(foo,true)
|
||||
// produces this addon's settings, which are passed to the in-
|
||||
// stantiate_* functions and stored persistently. This function
|
||||
// should gracefully handle empty and NULL settings.
|
||||
// A note on the metadata argument: The metadata pointer is
|
||||
// guaranteed to remain valid as long as this view exists. As it is
|
||||
// a pointer to the chain's metadata, your view can save any
|
||||
// chain-global settings to it in its Archive() function. Note that
|
||||
// you must cache this pointer yourself! You will never get it again.
|
||||
// Also note that it is possible for it to be NULL.
|
||||
|
||||
extern "C" _EXPORT BMailFilter* instantiate_mailfilter(BMessage *settings,
|
||||
BMailChainRunner *runner);
|
||||
// Return a MailProtocol or MailFilter ready to do its thing,
|
||||
// based on settings produced by archiving your config panel.
|
||||
// Note that a Mail::Protocol is a Mail::Filter, so use
|
||||
// instantiate_mailfilter to start things up.
|
||||
|
||||
extern "C" _EXPORT status_t descriptive_name(BMessage *msg, char *buffer);
|
||||
// the config panel will show this name in the chains filter
|
||||
// list if this function returns B_OK.
|
||||
// The buffer is as big as B_FILE_NAME_LENGTH.
|
||||
|
||||
// standard Filters:
|
||||
//
|
||||
// * Parser - does ParseRFC2822(io_message,io_headers)
|
||||
// * Folder - stores the message in the specified folder,
|
||||
// optionally under io_folder, returns MD_HANDLED
|
||||
// * HeaderFilter(regex,Yes_fiters,No_filters) -
|
||||
// Applies Nes_filters to messages that have a header
|
||||
// matching regex; applies No_filters otherwise.
|
||||
// * CompatabilityFilter - Invokes the standard mail_dae-
|
||||
// mon filter ~/config/settings/add-ons/MailDaemon/Filter
|
||||
// on the message's Entry.
|
||||
// * Producer - Reads outbound messages from disk and inserts
|
||||
// them into the queue.
|
||||
// * SMTPSender - Sends the message, via the specified
|
||||
// SMTP server, to the people in header field
|
||||
// "MAIL:recipients", changes the the Entry's
|
||||
// "MAIL:flags" field to no longer pending, changes the
|
||||
// "MAIL:status" header field to "Sent", and adds a header
|
||||
// field "MAIL:when" with the time it was sent.
|
||||
// * Dumper - returns MD_DISCARD
|
||||
//
|
||||
//
|
||||
// Standard chain types:
|
||||
//
|
||||
// Incoming Mail: Protocol - Parser - Notifier - Folder
|
||||
// Outgoing Mail: Producer - SMTPSender
|
||||
//
|
||||
// "chains" are lists of addons that appear in, or can be
|
||||
// added to, the "Accounts" list in the config panel, a tree-
|
||||
// view ordered by the chain type and the chain's AccountName().
|
||||
// Their config views should be shown, one after the other,
|
||||
// in the config panel.
|
||||
|
||||
#endif /* ZOIDBERG_MAIL_ADDON_H */
|
||||
@@ -0,0 +1,107 @@
|
||||
#ifndef ZOIDBERG_MAIL_PROTOCOL_H
|
||||
#define ZOIDBERG_MAIL_PROTOCOL_H
|
||||
/* Protocol - the base class for protocol filters
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <OS.h>
|
||||
|
||||
#include <MailAddon.h>
|
||||
|
||||
|
||||
class BHandler;
|
||||
class BStringList;
|
||||
class BMailChainRunner;
|
||||
|
||||
class BMailProtocol : public BMailFilter
|
||||
{
|
||||
public:
|
||||
BMailProtocol(BMessage* settings, BMailChainRunner *runner);
|
||||
// Open a connection based on 'settings'. 'settings' will
|
||||
// contain a persistent uint32 ChainID field. At most one
|
||||
// Protocol per ChainID will exist at a given time.
|
||||
// The constructor of Mail::Protocol initializes manifest.
|
||||
// It is your responsibility to fill in unique_ids, *and
|
||||
// to keep it updated* in the course of whatever nefarious
|
||||
// things your protocol does.
|
||||
|
||||
virtual ~BMailProtocol();
|
||||
// Close the connection and clean up. This will be cal-
|
||||
// led after FetchMessage() or FetchNewMessage() returns
|
||||
// B_TIMED_OUT or B_ERROR, or when the settings for this
|
||||
// Protocol are changed.
|
||||
|
||||
virtual status_t GetMessage(
|
||||
const char* uid,
|
||||
BPositionIO** out_file, BMessage* out_headers,
|
||||
BPath* out_folder_location
|
||||
)=0;
|
||||
// Downloads the message with id uid, writing the message's
|
||||
// RFC2822 contents to *out_file and storing any headers it
|
||||
// wants to add other than those from the message itself into
|
||||
// out_headers. It may store a path (if this type of account
|
||||
// supports folders) in *out_folder_location.
|
||||
//
|
||||
// Returns B_OK if the message is now available in out_file,
|
||||
// B_NAME_NOT_FOUND if there is no message with id 'uid' on
|
||||
// the server, or another error if the connection failed.
|
||||
//
|
||||
// B_OK will cause the message to be stored and processed.
|
||||
// B_NAME_NOT_FOUND will cause appropriate recovery to be
|
||||
// taken (if such exists) but not cause the connection to
|
||||
// be terminated. Any other error will cause anything writen
|
||||
// to be discarded and and the connection closed.
|
||||
|
||||
// OBS:
|
||||
// The Protocol may replace *out_file with a custom (read-
|
||||
// only) BPositionIO-derived object that preserves the il-
|
||||
// lusion that the message is writen to *out_file, but in
|
||||
// fact only reads from the server and writes to *out_file
|
||||
// on demand. This BPositionIO must guarantee that any
|
||||
// data returned by Read() has also been writen to *out_-
|
||||
// file. It must return a read error if reading from the
|
||||
// network or writing to *out_file fails.
|
||||
//
|
||||
// The mail_daemon will delete *out_file before invoking
|
||||
// FetchMessage() or FetchNewMessage() again.
|
||||
|
||||
virtual status_t DeleteMessage(const char* uid)=0;
|
||||
// Removes the message from the server. After this, it's
|
||||
// assumed (but not required) that GetMessage(uid,...)
|
||||
// et al will fail with B_NAME_NOT_FOUND.
|
||||
|
||||
void CheckForDeletedMessages();
|
||||
// You can call this to trigger a sweep for deleted messages.
|
||||
// Automatically called at the beginning of the chain.
|
||||
|
||||
//------MailFilter calls
|
||||
virtual status_t ProcessMailMessage
|
||||
(
|
||||
BPositionIO** io_message, BEntry* io_entry,
|
||||
BMessage* io_headers, BPath* io_folder, const char* io_uid
|
||||
);
|
||||
|
||||
protected:
|
||||
BStringList *manifest, *unique_ids;
|
||||
BMessage *settings;
|
||||
|
||||
BMailChainRunner *runner;
|
||||
private:
|
||||
inline void error_alert(const char *process, status_t error);
|
||||
virtual void _ReservedProtocol1();
|
||||
virtual void _ReservedProtocol2();
|
||||
virtual void _ReservedProtocol3();
|
||||
virtual void _ReservedProtocol4();
|
||||
virtual void _ReservedProtocol5();
|
||||
|
||||
friend class DeletePass;
|
||||
|
||||
BHandler *trash_monitor;
|
||||
BStringList *uids_on_disk;
|
||||
|
||||
uint32 _reserved[3];
|
||||
};
|
||||
|
||||
#endif // ZOIDBERG_MAIL_PROTOCOL_H
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef ZOIDBERG_PROTOCOL_CONFIG_VIEW_H
|
||||
#define ZOIDBERG_PROTOCOL_CONFIG_VIEW_H
|
||||
/* ProtocolConfigView - the standard config view for all protocols
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <View.h>
|
||||
|
||||
typedef enum {
|
||||
B_MAIL_PROTOCOL_HAS_AUTH_METHODS = 1,
|
||||
B_MAIL_PROTOCOL_HAS_FLAVORS = 2,
|
||||
B_MAIL_PROTOCOL_HAS_USERNAME = 4,
|
||||
B_MAIL_PROTOCOL_HAS_PASSWORD = 8,
|
||||
B_MAIL_PROTOCOL_HAS_HOSTNAME = 16,
|
||||
B_MAIL_PROTOCOL_CAN_LEAVE_MAIL_ON_SERVER = 32
|
||||
} b_mail_protocol_config_options;
|
||||
|
||||
class BMailProtocolConfigView : public BView {
|
||||
public:
|
||||
BMailProtocolConfigView(uint32 options_mask = B_MAIL_PROTOCOL_HAS_FLAVORS | B_MAIL_PROTOCOL_HAS_USERNAME | B_MAIL_PROTOCOL_HAS_PASSWORD | B_MAIL_PROTOCOL_HAS_HOSTNAME);
|
||||
virtual ~BMailProtocolConfigView();
|
||||
|
||||
void SetTo(BMessage *archive);
|
||||
|
||||
void AddFlavor(const char *label);
|
||||
void AddAuthMethod(const char *label,bool needUserPassword = true);
|
||||
|
||||
virtual status_t Archive(BMessage *into, bool deep = true) const;
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
|
||||
private:
|
||||
uint32 _reserved[5];
|
||||
};
|
||||
|
||||
#endif /* ZOIDBERG_PROTOCOL_CONFIG_VIEW_H */
|
||||
@@ -0,0 +1,41 @@
|
||||
#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 BMailRemoteStorageProtocol : public BMailProtocol {
|
||||
public:
|
||||
BMailRemoteStorageProtocol(BMessage *settings, BMailChainRunner *runner);
|
||||
virtual ~BMailRemoteStorageProtocol();
|
||||
|
||||
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
|
||||
@@ -0,0 +1,73 @@
|
||||
#ifndef ZOIDBERG_STRING_LIST_H
|
||||
#define ZOIDBERG_STRING_LIST_H
|
||||
/* StringList - a string list implementation
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Flattenable.h>
|
||||
|
||||
class BList;
|
||||
|
||||
class BStringList : public BFlattenable {
|
||||
public:
|
||||
BStringList();
|
||||
BStringList(const BStringList&);
|
||||
|
||||
~BStringList(void);
|
||||
|
||||
BStringList &operator=(const BStringList &from);
|
||||
|
||||
/* Flattenable stuff */
|
||||
virtual bool IsFixedSize() const; //--false for obvious reasons
|
||||
virtual type_code TypeCode() const;
|
||||
virtual ssize_t FlattenedSize() const;
|
||||
virtual status_t Flatten(void *buffer, ssize_t size) const;
|
||||
virtual bool AllowsTypeCode(type_code code) const;
|
||||
virtual status_t Unflatten(type_code c, const void *buf, ssize_t size);
|
||||
|
||||
/* Adding and removing items. */
|
||||
void AddItem(const char *item);
|
||||
void AddList(const BStringList *newItems);
|
||||
bool RemoveItem(const char *item);
|
||||
void MakeEmpty();
|
||||
|
||||
/* Retrieving items. */
|
||||
const char *ItemAt(int32) const;
|
||||
int32 IndexOf(const char *) const;
|
||||
|
||||
/* Querying the list. */
|
||||
bool HasItem(const char *item) const;
|
||||
int32 CountItems() const;
|
||||
bool IsEmpty() const;
|
||||
|
||||
/* Determining differences between lists */
|
||||
void NotHere(BStringList &other_list, BStringList *results);
|
||||
void NotThere(BStringList &other_list, BStringList *results);
|
||||
|
||||
/* Useful list logic operators */
|
||||
BStringList &operator += (const char *item);
|
||||
BStringList &operator += (BStringList &list);
|
||||
|
||||
BStringList &operator -= (const char *item);
|
||||
BStringList &operator -= (BStringList &list);
|
||||
|
||||
BStringList operator | (BStringList &list);
|
||||
BStringList &operator |= (BStringList &list);
|
||||
|
||||
BStringList operator ^ (BStringList &list);
|
||||
BStringList &operator ^= (BStringList &list);
|
||||
|
||||
bool operator == (BStringList &list);
|
||||
const char *operator [] (int32 index);
|
||||
|
||||
private:
|
||||
void *_buckets[256];
|
||||
int32 _items;
|
||||
BList *_indexed;
|
||||
|
||||
uint32 _reserved[5];
|
||||
};
|
||||
|
||||
#endif /* ZOIDBERG_STRING_LIST_H */
|
||||
@@ -0,0 +1,56 @@
|
||||
#ifndef FILE_CONFIG_VIEW
|
||||
#define FILE_CONFIG_VIEW
|
||||
/* FileConfigView - a file configuration view for filters
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <View.h>
|
||||
#include <FilePanel.h>
|
||||
|
||||
class BTextControl;
|
||||
class BButton;
|
||||
|
||||
class BFileControl : public BView
|
||||
{
|
||||
public:
|
||||
BFileControl(BRect rect,const char *name,const char *label,const char *pathOfFile = NULL,uint32 flavors = B_DIRECTORY_NODE);
|
||||
~BFileControl();
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
|
||||
void SetText(const char *pathOfFile);
|
||||
const char *Text() const;
|
||||
|
||||
void SetEnabled(bool enabled);
|
||||
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
|
||||
private:
|
||||
BTextControl *fText;
|
||||
BButton *fButton;
|
||||
|
||||
BFilePanel *fPanel;
|
||||
|
||||
uint32 _reserved[5];
|
||||
};
|
||||
|
||||
class BMailFileConfigView : public BFileControl
|
||||
{
|
||||
public:
|
||||
BMailFileConfigView(const char *label,const char *name,bool useMeta = false,const char *defaultPath = NULL,uint32 flavors = B_DIRECTORY_NODE);
|
||||
|
||||
void SetTo(BMessage *archive,BMessage *metadata);
|
||||
virtual status_t Archive(BMessage *into,bool deep = true) const;
|
||||
|
||||
private:
|
||||
BMessage *fMeta;
|
||||
bool fUseMeta;
|
||||
const char *fName;
|
||||
|
||||
uint32 _reserved[5];
|
||||
};
|
||||
|
||||
#endif /* FILE_CONFIG_VIEW */
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef ZOIDBERG_MDR_LANGUAGE_H
|
||||
#define ZOIDBERG_MDR_LANGUAGE_H
|
||||
/*
|
||||
** Mail Daemon Replacement interim International Language Macros.
|
||||
**
|
||||
** Copyright 2003 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
**
|
||||
** The input for the language macro system is the MDR_DIALECT define which is
|
||||
** set by the makefile (you compile a version for the desired language, it
|
||||
** can't change at run-time using this temporary internationalization system).
|
||||
** MDR_DIALECT was set to 0 for English-USA, 1 for Japanese, and other numbers
|
||||
** for other language dialects. If it's not present, we use English-USA.
|
||||
**
|
||||
** $Log: MDRLanguage.h,v $
|
||||
** Revision 1.1 2004/09/20 22:31:42 nwhitehorn
|
||||
** Imported MDR. Some code still not entirely functional -- I haven't been able to figure out how to detect SSL, so IMAP and POP have it turned off. PPP auto-detect is also not functional at the moment. Other than that, it seems to work beautifully. Packaging will come later.
|
||||
**
|
||||
** Revision 1.3 2003/02/05 22:43:17 agmsmith
|
||||
** Default language (judging by the use of "color" in the bemail
|
||||
** preferences) changed to be English-USA.
|
||||
**
|
||||
** Revision 1.2 2003/01/30 23:52:12 agmsmith
|
||||
** Initial simple language system macros done.
|
||||
**
|
||||
** Revision 1.1 2003/01/30 23:26:07 agmsmith
|
||||
** Starting to add a simplistic internationalization system for "Koki",
|
||||
** who wants to use BeMail in Japanese. It should later be replaced by
|
||||
** a more comprehensive system, but at least this one will mark out the
|
||||
** spots where translated text is needed.
|
||||
*/
|
||||
|
||||
#define MDR_DIALECT_ENGLISH_USA 0
|
||||
#define MDR_DIALECT_JAPANESE 1
|
||||
|
||||
#ifndef MDR_DIALECT
|
||||
#define MDR_DIALECT MDR_DIALECT_ENGLISH_USA
|
||||
#endif
|
||||
|
||||
#if (MDR_DIALECT == MDR_DIALECT_ENGLISH_USA)
|
||||
#define MDR_DIALECT_CHOICE(EnglishUSA,Japanese) EnglishUSA
|
||||
#define MDR_COUNTRY "United States of America"
|
||||
#define MDR_LANGUAGE "English"
|
||||
#elif (MDR_DIALECT == MDR_DIALECT_JAPANESE)
|
||||
#define MDR_DIALECT_CHOICE(EnglishUSA,Japanese) Japanese
|
||||
#define MDR_COUNTRY "Japan"
|
||||
#define MDR_LANGUAGE "Japanese"
|
||||
#else
|
||||
#error "Unrecognized value specified for MDR_DIALECT macro constant."
|
||||
#endif
|
||||
|
||||
#endif /* ZOIDBERG_MDR_LANGUAGE_H */
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef ZOIDBERG_GARGOYLE_NODE_MESSAGE_H
|
||||
#define ZOIDBERG_GARGOYLE_NODE_MESSAGE_H
|
||||
/* NodeMessage - "streaming" interface and support functions for BNodes
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
/*
|
||||
These functions gives a nice BMessage interface to node attributes,
|
||||
by letting you transfer attributes to and from BMessages. It makes
|
||||
it so you can use all the convenient Find...() and Add...() functions
|
||||
provided by BMessage for attributes too. You use it as follows:
|
||||
|
||||
BMessage m;
|
||||
BNode n(path);
|
||||
if (reading) { n>>m; printf("woohoo=%s\n",m.FindString("woohoo")) }
|
||||
else { m.AddString("woohoo","it's howdy doody time"); n<<m; }
|
||||
|
||||
If there is more than one data item with a given name, the first
|
||||
item is the one writen to the node.
|
||||
*/
|
||||
|
||||
#include <Node.h>
|
||||
#include <Message.h>
|
||||
|
||||
#ifdef B_BEOS_VERSION_DANO
|
||||
#define _IMPEXP_MAIL
|
||||
#endif
|
||||
|
||||
_IMPEXP_MAIL BNode& operator<<(BNode& n, const BMessage& m);
|
||||
_IMPEXP_MAIL BNode& operator>>(BNode& n, BMessage& m);
|
||||
inline const BMessage& operator>>(const BMessage& m, BNode& n){n<<m;return m;}
|
||||
inline BMessage& operator<<( BMessage& m, BNode& n){n>>m;return m;}
|
||||
|
||||
#endif /* ZOIDBERG_GARGOYLE_NODE_MESSAGE_H */
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef ZOIDBERG_CRYPT_H
|
||||
#define ZOIDBERG_CRYPT_H
|
||||
/* crypt - simple encryption algorithm used for passwords
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#define PASSWORD_LENGTH 32
|
||||
|
||||
|
||||
char *get_passwd(BMessage *msg,const char *name);
|
||||
bool set_passwd(BMessage *msg,const char *name,const char *password);
|
||||
|
||||
void passwd_crypt(char *in,char *out,int length);
|
||||
|
||||
#endif /* ZOIDBERG_CRYPT_H */
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef ZOIDBERG_DES_H
|
||||
#define ZOIDBERG_DES_H
|
||||
/* DES - encryption algorithm, removed double and triple DES
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
/* des.h - adapted from d3des.h:
|
||||
*
|
||||
* Headers and defines for d3des.c
|
||||
* Graven Imagery, 1992.
|
||||
*
|
||||
* Copyright (c) 1988,1989,1990,1991,1992 by Richard Outerbridge
|
||||
* (GEnie : OUTER; CIS : [71755,204])
|
||||
*/
|
||||
|
||||
#define DES_ENCRYPT 0 /* MODE == encrypt */
|
||||
#define DES_DECRYPT 1 /* MODE == decrypt */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern void des_setkey(unsigned char *, short);
|
||||
/* hexkey[8] MODE
|
||||
* Sets the internal key register according to the hexadecimal
|
||||
* key contained in the 8 bytes of hexkey, according to the DES,
|
||||
* for encryption or decryption according to MODE.
|
||||
*/
|
||||
|
||||
extern void des_usekey(unsigned long *);
|
||||
/* cookedkey[32]
|
||||
* Loads the internal key register with the data in cookedkey.
|
||||
*/
|
||||
|
||||
extern void des_cpkey(unsigned long *);
|
||||
/* cookedkey[32]
|
||||
* Copies the contents of the internal key register into the storage
|
||||
* located at &cookedkey[0].
|
||||
*/
|
||||
|
||||
extern void des_crypt(unsigned char *, unsigned char *);
|
||||
/* from[8] to[8]
|
||||
* Encrypts/Decrypts (according to the key currently loaded in the
|
||||
* internal key register) one block of eight bytes at address 'from'
|
||||
* into the block at address 'to'. They can be the same.
|
||||
*/
|
||||
|
||||
extern void des_encrypt(char *from,char *to);
|
||||
extern void des_decrypt(char *from,int fromLength,char *to);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZOIDBERG_DES_H */
|
||||
@@ -0,0 +1,85 @@
|
||||
#ifndef ZOIDBERG_GARGOYLE_MAIL_UTIL_H
|
||||
#define ZOIDBERG_GARGOYLE_MAIL_UTIL_H
|
||||
/* mail util - header parsing
|
||||
**
|
||||
** Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class BString;
|
||||
|
||||
// The next couple of functions are our wrapper around convert_to_utf8 and
|
||||
// convert_from_utf8 so that they can also convert from UTF-8 to UTF-8 by
|
||||
// specifying the MDR_UTF8_CONVERSION constant as the conversion operation.
|
||||
|
||||
status_t mail_convert_to_utf8(uint32 srcEncoding, const char *src,
|
||||
int32 *srcLen, char *dst, int32 *dstLen, int32 *state,
|
||||
char substitute = B_SUBSTITUTE);
|
||||
|
||||
status_t mail_convert_from_utf8(uint32 dstEncoding, const char *src,
|
||||
int32 *srcLen, char *dst, int32 *dstLen, int32 *state,
|
||||
char substitute = B_SUBSTITUTE);
|
||||
|
||||
|
||||
void trim_white_space(BString &string);
|
||||
// Remove leading and trailing white space from the string.
|
||||
|
||||
void SubjectToThread(BString &string);
|
||||
// Convert a subject to the core words (remove the extraneous RE: re: etc).
|
||||
|
||||
time_t ParseDateWithTimeZone(const char *DateString);
|
||||
// Converts a date to a time. Handles time zones too, unlike parsedate.
|
||||
|
||||
ssize_t rfc2047_to_utf8(char **buffer, size_t *bufLen, size_t strLen = 0);
|
||||
ssize_t utf8_to_rfc2047(char **bufp, ssize_t length,uint32 charset, char encoding);
|
||||
// convert (in place) RFC 2047-style escape sequences ("=?...?.?...?=")
|
||||
// in the first strLen characters of *buffer into UTF-8, and return the
|
||||
// length of the converted string or an error code less than 0 on error.
|
||||
//
|
||||
// This may cause the string to grow. If it grows bigger than *bufLen,
|
||||
// *buffer will be reallocated using realloc(), and its new length stored
|
||||
// in *bufLen.
|
||||
//
|
||||
// Unidentified charsets and conversion errors cause
|
||||
// the offending text to be skipped.
|
||||
|
||||
void FoldLineAtWhiteSpaceAndAddCRLF (BString &string);
|
||||
// Insert CRLF at various spots in the given string (before white space) so
|
||||
// that the line length is mostly under 78 bytes. Also makes sure there is a
|
||||
// CRLF at the very end.
|
||||
|
||||
ssize_t nextfoldedline(const char** header, char **buffer, size_t *buflen);
|
||||
ssize_t readfoldedline(FILE *file, char **buffer, size_t *buflen);
|
||||
ssize_t readfoldedline(BPositionIO &in, char **buffer, size_t *buflen);
|
||||
// Return in *buffer a \n-terminated line (even if the original is \r\n
|
||||
// terminated or not terminated at all (last line in file situation)) from a
|
||||
// memory buffer, FILE* or BPositionIO, after folding \r?\n(\s)->$1. Return
|
||||
// the length of the folded string directly, or a negative error code if there
|
||||
// was a memory allocation error or file read error. It will return zero only
|
||||
// when trying to read at end of file. *header, *file and &in are left
|
||||
// pointing to the first character after the line read.
|
||||
//
|
||||
// if buffer is not NULL return a pointer to the buffer in *buffer
|
||||
// if *buffer is not NULL, use the preallocated buffer, though it may get
|
||||
// realloc'd (so use malloc to allocate it and expect to have your *buffer
|
||||
// pointer modified to point to the new buffer if a realloc happens).
|
||||
// if buflen is not NULL, return the final size of the buffer in buflen
|
||||
// if buffer is not NULL, buflen is not NULL, and *buffer is not NULL
|
||||
// *buffer is a buffer of size *buflen
|
||||
// if buffer is NULL or *buffer is NULL, and buflen is not NULL then
|
||||
// start with a buffer of size *buflen
|
||||
|
||||
status_t parse_header(BMessage &headers, BPositionIO &input);
|
||||
|
||||
void extract_address(BString &address);
|
||||
// retrieves the mail address only from an address header formatted field
|
||||
|
||||
void extract_address_name(BString &address);
|
||||
// Given a header field (usually the From: e-mail address) with gobbledygook in
|
||||
// it, find the longest human-readable phrase (usually the person's name).
|
||||
|
||||
void get_address_list(BList &list, const char *string, void (*cleanupFunc)(BString &) = NULL);
|
||||
|
||||
#endif /* ZOIDBERG_GARGOYLE_MAIL_UTIL_H */
|
||||
@@ -0,0 +1,606 @@
|
||||
/* Definitions for data structures and routines for the regular
|
||||
expression library, version 0.12.
|
||||
Copyright (C) 1985,89,90,91,92,93,95,96,97,98 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU C Library. Its master source is NOT part of
|
||||
the C library, however. The master source lives in /gd/gnu/lib.
|
||||
|
||||
The GNU C Library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public License as
|
||||
published by the Free Software Foundation; either version 2 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
The GNU C Library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with the GNU C Library; see the file COPYING.LIB. If not,
|
||||
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
Boston, MA 02111-1307, USA. */
|
||||
|
||||
/* BeOS PPC has no regex in libroot */
|
||||
#if !__POWERPC__
|
||||
# include <posix/regex.h>
|
||||
#else
|
||||
|
||||
#ifndef _REGEX_H
|
||||
#define _REGEX_H 1
|
||||
|
||||
#ifdef __BEOS__
|
||||
# undef __STDC__
|
||||
# define __STDC__ 1
|
||||
#endif
|
||||
|
||||
/* Allow the use in C++ code. */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* POSIX says that <sys/types.h> must be included (by the caller) before
|
||||
<regex.h>. */
|
||||
|
||||
#if !defined _POSIX_C_SOURCE && !defined _POSIX_SOURCE && defined VMS
|
||||
/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
|
||||
should be there. */
|
||||
# include <stddef.h>
|
||||
#endif
|
||||
|
||||
/* The following two types have to be signed and unsigned integer type
|
||||
wide enough to hold a value of a pointer. For most ANSI compilers
|
||||
ptrdiff_t and size_t should be likely OK. Still size of these two
|
||||
types is 2 for Microsoft C. Ugh... */
|
||||
typedef long int s_reg_t;
|
||||
typedef unsigned long int active_reg_t;
|
||||
|
||||
/* The following bits are used to determine the regexp syntax we
|
||||
recognize. The set/not-set meanings are chosen so that Emacs syntax
|
||||
remains the value 0. The bits are given in alphabetical order, and
|
||||
the definitions shifted by one from the previous bit; thus, when we
|
||||
add or remove a bit, only one other definition need change. */
|
||||
typedef unsigned long int reg_syntax_t;
|
||||
|
||||
/* If this bit is not set, then \ inside a bracket expression is literal.
|
||||
If set, then such a \ quotes the following character. */
|
||||
#define RE_BACKSLASH_ESCAPE_IN_LISTS ((unsigned long int) 1)
|
||||
|
||||
/* If this bit is not set, then + and ? are operators, and \+ and \? are
|
||||
literals.
|
||||
If set, then \+ and \? are operators and + and ? are literals. */
|
||||
#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
|
||||
|
||||
/* If this bit is set, then character classes are supported. They are:
|
||||
[:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
|
||||
[:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
|
||||
If not set, then character classes are not supported. */
|
||||
#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
|
||||
|
||||
/* If this bit is set, then ^ and $ are always anchors (outside bracket
|
||||
expressions, of course).
|
||||
If this bit is not set, then it depends:
|
||||
^ is an anchor if it is at the beginning of a regular
|
||||
expression or after an open-group or an alternation operator;
|
||||
$ is an anchor if it is at the end of a regular expression, or
|
||||
before a close-group or an alternation operator.
|
||||
|
||||
This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
|
||||
POSIX draft 11.2 says that * etc. in leading positions is undefined.
|
||||
We already implemented a previous draft which made those constructs
|
||||
invalid, though, so we haven't changed the code back. */
|
||||
#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
|
||||
|
||||
/* If this bit is set, then special characters are always special
|
||||
regardless of where they are in the pattern.
|
||||
If this bit is not set, then special characters are special only in
|
||||
some contexts; otherwise they are ordinary. Specifically,
|
||||
* + ? and intervals are only special when not after the beginning,
|
||||
open-group, or alternation operator. */
|
||||
#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
|
||||
|
||||
/* If this bit is set, then *, +, ?, and { cannot be first in an re or
|
||||
immediately after an alternation or begin-group operator. */
|
||||
#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
|
||||
|
||||
/* If this bit is set, then . matches newline.
|
||||
If not set, then it doesn't. */
|
||||
#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
|
||||
|
||||
/* If this bit is set, then . doesn't match NUL.
|
||||
If not set, then it does. */
|
||||
#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
|
||||
|
||||
/* If this bit is set, nonmatching lists [^...] do not match newline.
|
||||
If not set, they do. */
|
||||
#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
|
||||
|
||||
/* If this bit is set, either \{...\} or {...} defines an
|
||||
interval, depending on RE_NO_BK_BRACES.
|
||||
If not set, \{, \}, {, and } are literals. */
|
||||
#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
|
||||
|
||||
/* If this bit is set, +, ? and | aren't recognized as operators.
|
||||
If not set, they are. */
|
||||
#define RE_LIMITED_OPS (RE_INTERVALS << 1)
|
||||
|
||||
/* If this bit is set, newline is an alternation operator.
|
||||
If not set, newline is literal. */
|
||||
#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
|
||||
|
||||
/* If this bit is set, then `{...}' defines an interval, and \{ and \}
|
||||
are literals.
|
||||
If not set, then `\{...\}' defines an interval. */
|
||||
#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
|
||||
|
||||
/* If this bit is set, (...) defines a group, and \( and \) are literals.
|
||||
If not set, \(...\) defines a group, and ( and ) are literals. */
|
||||
#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
|
||||
|
||||
/* If this bit is set, then \<digit> matches <digit>.
|
||||
If not set, then \<digit> is a back-reference. */
|
||||
#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
|
||||
|
||||
/* If this bit is set, then | is an alternation operator, and \| is literal.
|
||||
If not set, then \| is an alternation operator, and | is literal. */
|
||||
#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
|
||||
|
||||
/* If this bit is set, then an ending range point collating higher
|
||||
than the starting range point, as in [z-a], is invalid.
|
||||
If not set, then when ending range point collates higher than the
|
||||
starting range point, the range is ignored. */
|
||||
#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
|
||||
|
||||
/* If this bit is set, then an unmatched ) is ordinary.
|
||||
If not set, then an unmatched ) is invalid. */
|
||||
#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
|
||||
|
||||
/* If this bit is set, succeed as soon as we match the whole pattern,
|
||||
without further backtracking. */
|
||||
#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
|
||||
|
||||
/* If this bit is set, do not process the GNU regex operators.
|
||||
If not set, then the GNU regex operators are recognized. */
|
||||
#define RE_NO_GNU_OPS (RE_NO_POSIX_BACKTRACKING << 1)
|
||||
|
||||
/* If this bit is set, turn on internal regex debugging.
|
||||
If not set, and debugging was on, turn it off.
|
||||
This only works if regex.c is compiled -DDEBUG.
|
||||
We define this bit always, so that all that's needed to turn on
|
||||
debugging is to recompile regex.c; the calling code can always have
|
||||
this bit set, and it won't affect anything in the normal case. */
|
||||
#define RE_DEBUG (RE_NO_GNU_OPS << 1)
|
||||
|
||||
/* This global variable defines the particular regexp syntax to use (for
|
||||
some interfaces). When a regexp is compiled, the syntax used is
|
||||
stored in the pattern buffer, so changing this does not affect
|
||||
already-compiled regexps. */
|
||||
extern reg_syntax_t re_syntax_options;
|
||||
|
||||
/* Define combinations of the above bits for the standard possibilities.
|
||||
(The [[[ comments delimit what gets put into the Texinfo file, so
|
||||
don't delete them!) */
|
||||
/* [[[begin syntaxes]]] */
|
||||
#define RE_SYNTAX_EMACS 0
|
||||
|
||||
#define RE_SYNTAX_AWK \
|
||||
(RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
|
||||
| RE_NO_BK_PARENS | RE_NO_BK_REFS \
|
||||
| RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
|
||||
| RE_DOT_NEWLINE | RE_CONTEXT_INDEP_ANCHORS \
|
||||
| RE_UNMATCHED_RIGHT_PAREN_ORD | RE_NO_GNU_OPS)
|
||||
|
||||
#define RE_SYNTAX_GNU_AWK \
|
||||
((RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DEBUG) \
|
||||
& ~(RE_DOT_NOT_NULL | RE_INTERVALS | RE_CONTEXT_INDEP_OPS))
|
||||
|
||||
#define RE_SYNTAX_POSIX_AWK \
|
||||
(RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS \
|
||||
| RE_INTERVALS | RE_NO_GNU_OPS)
|
||||
|
||||
#define RE_SYNTAX_GREP \
|
||||
(RE_BK_PLUS_QM | RE_CHAR_CLASSES \
|
||||
| RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
|
||||
| RE_NEWLINE_ALT)
|
||||
|
||||
#define RE_SYNTAX_EGREP \
|
||||
(RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
|
||||
| RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
|
||||
| RE_NEWLINE_ALT | RE_NO_BK_PARENS \
|
||||
| RE_NO_BK_VBAR)
|
||||
|
||||
#define RE_SYNTAX_POSIX_EGREP \
|
||||
(RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
|
||||
|
||||
/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
|
||||
#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
|
||||
|
||||
#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
|
||||
|
||||
/* Syntax bits common to both basic and extended POSIX regex syntax. */
|
||||
#define _RE_SYNTAX_POSIX_COMMON \
|
||||
(RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
|
||||
| RE_INTERVALS | RE_NO_EMPTY_RANGES)
|
||||
|
||||
#define RE_SYNTAX_POSIX_BASIC \
|
||||
(_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
|
||||
|
||||
/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
|
||||
RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
|
||||
isn't minimal, since other operators, such as \`, aren't disabled. */
|
||||
#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
|
||||
(_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
|
||||
|
||||
#define RE_SYNTAX_POSIX_EXTENDED \
|
||||
(_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
|
||||
| RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
|
||||
| RE_NO_BK_PARENS | RE_NO_BK_VBAR \
|
||||
| RE_UNMATCHED_RIGHT_PAREN_ORD)
|
||||
|
||||
/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
|
||||
replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
|
||||
#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
|
||||
(_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
|
||||
| RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
|
||||
| RE_NO_BK_PARENS | RE_NO_BK_REFS \
|
||||
| RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
|
||||
/* [[[end syntaxes]]] */
|
||||
|
||||
/* Maximum number of duplicates an interval can allow. Some systems
|
||||
(erroneously) define this in other header files, but we want our
|
||||
value, so remove any previous define. */
|
||||
#ifdef RE_DUP_MAX
|
||||
# undef RE_DUP_MAX
|
||||
#endif
|
||||
/* If sizeof(int) == 2, then ((1 << 15) - 1) overflows. */
|
||||
#define RE_DUP_MAX (0x7fff)
|
||||
|
||||
|
||||
/* POSIX `cflags' bits (i.e., information for `regcomp'). */
|
||||
|
||||
/* If this bit is set, then use extended regular expression syntax.
|
||||
If not set, then use basic regular expression syntax. */
|
||||
#define REG_EXTENDED 1
|
||||
|
||||
/* If this bit is set, then ignore case when matching.
|
||||
If not set, then case is significant. */
|
||||
#define REG_ICASE (REG_EXTENDED << 1)
|
||||
|
||||
/* If this bit is set, then anchors do not match at newline
|
||||
characters in the string.
|
||||
If not set, then anchors do match at newlines. */
|
||||
#define REG_NEWLINE (REG_ICASE << 1)
|
||||
|
||||
/* If this bit is set, then report only success or fail in regexec.
|
||||
If not set, then returns differ between not matching and errors. */
|
||||
#define REG_NOSUB (REG_NEWLINE << 1)
|
||||
|
||||
|
||||
/* POSIX `eflags' bits (i.e., information for regexec). */
|
||||
|
||||
/* If this bit is set, then the beginning-of-line operator doesn't match
|
||||
the beginning of the string (presumably because it's not the
|
||||
beginning of a line).
|
||||
If not set, then the beginning-of-line operator does match the
|
||||
beginning of the string. */
|
||||
#define REG_NOTBOL 1
|
||||
|
||||
/* Like REG_NOTBOL, except for the end-of-line. */
|
||||
#define REG_NOTEOL (1 << 1)
|
||||
|
||||
|
||||
/* If any error codes are removed, changed, or added, update the
|
||||
`re_error_msg' table in regex.c. */
|
||||
typedef enum
|
||||
{
|
||||
#ifdef _XOPEN_SOURCE
|
||||
REG_ENOSYS = -1, /* This will never happen for this implementation. */
|
||||
#endif
|
||||
|
||||
REG_NOERROR = 0, /* Success. */
|
||||
REG_NOMATCH, /* Didn't find a match (for regexec). */
|
||||
|
||||
/* POSIX regcomp return error codes. (In the order listed in the
|
||||
standard.) */
|
||||
REG_BADPAT, /* Invalid pattern. */
|
||||
REG_ECOLLATE, /* Not implemented. */
|
||||
REG_ECTYPE, /* Invalid character class name. */
|
||||
REG_EESCAPE, /* Trailing backslash. */
|
||||
REG_ESUBREG, /* Invalid back reference. */
|
||||
REG_EBRACK, /* Unmatched left bracket. */
|
||||
REG_EPAREN, /* Parenthesis imbalance. */
|
||||
REG_EBRACE, /* Unmatched \{. */
|
||||
REG_BADBR, /* Invalid contents of \{\}. */
|
||||
REG_ERANGE, /* Invalid range end. */
|
||||
REG_ESPACE, /* Ran out of memory. */
|
||||
REG_BADRPT, /* No preceding re for repetition op. */
|
||||
|
||||
/* Error codes we've added. */
|
||||
REG_EEND, /* Premature end. */
|
||||
REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
|
||||
REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
|
||||
} reg_errcode_t;
|
||||
|
||||
/* This data structure represents a compiled pattern. Before calling
|
||||
the pattern compiler, the fields `buffer', `allocated', `fastmap',
|
||||
`translate', and `no_sub' can be set. After the pattern has been
|
||||
compiled, the `re_nsub' field is available. All other fields are
|
||||
private to the regex routines. */
|
||||
|
||||
#ifndef RE_TRANSLATE_TYPE
|
||||
# define RE_TRANSLATE_TYPE char *
|
||||
#endif
|
||||
|
||||
struct re_pattern_buffer
|
||||
{
|
||||
/* [[[begin pattern_buffer]]] */
|
||||
/* Space that holds the compiled pattern. It is declared as
|
||||
`unsigned char *' because its elements are
|
||||
sometimes used as array indexes. */
|
||||
unsigned char *buffer;
|
||||
|
||||
/* Number of bytes to which `buffer' points. */
|
||||
unsigned long int allocated;
|
||||
|
||||
/* Number of bytes actually used in `buffer'. */
|
||||
unsigned long int used;
|
||||
|
||||
/* Syntax setting with which the pattern was compiled. */
|
||||
reg_syntax_t syntax;
|
||||
|
||||
/* Pointer to a fastmap, if any, otherwise zero. re_search uses
|
||||
the fastmap, if there is one, to skip over impossible
|
||||
starting points for matches. */
|
||||
char *fastmap;
|
||||
|
||||
/* Either a translate table to apply to all characters before
|
||||
comparing them, or zero for no translation. The translation
|
||||
is applied to a pattern when it is compiled and to a string
|
||||
when it is matched. */
|
||||
RE_TRANSLATE_TYPE translate;
|
||||
|
||||
/* Number of subexpressions found by the compiler. */
|
||||
size_t re_nsub;
|
||||
|
||||
/* Zero if this pattern cannot match the empty string, one else.
|
||||
Well, in truth it's used only in `re_search_2', to see
|
||||
whether or not we should use the fastmap, so we don't set
|
||||
this absolutely perfectly; see `re_compile_fastmap' (the
|
||||
`duplicate' case). */
|
||||
#if LITTLE_ENDIAN
|
||||
unsigned can_be_null : 1;
|
||||
|
||||
/* If REGS_UNALLOCATED, allocate space in the `regs' structure
|
||||
for `max (RE_NREGS, re_nsub + 1)' groups.
|
||||
If REGS_REALLOCATE, reallocate space if necessary.
|
||||
If REGS_FIXED, use what's there. */
|
||||
#define REGS_UNALLOCATED 0
|
||||
#define REGS_REALLOCATE 1
|
||||
#define REGS_FIXED 2
|
||||
unsigned regs_allocated : 2;
|
||||
|
||||
/* Set to zero when `regex_compile' compiles a pattern; set to one
|
||||
by `re_compile_fastmap' if it updates the fastmap. */
|
||||
unsigned fastmap_accurate : 1;
|
||||
|
||||
/* If set, `re_match_2' does not return information about
|
||||
subexpressions. */
|
||||
unsigned no_sub : 1;
|
||||
|
||||
/* If set, a beginning-of-line anchor doesn't match at the
|
||||
beginning of the string. */
|
||||
unsigned not_bol : 1;
|
||||
|
||||
/* Similarly for an end-of-line anchor. */
|
||||
unsigned not_eol : 1;
|
||||
|
||||
/* If true, an anchor at a newline matches. */
|
||||
unsigned newline_anchor : 1;
|
||||
#else
|
||||
/* If true, an anchor at a newline matches. */
|
||||
unsigned newline_anchor : 1;
|
||||
|
||||
/* Similarly for an end-of-line anchor. */
|
||||
unsigned not_eol : 1;
|
||||
|
||||
/* If set, a beginning-of-line anchor doesn't match at the
|
||||
beginning of the string. */
|
||||
unsigned not_bol : 1;
|
||||
|
||||
/* If set, `re_match_2' does not return information about
|
||||
subexpressions. */
|
||||
unsigned no_sub : 1;
|
||||
|
||||
/* Set to zero when `regex_compile' compiles a pattern; set to one
|
||||
by `re_compile_fastmap' if it updates the fastmap. */
|
||||
unsigned fastmap_accurate : 1;
|
||||
|
||||
/* If REGS_UNALLOCATED, allocate space in the `regs' structure
|
||||
for `max (RE_NREGS, re_nsub + 1)' groups.
|
||||
If REGS_REALLOCATE, reallocate space if necessary.
|
||||
If REGS_FIXED, use what's there. */
|
||||
#define REGS_UNALLOCATED 0
|
||||
#define REGS_REALLOCATE 1
|
||||
#define REGS_FIXED 2
|
||||
unsigned regs_allocated : 2;
|
||||
|
||||
unsigned can_be_null : 1;
|
||||
#endif
|
||||
/* [[[end pattern_buffer]]] */
|
||||
};
|
||||
|
||||
typedef struct re_pattern_buffer regex_t;
|
||||
|
||||
/* Type for byte offsets within the string. POSIX mandates this. */
|
||||
typedef int regoff_t;
|
||||
|
||||
|
||||
/* This is the structure we store register match data in. See
|
||||
regex.texinfo for a full description of what registers match. */
|
||||
struct re_registers
|
||||
{
|
||||
unsigned num_regs;
|
||||
regoff_t *start;
|
||||
regoff_t *end;
|
||||
};
|
||||
|
||||
|
||||
/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
|
||||
`re_match_2' returns information about at least this many registers
|
||||
the first time a `regs' structure is passed. */
|
||||
#ifndef RE_NREGS
|
||||
# define RE_NREGS 30
|
||||
#endif
|
||||
|
||||
|
||||
/* POSIX specification for registers. Aside from the different names than
|
||||
`re_registers', POSIX uses an array of structures, instead of a
|
||||
structure of arrays. */
|
||||
typedef struct
|
||||
{
|
||||
regoff_t rm_so; /* Byte offset from string's start to substring's start. */
|
||||
regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
|
||||
} regmatch_t;
|
||||
|
||||
/* Declarations for routines. */
|
||||
|
||||
/* To avoid duplicating every routine declaration -- once with a
|
||||
prototype (if we are ANSI), and once without (if we aren't) -- we
|
||||
use the following macro to declare argument types. This
|
||||
unfortunately clutters up the declarations a bit, but I think it's
|
||||
worth it. */
|
||||
|
||||
#if __STDC__
|
||||
|
||||
# define _RE_ARGS(args) args
|
||||
|
||||
#else /* not __STDC__ */
|
||||
|
||||
# define _RE_ARGS(args) ()
|
||||
|
||||
#endif /* not __STDC__ */
|
||||
|
||||
/* Sets the current default syntax to SYNTAX, and return the old syntax.
|
||||
You can also simply assign to the `re_syntax_options' variable. */
|
||||
extern reg_syntax_t __re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
|
||||
extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
|
||||
|
||||
/* Compile the regular expression PATTERN, with length LENGTH
|
||||
and syntax given by the global `re_syntax_options', into the buffer
|
||||
BUFFER. Return NULL if successful, and an error string if not. */
|
||||
extern const char *__re_compile_pattern
|
||||
_RE_ARGS ((const char *pattern, size_t length,
|
||||
struct re_pattern_buffer *buffer));
|
||||
extern const char *re_compile_pattern
|
||||
_RE_ARGS ((const char *pattern, size_t length,
|
||||
struct re_pattern_buffer *buffer));
|
||||
|
||||
|
||||
/* Compile a fastmap for the compiled pattern in BUFFER; used to
|
||||
accelerate searches. Return 0 if successful and -2 if was an
|
||||
internal error. */
|
||||
extern int __re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
|
||||
extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
|
||||
|
||||
|
||||
/* Search in the string STRING (with length LENGTH) for the pattern
|
||||
compiled into BUFFER. Start searching at position START, for RANGE
|
||||
characters. Return the starting position of the match, -1 for no
|
||||
match, or -2 for an internal error. Also return register
|
||||
information in REGS (if REGS and BUFFER->no_sub are nonzero). */
|
||||
extern int __re_search
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
|
||||
int length, int start, int range, struct re_registers *regs));
|
||||
extern int re_search
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
|
||||
int length, int start, int range, struct re_registers *regs));
|
||||
|
||||
|
||||
/* Like `re_search', but search in the concatenation of STRING1 and
|
||||
STRING2. Also, stop searching at index START + STOP. */
|
||||
extern int __re_search_2
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
|
||||
int length1, const char *string2, int length2,
|
||||
int start, int range, struct re_registers *regs, int stop));
|
||||
extern int re_search_2
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
|
||||
int length1, const char *string2, int length2,
|
||||
int start, int range, struct re_registers *regs, int stop));
|
||||
|
||||
|
||||
/* Like `re_search', but return how many characters in STRING the regexp
|
||||
in BUFFER matched, starting at position START. */
|
||||
extern int __re_match
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
|
||||
int length, int start, struct re_registers *regs));
|
||||
extern int re_match
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
|
||||
int length, int start, struct re_registers *regs));
|
||||
|
||||
|
||||
/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
|
||||
extern int __re_match_2
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
|
||||
int length1, const char *string2, int length2,
|
||||
int start, struct re_registers *regs, int stop));
|
||||
extern int re_match_2
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
|
||||
int length1, const char *string2, int length2,
|
||||
int start, struct re_registers *regs, int stop));
|
||||
|
||||
|
||||
/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
|
||||
ENDS. Subsequent matches using BUFFER and REGS will use this memory
|
||||
for recording register information. STARTS and ENDS must be
|
||||
allocated with malloc, and must each be at least `NUM_REGS * sizeof
|
||||
(regoff_t)' bytes long.
|
||||
|
||||
If NUM_REGS == 0, then subsequent matches should allocate their own
|
||||
register data.
|
||||
|
||||
Unless this function is called, the first search or match using
|
||||
PATTERN_BUFFER will allocate its own register data, without
|
||||
freeing the old data. */
|
||||
extern void __re_set_registers
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
|
||||
unsigned num_regs, regoff_t *starts, regoff_t *ends));
|
||||
extern void re_set_registers
|
||||
_RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
|
||||
unsigned num_regs, regoff_t *starts, regoff_t *ends));
|
||||
|
||||
#ifdef _REGEX_RE_COMP
|
||||
# ifndef _CRAY
|
||||
/* 4.2 bsd compatibility. */
|
||||
extern char *re_comp _RE_ARGS ((const char *));
|
||||
extern int re_exec _RE_ARGS ((const char *));
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* POSIX compatibility. */
|
||||
extern int __regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern,
|
||||
int __cflags));
|
||||
extern int regcomp _RE_ARGS ((regex_t *__preg, const char *__pattern,
|
||||
int __cflags));
|
||||
|
||||
extern int __regexec _RE_ARGS ((const regex_t *__preg,
|
||||
const char *__string, size_t __nmatch,
|
||||
regmatch_t __pmatch[], int __eflags));
|
||||
extern int regexec _RE_ARGS ((const regex_t *__preg,
|
||||
const char *__string, size_t __nmatch,
|
||||
regmatch_t __pmatch[], int __eflags));
|
||||
|
||||
extern size_t __regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
|
||||
char *__errbuf, size_t __errbuf_size));
|
||||
extern size_t regerror _RE_ARGS ((int __errcode, const regex_t *__preg,
|
||||
char *__errbuf, size_t __errbuf_size));
|
||||
|
||||
extern void __regfree _RE_ARGS ((regex_t *__preg));
|
||||
extern void regfree _RE_ARGS ((regex_t *__preg));
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* C++ */
|
||||
|
||||
#endif /* regex.h */
|
||||
|
||||
#endif /* __PPC__ */
|
||||
@@ -0,0 +1,83 @@
|
||||
#ifndef ZOIDBERG_STATUS_WINDOW_H
|
||||
#define ZOIDBERG_STATUS_WINDOW_H
|
||||
/* StatusWindow - the status window while fetching/sending mails
|
||||
**
|
||||
** Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Window.h>
|
||||
#include <Box.h>
|
||||
#include <List.h>
|
||||
#include <Alert.h>
|
||||
|
||||
class BStatusBar;
|
||||
class BStringView;
|
||||
class BMailStatusView;
|
||||
|
||||
class BMailStatusWindow : public BWindow {
|
||||
public:
|
||||
BMailStatusWindow(BRect rect, const char *name, uint32 show_when);
|
||||
~BMailStatusWindow();
|
||||
|
||||
virtual void FrameMoved(BPoint origin);
|
||||
virtual void WorkspaceActivated(int32 workspace, bool active);
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
|
||||
BMailStatusView *NewStatusView(const char *description, bool upstream);
|
||||
void RemoveView(BMailStatusView *view);
|
||||
int32 CountVisibleItems();
|
||||
|
||||
bool HasItems(void);
|
||||
void SetShowCriterion(uint32);
|
||||
void SetDefaultMessage(const BString &message);
|
||||
|
||||
private:
|
||||
friend class BMailStatusView;
|
||||
|
||||
void SetBorderStyle(int32 look);
|
||||
void ActuallyAddStatusView(BMailStatusView *status);
|
||||
|
||||
BList fStatusViews;
|
||||
uint32 fShowMode;
|
||||
BView *fDefaultView;
|
||||
BStringView *fMessageView;
|
||||
float fMinWidth;
|
||||
float fMinHeight;
|
||||
int32 fWindowMoved;
|
||||
int32 fLastWorkspace;
|
||||
BRect fFrame;
|
||||
|
||||
uint32 _reserved[5];
|
||||
};
|
||||
|
||||
class BMailStatusView : public BBox {
|
||||
public:
|
||||
void AddProgress(int32 how_much);
|
||||
void SetMessage(const char *msg);
|
||||
void SetMaximum(int32 max_bytes);
|
||||
int32 CountTotalItems();
|
||||
void SetTotalItems(int32 items);
|
||||
void AddItem(void);
|
||||
void Reset(bool hide = true);
|
||||
|
||||
virtual ~BMailStatusView();
|
||||
|
||||
private:
|
||||
friend class BMailStatusWindow;
|
||||
|
||||
BMailStatusView(BRect rect,const char *description,bool upstream);
|
||||
void AddSelfToWindow();
|
||||
|
||||
BStatusBar *status;
|
||||
BMailStatusWindow *window;
|
||||
int32 items_now;
|
||||
int32 total_items;
|
||||
bool is_upstream;
|
||||
bool by_bytes;
|
||||
char pre_text[255];
|
||||
|
||||
uint32 _reserved[5];
|
||||
};
|
||||
|
||||
#endif /* ZOIDBERG_STATUS_WINDOW_H */
|
||||
@@ -81,6 +81,7 @@ KernelLd
|
||||
SubInclude OBOS_TOP src add-ons accelerants ;
|
||||
SubInclude OBOS_TOP src add-ons input_server ;
|
||||
SubInclude OBOS_TOP src add-ons kernel ;
|
||||
SubInclude OBOS_TOP src add-ons mail_daemon ;
|
||||
SubInclude OBOS_TOP src add-ons media ;
|
||||
SubInclude OBOS_TOP src add-ons print ;
|
||||
SubInclude OBOS_TOP src add-ons translators ;
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
/* RuleFilter's config view - performs action depending on matching a header value
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <MenuField.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <Message.h>
|
||||
#include <TextControl.h>
|
||||
#include <MenuItem.h>
|
||||
|
||||
#include <MailAddon.h>
|
||||
#include <FileConfigView.h>
|
||||
#include <MailSettings.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
const uint32 kMsgActionMoveTo = 'argm';
|
||||
const uint32 kMsgActionDelete = 'argd';
|
||||
const uint32 kMsgActionSetTo = 'args';
|
||||
const uint32 kMsgActionReplyWith = 'argr';
|
||||
const uint32 kMsgActionSetRead = 'arge';
|
||||
|
||||
|
||||
class RuleFilterConfig : public BView {
|
||||
public:
|
||||
RuleFilterConfig(BMessage *settings);
|
||||
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
virtual void AttachedToWindow();
|
||||
virtual status_t Archive(BMessage *into, bool deep = true) const;
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
private:
|
||||
BTextControl *attr, *regex;
|
||||
BFileControl *arg;
|
||||
BPopUpMenu *menu, *outbound;
|
||||
BMenuField *outbound_field;
|
||||
int staging;
|
||||
int32 chain;
|
||||
};
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
RuleFilterConfig::RuleFilterConfig(BMessage *settings) : BView(BRect(0,0,260,85),"rulefilter_config", B_FOLLOW_LEFT | B_FOLLOW_TOP, 0) {
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
attr = new BTextControl(BRect(5,5,100,20),"attr",MDR_DIALECT_CHOICE ("If","条件:"),MDR_DIALECT_CHOICE ("header (e.g. Subject)","ヘッダ(例えばSubject)"),NULL);
|
||||
attr->SetDivider(be_plain_font->StringWidth(MDR_DIALECT_CHOICE ("If ","条件: "))+ 4);
|
||||
if (settings->HasString("attribute"))
|
||||
attr->SetText(settings->FindString("attribute"));
|
||||
AddChild(attr);
|
||||
|
||||
regex = new BTextControl(BRect(104,5,255,20),"attr",MDR_DIALECT_CHOICE (" is "," が "),MDR_DIALECT_CHOICE ("value (can be a regular expression, like *spam*)","値(正規表現対応)"),NULL);
|
||||
regex->SetDivider(be_plain_font->StringWidth(MDR_DIALECT_CHOICE (" is "," が ")) + 4);
|
||||
if (settings->HasString("regex"))
|
||||
regex->SetText(settings->FindString("regex"));
|
||||
AddChild(regex);
|
||||
|
||||
arg = new BFileControl(BRect(5,55,255,80),"arg",NULL,MDR_DIALECT_CHOICE ("this field is based on the Action","ここは動作によって意味が変わります"));
|
||||
if (BControl *control = (BControl *)arg->FindView("select_file"))
|
||||
control->SetEnabled(false);
|
||||
if (settings->HasString("argument"))
|
||||
arg->SetText(settings->FindString("argument"));
|
||||
|
||||
outbound = new BPopUpMenu(MDR_DIALECT_CHOICE ("<Choose Account>","<アカウントを選択>"));
|
||||
BList list;
|
||||
GetOutboundMailChains(&list);
|
||||
if (settings->HasInt32("do_what"))
|
||||
staging = settings->FindInt32("do_what");
|
||||
else
|
||||
staging = -1;
|
||||
if (staging == 3)
|
||||
chain = settings->FindInt32("argument");
|
||||
else
|
||||
chain = -1;
|
||||
printf("Chain: %d\n",chain);
|
||||
for (int32 i = 0; i < list.CountItems(); i++) {
|
||||
BMenuItem *item = new BMenuItem(((BMailChain *)(list.ItemAt(i)))->Name(), new BMessage(((BMailChain *)(list.ItemAt(i)))->ID()));
|
||||
outbound->AddItem(item);
|
||||
if (((BMailChain *)(list.ItemAt(i)))->ID() == chain)
|
||||
item->SetMarked(true);
|
||||
delete (BMailChain *)(list.ItemAt(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void RuleFilterConfig::AttachedToWindow() {
|
||||
menu = new BPopUpMenu(MDR_DIALECT_CHOICE ("<Choose Action>","<動作を選択>"));
|
||||
menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE ("Move To","移動する"), new BMessage(kMsgActionMoveTo)));
|
||||
menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE ("Set Flags To","フラグを指定する"), new BMessage(kMsgActionSetTo)));
|
||||
menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE ("Delete Message","削除する"), new BMessage(kMsgActionDelete)));
|
||||
menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE ("Reply With","返事を書く"), new BMessage(kMsgActionReplyWith)));
|
||||
menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE ("Set As Read","既読にする"), new BMessage(kMsgActionSetRead)));
|
||||
menu->SetTargetForItems(this);
|
||||
|
||||
BMenuField *field = new BMenuField(BRect(5,30,210,50),"do_what",MDR_DIALECT_CHOICE ("Then","ならば"),menu);
|
||||
field->ResizeToPreferred();
|
||||
field->SetDivider(be_plain_font->StringWidth(MDR_DIALECT_CHOICE ("Then","ならば")) + 8);
|
||||
AddChild(field);
|
||||
|
||||
outbound_field = new BMenuField(BRect(5,55,255,80),"reply","Foo",outbound);
|
||||
outbound_field->ResizeToPreferred();
|
||||
outbound_field->SetDivider(0);
|
||||
if (staging >= 0) {
|
||||
menu->ItemAt(staging)->SetMarked(true);
|
||||
MessageReceived(menu->ItemAt(staging)->Message());
|
||||
} else {
|
||||
AddChild(arg);
|
||||
}
|
||||
}
|
||||
|
||||
status_t RuleFilterConfig::Archive(BMessage *into, bool deep) const {
|
||||
into->MakeEmpty();
|
||||
into->AddInt32("do_what",menu->IndexOf(menu->FindMarked()));
|
||||
into->AddString("attribute",attr->Text());
|
||||
into->AddString("regex",regex->Text());
|
||||
if (into->FindInt32("do_what") == 3) {
|
||||
printf("foo!");
|
||||
into->AddInt32("argument",outbound->FindMarked()->Message()->what);
|
||||
} else
|
||||
into->AddString("argument",arg->Text());
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void RuleFilterConfig::MessageReceived(BMessage *msg) {
|
||||
switch (msg->what)
|
||||
{
|
||||
case kMsgActionMoveTo:
|
||||
case kMsgActionSetTo:
|
||||
if (BControl *control = (BControl *)arg->FindView("file_path"))
|
||||
arg->SetEnabled(true);
|
||||
if (BControl *control = (BControl *)arg->FindView("select_file"))
|
||||
control->SetEnabled(msg->what == kMsgActionMoveTo);
|
||||
if (arg->Parent() == NULL) {
|
||||
outbound_field->RemoveSelf();
|
||||
AddChild(arg);
|
||||
}
|
||||
break;
|
||||
case kMsgActionDelete:
|
||||
arg->SetEnabled(false);
|
||||
if (arg->Parent() == NULL) {
|
||||
outbound_field->RemoveSelf();
|
||||
AddChild(arg);
|
||||
}
|
||||
break;
|
||||
case kMsgActionReplyWith:
|
||||
if (outbound->Parent() == NULL) {
|
||||
arg->RemoveSelf();
|
||||
AddChild(outbound_field);
|
||||
}
|
||||
break;
|
||||
case kMsgActionSetRead:
|
||||
arg->SetEnabled(false);
|
||||
if (arg->Parent() == NULL) {
|
||||
outbound_field->RemoveSelf();
|
||||
AddChild(arg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void RuleFilterConfig::GetPreferredSize(float *width, float *height) {
|
||||
*width = 260;
|
||||
*height = 55;
|
||||
}
|
||||
|
||||
BView* instantiate_config_panel(BMessage *settings,BMessage *metadata) {
|
||||
return new RuleFilterConfig(settings);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon inbound_filters match_header ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
Addon Match\ Header : mail_daemon inbound_filters :
|
||||
ConfigView.cpp
|
||||
RuleFilter.cpp
|
||||
StringMatcher.cpp ;
|
||||
|
||||
LinkSharedOSLibs Match\ Header :
|
||||
be mail ;
|
||||
@@ -0,0 +1,119 @@
|
||||
/* Match Header - performs action depending on matching a header value
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Node.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "RuleFilter.h"
|
||||
|
||||
//class StatusView;
|
||||
|
||||
RuleFilter::RuleFilter(BMessage *settings) : BMailFilter(settings) {
|
||||
// attribute is adapted to our "capitalize-each-word-in-the-header" policy
|
||||
BString attr;
|
||||
settings->FindString("attribute",&attr);
|
||||
attr.CapitalizeEachWord();
|
||||
attribute = strdup(attr.String());
|
||||
|
||||
const char *regex = NULL;
|
||||
settings->FindString("regex",®ex);
|
||||
matcher.SetPattern(regex,true);
|
||||
|
||||
settings->FindString("argument",&arg);
|
||||
settings->FindInt32("do_what",(long *)&do_what);
|
||||
if (do_what == Z_SET_REPLY)
|
||||
settings->FindInt32("argument",&chain_id);
|
||||
}
|
||||
|
||||
RuleFilter::~RuleFilter()
|
||||
{
|
||||
if (attribute)
|
||||
free((void *)attribute);
|
||||
}
|
||||
|
||||
status_t RuleFilter::InitCheck(BString* out_message) {
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t RuleFilter::ProcessMailMessage
|
||||
(
|
||||
BPositionIO** , BEntry* entry,
|
||||
BMessage* io_headers, BPath* io_folder, const char*
|
||||
) {
|
||||
const char *data;
|
||||
if (!attribute)
|
||||
return B_OK; //----That field doesn't exist? NO match
|
||||
|
||||
if (io_headers->FindString(attribute,&data) < B_OK) { //--Maybe the capitalization was wrong?
|
||||
BString capped(attribute);
|
||||
capped.CapitalizeEachWord(); //----Enfore capitalization
|
||||
if (io_headers->FindString(capped.String(),&data) < B_OK) //----This time it's *really* not there
|
||||
return B_OK; //---No match
|
||||
}
|
||||
|
||||
if (data == NULL) //--- How would this happen? No idea
|
||||
return B_OK;
|
||||
|
||||
if (!matcher.Match(data))
|
||||
return B_OK; //-----There wasn't an error. We're just not supposed to do anything
|
||||
|
||||
switch (do_what) {
|
||||
case Z_MOVE_TO:
|
||||
if (io_headers->ReplaceString("DESTINATION",arg) != B_OK)
|
||||
io_headers->AddString("DESTINATION",arg);
|
||||
break;
|
||||
case Z_TRASH:
|
||||
return B_MAIL_DISCARD;
|
||||
case Z_FLAG:
|
||||
{
|
||||
BString string = arg;
|
||||
BNode(entry).WriteAttrString("MAIL:filter_flags",&string);
|
||||
}
|
||||
break;
|
||||
case Z_SET_REPLY:
|
||||
BNode(entry).WriteAttr("MAIL:reply_with",B_INT32_TYPE,0,&chain_id,4);
|
||||
break;
|
||||
case Z_SET_READ:
|
||||
if (io_headers->ReplaceString("STATUS", "Read") != B_OK)
|
||||
io_headers->AddString("STATUS", "Read");
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr,"Unknown do_what: 0x%04x!\n",do_what);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t descriptive_name(BMessage *settings, char *buffer) {
|
||||
const char *attribute = NULL;
|
||||
settings->FindString("attribute",&attribute);
|
||||
const char *regex = NULL;
|
||||
settings->FindString("regex",®ex);
|
||||
|
||||
if (!attribute || strlen(attribute) > 15)
|
||||
return B_ERROR;
|
||||
sprintf(buffer, "Match \"%s\"", attribute);
|
||||
|
||||
if (!regex)
|
||||
return B_OK;
|
||||
|
||||
char reg[20];
|
||||
strncpy(reg, regex, 16);
|
||||
if (strlen(regex) > 15)
|
||||
strcpy(reg + 15, "...");
|
||||
|
||||
sprintf(buffer + strlen(buffer), " against \"%s\"", reg);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
BMailFilter* instantiate_mailfilter(BMessage* settings,BMailChainRunner *)
|
||||
{
|
||||
return new RuleFilter(settings);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef ZOIDBERG_RULE_FILTER_H
|
||||
#define ZOIDBERG_RULE_FILTER_H
|
||||
/* RuleFilter - performs action depending on matching a header value
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Message.h>
|
||||
#include <List.h>
|
||||
#include <MailAddon.h>
|
||||
|
||||
#include "StringMatcher.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
Z_MOVE_TO,
|
||||
Z_FLAG,
|
||||
Z_TRASH,
|
||||
Z_SET_REPLY,
|
||||
Z_SET_READ
|
||||
} z_mail_action_flags;
|
||||
|
||||
class RuleFilter : public BMailFilter {
|
||||
public:
|
||||
RuleFilter(BMessage *settings);
|
||||
virtual ~RuleFilter();
|
||||
|
||||
virtual status_t InitCheck(BString* out_message = NULL);
|
||||
|
||||
virtual status_t ProcessMailMessage(BPositionIO** io_message,
|
||||
BEntry* io_entry,
|
||||
BMessage* io_headers,
|
||||
BPath* io_folder,
|
||||
const char* io_uid);
|
||||
private:
|
||||
StringMatcher matcher;
|
||||
const char* attribute;
|
||||
const char* arg;
|
||||
int32 chain_id;
|
||||
z_mail_action_flags do_what;
|
||||
};
|
||||
|
||||
#endif /* ZOIDBERG_RULE_FILTER_H */
|
||||
@@ -0,0 +1,186 @@
|
||||
//--------This file shamelessly stolen from Jeremy Friesner's excellent MUSCLE---------
|
||||
/* This file is Copyright 2000 Level Control Systems. See the included LICENSE.txt file for details. */
|
||||
|
||||
#include <new.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "StringMatcher.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <String.h>
|
||||
|
||||
StringMatcher::StringMatcher() : _regExpValid(false)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
StringMatcher :: StringMatcher(const char * str) : _regExpValid(false)
|
||||
{
|
||||
SetPattern(str);
|
||||
}
|
||||
|
||||
StringMatcher::~StringMatcher()
|
||||
{
|
||||
if (_regExpValid) regfree(&_regExp);
|
||||
}
|
||||
|
||||
bool StringMatcher::SetPattern(const char * str, bool isSimple)
|
||||
{
|
||||
PortableString pattern;
|
||||
|
||||
if (isSimple)
|
||||
{
|
||||
pattern = "^\\(";
|
||||
|
||||
bool escapeMode = false;
|
||||
for (const char * ptr = str; *ptr != '\0'; ptr++)
|
||||
{
|
||||
if (escapeMode)
|
||||
{
|
||||
escapeMode = false;
|
||||
switch(*ptr)
|
||||
{
|
||||
case ',': case '|': case '(': case ')': case '?':
|
||||
pattern += *ptr;
|
||||
break;
|
||||
|
||||
default:
|
||||
pattern += '\\';
|
||||
pattern += *ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch(*ptr)
|
||||
{
|
||||
case ',': case '|':
|
||||
pattern += "\\|";
|
||||
break;
|
||||
|
||||
case '.': case '(': case ')':
|
||||
pattern += '\\';
|
||||
pattern += *ptr;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
pattern += ".*";
|
||||
break;
|
||||
|
||||
case '?':
|
||||
pattern += '.';
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
escapeMode = true;
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
pattern += *ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pattern += "\\)$";
|
||||
//printf("OUTPUT: pattern became '%s'.\n", pattern.Cstr());
|
||||
}
|
||||
|
||||
// Free the old regular expression, if any
|
||||
if (_regExpValid)
|
||||
{
|
||||
regfree(&_regExp);
|
||||
_regExpValid = false;
|
||||
}
|
||||
|
||||
// And compile the new one
|
||||
_regExpValid = (regcomp(&_regExp, (pattern.Length() > 0) ? pattern.String() : str, 0) == 0);
|
||||
return _regExpValid;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
StringMatcher::Match(const char *str) const
|
||||
{
|
||||
#ifdef __INTEL__
|
||||
char buffer[1024];
|
||||
if (strlen(str) > 1024) {
|
||||
// internal Be regex seems to be broken with strings larger than a certain size :-/
|
||||
memcpy(buffer, str, 1023);
|
||||
buffer[1023] = '\0';
|
||||
str = buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (_regExpValid == false)
|
||||
return false;
|
||||
|
||||
int regExpStat = regexec(&_regExp, str, 0, NULL, 0);
|
||||
|
||||
return (regExpStat != REG_NOMATCH);
|
||||
}
|
||||
|
||||
|
||||
bool IsRegexToken(char c)
|
||||
{
|
||||
switch(c)
|
||||
{
|
||||
case '[': case ']': case '*': case '?': case '\\': case ',': case '|': case '(': case ')':
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void EscapeRegexTokens(PortableString & s)
|
||||
{
|
||||
const char * str = s.String();
|
||||
|
||||
PortableString ret;
|
||||
while(*str)
|
||||
{
|
||||
if (IsRegexToken(*str)) ret += '\\';
|
||||
ret += *str;
|
||||
str++;
|
||||
}
|
||||
s = ret;
|
||||
}
|
||||
|
||||
bool HasRegexTokens(const char * str)
|
||||
{
|
||||
while(*str)
|
||||
{
|
||||
if (IsRegexToken(*str)) return true;
|
||||
else str++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MakeRegexCaseInsensitive(PortableString & str)
|
||||
{
|
||||
bool changed = false;
|
||||
PortableString ret;
|
||||
for (uint32 i=0; i<str.Length(); i++)
|
||||
{
|
||||
char next = str[i];
|
||||
if ((next >= 'A')&&(next <= 'Z'))
|
||||
{
|
||||
char buf[5];
|
||||
sprintf(buf, "[%c%c]", next, next+('a'-'A'));
|
||||
ret += buf;
|
||||
changed = true;
|
||||
}
|
||||
else if ((next >= 'a')&&(next <= 'z'))
|
||||
{
|
||||
char buf[5];
|
||||
sprintf(buf, "[%c%c]", next, next+('A'-'a'));
|
||||
ret += buf;
|
||||
changed = true;
|
||||
}
|
||||
else ret += next;
|
||||
}
|
||||
if (changed) str = ret;
|
||||
return changed;
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
//--------This file shamelessly stolen from Jeremy Friesner's excellent MUSCLE---------
|
||||
/* This file is Copyright 2001 Level Control Systems. See the included LICENSE.txt file for details. */
|
||||
|
||||
#ifndef STRINGMATCHER_H
|
||||
#define STRINGMATCHER_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __BEOS__
|
||||
# if __POWERPC__
|
||||
# include "regex.h" // use included regex if system doesn't provide one
|
||||
# else
|
||||
# include <regex.h>
|
||||
# endif
|
||||
#else
|
||||
# include <regex.h>
|
||||
#endif
|
||||
|
||||
class BString;
|
||||
#define PortableString BString
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// NOTE: This class is based on the psStringMatcher v1.3 class
|
||||
// developed by Lars Jørgen Aas <[email protected]> for the
|
||||
// Prodigal Software File Requester. Used by permission.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/** A utility class for doing globbing or regular expression matching. (A thin wrapper around the C regex calls) */
|
||||
class StringMatcher
|
||||
{
|
||||
public:
|
||||
/** Default Constructor. */
|
||||
StringMatcher();
|
||||
|
||||
/** A constructor that sets the simple expression.
|
||||
* @param matchString the wildcard pattern or regular expression to match with
|
||||
*/
|
||||
StringMatcher(const char * matchString);
|
||||
|
||||
/** Destructor */
|
||||
~StringMatcher();
|
||||
|
||||
/**
|
||||
* Set a new wildcard pattern or regular expression for this StringMatcher to use in future Match() calls.
|
||||
* @param expression The new globbing pattern or regular expression to match with.
|
||||
* @param isSimpleFormat If you wish to use the formal regex syntax,
|
||||
* instead of the simple syntax, set isSimpleFormat to false.
|
||||
* @return True on success, false on error (e.g. expression wasn't parsable, or out of memory)
|
||||
*/
|
||||
bool SetPattern(const char * const expression, bool isSimpleFormat=true);
|
||||
|
||||
/** Returns true iff (string) is matched by the current expression.
|
||||
* @param string a string to match against using our current expression.
|
||||
* @return true iff (string) matches, false otherwise.
|
||||
*/
|
||||
bool Match(const char *string) const;
|
||||
|
||||
private:
|
||||
bool _regExpValid;
|
||||
regex_t _regExp;
|
||||
};
|
||||
|
||||
// Some regular expression utility functions
|
||||
|
||||
/** Puts a backslash in front of any char in (str) that is "special" to the regex pattern matching.
|
||||
* @param str The string to check for special regex chars and possibly modify to escape them.
|
||||
*/
|
||||
void EscapeRegexTokens(PortableString & str);
|
||||
|
||||
/** Returns true iff any "special" chars are found in (str).
|
||||
* @param str The string to check for special regex chars.
|
||||
* @return True iff any special regex chars were found in (str).
|
||||
*/
|
||||
bool HasRegexTokens(const char * str);
|
||||
|
||||
/** Returns true iff (c) is a regular expression "special" char.
|
||||
* @param c an ASCII char
|
||||
* @return true iff (c) is a special regex char.
|
||||
*/
|
||||
bool IsRegexToken(char c);
|
||||
|
||||
/** Given a regular expression, makes it case insensitive by
|
||||
* replacing every occurance of a letter with a upper-lower combo,
|
||||
* e.g. Hello -> [Hh][Ee][Ll][Ll][Oo]
|
||||
* @param str a string to check for letters, and possibly modify to make case-insensitive
|
||||
* @return true iff anything was changed, false if no changes were necessary.
|
||||
*/
|
||||
bool MakeRegexCaseInsensitive(PortableString & str);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon inbound_filters r5_filter ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
Addon R5\ Daemon\ Filter : mail_daemon inbound_filters :
|
||||
filter.cpp ;
|
||||
|
||||
LinkSharedOSLibs R5\ Daemon\ Filter :
|
||||
be mail ;
|
||||
@@ -0,0 +1,87 @@
|
||||
/* R5 Daemon Filter - a filter comparable with the one from the original mail_daemon
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Message.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Entry.h>
|
||||
#include <Roster.h>
|
||||
#include <File.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
#include <stdio.h>
|
||||
#include <image.h>
|
||||
#include <stdlib.h>
|
||||
#include <MailAddon.h>
|
||||
|
||||
#include "NodeMessage.h"
|
||||
|
||||
class CompatibilityFilter : public BMailFilter
|
||||
{
|
||||
bool enabled;
|
||||
BPath path;
|
||||
BEntry filter;
|
||||
status_t status;
|
||||
|
||||
public:
|
||||
CompatibilityFilter(BMessage*);
|
||||
virtual status_t InitCheck(BString *err);
|
||||
virtual status_t ProcessMailMessage
|
||||
(
|
||||
BPositionIO** io_message, BEntry* io_entry,
|
||||
BMessage* io_headers, BPath* io_folder, const char* io_uid
|
||||
);
|
||||
};
|
||||
|
||||
CompatibilityFilter::CompatibilityFilter(BMessage* msg)
|
||||
: BMailFilter(msg), enabled(msg->FindBool("enabled")), status(B_OK)
|
||||
{
|
||||
if (find_directory(B_USER_ADDONS_DIRECTORY, &path) != B_OK) {
|
||||
status = B_NAME_NOT_FOUND;
|
||||
return;
|
||||
}
|
||||
path.Append("MailDaemon/Filter");
|
||||
BEntry filter(path.Path());
|
||||
}
|
||||
|
||||
status_t CompatibilityFilter::InitCheck(BString* err)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t CompatibilityFilter::ProcessMailMessage
|
||||
(BPositionIO** , BEntry* io_entry, BMessage* headers, BPath* , const char*)
|
||||
{
|
||||
int32 ret;
|
||||
|
||||
if (enabled && filter.InitCheck() == B_OK && filter.Exists())
|
||||
{
|
||||
const char *refs[2];
|
||||
refs[0] = path.Path();
|
||||
|
||||
BPath epath;
|
||||
io_entry->GetPath(&epath);
|
||||
refs[1] = epath.Path();
|
||||
|
||||
thread_id fil = load_image(2, refs, (const char**)environ);
|
||||
if (fil >= B_OK)
|
||||
{
|
||||
/*BNode node(io_entry); //---ATT-Someone explain this, please.
|
||||
node << *message;*/
|
||||
|
||||
wait_for_thread(fil,&ret);
|
||||
|
||||
/*message->MakeEmpty();
|
||||
node >> *message;*/
|
||||
}
|
||||
else fprintf(stderr,"%s\n", strerror(fil));
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
BMailFilter* instantiate_mailfilter(BMessage* settings, BMailChainRunner*)
|
||||
{
|
||||
return new CompatibilityFilter(settings);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon inbound_protocols imap ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
SubDirC++Flags -DBONE ;
|
||||
|
||||
Addon IMAP : mail_daemon inbound_protocols :
|
||||
imap_client.cpp
|
||||
imap_config.cpp
|
||||
NestedString.cpp ;
|
||||
|
||||
LinkSharedOSLibs IMAP :
|
||||
be mail socket bind ;
|
||||
@@ -0,0 +1,111 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include "NestedString.h"
|
||||
|
||||
NestedString::NestedString() : string(NULL), we_own(false) {}
|
||||
|
||||
NestedString::~NestedString() {
|
||||
for (int32 i = 0; i < children.CountItems(); i++)
|
||||
delete (NestedString *)(children.ItemAt(i));
|
||||
|
||||
if (we_own && string)
|
||||
delete [] string;
|
||||
}
|
||||
|
||||
NestedString &NestedString::operator [] (int i) const {
|
||||
return *((NestedString *)(children.ItemAt(i)));
|
||||
}
|
||||
|
||||
const char *NestedString::operator ()() const {
|
||||
if (string == NULL) {
|
||||
static BString result; //---This isn't at all thread-safe, but it doesn't matter, since it's single-threaded
|
||||
result = "(";
|
||||
for (int32 i = 0; i < CountItems(); i++)
|
||||
result << (*this)[i]() << ' ';
|
||||
result << ')';
|
||||
return result.String();
|
||||
}
|
||||
return string;
|
||||
}
|
||||
|
||||
NestedString &NestedString::AdoptAndAdd(const char *add) {
|
||||
|
||||
if (string != NULL) {
|
||||
NestedString *to_add = new NestedString;
|
||||
to_add->string = string;
|
||||
to_add->we_own = we_own;
|
||||
children.AddItem(to_add);
|
||||
string = NULL;
|
||||
}
|
||||
|
||||
NestedString *to_add = new NestedString;
|
||||
to_add->string = add;
|
||||
to_add->we_own = true;
|
||||
children.AddItem(to_add);
|
||||
return *to_add;
|
||||
}
|
||||
|
||||
NestedString &NestedString::operator += (const char *add) {
|
||||
//printf("Adding string: \"%s\"\n",add);
|
||||
|
||||
if (string != NULL) {
|
||||
NestedString *to_add = new NestedString;
|
||||
to_add->string = string;
|
||||
to_add->we_own = we_own;
|
||||
children.AddItem(to_add);
|
||||
string = NULL;
|
||||
}
|
||||
|
||||
NestedString *to_add = new NestedString;
|
||||
to_add->string = add;
|
||||
to_add->we_own = false;
|
||||
children.AddItem(to_add);
|
||||
return *to_add;
|
||||
}
|
||||
|
||||
NestedString &NestedString::operator += (BString &add) {
|
||||
//printf("Adding string: \"%s\"\n",add.String());
|
||||
|
||||
if (string != NULL) {
|
||||
NestedString *to_add = new NestedString;
|
||||
to_add->string = string;
|
||||
to_add->we_own = we_own;
|
||||
children.AddItem(to_add);
|
||||
string = NULL;
|
||||
}
|
||||
|
||||
NestedString *to_add = new NestedString;
|
||||
to_add->string = new char[add.Length()+1];
|
||||
strcpy((char *)(to_add->string),add.String());
|
||||
to_add->we_own = false;
|
||||
children.AddItem(to_add);
|
||||
return *to_add;
|
||||
}
|
||||
|
||||
int32 NestedString::CountItems() const {
|
||||
return children.CountItems();
|
||||
}
|
||||
|
||||
bool NestedString::HasChildren() const {
|
||||
return (children.CountItems() != 0);
|
||||
}
|
||||
|
||||
void NestedString::PrintToStream(int indentation) {
|
||||
for (int j = 0; j < indentation; j++)
|
||||
printf("\t");
|
||||
printf("%d items:\n",CountItems());
|
||||
/*if (CountItems() == 1) {
|
||||
for (int j = 0; j < indentation; j++)
|
||||
printf("\t");
|
||||
printf("0: %s",(*this)());
|
||||
}*/
|
||||
for (int32 i = 0; i < CountItems(); i++) {
|
||||
for (int j = 0; j < indentation; j++)
|
||||
printf("\t");
|
||||
if ((*this)[i].HasChildren())
|
||||
(*this)[i].PrintToStream(indentation+1);
|
||||
else
|
||||
printf("%d: %s\n",i,(*this)[i]());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <List.h>
|
||||
#include <String.h>
|
||||
|
||||
class NestedString {
|
||||
public:
|
||||
NestedString();
|
||||
~NestedString();
|
||||
|
||||
NestedString &operator [] (int) const;
|
||||
const char *operator ()() const;
|
||||
|
||||
NestedString &AdoptAndAdd(const char *);
|
||||
NestedString &operator += (const char *);
|
||||
NestedString &operator += (BString &);
|
||||
|
||||
int32 CountItems() const;
|
||||
bool HasChildren() const;
|
||||
|
||||
void PrintToStream(int indent = 0);
|
||||
private:
|
||||
BList children;
|
||||
const char *string;
|
||||
bool we_own;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,79 @@
|
||||
/* IMAPConfig - config view for the IMAP protocol add-on
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <TextControl.h>
|
||||
|
||||
#include <ProtocolConfigView.h>
|
||||
#include <MailAddon.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
class IMAPConfig : public BMailProtocolConfigView {
|
||||
public:
|
||||
IMAPConfig(BMessage *archive);
|
||||
virtual ~IMAPConfig();
|
||||
virtual status_t Archive(BMessage *into, bool deep = true) const;
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
};
|
||||
|
||||
IMAPConfig::IMAPConfig(BMessage *archive)
|
||||
: BMailProtocolConfigView(B_MAIL_PROTOCOL_HAS_USERNAME | B_MAIL_PROTOCOL_HAS_PASSWORD | B_MAIL_PROTOCOL_HAS_HOSTNAME | B_MAIL_PROTOCOL_CAN_LEAVE_MAIL_ON_SERVER
|
||||
#ifdef IMAPSSL
|
||||
| B_MAIL_PROTOCOL_HAS_FLAVORS)
|
||||
{
|
||||
AddFlavor("Unencrypted");
|
||||
AddFlavor("IMAP-SSL");
|
||||
#else
|
||||
) {
|
||||
#endif
|
||||
|
||||
SetTo(archive);
|
||||
|
||||
((BControl *)(FindView("leave_mail_remote")))->SetValue(B_CONTROL_ON);
|
||||
((BControl *)(FindView("leave_mail_remote")))->Hide();
|
||||
|
||||
BRect frame = FindView("delete_remote_when_local")->Frame();
|
||||
|
||||
((BControl *)(FindView("delete_remote_when_local")))->SetEnabled(true);
|
||||
((BControl *)(FindView("delete_remote_when_local")))->MoveBy(0,-25);
|
||||
|
||||
|
||||
frame.right -= 10;// FindView("pass")->Frame().right;
|
||||
/*frame.top += 10;
|
||||
frame.bottom += 10;*/
|
||||
|
||||
BTextControl *folder = new BTextControl(frame,"root","Mailbox Root: ","",NULL);
|
||||
folder->SetDivider(be_plain_font->StringWidth("Mailbox Root: "));
|
||||
|
||||
if (archive->HasString("root"))
|
||||
folder->SetText(archive->FindString("root"));
|
||||
|
||||
AddChild(folder);
|
||||
|
||||
ResizeToPreferred();
|
||||
}
|
||||
|
||||
IMAPConfig::~IMAPConfig() {}
|
||||
|
||||
status_t IMAPConfig::Archive(BMessage *into, bool deep) const {
|
||||
BMailProtocolConfigView::Archive(into,deep);
|
||||
|
||||
if (into->ReplaceString("root",((BTextControl *)(FindView("root")))->Text()) != B_OK)
|
||||
into->AddString("root",((BTextControl *)(FindView("root")))->Text());
|
||||
|
||||
into->PrintToStream();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void IMAPConfig::GetPreferredSize(float *width, float *height) {
|
||||
BMailProtocolConfigView::GetPreferredSize(width,height);
|
||||
*height -= 20;
|
||||
}
|
||||
|
||||
BView* instantiate_config_panel(BMessage *settings,BMessage *) {
|
||||
return new IMAPConfig(settings);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon inbound_protocols pop3 ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
SubDirC++Flags -DBONE ;
|
||||
|
||||
Addon POP3 : mail_daemon inbound_protocols :
|
||||
MessageIO.cpp
|
||||
pop3.cpp
|
||||
SimpleMailProtocol.cpp
|
||||
md5c.c ;
|
||||
|
||||
LinkSharedOSLibs POP3 :
|
||||
be mail socket bind ;
|
||||
@@ -0,0 +1,138 @@
|
||||
/* BMailMessageIO - Glue code for reading/writing messages directly from the
|
||||
** protocols but present a BPositionIO interface to the caller, while caching
|
||||
** the data read/written in a slave file.
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <BeBuild.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MessageIO.h"
|
||||
#include "SimpleMailProtocol.h"
|
||||
|
||||
BMailMessageIO::BMailMessageIO(SimpleMailProtocol *protocol, BPositionIO *dump_to, int32 seq_id) :
|
||||
slave(dump_to),
|
||||
message_id(seq_id),
|
||||
network(protocol),
|
||||
size(0),
|
||||
state(READ_HEADER_NEXT) {
|
||||
//-----do nothing, and do it well-----
|
||||
}
|
||||
|
||||
|
||||
ssize_t BMailMessageIO::ReadAt(off_t pos, void *buffer, size_t amountToRead) {
|
||||
status_t errorCode;
|
||||
char lastBytes [5];
|
||||
off_t old_pos = slave->Position();
|
||||
|
||||
while ((pos + amountToRead) > size) {
|
||||
if (state >= ALL_READING_DONE)
|
||||
break;
|
||||
switch (state) {
|
||||
// Read (download from the mail server) just the message headers,
|
||||
// and append a blank line if needed (so the header processing code
|
||||
// can tell where the end of the headers is). Don't append too
|
||||
// much otherwise the part after the header will appear mangled
|
||||
// when it is overwritten in a full read. This can be useful for
|
||||
// filters which discard the message after only reading the header,
|
||||
// thus avoiding the time it takes to download the whole message.
|
||||
case READ_HEADER_NEXT:
|
||||
slave->SetSize(0); // Truncate the file.
|
||||
slave->Seek(0,SEEK_SET);
|
||||
errorCode = network->GetHeader(message_id,slave);
|
||||
if (errorCode < 0)
|
||||
return errorCode;
|
||||
// See if it already ends in a blank line, if not, add enough
|
||||
// end-of-lines to give a blank line.
|
||||
slave->Seek (-4, SEEK_END);
|
||||
strcpy (lastBytes, "xxxx");
|
||||
slave->Read (lastBytes, 4);
|
||||
if (strcmp (lastBytes, "\r\n\r\n") != 0) {
|
||||
if (strcmp (lastBytes + 2, "\r\n") == 0)
|
||||
slave->Write("\r\n", 2);
|
||||
else
|
||||
slave->Write("\r\n\r\n", 4);
|
||||
}
|
||||
state = READ_BODY_NEXT;
|
||||
break;
|
||||
|
||||
// OK, they want more than the headers. Read the whole message,
|
||||
// starting from the beginning (network->Retrieve does a seek to
|
||||
// the start of the file for POP3 so we have to read the whole
|
||||
// thing). This wastes a slight amount of time on high speed
|
||||
// connections, and on dial-up modem connections, hopefully the
|
||||
// modem's V.90 data compression will make it very quick to
|
||||
// retransmit the header portion.
|
||||
case READ_BODY_NEXT:
|
||||
slave->SetSize(0); // Truncate the file.
|
||||
slave->Seek(0,SEEK_SET);
|
||||
errorCode = network->Retrieve(message_id,slave);
|
||||
if (errorCode < 0)
|
||||
return errorCode;
|
||||
state = ALL_READING_DONE;
|
||||
break;
|
||||
|
||||
default: // Shouldn't happen.
|
||||
return -1;
|
||||
}
|
||||
ResetSize();
|
||||
}
|
||||
|
||||
// Put the file position back at where it was, if possible. That's because
|
||||
// ReadAt isn't supposed to affect the file position.
|
||||
if (old_pos < size)
|
||||
slave->Seek (old_pos, SEEK_SET);
|
||||
else
|
||||
slave->Seek (0, SEEK_END);
|
||||
|
||||
return slave->ReadAt(pos,buffer,amountToRead);
|
||||
}
|
||||
|
||||
|
||||
ssize_t BMailMessageIO::WriteAt(off_t pos, const void *buffer, size_t amountToWrite) {
|
||||
ssize_t return_val;
|
||||
|
||||
return_val = slave->WriteAt(pos,buffer,amountToWrite);
|
||||
ResetSize();
|
||||
|
||||
return return_val;
|
||||
}
|
||||
|
||||
off_t BMailMessageIO::Seek(off_t position, uint32 seek_mode) {
|
||||
ssize_t errorCode;
|
||||
char tempBuffer [1];
|
||||
|
||||
if (seek_mode == SEEK_END) {
|
||||
if (state != ALL_READING_DONE) {
|
||||
// Force it to read the whole message to find the size of it.
|
||||
state = READ_BODY_NEXT; // Skip the header reading step.
|
||||
errorCode = ReadAt (size + 1, tempBuffer, sizeof (tempBuffer));
|
||||
if (errorCode < 0)
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
return slave->Seek(position,seek_mode);
|
||||
}
|
||||
|
||||
off_t BMailMessageIO::Position() const {
|
||||
return slave->Position();
|
||||
}
|
||||
|
||||
void BMailMessageIO::ResetSize(void) {
|
||||
off_t old = slave->Position();
|
||||
|
||||
slave->Seek(0,SEEK_END);
|
||||
size = slave->Position();
|
||||
|
||||
slave->Seek(old,SEEK_SET);
|
||||
}
|
||||
|
||||
BMailMessageIO::~BMailMessageIO() {
|
||||
delete slave;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef ZOIDBERG_MAIL_MESSAGE_IO_H
|
||||
#define ZOIDBERG_MAIL_MESSAGE_IO_H
|
||||
/* MessageIO - Glue code for reading/writing messages directly from the
|
||||
** protocols but present a BPositionIO interface to the caller, while caching
|
||||
** the data read/written in a slave file.
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <Path.h>
|
||||
#include <Message.h>
|
||||
|
||||
class SimpleMailProtocol;
|
||||
|
||||
class BMailMessageIO : public BPositionIO {
|
||||
public:
|
||||
BMailMessageIO(SimpleMailProtocol *protocol, BPositionIO *dump_to, int32 seq_id);
|
||||
~BMailMessageIO();
|
||||
|
||||
//----BPositionIO
|
||||
virtual ssize_t ReadAt(off_t pos, void *buffer, size_t amountToRead);
|
||||
virtual ssize_t WriteAt(off_t pos, const void *buffer, size_t amountToWrite);
|
||||
|
||||
virtual off_t Seek(off_t position, uint32 seek_mode);
|
||||
virtual off_t Position() const;
|
||||
|
||||
private:
|
||||
void ResetSize(void);
|
||||
|
||||
BPositionIO *slave;
|
||||
int32 message_id;
|
||||
SimpleMailProtocol *network;
|
||||
|
||||
size_t size;
|
||||
enum MessageIOStateEnum {
|
||||
READ_HEADER_NEXT,
|
||||
READ_BODY_NEXT,
|
||||
ALL_READING_DONE
|
||||
} state;
|
||||
};
|
||||
|
||||
#endif /* ZOIDBERG_MAIL_MESSAGE_IO_H */
|
||||
@@ -0,0 +1,125 @@
|
||||
/* SimpleMailProtocol - the base protocol implementation
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Message.h>
|
||||
#include <Path.h>
|
||||
#include <String.h>
|
||||
#include <Alert.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <crypt.h>
|
||||
|
||||
#include <StringList.h>
|
||||
#include <ChainRunner.h>
|
||||
#include <status.h>
|
||||
|
||||
#include "SimpleMailProtocol.h"
|
||||
#include "MessageIO.h"
|
||||
|
||||
SimpleMailProtocol::SimpleMailProtocol(BMessage *settings, BMailChainRunner *run) :
|
||||
BMailProtocol(settings,run),
|
||||
error(B_OK),
|
||||
last_message(-1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SimpleMailProtocol::Init()
|
||||
{
|
||||
error = Open(settings->FindString("server"), settings->FindInt32("port"),
|
||||
settings->FindInt32("flavor"));
|
||||
if (error < B_OK) {
|
||||
runner->Stop();
|
||||
return error;
|
||||
}
|
||||
|
||||
const char *password = settings->FindString("password");
|
||||
char *passwd = get_passwd(settings, "cpasswd");
|
||||
if (passwd)
|
||||
password = passwd;
|
||||
|
||||
error = Login(settings->FindString("username"), password, settings->FindInt32("auth_method"));
|
||||
delete passwd;
|
||||
|
||||
if (error < B_OK) {
|
||||
runner->Stop();
|
||||
return error;
|
||||
}
|
||||
|
||||
if (settings->FindBool("login_and_do_nothing_else_of_any_importance"))
|
||||
return error;
|
||||
|
||||
error = UniqueIDs();
|
||||
if (error < B_OK) {
|
||||
runner->Stop();
|
||||
return error;
|
||||
}
|
||||
|
||||
size_t maildrop_size = 0;
|
||||
int32 num_messages;
|
||||
|
||||
BStringList to_dl;
|
||||
manifest->NotHere(*unique_ids, &to_dl);
|
||||
|
||||
num_messages = to_dl.CountItems();
|
||||
if (num_messages == 0) {
|
||||
runner->Stop();
|
||||
return error;
|
||||
}
|
||||
|
||||
for (int32 i = 0; i < to_dl.CountItems(); i++)
|
||||
maildrop_size += MessageSize(unique_ids->IndexOf(to_dl[i]));
|
||||
|
||||
runner->GetMessages(&to_dl, maildrop_size);
|
||||
runner->Stop(); //---This gets queued
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
SimpleMailProtocol::~SimpleMailProtocol()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SimpleMailProtocol::GetMessage(const char *uid, BPositionIO **out_file, BMessage *out_headers,
|
||||
BPath *out_folder_location)
|
||||
{
|
||||
int32 to_retrieve = unique_ids->IndexOf(uid);
|
||||
if (to_retrieve < 0)
|
||||
return B_NAME_NOT_FOUND;
|
||||
|
||||
out_headers->AddInt32("SIZE",MessageSize(to_retrieve));
|
||||
*out_file = new BMailMessageIO(this,*out_file,to_retrieve);
|
||||
|
||||
if (out_folder_location != NULL)
|
||||
out_folder_location->SetTo("");
|
||||
|
||||
if((*out_file)->ReadAt(0,&to_retrieve,1) < B_OK)
|
||||
return B_MAIL_END_CHAIN;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SimpleMailProtocol::DeleteMessage(const char *uid)
|
||||
{
|
||||
#if DEBUG
|
||||
printf("ID is %d\n", (int)unique_ids->IndexOf(uid)); // What should we use for int32 instead of %d?
|
||||
#endif
|
||||
Delete(unique_ids->IndexOf(uid));
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SimpleMailProtocol::InitCheck(BString* /*out_message*/)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef ZOIDBERG_MAIL_SIMPLEPROTOCOL_H
|
||||
#define ZOIDBERG_MAIL_SIMPLEPROTOCOL_H
|
||||
|
||||
#include <MailProtocol.h>
|
||||
|
||||
class SimpleMailProtocol : public BMailProtocol {
|
||||
public:
|
||||
SimpleMailProtocol(BMessage *settings, BMailChainRunner *runner);
|
||||
//---Constructor. Simply call this in yours, and most everything will be handled for you.
|
||||
|
||||
virtual status_t Open(const char *server, int port, int protocol) = 0;
|
||||
//---server is an ASCII representation of the server that you are logging in to
|
||||
//---port is the remote port, -1 if you are to use default
|
||||
//---protocol is the protocol to use (defined by your add-on and useful for using, say, SSL) -1 is default
|
||||
|
||||
virtual status_t Login(const char *uid, const char *password, int method) = 0;
|
||||
//---uid is the username provided
|
||||
//---likewise password
|
||||
//---method is the auth method to use, this works like protocol in Open
|
||||
|
||||
virtual int32 Messages(void) = 0;
|
||||
//---return the number of messages waiting
|
||||
|
||||
virtual status_t GetHeader(int32 message, BPositionIO *write_to) = 0;
|
||||
//---Retrieve the header of message <message> into <write_to>
|
||||
|
||||
virtual status_t Retrieve(int32 message, BPositionIO *write_to) = 0;
|
||||
//---get message number <message>
|
||||
//---write your message to <write_to>
|
||||
|
||||
virtual void Delete(int32 num) = 0;
|
||||
//---delete message number num
|
||||
|
||||
virtual size_t MessageSize(int32 index) = 0;
|
||||
//---return the size in bytes of message number <index>
|
||||
|
||||
virtual size_t MailDropSize(void) = 0;
|
||||
//---return the size of the entire maildrop in bytes
|
||||
|
||||
virtual status_t UniqueIDs() = 0;
|
||||
// Fill the protected member unique_ids with strings containing
|
||||
// unique ids for all messages present on the server. This al-
|
||||
// lows comparison of remote and local message manifests, so
|
||||
// the local and remote contents can be kept in sync.
|
||||
//
|
||||
// The ID should be unique to this Chain; if that means
|
||||
// this Protocol must add account/server info to differ-
|
||||
// entiate it from other messages, then that info should
|
||||
// be added before returning the IDs and stripped from the
|
||||
// ID for use in GetMessage() et al, below.
|
||||
//
|
||||
// Returns B_OK if this was performed successfully, or another
|
||||
// error if the connection has failed.
|
||||
|
||||
//---------These implement hooks from up above---------
|
||||
//---------not user-servicable-------------------------
|
||||
virtual status_t GetMessage(
|
||||
const char* uid,
|
||||
BPositionIO** out_file, BMessage* out_headers,
|
||||
BPath* out_folder_location
|
||||
);
|
||||
virtual status_t DeleteMessage(const char* uid);
|
||||
virtual status_t InitCheck(BString* out_message = NULL);
|
||||
virtual ~SimpleMailProtocol();
|
||||
|
||||
protected:
|
||||
status_t Init();
|
||||
|
||||
private:
|
||||
status_t error;
|
||||
int32 last_message;
|
||||
|
||||
uint32 _reserved[5];
|
||||
};
|
||||
|
||||
#endif // ZOIDBERG_MAIL_SIMPLEPROTOCOL_H
|
||||
@@ -0,0 +1,56 @@
|
||||
/* MD5.H - header file for MD5C.C
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
#ifndef MD5_H__
|
||||
#define MD5_H__
|
||||
|
||||
#include "md5global.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* MD5 context. */
|
||||
typedef struct {
|
||||
UINT4 state[4]; /* state (ABCD) */
|
||||
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
} MD5_CTX;
|
||||
|
||||
void MD5Init PROTO_LIST ((MD5_CTX *));
|
||||
void MD5Update PROTO_LIST
|
||||
((MD5_CTX *, unsigned char *, unsigned int));
|
||||
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
|
||||
void MD5Hmac(unsigned char *digest,
|
||||
const unsigned char* text, int text_len,
|
||||
const unsigned char* key, int key_len);
|
||||
void MD5HexHmac(char *hexdigest,
|
||||
const unsigned char* text, int text_len,
|
||||
const unsigned char* key, int key_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* MD5_H__ */
|
||||
@@ -0,0 +1,410 @@
|
||||
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
//#include "config.h"
|
||||
#include "md5global.h"
|
||||
#include "md5.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Constants for MD5Transform routine.
|
||||
*/
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
|
||||
static void Encode PROTO_LIST
|
||||
((unsigned char *, UINT4 *, unsigned int));
|
||||
static void Decode PROTO_LIST
|
||||
((UINT4 *, unsigned char *, unsigned int));
|
||||
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
|
||||
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
|
||||
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* F, G, H and I are basic MD5 functions.
|
||||
*/
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits.
|
||||
*/
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
Rotation is separate from addition to prevent recomputation.
|
||||
*/
|
||||
#define FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) { \
|
||||
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
/* MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||
*/
|
||||
void MD5Init (MD5_CTX *context)
|
||||
/* context */
|
||||
{
|
||||
context->count[0] = context->count[1] = 0;
|
||||
/* Load magic initialization constants.
|
||||
*/
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xefcdab89;
|
||||
context->state[2] = 0x98badcfe;
|
||||
context->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/* MD5 block update operation. Continues an MD5 message-digest
|
||||
operation, processing another message block, and updating the
|
||||
context.
|
||||
*/
|
||||
void MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen)
|
||||
/* context */
|
||||
/* input block */
|
||||
/* length of input block */
|
||||
{
|
||||
unsigned int i, index, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((context->count[0] += ((UINT4)inputLen << 3))
|
||||
< ((UINT4)inputLen << 3))
|
||||
context->count[1]++;
|
||||
context->count[1] += ((UINT4)inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
/* Transform as many times as possible.
|
||||
*/
|
||||
if (inputLen >= partLen) {
|
||||
MD5_memcpy
|
||||
((POINTER)&context->buffer[index], (POINTER)input, partLen);
|
||||
MD5Transform (context->state, context->buffer);
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD5Transform (context->state, &input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
MD5_memcpy
|
||||
((POINTER)&context->buffer[index], (POINTER)&input[i],
|
||||
inputLen-i);
|
||||
}
|
||||
|
||||
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
the message digest and zeroizing the context.
|
||||
*/
|
||||
void MD5Final (unsigned char digest[16], MD5_CTX *context)
|
||||
/* message digest */
|
||||
/* context */
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode (bits, context->count, 8);
|
||||
|
||||
/* Pad out to 56 mod 64.
|
||||
*/
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
MD5Update (context, PADDING, padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
MD5Update (context, bits, 8);
|
||||
/* Store state in digest */
|
||||
Encode (digest, context->state, 16);
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset ((POINTER)context, 0, sizeof (*context));
|
||||
}
|
||||
|
||||
/* MD5 basic transformation. Transforms state based on block.
|
||||
*/
|
||||
static void MD5Transform (UINT4 state[4], unsigned char block[64])
|
||||
{
|
||||
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
Decode (x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset ((POINTER)x, 0, sizeof (x));
|
||||
}
|
||||
|
||||
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||
a multiple of 4.
|
||||
*/
|
||||
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char)(input[i] & 0xff);
|
||||
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||
a multiple of 4.
|
||||
*/
|
||||
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
|
||||
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memcpy if possible.
|
||||
*/
|
||||
|
||||
static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = input[i];
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memset if possible.
|
||||
*/
|
||||
static void MD5_memset (POINTER output, int value, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
((char *)output)[i] = (char)value;
|
||||
}
|
||||
|
||||
/*
|
||||
** Function: md5_hmac
|
||||
** taken from the file rfc2104.txt
|
||||
** written by Martin Schaaf <[email protected]>
|
||||
*/
|
||||
void
|
||||
MD5Hmac(unsigned char *digest,
|
||||
const unsigned char* text, int text_len,
|
||||
const unsigned char* key, int key_len)
|
||||
{
|
||||
MD5_CTX context;
|
||||
unsigned char k_ipad[64]; /* inner padding -
|
||||
* key XORd with ipad
|
||||
*/
|
||||
unsigned char k_opad[64]; /* outer padding -
|
||||
* key XORd with opad
|
||||
*/
|
||||
/* unsigned char tk[16]; */
|
||||
int i;
|
||||
|
||||
/* start out by storing key in pads */
|
||||
memset(k_ipad, 0, sizeof k_ipad);
|
||||
memset(k_opad, 0, sizeof k_opad);
|
||||
if (key_len > 64) {
|
||||
/* if key is longer than 64 bytes reset it to key=MD5(key) */
|
||||
MD5_CTX tctx;
|
||||
|
||||
MD5Init(&tctx);
|
||||
MD5Update(&tctx, (unsigned char*)key, key_len);
|
||||
MD5Final(k_ipad, &tctx);
|
||||
MD5Final(k_opad, &tctx);
|
||||
} else {
|
||||
memcpy(k_ipad, key, key_len);
|
||||
memcpy(k_opad, key, key_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* the HMAC_MD5 transform looks like:
|
||||
*
|
||||
* MD5(K XOR opad, MD5(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key
|
||||
* ipad is the byte 0x36 repeated 64 times
|
||||
* opad is the byte 0x5c repeated 64 times
|
||||
* and text is the data being protected
|
||||
*/
|
||||
|
||||
|
||||
/* XOR key with ipad and opad values */
|
||||
for (i = 0; i < 64; i++) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
|
||||
/*
|
||||
* perform inner MD5
|
||||
*/
|
||||
MD5Init(&context); /* init context for 1st
|
||||
* pass */
|
||||
MD5Update(&context, k_ipad, 64); /* start with inner pad */
|
||||
MD5Update(&context, (unsigned char*)text, text_len); /* then text of datagram */
|
||||
MD5Final(digest, &context); /* finish up 1st pass */
|
||||
/*
|
||||
* perform outer MD5
|
||||
*/
|
||||
MD5Init(&context); /* init context for 2nd
|
||||
* pass */
|
||||
MD5Update(&context, k_opad, 64); /* start with outer pad */
|
||||
MD5Update(&context, digest, 16); /* then results of 1st
|
||||
* hash */
|
||||
MD5Final(digest, &context); /* finish up 2nd pass */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MD5HexHmac(char *hexdigest,
|
||||
const unsigned char* text, int text_len,
|
||||
const unsigned char* key, int key_len)
|
||||
{
|
||||
unsigned char digest[16];
|
||||
int i;
|
||||
|
||||
MD5Hmac(digest, text, text_len, key, key_len);
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(hexdigest + 2 * i, "%02x", digest[i]);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* For license terms, see the file COPYING in this directory.
|
||||
*
|
||||
* md5global.h Global declarations for MD5 module used by fetchmail
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MD5GLOBAL_H__
|
||||
#define MD5GLOBAL_H__
|
||||
/* GLOBAL.H - RSAREF types and constants
|
||||
*/
|
||||
|
||||
/* force prototypes on, we need ANSI C anyway */
|
||||
#ifndef PROTOTYPES
|
||||
#define PROTOTYPES 1
|
||||
#endif
|
||||
|
||||
/* POINTER defines a generic pointer type */
|
||||
typedef unsigned char *POINTER;
|
||||
|
||||
/* UINT2 defines a two byte word */
|
||||
typedef unsigned short int UINT2;
|
||||
|
||||
/* UINT4 defines a four byte word */
|
||||
#if SIZEOF_INT == 4
|
||||
typedef unsigned int UINT4;
|
||||
#else
|
||||
typedef unsigned long int UINT4;
|
||||
#endif
|
||||
|
||||
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
|
||||
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
|
||||
returns an empty list.
|
||||
*/
|
||||
#if PROTOTYPES
|
||||
#define PROTO_LIST(list) list
|
||||
#else
|
||||
#define PROTO_LIST(list) ()
|
||||
#endif
|
||||
|
||||
#endif /* MD5GLOBAL_H__ */
|
||||
@@ -0,0 +1,731 @@
|
||||
/* POP3Protocol - implementation of the POP3 protocol
|
||||
**
|
||||
** Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <DataIO.h>
|
||||
#include <Alert.h>
|
||||
#include <Debug.h>
|
||||
#include <netdb.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include <status.h>
|
||||
#include <StringList.h>
|
||||
#include <ProtocolConfigView.h>
|
||||
#include <ChainRunner.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
|
||||
#ifdef BONE
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <socket.h>
|
||||
#endif
|
||||
|
||||
#if POPSSL
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/md5.h>
|
||||
#else
|
||||
#include "md5.h"
|
||||
#endif
|
||||
|
||||
#include "pop3.h"
|
||||
|
||||
#define POP3_RETRIEVAL_TIMEOUT 60000000
|
||||
#define CRLF "\r\n"
|
||||
|
||||
#define pop3_error(string) runner->ShowError(string)
|
||||
|
||||
POP3Protocol::POP3Protocol(BMessage *settings, BMailChainRunner *status)
|
||||
: SimpleMailProtocol(settings,status),
|
||||
fNumMessages(-1),
|
||||
fMailDropSize(0)
|
||||
{
|
||||
#ifdef POPSSL
|
||||
use_ssl = (settings->FindInt32("flavor") == 1);
|
||||
#endif
|
||||
Init();
|
||||
}
|
||||
|
||||
|
||||
POP3Protocol::~POP3Protocol()
|
||||
{
|
||||
SendCommand("QUIT" CRLF);
|
||||
|
||||
#ifdef POPSSL
|
||||
if (use_ssl) {
|
||||
SSL_shutdown(ssl);
|
||||
SSL_CTX_free(ctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BONE
|
||||
close(conn);
|
||||
#else
|
||||
closesocket(conn);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
POP3Protocol::Open(const char *server, int port, int)
|
||||
{
|
||||
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Connecting to POP3 Server...","POP3サーバに接続しています..."));
|
||||
|
||||
if (port <= 0)
|
||||
#ifdef POPSSL
|
||||
port = use_ssl ? 995 : 110;
|
||||
#else
|
||||
port = 110;
|
||||
#endif
|
||||
|
||||
fLog = "";
|
||||
|
||||
//-----Prime the error message
|
||||
BString error_msg;
|
||||
error_msg << MDR_DIALECT_CHOICE ("Error while connecting to server ","サーバに接続中にエラーが発生しました ") << server;
|
||||
if (port != 110)
|
||||
error_msg << ":" << port;
|
||||
|
||||
uint32 hostIP = inet_addr(server); // first see if we can parse it as a numeric address
|
||||
if ((hostIP == 0)||(hostIP == (uint32)-1)) {
|
||||
struct hostent * he = gethostbyname(server);
|
||||
hostIP = he ? *((uint32*)he->h_addr) : 0;
|
||||
}
|
||||
|
||||
if (hostIP == 0) {
|
||||
error_msg << MDR_DIALECT_CHOICE (": Connection refused or host not found",": :接続が拒否されたかサーバーが見つかりません");
|
||||
pop3_error(error_msg.String());
|
||||
|
||||
return B_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
conn = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (conn >= 0) {
|
||||
struct sockaddr_in saAddr;
|
||||
memset(&saAddr, 0, sizeof(saAddr));
|
||||
saAddr.sin_family = AF_INET;
|
||||
saAddr.sin_port = htons(port);
|
||||
saAddr.sin_addr.s_addr = hostIP;
|
||||
int result = connect(conn, (struct sockaddr *) &saAddr, sizeof(saAddr));
|
||||
if (result < 0) {
|
||||
#ifdef BONE
|
||||
close(conn);
|
||||
#else
|
||||
closesocket(conn);
|
||||
#endif
|
||||
conn = -1;
|
||||
error_msg << ": " << strerror(errno);
|
||||
pop3_error(error_msg.String());
|
||||
return errno;
|
||||
}
|
||||
} else {
|
||||
error_msg << ": Could not allocate socket.";
|
||||
pop3_error(error_msg.String());
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
#ifdef POPSSL
|
||||
if (use_ssl) {
|
||||
SSL_library_init();
|
||||
SSL_load_error_strings();
|
||||
RAND_seed(this,sizeof(POP3Protocol));
|
||||
/*--- Because we're an add-on loaded at an unpredictable time, all
|
||||
the memory addresses and things contained in ourself are
|
||||
esssentially random. */
|
||||
|
||||
ctx = SSL_CTX_new(SSLv23_method());
|
||||
ssl = SSL_new(ctx);
|
||||
sbio=BIO_new_socket(conn,BIO_NOCLOSE);
|
||||
SSL_set_bio(ssl,sbio,sbio);
|
||||
|
||||
if (SSL_connect(ssl) <= 0) {
|
||||
BString error;
|
||||
error << "Could not connect to POP3 server " << settings->FindString("server");
|
||||
if (port != 995)
|
||||
error << ":" << port;
|
||||
error << ". (SSL Connection Error)";
|
||||
runner->ShowError(error.String());
|
||||
SSL_CTX_free(ctx);
|
||||
#ifdef BONE
|
||||
close(conn);
|
||||
#else
|
||||
closesocket(net);
|
||||
#endif
|
||||
runner->Stop();
|
||||
return B_ERROR;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BString line;
|
||||
status_t err;
|
||||
int32 tries = 200000;
|
||||
// no endless loop here
|
||||
while ((err = ReceiveLine(line)) == 0) {
|
||||
if (tries-- < 0)
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (err < 0) {
|
||||
#ifdef BONE
|
||||
close(conn);
|
||||
#else
|
||||
closesocket(conn);
|
||||
#endif
|
||||
conn = -1;
|
||||
error_msg << ": " << strerror(err);
|
||||
pop3_error(error_msg.String());
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (strncmp(line.String(), "+OK", 3) != 0) {
|
||||
error_msg << MDR_DIALECT_CHOICE (". The server said:\n","サーバのメッセージです\n") << line.String();
|
||||
pop3_error(error_msg.String());
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
fLog = line;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t POP3Protocol::Login(const char *uid, const char *password, int method)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
BString error_msg;
|
||||
error_msg << MDR_DIALECT_CHOICE ("Error while authenticating user ","ユーザー認証中にエラーが発生しました ") << uid;
|
||||
|
||||
if (method == 1) { //APOP
|
||||
int32 index = fLog.FindFirst("<");
|
||||
if(index != B_ERROR) {
|
||||
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Sending APOP authentication...","APOP認証情報を送信中..."));
|
||||
int32 end = fLog.FindFirst(">",index);
|
||||
BString timestamp("");
|
||||
fLog.CopyInto(timestamp,index,end-index+1);
|
||||
timestamp += password;
|
||||
char md5sum[33];
|
||||
MD5Digest((unsigned char*)timestamp.String(),md5sum);
|
||||
BString cmd = "APOP ";
|
||||
cmd += uid;
|
||||
cmd += " ";
|
||||
cmd += md5sum;
|
||||
cmd += CRLF;
|
||||
|
||||
err = SendCommand(cmd.String());
|
||||
if (err != B_OK) {
|
||||
error_msg << MDR_DIALECT_CHOICE (". The server said:\n","サーバのメッセージです\n") << fLog;
|
||||
pop3_error(error_msg.String());
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
} else {
|
||||
error_msg << MDR_DIALECT_CHOICE (": The server does not support APOP.","サーバはAPOPをサポートしていません");
|
||||
pop3_error(error_msg.String());
|
||||
return B_NOT_ALLOWED;
|
||||
}
|
||||
}
|
||||
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Sending username...","ユーザーID送信中..."));
|
||||
|
||||
BString cmd = "USER ";
|
||||
cmd += uid;
|
||||
cmd += CRLF;
|
||||
|
||||
err = SendCommand(cmd.String());
|
||||
if (err != B_OK) {
|
||||
error_msg << MDR_DIALECT_CHOICE (". The server said:\n","サーバのメッセージです\n") << fLog;
|
||||
pop3_error(error_msg.String());
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Sending password...","パスワード送信中..."));
|
||||
cmd = "PASS ";
|
||||
cmd += password;
|
||||
cmd += CRLF;
|
||||
|
||||
err = SendCommand(cmd.String());
|
||||
if (err != B_OK) {
|
||||
error_msg << MDR_DIALECT_CHOICE (". The server said:\n","サーバのメッセージです\n") << fLog;
|
||||
pop3_error(error_msg.String());
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t POP3Protocol::Stat()
|
||||
{
|
||||
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Getting mailbox size...","メールボックスのサイズを取得しています..."));
|
||||
|
||||
if (SendCommand("STAT" CRLF) < B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
int32 messages,dropSize;
|
||||
if (sscanf(fLog.String(),"+OK %ld %ld",&messages,&dropSize) < 2)
|
||||
return B_ERROR;
|
||||
|
||||
fNumMessages = messages;
|
||||
fMailDropSize = dropSize;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
int32 POP3Protocol::Messages()
|
||||
{
|
||||
if (fNumMessages < 0)
|
||||
Stat();
|
||||
|
||||
return fNumMessages;
|
||||
}
|
||||
|
||||
|
||||
size_t POP3Protocol::MailDropSize()
|
||||
{
|
||||
if (fNumMessages < 0)
|
||||
Stat();
|
||||
|
||||
return fMailDropSize;
|
||||
}
|
||||
|
||||
|
||||
status_t POP3Protocol::Retrieve(int32 message, BPositionIO *write_to)
|
||||
{
|
||||
status_t returnCode;
|
||||
BString cmd;
|
||||
cmd << "RETR " << message + 1 << CRLF;
|
||||
returnCode = RetrieveInternal(cmd.String(), message, write_to, true);
|
||||
runner->ReportProgress(0 /* bytes */, 1 /* messages */);
|
||||
|
||||
if (returnCode == B_OK) { // Some debug code.
|
||||
int32 message_len = MessageSize(message);
|
||||
write_to->Seek (0, SEEK_END);
|
||||
if (write_to->Position() != message_len) {
|
||||
printf ("POP3Protocol::Retrieve Note: message size is %d, was "
|
||||
"expecting %ld, for message #%ld. Could be a transmission error "
|
||||
"or a bad POP server implementation (does it remove escape codes "
|
||||
"when it counts size?).\n",
|
||||
(int) write_to->Position(), message_len, message);
|
||||
}
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
|
||||
status_t POP3Protocol::GetHeader(int32 message, BPositionIO *write_to)
|
||||
{
|
||||
BString cmd;
|
||||
cmd << "TOP " << message + 1 << " 0" << CRLF;
|
||||
return RetrieveInternal(cmd.String(),message,write_to, false);
|
||||
}
|
||||
|
||||
|
||||
status_t POP3Protocol::RetrieveInternal(const char *command, int32 message,
|
||||
BPositionIO *write_to, bool post_progress)
|
||||
{
|
||||
const int bufSize = 1024 * 30;
|
||||
|
||||
// To avoid waiting for the non-arrival of the next data packet, try to
|
||||
// receive only the message size, plus the 3 extra bytes for the ".\r\n"
|
||||
// after the message. Of course, if we get it wrong (or it is a huge
|
||||
// message or has lines starting with escaped periods), it will then switch
|
||||
// back to receiving full buffers until the message is done.
|
||||
int amountToReceive = MessageSize (message) + 3;
|
||||
if (amountToReceive >= bufSize || amountToReceive <= 0)
|
||||
amountToReceive = bufSize - 1;
|
||||
|
||||
BString bufBString; // Used for auto-dealloc on return feature.
|
||||
char *buf = bufBString.LockBuffer (bufSize);
|
||||
int amountInBuffer = 0;
|
||||
int amountReceived;
|
||||
int testIndex;
|
||||
char *testStr;
|
||||
bool cont = true;
|
||||
bool flushWholeBuffer = false;
|
||||
write_to->Seek(0,SEEK_SET);
|
||||
|
||||
if (SendCommand(command) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
struct timeval tv;
|
||||
struct fd_set fds;
|
||||
|
||||
tv.tv_sec = long(POP3_RETRIEVAL_TIMEOUT / 1e6);
|
||||
tv.tv_usec = long(POP3_RETRIEVAL_TIMEOUT-(tv.tv_sec * 1e6));
|
||||
|
||||
/* Initialize (clear) the socket mask. */
|
||||
FD_ZERO(&fds);
|
||||
|
||||
/* Set the socket in the mask. */
|
||||
FD_SET(conn, &fds);
|
||||
|
||||
while (cont) {
|
||||
int result = 0;
|
||||
|
||||
#ifdef POPSSL
|
||||
if ((use_ssl) && (SSL_pending(ssl)))
|
||||
result = 1;
|
||||
else
|
||||
#endif
|
||||
result = select(32, &fds, NULL, NULL, &tv);
|
||||
if (result == 0) {
|
||||
// No data available, even after waiting a minute.
|
||||
fLog = "POP3 timeout - no data received after a long wait.";
|
||||
runner->Stop();
|
||||
return B_ERROR;
|
||||
}
|
||||
if (amountToReceive > bufSize - 1 - amountInBuffer)
|
||||
amountToReceive = bufSize - 1 - amountInBuffer;
|
||||
#ifdef POPSSL
|
||||
if (use_ssl)
|
||||
amountReceived = SSL_read(ssl,buf + amountInBuffer, amountToReceive);
|
||||
else
|
||||
#endif
|
||||
amountReceived = recv(conn,buf + amountInBuffer, amountToReceive,0);
|
||||
|
||||
if (amountReceived < 0) {
|
||||
fLog = strerror(errno);
|
||||
return errno;
|
||||
}
|
||||
if (amountReceived == 0) {
|
||||
fLog = "POP3 data supposedly ready to receive but not received!";
|
||||
return B_ERROR; // Shouldn't happen, but...
|
||||
}
|
||||
amountToReceive = bufSize - 1; // For next time, read a full buffer.
|
||||
amountInBuffer += amountReceived;
|
||||
buf[amountInBuffer] = 0; // NUL stops tests past the end of buffer.
|
||||
|
||||
// Look for lines starting with a period. A single period by itself on
|
||||
// a line "\r\n.\r\n" marks the end of the message (thus the need for
|
||||
// at least five characters in the buffer for testing). A period
|
||||
// "\r\n.Stuff" at the start of a line get deleted "\r\nStuff", since
|
||||
// POP adds one as an escape code to let you have message text with
|
||||
// lines starting with a period. For convenience, assume that no
|
||||
// messages start with a period on the very first line, so we can
|
||||
// search for the previous line's "\r\n".
|
||||
|
||||
for (testIndex = 0; testIndex <= amountInBuffer - 5; testIndex++) {
|
||||
testStr = buf + testIndex;
|
||||
if (testStr[0] == '\r' && testStr[1] == '\n' && testStr[2] == '.') {
|
||||
if (testStr[3] == '\r' && testStr[4] == '\n') {
|
||||
// Found the end of the message marker. Ignore remaining data.
|
||||
if (amountInBuffer > testIndex + 5)
|
||||
printf ("POP3Protocol::RetrieveInternal Ignoring %d bytes "
|
||||
"of extra data past message end.\n",
|
||||
amountInBuffer - (testIndex + 5));
|
||||
amountInBuffer = testIndex + 2; // Don't include ".\r\n".
|
||||
buf[amountInBuffer] = 0;
|
||||
cont = false;
|
||||
} else {
|
||||
// Remove an extra period at the start of a line.
|
||||
// Inefficient, but it doesn't happen often that you have a
|
||||
// dot starting a line of text. Of course, a file with a
|
||||
// lot of double period lines will get processed very
|
||||
// slowly.
|
||||
memmove (buf + testIndex + 2, buf + testIndex + 3,
|
||||
amountInBuffer - (testIndex + 3) + 1 /* for NUL at end */);
|
||||
amountInBuffer--;
|
||||
// Watch out for the end of buffer case, when the POP text
|
||||
// is "\r\n..X". Don't want to leave the resulting
|
||||
// "\r\n.X" in the buffer (flush out the whole buffer),
|
||||
// since that will get mistakenly evaluated again in the
|
||||
// next loop and delete a character by mistake.
|
||||
if (testIndex >= amountInBuffer - 4 && testStr[2] == '.') {
|
||||
printf ("POP3Protocol::RetrieveInternal: Jackpot! You have "
|
||||
"hit the rare situation with an escaped period at the "
|
||||
"end of the buffer. Aren't you happy it decodes it "
|
||||
"correctly?\n");
|
||||
flushWholeBuffer = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cont && !flushWholeBuffer) {
|
||||
// Dump out most of the buffer, but leave the last 4 characters for
|
||||
// comparison continuity, in case the line starting with a period
|
||||
// crosses a buffer boundary.
|
||||
if (amountInBuffer > 4) {
|
||||
write_to->Write(buf, amountInBuffer - 4);
|
||||
if (post_progress)
|
||||
runner->ReportProgress(amountInBuffer - 4,0);
|
||||
memmove (buf, buf + amountInBuffer - 4, 4);
|
||||
amountInBuffer = 4;
|
||||
}
|
||||
} else { // Dump everything - end of message or flushing the whole buffer.
|
||||
write_to->Write(buf, amountInBuffer);
|
||||
if (post_progress)
|
||||
runner->ReportProgress(amountInBuffer,0);
|
||||
amountInBuffer = 0;
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t POP3Protocol::UniqueIDs() {
|
||||
status_t ret = B_OK;
|
||||
runner->ReportProgress(0,0,MDR_DIALECT_CHOICE ("Getting UniqueIDs...","固有のIDを取得中..."));
|
||||
|
||||
ret = SendCommand("UIDL" CRLF);
|
||||
if (ret != B_OK) return ret;
|
||||
|
||||
BString result;
|
||||
int32 uid_offset;
|
||||
while (ReceiveLine(result) > 0) {
|
||||
if (result.ByteAt(0) == '.')
|
||||
break;
|
||||
|
||||
uid_offset = result.FindFirst(' ') + 1;
|
||||
result.Remove(0,uid_offset);
|
||||
unique_ids->AddItem(result.String());
|
||||
}
|
||||
|
||||
if (SendCommand("LIST"CRLF) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
int32 b;
|
||||
while (ReceiveLine(result) > 0) {
|
||||
if (result.ByteAt(0) == '.')
|
||||
break;
|
||||
|
||||
b = result.FindLast(" ");
|
||||
if (b >= 0)
|
||||
b = atol(&(result.String()[b]));
|
||||
else
|
||||
b = 0;
|
||||
sizes.AddItem((void *)(b));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void POP3Protocol::Delete(int32 num) {
|
||||
BString cmd = "DELE ";
|
||||
cmd << (num+1) << CRLF;
|
||||
if (SendCommand(cmd.String()) != B_OK) {
|
||||
// Error
|
||||
}
|
||||
#if DEBUG
|
||||
puts(fLog.String());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
size_t POP3Protocol::MessageSize(int32 index) {
|
||||
return (size_t)(sizes.ItemAt(index));
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
POP3Protocol::ReceiveLine(BString &line)
|
||||
{
|
||||
int32 len = 0, rcv;
|
||||
int8 c = 0;
|
||||
bool flag = false;
|
||||
|
||||
line = "";
|
||||
|
||||
struct timeval tv;
|
||||
struct fd_set fds;
|
||||
|
||||
tv.tv_sec = long(POP3_RETRIEVAL_TIMEOUT / 1e6);
|
||||
tv.tv_usec = long(POP3_RETRIEVAL_TIMEOUT-(tv.tv_sec * 1e6));
|
||||
|
||||
/* Initialize (clear) the socket mask. */
|
||||
FD_ZERO(&fds);
|
||||
|
||||
/* Set the socket in the mask. */
|
||||
FD_SET(conn, &fds);
|
||||
int result = -1;
|
||||
#ifdef POPSSL
|
||||
if ((use_ssl) && (SSL_pending(ssl)))
|
||||
result = 1;
|
||||
else
|
||||
#endif
|
||||
result = select(32, &fds, NULL, NULL, &tv);
|
||||
|
||||
if (result < 0)
|
||||
return B_TIMEOUT;
|
||||
|
||||
if (result > 0) {
|
||||
while (true) { // Hope there's an end of line out there else this gets stuck.
|
||||
#ifdef POPSSL
|
||||
if (use_ssl)
|
||||
rcv = SSL_read(ssl,&c,1);
|
||||
else
|
||||
#endif
|
||||
rcv = recv(conn, &c, 1, 0);
|
||||
if (rcv < 0)
|
||||
return errno; //--An error!
|
||||
//putchar(c);
|
||||
if ((c == '\n') || (rcv == 0 /* EOF */))
|
||||
break;
|
||||
|
||||
if (c == '\r') {
|
||||
flag = true;
|
||||
} else {
|
||||
if (flag) {
|
||||
len++;
|
||||
line += '\r';
|
||||
flag = false;
|
||||
}
|
||||
len++;
|
||||
line += (char)c;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fLog = "POP3 socket timeout.";
|
||||
runner->Stop();
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
status_t
|
||||
|
||||
POP3Protocol::SendCommand(const char *cmd)
|
||||
{
|
||||
if (conn < 0 || conn > FD_SETSIZE)
|
||||
return B_FILE_ERROR;
|
||||
//printf(cmd);
|
||||
// Flush any accumulated garbage data before we send our command, so we
|
||||
// don't misinterrpret responses from previous commands (that got left over
|
||||
// due to bugs) as being from this command.
|
||||
|
||||
struct timeval tv;
|
||||
tv.tv_sec = long(1000 / 1e6);
|
||||
tv.tv_usec = long(1000-(tv.tv_sec * 1e6)); /* very short timeout, hangs with 0 in R5 */
|
||||
|
||||
struct fd_set fds;
|
||||
|
||||
/* Initialize (clear) the socket mask. */
|
||||
FD_ZERO(&fds);
|
||||
|
||||
/* Set the socket in the mask. */
|
||||
FD_SET(conn, &fds);
|
||||
int result;
|
||||
#ifdef POPSSL
|
||||
if ((use_ssl) && (SSL_pending(ssl)))
|
||||
result = 1;
|
||||
else
|
||||
#endif
|
||||
result = select(32, &fds, NULL, NULL, &tv);
|
||||
|
||||
if (result > 0) {
|
||||
int amountReceived;
|
||||
char tempString [1025];
|
||||
#ifdef POPSSL
|
||||
if (use_ssl)
|
||||
amountReceived = SSL_read(ssl,tempString, sizeof (tempString) - 1);
|
||||
else
|
||||
#endif
|
||||
amountReceived = recv (conn,tempString, sizeof (tempString) - 1,0);
|
||||
if (amountReceived < 0)
|
||||
return errno;
|
||||
tempString [amountReceived] = 0;
|
||||
printf ("POP3Protocol::SendCommand Bug! Had to flush %d bytes: %s\n",
|
||||
amountReceived, tempString);
|
||||
//if (amountReceived == 0)
|
||||
// break;
|
||||
}
|
||||
#ifdef POPSSL
|
||||
if (use_ssl) {
|
||||
SSL_write(ssl,cmd,::strlen(cmd));
|
||||
//SSL_write(ssl,"\r\n",2);
|
||||
} else
|
||||
#endif
|
||||
if (send(conn, cmd, ::strlen(cmd), 0) < 0) {
|
||||
fLog = strerror(errno);
|
||||
printf ("POP3Protocol::SendCommand Send \"%s\" failed, code %d: %s\n",
|
||||
cmd, errno, fLog.String());
|
||||
return errno;
|
||||
}
|
||||
|
||||
fLog = "";
|
||||
status_t err = B_OK;
|
||||
|
||||
while (true) {
|
||||
int32 len = ReceiveLine(fLog);
|
||||
if (len <= 0 || fLog.ICompare("+OK", 3) == 0)
|
||||
break;
|
||||
|
||||
if (fLog.ICompare("-ERR", 4) == 0) {
|
||||
printf("POP3Protocol::SendCommand \"%s\" got error message "
|
||||
"from server: %s\n", cmd, fLog.String());
|
||||
err = B_ERROR;
|
||||
break;
|
||||
} else {
|
||||
printf("POP3Protocol::SendCommand \"%s\" got nonsense message "
|
||||
"from server: %s\n", cmd, fLog.String());
|
||||
err = B_BAD_VALUE; //-------If it's not +OK, and it's not -ERR, then what the heck is it? Presume an error
|
||||
break;
|
||||
}
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
void POP3Protocol::MD5Digest (unsigned char *in,char *ascii_digest)
|
||||
{
|
||||
unsigned char digest[16];
|
||||
|
||||
#ifdef POPSSL
|
||||
MD5(in, ::strlen((char*)in),digest);
|
||||
#else
|
||||
MD5_CTX context;
|
||||
|
||||
MD5Init(&context);
|
||||
MD5Update(&context, in, ::strlen((char*)in));
|
||||
MD5Final(digest, &context);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 16; i++)
|
||||
sprintf(ascii_digest+2*i, "%02x", digest[i]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BMailFilter *instantiate_mailfilter(BMessage *settings, BMailChainRunner *runner)
|
||||
{
|
||||
return new POP3Protocol(settings,runner);
|
||||
}
|
||||
|
||||
|
||||
BView* instantiate_config_panel(BMessage *settings,BMessage *)
|
||||
{
|
||||
BMailProtocolConfigView *view = new BMailProtocolConfigView(B_MAIL_PROTOCOL_HAS_USERNAME | B_MAIL_PROTOCOL_HAS_AUTH_METHODS | B_MAIL_PROTOCOL_HAS_FLAVORS | B_MAIL_PROTOCOL_HAS_PASSWORD | B_MAIL_PROTOCOL_HAS_HOSTNAME | B_MAIL_PROTOCOL_CAN_LEAVE_MAIL_ON_SERVER);
|
||||
view->AddAuthMethod("Plain Text");
|
||||
view->AddAuthMethod("APOP");
|
||||
|
||||
#if POPSSL
|
||||
view->AddFlavor("Unencrypted");
|
||||
view->AddFlavor("SSL");
|
||||
#endif
|
||||
|
||||
view->SetTo(settings);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#ifndef ZOIDBERG_POP3_H
|
||||
#define ZOIDBERG_POP3_H
|
||||
/* POP3Protocol - implementation of the POP3 protocol
|
||||
**
|
||||
** Copyright 2001-2002 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
#include <String.h>
|
||||
#include <map>
|
||||
|
||||
#include "SimpleMailProtocol.h"
|
||||
|
||||
class POP3Protocol : public SimpleMailProtocol {
|
||||
public:
|
||||
POP3Protocol(BMessage *settings, BMailChainRunner *status);
|
||||
~POP3Protocol();
|
||||
|
||||
status_t Open(const char *server, int port, int protocol);
|
||||
status_t Login(const char *uid, const char *password, int method);
|
||||
status_t UniqueIDs();
|
||||
status_t Retrieve(int32 message, BPositionIO *write_to);
|
||||
status_t GetHeader(int32 message, BPositionIO *write_to);
|
||||
void Delete(int32 num);
|
||||
size_t MessageSize(int32 index);
|
||||
status_t Stat();
|
||||
int32 Messages(void);
|
||||
size_t MailDropSize(void);
|
||||
|
||||
protected:
|
||||
status_t RetrieveInternal(const char *command,int32 message, BPositionIO *write_to, bool show_progress);
|
||||
|
||||
int32 ReceiveLine(BString &line);
|
||||
status_t SendCommand(const char* cmd);
|
||||
void MD5Digest (unsigned char *in, char *out); // MD5 Digest
|
||||
|
||||
private:
|
||||
int conn;
|
||||
BString fLog;
|
||||
int32 fNumMessages;
|
||||
size_t fMailDropSize;
|
||||
BList sizes;
|
||||
|
||||
#ifdef POPSSL
|
||||
SSL_CTX *ctx;
|
||||
SSL *ssl;
|
||||
BIO *sbio;
|
||||
|
||||
bool use_ssl;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* ZOIDBERG_POP3_H */
|
||||
@@ -0,0 +1,86 @@
|
||||
/* ConfigView - the configuration view for the Fortune filter
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include "ConfigView.h"
|
||||
|
||||
#include <TextControl.h>
|
||||
#include <String.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include <FileConfigView.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
|
||||
ConfigView::ConfigView()
|
||||
: BView(BRect(0,0,20,20),"fortune_filter",B_FOLLOW_LEFT | B_FOLLOW_TOP,0)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
// determine font height
|
||||
font_height fontHeight;
|
||||
GetFontHeight(&fontHeight);
|
||||
float itemHeight = (int32)(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 13;
|
||||
|
||||
BRect rect(5,4,250,25);
|
||||
rect.bottom = rect.top - 2 + itemHeight;
|
||||
BMailFileConfigView *fview = new BMailFileConfigView(MDR_DIALECT_CHOICE ("Fortune File:","予言ファイル:"),"fortune_file",false,"/boot/beos/etc/fortunes/default",B_FILE_NODE);
|
||||
AddChild(fview);
|
||||
|
||||
rect.top = rect.bottom + 8;
|
||||
rect.bottom = rect.top - 2 + itemHeight;
|
||||
BTextControl * control = new BTextControl(rect,"tag_line",MDR_DIALECT_CHOICE ("Tag Line:","見出し:"),NULL,NULL);
|
||||
control->SetDivider(control->StringWidth(control->Label()) + 6);
|
||||
AddChild(control);
|
||||
|
||||
ResizeToPreferred();
|
||||
}
|
||||
|
||||
|
||||
void ConfigView::SetTo(BMessage *archive)
|
||||
{
|
||||
BString path = archive->FindString("fortune_file");
|
||||
if (path == B_EMPTY_STRING)
|
||||
path = "/boot/beos/etc/fortunes/default";
|
||||
|
||||
if (BMailFileConfigView *control = (BMailFileConfigView *)FindView("fortune_file"))
|
||||
control->SetTo(archive,NULL);
|
||||
|
||||
path = archive->FindString("tag_line");
|
||||
if (!archive->HasString("tag_line"))
|
||||
path = "Fortune Cookie Says:\n\n";
|
||||
|
||||
path.Truncate(path.Length() - 2);
|
||||
if (BTextControl *control = (BTextControl *)FindView("tag_line"))
|
||||
control->SetText(path.String());
|
||||
}
|
||||
|
||||
|
||||
status_t ConfigView::Archive(BMessage *into,bool) const
|
||||
{
|
||||
if (BMailFileConfigView *control = (BMailFileConfigView *)FindView("fortune_file"))
|
||||
{
|
||||
control->Archive(into);
|
||||
}
|
||||
|
||||
if (BTextControl *control = (BTextControl *)FindView("tag_line"))
|
||||
{
|
||||
BString line = control->Text();
|
||||
if (line != B_EMPTY_STRING)
|
||||
line << "\n\n";
|
||||
if (into->ReplaceString("tag_line",line.String()) != B_OK)
|
||||
into->AddString("tag_line",line.String());
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void ConfigView::GetPreferredSize(float *width, float *height)
|
||||
{
|
||||
*width = 258;
|
||||
*height = (ChildAt(0)->Bounds().Height() + 8) * CountChildren();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#ifndef CONFIG_VIEW
|
||||
#define CONFIG_VIEW
|
||||
/* ConfigView - the configuration view for the Folder filter
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <View.h>
|
||||
|
||||
|
||||
class ConfigView : public BView
|
||||
{
|
||||
public:
|
||||
ConfigView();
|
||||
void SetTo(BMessage *archive);
|
||||
|
||||
virtual status_t Archive(BMessage *into, bool deep = true) const;
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
};
|
||||
|
||||
#endif /* CONFIG_VIEW */
|
||||
@@ -0,0 +1,11 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon outbound_filters fortune ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
Addon Fortune : mail_daemon outbound_fitlers :
|
||||
ConfigView.cpp
|
||||
filter.cpp ;
|
||||
|
||||
LinkSharedOSLibs Fortune :
|
||||
be mail ;
|
||||
@@ -0,0 +1,112 @@
|
||||
/* Add Fortune - adds fortunes to your mail
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include "ConfigView.h"
|
||||
|
||||
#include <Message.h>
|
||||
#include <Entry.h>
|
||||
#include <String.h>
|
||||
#include <MailAddon.h>
|
||||
#include <MailMessage.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "NodeMessage.h"
|
||||
|
||||
class FortuneFilter : public BMailFilter
|
||||
{
|
||||
BMessage *settings;
|
||||
public:
|
||||
FortuneFilter(BMessage*);
|
||||
virtual status_t InitCheck(BString *err);
|
||||
virtual status_t ProcessMailMessage
|
||||
(
|
||||
BPositionIO** io_message, BEntry* io_entry,
|
||||
BMessage* io_headers, BPath* io_folder, const char* io_uid
|
||||
);
|
||||
};
|
||||
|
||||
FortuneFilter::FortuneFilter(BMessage* msg)
|
||||
: BMailFilter(msg), settings(msg)
|
||||
{
|
||||
}
|
||||
|
||||
status_t FortuneFilter::InitCheck(BString* err)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t FortuneFilter::ProcessMailMessage
|
||||
(BPositionIO** io, BEntry* io_entry, BMessage* headers, BPath* , const char*)
|
||||
{
|
||||
// What we want to do here is to change the message body. To do that we use the
|
||||
// framework we already have by creating a new BEmailMessage based on the
|
||||
// BPositionIO, changing the message body and rendering it back to disk. Of course
|
||||
// this method ends up not being super-efficient, but it works. Ideas on how to
|
||||
// improve this are welcome.
|
||||
BString fortune_file;
|
||||
BString tag_line;
|
||||
BString fortune;
|
||||
|
||||
BEmailMessage mail_message(*io);
|
||||
BString mail_body(mail_message.BodyText());
|
||||
|
||||
// Obtain relevant settings
|
||||
settings->FindString("fortune_file", &fortune_file);
|
||||
settings->FindString("tag_line", &tag_line);
|
||||
|
||||
// Add command to be executed
|
||||
fortune_file.Prepend("/bin/fortune ");
|
||||
|
||||
char buffer[768];
|
||||
FILE *fd;
|
||||
|
||||
fd = popen(fortune_file.String(), "r");
|
||||
if (fd)
|
||||
{
|
||||
mail_body += "\n--\n";
|
||||
mail_body += tag_line;
|
||||
|
||||
while (fgets(buffer, 768, fd))
|
||||
mail_body += buffer;
|
||||
|
||||
mail_body += "\n";
|
||||
|
||||
pclose(fd);
|
||||
|
||||
// Update the message body
|
||||
mail_message.SetBodyTextTo(mail_body.String());
|
||||
|
||||
// Render it back to a BMallocIO object. We need this because we do not render
|
||||
// the entire message in memory so if we try to change the BPositionIO object we
|
||||
// have directly we will end up having the mail components pointing out to wrong
|
||||
// locations in the BPositionIo itself.
|
||||
BMallocIO shimmy_pipe;
|
||||
mail_message.RenderToRFC822(&shimmy_pipe);
|
||||
|
||||
// Now we use the BMallocIO object and overwrite the BPositionIO one with it.
|
||||
(*io)->Seek(0, SEEK_SET);
|
||||
(*io)->SetSize(0);
|
||||
(*io)->Write(shimmy_pipe.Buffer(),shimmy_pipe.BufferLength());
|
||||
}
|
||||
else
|
||||
printf("Could not open pipe to fortune!\n");
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
BMailFilter* instantiate_mailfilter(BMessage* settings, BMailChainRunner*)
|
||||
{
|
||||
return new FortuneFilter(settings);
|
||||
}
|
||||
|
||||
BView* instantiate_config_panel(BMessage *settings,BMessage *)
|
||||
{
|
||||
ConfigView *view = new ConfigView();
|
||||
view->SetTo(settings);
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon outbound_protocols smtp ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
SubDirC++Flags -DBONE ;
|
||||
|
||||
Addon SMTP : mail_daemon outbound_protocols :
|
||||
smtp.cpp
|
||||
md5c.c ;
|
||||
|
||||
LinkSharedOSLibs SMTP :
|
||||
be mail socket bind ;
|
||||
@@ -0,0 +1,56 @@
|
||||
/* MD5.H - header file for MD5C.C
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
#ifndef MD5_H__
|
||||
#define MD5_H__
|
||||
|
||||
#include "md5global.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* MD5 context. */
|
||||
typedef struct {
|
||||
UINT4 state[4]; /* state (ABCD) */
|
||||
UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
|
||||
unsigned char buffer[64]; /* input buffer */
|
||||
} MD5_CTX;
|
||||
|
||||
void MD5Init PROTO_LIST ((MD5_CTX *));
|
||||
void MD5Update PROTO_LIST
|
||||
((MD5_CTX *, unsigned char *, unsigned int));
|
||||
void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
|
||||
void MD5Hmac(unsigned char *digest,
|
||||
const unsigned char* text, int text_len,
|
||||
const unsigned char* key, int key_len);
|
||||
void MD5HexHmac(char *hexdigest,
|
||||
const unsigned char* text, int text_len,
|
||||
const unsigned char* key, int key_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* MD5_H__ */
|
||||
@@ -0,0 +1,410 @@
|
||||
/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
|
||||
*/
|
||||
|
||||
/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
|
||||
rights reserved.
|
||||
|
||||
License to copy and use this software is granted provided that it
|
||||
is identified as the "RSA Data Security, Inc. MD5 Message-Digest
|
||||
Algorithm" in all material mentioning or referencing this software
|
||||
or this function.
|
||||
|
||||
License is also granted to make and use derivative works provided
|
||||
that such works are identified as "derived from the RSA Data
|
||||
Security, Inc. MD5 Message-Digest Algorithm" in all material
|
||||
mentioning or referencing the derived work.
|
||||
|
||||
RSA Data Security, Inc. makes no representations concerning either
|
||||
the merchantability of this software or the suitability of this
|
||||
software for any particular purpose. It is provided "as is"
|
||||
without express or implied warranty of any kind.
|
||||
|
||||
These notices must be retained in any copies of any part of this
|
||||
documentation and/or software.
|
||||
*/
|
||||
|
||||
//#include "config.h"
|
||||
#include "md5global.h"
|
||||
#include "md5.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Constants for MD5Transform routine.
|
||||
*/
|
||||
#define S11 7
|
||||
#define S12 12
|
||||
#define S13 17
|
||||
#define S14 22
|
||||
#define S21 5
|
||||
#define S22 9
|
||||
#define S23 14
|
||||
#define S24 20
|
||||
#define S31 4
|
||||
#define S32 11
|
||||
#define S33 16
|
||||
#define S34 23
|
||||
#define S41 6
|
||||
#define S42 10
|
||||
#define S43 15
|
||||
#define S44 21
|
||||
|
||||
static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
|
||||
static void Encode PROTO_LIST
|
||||
((unsigned char *, UINT4 *, unsigned int));
|
||||
static void Decode PROTO_LIST
|
||||
((UINT4 *, unsigned char *, unsigned int));
|
||||
static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
|
||||
static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
|
||||
|
||||
static unsigned char PADDING[64] = {
|
||||
0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
/* F, G, H and I are basic MD5 functions.
|
||||
*/
|
||||
#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
|
||||
#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
|
||||
#define H(x, y, z) ((x) ^ (y) ^ (z))
|
||||
#define I(x, y, z) ((y) ^ ((x) | (~z)))
|
||||
|
||||
/* ROTATE_LEFT rotates x left n bits.
|
||||
*/
|
||||
#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
|
||||
|
||||
/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
|
||||
Rotation is separate from addition to prevent recomputation.
|
||||
*/
|
||||
#define FF(a, b, c, d, x, s, ac) { \
|
||||
(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define GG(a, b, c, d, x, s, ac) { \
|
||||
(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define HH(a, b, c, d, x, s, ac) { \
|
||||
(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
#define II(a, b, c, d, x, s, ac) { \
|
||||
(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
|
||||
(a) = ROTATE_LEFT ((a), (s)); \
|
||||
(a) += (b); \
|
||||
}
|
||||
|
||||
/* MD5 initialization. Begins an MD5 operation, writing a new context.
|
||||
*/
|
||||
void MD5Init (MD5_CTX *context)
|
||||
/* context */
|
||||
{
|
||||
context->count[0] = context->count[1] = 0;
|
||||
/* Load magic initialization constants.
|
||||
*/
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xefcdab89;
|
||||
context->state[2] = 0x98badcfe;
|
||||
context->state[3] = 0x10325476;
|
||||
}
|
||||
|
||||
/* MD5 block update operation. Continues an MD5 message-digest
|
||||
operation, processing another message block, and updating the
|
||||
context.
|
||||
*/
|
||||
void MD5Update (MD5_CTX *context, unsigned char *input, unsigned int inputLen)
|
||||
/* context */
|
||||
/* input block */
|
||||
/* length of input block */
|
||||
{
|
||||
unsigned int i, index, partLen;
|
||||
|
||||
/* Compute number of bytes mod 64 */
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3F);
|
||||
|
||||
/* Update number of bits */
|
||||
if ((context->count[0] += ((UINT4)inputLen << 3))
|
||||
< ((UINT4)inputLen << 3))
|
||||
context->count[1]++;
|
||||
context->count[1] += ((UINT4)inputLen >> 29);
|
||||
|
||||
partLen = 64 - index;
|
||||
|
||||
/* Transform as many times as possible.
|
||||
*/
|
||||
if (inputLen >= partLen) {
|
||||
MD5_memcpy
|
||||
((POINTER)&context->buffer[index], (POINTER)input, partLen);
|
||||
MD5Transform (context->state, context->buffer);
|
||||
|
||||
for (i = partLen; i + 63 < inputLen; i += 64)
|
||||
MD5Transform (context->state, &input[i]);
|
||||
|
||||
index = 0;
|
||||
}
|
||||
else
|
||||
i = 0;
|
||||
|
||||
/* Buffer remaining input */
|
||||
MD5_memcpy
|
||||
((POINTER)&context->buffer[index], (POINTER)&input[i],
|
||||
inputLen-i);
|
||||
}
|
||||
|
||||
/* MD5 finalization. Ends an MD5 message-digest operation, writing the
|
||||
the message digest and zeroizing the context.
|
||||
*/
|
||||
void MD5Final (unsigned char digest[16], MD5_CTX *context)
|
||||
/* message digest */
|
||||
/* context */
|
||||
{
|
||||
unsigned char bits[8];
|
||||
unsigned int index, padLen;
|
||||
|
||||
/* Save number of bits */
|
||||
Encode (bits, context->count, 8);
|
||||
|
||||
/* Pad out to 56 mod 64.
|
||||
*/
|
||||
index = (unsigned int)((context->count[0] >> 3) & 0x3f);
|
||||
padLen = (index < 56) ? (56 - index) : (120 - index);
|
||||
MD5Update (context, PADDING, padLen);
|
||||
|
||||
/* Append length (before padding) */
|
||||
MD5Update (context, bits, 8);
|
||||
/* Store state in digest */
|
||||
Encode (digest, context->state, 16);
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset ((POINTER)context, 0, sizeof (*context));
|
||||
}
|
||||
|
||||
/* MD5 basic transformation. Transforms state based on block.
|
||||
*/
|
||||
static void MD5Transform (UINT4 state[4], unsigned char block[64])
|
||||
{
|
||||
UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
|
||||
|
||||
Decode (x, block, 64);
|
||||
|
||||
/* Round 1 */
|
||||
FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
|
||||
FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
|
||||
FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
|
||||
FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
|
||||
FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
|
||||
FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
|
||||
FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
|
||||
FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
|
||||
FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
|
||||
FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
|
||||
FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
|
||||
FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
|
||||
FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
|
||||
FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
|
||||
FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
|
||||
FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
|
||||
|
||||
/* Round 2 */
|
||||
GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
|
||||
GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
|
||||
GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
|
||||
GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
|
||||
GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
|
||||
GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
|
||||
GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
|
||||
GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
|
||||
GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
|
||||
GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
|
||||
GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
|
||||
GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
|
||||
GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
|
||||
GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
|
||||
GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
|
||||
GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
|
||||
|
||||
/* Round 3 */
|
||||
HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
|
||||
HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
|
||||
HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
|
||||
HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
|
||||
HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
|
||||
HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
|
||||
HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
|
||||
HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
|
||||
HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
|
||||
HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
|
||||
HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
|
||||
HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
|
||||
HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
|
||||
HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
|
||||
HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
|
||||
HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
|
||||
|
||||
/* Round 4 */
|
||||
II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
|
||||
II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
|
||||
II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
|
||||
II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
|
||||
II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
|
||||
II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
|
||||
II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
|
||||
II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
|
||||
II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
|
||||
II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
|
||||
II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
|
||||
II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
|
||||
II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
|
||||
II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
|
||||
II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
|
||||
II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
|
||||
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
|
||||
/* Zeroize sensitive information.
|
||||
*/
|
||||
MD5_memset ((POINTER)x, 0, sizeof (x));
|
||||
}
|
||||
|
||||
/* Encodes input (UINT4) into output (unsigned char). Assumes len is
|
||||
a multiple of 4.
|
||||
*/
|
||||
static void Encode (unsigned char *output, UINT4 *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4) {
|
||||
output[j] = (unsigned char)(input[i] & 0xff);
|
||||
output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
|
||||
output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
|
||||
output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decodes input (unsigned char) into output (UINT4). Assumes len is
|
||||
a multiple of 4.
|
||||
*/
|
||||
static void Decode (UINT4 *output, unsigned char *input, unsigned int len)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
for (i = 0, j = 0; j < len; i++, j += 4)
|
||||
output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
|
||||
(((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memcpy if possible.
|
||||
*/
|
||||
|
||||
static void MD5_memcpy (POINTER output, POINTER input, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
output[i] = input[i];
|
||||
}
|
||||
|
||||
/* Note: Replace "for loop" with standard memset if possible.
|
||||
*/
|
||||
static void MD5_memset (POINTER output, int value, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
((char *)output)[i] = (char)value;
|
||||
}
|
||||
|
||||
/*
|
||||
** Function: md5_hmac
|
||||
** taken from the file rfc2104.txt
|
||||
** written by Martin Schaaf <[email protected]>
|
||||
*/
|
||||
void
|
||||
MD5Hmac(unsigned char *digest,
|
||||
const unsigned char* text, int text_len,
|
||||
const unsigned char* key, int key_len)
|
||||
{
|
||||
MD5_CTX context;
|
||||
unsigned char k_ipad[64]; /* inner padding -
|
||||
* key XORd with ipad
|
||||
*/
|
||||
unsigned char k_opad[64]; /* outer padding -
|
||||
* key XORd with opad
|
||||
*/
|
||||
/* unsigned char tk[16]; */
|
||||
int i;
|
||||
|
||||
/* start out by storing key in pads */
|
||||
memset(k_ipad, 0, sizeof k_ipad);
|
||||
memset(k_opad, 0, sizeof k_opad);
|
||||
if (key_len > 64) {
|
||||
/* if key is longer than 64 bytes reset it to key=MD5(key) */
|
||||
MD5_CTX tctx;
|
||||
|
||||
MD5Init(&tctx);
|
||||
MD5Update(&tctx, (unsigned char*)key, key_len);
|
||||
MD5Final(k_ipad, &tctx);
|
||||
MD5Final(k_opad, &tctx);
|
||||
} else {
|
||||
memcpy(k_ipad, key, key_len);
|
||||
memcpy(k_opad, key, key_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* the HMAC_MD5 transform looks like:
|
||||
*
|
||||
* MD5(K XOR opad, MD5(K XOR ipad, text))
|
||||
*
|
||||
* where K is an n byte key
|
||||
* ipad is the byte 0x36 repeated 64 times
|
||||
* opad is the byte 0x5c repeated 64 times
|
||||
* and text is the data being protected
|
||||
*/
|
||||
|
||||
|
||||
/* XOR key with ipad and opad values */
|
||||
for (i = 0; i < 64; i++) {
|
||||
k_ipad[i] ^= 0x36;
|
||||
k_opad[i] ^= 0x5c;
|
||||
}
|
||||
|
||||
/*
|
||||
* perform inner MD5
|
||||
*/
|
||||
MD5Init(&context); /* init context for 1st
|
||||
* pass */
|
||||
MD5Update(&context, k_ipad, 64); /* start with inner pad */
|
||||
MD5Update(&context, (unsigned char*)text, text_len); /* then text of datagram */
|
||||
MD5Final(digest, &context); /* finish up 1st pass */
|
||||
/*
|
||||
* perform outer MD5
|
||||
*/
|
||||
MD5Init(&context); /* init context for 2nd
|
||||
* pass */
|
||||
MD5Update(&context, k_opad, 64); /* start with outer pad */
|
||||
MD5Update(&context, digest, 16); /* then results of 1st
|
||||
* hash */
|
||||
MD5Final(digest, &context); /* finish up 2nd pass */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MD5HexHmac(char *hexdigest,
|
||||
const unsigned char* text, int text_len,
|
||||
const unsigned char* key, int key_len)
|
||||
{
|
||||
unsigned char digest[16];
|
||||
int i;
|
||||
|
||||
MD5Hmac(digest, text, text_len, key, key_len);
|
||||
for (i = 0; i < 16; i++)
|
||||
sprintf(hexdigest + 2 * i, "%02x", digest[i]);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* For license terms, see the file COPYING in this directory.
|
||||
*
|
||||
* md5global.h Global declarations for MD5 module used by fetchmail
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MD5GLOBAL_H__
|
||||
#define MD5GLOBAL_H__
|
||||
/* GLOBAL.H - RSAREF types and constants
|
||||
*/
|
||||
|
||||
/* force prototypes on, we need ANSI C anyway */
|
||||
#ifndef PROTOTYPES
|
||||
#define PROTOTYPES 1
|
||||
#endif
|
||||
|
||||
/* POINTER defines a generic pointer type */
|
||||
typedef unsigned char *POINTER;
|
||||
|
||||
/* UINT2 defines a two byte word */
|
||||
typedef unsigned short int UINT2;
|
||||
|
||||
/* UINT4 defines a four byte word */
|
||||
#if SIZEOF_INT == 4
|
||||
typedef unsigned int UINT4;
|
||||
#else
|
||||
typedef unsigned long int UINT4;
|
||||
#endif
|
||||
|
||||
/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
|
||||
If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
|
||||
returns an empty list.
|
||||
*/
|
||||
#if PROTOTYPES
|
||||
#define PROTO_LIST(list) list
|
||||
#else
|
||||
#define PROTO_LIST(list) ()
|
||||
#endif
|
||||
|
||||
#endif /* MD5GLOBAL_H__ */
|
||||
@@ -0,0 +1,678 @@
|
||||
/* SMTPProtocol - implementation of the SMTP protocol
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <Message.h>
|
||||
#include <Alert.h>
|
||||
#include <TextControl.h>
|
||||
#include <Entry.h>
|
||||
#include <Path.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
|
||||
#include <status.h>
|
||||
#include <ProtocolConfigView.h>
|
||||
#include <mail_encoding.h>
|
||||
#include <MailSettings.h>
|
||||
#include <ChainRunner.h>
|
||||
#include <crypt.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "smtp.h"
|
||||
#include "md5.h"
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
#ifdef BONE
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <arpa/inet.h>
|
||||
#else
|
||||
#include <socket.h>
|
||||
#endif
|
||||
|
||||
#define CRLF "\r\n"
|
||||
#define SMTP_RESPONSE_SIZE 8192
|
||||
|
||||
#ifdef DEBUG
|
||||
# define D(x) x
|
||||
# define bug printf
|
||||
#else
|
||||
# define D(x) ;
|
||||
#endif
|
||||
|
||||
|
||||
// Authentication types recognized. Not all methods are implemented.
|
||||
enum AuthType {
|
||||
LOGIN = 1,
|
||||
PLAIN = 1 << 2,
|
||||
CRAM_MD5 = 1 << 3,
|
||||
DIGEST_MD5 = 1 << 4
|
||||
};
|
||||
|
||||
|
||||
SMTPProtocol::SMTPProtocol(BMessage *message, BMailChainRunner *run)
|
||||
: BMailFilter(message),
|
||||
fSettings(message),
|
||||
runner(run),
|
||||
fAuthType(0)
|
||||
{
|
||||
BString error_msg;
|
||||
int32 authMethod = fSettings->FindInt32("auth_method");
|
||||
|
||||
if (authMethod == 2) {
|
||||
// POP3 authentification is handled here instead of SMTPProtocol::Login()
|
||||
// because some servers obviously don't like establishing the connection
|
||||
// to the SMTP server first...
|
||||
fStatus = POP3Authentification();
|
||||
if (fStatus < B_OK) {
|
||||
error_msg << MDR_DIALECT_CHOICE ("POP3 authentification failed. The server said:\n","POP3認証に失敗しました\n") << fLog;
|
||||
runner->ShowError(error_msg.String());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fStatus = Open(fSettings->FindString("server"), fSettings->FindInt32("port"), authMethod == 1);
|
||||
if (fStatus < B_OK) {
|
||||
error_msg << MDR_DIALECT_CHOICE ("Error while opening connection to ","接続中にエラーが発生しました") << fSettings->FindString("server");
|
||||
|
||||
if (fSettings->FindInt32("port") > 0)
|
||||
error_msg << ":" << fSettings->FindInt32("port");
|
||||
|
||||
// << strerror(err) - BNetEndpoint sucks, we can't use this;
|
||||
if (fLog.Length() > 0)
|
||||
error_msg << ". The server says:\n" << fLog;
|
||||
else
|
||||
error_msg << MDR_DIALECT_CHOICE (": Connection refused or host not found.",";接続が拒否されたかサーバーが見つかりません");
|
||||
|
||||
runner->ShowError(error_msg.String());
|
||||
return;
|
||||
}
|
||||
|
||||
const char *password = fSettings->FindString("password");
|
||||
char *passwd = get_passwd(fSettings, "cpasswd");
|
||||
if (passwd)
|
||||
password = passwd;
|
||||
|
||||
fStatus = Login(fSettings->FindString("username"), password);
|
||||
delete passwd;
|
||||
|
||||
if (fStatus < B_OK) {
|
||||
//-----This is a really cool kind of error message. How can we make it work for POP3?
|
||||
error_msg << MDR_DIALECT_CHOICE ("Error while logging in to ","ログイン中にエラーが発生しました\n") << fSettings->FindString("server")
|
||||
<< MDR_DIALECT_CHOICE (". The server said:\n","サーバーエラー\n") << fLog;
|
||||
runner->ShowError(error_msg.String());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SMTPProtocol::~SMTPProtocol()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
// Check for errors?
|
||||
status_t
|
||||
SMTPProtocol::InitCheck(BString *verbose)
|
||||
{
|
||||
if (verbose != NULL && fStatus < B_OK) {
|
||||
*verbose << MDR_DIALECT_CHOICE ("Error while fetching mail from ","受信中にエラーが発生しました") << fSettings->FindString("server")
|
||||
<< ": " << strerror(fStatus);
|
||||
}
|
||||
return fStatus;
|
||||
}
|
||||
|
||||
|
||||
// Process EMail to be sent
|
||||
|
||||
status_t
|
||||
SMTPProtocol::ProcessMailMessage(BPositionIO **io_message, BEntry */*io_entry*/,
|
||||
BMessage *io_headers, BPath */*io_folder*/, const char */*io_uid*/)
|
||||
{
|
||||
const char *from = io_headers->FindString("MAIL:from");
|
||||
const char *to = io_headers->FindString("MAIL:recipients");
|
||||
if (!to)
|
||||
to = io_headers->FindString("MAIL:to");
|
||||
|
||||
if (to == NULL || from == NULL)
|
||||
fLog = "Invalid message headers";
|
||||
|
||||
if (to && from && Send(to, from, *io_message) == B_OK) {
|
||||
runner->ReportProgress(0, 1);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
BString error;
|
||||
MDR_DIALECT_CHOICE (
|
||||
error << "An error occurred while sending the message " << io_headers->FindString("MAIL:subject") << " to " << to << ":\n" << fLog;,
|
||||
error << io_headers->FindString("MAIL:subject") << "を" << to << "\nへ送信中にエラーが発生しました:\n" << fLog;
|
||||
)
|
||||
|
||||
runner->ShowError(error.String());
|
||||
runner->ReportProgress(0, 1);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
// Opens connection to server
|
||||
|
||||
status_t
|
||||
SMTPProtocol::Open(const char *address, int port, bool esmtp)
|
||||
{
|
||||
runner->ReportProgress(0, 0, MDR_DIALECT_CHOICE ("Connecting to server...","接続中..."));
|
||||
|
||||
if (port <= 0)
|
||||
port = 25;
|
||||
|
||||
uint32 hostIP = inet_addr(address); // first see if we can parse it as a numeric address
|
||||
if ((hostIP == 0)||(hostIP == (uint32)-1)) {
|
||||
struct hostent * he = gethostbyname(address);
|
||||
hostIP = he ? *((uint32*)he->h_addr) : 0;
|
||||
}
|
||||
|
||||
if (hostIP == 0)
|
||||
return EHOSTUNREACH;
|
||||
|
||||
_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (_fd >= 0) {
|
||||
struct sockaddr_in saAddr;
|
||||
memset(&saAddr, 0, sizeof(saAddr));
|
||||
saAddr.sin_family = AF_INET;
|
||||
saAddr.sin_port = htons(port);
|
||||
saAddr.sin_addr.s_addr = hostIP;
|
||||
int result = connect(_fd, (struct sockaddr *) &saAddr, sizeof(saAddr));
|
||||
if (result < 0) {
|
||||
#ifdef BONE
|
||||
close(_fd);
|
||||
#else
|
||||
closesocket(_fd);
|
||||
#endif
|
||||
_fd = -1;
|
||||
return errno;
|
||||
}
|
||||
} else {
|
||||
return errno;
|
||||
}
|
||||
|
||||
BString line;
|
||||
ReceiveResponse(line);
|
||||
|
||||
char *cmd = new char[::strlen(address)+8];
|
||||
if (!esmtp)
|
||||
::sprintf(cmd,"HELO %s"CRLF, address);
|
||||
else
|
||||
::sprintf(cmd,"EHLO %s"CRLF, address);
|
||||
|
||||
if (SendCommand(cmd) != B_OK) {
|
||||
delete[] cmd;
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
delete[] cmd;
|
||||
|
||||
// Check auth type
|
||||
if (esmtp) {
|
||||
const char *res = fLog.String();
|
||||
char *p;
|
||||
if ((p = ::strstr(res, "250-AUTH")) != NULL) {
|
||||
if(::strstr(p, "LOGIN"))
|
||||
fAuthType |= LOGIN;
|
||||
if(::strstr(p, "PLAIN"))
|
||||
fAuthType |= PLAIN;
|
||||
if(::strstr(p, "CRAM-MD5"))
|
||||
fAuthType |= CRAM_MD5;
|
||||
if(::strstr(p, "DIGEST-MD5"))
|
||||
fAuthType |= DIGEST_MD5;
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SMTPProtocol::POP3Authentification()
|
||||
{
|
||||
// find the POP3 filter of the other chain - identify by name...
|
||||
BList chains;
|
||||
if (GetInboundMailChains(&chains) < B_OK) {
|
||||
fLog = "Cannot get inbound chains";
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
BMailChainRunner *parent = runner;
|
||||
BMailChain *chain = NULL;
|
||||
for (int i = chains.CountItems(); i-- > 0;)
|
||||
{
|
||||
chain = (BMailChain *)chains.ItemAt(i);
|
||||
if (chain != NULL && !strcmp(chain->Name(), parent->Chain()->Name()))
|
||||
break;
|
||||
chain = NULL;
|
||||
}
|
||||
if (chain != NULL)
|
||||
{
|
||||
// found mail chain! let's check for the POP3 protocol
|
||||
BMessage msg;
|
||||
entry_ref ref;
|
||||
if (chain->GetFilter(0, &msg, &ref) >= B_OK)
|
||||
{
|
||||
BPath path(&ref);
|
||||
if (path.InitCheck() >= B_OK && !strcmp(path.Leaf(), "POP3"))
|
||||
{
|
||||
// protocol matches, go execute it!
|
||||
|
||||
image_id image = load_add_on(path.Path());
|
||||
|
||||
fLog = "Cannot load POP3 add-on";
|
||||
if (image >= B_OK)
|
||||
{
|
||||
BMailFilter *(* instantiate)(BMessage *, BMailChainRunner *);
|
||||
status_t status = get_image_symbol(image, "instantiate_mailfilter",
|
||||
B_SYMBOL_TYPE_TEXT, (void **)&instantiate);
|
||||
if (status >= B_OK)
|
||||
{
|
||||
msg.AddInt32("chain", chain->ID());
|
||||
msg.AddBool("login_and_do_nothing_else_of_any_importance",true);
|
||||
|
||||
// instantiating and deleting should be enough
|
||||
BMailFilter *filter = (*instantiate)(&msg, runner);
|
||||
delete filter;
|
||||
}
|
||||
else
|
||||
fLog = "Cannot run POP3 add-on, symbol not found";
|
||||
|
||||
unload_add_on(image);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
fLog = "Could not get inbound protocol";
|
||||
}
|
||||
else
|
||||
fLog = "Cannot find inbound chain";
|
||||
|
||||
for (int i = chains.CountItems(); i-- > 0;)
|
||||
{
|
||||
chain = (BMailChain *)chains.ItemAt(i);
|
||||
delete chain;
|
||||
}
|
||||
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SMTPProtocol::Login(const char *_login, const char *password)
|
||||
{
|
||||
if (fAuthType == 0)
|
||||
return B_OK;
|
||||
|
||||
const char *login = _login;
|
||||
char hex_digest[33];
|
||||
BString out;
|
||||
|
||||
int32 loginlen = ::strlen(login);
|
||||
int32 passlen = ::strlen(password);
|
||||
|
||||
if (fAuthType & CRAM_MD5) {
|
||||
//******* CRAM-MD5 Authentication ( not tested yet.)
|
||||
SendCommand("AUTH CRAM-MD5"CRLF);
|
||||
const char *res = fLog.String();
|
||||
|
||||
if (strncmp(res, "334", 3) != 0)
|
||||
return B_ERROR;
|
||||
char *base = new char[::strlen(&res[4])+1];
|
||||
int32 baselen = ::strlen(base);
|
||||
baselen = ::decode_base64(base, base, baselen);
|
||||
base[baselen] = '\0';
|
||||
|
||||
D(bug("base: %s\n", base));
|
||||
|
||||
::MD5HexHmac(hex_digest, (const unsigned char *)base, (int)baselen,
|
||||
(const unsigned char *)password, (int)passlen);
|
||||
|
||||
D(bug("%s\n%s\n", base, hex_digest));
|
||||
|
||||
delete[] base;
|
||||
|
||||
BString preResponse, postResponse;
|
||||
preResponse = login;
|
||||
preResponse << " " << hex_digest << CRLF;
|
||||
char *resp = postResponse.LockBuffer(preResponse.Length() * 2 + 10);
|
||||
baselen = ::encode_base64(resp, preResponse.String(), preResponse.Length(), true /* headerMode */);
|
||||
resp[baselen] = 0;
|
||||
postResponse.UnlockBuffer();
|
||||
postResponse.Append(CRLF);
|
||||
|
||||
SendCommand(postResponse.String());
|
||||
|
||||
res = fLog.String();
|
||||
if (atol(res) < 500)
|
||||
return B_OK;
|
||||
}
|
||||
if (fAuthType & DIGEST_MD5) {
|
||||
//******* DIGEST-MD5 Authentication ( not written yet..)
|
||||
fLog = "DIGEST-MD5 Authentication is not supported";
|
||||
}
|
||||
if (fAuthType & LOGIN) {
|
||||
//******* LOGIN Authentication ( tested. works fine)
|
||||
ssize_t encodedsize; // required by our base64 implementation
|
||||
|
||||
SendCommand("AUTH LOGIN"CRLF);
|
||||
const char *res = fLog.String();
|
||||
|
||||
if (strncmp(res, "334", 3) != 0)
|
||||
return B_ERROR;
|
||||
|
||||
// Send login name as base64
|
||||
char *login64 = new char[loginlen*3 + 6];
|
||||
encodedsize = ::encode_base64(login64, (char *)login, loginlen, true /* headerMode */);
|
||||
login64[encodedsize] = 0;
|
||||
strcat (login64, CRLF);
|
||||
SendCommand(login64);
|
||||
delete[] login64;
|
||||
|
||||
res = fLog.String();
|
||||
if (strncmp(res,"334",3) != 0)
|
||||
return B_ERROR;
|
||||
|
||||
// Send password as base64
|
||||
login64 = new char[passlen*3 + 6];
|
||||
encodedsize = ::encode_base64(login64, (char *)password, passlen, true /* headerMode */);
|
||||
login64[encodedsize] = 0;
|
||||
strcat (login64, CRLF);
|
||||
SendCommand(login64);
|
||||
delete[] login64;
|
||||
|
||||
res = fLog.String();
|
||||
if (atol(res) < 500)
|
||||
return B_OK;
|
||||
}
|
||||
if (fAuthType & PLAIN) {
|
||||
//******* PLAIN Authentication ( not tested yet.)
|
||||
BString preResponse, postResponse;
|
||||
char *stringPntr;
|
||||
ssize_t encodedLength;
|
||||
stringPntr = preResponse.LockBuffer(loginlen * 2 + passlen + 3);
|
||||
sprintf (stringPntr, "%s%c%s%c%s", login, 0, login, 0, password);
|
||||
preResponse.UnlockBuffer(loginlen * 2 + passlen + 3);
|
||||
stringPntr = postResponse.LockBuffer(preResponse.Length() * 3);
|
||||
encodedLength = ::encode_base64(stringPntr, preResponse.String(),
|
||||
preResponse.Length(), true /* headerMode */);
|
||||
stringPntr[encodedLength] = 0;
|
||||
postResponse.UnlockBuffer();
|
||||
postResponse.Prepend("AUTH PLAIN ");
|
||||
postResponse << CRLF;
|
||||
|
||||
SendCommand(postResponse.String());
|
||||
|
||||
const char *res = fLog.String();
|
||||
if (atol(res) < 500)
|
||||
return B_OK;
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SMTPProtocol::Close()
|
||||
{
|
||||
|
||||
BString cmd = "QUIT";
|
||||
cmd += CRLF;
|
||||
|
||||
if (SendCommand(cmd.String()) != B_OK) {
|
||||
// Error
|
||||
}
|
||||
#ifdef BONE
|
||||
close(_fd);
|
||||
#else
|
||||
closesocket(_fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/** Send mail */
|
||||
|
||||
status_t
|
||||
SMTPProtocol::Send(const char *to, const char *from, BPositionIO *message)
|
||||
{
|
||||
BString cmd = from;
|
||||
cmd.Remove(0, cmd.FindFirst("\" <") + 2);
|
||||
cmd.Prepend("MAIL FROM: ");
|
||||
cmd += CRLF;
|
||||
if (SendCommand(cmd.String()) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
int32 len = strlen(to);
|
||||
BString addr("");
|
||||
for (int32 i = 0;i < len;i++) {
|
||||
char c = to[i];
|
||||
if (c != ',')
|
||||
addr += (char)c;
|
||||
if (c == ','||i == len-1) {
|
||||
if(addr.Length() == 0)
|
||||
continue;
|
||||
cmd = "RCPT TO: ";
|
||||
cmd << addr.String() << CRLF;
|
||||
if (SendCommand(cmd.String()) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
addr ="";
|
||||
}
|
||||
}
|
||||
|
||||
cmd = "DATA";
|
||||
cmd += CRLF;
|
||||
if (SendCommand(cmd.String()) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
// Send the message data. Convert lines starting with a period to start
|
||||
// with two periods and so on. The actual sequence is CR LF Period. The
|
||||
// SMTP server will remove the periods. Of course, the POP server may then
|
||||
// add some of its own, but the POP client should take care of them.
|
||||
|
||||
ssize_t amountRead;
|
||||
ssize_t amountToRead;
|
||||
ssize_t amountUnread;
|
||||
ssize_t bufferLen = 0;
|
||||
const int bufferMax = 2000;
|
||||
bool foundCRLFPeriod;
|
||||
int i;
|
||||
bool messageEndedWithCRLF = false;
|
||||
|
||||
message->Seek(0, SEEK_END);
|
||||
amountUnread = message->Position();
|
||||
message->Seek(0, SEEK_SET);
|
||||
char *data = new char[bufferMax];
|
||||
|
||||
while (true) {
|
||||
// Fill the buffer if it is getting low, but not every time, to avoid
|
||||
// small reads.
|
||||
if (bufferLen < bufferMax / 2) {
|
||||
amountToRead = bufferMax - bufferLen;
|
||||
if (amountToRead > amountUnread)
|
||||
amountToRead = amountUnread;
|
||||
if (amountToRead > 0) {
|
||||
amountRead = message->Read (data + bufferLen, amountToRead);
|
||||
if (amountRead <= 0 || amountRead > amountToRead)
|
||||
amountUnread = 0; // Just stop reading when an error happens.
|
||||
else {
|
||||
amountUnread -= amountRead;
|
||||
bufferLen += amountRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for the next CRLFPeriod triple.
|
||||
foundCRLFPeriod = false;
|
||||
for (i = 0; i <= bufferLen - 3; i++) {
|
||||
if (data[i] == '\r' && data[i+1] == '\n' && data[i+2] == '.') {
|
||||
foundCRLFPeriod = true;
|
||||
// Send data up to the CRLF, and include the period too.
|
||||
if (send (_fd,data, i + 3,0) < 0) {
|
||||
amountUnread = 0; // Stop when an error happens.
|
||||
bufferLen = 0;
|
||||
break;
|
||||
}
|
||||
runner->ReportProgress (i + 2 /* Don't include the double period here */,0);
|
||||
// Move the data over in the buffer, but leave the period there
|
||||
// so it gets sent a second time.
|
||||
memmove(data, data + (i + 2), bufferLen - (i + 2));
|
||||
bufferLen -= i + 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundCRLFPeriod) {
|
||||
if (amountUnread <= 0) { // No more data, all we have is in the buffer.
|
||||
if (bufferLen > 0) {
|
||||
send (_fd,data, bufferLen,0);
|
||||
runner->ReportProgress (bufferLen,0);
|
||||
if (bufferLen >= 2)
|
||||
messageEndedWithCRLF = (data[bufferLen-2] == '\r' &&
|
||||
data[bufferLen-1] == '\n');
|
||||
}
|
||||
break; // Finished!
|
||||
}
|
||||
|
||||
// Send most of the buffer, except a few characters to overlap with
|
||||
// the next read, in case the CRLFPeriod is split between reads.
|
||||
if (bufferLen > 3) {
|
||||
if (send (_fd,data, bufferLen - 3,0) < 0)
|
||||
break; // Stop when an error happens.
|
||||
runner->ReportProgress (bufferLen - 3,0);
|
||||
memmove (data, data + bufferLen - 3, 3);
|
||||
bufferLen = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete [] data;
|
||||
|
||||
if (messageEndedWithCRLF)
|
||||
cmd = "."CRLF; // The standard says don't add extra CRLF.
|
||||
else
|
||||
cmd = CRLF"."CRLF;
|
||||
|
||||
if (SendCommand(cmd.String()) != B_OK)
|
||||
return B_ERROR;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// Receives response from server.
|
||||
|
||||
int32
|
||||
SMTPProtocol::ReceiveResponse(BString &out)
|
||||
{
|
||||
out = "";
|
||||
int32 len = 0,r;
|
||||
char buf[SMTP_RESPONSE_SIZE];
|
||||
bigtime_t timeout = 1000000*180; // timeout 180 secs
|
||||
|
||||
struct timeval tv;
|
||||
struct fd_set fds;
|
||||
|
||||
tv.tv_sec = long(timeout / 1e6);
|
||||
tv.tv_usec = long(timeout-(tv.tv_sec * 1e6));
|
||||
|
||||
/* Initialize (clear) the socket mask. */
|
||||
FD_ZERO(&fds);
|
||||
|
||||
/* Set the socket in the mask. */
|
||||
FD_SET(_fd, &fds);
|
||||
int result = select(32, &fds, NULL, NULL, &tv);
|
||||
if (result < 0)
|
||||
return errno;
|
||||
|
||||
if (result > 0) {
|
||||
while (1) {
|
||||
r = recv(_fd,buf, SMTP_RESPONSE_SIZE - 1,0);
|
||||
if (r <= 0)
|
||||
break;
|
||||
|
||||
len += r;
|
||||
out.Append(buf, r);
|
||||
if (strstr(buf, CRLF))
|
||||
break;
|
||||
}
|
||||
} else
|
||||
fLog = "SMTP socket timeout.";
|
||||
|
||||
D(bug("S:%s\n", out.String()));
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
// Sends SMTP command. Result kept in fLog
|
||||
|
||||
status_t
|
||||
SMTPProtocol::SendCommand(const char *cmd)
|
||||
{
|
||||
D(bug("C:%s\n", cmd));
|
||||
|
||||
if (send(_fd,cmd, ::strlen(cmd),0) == B_ERROR)
|
||||
return B_ERROR;
|
||||
|
||||
fLog = "";
|
||||
|
||||
// Receive
|
||||
while (1) {
|
||||
int32 len = ReceiveResponse(fLog);
|
||||
|
||||
if (len <= 0) {
|
||||
D(bug("SMTP: len == %ld\n", len));
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
if (fLog.Length() > 4 && (fLog[3] == ' ' || fLog[3] == '-'))
|
||||
{
|
||||
int32 num = atol(fLog.String());
|
||||
D(bug("ReplyNumber: %ld\n", num));
|
||||
|
||||
if (num >= 500)
|
||||
return B_ERROR;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// Instantiate hook
|
||||
BMailFilter *
|
||||
instantiate_mailfilter(BMessage *settings, BMailChainRunner *status)
|
||||
{
|
||||
return new SMTPProtocol(settings, status);
|
||||
}
|
||||
|
||||
|
||||
// Configuration interface
|
||||
BView *
|
||||
instantiate_config_panel(BMessage *settings, BMessage *)
|
||||
{
|
||||
BMailProtocolConfigView *view = new BMailProtocolConfigView(B_MAIL_PROTOCOL_HAS_AUTH_METHODS | B_MAIL_PROTOCOL_HAS_USERNAME | B_MAIL_PROTOCOL_HAS_PASSWORD | B_MAIL_PROTOCOL_HAS_HOSTNAME);
|
||||
|
||||
view->AddAuthMethod(MDR_DIALECT_CHOICE ("None","無し"), false);
|
||||
view->AddAuthMethod(MDR_DIALECT_CHOICE ("ESMTP","ESMTP"));
|
||||
view->AddAuthMethod(MDR_DIALECT_CHOICE ("POP3 before SMTP","送信前に受信する"), false);
|
||||
|
||||
BTextControl *control = (BTextControl *)(view->FindView("host"));
|
||||
control->SetLabel(MDR_DIALECT_CHOICE ("SMTP Host: ","SMTPサーバ: "));
|
||||
//control->SetDivider(be_plain_font->StringWidth("SMTP Host: "));
|
||||
|
||||
view->SetTo(settings);
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#ifndef ZOIDBERG_SMTP_H
|
||||
#define ZOIDBERG_SMTP_H
|
||||
/* SMTPProtocol - implementation of the SMTP protocol
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include <MailAddon.h>
|
||||
|
||||
|
||||
class SMTPProtocol : public BMailFilter {
|
||||
public:
|
||||
SMTPProtocol(BMessage *message, BMailChainRunner *runner);
|
||||
~SMTPProtocol();
|
||||
|
||||
virtual status_t InitCheck(BString *verbose);
|
||||
virtual status_t ProcessMailMessage(BPositionIO **io_message, BEntry *io_entry,
|
||||
BMessage *io_headers, BPath *io_folder, const char *io_uid);
|
||||
|
||||
//----Perfectly good holdovers from the old days
|
||||
status_t Open(const char *server, int port, bool esmtp);
|
||||
status_t Login(const char *uid, const char *password);
|
||||
void Close();
|
||||
status_t Send(const char *to, const char *from, BPositionIO *message);
|
||||
|
||||
int32 ReceiveResponse(BString &line);
|
||||
status_t SendCommand(const char *cmd);
|
||||
|
||||
private:
|
||||
status_t POP3Authentification();
|
||||
|
||||
int _fd;
|
||||
BString fLog;
|
||||
BMessage *fSettings;
|
||||
BMailChainRunner *runner;
|
||||
int32 fAuthType;
|
||||
|
||||
status_t fStatus;
|
||||
};
|
||||
|
||||
#endif /* ZOIDBERG_SMTP_H */
|
||||
@@ -0,0 +1,10 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon system_filters inbox ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
Addon Inbox : mail_daemon inbound_filters :
|
||||
filter.cpp ;
|
||||
|
||||
LinkSharedOSLibs Inbox :
|
||||
be mail ;
|
||||
@@ -0,0 +1,410 @@
|
||||
/* Inbox - places the incoming mail to their destination folder
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <FileConfigView.h>
|
||||
|
||||
#include <Directory.h>
|
||||
#include <String.h>
|
||||
#include <Entry.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <E-mail.h>
|
||||
#include <Path.h>
|
||||
#include <Roster.h>
|
||||
#include <CheckBox.h>
|
||||
#include <TextControl.h>
|
||||
#include <StringView.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <parsedate.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <MailAddon.h>
|
||||
#include <MailSettings.h>
|
||||
#include <NodeMessage.h>
|
||||
#include <ChainRunner.h>
|
||||
#include <status.h>
|
||||
#include <mail_util.h>
|
||||
|
||||
#include <MDRLanguage.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 },
|
||||
{ "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 }
|
||||
};
|
||||
|
||||
|
||||
class FolderFilter : public BMailFilter
|
||||
{
|
||||
BString dest_string;
|
||||
BDirectory destination;
|
||||
int32 chain_id;
|
||||
BMailChainRunner *runner;
|
||||
int fNumberOfFilesSaved;
|
||||
int size_limit; // Messages larger than this many bytes get partially downloaded. -1 for always do full download.
|
||||
|
||||
public:
|
||||
FolderFilter(BMessage*,BMailChainRunner *);
|
||||
virtual ~FolderFilter();
|
||||
virtual status_t InitCheck(BString *err);
|
||||
virtual status_t ProcessMailMessage
|
||||
(
|
||||
BPositionIO** io_message, BEntry* io_entry,
|
||||
BMessage* io_headers, BPath* io_folder, const char* io_uid
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
FolderFilter::FolderFilter(BMessage* msg,BMailChainRunner *therunner)
|
||||
: BMailFilter(msg),
|
||||
runner(therunner), chain_id(msg->FindInt32("chain")), size_limit(-1)
|
||||
{
|
||||
fNumberOfFilesSaved = 0;
|
||||
dest_string = runner->Chain()->MetaData()->FindString("path");
|
||||
create_directory(dest_string.String(),0777);
|
||||
destination = dest_string.String();
|
||||
|
||||
if (msg->FindInt32("size_limit",(long *)&size_limit) != B_OK)
|
||||
size_limit = -1;
|
||||
}
|
||||
|
||||
|
||||
FolderFilter::~FolderFilter ()
|
||||
{
|
||||
// Save the disk cache to the actual disk so mail data won't get lost if a
|
||||
// crash happens soon after mail has been received or sent. Mostly put
|
||||
// here because of unexpected mail daemon activity during debugging of
|
||||
// kernel crashing software.
|
||||
|
||||
if (fNumberOfFilesSaved > 0)
|
||||
sync ();
|
||||
}
|
||||
|
||||
|
||||
status_t FolderFilter::InitCheck(BString* err)
|
||||
{
|
||||
|
||||
status_t ret = destination.InitCheck();
|
||||
|
||||
if (ret==B_OK) return B_OK;
|
||||
else
|
||||
{
|
||||
if (err) *err
|
||||
<< "FolderFilter failed: destination '" << dest_string
|
||||
<< "' not found (" << strerror(ret) << ").";
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
status_t FolderFilter::ProcessMailMessage(BPositionIO**io, BEntry* e, BMessage* out_headers, BPath*loc, const char* io_uid)
|
||||
{
|
||||
time_t dateAsTime;
|
||||
const time_t *datePntr;
|
||||
ssize_t dateSize;
|
||||
char numericDateString [40];
|
||||
bool tempBool;
|
||||
struct tm timeFields;
|
||||
BString worker;
|
||||
|
||||
BDirectory dir;
|
||||
|
||||
BPath path = dest_string.String();
|
||||
if (out_headers->HasString("DESTINATION")) {
|
||||
const char *string;
|
||||
out_headers->FindString("DESTINATION",&string);
|
||||
if (string[0] == '/')
|
||||
path = string;
|
||||
else
|
||||
path.Append(string);
|
||||
} else if (loc != NULL && loc->Path() != NULL && strcmp(loc->Path(),"") != 0) // --- Don't append folder names to overridden paths
|
||||
path.Append(loc->Path());
|
||||
|
||||
create_directory(path.Path(),0777);
|
||||
dir.SetTo(path.Path());
|
||||
|
||||
BNode node(e);
|
||||
status_t err = 0;
|
||||
bool haveReadWholeMessage = false;
|
||||
// "ENTIRE_MESSAGE" really means the user has double clicked on a partial
|
||||
// message and now it should be fully read, and then displayed to the user.
|
||||
if ((out_headers->FindBool("ENTIRE_MESSAGE", &tempBool) == B_OK && tempBool)
|
||||
|| !out_headers->HasInt32("SIZE")
|
||||
|| (size_limit < 0 || size_limit >= out_headers->FindInt32("SIZE"))) {
|
||||
err = (*io)->Seek(0,SEEK_END); // Force protocol to read the whole message.
|
||||
if (err < 0)
|
||||
{
|
||||
BString error;
|
||||
MDR_DIALECT_CHOICE (
|
||||
error << "Unable to read whole message from server, ignoring it. "
|
||||
<< "Subject \"" << out_headers->FindString("Subject")
|
||||
<< "\", save to dir \"" << path.Path() <<
|
||||
"\", error code: " << err << " " << strerror(err);
|
||||
,
|
||||
error << out_headers->FindString("Subject") << " のメッセージを " <<
|
||||
path.Path() << "に保存中にエラーが発生しました" << strerror(err);
|
||||
)
|
||||
runner->ShowError(error.String());
|
||||
return B_MAIL_END_FETCH; // Stop reading further mail messages.
|
||||
}
|
||||
haveReadWholeMessage = true;
|
||||
}
|
||||
|
||||
BNodeInfo info(&node);
|
||||
node.Sync();
|
||||
off_t size;
|
||||
node.GetSize(&size);
|
||||
// Note - sometimes the actual message size is a few bytes more than the
|
||||
// registered size, so use >= when testing. And sometimes the message is
|
||||
// actually slightly smaller, due to POP server errors (some count double
|
||||
// dots correctly, some don't, if it causes problems, you'll get a partial
|
||||
// message and waste time downloading it twice).
|
||||
if (haveReadWholeMessage ||
|
||||
(out_headers->HasInt32("SIZE") && size >= out_headers->FindInt32("SIZE"))) {
|
||||
info.SetType(B_MAIL_TYPE);
|
||||
// A little fixup for incorrect registered sizes, so that the full
|
||||
// length attribute gets written correctly later.
|
||||
if (out_headers->HasInt32("SIZE"))
|
||||
out_headers->ReplaceInt32("SIZE", size);
|
||||
haveReadWholeMessage = true;
|
||||
} else // Don't have the whole message.
|
||||
info.SetType("text/x-partial-email");
|
||||
|
||||
BMessage attributes;
|
||||
|
||||
attributes.AddString("MAIL:unique_id",io_uid);
|
||||
attributes.AddString("MAIL:account",BMailChain(chain_id).Name());
|
||||
attributes.AddInt32("MAIL:chain",chain_id);
|
||||
|
||||
size_t length = (*io)->Position();
|
||||
length -= out_headers->FindInt32(B_MAIL_ATTR_HEADER);
|
||||
if (attributes.ReplaceInt32(B_MAIL_ATTR_CONTENT,length) != B_OK)
|
||||
attributes.AddInt32(B_MAIL_ATTR_CONTENT,length);
|
||||
|
||||
const char *buf;
|
||||
time_t when;
|
||||
for (int i = 0; gDefaultFields[i].rfc_name; ++i)
|
||||
{
|
||||
out_headers->FindString(gDefaultFields[i].rfc_name,&buf);
|
||||
if (buf == NULL)
|
||||
continue;
|
||||
|
||||
switch (gDefaultFields[i].attr_type){
|
||||
case B_STRING_TYPE:
|
||||
attributes.AddString(gDefaultFields[i].attr_name, buf);
|
||||
break;
|
||||
|
||||
case B_TIME_TYPE:
|
||||
when = ParseDateWithTimeZone (buf);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_headers->HasInt32("SIZE")) {
|
||||
size_t size = out_headers->FindInt32("SIZE");
|
||||
attributes.AddData("MAIL:fullsize",B_SIZE_T_TYPE,&size,sizeof(size_t));
|
||||
}
|
||||
|
||||
// add "New" status, if the status hasn't been set already
|
||||
if (attributes.FindString(B_MAIL_ATTR_STATUS,&buf) < B_OK)
|
||||
attributes.AddString(B_MAIL_ATTR_STATUS,"New");
|
||||
|
||||
node << attributes;
|
||||
|
||||
// Move the message file out of the temporary directory, else it gets
|
||||
// deleted. Partial messages have already been moved, so don't move them.
|
||||
if (out_headers->FindBool("ENTIRE_MESSAGE", &tempBool) != B_OK
|
||||
|| tempBool == false) {
|
||||
err = B_OK;
|
||||
if (!dir.Contains(e))
|
||||
err = e->MoveTo(&dir);
|
||||
if (err != B_OK)
|
||||
{
|
||||
BString error;
|
||||
MDR_DIALECT_CHOICE (
|
||||
error << "An error occurred while moving the message " <<
|
||||
out_headers->FindString("Subject") << " to " << path.Path() <<
|
||||
": " << strerror(err);
|
||||
,
|
||||
error << out_headers->FindString("Subject") << " のメッセージを " <<
|
||||
path.Path() << "に保存中にエラーが発生しました" << strerror(err);
|
||||
)
|
||||
runner->ShowError(error.String());
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
dateAsTime = 0;
|
||||
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;
|
||||
|
||||
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 */);
|
||||
|
||||
int32 uniquer = time(NULL);
|
||||
worker = name;
|
||||
int32 tries = 20;
|
||||
while ((err = e->Rename(worker.String())) == B_FILE_EXISTS && --tries > 0) {
|
||||
srand(rand());
|
||||
uniquer += (rand() >> 16) - 16384;
|
||||
|
||||
worker = name;
|
||||
worker << ' ' << uniquer;
|
||||
}
|
||||
if (err < B_OK)
|
||||
printf("FolderFilter::ProcessMailMessage: could not rename mail (%s)! "
|
||||
"(should be: %s)\n",strerror(err),worker.String());
|
||||
|
||||
fNumberOfFilesSaved++;
|
||||
if (out_headers->FindBool("ENTIRE_MESSAGE")) {
|
||||
entry_ref ref;
|
||||
e->GetRef(&ref);
|
||||
be_roster->Launch(&ref);
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
BMailFilter* instantiate_mailfilter(BMessage* settings, BMailChainRunner *run)
|
||||
{
|
||||
return new FolderFilter(settings,run);
|
||||
}
|
||||
|
||||
class FolderConfig : public BView {
|
||||
public:
|
||||
FolderConfig(BMessage *settings, BMessage *meta_data) : BView(BRect(0,0,50,50),"folder_config",B_FOLLOW_ALL_SIDES,0) {
|
||||
|
||||
const char *partial_text = MDR_DIALECT_CHOICE (
|
||||
"Partially download messages larger than",
|
||||
"部分ダウンロードする");
|
||||
|
||||
view = new BMailFileConfigView(
|
||||
MDR_DIALECT_CHOICE ("Destination Folder:","受信箱:"),
|
||||
"path",true,"/boot/home/mail/in");
|
||||
view->SetTo(settings,meta_data);
|
||||
view->ResizeToPreferred();
|
||||
|
||||
partial_box = new BCheckBox(BRect(view->Frame().left, view->Frame().bottom + 5,
|
||||
view->Frame().left + 18 + be_plain_font->StringWidth(partial_text),
|
||||
view->Frame().bottom + 25), "size_if", partial_text, new BMessage('SIZF'));
|
||||
size = new BTextControl(BRect(
|
||||
view->Frame().left + 20 + be_plain_font->StringWidth(partial_text),
|
||||
view->Frame().bottom + 5,
|
||||
view->Frame().left + 42 + be_plain_font->StringWidth(partial_text),
|
||||
view->Frame().bottom + 25), "size", "", "", NULL);
|
||||
AddChild(new BStringView(BRect(
|
||||
view->Frame().left + 42 + be_plain_font->StringWidth(partial_text),
|
||||
view->Frame().bottom + 5, view->Frame().right,view->Frame().bottom+21),
|
||||
"kb", "KB"));
|
||||
size->SetDivider(0);
|
||||
if (settings->HasInt32("size_limit")) {
|
||||
BString kb;
|
||||
kb << int32(settings->FindInt32("size_limit")/1024);
|
||||
size->SetText(kb.String());
|
||||
partial_box->SetValue(B_CONTROL_ON);
|
||||
} else
|
||||
size->SetEnabled(false);
|
||||
AddChild(view);
|
||||
SetViewColor(216,216,216);
|
||||
AddChild(partial_box);
|
||||
AddChild(size);
|
||||
ResizeToPreferred();
|
||||
}
|
||||
void MessageReceived(BMessage *msg) {
|
||||
if (msg->what != 'SIZF')
|
||||
return BView::MessageReceived(msg);
|
||||
size->SetEnabled(partial_box->Value());
|
||||
}
|
||||
void AttachedToWindow() {
|
||||
partial_box->SetTarget(this);
|
||||
}
|
||||
void GetPreferredSize(float *width, float *height) {
|
||||
view->GetPreferredSize(width,height);
|
||||
*height += 25;
|
||||
*width += 10;
|
||||
}
|
||||
status_t Archive(BMessage *into, bool) const {
|
||||
into->MakeEmpty();
|
||||
view->Archive(into);
|
||||
if (partial_box->Value())
|
||||
into->AddInt32("size_limit",atoi(size->Text()) * 1024);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
BMailFileConfigView *view;
|
||||
BTextControl *size;
|
||||
BCheckBox *partial_box;
|
||||
};
|
||||
|
||||
BView* instantiate_config_panel(BMessage *settings, BMessage *meta_data)
|
||||
{
|
||||
|
||||
return new FolderConfig(settings,meta_data);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/* ConfigView - the configuration view for the Notifier filter
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include "ConfigView.h"
|
||||
|
||||
#include <CheckBox.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <MenuItem.h>
|
||||
#include <MenuField.h>
|
||||
#include <String.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
#include <MailAddon.h>
|
||||
|
||||
const uint32 kMsgNotifyMethod = 'nomt';
|
||||
|
||||
|
||||
ConfigView::ConfigView()
|
||||
: BView(BRect(0,0,10,10),"notifier_config",B_FOLLOW_LEFT | B_FOLLOW_TOP,0)
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
// determine font height
|
||||
font_height fontHeight;
|
||||
GetFontHeight(&fontHeight);
|
||||
float itemHeight = (int32)(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 6;
|
||||
|
||||
BRect frame(5,2,250,itemHeight + 2);
|
||||
BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING,false,false);
|
||||
|
||||
const char *notifyMethods[] = {
|
||||
MDR_DIALECT_CHOICE ("Beep","音"),
|
||||
MDR_DIALECT_CHOICE ("Alert","窓(メール毎)"),
|
||||
MDR_DIALECT_CHOICE ("Keyboard LEDs","キーボードLED"),
|
||||
MDR_DIALECT_CHOICE ("Central Alert","窓(一括)"),
|
||||
"Central Beep","Log Window"};
|
||||
for (int32 i = 0,j = 1;i < 6;i++,j *= 2)
|
||||
menu->AddItem(new BMenuItem(notifyMethods[i],new BMessage(kMsgNotifyMethod)));
|
||||
|
||||
BMenuField *field = new BMenuField(frame,"notify",
|
||||
MDR_DIALECT_CHOICE ("Method:","方法:"),menu);
|
||||
field->ResizeToPreferred();
|
||||
field->SetDivider(field->StringWidth(
|
||||
MDR_DIALECT_CHOICE ("Method:","方法:")) + 6);
|
||||
AddChild(field);
|
||||
|
||||
ResizeToPreferred();
|
||||
}
|
||||
|
||||
|
||||
void ConfigView::AttachedToWindow()
|
||||
{
|
||||
if (BMenuField *field = dynamic_cast<BMenuField *>(FindView("notify")))
|
||||
field->Menu()->SetTargetForItems(this);
|
||||
}
|
||||
|
||||
|
||||
void ConfigView::SetTo(BMessage *archive)
|
||||
{
|
||||
int32 method = archive->FindInt32("notification_method");
|
||||
if (method < 0)
|
||||
method = 1;
|
||||
|
||||
BMenuField *field;
|
||||
if ((field = dynamic_cast<BMenuField *>(FindView("notify"))) == NULL)
|
||||
return;
|
||||
|
||||
for (int32 i = field->Menu()->CountItems();i-- > 0;)
|
||||
{
|
||||
BMenuItem *item = field->Menu()->ItemAt(i);
|
||||
item->SetMarked((method & (1L << i)) != 0);
|
||||
}
|
||||
UpdateNotifyText();
|
||||
}
|
||||
|
||||
|
||||
void ConfigView::UpdateNotifyText()
|
||||
{
|
||||
BMenuField *field;
|
||||
if ((field = dynamic_cast<BMenuField *>(FindView("notify"))) == NULL)
|
||||
return;
|
||||
|
||||
BString label;
|
||||
for (int32 i = field->Menu()->CountItems();i-- > 0;)
|
||||
{
|
||||
BMenuItem *item = field->Menu()->ItemAt(i);
|
||||
if (!item->IsMarked())
|
||||
continue;
|
||||
|
||||
if (label != "")
|
||||
label.Prepend(" + ");
|
||||
label.Prepend(item->Label());
|
||||
}
|
||||
if (label == "")
|
||||
label = "none";
|
||||
field->MenuItem()->SetLabel(label.String());
|
||||
}
|
||||
|
||||
|
||||
void ConfigView::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what)
|
||||
{
|
||||
case kMsgNotifyMethod:
|
||||
{
|
||||
msg->PrintToStream();
|
||||
BMenuItem *item;
|
||||
if (msg->FindPointer("source",(void **)&item) < B_OK)
|
||||
break;
|
||||
|
||||
item->SetMarked(!item->IsMarked());
|
||||
UpdateNotifyText();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t ConfigView::Archive(BMessage *into,bool) const
|
||||
{
|
||||
int32 method = 0;
|
||||
|
||||
BMenuField *field;
|
||||
if ((field = dynamic_cast<BMenuField *>(FindView("notify"))) != NULL)
|
||||
{
|
||||
for (int32 i = field->Menu()->CountItems();i-- > 0;)
|
||||
{
|
||||
BMenuItem *item = field->Menu()->ItemAt(i);
|
||||
if (item->IsMarked())
|
||||
method |= 1L << i;
|
||||
}
|
||||
}
|
||||
|
||||
if (into->ReplaceInt32("notification_method",method) != B_OK)
|
||||
into->AddInt32("notification_method",method);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
void ConfigView::GetPreferredSize(float *width, float *height)
|
||||
{
|
||||
*width = 258;
|
||||
*height = ChildAt(0)->Bounds().Height() + 8;
|
||||
}
|
||||
|
||||
BView* instantiate_config_panel(BMessage *settings,BMessage *)
|
||||
{
|
||||
ConfigView *view = new ConfigView();
|
||||
view->SetTo(settings);
|
||||
|
||||
return view;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef CONFIG_VIEW
|
||||
#define CONFIG_VIEW
|
||||
/* ConfigView - the configuration view for the Notifier filter
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <View.h>
|
||||
|
||||
enum {
|
||||
do_beep = 1,
|
||||
alert = 2,
|
||||
blink_leds = 4,
|
||||
big_doozy_alert = 8,
|
||||
one_central_beep = 16,
|
||||
log_window = 32
|
||||
};
|
||||
|
||||
class ConfigView : public BView
|
||||
{
|
||||
public:
|
||||
ConfigView();
|
||||
void SetTo(BMessage *archive);
|
||||
virtual status_t Archive(BMessage *into, bool deep = true) const;
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
|
||||
void UpdateNotifyText();
|
||||
};
|
||||
|
||||
#endif /* CONFIG_VIEW */
|
||||
@@ -0,0 +1,10 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon system_filters notifier ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
Addon New\ Mail\ Notification : mail_daemon inbound_filters :
|
||||
filter.cpp ConfigView.cpp ;
|
||||
|
||||
LinkSharedOSLibs New\ Mail\ Notification :
|
||||
be mail ;
|
||||
@@ -0,0 +1,134 @@
|
||||
/* New Mail Notification - notifies incoming e-mail
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Message.h>
|
||||
#include <String.h>
|
||||
#include <Alert.h>
|
||||
#include <Beep.h>
|
||||
#include <Application.h>
|
||||
|
||||
#include <MailAddon.h>
|
||||
#include <ChainRunner.h>
|
||||
#include <status.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
#include "ConfigView.h"
|
||||
|
||||
class NotifyFilter;
|
||||
|
||||
class NotifyCallback : public BMailChainCallback {
|
||||
public:
|
||||
NotifyCallback (int32 notification_method, BMailChainRunner *us,NotifyFilter *ref2);
|
||||
virtual void Callback(status_t result);
|
||||
|
||||
uint32 num_messages;
|
||||
private:
|
||||
BMailChainRunner *chainrunner;
|
||||
int32 strategy;
|
||||
NotifyFilter *parent;
|
||||
};
|
||||
|
||||
class NotifyFilter : public BMailFilter
|
||||
{
|
||||
public:
|
||||
NotifyFilter(BMessage*,BMailChainRunner*);
|
||||
virtual status_t InitCheck(BString *err);
|
||||
virtual status_t ProcessMailMessage
|
||||
(
|
||||
BPositionIO** io_message, BEntry* io_entry,
|
||||
BMessage* io_headers, BPath* io_folder, const char* io_uid
|
||||
);
|
||||
|
||||
private:
|
||||
friend class NotifyCallback;
|
||||
|
||||
NotifyCallback *callback;
|
||||
BMailChainRunner *_runner;
|
||||
int32 strategy;
|
||||
};
|
||||
|
||||
|
||||
NotifyFilter::NotifyFilter(BMessage* msg,BMailChainRunner *runner)
|
||||
: BMailFilter(msg), _runner(runner), callback(NULL)
|
||||
{
|
||||
strategy = msg->FindInt32("notification_method");
|
||||
}
|
||||
|
||||
status_t NotifyFilter::InitCheck(BString* err)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t NotifyFilter::ProcessMailMessage(BPositionIO**, BEntry*, BMessage*headers, BPath*, const char*)
|
||||
{
|
||||
if (callback == NULL) {
|
||||
callback = new NotifyCallback(strategy,_runner,this);
|
||||
_runner->RegisterProcessCallback(callback);
|
||||
}
|
||||
|
||||
if (!headers->FindBool("ENTIRE_MESSAGE"))
|
||||
callback->num_messages ++;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
NotifyCallback::NotifyCallback (int32 notification_method, BMailChainRunner *us,NotifyFilter *ref2) :
|
||||
strategy(notification_method),
|
||||
chainrunner(us),
|
||||
num_messages(0), parent(ref2)
|
||||
{
|
||||
}
|
||||
|
||||
void NotifyCallback::Callback(status_t result) {
|
||||
parent->callback = NULL;
|
||||
|
||||
if (num_messages == 0)
|
||||
return;
|
||||
|
||||
if (strategy & do_beep)
|
||||
system_beep("New E-mail");
|
||||
|
||||
if (strategy & alert) {
|
||||
BString text;
|
||||
MDR_DIALECT_CHOICE (
|
||||
text << "You have " << num_messages << " new message" << ((num_messages != 1) ? "s" : "")
|
||||
<< " for " << chainrunner->Chain()->Name() << ".",
|
||||
|
||||
text << chainrunner->Chain()->Name() << "より\n" << num_messages << " 通のメッセージが届きました");
|
||||
|
||||
BAlert *alert = new BAlert(MDR_DIALECT_CHOICE ("New Messages","新着メッセージ"), text.String(), "OK", NULL, NULL, B_WIDTH_AS_USUAL);
|
||||
alert->SetFeel(B_NORMAL_WINDOW_FEEL);
|
||||
alert->Go(NULL);
|
||||
}
|
||||
|
||||
if (strategy & blink_leds)
|
||||
be_app->PostMessage('mblk');
|
||||
|
||||
if (strategy & one_central_beep)
|
||||
be_app->PostMessage('mcbp');
|
||||
|
||||
if (strategy & big_doozy_alert) {
|
||||
BMessage msg('numg');
|
||||
msg.AddInt32("num_messages",num_messages);
|
||||
msg.AddString("chain_name",chainrunner->Chain()->Name());
|
||||
msg.AddInt32("chain_id",chainrunner->Chain()->ID());
|
||||
|
||||
be_app->PostMessage(&msg);
|
||||
}
|
||||
|
||||
if (strategy & log_window) {
|
||||
BString message;
|
||||
message << num_messages << " new message" << ((num_messages != 1) ? "s" : "");
|
||||
chainrunner->ShowMessage(message.String());
|
||||
}
|
||||
}
|
||||
|
||||
BMailFilter* instantiate_mailfilter(BMessage* settings, BMailChainRunner *runner)
|
||||
{
|
||||
return new NotifyFilter(settings,runner);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon system_filters outbox ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
Addon Outbox : mail_daemon inbound_filters :
|
||||
filter.cpp ;
|
||||
|
||||
LinkSharedOSLibs Outbox :
|
||||
be mail ;
|
||||
@@ -0,0 +1,108 @@
|
||||
/* Outbox - scans outgoing mail in a specific folder
|
||||
**
|
||||
** Copyright 2001 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Directory.h>
|
||||
#include <String.h>
|
||||
#include <Entry.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Path.h>
|
||||
#include <E-mail.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <MailAddon.h>
|
||||
#include <NodeMessage.h>
|
||||
#include <ChainRunner.h>
|
||||
#include <status.h>
|
||||
#include <FileConfigView.h>
|
||||
#include <StringList.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
class StatusChanger : public BMailChainCallback {
|
||||
public:
|
||||
StatusChanger(const char * entry);
|
||||
void Callback(status_t result);
|
||||
|
||||
private:
|
||||
const char * to_change;
|
||||
};
|
||||
|
||||
class DiskProducer : public BMailFilter
|
||||
{
|
||||
BMailChainRunner *runner;
|
||||
status_t init;
|
||||
|
||||
public:
|
||||
DiskProducer(BMessage*,BMailChainRunner*);
|
||||
virtual status_t InitCheck(BString *err);
|
||||
virtual status_t ProcessMailMessage
|
||||
(
|
||||
BPositionIO** io_message, BEntry* io_entry,
|
||||
BMessage* io_headers, BPath* io_folder, const char* io_uid
|
||||
);
|
||||
};
|
||||
|
||||
DiskProducer::DiskProducer(BMessage* msg,BMailChainRunner*status)
|
||||
: BMailFilter(msg), runner(status), init(B_OK)
|
||||
{}
|
||||
|
||||
status_t DiskProducer::InitCheck(BString* err)
|
||||
{
|
||||
if (init != B_OK)
|
||||
return init;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t DiskProducer::ProcessMailMessage(BPositionIO**io, BEntry* e, BMessage* out_headers, BPath*, const char* io_uid)
|
||||
{
|
||||
e->Remove();
|
||||
|
||||
BFile *file = new BFile(io_uid,B_READ_WRITE);
|
||||
|
||||
e->SetTo(io_uid);
|
||||
*file >> *out_headers;
|
||||
*io = file;
|
||||
|
||||
runner->RegisterMessageCallback(new StatusChanger(io_uid));
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
StatusChanger::StatusChanger(const char * entry)
|
||||
: to_change(entry)
|
||||
{
|
||||
}
|
||||
|
||||
void StatusChanger::Callback(status_t result) {
|
||||
BNode node(to_change);
|
||||
|
||||
if (result == B_OK) {
|
||||
mail_flags flags = B_MAIL_SENT;
|
||||
|
||||
node.WriteAttr(B_MAIL_ATTR_FLAGS,B_INT32_TYPE,0,&flags,4);
|
||||
node.WriteAttr(B_MAIL_ATTR_STATUS,B_STRING_TYPE,0,"Sent",5);
|
||||
} else {
|
||||
node.WriteAttr(B_MAIL_ATTR_STATUS,B_STRING_TYPE,0,"Error",6);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BMailFilter* instantiate_mailfilter(BMessage* settings, BMailChainRunner *runner)
|
||||
{
|
||||
return new DiskProducer(settings,runner);
|
||||
}
|
||||
|
||||
|
||||
BView* instantiate_config_panel(BMessage *settings,BMessage *metadata)
|
||||
{
|
||||
BMailFileConfigView *view = new BMailFileConfigView(MDR_DIALECT_CHOICE ("Source Folder:","送信箱:"),"path",true,"/boot/home/mail/out");
|
||||
view->SetTo(settings,metadata);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
SubDir OBOS_TOP src add-ons mail_daemon system_filters parser ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
SubDirHdrs [ FDirName $(OBOS_TOP) headers os add-ons mail_daemon ] ;
|
||||
|
||||
Addon Message\ Parser : mail_daemon inbound_filters :
|
||||
filter.cpp ;
|
||||
|
||||
LinkSharedOSLibs Message\ Parser :
|
||||
be mail ;
|
||||
@@ -0,0 +1,91 @@
|
||||
/* Message Parser - parses the header of incoming e-mail
|
||||
**
|
||||
** Copyright 2001-2003 Dr. Zoidberg Enterprises. All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
#include <Message.h>
|
||||
#include <String.h>
|
||||
#include <E-mail.h>
|
||||
#include <Locker.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <MailAddon.h>
|
||||
#include <mail_util.h>
|
||||
|
||||
class ParseFilter : public BMailFilter {
|
||||
public:
|
||||
ParseFilter(BMessage *msg);
|
||||
|
||||
virtual status_t InitCheck(BString *err);
|
||||
virtual status_t ProcessMailMessage(BPositionIO **ioMessage, BEntry *ioEntry,
|
||||
BMessage *ioHeaders, BPath *ioFolder, const char *io_uid);
|
||||
|
||||
private:
|
||||
BString fNameField;
|
||||
};
|
||||
|
||||
|
||||
ParseFilter::ParseFilter(BMessage *msg)
|
||||
: BMailFilter(msg),
|
||||
fNameField("From")
|
||||
{
|
||||
const char *name = msg->FindString("name_field");
|
||||
if (name)
|
||||
fNameField = name;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ParseFilter::InitCheck(BString* err)
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ParseFilter::ProcessMailMessage(BPositionIO **data, BEntry */*entry*/, BMessage *headers,
|
||||
BPath */*folder*/, const char */*uid*/)
|
||||
{
|
||||
char byte;
|
||||
(*data)->ReadAt(0,&byte, 1);
|
||||
(*data)->Seek(SEEK_SET, 0);
|
||||
|
||||
status_t status = parse_header(*headers, **data);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
//
|
||||
// add pseudo-header THREAD, that contains the subject
|
||||
// minus stuff in []s (added by mailing lists) and
|
||||
// Re: prefixes, added by mailers when you reply.
|
||||
// This will generally be the "thread subject".
|
||||
//
|
||||
BString string;
|
||||
string.SetTo(headers->FindString("Subject"));
|
||||
SubjectToThread(string);
|
||||
headers->AddString("THREAD", string.String());
|
||||
|
||||
// name
|
||||
if (headers->FindString(fNameField.String(), 0, &string) == B_OK) {
|
||||
extract_address_name(string);
|
||||
headers->AddString("NAME", string);
|
||||
}
|
||||
|
||||
// header length
|
||||
headers->AddInt32(B_MAIL_ATTR_HEADER, (int32)((*data)->Position()));
|
||||
// What about content length? If we do that, we have to D/L the
|
||||
// whole message...
|
||||
//--NathanW says let the disk consumer do that
|
||||
|
||||
(*data)->Seek(0, SEEK_SET);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
BMailFilter *
|
||||
instantiate_mailfilter(BMessage *settings, BMailChainRunner *)
|
||||
{
|
||||
return new ParseFilter(settings);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/* To compile this test program, use this command line:
|
||||
g++ -I../../include/numail -I../../include/public/ -I../../include/support/ -lbe -lmail -o Test -Wall retest.cpp
|
||||
Then run Test with the subjects data file as input, or manually type in entries.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <String.h>
|
||||
#include <InterfaceDefs.h>
|
||||
|
||||
#include <mail_util.h>
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
BString string;
|
||||
char buf[1024];
|
||||
while (gets(buf))
|
||||
{
|
||||
string = buf;
|
||||
Zoidberg::Mail::SubjectToThread(string);
|
||||
printf ("Input: \"%s\"\nOutput: \"%s\"\n\n", buf, string.String());
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
Re: [list]subject
|
||||
Re: [list] subject
|
||||
[list] Re: subject
|
||||
[list]Re: subject
|
||||
[list]Re[2]: subject
|
||||
[list] Re [2] : subject
|
||||
Re[2]:[list] subject
|
||||
Re[2]:[list]subject
|
||||
Re:[list]subject
|
||||
Re [2] : [list] subject
|
||||
Réf [2] : [list] subject
|
||||
AW: Re [2]: [list] Réf: Re [5]: Fwd: Fwd [2]: subject
|
||||
Re: [list]subject (fwd)
|
||||
Re: [list] subject (fwd)
|
||||
[list] Re: subject (fwd)
|
||||
[list]Re: subject (fwd)
|
||||
[list]Re[2]: subject (fwd)
|
||||
[list] Re [2] : subject (fwd)
|
||||
Re[2]:[list] subject (fwd)
|
||||
Re[2]:[list]subject (fwd)
|
||||
Re:[list]subject (fwd)
|
||||
Re [2] : [list] subject (fwd)
|
||||
Réf [2] : [list] subject (fwd)
|
||||
AW: Re [2]: [list] Réf: Re [5]: Fwd: Fwd [2]: subject (fwd)
|
||||
@@ -0,0 +1 @@
|
||||
Moved to SubjectToThread in the mail library, AGMS 20030126.
|
||||
@@ -1,6 +1,7 @@
|
||||
SubDir OBOS_TOP src apps ;
|
||||
|
||||
SubInclude OBOS_TOP src apps bin ;
|
||||
SubInclude OBOS_TOP src apps bemail ;
|
||||
SubInclude OBOS_TOP src apps cdplayer ;
|
||||
SubInclude OBOS_TOP src apps clock ;
|
||||
SubInclude OBOS_TOP src apps codycam ;
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,387 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "BmapButton.h"
|
||||
#include <Bitmap.h>
|
||||
#include <Autolock.h>
|
||||
#include <Application.h>
|
||||
#include <Resources.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifndef B_BEOS_VERSION_5_0_4
|
||||
static rgb_color
|
||||
mix_color(rgb_color color1, rgb_color color2, float portion)
|
||||
{
|
||||
rgb_color ret;
|
||||
ret.red = uint8(color1.red*portion + color2.red*(1-portion) + .5);
|
||||
ret.green = uint8(color1.green*portion + color2.green*(1-portion) + .5);
|
||||
ret.blue = uint8(color1.blue*portion + color2.blue*(1-portion) + .5);
|
||||
ret.alpha = uint8(color1.alpha*portion + color2.alpha*(1-portion) + .5);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline rgb_color
|
||||
disable_color(rgb_color color, rgb_color background)
|
||||
{
|
||||
return mix_color(color, background, .5);
|
||||
}
|
||||
#endif // #ifndef B_BEOS_VERSION_5_0_4
|
||||
|
||||
BList BmapButton::fBitmapCache;
|
||||
BLocker BmapButton::fBmCacheLock;
|
||||
|
||||
struct BitmapItem
|
||||
{
|
||||
BBitmap *bm;
|
||||
int32 id;
|
||||
int32 openCount;
|
||||
};
|
||||
|
||||
|
||||
BmapButton::BmapButton(BRect frame,
|
||||
const char *name,
|
||||
const char *label,
|
||||
int32 enabledID,
|
||||
int32 disabledID,
|
||||
int32 rollID,
|
||||
int32 pressedID,
|
||||
bool showLabel,
|
||||
BMessage *message,
|
||||
uint32 resizeMask,
|
||||
uint32 flags) :
|
||||
BControl(frame, name, label, message, resizeMask, flags),
|
||||
fPressing(false),
|
||||
fIsInBounds(false),
|
||||
fShowLabel(showLabel),
|
||||
fActive(true),
|
||||
fIButtons(0)
|
||||
{
|
||||
fEnabledBM = RetrieveBitmap(enabledID);
|
||||
fDisabledBM = RetrieveBitmap(disabledID);
|
||||
fRollBM = RetrieveBitmap(rollID);
|
||||
fPressedBM = RetrieveBitmap(pressedID);
|
||||
}
|
||||
|
||||
|
||||
BmapButton::~BmapButton(void)
|
||||
{
|
||||
ReleaseBitmap(fEnabledBM);
|
||||
ReleaseBitmap(fDisabledBM);
|
||||
ReleaseBitmap(fRollBM);
|
||||
ReleaseBitmap(fPressedBM);
|
||||
}
|
||||
|
||||
|
||||
const BBitmap *
|
||||
BmapButton::RetrieveBitmap(int32 id)
|
||||
{
|
||||
// Lock access to the list
|
||||
BAutolock lock(fBmCacheLock);
|
||||
if (!lock.IsLocked())
|
||||
return NULL;
|
||||
|
||||
// Check for the bitmap in the cache first
|
||||
BitmapItem *item;
|
||||
for (int32 i=0; (item=(BitmapItem *)fBitmapCache.ItemAt(i)) != NULL; i++) {
|
||||
if (item->id == id) {
|
||||
item->openCount++;
|
||||
return item->bm;
|
||||
}
|
||||
}
|
||||
|
||||
// If it's not in the cache, try to load it
|
||||
BResources* res = BApplication::AppResources();
|
||||
if (!res) return NULL;
|
||||
|
||||
size_t size = 0;
|
||||
const void * data = res->LoadResource('BMAP', id, &size);
|
||||
if (!data) return NULL;
|
||||
BMemoryIO mio(data, size);
|
||||
BMessage arch;
|
||||
if (arch.Unflatten(&mio) != B_OK) return NULL;
|
||||
|
||||
BArchivable* obj = instantiate_object(&arch);
|
||||
BBitmap* bm = dynamic_cast<BBitmap*>(obj);
|
||||
if (!bm) {
|
||||
delete obj;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
item = (BitmapItem *)malloc(sizeof(BitmapItem));
|
||||
item->bm = bm;
|
||||
item->id = id;
|
||||
item->openCount = 1;
|
||||
fBitmapCache.AddItem(item);
|
||||
return bm;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
BmapButton::ReleaseBitmap(const BBitmap *bm)
|
||||
{
|
||||
// Lock access to the list
|
||||
BAutolock lock(fBmCacheLock);
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
// Find the bitmap
|
||||
BitmapItem *item;
|
||||
for (int32 i=0; (item=(BitmapItem *)fBitmapCache.ItemAt(i)) != NULL; i++) {
|
||||
if (item->bm == bm) {
|
||||
// If it's no longer in use by any objects, free the resources
|
||||
if (--item->openCount <= 0) {
|
||||
fBitmapCache.RemoveItem(i);
|
||||
delete item->bm;
|
||||
free(item);
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
#define F_SHOW_GEOMETRY 0
|
||||
|
||||
void
|
||||
BmapButton::Draw(BRect updateRect)
|
||||
{
|
||||
BRect bounds(Bounds());
|
||||
float labelHeight, labelWidth;
|
||||
|
||||
#if F_SHOW_GEOMETRY
|
||||
StrokeRect(bounds);
|
||||
#endif
|
||||
// Draw Label
|
||||
if (fShowLabel) {
|
||||
font_height fheight;
|
||||
|
||||
BFont renderFont;
|
||||
renderFont = *be_plain_font;
|
||||
renderFont.GetHeight(&fheight);
|
||||
SetFont(&renderFont);
|
||||
|
||||
labelHeight = fheight.leading + fheight.ascent + fheight.descent + 1;
|
||||
labelWidth = renderFont.StringWidth(Label())-2;
|
||||
|
||||
BRect textRect;
|
||||
textRect.left = (bounds.right-bounds.left-labelWidth+1)/2;
|
||||
textRect.right = textRect.left+labelWidth;
|
||||
textRect.bottom = bounds.bottom;
|
||||
textRect.top = textRect.bottom-fheight.descent-fheight.ascent-1;
|
||||
|
||||
// Only draw if it's within the update rect
|
||||
if (updateRect.Intersects(textRect)) {
|
||||
float baseLine = textRect.bottom-fheight.descent;
|
||||
|
||||
if (IsFocus() && fActive)
|
||||
SetHighColor(0, 0, 255);
|
||||
else
|
||||
SetHighColor(ViewColor());
|
||||
StrokeLine(BPoint(textRect.left, baseLine),
|
||||
BPoint(textRect.right, baseLine));
|
||||
|
||||
if (IsEnabled())
|
||||
SetHighColor(0, 0, 0);
|
||||
else {
|
||||
const rgb_color black = { 0, 0, 0, 255 };
|
||||
SetHighColor(disable_color(black, ViewColor()));
|
||||
}
|
||||
MovePenTo(textRect.left, baseLine);
|
||||
DrawString(Label());
|
||||
|
||||
#if F_SHOW_GEOMETRY
|
||||
FrameRect(textRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else {
|
||||
labelHeight = 0;
|
||||
labelWidth = 0;
|
||||
}
|
||||
|
||||
// Draw Bitmap
|
||||
|
||||
// Select the bitmap to use
|
||||
const BBitmap *bm;
|
||||
|
||||
if (!IsEnabled())
|
||||
bm = fDisabledBM;
|
||||
else if (fPressing) {
|
||||
if (fIsInBounds)
|
||||
bm = fPressedBM;
|
||||
else
|
||||
bm = fRollBM;
|
||||
} else {
|
||||
if (fIsInBounds)
|
||||
bm = fRollBM;
|
||||
else
|
||||
bm = fEnabledBM;
|
||||
}
|
||||
|
||||
// Draw the bitmap
|
||||
if (bm) {
|
||||
fBitmapRect = bm->Bounds();
|
||||
fBitmapRect.OffsetTo(0, 0);
|
||||
fBitmapRect.OffsetBy((bounds.right-bounds.left-fBitmapRect.right-fBitmapRect.left)/2,
|
||||
(bounds.bottom-bounds.top-labelHeight-fBitmapRect.bottom-fBitmapRect.top)/2);
|
||||
// Update if within update rect
|
||||
if (updateRect.Intersects(fBitmapRect)) {
|
||||
DrawBitmap(bm, fBitmapRect);
|
||||
#if F_SHOW_GEOMETRY
|
||||
StrokeRect(fBitmapRect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BmapButton::GetPreferredSize(float *width, float *height)
|
||||
{
|
||||
BRect prefBounds;
|
||||
|
||||
if (fEnabledBM) {
|
||||
if (fShowLabel) {
|
||||
float labelHeight, labelWidth;
|
||||
font_height fheight;
|
||||
BRect bmBounds(fEnabledBM->Bounds());
|
||||
BFont renderFont;
|
||||
renderFont = *be_plain_font;
|
||||
renderFont.GetHeight(&fheight);
|
||||
SetFont(&renderFont);
|
||||
|
||||
labelHeight = fheight.leading + fheight.ascent + fheight.descent + 1;
|
||||
labelWidth = renderFont.StringWidth(Label());
|
||||
prefBounds.left = 0;
|
||||
prefBounds.top = 0;
|
||||
prefBounds.right = labelWidth > (bmBounds.right-bmBounds.left) ? labelWidth :
|
||||
(bmBounds.right-bmBounds.left);
|
||||
prefBounds.bottom = labelHeight + (bmBounds.bottom-bmBounds.top);
|
||||
} else
|
||||
prefBounds = fEnabledBM->Bounds();
|
||||
} else
|
||||
prefBounds = Bounds();
|
||||
|
||||
*width = prefBounds.IntegerWidth();
|
||||
*height = prefBounds.IntegerHeight();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BmapButton::MouseMoved(BPoint where, uint32 code, const BMessage *msg)
|
||||
{
|
||||
// eliminate unused parameter warnings
|
||||
(void)where;
|
||||
(void)msg;
|
||||
|
||||
if (IsEnabled() && fActive) {
|
||||
switch(code) {
|
||||
case B_ENTERED_VIEW:
|
||||
fIsInBounds = true;
|
||||
Invalidate(fBitmapRect);
|
||||
break;
|
||||
|
||||
case B_EXITED_VIEW:
|
||||
fIsInBounds = false;
|
||||
Invalidate(fBitmapRect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BmapButton::MouseDown(BPoint point)
|
||||
{
|
||||
if (!IsEnabled())
|
||||
return;
|
||||
// Save Mouse State
|
||||
GetMouse(&point, &fButtons);
|
||||
fWhere = point;
|
||||
|
||||
if (fButtons & fIButtons) {
|
||||
BMessage copy(*Message());
|
||||
copy.AddPoint("where", ConvertToScreen(fWhere));
|
||||
copy.AddInt32("buttons", fButtons);
|
||||
Invoke(©);
|
||||
return;
|
||||
}
|
||||
|
||||
SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS | B_SUSPEND_VIEW_FOCUS | B_NO_POINTER_HISTORY);
|
||||
fPressing = true;
|
||||
Invalidate(fBitmapRect);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BmapButton::MouseUp(BPoint where)
|
||||
{
|
||||
if (atomic_and(&fPressing, 0)) {
|
||||
SetMouseEventMask(0, 0);
|
||||
if (Bounds().Contains(where) && IsEnabled()) {
|
||||
BMessage copy(*Message());
|
||||
copy.AddPoint("where", ConvertToScreen(fWhere));
|
||||
copy.AddInt32("buttons", fButtons);
|
||||
Invoke(©);
|
||||
}
|
||||
Invalidate(fBitmapRect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BmapButton::ShowLabel(bool show)
|
||||
{
|
||||
fShowLabel = show;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BmapButton::WindowActivated(bool active)
|
||||
{
|
||||
fActive = active;
|
||||
if (IsFocus() || fIsInBounds) {
|
||||
fIsInBounds = false;
|
||||
Invalidate();
|
||||
}
|
||||
BControl::WindowActivated(active);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
BmapButton::InvokeOnButton(uint32 button)
|
||||
{
|
||||
fIButtons = button;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _BMAP_BUTTON_H
|
||||
#define _BMAP_BUTTON_H
|
||||
|
||||
#include <Control.h>
|
||||
#include <List.h>
|
||||
#include <Locker.h>
|
||||
#include <View.h>
|
||||
|
||||
class BBitmap;
|
||||
class BResources;
|
||||
|
||||
class BmapButton : public BControl {
|
||||
public:
|
||||
BmapButton(BRect frame, const char *name, const char *label,
|
||||
int32 enabledID, int32 disabledID, int32 rollID, int32 pressedID,
|
||||
bool showLabel, BMessage *message, uint32 resizeMask,
|
||||
uint32 flags = B_WILL_DRAW | B_NAVIGABLE);
|
||||
virtual ~BmapButton(void);
|
||||
|
||||
// Hooks
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
virtual void MouseMoved(BPoint where, uint32 code, const BMessage *msg);
|
||||
virtual void MouseDown(BPoint point);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void WindowActivated(bool active);
|
||||
|
||||
void InvokeOnButton(uint32 button);
|
||||
void ShowLabel(bool show);
|
||||
|
||||
protected:
|
||||
const BBitmap *RetrieveBitmap(int32 id);
|
||||
status_t ReleaseBitmap(const BBitmap *bm);
|
||||
|
||||
const BBitmap *fEnabledBM;
|
||||
const BBitmap *fDisabledBM;
|
||||
const BBitmap *fRollBM;
|
||||
const BBitmap *fPressedBM;
|
||||
int32 fPressing;
|
||||
int32 fIsInBounds;
|
||||
uint32 fButtons;
|
||||
bool fShowLabel;
|
||||
bool fActive;
|
||||
BRect fBitmapRect;
|
||||
BPoint fWhere;
|
||||
uint32 fIButtons;
|
||||
|
||||
private:
|
||||
static BList fBitmapCache;
|
||||
static BLocker fBmCacheLock;
|
||||
};
|
||||
|
||||
#endif // #ifndef _BMAP_BUTTON_H
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "ButtonBar.h"
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
struct BBDivider {
|
||||
float where;
|
||||
float vmargin;
|
||||
BmapButton *button;
|
||||
};
|
||||
|
||||
static const int32 kDividerBlockSize = 8;
|
||||
|
||||
ButtonBar::ButtonBar(BRect frame, const char *name, uint8 enabledOffset, uint8 disabledOffset,
|
||||
uint8 rollOffset, uint8 pressedOffset, float Hmargin, float Vmargin,
|
||||
uint32 resizeMask, int32 flags, border_style border)
|
||||
: BBox(frame, name, resizeMask, flags, border),
|
||||
fMaxHeight(0),
|
||||
fMaxWidth(0),
|
||||
fNextXOffset(Hmargin),
|
||||
fHMargin(Hmargin),
|
||||
fVMargin(Vmargin),
|
||||
fEnabledOffset(enabledOffset),
|
||||
fDisabledOffset(disabledOffset),
|
||||
fRollOffset(rollOffset),
|
||||
fPressedOffset(pressedOffset),
|
||||
fDividerArray(NULL),
|
||||
fDividers(0),
|
||||
fShowLabels(true)
|
||||
{
|
||||
}
|
||||
|
||||
ButtonBar::~ButtonBar(void)
|
||||
{
|
||||
if (fDividerArray)
|
||||
free(fDividerArray);
|
||||
}
|
||||
|
||||
BmapButton *ButtonBar::AddButton(const char *label, int32 baseID, BMessage *msg)
|
||||
{
|
||||
BmapButton *button;
|
||||
|
||||
button = new BmapButton(BRect(0, 0, 31, 31), label, label, baseID+fEnabledOffset,
|
||||
baseID+fDisabledOffset, baseID+fRollOffset, baseID+fPressedOffset,
|
||||
fShowLabels, msg, B_FOLLOW_LEFT | B_FOLLOW_TOP);
|
||||
|
||||
fButtonList.AddItem(button);
|
||||
AddChild(button);
|
||||
return button;
|
||||
}
|
||||
|
||||
void ButtonBar::Arrange(bool fixedWidth)
|
||||
{
|
||||
// Reset Positioning Info
|
||||
fNextXOffset = fHMargin;
|
||||
fMaxHeight = 0;
|
||||
fMaxWidth = 0;
|
||||
|
||||
int32 i;
|
||||
float width, height;
|
||||
BmapButton *button;
|
||||
|
||||
// Determine Largest button dimensions
|
||||
for (i = 0; (button = (BmapButton *)fButtonList.ItemAt(i)) != NULL; i++)
|
||||
{
|
||||
button->GetPreferredSize(&width, &height);
|
||||
if (height > fMaxHeight)
|
||||
fMaxHeight = height;
|
||||
if (width > fMaxWidth)
|
||||
fMaxWidth = width;
|
||||
}
|
||||
|
||||
// Arrange buttons
|
||||
for (i = 0; (button = (BmapButton *)fButtonList.ItemAt(i)) != NULL; i++)
|
||||
{
|
||||
button->MoveTo(fNextXOffset, fVMargin);
|
||||
if (fixedWidth) {
|
||||
button->ResizeTo(fMaxWidth, fMaxHeight);
|
||||
fNextXOffset += fMaxWidth+fHMargin;
|
||||
} else {
|
||||
button->GetPreferredSize(&width, &height);
|
||||
button->ResizeTo(width, fMaxHeight);
|
||||
fNextXOffset += width+fHMargin;
|
||||
}
|
||||
}
|
||||
|
||||
// Move dividers to match
|
||||
for(i = 0; i < fDividers; i++)
|
||||
{
|
||||
if (fDividerArray[i].button)
|
||||
fDividerArray[i].where = fDividerArray[i].button->Frame().right + floor(fHMargin/2);
|
||||
else
|
||||
fDividerArray[i].where = floor(fHMargin/2);
|
||||
}
|
||||
}
|
||||
|
||||
void ButtonBar::GetPreferredSize(float *width, float *height)
|
||||
{
|
||||
*width = fNextXOffset+fHMargin;
|
||||
*height = fMaxHeight+(2*fVMargin);
|
||||
}
|
||||
|
||||
void ButtonBar::AttachedToWindow(void)
|
||||
{
|
||||
if (Parent())
|
||||
SetViewColor(Parent()->ViewColor());
|
||||
BBox::AttachedToWindow();
|
||||
}
|
||||
|
||||
void ButtonBar::Draw(BRect updateRect)
|
||||
{
|
||||
BBox::Draw(updateRect);
|
||||
rgb_color high = { 184, 184, 184, 255 };
|
||||
rgb_color low = { 232, 232, 232, 255 };
|
||||
BRect bounds = Bounds();
|
||||
float where, vmargin;
|
||||
|
||||
BeginLineArray(fDividers*2);
|
||||
for (int32 i=0; i<fDividers; i++) {
|
||||
where = fDividerArray[i].where;
|
||||
vmargin = fDividerArray[i].vmargin;
|
||||
AddLine(BPoint(where, fVMargin+vmargin), BPoint(where, bounds.bottom-fVMargin-vmargin), high);
|
||||
AddLine(BPoint(where+1, fVMargin+vmargin), BPoint(where+1, bounds.bottom-fVMargin-vmargin), low);
|
||||
}
|
||||
EndLineArray();
|
||||
}
|
||||
|
||||
void ButtonBar::AddDivider(float vmargin)
|
||||
{
|
||||
// Do we need to allocate memory?
|
||||
if (fDividers == 0)
|
||||
fDividerArray = (BBDivider *)malloc(sizeof(BBDivider)*kDividerBlockSize);
|
||||
if ((fDividers % kDividerBlockSize) == 0)
|
||||
fDividerArray = (BBDivider *)realloc(fDividerArray, sizeof(BBDivider)*kDividerBlockSize*((fDividers/kDividerBlockSize)+1));
|
||||
|
||||
// Cache the location and the button which proceeds it
|
||||
// The button is stored because we may later wish to change the layout
|
||||
fDividerArray[fDividers].vmargin = vmargin;
|
||||
fDividerArray[fDividers].where = fNextXOffset+floor(fHMargin/2);
|
||||
fDividerArray[fDividers].button = (BmapButton *)fButtonList.ItemAt(fButtonList.CountItems()-1);
|
||||
fDividers++;
|
||||
}
|
||||
|
||||
void ButtonBar::ShowLabels(bool show)
|
||||
{
|
||||
BmapButton *button;
|
||||
|
||||
// Set show label flags on buttons
|
||||
for (int32 i=0; (button = (BmapButton *)fButtonList.ItemAt(i)) != NULL; i++)
|
||||
button->ShowLabel(show);
|
||||
fShowLabels = show;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _BUTTON_BAR_H
|
||||
#define _BUTTON_BAR_H
|
||||
|
||||
#include <Box.h>
|
||||
|
||||
#include "BmapButton.h"
|
||||
|
||||
struct BBDivider;
|
||||
|
||||
class ButtonBar : public BBox {
|
||||
public:
|
||||
ButtonBar(BRect frame, const char *name, uint8 enabledOffset,
|
||||
uint8 disabledOffset, uint8 rollOffset, uint8 pressedOffset,
|
||||
float Hmargin, float Vmargin,
|
||||
uint32 resizeMask = B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP,
|
||||
int32 flags = B_NAVIGABLE_JUMP | B_FRAME_EVENTS | B_WILL_DRAW,
|
||||
border_style border = B_FANCY_BORDER);
|
||||
virtual ~ButtonBar( void );
|
||||
|
||||
// Hooks
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
virtual void AttachedToWindow(void);
|
||||
virtual void Draw(BRect updateRect);
|
||||
|
||||
void ShowLabels(bool show);
|
||||
void Arrange(bool fixedWidth = true);
|
||||
BmapButton *AddButton(const char *label, int32 baseID, BMessage *msg);
|
||||
void AddDivider(float vmargin);
|
||||
|
||||
protected:
|
||||
float fMaxHeight;
|
||||
float fMaxWidth;
|
||||
float fNextXOffset;
|
||||
float fHMargin;
|
||||
float fVMargin;
|
||||
uint8 fEnabledOffset;
|
||||
uint8 fDisabledOffset;
|
||||
uint8 fRollOffset;
|
||||
uint8 fPressedOffset;
|
||||
BList fButtonList;
|
||||
BBDivider *fDividerArray;
|
||||
int32 fDividers;
|
||||
bool fShowLabels;
|
||||
};
|
||||
|
||||
#endif // #ifndef _BUTTON_BAR_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//
|
||||
// ComboBox.h
|
||||
//
|
||||
// A view that is the combination of a text control and a pop-up list
|
||||
//
|
||||
//
|
||||
|
||||
#ifndef _COMBOBOX_H
|
||||
#define _COMBOBOX_H
|
||||
|
||||
#include <Control.h>
|
||||
#include <View.h>
|
||||
|
||||
class BButton;
|
||||
class BList;
|
||||
class BTextControl;
|
||||
class BWindow;
|
||||
class BComboBox;
|
||||
|
||||
/*
|
||||
// Abstract class provides an interface for BComboBox to access possible choices.
|
||||
// Choices are used for auto-completion and for showing the pop-up list
|
||||
class BChoiceList {
|
||||
public:
|
||||
// Returns the choice at index or NULL if the index is invalid
|
||||
virtual const char *ChoiceAt(int32 index) = 0;
|
||||
|
||||
// Looks for a match at or after startIndex which contains a choice
|
||||
// that starts with prefix. If a match is found, B_OK is returned,
|
||||
// matchIndex is set to the list index that should be selected, and completionText
|
||||
// is set to point at the text that should be appended to the text input.
|
||||
// If no match is found, a negative value is returned.
|
||||
virtual status_t GetMatch(const char *prefix, int32 startIndex,
|
||||
int32 *matchIndex, const char **completionText) = 0;
|
||||
|
||||
// Returns the number of choices
|
||||
virtual int32 CountChoices() = 0;
|
||||
};
|
||||
*/
|
||||
|
||||
class StringObjectList;
|
||||
|
||||
// Implementation of BChoiceList. Keeps copies of each choice added, and frees
|
||||
// the memory when the choices are removed.
|
||||
class BDefaultChoiceList // : public BChoiceList
|
||||
{
|
||||
public:
|
||||
BDefaultChoiceList(BComboBox *owner = NULL);
|
||||
virtual ~BDefaultChoiceList();
|
||||
|
||||
virtual const char *ChoiceAt(int32 index);
|
||||
virtual status_t GetMatch(const char *prefix, int32 startIndex,
|
||||
int32 *matchIndex, const char **completionText);
|
||||
virtual int32 CountChoices();
|
||||
|
||||
status_t AddChoice(const char *toAdd);
|
||||
status_t AddChoiceAt(const char *toAdd, int32 index);
|
||||
status_t RemoveChoice(const char *toRemove);
|
||||
status_t RemoveChoiceAt(int32 index);
|
||||
|
||||
void SetOwner(BComboBox *owner);
|
||||
BComboBox *Owner();
|
||||
|
||||
private:
|
||||
StringObjectList *fList;
|
||||
BComboBox *fOwner;
|
||||
};
|
||||
typedef BDefaultChoiceList BChoiceList;
|
||||
|
||||
|
||||
class BComboBox : public BControl {
|
||||
public:
|
||||
BComboBox(BRect frame, const char *name, const char *label,
|
||||
BMessage *message, uint32 resizeMask = B_FOLLOW_LEFT | B_FOLLOW_TOP,
|
||||
uint32 flags = B_WILL_DRAW | B_FRAME_EVENTS | B_NAVIGABLE);
|
||||
// BComboBox(BMessage *data);
|
||||
virtual ~BComboBox();
|
||||
|
||||
// BArchivable methods
|
||||
// static BArchivable *Instantiate(BMessage *data);
|
||||
// virtual status_t Archive(BMessage *data, bool deep = true) const;
|
||||
|
||||
// SetChoiceList causes the BComboBox to delete the old BChoiceList object,
|
||||
// take ownership of the new choice list, and then invalidate the pop-up list
|
||||
void SetChoiceList(BChoiceList *list);
|
||||
|
||||
// ChoiceList returns a pointer to the current choice list
|
||||
BChoiceList *ChoiceList();
|
||||
|
||||
// ChoiceListUpdated should be called whenever an item in the choice list changes
|
||||
// so that BComboBox can perform the proper updating.
|
||||
virtual void ChoiceListUpdated();
|
||||
|
||||
// Select changes the list selection to the specified index, and if the
|
||||
// changeTextSelection flag is true, changes the text in the TextView to
|
||||
// the value at index and selects all the text in the TextView.
|
||||
virtual void Select(int32 index, bool changeTextSelection = false);
|
||||
|
||||
virtual void Deselect();
|
||||
|
||||
// Returns the index of the current selection, or a negative value
|
||||
int32 CurrentSelection();
|
||||
|
||||
// SetAutoComplete enables or disables auto-completion
|
||||
virtual void SetAutoComplete(bool on);
|
||||
bool GetAutoComplete();
|
||||
|
||||
// The following methods are mostly identical to their BTextControl counterparts
|
||||
virtual void SetValue(int32 value);
|
||||
virtual void SetEnabled(bool enabled);
|
||||
virtual void SetLabel(const char *text);
|
||||
virtual void SetText(const char *text);
|
||||
const char *Text() const;
|
||||
BTextView *TextView();
|
||||
virtual void SetDivider(float dividing_line);
|
||||
float Divider() const;
|
||||
virtual void SetAlignment(alignment label, alignment text);
|
||||
void GetAlignment(alignment *label, alignment *text) const;
|
||||
|
||||
virtual void SetModificationMessage(BMessage *message);
|
||||
BMessage *ModificationMessage() const;
|
||||
|
||||
virtual void GetPreferredSize(float *width, float *height);
|
||||
virtual void ResizeToPreferred();
|
||||
virtual void FrameMoved(BPoint new_position);
|
||||
virtual void FrameResized(float new_width, float new_height);
|
||||
virtual void WindowActivated(bool active);
|
||||
virtual void MakeFocus(bool state);
|
||||
|
||||
virtual void Draw(BRect update);
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage *dragMessage);
|
||||
// virtual void AllAttached();
|
||||
virtual void AttachedToWindow();
|
||||
virtual void DetachedFromWindow();
|
||||
virtual void SetFlags(uint32 flags);
|
||||
// virtual void SetFont(const BFont *font, uint32 properties = B_FONT_ALL);
|
||||
|
||||
virtual status_t Invoke(BMessage *msg = NULL);
|
||||
|
||||
// virtual BHandler *ResolveSpecifier(BMessage *msg, int32 index,
|
||||
// BMessage *specifier, int32 form, const char *property);
|
||||
// virtual status_t GetSupportedSuites(BMessage *data);
|
||||
//
|
||||
//
|
||||
// virtual status_t Perform(perform_code d, void *arg);
|
||||
|
||||
private:
|
||||
class ComboBoxWindow;
|
||||
class ChoiceListView;
|
||||
class TextInput;
|
||||
class MovedMessageFilter;
|
||||
|
||||
protected:
|
||||
ComboBoxWindow *CreatePopupWindow();
|
||||
void CommitValue();
|
||||
void TryAutoComplete();
|
||||
void ShowPopupWindow();
|
||||
void HidePopupWindow();
|
||||
|
||||
BRect fButtonRect;
|
||||
int32 fSelected;
|
||||
int32 fCompletionIndex;
|
||||
float fDivider;
|
||||
TextInput *fText;
|
||||
ComboBoxWindow *fPopupWindow;
|
||||
BMessage *fModificationMessage;
|
||||
BChoiceList *fChoiceList;
|
||||
alignment fLabelAlign;
|
||||
bool fAutoComplete;
|
||||
bool fButtonDepressed;
|
||||
bool fDepressedWhenClicked;
|
||||
bool fTrackingButtonDown;
|
||||
|
||||
/*----- Private or reserved -----------------------------------------*/
|
||||
private:
|
||||
BRect fFrameCache;
|
||||
MovedMessageFilter *fWinMovedFilter;
|
||||
int32 fTextEnd;
|
||||
bool fSkipSetFlags;
|
||||
|
||||
friend class ChoiceListView;
|
||||
friend class ComboBoxWindow;
|
||||
friend class TextInput;
|
||||
};
|
||||
|
||||
#endif // #ifndef _COMBOBOX_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,291 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Content.h
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef _CONTENT_H
|
||||
#define _CONTENT_H
|
||||
|
||||
#include <FilePanel.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Font.h>
|
||||
#include <fs_attr.h>
|
||||
#include <Point.h>
|
||||
#include <Rect.h>
|
||||
#include <MessageFilter.h>
|
||||
|
||||
#include "KUndoBuffer.h"
|
||||
|
||||
#define MESSAGE_TEXT "Message:"
|
||||
#define MESSAGE_TEXT_H 16
|
||||
#define MESSAGE_TEXT_V 5
|
||||
#define MESSAGE_FIELD_H 59
|
||||
#define MESSAGE_FIELD_V 11
|
||||
|
||||
#define CONTENT_TYPE "content-type: "
|
||||
#define CONTENT_ENCODING "content-transfer-encoding: "
|
||||
#define CONTENT_DISPOSITION "Content-Disposition: "
|
||||
#define MIME_TEXT "text/"
|
||||
#define MIME_MULTIPART "multipart/"
|
||||
|
||||
class TMailWindow;
|
||||
class TScrollView;
|
||||
class TTextView;
|
||||
class BFile;
|
||||
class BList;
|
||||
class BPopupMenu;
|
||||
|
||||
struct text_run_array;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool header;
|
||||
bool raw;
|
||||
bool quote;
|
||||
bool incoming;
|
||||
bool close;
|
||||
bool mime;
|
||||
TTextView *view;
|
||||
BEmailMessage *mail;
|
||||
BList *enclosures;
|
||||
sem_id *stop_sem;
|
||||
} reader_info;
|
||||
|
||||
enum ENCLOSURE_TYPE
|
||||
{
|
||||
TYPE_ENCLOSURE = 100,
|
||||
TYPE_BE_ENCLOSURE,
|
||||
TYPE_URL,
|
||||
TYPE_MAILTO
|
||||
};
|
||||
|
||||
struct hyper_text {
|
||||
int32 type;
|
||||
char *name;
|
||||
char *content_type;
|
||||
char *encoding;
|
||||
int32 text_start;
|
||||
int32 text_end;
|
||||
BMailComponent *component;
|
||||
bool saved;
|
||||
bool have_ref;
|
||||
entry_ref ref;
|
||||
node_ref node;
|
||||
};
|
||||
|
||||
class TSavePanel;
|
||||
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TContentView : public BView
|
||||
{
|
||||
public:
|
||||
TContentView(BRect, bool incoming, BEmailMessage *mail, BFont *);
|
||||
virtual void MessageReceived(BMessage *);
|
||||
void FindString(const char *);
|
||||
void Focus(bool);
|
||||
void FrameResized(float, float);
|
||||
|
||||
TTextView *fTextView;
|
||||
|
||||
private:
|
||||
bool fFocus;
|
||||
bool fIncoming;
|
||||
float fOffset;
|
||||
};
|
||||
|
||||
//====================================================================
|
||||
|
||||
enum {
|
||||
S_CLEAR_ERRORS = 1,
|
||||
S_SHOW_ERRORS = 2
|
||||
};
|
||||
|
||||
class TTextView : public BTextView
|
||||
{
|
||||
public:
|
||||
TTextView(BRect, BRect, bool incoming, BEmailMessage *mail, TContentView *,BFont *);
|
||||
~TTextView();
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void KeyDown(const char*, int32);
|
||||
virtual void MakeFocus(bool);
|
||||
virtual void MessageReceived(BMessage*);
|
||||
virtual void MouseDown(BPoint);
|
||||
virtual void MouseMoved(BPoint, uint32, const BMessage*);
|
||||
virtual void InsertText(const char *text, int32 length, int32 offset,
|
||||
const text_run_array *runs);
|
||||
virtual void DeleteText(int32 start, int32 finish);
|
||||
|
||||
void ClearList();
|
||||
void LoadMessage(BEmailMessage *mail, bool quoteIt, const char *insertText);
|
||||
void Open(hyper_text*);
|
||||
status_t Save(BMessage *, bool makeNewFile = true);
|
||||
void StopLoad();
|
||||
void AddAsContent(BEmailMessage *mail, bool wrap, uint32 charset, mail_encoding encoding);
|
||||
void CheckSpelling(int32 start, int32 end,
|
||||
int32 flags = S_CLEAR_ERRORS | S_SHOW_ERRORS);
|
||||
void FindSpellBoundry(int32 length, int32 offset, int32 *start,
|
||||
int32 *end);
|
||||
void EnableSpellCheck(bool enable);
|
||||
|
||||
void AddQuote(int32 start, int32 finish);
|
||||
void RemoveQuote(int32 start, int32 finish);
|
||||
|
||||
void WindowActivated(bool flag);
|
||||
void Undo(BClipboard *clipboard);
|
||||
void Redo();
|
||||
|
||||
const BFont *Font() const { return &fFont; }
|
||||
|
||||
bool fHeader;
|
||||
bool fReady;
|
||||
|
||||
private:
|
||||
struct { bool replaced, deleted; } fUndoState;
|
||||
KUndoBuffer fUndoBuffer;
|
||||
|
||||
struct { bool active, replace; } fInputMethodUndoState;
|
||||
KUndoBuffer fInputMethodUndoBuffer;
|
||||
// For handling Input Method changes in undo.
|
||||
|
||||
struct spell_mark;
|
||||
|
||||
spell_mark *FindSpellMark(int32 start, int32 end, spell_mark **_previousMark = NULL);
|
||||
void UpdateSpellMarks(int32 offset, int32 length);
|
||||
status_t AddSpellMark(int32 start, int32 end);
|
||||
bool RemoveSpellMark(int32 start, int32 end);
|
||||
void RemoveSpellMarks();
|
||||
|
||||
void ContentChanged(void);
|
||||
|
||||
class Reader;
|
||||
friend TTextView::Reader;
|
||||
|
||||
char *fYankBuffer;
|
||||
int32 fLastPosition;
|
||||
BFile *fFile;
|
||||
BEmailMessage *fMail;
|
||||
// for incoming/replied/forwarded mails only
|
||||
BFont fFont;
|
||||
TContentView *fParent;
|
||||
sem_id fStopSem;
|
||||
bool fStopLoading;
|
||||
thread_id fThread;
|
||||
BList *fEnclosures;
|
||||
BPopUpMenu *fEnclosureMenu;
|
||||
BPopUpMenu *fLinkMenu;
|
||||
TSavePanel *fPanel;
|
||||
bool fIncoming;
|
||||
bool fSpellCheck;
|
||||
bool fRaw;
|
||||
bool fCursor;
|
||||
|
||||
struct spell_mark
|
||||
{
|
||||
spell_mark *next;
|
||||
int32 start;
|
||||
int32 end;
|
||||
struct text_run_array *style;
|
||||
};
|
||||
|
||||
spell_mark *fFirstSpellMark;
|
||||
|
||||
class Reader
|
||||
{
|
||||
public:
|
||||
Reader(bool header,bool raw,bool quote,bool incoming,bool stripHeaders,bool mime,
|
||||
TTextView *view,BEmailMessage *mail,BList *list,sem_id sem);
|
||||
|
||||
static status_t Run(void *);
|
||||
|
||||
private:
|
||||
bool ParseMail(BMailContainer *container,BTextMailComponent *ignore);
|
||||
bool Process(const char *data, int32 len, bool isHeader = false);
|
||||
bool Insert(const char *line, int32 count, bool isHyperLink, bool isHeader = false);
|
||||
|
||||
bool Lock();
|
||||
status_t Unlock();
|
||||
|
||||
bool fHeader;
|
||||
bool fRaw;
|
||||
bool fQuote;
|
||||
bool fIncoming;
|
||||
bool fStripHeader;
|
||||
bool fMime;
|
||||
TTextView *fView;
|
||||
BEmailMessage *fMail;
|
||||
BList *fEnclosures;
|
||||
sem_id fStopSem;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TSavePanel : public BFilePanel {
|
||||
public:
|
||||
TSavePanel(hyper_text*, TTextView*);
|
||||
virtual void SendMessage(const BMessenger*, BMessage*);
|
||||
void SetEnclosure(hyper_text*);
|
||||
|
||||
private:
|
||||
hyper_text *fEnclosure;
|
||||
TTextView *fView;
|
||||
};
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TextRunArray {
|
||||
public:
|
||||
TextRunArray(size_t entries);
|
||||
~TextRunArray();
|
||||
|
||||
text_run_array &Array() { return *fArray; }
|
||||
size_t MaxEntries() const { return fNumEntries; }
|
||||
|
||||
private:
|
||||
text_run_array *fArray;
|
||||
size_t fNumEntries;
|
||||
};
|
||||
|
||||
extern void FillInQuoteTextRuns(BTextView *view, const char *line, int32 length,
|
||||
const BFont &font, text_run_array *style, int32 maxStyles = 5);
|
||||
|
||||
#endif /* #ifndef _CONTENT_H */
|
||||
@@ -0,0 +1,556 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Enclosures.cpp
|
||||
// The enclosures list view (TListView), the list items (TListItem),
|
||||
// and the view containing the list and handling the messages (TEnclosuresView).
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#include "Mail.h"
|
||||
#include "Enclosures.h"
|
||||
|
||||
#include <Debug.h>
|
||||
#include <Beep.h>
|
||||
#include <Bitmap.h>
|
||||
#include <MenuItem.h>
|
||||
#include <Alert.h>
|
||||
#include <NodeMonitor.h>
|
||||
|
||||
#include <MailAttachment.h>
|
||||
#include <MailMessage.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
//====================================================================
|
||||
|
||||
|
||||
static status_t
|
||||
GetTrackerIcon(BMimeType &type, BBitmap *icon, icon_size iconSize)
|
||||
{
|
||||
// set some icon size related variables
|
||||
status_t error = B_OK;
|
||||
BRect bounds;
|
||||
switch (iconSize) {
|
||||
case B_MINI_ICON:
|
||||
bounds.Set(0, 0, 15, 15);
|
||||
break;
|
||||
case B_LARGE_ICON:
|
||||
bounds.Set(0, 0, 31, 31);
|
||||
break;
|
||||
default:
|
||||
error = B_BAD_VALUE;
|
||||
break;
|
||||
}
|
||||
// check parameters and initialization
|
||||
if (error == B_OK
|
||||
&& (!icon || icon->InitCheck() != B_OK || icon->Bounds() != bounds))
|
||||
return B_BAD_VALUE;
|
||||
|
||||
bool success = false;
|
||||
|
||||
// Ask the MIME database for the preferred application for the file type
|
||||
// and whether this application has a special icon for the type.
|
||||
char signature[B_MIME_TYPE_LENGTH];
|
||||
if (type.GetPreferredApp(signature) == B_OK) {
|
||||
BMimeType type(signature);
|
||||
success = (type.GetIconForType(type.Type(), icon, iconSize) == B_OK);
|
||||
}
|
||||
|
||||
// Ask the MIME database whether there is an icon for the node's file type.
|
||||
if (error == B_OK && !success)
|
||||
success = (type.GetIcon(icon, iconSize) == B_OK);
|
||||
|
||||
// Ask the MIME database for the super type and start all over
|
||||
if (error == B_OK && !success) {
|
||||
BMimeType super;
|
||||
if (type.GetSupertype(&super) == B_OK)
|
||||
return GetTrackerIcon(super, icon, iconSize);
|
||||
}
|
||||
|
||||
// Return the icon for "application/octet-stream" from the MIME database.
|
||||
if (error == B_OK && !success) {
|
||||
// get the "application/octet-stream" icon
|
||||
BMimeType type("application/octet-stream");
|
||||
error = type.GetIcon(icon, iconSize);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TEnclosuresView::TEnclosuresView(BRect rect, BRect wind_rect)
|
||||
: BView(rect, "m_enclosures", B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT, B_WILL_DRAW),
|
||||
fFocus(false)
|
||||
{
|
||||
rgb_color c;
|
||||
c.red = c.green = c.blue = VIEW_COLOR;
|
||||
SetViewColor(c);
|
||||
|
||||
BFont font = *be_plain_font;
|
||||
font.SetSize(FONT_SIZE);
|
||||
font_height fHeight;
|
||||
font.GetHeight(&fHeight);
|
||||
fOffset = 12;
|
||||
|
||||
BRect r;
|
||||
r.left = ENCLOSE_TEXT_H + font.StringWidth(
|
||||
MDR_DIALECT_CHOICE ("Enclosures: ","添付ファイル")) + 5;
|
||||
r.top = ENCLOSE_FIELD_V;
|
||||
r.right = wind_rect.right - wind_rect.left - B_V_SCROLL_BAR_WIDTH - 9;
|
||||
r.bottom = Frame().Height() - 8;
|
||||
fList = new TListView(r, this);
|
||||
fList->SetInvocationMessage(new BMessage(LIST_INVOKED));
|
||||
|
||||
BScrollView *scroll = new BScrollView("", fList, B_FOLLOW_LEFT_RIGHT |
|
||||
B_FOLLOW_TOP, 0, false, true);
|
||||
AddChild(scroll);
|
||||
scroll->ScrollBar(B_VERTICAL)->SetRange(0, 0);
|
||||
}
|
||||
|
||||
|
||||
TEnclosuresView::~TEnclosuresView()
|
||||
{
|
||||
for (int32 index = fList->CountItems();index-- > 0;)
|
||||
{
|
||||
TListItem *item = static_cast<TListItem *>(fList->ItemAt(index));
|
||||
fList->RemoveItem(index);
|
||||
|
||||
if (item->Component() == NULL)
|
||||
watch_node(item->NodeRef(), B_STOP_WATCHING, this);
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TEnclosuresView::Draw(BRect where)
|
||||
{
|
||||
float offset;
|
||||
BFont font = *be_plain_font;
|
||||
|
||||
BView::Draw(where);
|
||||
font.SetSize(FONT_SIZE);
|
||||
SetFont(&font);
|
||||
SetHighColor(0, 0, 0);
|
||||
SetLowColor(VIEW_COLOR, VIEW_COLOR, VIEW_COLOR);
|
||||
|
||||
offset = 12;
|
||||
|
||||
font_height fHeight;
|
||||
font.GetHeight(&fHeight);
|
||||
|
||||
MovePenTo(ENCLOSE_TEXT_H, ENCLOSE_TEXT_V + fHeight.ascent);
|
||||
DrawString(ENCLOSE_TEXT);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TEnclosuresView::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what)
|
||||
{
|
||||
case LIST_INVOKED:
|
||||
{
|
||||
BListView *list;
|
||||
msg->FindPointer("source", (void **)&list);
|
||||
if (list)
|
||||
{
|
||||
TListItem *item = (TListItem *) (list->ItemAt(msg->FindInt32("index")));
|
||||
if (item)
|
||||
{
|
||||
BMessenger tracker("application/x-vnd.Be-TRAK");
|
||||
if (tracker.IsValid())
|
||||
{
|
||||
BMessage message(B_REFS_RECEIVED);
|
||||
message.AddRef("refs", item->Ref());
|
||||
|
||||
tracker.SendMessage(&message);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case M_REMOVE:
|
||||
{
|
||||
int32 index;
|
||||
while ((index = fList->CurrentSelection()) >= 0)
|
||||
{
|
||||
TListItem *item = (TListItem *) fList->ItemAt(index);
|
||||
fList->RemoveItem(index);
|
||||
|
||||
if (item->Component())
|
||||
{
|
||||
// remove the component from the mail
|
||||
TMailWindow *window = dynamic_cast<TMailWindow *>(Window());
|
||||
if (window && window->Mail())
|
||||
window->Mail()->RemoveComponent(item->Component());
|
||||
|
||||
(new BAlert("", MDR_DIALECT_CHOICE (
|
||||
"Removing enclosures from a forwarded mail is not yet implemented!\n"
|
||||
"It will not yet work correctly.",
|
||||
"転送メールから添付ファイルを削除する機能はまだ実装されていません。"),
|
||||
MDR_DIALECT_CHOICE ("OK","了解")))->Go();
|
||||
}
|
||||
else
|
||||
watch_node(item->NodeRef(), B_STOP_WATCHING, this);
|
||||
delete item;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case M_SELECT:
|
||||
fList->Select(0, fList->CountItems() - 1, true);
|
||||
break;
|
||||
|
||||
case B_SIMPLE_DATA:
|
||||
case B_REFS_RECEIVED:
|
||||
case REFS_RECEIVED:
|
||||
if (msg->HasRef("refs"))
|
||||
{
|
||||
bool badType = false;
|
||||
|
||||
int32 index = 0;
|
||||
entry_ref ref;
|
||||
while (msg->FindRef("refs", index++, &ref) == B_NO_ERROR)
|
||||
{
|
||||
BFile file(&ref, O_RDONLY);
|
||||
if (file.InitCheck() == B_OK && file.IsFile())
|
||||
{
|
||||
TListItem *item;
|
||||
for (int16 loop = 0; loop < fList->CountItems(); loop++)
|
||||
{
|
||||
item = (TListItem *) fList->ItemAt(loop);
|
||||
if (ref == *(item->Ref()))
|
||||
{
|
||||
fList->Select(loop);
|
||||
fList->ScrollToSelection();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
fList->AddItem(item = new TListItem(&ref));
|
||||
fList->Select(fList->CountItems() - 1);
|
||||
fList->ScrollToSelection();
|
||||
|
||||
watch_node(item->NodeRef(), B_WATCH_NAME, this);
|
||||
}
|
||||
else
|
||||
badType = true;
|
||||
}
|
||||
if (badType)
|
||||
{
|
||||
beep();
|
||||
(new BAlert("", MDR_DIALECT_CHOICE (
|
||||
"Only files can be added as enclosures.",
|
||||
"添付できるのは、ファイルのみです。"),
|
||||
MDR_DIALECT_CHOICE ("Ok","了解")))->Go();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case B_NODE_MONITOR:
|
||||
{
|
||||
int32 opcode;
|
||||
if (msg->FindInt32("opcode", &opcode) == B_NO_ERROR)
|
||||
{
|
||||
dev_t device;
|
||||
if (msg->FindInt32("device", &device) < B_OK)
|
||||
break;
|
||||
ino_t inode;
|
||||
if (msg->FindInt64("node", &inode) < B_OK)
|
||||
break;
|
||||
|
||||
for (int32 index = fList->CountItems();index-- > 0;)
|
||||
{
|
||||
TListItem *item = static_cast<TListItem *>(fList->ItemAt(index));
|
||||
|
||||
if (device == item->NodeRef()->device
|
||||
&& inode == item->NodeRef()->node)
|
||||
{
|
||||
if (opcode == B_ENTRY_REMOVED)
|
||||
{
|
||||
// don't hide the <missing enclosure> item
|
||||
|
||||
//fList->RemoveItem(index);
|
||||
//
|
||||
//watch_node(item->NodeRef(), B_STOP_WATCHING, this);
|
||||
//delete item;
|
||||
}
|
||||
else if (opcode == B_ENTRY_MOVED)
|
||||
{
|
||||
item->Ref()->device = device;
|
||||
msg->FindInt64("to directory", &item->Ref()->directory);
|
||||
|
||||
const char *name;
|
||||
msg->FindString("name", &name);
|
||||
item->Ref()->set_name(name);
|
||||
}
|
||||
|
||||
fList->InvalidateItem(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TEnclosuresView::Focus(bool focus)
|
||||
{
|
||||
if (fFocus != focus)
|
||||
{
|
||||
fFocus = focus;
|
||||
Draw(Frame());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TEnclosuresView::AddEnclosuresFromMail(BEmailMessage *mail)
|
||||
{
|
||||
for (int32 i = 0; i < mail->CountComponents(); i++)
|
||||
{
|
||||
BMailComponent *component = mail->GetComponent(i);
|
||||
if (component == mail->Body())
|
||||
continue;
|
||||
|
||||
BMailAttachment *attachment = dynamic_cast<BMailAttachment *>(component);
|
||||
if (attachment == NULL)
|
||||
continue;
|
||||
|
||||
fList->AddItem(new TListItem(component));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TListView::TListView(BRect rect, TEnclosuresView *view)
|
||||
: BListView(rect, "", B_MULTIPLE_SELECTION_LIST, B_FOLLOW_TOP | B_FOLLOW_LEFT_RIGHT),
|
||||
fParent(view)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TListView::AttachedToWindow()
|
||||
{
|
||||
BListView::AttachedToWindow();
|
||||
|
||||
BFont font = *be_plain_font;
|
||||
font.SetSize(FONT_SIZE);
|
||||
SetFont(&font);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TListView::MakeFocus(bool focus)
|
||||
{
|
||||
BListView::MakeFocus(focus);
|
||||
fParent->Focus(focus);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TListView::MouseDown(BPoint point)
|
||||
{
|
||||
int32 buttons;
|
||||
Looper()->CurrentMessage()->FindInt32("buttons",&buttons);
|
||||
|
||||
if (buttons & B_SECONDARY_MOUSE_BUTTON)
|
||||
{
|
||||
BFont font = *be_plain_font;
|
||||
font.SetSize(10);
|
||||
|
||||
BPopUpMenu menu("enclosure", false, false);
|
||||
menu.SetFont(&font);
|
||||
menu.AddItem(new BMenuItem(
|
||||
MDR_DIALECT_CHOICE ("Open Enclosure","添付ファイルを開く"),
|
||||
new BMessage(LIST_INVOKED)));
|
||||
menu.AddItem(new BMenuItem(
|
||||
MDR_DIALECT_CHOICE ("Remove Enclosure","添付ファイルを削除"),
|
||||
new BMessage(M_REMOVE)));
|
||||
|
||||
BPoint menuStart = ConvertToScreen(point);
|
||||
|
||||
BMenuItem *item;
|
||||
if ((item = menu.Go(menuStart)) != NULL)
|
||||
{
|
||||
if (item->Command() == LIST_INVOKED)
|
||||
{
|
||||
BMessage msg(LIST_INVOKED);
|
||||
msg.AddPointer("source",this);
|
||||
msg.AddInt32("index",IndexOf(point));
|
||||
Window()->PostMessage(&msg,fParent);
|
||||
}
|
||||
else
|
||||
{
|
||||
Select(IndexOf(point));
|
||||
Window()->PostMessage(item->Command(),fParent);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BListView::MouseDown(point);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TListView::KeyDown(const char *bytes, int32 numBytes)
|
||||
{
|
||||
BListView::KeyDown(bytes,numBytes);
|
||||
|
||||
if (numBytes == 1 && *bytes == B_DELETE)
|
||||
Window()->PostMessage(M_REMOVE, fParent);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TListItem::TListItem(entry_ref *ref)
|
||||
{
|
||||
fComponent = NULL;
|
||||
fRef = *ref;
|
||||
|
||||
BEntry entry(ref);
|
||||
entry.GetNodeRef(&fNodeRef);
|
||||
}
|
||||
|
||||
|
||||
TListItem::TListItem(BMailComponent *component)
|
||||
:
|
||||
fComponent(component)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TListItem::Update(BView *owner, const BFont *font)
|
||||
{
|
||||
BListItem::Update(owner, font);
|
||||
|
||||
if (Height() < 17) // mini icon height + 1
|
||||
SetHeight(17);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TListItem::DrawItem(BView *owner, BRect r, bool /* complete */)
|
||||
{
|
||||
if (IsSelected()) {
|
||||
owner->SetHighColor(180, 180, 180);
|
||||
owner->SetLowColor(180, 180, 180);
|
||||
} else {
|
||||
owner->SetHighColor(255, 255, 255);
|
||||
owner->SetLowColor(255, 255, 255);
|
||||
}
|
||||
owner->FillRect(r);
|
||||
owner->SetHighColor(0, 0, 0);
|
||||
|
||||
BFont font = *be_plain_font;
|
||||
font.SetSize(FONT_SIZE);
|
||||
owner->SetFont(&font);
|
||||
owner->MovePenTo(r.left + 24, r.bottom - 4);
|
||||
|
||||
if (fComponent) {
|
||||
// if it's already a mail component, we don't have an icon to
|
||||
// draw, and the entry_ref is invalid
|
||||
BMailAttachment *attachment = static_cast<BMailAttachment *>(fComponent);
|
||||
|
||||
char name[B_FILE_NAME_LENGTH * 2];
|
||||
if (attachment->FileName(name) < B_OK)
|
||||
strcpy(name, "unnamed");
|
||||
|
||||
BMimeType type;
|
||||
if (attachment->MIMEType(&type) == B_OK)
|
||||
sprintf(name + strlen(name), ", Type: %s", type.Type());
|
||||
|
||||
owner->DrawString(name);
|
||||
|
||||
BRect iconRect(0, 0, B_MINI_ICON - 1, B_MINI_ICON - 1);
|
||||
|
||||
BBitmap bitmap(iconRect, B_COLOR_8_BIT);
|
||||
if (GetTrackerIcon(type, &bitmap, B_MINI_ICON) == B_NO_ERROR) {
|
||||
BRect rect(r.left + 4, r.top + 1, r.left + 4 + 15, r.top + 1 + 15);
|
||||
owner->SetDrawingMode(B_OP_OVER);
|
||||
owner->DrawBitmap(&bitmap, iconRect, rect);
|
||||
owner->SetDrawingMode(B_OP_COPY);
|
||||
} else {
|
||||
// ToDo: find some nicer image for this :-)
|
||||
owner->SetHighColor(150, 150, 150);
|
||||
owner->FillEllipse(BRect(r.left + 8, r.top + 4, r.left + 16, r.top + 13));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BFile file(&fRef, O_RDONLY);
|
||||
BEntry entry(&fRef);
|
||||
BPath path;
|
||||
if (entry.GetPath(&path) == B_OK && file.InitCheck() == B_OK) {
|
||||
owner->DrawString(path.Path());
|
||||
|
||||
BNodeInfo info(&file);
|
||||
BRect sr(0, 0, B_MINI_ICON - 1, B_MINI_ICON - 1);
|
||||
|
||||
BBitmap bitmap(sr, B_COLOR_8_BIT);
|
||||
if (info.GetTrackerIcon(&bitmap, B_MINI_ICON) == B_NO_ERROR) {
|
||||
BRect dr(r.left + 4, r.top + 1, r.left + 4 + 15, r.top + 1 + 15);
|
||||
owner->SetDrawingMode(B_OP_OVER);
|
||||
owner->DrawBitmap(&bitmap, sr, dr);
|
||||
owner->SetDrawingMode(B_OP_COPY);
|
||||
}
|
||||
} else
|
||||
owner->DrawString("<missing enclosure>");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Enclosures.h
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef _ENCLOSURES_H
|
||||
#define _ENCLOSURES_H
|
||||
|
||||
#include <Box.h>
|
||||
#include <File.h>
|
||||
#include <ListView.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Path.h>
|
||||
#include <Point.h>
|
||||
#include <Rect.h>
|
||||
#include <ScrollView.h>
|
||||
#include <View.h>
|
||||
#include <Volume.h>
|
||||
|
||||
#include <MailMessage.h>
|
||||
|
||||
#define ENCLOSURES_HEIGHT 65
|
||||
|
||||
#define ENCLOSE_TEXT "Enclosures:"
|
||||
#define ENCLOSE_TEXT_H 7
|
||||
#define ENCLOSE_TEXT_V 3
|
||||
#define ENCLOSE_FIELD_V 3
|
||||
|
||||
class TListView;
|
||||
class TMailWindow;
|
||||
class TScrollView;
|
||||
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TEnclosuresView : public BView
|
||||
{
|
||||
public:
|
||||
TEnclosuresView(BRect, BRect);
|
||||
~TEnclosuresView();
|
||||
|
||||
virtual void Draw(BRect);
|
||||
virtual void MessageReceived(BMessage*);
|
||||
void Focus(bool);
|
||||
void AddEnclosuresFromMail(BEmailMessage *mail);
|
||||
|
||||
TListView *fList;
|
||||
|
||||
private:
|
||||
bool fFocus;
|
||||
float fOffset;
|
||||
TMailWindow *fWindow;
|
||||
};
|
||||
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TListView : public BListView
|
||||
{
|
||||
public:
|
||||
TListView(BRect, TEnclosuresView *);
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MakeFocus(bool);
|
||||
virtual void MouseDown(BPoint point);
|
||||
virtual void KeyDown(const char *bytes,int32 numBytes);
|
||||
|
||||
private:
|
||||
TEnclosuresView *fParent;
|
||||
};
|
||||
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TListItem : public BListItem
|
||||
{
|
||||
public:
|
||||
TListItem(entry_ref *);
|
||||
TListItem(BMailComponent *);
|
||||
|
||||
virtual void DrawItem(BView *, BRect, bool);
|
||||
virtual void Update(BView *, const BFont *);
|
||||
|
||||
BMailComponent *Component() { return fComponent; };
|
||||
entry_ref *Ref() { return &fRef; }
|
||||
node_ref *NodeRef() { return &fNodeRef; }
|
||||
|
||||
private:
|
||||
BMailComponent *fComponent;
|
||||
entry_ref fRef;
|
||||
node_ref fNodeRef;
|
||||
};
|
||||
|
||||
#endif // #ifndef _ENCLOSURES_H
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _FIELD_MSG_H
|
||||
#define _FIELD_MSG_H
|
||||
|
||||
enum {
|
||||
FIELD_CHANGED = 0x0800
|
||||
};
|
||||
|
||||
enum {
|
||||
FIELD_TO = 0x01,
|
||||
FIELD_SUBJECT = 0x02,
|
||||
FIELD_CC = 0x04,
|
||||
FIELD_BCC = 0x08,
|
||||
FIELD_BODY = 0x10
|
||||
};
|
||||
|
||||
#endif // #ifndef _FIELD_MSG_H
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
// ===========================================================================
|
||||
// FindWindow.cpp
|
||||
// Copyright 1996 by Peter Barrett, All rights reserved.
|
||||
// ===========================================================================
|
||||
|
||||
#include "FindWindow.h"
|
||||
#include "Mail.h"
|
||||
|
||||
#include <TextView.h>
|
||||
#include <Button.h>
|
||||
#include <Application.h>
|
||||
#include <String.h>
|
||||
#include <Box.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
void TextBevel(BView& view, BRect r);
|
||||
|
||||
// ============================================================================
|
||||
void TextBevel(BView& view, BRect r)
|
||||
{
|
||||
r.InsetBy(-1,-1);
|
||||
view.SetHighColor(96,96,96);
|
||||
view.MovePenTo(r.left,r.bottom);
|
||||
view.StrokeLine(BPoint(r.left,r.top));
|
||||
view.StrokeLine(BPoint(r.right,r.top));
|
||||
view.SetHighColor(216,216,216);
|
||||
view.StrokeLine(BPoint(r.right,r.bottom));
|
||||
view.StrokeLine(BPoint(r.left,r.bottom));
|
||||
r.InsetBy(-1,-1);
|
||||
view.SetHighColor(192,192,192);
|
||||
view.MovePenTo(r.left,r.bottom);
|
||||
view.StrokeLine(BPoint(r.left,r.top));
|
||||
view.StrokeLine(BPoint(r.right,r.top));
|
||||
view.SetHighColor(255,255,255);
|
||||
view.StrokeLine(BPoint(r.right,r.bottom));
|
||||
view.StrokeLine(BPoint(r.left,r.bottom));
|
||||
view.SetHighColor(0,0,0);
|
||||
}
|
||||
|
||||
// FindWindow is modeless...
|
||||
|
||||
#define FINDBUTTON 'find'
|
||||
|
||||
static BString sPreviousFind = "";
|
||||
|
||||
FindWindow* FindWindow::mFindWindow = NULL;
|
||||
BRect FindWindow::mLastPosition(BRect(100,300,300,374));
|
||||
|
||||
void FindWindow::DoFind(BWindow *window, const char *text)
|
||||
{
|
||||
if (window == NULL) {
|
||||
long i=0;
|
||||
while ((bool)(window = be_app->WindowAt(i++))) { // Send the text to a waiting window
|
||||
if (window != mFindWindow)
|
||||
if (dynamic_cast<TMailWindow *>(window) != NULL)
|
||||
break; // Found a window
|
||||
}
|
||||
}
|
||||
|
||||
/* ask that window who is in the front */
|
||||
window = dynamic_cast<TMailWindow *>(window)->FrontmostWindow();
|
||||
if (window == NULL)
|
||||
return;
|
||||
|
||||
// Found a window, send a find message
|
||||
|
||||
if (!window->Lock())
|
||||
return;
|
||||
BView *focus = window->FindView("m_content");
|
||||
window->Unlock();
|
||||
|
||||
if (focus)
|
||||
{
|
||||
BMessage msg(M_FIND);
|
||||
msg.AddString("findthis",text);
|
||||
window->PostMessage(&msg, focus);
|
||||
}
|
||||
}
|
||||
|
||||
FindPanel::FindPanel(BRect rect)
|
||||
: BBox(rect, "FindPanel", B_FOLLOW_LEFT_RIGHT,
|
||||
B_WILL_DRAW)
|
||||
{
|
||||
BRect r = Bounds();
|
||||
r.InsetBy(8,8);
|
||||
r.bottom -= 44;
|
||||
BRect text = r;
|
||||
text.OffsetTo(B_ORIGIN);
|
||||
text.InsetBy(2,2);
|
||||
|
||||
mBTextView = new DialogTextView(r,"BTextView",text,B_FOLLOW_ALL,B_WILL_DRAW);
|
||||
mBTextView->DisallowChar('\n');
|
||||
mBTextView->SetText(sPreviousFind.String());
|
||||
mBTextView->MakeFocus();
|
||||
AddChild(mBTextView);
|
||||
|
||||
mFindButton = new BButton(BRect(0,0,90,20),"FINDBUTTON",
|
||||
MDR_DIALECT_CHOICE ("Find","検索"),
|
||||
new BMessage(FINDBUTTON),B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
|
||||
AddChild(mFindButton);
|
||||
r = mFindButton->Bounds();
|
||||
|
||||
mFindButton->MoveTo(Bounds().right - r.Width() - 8,
|
||||
Bounds().bottom - r.Height() - 8);
|
||||
mFindButton->SetEnabled(sPreviousFind.Length());
|
||||
}
|
||||
|
||||
FindPanel::~FindPanel()
|
||||
{
|
||||
sPreviousFind = mBTextView->Text();
|
||||
}
|
||||
|
||||
void FindPanel::AttachedToWindow()
|
||||
{
|
||||
BView::AttachedToWindow();
|
||||
SetViewColor(216,216,216);
|
||||
Window()->SetDefaultButton(mFindButton);
|
||||
mFindButton->SetTarget(this);
|
||||
mBTextView->MakeFocus(true);
|
||||
mBTextView->SelectAll();
|
||||
}
|
||||
|
||||
void FindPanel::MouseDown(BPoint point)
|
||||
{
|
||||
Window()->Activate();
|
||||
BView::MouseDown(point);
|
||||
}
|
||||
|
||||
void FindPanel::Draw(BRect)
|
||||
{
|
||||
TextBevel(*this,mBTextView->Frame());
|
||||
}
|
||||
|
||||
void FindPanel::KeyDown(const char *, int32)
|
||||
{
|
||||
int32 length = mBTextView->TextLength();
|
||||
bool enabled = mFindButton->IsEnabled();
|
||||
|
||||
if (length > 0 && !enabled)
|
||||
mFindButton->SetEnabled(true);
|
||||
else if (length == 0 && enabled)
|
||||
mFindButton->SetEnabled(false);
|
||||
}
|
||||
|
||||
void FindPanel::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case FINDBUTTON:
|
||||
Find();
|
||||
break;
|
||||
default:
|
||||
BView::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void FindPanel::Find()
|
||||
{
|
||||
mBTextView->SelectAll();
|
||||
const char *text = mBTextView->Text();
|
||||
if (text == NULL || text[0] == 0) return;
|
||||
|
||||
BWindow *window = NULL;
|
||||
long i=0;
|
||||
while ((bool)(window = be_app->WindowAt(i++))) { // Send the text to a waiting window
|
||||
if (window != FindWindow::mFindWindow)
|
||||
break; // Found a window
|
||||
}
|
||||
|
||||
if (window)
|
||||
FindWindow::DoFind(window, text);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
|
||||
FindWindow::FindWindow()
|
||||
: BWindow(FindWindow::mLastPosition,
|
||||
MDR_DIALECT_CHOICE ("Find","検索"),
|
||||
B_FLOATING_WINDOW,
|
||||
B_NOT_RESIZABLE | B_NOT_ZOOMABLE | B_WILL_ACCEPT_FIRST_CLICK)
|
||||
{
|
||||
mFindPanel = new FindPanel(Bounds());
|
||||
AddChild(mFindPanel);
|
||||
mFindWindow = this;
|
||||
Show();
|
||||
}
|
||||
|
||||
FindWindow::~FindWindow()
|
||||
{
|
||||
FindWindow::mLastPosition = Frame();
|
||||
mFindWindow = NULL;
|
||||
}
|
||||
|
||||
void FindWindow::Find(BWindow *window)
|
||||
{
|
||||
// eliminate unused parameter warning
|
||||
(void)window;
|
||||
|
||||
if (mFindWindow == NULL) {
|
||||
mFindWindow = new FindWindow();
|
||||
} else
|
||||
mFindWindow->Activate();
|
||||
}
|
||||
|
||||
void FindWindow::FindAgain(BWindow *window)
|
||||
{
|
||||
if (mFindWindow) {
|
||||
mFindWindow->Lock();
|
||||
mFindWindow->mFindPanel->Find();
|
||||
mFindWindow->Unlock();
|
||||
} else if (sPreviousFind.Length() != 0)
|
||||
DoFind(window, sPreviousFind.String());
|
||||
else
|
||||
Find(window);
|
||||
}
|
||||
|
||||
void FindWindow::SetFindString(const char *string)
|
||||
{
|
||||
sPreviousFind = string;
|
||||
}
|
||||
|
||||
const char *FindWindow::GetFindString()
|
||||
{
|
||||
return sPreviousFind.String();
|
||||
}
|
||||
|
||||
|
||||
DialogTextView::DialogTextView(BRect frame, const char *name, BRect textRect,
|
||||
uint32 resizingMode, uint32 flags)
|
||||
: BTextView(frame, name, textRect, resizingMode, flags)
|
||||
{
|
||||
}
|
||||
|
||||
void DialogTextView::KeyDown(const char *bytes, int32 numBytes)
|
||||
{
|
||||
BTextView::KeyDown(bytes, numBytes);
|
||||
if (Parent())
|
||||
Parent()->KeyDown(bytes, numBytes);
|
||||
}
|
||||
|
||||
void DialogTextView::MouseDown(BPoint point)
|
||||
{
|
||||
Window()->Activate();
|
||||
BTextView::MouseDown(point);
|
||||
}
|
||||
|
||||
void DialogTextView::InsertText(const char *inText, int32 inLength, int32 inOffset,
|
||||
const text_run_array *inRuns)
|
||||
{
|
||||
BTextView::InsertText(inText, inLength, inOffset, inRuns);
|
||||
if (Parent())
|
||||
Parent()->KeyDown(NULL, 0);
|
||||
}
|
||||
|
||||
void DialogTextView::DeleteText(int32 fromOffset, int32 toOffset)
|
||||
{
|
||||
BTextView::DeleteText(fromOffset, toOffset);
|
||||
if (Parent())
|
||||
Parent()->KeyDown(NULL, 0);
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
// ===========================================================================
|
||||
// FindWindow.h
|
||||
// Copyright 1996 by Peter Barrett, All rights reserved.
|
||||
// ===========================================================================
|
||||
|
||||
#ifndef _FINDWINDOW_H
|
||||
#define _FINDWINDOW_H
|
||||
|
||||
#include <AppDefs.h>
|
||||
#include <Box.h>
|
||||
#include <TextView.h>
|
||||
#include <Window.h>
|
||||
|
||||
class FindPanel;
|
||||
|
||||
// ============================================================================
|
||||
// Floating find window, just one of them.....
|
||||
|
||||
class FindWindow : public BWindow {
|
||||
friend class FindPanel;
|
||||
public:
|
||||
FindWindow();
|
||||
virtual ~FindWindow();
|
||||
|
||||
static void FindAgain(BWindow *window);
|
||||
static void Find(BWindow *window);
|
||||
static bool IsFindWindowOpen() {return mFindWindow;}
|
||||
static void Close()
|
||||
{ if (mFindWindow) mFindWindow->PostMessage(B_QUIT_REQUESTED); }
|
||||
static void SetFindString(const char *string);
|
||||
static const char* GetFindString();
|
||||
|
||||
protected:
|
||||
static void DoFind(BWindow *window, const char *text);
|
||||
|
||||
static FindWindow* mFindWindow;
|
||||
FindPanel* mFindPanel;
|
||||
static BRect mLastPosition;
|
||||
};
|
||||
|
||||
class FindPanel : public BBox {
|
||||
public:
|
||||
FindPanel(BRect rect);
|
||||
virtual ~FindPanel();
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void KeyDown(const char *bytes, int32 numBytes);
|
||||
void Find();
|
||||
virtual void MouseDown(BPoint point);
|
||||
|
||||
protected:
|
||||
BButton* mFindButton;
|
||||
BTextView* mBTextView;
|
||||
};
|
||||
|
||||
|
||||
class DialogTextView : public BTextView {
|
||||
public:
|
||||
DialogTextView(BRect frame, const char *name, BRect textRect,
|
||||
uint32 resizingMode, uint32 flags);
|
||||
virtual void KeyDown(const char *bytes, int32 numBytes);
|
||||
virtual void MouseDown(BPoint point);
|
||||
virtual void InsertText(const char *inText, int32 inLength,
|
||||
int32 inOffset, const text_run_array *inRuns);
|
||||
virtual void DeleteText(int32 fromOffset, int32 toOffset);
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
|
||||
#endif // #ifndef _FINDWINDOW_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Header.h
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef _HEADER_H
|
||||
#define _HEADER_H
|
||||
|
||||
#include <fs_attr.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Point.h>
|
||||
#include <Rect.h>
|
||||
#include <TextControl.h>
|
||||
#include <View.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "ComboBox.h"
|
||||
|
||||
#define TO_TEXT "To:"
|
||||
#define FROM_TEXT "From:"
|
||||
#define ENCODING_TEXT "Encoding:"
|
||||
#define DECODING_TEXT "Decoding:"
|
||||
#define TO_FIELD_H 39
|
||||
#define FROM_FIELD_H 31
|
||||
#define TO_FIELD_V 7
|
||||
#define TO_FIELD_WIDTH 270
|
||||
#define FROM_FIELD_WIDTH 280
|
||||
#define TO_FIELD_HEIGHT 16
|
||||
#define FIELD_HEIGHT 24
|
||||
|
||||
#define ACCOUNT_TEXT "Account:"
|
||||
#define ACCOUNT_FIELD_WIDTH 165
|
||||
|
||||
#define SUBJECT_TEXT "Subject:"
|
||||
#define SUBJECT_FIELD_H 18
|
||||
#define SUBJECT_FIELD_V 33
|
||||
#define SUBJECT_FIELD_WIDTH 270
|
||||
#define SUBJECT_FIELD_HEIGHT 16
|
||||
|
||||
#define CC_TEXT "CC:"
|
||||
#define CC_FIELD_H 40
|
||||
#define CC_FIELD_V 58
|
||||
#define CC_FIELD_WIDTH 192
|
||||
#define CC_FIELD_HEIGHT 16
|
||||
|
||||
#define BCC_TEXT "BCC:"
|
||||
#define BCC_FIELD_H 268
|
||||
#define BCC_FIELD_V 58
|
||||
#define BCC_FIELD_WIDTH 197
|
||||
#define BCC_FIELD_HEIGHT 16
|
||||
|
||||
class TTextControl;
|
||||
class BFile;
|
||||
class BMenuField;
|
||||
class BMenuItem;
|
||||
class BPopupMenu;
|
||||
class QPopupMenu;
|
||||
|
||||
//====================================================================
|
||||
|
||||
class THeaderView : public BBox
|
||||
{
|
||||
public:
|
||||
THeaderView(BRect, BRect, bool incoming, BEmailMessage *mail, bool resending, uint32 defaultCharacterSet);
|
||||
|
||||
virtual void MessageReceived(BMessage *);
|
||||
virtual void AttachedToWindow(void);
|
||||
status_t LoadMessage(BEmailMessage *);
|
||||
|
||||
BPopUpMenu *fAccountMenu;
|
||||
BPopUpMenu *fEncodingMenu;
|
||||
int32 fChain;
|
||||
TTextControl *fAccountTo;
|
||||
TTextControl *fAccount;
|
||||
TTextControl *fBcc;
|
||||
TTextControl *fCc;
|
||||
TTextControl *fSubject;
|
||||
TTextControl *fTo;
|
||||
BStringView *fDate;
|
||||
bool fIncoming;
|
||||
uint32 fCharacterSetUserSees;
|
||||
|
||||
private:
|
||||
void InitEmailCompletion();
|
||||
void InitGroupCompletion();
|
||||
|
||||
bool fResending;
|
||||
QPopupMenu *fBccMenu;
|
||||
QPopupMenu *fCcMenu;
|
||||
QPopupMenu *fToMenu;
|
||||
BDefaultChoiceList fEmailList;
|
||||
};
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TTextControl : public BComboBox
|
||||
{
|
||||
public:
|
||||
TTextControl(BRect, char*, BMessage*, bool, bool, int32 resizingMode = B_FOLLOW_NONE);
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage*);
|
||||
|
||||
// returns focus for the text view
|
||||
bool HasFocus();
|
||||
|
||||
private:
|
||||
bool fIncoming;
|
||||
bool fResending;
|
||||
char fLabel[100];
|
||||
int32 fCommand;
|
||||
};
|
||||
|
||||
#endif /* _HEADER_H */
|
||||
@@ -0,0 +1,24 @@
|
||||
SubDir OBOS_TOP src apps bemail ;
|
||||
|
||||
UsePrivateHeaders mail ;
|
||||
|
||||
AddResources BeMail : BeMail.rsrc ;
|
||||
App BeMail :
|
||||
BmapButton.cpp
|
||||
ButtonBar.cpp
|
||||
ComboBox.cpp
|
||||
Content.cpp
|
||||
Enclosures.cpp
|
||||
FindWindow.cpp
|
||||
Header.cpp
|
||||
Mail.cpp
|
||||
Prefs.cpp
|
||||
QueryMenu.cpp
|
||||
Signature.cpp
|
||||
Status.cpp
|
||||
Utilities.cpp
|
||||
WIndex.cpp
|
||||
Words.cpp
|
||||
KUndoBuffer.cpp ;
|
||||
|
||||
LinkSharedOSLibs BeMail : be mail tracker stdc++.r4 ;
|
||||
@@ -0,0 +1,321 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <memory.h>
|
||||
#include "KUndoBuffer.h"
|
||||
|
||||
|
||||
/*
|
||||
KUndoItem
|
||||
KUndoBuffer に格納される Undo/Redo 情報を記憶するクラス
|
||||
(The class which remembers the Undo/Redo information which is housed in the KUndoBuffer)
|
||||
*/
|
||||
KUndoItem::KUndoItem(const char *redo_text,
|
||||
int32 length,
|
||||
int32 offset,
|
||||
undo_type history,
|
||||
int32 cursor_pos)
|
||||
{
|
||||
Offset = offset;
|
||||
Length = length;
|
||||
History = history;
|
||||
CursorPos = cursor_pos;
|
||||
|
||||
if (redo_text!=NULL) {
|
||||
RedoText = (char *)malloc(length);
|
||||
memcpy(RedoText, redo_text, length);
|
||||
if (RedoText!=NULL) {
|
||||
Status = B_OK;
|
||||
} else {
|
||||
Status = B_ERROR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KUndoItem::~KUndoItem()
|
||||
{
|
||||
free(RedoText);
|
||||
}
|
||||
|
||||
status_t
|
||||
KUndoItem::InitCheck()
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
void
|
||||
KUndoItem::Merge(const char *text, int32 length)
|
||||
{
|
||||
RedoText = (char *)realloc(RedoText, Length + length);
|
||||
memcpy(&RedoText[Length], text, length);
|
||||
Length += length;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
KUndoBuffer
|
||||
Undo/Redo情報リストを管理するクラス。
|
||||
(The class which manages the Undo/Redo information list.)
|
||||
このクラス自体は、BTextViewに影響を及ぼすものではない。
|
||||
(This class itself is not something which exerts influence on the BTextView.)
|
||||
あくまで、アプリケーションがUndo/Redoを実装するための補助にすぎない。
|
||||
(To the last, it is no more than an assistance because application mounts the Undo/Redo.)
|
||||
*/
|
||||
KUndoBuffer::KUndoBuffer():BList(1024)
|
||||
{
|
||||
FIndex = 0;
|
||||
Off();
|
||||
FNewItem = true;
|
||||
}
|
||||
|
||||
KUndoBuffer::~KUndoBuffer()
|
||||
{
|
||||
MakeEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
Undo情報を追加する。
|
||||
(Undo information is added.)
|
||||
リスト途中に追加したら、以降はRedoの必要がなくなるため、
|
||||
追加位置以降のUndo情報があれば削除する。
|
||||
(When it adds on the list middle, if later because necessity of the Redo is
|
||||
gone, there is Undo information after the additional position, it deletes.)
|
||||
*/
|
||||
bool
|
||||
KUndoBuffer::AddItem(KUndoItem *item, int32 index)
|
||||
{
|
||||
for (int32 i=CountItems()-1; i>=index; i--) {
|
||||
RemoveItem(i);
|
||||
}
|
||||
return AddItem(item);
|
||||
}
|
||||
|
||||
bool
|
||||
KUndoBuffer::AddItem(KUndoItem *item)
|
||||
{
|
||||
return BList::AddItem(item);
|
||||
}
|
||||
|
||||
void
|
||||
KUndoBuffer::MakeEmpty(void)
|
||||
{
|
||||
for(int32 i=CountItems()-1; i>=0;i--) {
|
||||
RemoveItem(i);
|
||||
}
|
||||
}
|
||||
|
||||
KUndoItem *
|
||||
KUndoBuffer::RemoveItem(int32 index)
|
||||
{
|
||||
if (FIndex>=CountItems()) FIndex--;
|
||||
delete this->ItemAt(index);
|
||||
return (KUndoItem *)BList::RemoveItem(index);
|
||||
}
|
||||
|
||||
KUndoItem *
|
||||
KUndoBuffer::ItemAt(int32 index) const
|
||||
{
|
||||
return (KUndoItem *)BList::ItemAt(index);
|
||||
}
|
||||
|
||||
/*
|
||||
Off() 呼び出し後は、On()を実行しないとUndo情報追加を行わない。
|
||||
(Unless OFF () it calls after, ON () executes, Undo information addition is not done.)
|
||||
*/
|
||||
void
|
||||
KUndoBuffer::On()
|
||||
{
|
||||
FNoTouch = false;
|
||||
}
|
||||
|
||||
void
|
||||
KUndoBuffer::Off()
|
||||
{
|
||||
FNoTouch = true;
|
||||
}
|
||||
|
||||
status_t
|
||||
KUndoBuffer::NewUndo(const char *text, int32 length, int32 offset, undo_type history, int32 cursor_pos)
|
||||
{
|
||||
KUndoItem *NewUndoItem = new KUndoItem(text, length, offset, history, cursor_pos);
|
||||
status_t status = NewUndoItem->InitCheck();
|
||||
if ( status != B_OK) {
|
||||
delete NewUndoItem;
|
||||
return status;
|
||||
}
|
||||
AddItem(NewUndoItem, FIndex);
|
||||
FIndex++;
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
Undo情報をリストに追加する。
|
||||
(Undo information is added to the list.)
|
||||
*/
|
||||
status_t
|
||||
KUndoBuffer::AddUndo(const char *text, int32 length, int32 offset, undo_type history, int32 cursor_pos)
|
||||
{
|
||||
if (FNoTouch) return B_OK;
|
||||
|
||||
status_t status;
|
||||
|
||||
// 新たな追加予約がある(FNewItem)か、現在位置(FIndex)が最後尾でないか、Undoリストが空であれば
|
||||
// 新たにUndo情報を追加する。
|
||||
// (There is new additional reservation, if (the FNewItem), 現在位置 (the
|
||||
// FIndex) is not the last tail or and the Undo list is the sky, Undo
|
||||
// information is added anew.)
|
||||
// さもなくば、最後尾Undo情報に結合すべきなら結合し、そうでなければ
|
||||
// やはり新たにUndo情報を追加する。
|
||||
// (Without, if it should connect to last tail Undo information, if it
|
||||
// connects and so is not Undo information is added after all anew.)
|
||||
if (FNewItem || (FIndex < CountItems()) || (CountItems()==0)) {
|
||||
status = NewUndo(text, length, offset, history, cursor_pos);
|
||||
FNewItem = false;
|
||||
} else {
|
||||
KUndoItem *CurrentUndoItem;
|
||||
CurrentUndoItem = ItemAt(FIndex-1);
|
||||
if (CurrentUndoItem!=NULL) {
|
||||
int32 c_length = CurrentUndoItem->Length;
|
||||
int32 c_offset = CurrentUndoItem->Offset;
|
||||
undo_type c_history = CurrentUndoItem->History;
|
||||
if (c_history == history) {
|
||||
switch(c_history) {
|
||||
case K_INSERTED:
|
||||
case K_REPLACED:
|
||||
if ((c_offset + c_length) == offset) {
|
||||
CurrentUndoItem->Merge(text, length);
|
||||
} else {
|
||||
status = NewUndo(text, length, offset, history, cursor_pos);
|
||||
}
|
||||
break;
|
||||
case K_DELETED:
|
||||
status = NewUndo(text, length, offset, history, cursor_pos);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
status = NewUndo(text, length, offset, history, cursor_pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// Enterを押した、矢印キーを押した等、Undoを一区切り起きたい場合に
|
||||
// MakeNewUndoItem()を呼び出す。
|
||||
// (The Enter was pushed, one you divide the Undo and the MakeNewUndoItem ()
|
||||
// you call when we would like to occur e.g., the arrow key was pushed.)
|
||||
status_t
|
||||
KUndoBuffer::MakeNewUndoItem()
|
||||
{
|
||||
if (FIndex >= CountItems()) {
|
||||
FNewItem = true;
|
||||
return B_OK;
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Undo() Redo() は、FIndexをいったりきたりしながら
|
||||
// 挿入位置、文字長、復元テキスト等の情報を返す。
|
||||
// (The Undo () the Redo (), the FIndex, while going back and forth, it
|
||||
// returns the information of insertion position, letter length and the
|
||||
// restoration text et cetera.)
|
||||
status_t
|
||||
KUndoBuffer::Undo(char **text,
|
||||
int32 *length,
|
||||
int32 *offset,
|
||||
undo_type *history,
|
||||
int32 *cursor_pos)
|
||||
{
|
||||
KUndoItem *undoItem;
|
||||
status_t status;
|
||||
|
||||
if (FIndex>0) {
|
||||
undoItem = ItemAt(FIndex-1);
|
||||
if (undoItem!=NULL) {
|
||||
*text = undoItem->RedoText;
|
||||
*length = undoItem->Length;
|
||||
*offset = undoItem->Offset;
|
||||
*history = undoItem->History;
|
||||
*cursor_pos = undoItem->CursorPos + undoItem->Length;
|
||||
status = B_OK;
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
FIndex--;
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
status_t
|
||||
KUndoBuffer::Redo(char **text,
|
||||
int32 *length,
|
||||
int32 *offset,
|
||||
undo_type *history,
|
||||
int32 *cursor_pos,
|
||||
bool *replaced)
|
||||
{
|
||||
KUndoItem *undoItem;
|
||||
status_t status;
|
||||
|
||||
if (FIndex < CountItems()) {
|
||||
undoItem = ItemAt(FIndex);
|
||||
if (undoItem!=NULL) {
|
||||
*text = undoItem->RedoText;
|
||||
*length = undoItem->Length;
|
||||
*offset = undoItem->Offset;
|
||||
*history = undoItem->History;
|
||||
*cursor_pos = undoItem->CursorPos;
|
||||
if ((FIndex+1) < CountItems()) {
|
||||
*replaced = ItemAt(FIndex+1)->History==K_REPLACED;
|
||||
} else {
|
||||
*replaced = false;
|
||||
}
|
||||
status = B_OK;
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
FIndex++;
|
||||
} else {
|
||||
status = B_ERROR;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// Undo/Redo 情報を標準出力に書きだす。
|
||||
// (It starts writing Undo/Redo information on standard output.)
|
||||
// デバッグ時のみ。
|
||||
// (Only when debugging.)
|
||||
void
|
||||
KUndoBuffer::PrintToStream()
|
||||
{
|
||||
for(int32 i=0; i<CountItems(); i++) {
|
||||
KUndoItem *item = ItemAt(i);
|
||||
printf("%3.3d ", (int)i);
|
||||
switch(item->History) {
|
||||
case K_INSERTED:
|
||||
printf("INSERTED ");
|
||||
break;
|
||||
case K_DELETED:
|
||||
printf("DELETED ");
|
||||
break;
|
||||
case K_REPLACED:
|
||||
printf("REPLACED ");
|
||||
break;
|
||||
}
|
||||
printf("Offset = %d ", (int)item->Offset);
|
||||
printf("Length = %d ", (int)item->Length);
|
||||
printf("CursorPos = %d ", (int)item->CursorPos);
|
||||
printf("RedoText = '");
|
||||
for(int32 j=0;j<item->Length;j++) {
|
||||
uchar c = (uchar)item->RedoText[j];
|
||||
if (c >= 0x20) {
|
||||
printf("%c", c);
|
||||
} else {
|
||||
printf("?");
|
||||
}
|
||||
}
|
||||
printf("'\n");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#include <List.h>
|
||||
|
||||
enum undo_type{
|
||||
K_INSERTED, // 文字挿入時 (At the time of character insertion)
|
||||
K_DELETED, // 削除時 (When deleting)
|
||||
K_REPLACED // 置換、つまり削除→挿入の連続動作時 (Substitution, in other words deletion -> at the time of continuous action of insertion)
|
||||
};
|
||||
|
||||
class KUndoItem
|
||||
{
|
||||
public:
|
||||
KUndoItem(const char *text,
|
||||
int32 length,
|
||||
int32 offset,
|
||||
undo_type history,
|
||||
int32 cursor_pos);
|
||||
~KUndoItem();
|
||||
void Merge(const char *text, int32 length);
|
||||
status_t InitCheck();
|
||||
|
||||
int32 Offset; // 開始位置 (Start position)
|
||||
int32 Length; // 文字長 (Letter length)
|
||||
char *RedoText; // 復元すべきテキスト (The text which it should reconstruct)
|
||||
undo_type History; // 操作区分 (Operation division)
|
||||
int32 CursorPos; // カーソル位置 (Cursor position)
|
||||
|
||||
private:
|
||||
status_t Status;
|
||||
};
|
||||
|
||||
class KUndoBuffer:public BList
|
||||
{
|
||||
public:
|
||||
KUndoBuffer();
|
||||
~KUndoBuffer();
|
||||
|
||||
bool AddItem(KUndoItem *item, int32 index);
|
||||
bool AddItem(KUndoItem *item);
|
||||
void MakeEmpty(void);
|
||||
KUndoItem *RemoveItem(int32 index);
|
||||
KUndoItem *ItemAt(int32 index) const;
|
||||
|
||||
|
||||
status_t AddUndo(const char *redo_text,
|
||||
int32 length,
|
||||
int32 offset,
|
||||
undo_type history,
|
||||
int32 cursor_pos);
|
||||
status_t MakeNewUndoItem();
|
||||
status_t Undo(char **text,
|
||||
int32 *length,
|
||||
int32 *offset,
|
||||
undo_type *history,
|
||||
int32 *cursor_pos);
|
||||
status_t Redo(char **text,
|
||||
int32 *length,
|
||||
int32 *offset,
|
||||
undo_type *history,
|
||||
int32 *cursor_pos,
|
||||
bool *replaced);
|
||||
|
||||
void PrintToStream();
|
||||
|
||||
void On();
|
||||
void Off();
|
||||
|
||||
private:
|
||||
int32 FIndex;
|
||||
bool FNewItem;
|
||||
bool FNoTouch;
|
||||
|
||||
status_t NewUndo(const char *text,
|
||||
int32 length,
|
||||
int32 offset,
|
||||
undo_type history,
|
||||
int32 cursor_pos);
|
||||
};
|
||||
@@ -0,0 +1,31 @@
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,350 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Mail.h
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef _MAIL_H
|
||||
#define _MAIL_H
|
||||
|
||||
#include <Application.h>
|
||||
#include <Font.h>
|
||||
#include <Menu.h>
|
||||
#include <MenuBar.h>
|
||||
#include <MessageFilter.h>
|
||||
#include <Point.h>
|
||||
#include <PopUpMenu.h>
|
||||
#include <Rect.h>
|
||||
#include <Window.h>
|
||||
#include <Entry.h>
|
||||
|
||||
#include <mail_encoding.h>
|
||||
|
||||
#define MAX_DICTIONARIES 8
|
||||
#define TITLE_BAR_HEIGHT 25
|
||||
#define WIND_WIDTH 457
|
||||
#define WIND_HEIGHT 400
|
||||
#define RIGHT_BOUNDARY 8191
|
||||
#define SEPARATOR_MARGIN 7
|
||||
#define VIEW_COLOR 216
|
||||
#define FONT_SIZE 11.0
|
||||
#define QUOTE "> "
|
||||
|
||||
enum MESSAGES {
|
||||
REFS_RECEIVED = 64,
|
||||
LIST_INVOKED,
|
||||
WINDOW_CLOSED,
|
||||
CHANGE_FONT,
|
||||
RESET_BUTTONS,
|
||||
PREFS_CHANGED,
|
||||
CHARSET_CHOICE_MADE
|
||||
};
|
||||
|
||||
enum TEXT {
|
||||
SUBJECT_FIELD = REFS_RECEIVED + 64,
|
||||
TO_FIELD,
|
||||
ENCLOSE_FIELD,
|
||||
CC_FIELD,
|
||||
BCC_FIELD,
|
||||
NAME_FIELD
|
||||
};
|
||||
|
||||
enum MENUS {
|
||||
/* app */
|
||||
M_NEW = SUBJECT_FIELD + 64,
|
||||
M_PREFS,
|
||||
M_EDIT_SIGNATURE,
|
||||
M_FONT,
|
||||
M_STYLE,
|
||||
M_SIZE,
|
||||
M_BEGINNER,
|
||||
M_EXPERT,
|
||||
/* file */
|
||||
M_REPLY,
|
||||
M_REPLY_TO_SENDER,
|
||||
M_REPLY_ALL,
|
||||
M_FORWARD,
|
||||
M_FORWARD_WITHOUT_ATTACHMENTS,
|
||||
M_RESEND,
|
||||
M_COPY_TO_NEW,
|
||||
M_HEADER,
|
||||
M_RAW,
|
||||
M_SEND_NOW,
|
||||
M_SAVE_AS_DRAFT,
|
||||
M_SAVE,
|
||||
M_PRINT_SETUP,
|
||||
M_PRINT,
|
||||
M_DELETE,
|
||||
M_DELETE_PREV,
|
||||
M_DELETE_NEXT,
|
||||
M_CLOSE_READ,
|
||||
M_CLOSE_SAVED,
|
||||
M_CLOSE_SAME,
|
||||
M_CLOSE_CUSTOM,
|
||||
M_STATUS,
|
||||
M_OPEN_MAIL_BOX,
|
||||
M_OPEN_MAIL_FOLDER,
|
||||
/* edit */
|
||||
M_SELECT,
|
||||
M_QUOTE,
|
||||
M_REMOVE_QUOTE,
|
||||
M_CHECK_SPELLING,
|
||||
M_SIGNATURE,
|
||||
M_RANDOM_SIG,
|
||||
M_SIG_MENU,
|
||||
M_FIND,
|
||||
M_FIND_AGAIN,
|
||||
/* encls */
|
||||
M_ADD,
|
||||
M_REMOVE,
|
||||
M_OPEN,
|
||||
M_COPY,
|
||||
/* nav */
|
||||
M_NEXTMSG,
|
||||
M_PREVMSG,
|
||||
M_SAVE_POSITION,
|
||||
/* Spam GUI button and menu items. Order is important. */
|
||||
M_SPAM_BUTTON,
|
||||
M_TRAIN_SPAM_AND_DELETE,
|
||||
M_TRAIN_SPAM,
|
||||
M_UNTRAIN,
|
||||
M_TRAIN_GENUINE,
|
||||
|
||||
M_REDO
|
||||
};
|
||||
|
||||
enum USER_LEVEL {
|
||||
L_BEGINNER = 0,
|
||||
L_EXPERT
|
||||
};
|
||||
|
||||
enum WINDOW_TYPES {
|
||||
MAIL_WINDOW = 0,
|
||||
PREFS_WINDOW,
|
||||
SIG_WINDOW
|
||||
};
|
||||
|
||||
class TMailWindow;
|
||||
class THeaderView;
|
||||
class TEnclosuresView;
|
||||
class TContentView;
|
||||
class TMenu;
|
||||
class TPrefsWindow;
|
||||
class TSignatureWindow;
|
||||
class BMenuItem;
|
||||
class BmapButton;
|
||||
|
||||
class BFile;
|
||||
class BFilePanel;
|
||||
class ButtonBar;
|
||||
class BMenuBar;
|
||||
class Words;
|
||||
class BEmailMessage;
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TMailApp : public BApplication {
|
||||
public:
|
||||
TMailApp();
|
||||
~TMailApp();
|
||||
|
||||
virtual void AboutRequested();
|
||||
virtual void ArgvReceived(int32, char **);
|
||||
virtual void MessageReceived(BMessage *);
|
||||
virtual bool QuitRequested();
|
||||
virtual void ReadyToRun();
|
||||
virtual void RefsReceived(BMessage *);
|
||||
|
||||
TMailWindow *FindWindow(const entry_ref &);
|
||||
void FontChange();
|
||||
TMailWindow *NewWindow(const entry_ref *rec = NULL, const char *to = NULL,
|
||||
bool resend = false, BMessenger *messenger = NULL);
|
||||
|
||||
BFont fFont;
|
||||
|
||||
private:
|
||||
void ClearPrintSettings();
|
||||
void CheckForSpamFilterExistence();
|
||||
void LoadSavePrefs (bool loadThem);
|
||||
|
||||
BList fWindowList;
|
||||
int32 fWindowCount;
|
||||
TPrefsWindow *fPrefsWindow;
|
||||
TSignatureWindow *fSigWindow;
|
||||
//BMessenger fTrackerMessenger;
|
||||
// Talks to tracker window that this was launched from.
|
||||
|
||||
bool fPrevBBPref;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
class BMailMessage;
|
||||
|
||||
class TMailWindow : public BWindow {
|
||||
public:
|
||||
TMailWindow(BRect, const char *, const entry_ref *, const char *,
|
||||
const BFont *font, bool, BMessenger *trackerMessenger);
|
||||
virtual ~TMailWindow();
|
||||
|
||||
virtual void FrameResized(float width, float height);
|
||||
virtual void MenusBeginning();
|
||||
virtual void MessageReceived(BMessage*);
|
||||
virtual bool QuitRequested();
|
||||
virtual void Show();
|
||||
virtual void Zoom(BPoint, float, float);
|
||||
virtual void WindowActivated(bool state);
|
||||
|
||||
void SetTo(const char *mailTo, const char *subject, const char *ccTo = NULL,
|
||||
const char *bccTo = NULL, const BString *body = NULL, BMessage *enclosures = NULL);
|
||||
void AddSignature(BMailMessage *);
|
||||
void Forward(entry_ref *, TMailWindow *, bool includeAttachments);
|
||||
void Print();
|
||||
void PrintSetup();
|
||||
void Reply(entry_ref *, TMailWindow *, uint32);
|
||||
void CopyMessage(entry_ref *ref, TMailWindow *src);
|
||||
status_t Send(bool);
|
||||
status_t SaveAsDraft( void );
|
||||
status_t OpenMessage(entry_ref *ref, uint32 characterSetForDecoding = B_MAIL_NULL_CONVERSION);
|
||||
|
||||
status_t GetMailNodeRef(node_ref &nodeRef) const;
|
||||
BEmailMessage *Mail() const { return fMail; }
|
||||
|
||||
bool GetTrackerWindowFile(entry_ref *, bool dir) const;
|
||||
void SaveTrackerPosition(entry_ref *);
|
||||
void SetOriginatingWindow(BWindow *window);
|
||||
|
||||
void SetCurrentMessageRead();
|
||||
void SetTrackerSelectionToCurrent();
|
||||
TMailWindow* FrontmostWindow();
|
||||
void UpdateViews();
|
||||
|
||||
protected:
|
||||
void SetTitleForMessage();
|
||||
void AddEnclosure(BMessage *msg);
|
||||
void BuildButtonBar();
|
||||
status_t TrainMessageAs (const char *CommandWord);
|
||||
|
||||
private:
|
||||
BEmailMessage *fMail;
|
||||
entry_ref *fRef; // Reference to currently displayed file
|
||||
int32 fFieldState;
|
||||
BFilePanel *fPanel;
|
||||
BMenuBar *fMenuBar;
|
||||
BMenuItem *fAdd;
|
||||
BMenuItem *fCut;
|
||||
BMenuItem *fCopy;
|
||||
BMenuItem *fHeader;
|
||||
BMenuItem *fPaste;
|
||||
BMenuItem *fPrint;
|
||||
BMenuItem *fPrintSetup;
|
||||
BMenuItem *fQuote;
|
||||
BMenuItem *fRaw;
|
||||
BMenuItem *fRemove;
|
||||
BMenuItem *fRemoveQuote;
|
||||
BMenuItem *fSendNow;
|
||||
BMenuItem *fSendLater;
|
||||
BMenuItem *fUndo;
|
||||
BMenuItem *fRedo;
|
||||
BMenuItem *fNextMsg;
|
||||
BMenuItem *fPrevMsg;
|
||||
BMenuItem *fDeleteNext;
|
||||
BMenuItem *fSpelling;
|
||||
BMenu *fSaveAddrMenu;
|
||||
ButtonBar *fButtonBar;
|
||||
BmapButton *fSendButton;
|
||||
BmapButton *fSaveButton;
|
||||
BmapButton *fPrintButton;
|
||||
BmapButton *fSigButton;
|
||||
BRect fZoom;
|
||||
TContentView *fContentView;
|
||||
THeaderView *fHeaderView;
|
||||
TEnclosuresView *fEnclosuresView;
|
||||
TMenu *fSignature;
|
||||
BMessenger fTrackerMessenger;
|
||||
// Talks to tracker window that this was launched from.
|
||||
|
||||
entry_ref fPrevRef, fNextRef;
|
||||
bool fPrevTrackerPositionSaved : 1;
|
||||
bool fNextTrackerPositionSaved : 1;
|
||||
|
||||
static BList sWindowList;
|
||||
static BLocker sWindowListLock;
|
||||
|
||||
bool fSigAdded;
|
||||
bool fIncoming;
|
||||
bool fReplying;
|
||||
bool fResending;
|
||||
bool fSent;
|
||||
bool fDraft;
|
||||
bool fChanged;
|
||||
|
||||
char *fStartingText;
|
||||
entry_ref fRepliedMail;
|
||||
BMessenger *fOriginatingWindow;
|
||||
};
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TMenu: public BPopUpMenu
|
||||
{
|
||||
public:
|
||||
TMenu(const char *, const char *, int32, bool popup = false, bool addRandom = true);
|
||||
~TMenu();
|
||||
|
||||
virtual BPoint ScreenLocation(void);
|
||||
virtual void AttachedToWindow();
|
||||
|
||||
void BuildMenu();
|
||||
|
||||
private:
|
||||
char *fAttribute;
|
||||
char *fPredicate;
|
||||
bool fPopup, fAddRandom;
|
||||
int32 fMessage;
|
||||
};
|
||||
|
||||
//====================================================================
|
||||
|
||||
int32 header_len(BFile *);
|
||||
extern Words *gWords[MAX_DICTIONARIES];
|
||||
extern Words *gExactWords[MAX_DICTIONARIES];
|
||||
extern int32 gUserDict;
|
||||
extern BFile *gUserDictFile;
|
||||
extern int32 gDictCount;
|
||||
|
||||
#endif // #ifndef _MAIL_H
|
||||
@@ -0,0 +1,792 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING **
|
||||
** **
|
||||
** DANGER, WILL ROBINSON! **
|
||||
** **
|
||||
** The interfaces contained here are part of BeOS's **
|
||||
** **
|
||||
** >> PRIVATE NOT FOR PUBLIC USE << **
|
||||
** **
|
||||
** implementation. **
|
||||
** **
|
||||
** These interfaces WILL CHANGE in future releases. **
|
||||
** If you use them, your app WILL BREAK at some future time. **
|
||||
** **
|
||||
** WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING **
|
||||
****************************************************************************/
|
||||
|
||||
//
|
||||
// ObjectList is a wrapper around BList that adds type safety,
|
||||
// optional object ownership, search, insert operations, etc.
|
||||
//
|
||||
|
||||
#ifndef __OBJECT_LIST__
|
||||
#define __OBJECT_LIST__
|
||||
|
||||
#ifndef _BE_H
|
||||
#include <List.h>
|
||||
#endif
|
||||
|
||||
#include <Debug.h>
|
||||
|
||||
template<class T> class BObjectList;
|
||||
|
||||
template<class T>
|
||||
struct UnaryPredicate {
|
||||
virtual int operator()(const T *) const
|
||||
// virtual could be avoided here if FindBinaryInsertionIndex,
|
||||
// etc. were member template functions
|
||||
{ return 0; }
|
||||
|
||||
private:
|
||||
static int _unary_predicate_glue(const void *item, void *context);
|
||||
|
||||
friend class BObjectList<T>;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
int
|
||||
UnaryPredicate<T>::_unary_predicate_glue(const void *item, void *context)
|
||||
{
|
||||
return ((UnaryPredicate<T> *)context)->operator()((const T *)item);
|
||||
}
|
||||
|
||||
|
||||
class _PointerList_ : public BList {
|
||||
public:
|
||||
_PointerList_(const _PointerList_ &list);
|
||||
_PointerList_(int32 itemsPerBlock = 20, bool owning = false);
|
||||
~_PointerList_();
|
||||
|
||||
typedef void *(* GenericEachFunction)(void *, void *);
|
||||
typedef int (* GenericCompareFunction)(const void *, const void *);
|
||||
typedef int (* GenericCompareFunctionWithState)(const void *, const void *,
|
||||
void *);
|
||||
typedef int (* UnaryPredicateGlue)(const void *, void *);
|
||||
|
||||
void *EachElement(GenericEachFunction, void *);
|
||||
void SortItems(GenericCompareFunction);
|
||||
void SortItems(GenericCompareFunctionWithState, void *state);
|
||||
void HSortItems(GenericCompareFunction);
|
||||
void HSortItems(GenericCompareFunctionWithState, void *state);
|
||||
|
||||
void *BinarySearch(const void *, GenericCompareFunction) const;
|
||||
void *BinarySearch(const void *, GenericCompareFunctionWithState, void *state) const;
|
||||
|
||||
int32 BinarySearchIndex(const void *, GenericCompareFunction) const;
|
||||
int32 BinarySearchIndex(const void *, GenericCompareFunctionWithState, void *state) const;
|
||||
int32 BinarySearchIndexByPredicate(const void *, UnaryPredicateGlue) const;
|
||||
|
||||
bool Owning() const;
|
||||
bool ReplaceItem(int32, void *);
|
||||
|
||||
protected:
|
||||
bool owning;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class BObjectList : private _PointerList_ {
|
||||
public:
|
||||
// iteration and sorting
|
||||
typedef T *(* EachFunction)(T *, void *);
|
||||
typedef const T *(* ConstEachFunction)(const T *, void *);
|
||||
typedef int (* CompareFunction)(const T *, const T *);
|
||||
typedef int (* CompareFunctionWithState)(const T *, const T *, void *state);
|
||||
|
||||
BObjectList(int32 itemsPerBlock = 20, bool owning = false);
|
||||
BObjectList(const BObjectList &list);
|
||||
// clones list; if list is owning, makes copies of all
|
||||
// the items
|
||||
|
||||
virtual ~BObjectList();
|
||||
|
||||
BObjectList &operator=(const BObjectList &list);
|
||||
// clones list; if list is owning, makes copies of all
|
||||
// the items
|
||||
|
||||
// adding and removing
|
||||
// ToDo:
|
||||
// change Add calls to return const item
|
||||
bool AddItem(T *);
|
||||
bool AddItem(T *, int32);
|
||||
bool AddList(BObjectList *);
|
||||
bool AddList(BObjectList *, int32);
|
||||
|
||||
bool RemoveItem(T *, bool deleteIfOwning = true);
|
||||
// if owning, deletes the removed item
|
||||
T *RemoveItemAt(int32);
|
||||
// returns the removed item
|
||||
|
||||
void MakeEmpty();
|
||||
|
||||
// item access
|
||||
T *ItemAt(int32) const;
|
||||
|
||||
bool ReplaceItem(int32 index, T *);
|
||||
// if list is owning, deletes the item at <index> first
|
||||
T *SwapWithItem(int32 index, T *newItem);
|
||||
// same as ReplaceItem, except does not delete old item at <index>,
|
||||
// returns it instead
|
||||
|
||||
T *FirstItem() const;
|
||||
T *LastItem() const;
|
||||
|
||||
// misc. getters
|
||||
int32 IndexOf(const T *) const;
|
||||
bool HasItem(const T *) const;
|
||||
bool IsEmpty() const;
|
||||
int32 CountItems() const;
|
||||
|
||||
T *EachElement(EachFunction, void *);
|
||||
const T *EachElement(ConstEachFunction, void *) const;
|
||||
|
||||
void SortItems(CompareFunction);
|
||||
void SortItems(CompareFunctionWithState, void *state);
|
||||
void HSortItems(CompareFunction);
|
||||
void HSortItems(CompareFunctionWithState, void *state);
|
||||
|
||||
// linear search, returns first item that matches predicate
|
||||
const T *FindIf(const UnaryPredicate<T> &) const;
|
||||
T *FindIf(const UnaryPredicate<T> &);
|
||||
|
||||
// list must be sorted with CompareFunction for these to work
|
||||
const T *BinarySearch(const T &, CompareFunction) const;
|
||||
const T *BinarySearch(const T &, CompareFunctionWithState, void *state) const;
|
||||
|
||||
// Binary insertion - list must be sorted with CompareFunction for
|
||||
// these to work
|
||||
|
||||
// simple insert
|
||||
void BinaryInsert(T *, CompareFunction);
|
||||
void BinaryInsert(T *, CompareFunctionWithState, void *state);
|
||||
void BinaryInsert(T *, const UnaryPredicate<T> &);
|
||||
|
||||
// unique insert, returns false if item already in list
|
||||
bool BinaryInsertUnique(T *, CompareFunction);
|
||||
bool BinaryInsertUnique(T *, CompareFunctionWithState, void *state);
|
||||
bool BinaryInsertUnique(T *, const UnaryPredicate<T> &);
|
||||
|
||||
// insert a copy of the item, returns new inserted item
|
||||
T *BinaryInsertCopy(const T ©This, CompareFunction);
|
||||
T *BinaryInsertCopy(const T ©This, CompareFunctionWithState, void *state);
|
||||
|
||||
// insert a copy of the item if not in list already
|
||||
// returns new inserted item or existing item in case of a conflict
|
||||
T *BinaryInsertCopyUnique(const T ©This, CompareFunction);
|
||||
T *BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState, void *state);
|
||||
|
||||
int32 FindBinaryInsertionIndex(const UnaryPredicate<T> &, bool *alreadyInList = 0) const;
|
||||
// returns either the index into which a new item should be inserted
|
||||
// or index of an existing item that matches the predicate
|
||||
|
||||
// deprecated API, will go away
|
||||
BList *AsBList()
|
||||
{ return this; }
|
||||
const BList *AsBList() const
|
||||
{ return this; }
|
||||
|
||||
private:
|
||||
void SetItem(int32, T *);
|
||||
};
|
||||
|
||||
template<class Item, class Result, class Param1>
|
||||
Result
|
||||
WhileEachListItem(BObjectList<Item> *list, Result (Item::*func)(Param1), Param1 p1)
|
||||
{
|
||||
Result result = 0;
|
||||
int32 count = list->CountItems();
|
||||
|
||||
for (int32 index = 0; index < count; index++)
|
||||
if ((result = (list->ItemAt(index)->*func)(p1)) != 0)
|
||||
break;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class Item, class Result, class Param1>
|
||||
Result
|
||||
WhileEachListItem(BObjectList<Item> *list, Result (*func)(Item *, Param1), Param1 p1)
|
||||
{
|
||||
Result result = 0;
|
||||
int32 count = list->CountItems();
|
||||
|
||||
for (int32 index = 0; index < count; index++)
|
||||
if ((result = (*func)(list->ItemAt(index), p1)) != 0)
|
||||
break;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class Item, class Result, class Param1, class Param2>
|
||||
Result
|
||||
WhileEachListItem(BObjectList<Item> *list, Result (Item::*func)(Param1, Param2),
|
||||
Param1 p1, Param2 p2)
|
||||
{
|
||||
Result result = 0;
|
||||
int32 count = list->CountItems();
|
||||
|
||||
for (int32 index = 0; index < count; index++)
|
||||
if ((result = (list->ItemAt(index)->*func)(p1, p2)) != 0)
|
||||
break;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class Item, class Result, class Param1, class Param2>
|
||||
Result
|
||||
WhileEachListItem(BObjectList<Item> *list, Result (*func)(Item *, Param1, Param2),
|
||||
Param1 p1, Param2 p2)
|
||||
{
|
||||
Result result = 0;
|
||||
int32 count = list->CountItems();
|
||||
|
||||
for (int32 index = 0; index < count; index++)
|
||||
if ((result = (*func)(list->ItemAt(index), p1, p2)) != 0)
|
||||
break;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class Item, class Result, class Param1, class Param2, class Param3, class Param4>
|
||||
Result
|
||||
WhileEachListItem(BObjectList<Item> *list, Result (*func)(Item *, Param1, Param2,
|
||||
Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4)
|
||||
{
|
||||
Result result = 0;
|
||||
int32 count = list->CountItems();
|
||||
|
||||
for (int32 index = 0; index < count; index++)
|
||||
if ((result = (*func)(list->ItemAt(index), p1, p2, p3, p4)) != 0)
|
||||
break;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class Item, class Result>
|
||||
void
|
||||
EachListItemIgnoreResult(BObjectList<Item> *list, Result (Item::*func)())
|
||||
{
|
||||
int32 count = list->CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
(list->ItemAt(index)->*func)();
|
||||
}
|
||||
|
||||
template<class Item, class Param1>
|
||||
void
|
||||
EachListItem(BObjectList<Item> *list, void (*func)(Item *, Param1), Param1 p1)
|
||||
{
|
||||
int32 count = list->CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
(func)(list->ItemAt(index), p1);
|
||||
}
|
||||
|
||||
template<class Item, class Param1, class Param2>
|
||||
void
|
||||
EachListItem(BObjectList<Item> *list, void (Item::*func)(Param1, Param2),
|
||||
Param1 p1, Param2 p2)
|
||||
{
|
||||
int32 count = list->CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
(list->ItemAt(index)->*func)(p1, p2);
|
||||
}
|
||||
|
||||
template<class Item, class Param1, class Param2>
|
||||
void
|
||||
EachListItem(BObjectList<Item> *list, void (*func)(Item *,Param1, Param2),
|
||||
Param1 p1, Param2 p2)
|
||||
{
|
||||
int32 count = list->CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
(func)(list->ItemAt(index), p1, p2);
|
||||
}
|
||||
|
||||
template<class Item, class Param1, class Param2, class Param3>
|
||||
void
|
||||
EachListItem(BObjectList<Item> *list, void (*func)(Item *,Param1, Param2,
|
||||
Param3), Param1 p1, Param2 p2, Param3 p3)
|
||||
{
|
||||
int32 count = list->CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
(func)(list->ItemAt(index), p1, p2, p3);
|
||||
}
|
||||
|
||||
|
||||
template<class Item, class Param1, class Param2, class Param3, class Param4>
|
||||
void
|
||||
EachListItem(BObjectList<Item> *list, void (*func)(Item *,Param1, Param2,
|
||||
Param3, Param4), Param1 p1, Param2 p2, Param3 p3, Param4 p4)
|
||||
{
|
||||
int32 count = list->CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
(func)(list->ItemAt(index), p1, p2, p3, p4);
|
||||
}
|
||||
|
||||
// inline code
|
||||
|
||||
inline bool
|
||||
_PointerList_::Owning() const
|
||||
{
|
||||
return owning;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BObjectList<T>::BObjectList(int32 itemsPerBlock, bool owning)
|
||||
: _PointerList_(itemsPerBlock, owning)
|
||||
{
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BObjectList<T>::BObjectList(const BObjectList<T> &list)
|
||||
: _PointerList_(list)
|
||||
{
|
||||
owning = list.owning;
|
||||
if (owning) {
|
||||
// make our own copies in an owning list
|
||||
int32 count = list.CountItems();
|
||||
for (int32 index = 0; index < count; index++) {
|
||||
T *item = list.ItemAt(index);
|
||||
if (item)
|
||||
item = new T(*item);
|
||||
SetItem(index, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BObjectList<T>::~BObjectList()
|
||||
{
|
||||
if (Owning())
|
||||
// have to nuke elements first
|
||||
MakeEmpty();
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
BObjectList<T> &
|
||||
BObjectList<T>::operator=(const BObjectList<T> &list)
|
||||
{
|
||||
owning = list.owning;
|
||||
BObjectList<T> &result = (BObjectList<T> &)_PointerList_::operator=(list);
|
||||
if (owning) {
|
||||
// make our own copies in an owning list
|
||||
int32 count = list.CountItems();
|
||||
for (int32 index = 0; index < count; index++) {
|
||||
T *item = list.ItemAt(index);
|
||||
if (item)
|
||||
item = new T(*item);
|
||||
SetItem(index, item);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::AddItem(T *item)
|
||||
{
|
||||
// need to cast to void * to make T work for const pointers
|
||||
return _PointerList_::AddItem((void *)item);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::AddItem(T *item, int32 atIndex)
|
||||
{
|
||||
return _PointerList_::AddItem((void *)item, atIndex);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::AddList(BObjectList<T> *newItems)
|
||||
{
|
||||
return _PointerList_::AddList(newItems);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::AddList(BObjectList<T> *newItems, int32 atIndex)
|
||||
{
|
||||
return _PointerList_::AddList(newItems, atIndex);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::RemoveItem(T *item, bool deleteIfOwning)
|
||||
{
|
||||
bool result = _PointerList_::RemoveItem((void *)item);
|
||||
|
||||
if (result && Owning() && deleteIfOwning)
|
||||
delete item;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::RemoveItemAt(int32 index)
|
||||
{
|
||||
return (T *)_PointerList_::RemoveItem(index);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T *
|
||||
BObjectList<T>::ItemAt(int32 index) const
|
||||
{
|
||||
return (T *)_PointerList_::ItemAt(index);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::ReplaceItem(int32 index, T *item)
|
||||
{
|
||||
if (owning)
|
||||
delete ItemAt(index);
|
||||
return _PointerList_::ReplaceItem(index, (void *)item);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::SwapWithItem(int32 index, T *newItem)
|
||||
{
|
||||
T *result = ItemAt(index);
|
||||
_PointerList_::ReplaceItem(index, (void *)newItem);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::SetItem(int32 index, T *newItem)
|
||||
{
|
||||
_PointerList_::ReplaceItem(index, (void *)newItem);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
int32
|
||||
BObjectList<T>::IndexOf(const T *item) const
|
||||
{
|
||||
return _PointerList_::IndexOf((void *)item);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::FirstItem() const
|
||||
{
|
||||
return (T *)_PointerList_::FirstItem();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::LastItem() const
|
||||
{
|
||||
return (T *)_PointerList_::LastItem();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::HasItem(const T *item) const
|
||||
{
|
||||
return _PointerList_::HasItem((void *)item);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::IsEmpty() const
|
||||
{
|
||||
return _PointerList_::IsEmpty();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
int32
|
||||
BObjectList<T>::CountItems() const
|
||||
{
|
||||
return _PointerList_::CountItems();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::MakeEmpty()
|
||||
{
|
||||
if (owning) {
|
||||
int32 count = CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
delete ItemAt(index);
|
||||
}
|
||||
_PointerList_::MakeEmpty();
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::EachElement(EachFunction func, void *params)
|
||||
{
|
||||
return (T *)_PointerList_::EachElement((GenericEachFunction)func, params);
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
const T *
|
||||
BObjectList<T>::EachElement(ConstEachFunction func, void *params) const
|
||||
{
|
||||
return (const T *)
|
||||
const_cast<BObjectList<T> *>(this)->_PointerList_::EachElement(
|
||||
(GenericEachFunction)func, params);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T *
|
||||
BObjectList<T>::FindIf(const UnaryPredicate<T> &predicate) const
|
||||
{
|
||||
int32 count = CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
if (predicate.operator()(ItemAt(index)) == 0)
|
||||
return ItemAt(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::FindIf(const UnaryPredicate<T> &predicate)
|
||||
{
|
||||
int32 count = CountItems();
|
||||
for (int32 index = 0; index < count; index++)
|
||||
if (predicate.operator()(ItemAt(index)) == 0)
|
||||
return ItemAt(index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::SortItems(CompareFunction function)
|
||||
{
|
||||
_PointerList_::SortItems((GenericCompareFunction)function);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::SortItems(CompareFunctionWithState function, void *state)
|
||||
{
|
||||
_PointerList_::SortItems((GenericCompareFunctionWithState)function, state);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::HSortItems(CompareFunction function)
|
||||
{
|
||||
_PointerList_::HSortItems((GenericCompareFunction)function);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::HSortItems(CompareFunctionWithState function, void *state)
|
||||
{
|
||||
_PointerList_::HSortItems((GenericCompareFunctionWithState)function, state);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T *
|
||||
BObjectList<T>::BinarySearch(const T &key, CompareFunction func) const
|
||||
{
|
||||
return (const T *)_PointerList_::BinarySearch(&key,
|
||||
(GenericCompareFunction)func);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const T *
|
||||
BObjectList<T>::BinarySearch(const T &key, CompareFunctionWithState func, void *state) const
|
||||
{
|
||||
return (const T *)_PointerList_::BinarySearch(&key,
|
||||
(GenericCompareFunctionWithState)func, state);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::BinaryInsert(T *item, CompareFunction func)
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndex(item,
|
||||
(GenericCompareFunction)func);
|
||||
if (index >= 0)
|
||||
// already in list, add after existing
|
||||
AddItem(item, index + 1);
|
||||
else
|
||||
AddItem(item, -index - 1);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::BinaryInsert(T *item, CompareFunctionWithState func, void *state)
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndex(item,
|
||||
(GenericCompareFunctionWithState)func, state);
|
||||
if (index >= 0)
|
||||
// already in list, add after existing
|
||||
AddItem(item, index + 1);
|
||||
else
|
||||
AddItem(item, -index - 1);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::BinaryInsertUnique(T *, CompareFunction func)
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndex(item,
|
||||
(GenericCompareFunction)func);
|
||||
if (index >= 0)
|
||||
return false;
|
||||
|
||||
AddItem(item, -index - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::BinaryInsertUnique(T *, CompareFunctionWithState func, void *state)
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndex(item,
|
||||
(GenericCompareFunctionWithState)func, state);
|
||||
if (index >= 0)
|
||||
return false;
|
||||
|
||||
AddItem(item, -index - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::BinaryInsertCopy(const T ©This, CompareFunction func)
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndex(©This,
|
||||
(GenericCompareFunction)func);
|
||||
|
||||
if (index >= 0)
|
||||
index++;
|
||||
else
|
||||
index = -index - 1;
|
||||
|
||||
T *newItem = new T(copyThis);
|
||||
AddItem(newItem, index);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::BinaryInsertCopy(const T ©This, CompareFunctionWithState func, void *state)
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndex(©This,
|
||||
(GenericCompareFunctionWithState)func, state);
|
||||
|
||||
if (index >= 0)
|
||||
index++;
|
||||
else
|
||||
index = -index - 1;
|
||||
|
||||
T *newItem = new T(copyThis);
|
||||
AddItem(newItem, index);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::BinaryInsertCopyUnique(const T ©This, CompareFunction func)
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndex(©This,
|
||||
(GenericCompareFunction)func);
|
||||
if (index >= 0)
|
||||
return ItemAt(index);
|
||||
|
||||
index = -index - 1;
|
||||
T *newItem = new T(copyThis);
|
||||
AddItem(newItem, index);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T *
|
||||
BObjectList<T>::BinaryInsertCopyUnique(const T ©This, CompareFunctionWithState func,
|
||||
void *state)
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndex(©This,
|
||||
(GenericCompareFunctionWithState)func, state);
|
||||
if (index >= 0)
|
||||
return ItemAt(index);
|
||||
|
||||
index = -index - 1;
|
||||
T *newItem = new T(copyThis);
|
||||
AddItem(newItem, index);
|
||||
return newItem;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
int32
|
||||
BObjectList<T>::FindBinaryInsertionIndex(const UnaryPredicate<T> &pred, bool *alreadyInList)
|
||||
const
|
||||
{
|
||||
int32 index = _PointerList_::BinarySearchIndexByPredicate(&pred,
|
||||
(UnaryPredicateGlue)&UnaryPredicate<T>::_unary_predicate_glue);
|
||||
|
||||
if (alreadyInList)
|
||||
*alreadyInList = index >= 0;
|
||||
|
||||
if (index < 0)
|
||||
index = -index - 1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void
|
||||
BObjectList<T>::BinaryInsert(T *item, const UnaryPredicate<T> &pred)
|
||||
{
|
||||
int32 index = FindBinaryInsertionIndex(pred);
|
||||
AddItem(item, index);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool
|
||||
BObjectList<T>::BinaryInsertUnique(T *item, const UnaryPredicate<T> &pred)
|
||||
{
|
||||
bool alreadyInList;
|
||||
int32 index = FindBinaryInsertionIndex(pred, &alreadyInList);
|
||||
if (alreadyInList)
|
||||
return false;
|
||||
|
||||
AddItem(item, index);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // #ifndef __OBJECT_LIST__
|
||||
@@ -0,0 +1,966 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Prefs.cpp
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <InterfaceKit.h>
|
||||
#include <StorageKit.h>
|
||||
#include <E-mail.h>
|
||||
#include <Application.h>
|
||||
|
||||
#include <MailSettings.h>
|
||||
#include <mail_encoding.h>
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
#include "Mail.h"
|
||||
#include "Prefs.h"
|
||||
|
||||
#define BUTTON_WIDTH 70
|
||||
#define BUTTON_HEIGHT 20
|
||||
#define ITEM_SPACE 6
|
||||
|
||||
#define FONT_TEXT MDR_DIALECT_CHOICE ("Font:", "フォント:")
|
||||
#define SIZE_TEXT MDR_DIALECT_CHOICE ("Size:", "サイズ:")
|
||||
#define LEVEL_TEXT MDR_DIALECT_CHOICE ("User Level:", "ユーザーレベル:")
|
||||
#define WRAP_TEXT MDR_DIALECT_CHOICE ("Text Wrapping:", "テキスト・ラップ:")
|
||||
#define ATTACH_ATTRIBUTES_TEXT MDR_DIALECT_CHOICE ("Attach Attributes:", "ファイル属性情報:")
|
||||
#define QUOTES_TEXT MDR_DIALECT_CHOICE ("Colored Quotes:", "引用部分の着色:")
|
||||
#define ACCOUNT_TEXT MDR_DIALECT_CHOICE ("Default Account:", "標準アカウント:")
|
||||
#define REPLYTO_TEXT MDR_DIALECT_CHOICE ("Reply Account:", "返信用アカウント:")
|
||||
#define REPLYTO_USE_DEFAULT_TEXT MDR_DIALECT_CHOICE ("Use Default Account", "標準アカウントを使う")
|
||||
#define REPLYTO_FROM_MAIL_TEXT MDR_DIALECT_CHOICE ("Account From Mail", "メールのアカウントを使う")
|
||||
#define REPLY_PREAMBLE_TEXT MDR_DIALECT_CHOICE ("Reply Preamble:", "返信へ追加:")
|
||||
#define SIGNATURE_TEXT MDR_DIALECT_CHOICE ("Auto Signature:", "自動署名:")
|
||||
#define ENCODING_TEXT MDR_DIALECT_CHOICE ("Encoding:", "エンコード形式:")
|
||||
#define WARN_UNENCODABLE_TEXT MDR_DIALECT_CHOICE ("Warn Unencodable:", "警告: エンコードできません")
|
||||
#define SPELL_CHECK_START_ON_TEXT MDR_DIALECT_CHOICE ("Initial Spell Check Mode:", "編集時スペルチェック:")
|
||||
|
||||
#define BUTTONBAR_TEXT MDR_DIALECT_CHOICE ("Button Bar:", "ボタンバー:")
|
||||
|
||||
#define OK_BUTTON_X1 (PREF_WIDTH - BUTTON_WIDTH - 6)
|
||||
#define OK_BUTTON_X2 (OK_BUTTON_X1 + BUTTON_WIDTH)
|
||||
#define OK_BUTTON_TEXT MDR_DIALECT_CHOICE ("Done", "設定")
|
||||
#define CANCEL_BUTTON_TEXT MDR_DIALECT_CHOICE ("Cancel", "中止")
|
||||
|
||||
#define REVERT_BUTTON_X1 8
|
||||
#define REVERT_BUTTON_X2 (REVERT_BUTTON_X1 + BUTTON_WIDTH)
|
||||
#define REVERT_BUTTON_TEXT MDR_DIALECT_CHOICE ("Revert", "復元")
|
||||
|
||||
enum P_MESSAGES {P_OK = 128, P_CANCEL, P_REVERT, P_FONT,
|
||||
P_SIZE, P_LEVEL, P_WRAP, P_ATTACH_ATTRIBUTES,
|
||||
P_SIG, P_ENC, P_WARN_UNENCODABLE,
|
||||
P_SPELL_CHECK_START_ON, P_BUTTON_BAR,
|
||||
P_ACCOUNT, P_REPLYTO, P_REPLY_PREAMBLE,
|
||||
P_COLORED_QUOTES};
|
||||
|
||||
#define ICON_LABEL_TEXT MDR_DIALECT_CHOICE ("Show Icons & Labels", "アイコンとラベル")
|
||||
#define ICON_TEXT MDR_DIALECT_CHOICE ("Show Icons Only", "アイコンのみ")
|
||||
#define HIDE_TEXT MDR_DIALECT_CHOICE ("Hide", "隠す")
|
||||
|
||||
|
||||
extern BPoint prefs_window;
|
||||
|
||||
const EncodingItem kEncodings[] =
|
||||
{
|
||||
// B_MS_WINDOWS is a superset of B_ISO1, MS mailers lie and send Windows
|
||||
// chars as ISO-1 we still don't want to pretend we would use the Windows
|
||||
// 1252 codetable; this should only be done at decoding stage, axeld.
|
||||
// {"ISO-8859-1", B_MS_WINDOWS_CONVERSION},
|
||||
{"ISO-8859-1 (Latin-1)", B_ISO1_CONVERSION},
|
||||
{"ISO-8859-2", B_ISO2_CONVERSION},
|
||||
{"ISO-8859-3", B_ISO3_CONVERSION},
|
||||
{"ISO-8859-4", B_ISO4_CONVERSION},
|
||||
{"ISO-8859-5", B_ISO5_CONVERSION},
|
||||
{"ISO-8859-6", B_ISO6_CONVERSION},
|
||||
{"ISO-8859-7", B_ISO7_CONVERSION},
|
||||
{"ISO-8859-8", B_ISO8_CONVERSION},
|
||||
{"ISO-8859-9", B_ISO9_CONVERSION},
|
||||
{"ISO-8859-10", B_ISO10_CONVERSION},
|
||||
{"ISO-8859-13", B_ISO13_CONVERSION},
|
||||
{"ISO-8859-14", B_ISO14_CONVERSION},
|
||||
{"ISO-8859-15", B_ISO15_CONVERSION},
|
||||
{"SHIFT-JIS (obsolete)", B_SJIS_CONVERSION},
|
||||
{"ISO-2022-JP", B_JIS_CONVERSION},
|
||||
{"EUC-JP (obsolete)", B_EUC_CONVERSION},
|
||||
{"EUC-KR", B_EUC_KR_CONVERSION},
|
||||
{"KOI8-R", B_KOI8R_CONVERSION},
|
||||
{"Windows-1251",B_MS_WINDOWS_1251_CONVERSION},
|
||||
{"Windows-1252 (\"ANSI\")",B_MS_WINDOWS_CONVERSION},
|
||||
{"DOS-437 (common)", B_MS_DOS_CONVERSION},
|
||||
{"DOS-866 (rarer)", B_MS_DOS_866_CONVERSION},
|
||||
{"Macintosh Roman", B_MAC_ROMAN_CONVERSION},
|
||||
{"US-ASCII", B_MAIL_US_ASCII_CONVERSION},
|
||||
{"UTF-8 (BeOS)", B_MAIL_UTF8_CONVERSION},
|
||||
|
||||
{"Automatic", B_MAIL_NULL_CONVERSION /* marks end of list, only visible when decoding */}
|
||||
};
|
||||
|
||||
#define ATTRIBUTE_ON_TEXT MDR_DIALECT_CHOICE ("Include BeOS Attributes in Attachments", "BeOSの属性を付ける")
|
||||
#define ATTRIBUTE_OFF_TEXT MDR_DIALECT_CHOICE ("No BeOS Attributes, just Plain Data", "BeOSの属性を付けない(データのみ)")
|
||||
|
||||
//====================================================================
|
||||
|
||||
|
||||
TPrefsWindow::TPrefsWindow(BRect rect, BFont *font, int32 *level, bool *wrap,
|
||||
bool *attachAttributes, bool *cquotes, uint32 *account, int32 *replyTo,
|
||||
char **preamble, char **sig, uint32 *encoding, bool *warnUnencodable,
|
||||
bool *spellCheckStartOn, bool *buttonBar)
|
||||
: BWindow(rect, MDR_DIALECT_CHOICE ("BeMail Preferences","BeMailの設定"), B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE)
|
||||
{
|
||||
BMenuField *menu;
|
||||
|
||||
fNewFont = font; fFont = *fNewFont;
|
||||
fNewLevel = level; fLevel = *fNewLevel;
|
||||
fNewWrap = wrap; fWrap = *fNewWrap;
|
||||
fNewAttachAttributes = attachAttributes; fAttachAttributes = *fNewAttachAttributes;
|
||||
fNewColoredQuotes = cquotes; fColoredQuotes = *fNewColoredQuotes;
|
||||
fNewAccount = account; fAccount = *fNewAccount;
|
||||
fNewReplyTo = replyTo; fReplyTo = *fNewReplyTo;
|
||||
fNewEncoding = encoding; fEncoding = *fNewEncoding;
|
||||
fNewWarnUnencodable = warnUnencodable; fWarnUnencodable = *fNewWarnUnencodable;
|
||||
fNewSpellCheckStartOn = spellCheckStartOn; fSpellCheckStartOn = *fNewSpellCheckStartOn;
|
||||
fNewButtonBar = buttonBar; fButtonBar = *fNewButtonBar;
|
||||
|
||||
fNewPreamble = preamble;
|
||||
|
||||
fNewSignature = sig;
|
||||
fSignature = (char *)malloc(strlen(*fNewSignature) + 1);
|
||||
strcpy(fSignature, *fNewSignature);
|
||||
|
||||
BRect r = Bounds();
|
||||
BView *view = new BView(r, NULL, B_FOLLOW_ALL, B_FRAME_EVENTS);
|
||||
view->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
AddChild(view);
|
||||
|
||||
// determine font height
|
||||
font_height fontHeight;
|
||||
view->GetFontHeight(&fontHeight);
|
||||
int32 height = (int32)(fontHeight.ascent + fontHeight.descent + fontHeight.leading) + 6;
|
||||
int32 labelWidth = (int32)view->StringWidth(SPELL_CHECK_START_ON_TEXT) + SEPARATOR_MARGIN;
|
||||
|
||||
// group boxes
|
||||
|
||||
r.Set(8,4,Bounds().right - 8,4 + 7 * (height + ITEM_SPACE));
|
||||
BBox *interfaceBox = new BBox(r,NULL,B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
|
||||
interfaceBox->SetLabel(MDR_DIALECT_CHOICE ("User Interface","ユーザーインターフェース"));
|
||||
view->AddChild(interfaceBox);
|
||||
|
||||
r.top = r.bottom + 8; r.bottom = r.top + 9 * (height + ITEM_SPACE);
|
||||
BBox *mailBox = new BBox(r,NULL,B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
|
||||
mailBox->SetLabel(MDR_DIALECT_CHOICE ("Mailing","メール関係"));
|
||||
view->AddChild(mailBox);
|
||||
|
||||
// revert, ok & cancel
|
||||
|
||||
r.top = r.bottom + 10; r.bottom = r.top + height;
|
||||
r.left = OK_BUTTON_X1; r.right = OK_BUTTON_X2;
|
||||
BButton *button = new BButton(r, "ok", OK_BUTTON_TEXT, new BMessage(P_OK));
|
||||
button->MakeDefault(true);
|
||||
view->AddChild(button);
|
||||
|
||||
r.OffsetBy(-(OK_BUTTON_X2 - OK_BUTTON_X1 + 10), 0);
|
||||
button = new BButton(r, "cancel", CANCEL_BUTTON_TEXT, new BMessage(P_CANCEL));
|
||||
view->AddChild(button);
|
||||
|
||||
r.left = REVERT_BUTTON_X1; r.right = REVERT_BUTTON_X2;
|
||||
fRevert = new BButton(r, "revert", REVERT_BUTTON_TEXT, new BMessage(P_REVERT));
|
||||
fRevert->SetEnabled(false);
|
||||
view->AddChild(fRevert);
|
||||
|
||||
// User Interface
|
||||
|
||||
r = interfaceBox->Bounds();
|
||||
r.left += 8; r.right -= 8; r.top = height; r.bottom = r.top + height - 3;
|
||||
fButtonBarMenu = BuildButtonBarMenu(*buttonBar);
|
||||
menu = new BMenuField(r, "bar", BUTTONBAR_TEXT, fButtonBarMenu,B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
interfaceBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fFontMenu = BuildFontMenu(font);
|
||||
menu = new BMenuField(r, "font", FONT_TEXT, fFontMenu,B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
interfaceBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fSizeMenu = BuildSizeMenu(font);
|
||||
menu = new BMenuField(r, "size", SIZE_TEXT, fSizeMenu,B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
interfaceBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fColoredQuotesMenu = BuildColoredQuotesMenu(fColoredQuotes);
|
||||
menu = new BMenuField(r, "cquotes", QUOTES_TEXT, fColoredQuotesMenu,B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
interfaceBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fSpellCheckStartOnMenu = BuildSpellCheckStartOnMenu(fSpellCheckStartOn);
|
||||
menu = new BMenuField(r, "spellCheckStartOn", SPELL_CHECK_START_ON_TEXT,
|
||||
fSpellCheckStartOnMenu, B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
interfaceBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fLevelMenu = BuildLevelMenu(*level);
|
||||
menu = new BMenuField(r, "level", LEVEL_TEXT, fLevelMenu,B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
interfaceBox->AddChild(menu);
|
||||
|
||||
// Mail Accounts
|
||||
|
||||
r = mailBox->Bounds();
|
||||
r.left += 8; r.right -= 8; r.top = height; r.bottom = r.top + height - 3;
|
||||
fAccountMenu = BuildAccountMenu(fAccount);
|
||||
menu = new BMenuField(r, "account", ACCOUNT_TEXT, fAccountMenu, B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
mailBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fReplyToMenu = BuildReplyToMenu(fReplyTo);
|
||||
menu = new BMenuField(r, "replyTo", REPLYTO_TEXT, fReplyToMenu, B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
mailBox->AddChild(menu);
|
||||
|
||||
// Mail Contents
|
||||
|
||||
r.OffsetBy(0, height + ITEM_SPACE); r.right -= 25;
|
||||
fReplyPreamble = new BTextControl(r, "replytext", REPLY_PREAMBLE_TEXT, *preamble,
|
||||
new BMessage(P_REPLY_PREAMBLE), B_FOLLOW_ALL, B_WILL_DRAW | B_NAVIGABLE);
|
||||
fReplyPreamble->SetDivider(labelWidth);
|
||||
fReplyPreamble->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
|
||||
mailBox->AddChild(fReplyPreamble);
|
||||
|
||||
BRect popRect = r;
|
||||
popRect.left = r.right + 6; r.right += 25; popRect.right = r.right;
|
||||
fReplyPreambleMenu = BuildReplyPreambleMenu();
|
||||
menu = new BMenuField(popRect, "replyPreamble", B_EMPTY_STRING, fReplyPreambleMenu,
|
||||
B_FOLLOW_ALL, B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(0);
|
||||
mailBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0, height + ITEM_SPACE);
|
||||
fSignatureMenu = BuildSignatureMenu(*sig);
|
||||
menu = new BMenuField(r, "sig", SIGNATURE_TEXT, fSignatureMenu,B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
mailBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fEncodingMenu = BuildEncodingMenu(fEncoding);
|
||||
menu = new BMenuField(r, "enc", ENCODING_TEXT, fEncodingMenu,B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
mailBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fWarnUnencodableMenu = BuildWarnUnencodableMenu(fWarnUnencodable);
|
||||
menu = new BMenuField(r, "warnUnencodable", WARN_UNENCODABLE_TEXT,
|
||||
fWarnUnencodableMenu, B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
mailBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fWrapMenu = BuildWrapMenu(*wrap);
|
||||
menu = new BMenuField(r, "wrap", WRAP_TEXT, fWrapMenu,B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
mailBox->AddChild(menu);
|
||||
|
||||
r.OffsetBy(0,height + ITEM_SPACE);
|
||||
fAttachAttributesMenu = BuildAttachAttributesMenu(*attachAttributes);
|
||||
menu = new BMenuField(r, "attachAttributes", ATTACH_ATTRIBUTES_TEXT, fAttachAttributesMenu, B_FOLLOW_ALL,
|
||||
B_WILL_DRAW | B_NAVIGABLE | B_NAVIGABLE_JUMP);
|
||||
menu->SetDivider(labelWidth);
|
||||
menu->SetAlignment(B_ALIGN_RIGHT);
|
||||
mailBox->AddChild(menu);
|
||||
|
||||
ResizeTo(Frame().Width(), fRevert->Frame().bottom + 8);
|
||||
Show();
|
||||
}
|
||||
|
||||
|
||||
TPrefsWindow::~TPrefsWindow()
|
||||
{
|
||||
BMessage msg(WINDOW_CLOSED);
|
||||
|
||||
prefs_window = Frame().LeftTop();
|
||||
|
||||
msg.AddInt32("kind", PREFS_WINDOW);
|
||||
be_app->PostMessage(&msg);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TPrefsWindow::MessageReceived(BMessage *msg)
|
||||
{
|
||||
bool changed;
|
||||
bool revert = true;
|
||||
const char *family;
|
||||
const char *signature;
|
||||
const char *style;
|
||||
char label[256];
|
||||
int32 new_size;
|
||||
int32 old_size;
|
||||
font_family new_family;
|
||||
font_family old_family;
|
||||
font_style new_style;
|
||||
font_style old_style;
|
||||
BMenuItem *item;
|
||||
BMessage message;
|
||||
|
||||
switch (msg->what)
|
||||
{
|
||||
case P_OK:
|
||||
if (strcmp(fReplyPreamble->Text(), *fNewPreamble))
|
||||
{
|
||||
free(*fNewPreamble);
|
||||
*fNewPreamble = (char *)malloc(strlen(fReplyPreamble->Text()) + 1);
|
||||
strcpy(*fNewPreamble, fReplyPreamble->Text());
|
||||
}
|
||||
be_app->PostMessage(PREFS_CHANGED);
|
||||
Quit();
|
||||
break;
|
||||
|
||||
case P_CANCEL:
|
||||
revert = false;
|
||||
// supposed to fall through
|
||||
case P_REVERT:
|
||||
fFont.GetFamilyAndStyle(&old_family, &old_style);
|
||||
fNewFont->GetFamilyAndStyle(&new_family, &new_style);
|
||||
old_size = (int32) fFont.Size();
|
||||
new_size = (int32) fNewFont->Size();
|
||||
if (strcmp(old_family, new_family) || strcmp(old_style, new_style)
|
||||
|| old_size != new_size)
|
||||
{
|
||||
fNewFont->SetFamilyAndStyle(old_family, old_style);
|
||||
if (revert)
|
||||
{
|
||||
sprintf(label, "%s %s", old_family, old_style);
|
||||
item = fFontMenu->FindItem(label);
|
||||
item->SetMarked(true);
|
||||
}
|
||||
|
||||
fNewFont->SetSize(old_size);
|
||||
if (revert)
|
||||
{
|
||||
sprintf(label, "%ld", old_size);
|
||||
item = fSizeMenu->FindItem(label);
|
||||
item->SetMarked(true);
|
||||
}
|
||||
message.what = M_FONT;
|
||||
be_app->PostMessage(&message);
|
||||
}
|
||||
*fNewLevel = fLevel;
|
||||
*fNewWrap = fWrap;
|
||||
*fNewAttachAttributes = fAttachAttributes;
|
||||
|
||||
if (strcmp(fSignature, *fNewSignature))
|
||||
{
|
||||
free(*fNewSignature);
|
||||
*fNewSignature = (char *)malloc(strlen(fSignature) + 1);
|
||||
strcpy(*fNewSignature, fSignature);
|
||||
}
|
||||
|
||||
*fNewEncoding = fEncoding;
|
||||
*fNewWarnUnencodable = fWarnUnencodable;
|
||||
*fNewSpellCheckStartOn = fSpellCheckStartOn;
|
||||
*fNewButtonBar = fButtonBar;
|
||||
|
||||
be_app->PostMessage(PREFS_CHANGED);
|
||||
|
||||
if (revert)
|
||||
{
|
||||
if (fLevel == L_EXPERT)
|
||||
strcpy(label, "Expert");
|
||||
else
|
||||
strcpy(label, "Beginner");
|
||||
|
||||
item = fLevelMenu->FindItem(label);
|
||||
if (item)
|
||||
item->SetMarked(true);
|
||||
|
||||
for (int i = fAccountMenu->CountItems();i-- > 0;)
|
||||
{
|
||||
if (BMenuItem *item = fAccountMenu->ItemAt(i))
|
||||
if (item->Message()->FindInt32("id") == *(int32 *)&fAccount)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
|
||||
strcpy(label,fReplyTo == ACCOUNT_USE_DEFAULT ? REPLYTO_USE_DEFAULT_TEXT
|
||||
: REPLYTO_FROM_MAIL_TEXT);
|
||||
if ((item = fReplyToMenu->FindItem(label)) != NULL)
|
||||
item->SetMarked(true);
|
||||
|
||||
strcpy(label, fWrap ? "On" : "Off");
|
||||
if ((item = fWrapMenu->FindItem(label)) != NULL)
|
||||
item->SetMarked(true);
|
||||
|
||||
strcpy(label, fAttachAttributes ? ATTRIBUTE_ON_TEXT : ATTRIBUTE_OFF_TEXT);
|
||||
if ((item = fAttachAttributesMenu->FindItem(label)) != NULL)
|
||||
item->SetMarked(true);
|
||||
|
||||
strcpy(label, fColoredQuotes ? "On" : "Off");
|
||||
if ((item = fColoredQuotesMenu->FindItem(label)) != NULL)
|
||||
item->SetMarked(true);
|
||||
|
||||
if (strcmp(fReplyPreamble->Text(), *fNewPreamble))
|
||||
fReplyPreamble->SetText(*fNewPreamble);
|
||||
|
||||
item = fSignatureMenu->FindItem(fSignature);
|
||||
if (item)
|
||||
item->SetMarked(true);
|
||||
|
||||
for (uint32 index = 0; kEncodings[index].flavor != B_MAIL_NULL_CONVERSION; index++)
|
||||
{
|
||||
if (kEncodings[index].flavor == *fNewEncoding)
|
||||
{
|
||||
item = fEncodingMenu->FindItem(kEncodings[index].name);
|
||||
if (item)
|
||||
item->SetMarked(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
strcpy(label, fWarnUnencodable ? "On" : "Off");
|
||||
if ((item = fWarnUnencodableMenu->FindItem(label)) != NULL)
|
||||
item->SetMarked(true);
|
||||
|
||||
strcpy(label, fSpellCheckStartOn ? "On" : "Off");
|
||||
if ((item = fSpellCheckStartOnMenu->FindItem(label)) != NULL)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
else
|
||||
Quit();
|
||||
break;
|
||||
|
||||
case P_FONT:
|
||||
family = NULL;
|
||||
style = NULL;
|
||||
int32 family_menu_index;
|
||||
if (msg->FindString("font", &family) == B_OK)
|
||||
{
|
||||
msg->FindString("style", &style);
|
||||
fNewFont->SetFamilyAndStyle(family, style);
|
||||
message.what = M_FONT;
|
||||
be_app->PostMessage(&message);
|
||||
}
|
||||
|
||||
/* grab this little tidbit so we can set the correct Family */
|
||||
if(msg->FindInt32("parent_index", &family_menu_index) == B_OK)
|
||||
fFontMenu->ItemAt(family_menu_index)->SetMarked(true);
|
||||
break;
|
||||
|
||||
case P_SIZE:
|
||||
old_size = (int32) fNewFont->Size();
|
||||
msg->FindInt32("size", &new_size);
|
||||
if (old_size != new_size)
|
||||
{
|
||||
fNewFont->SetSize(new_size);
|
||||
message.what = M_FONT;
|
||||
be_app->PostMessage(&message);
|
||||
}
|
||||
break;
|
||||
|
||||
case P_LEVEL:
|
||||
msg->FindInt32("level", fNewLevel);
|
||||
break;
|
||||
case P_WRAP:
|
||||
msg->FindBool("wrap", fNewWrap);
|
||||
break;
|
||||
case P_ATTACH_ATTRIBUTES:
|
||||
msg->FindBool("attachAttributes", fNewAttachAttributes);
|
||||
break;
|
||||
case P_COLORED_QUOTES:
|
||||
msg->FindBool("cquotes", fNewColoredQuotes);
|
||||
break;
|
||||
case P_ACCOUNT:
|
||||
msg->FindInt32("id",(int32 *)fNewAccount);
|
||||
break;
|
||||
case P_REPLYTO:
|
||||
msg->FindInt32("replyTo", fNewReplyTo);
|
||||
break;
|
||||
case P_REPLY_PREAMBLE:
|
||||
{
|
||||
int32 index = -1;
|
||||
if (msg->FindInt32("index", &index) < B_OK)
|
||||
break;
|
||||
BMenuItem *item = fReplyPreambleMenu->ItemAt(index);
|
||||
if (item == NULL) {
|
||||
msg->PrintToStream();
|
||||
break;
|
||||
}
|
||||
|
||||
BTextView *text = fReplyPreamble->TextView();
|
||||
// To do: insert at selection point rather than at the end.
|
||||
text->Insert(text->TextLength(), item->Label(), 2);
|
||||
}
|
||||
case P_SIG:
|
||||
free(*fNewSignature);
|
||||
if (msg->FindString("signature", &signature) == B_NO_ERROR)
|
||||
{
|
||||
*fNewSignature = (char *)malloc(strlen(signature) + 1);
|
||||
strcpy(*fNewSignature, signature);
|
||||
}
|
||||
else
|
||||
{
|
||||
*fNewSignature = (char *)malloc(strlen(SIG_NONE) + 1);
|
||||
strcpy(*fNewSignature, SIG_NONE);
|
||||
}
|
||||
break;
|
||||
case P_ENC:
|
||||
msg->FindInt32("encoding", (int32 *)fNewEncoding);
|
||||
break;
|
||||
case P_WARN_UNENCODABLE:
|
||||
msg->FindBool("warnUnencodable", fNewWarnUnencodable);
|
||||
break;
|
||||
case P_SPELL_CHECK_START_ON:
|
||||
msg->FindBool("spellCheckStartOn", fNewSpellCheckStartOn);
|
||||
break;
|
||||
case P_BUTTON_BAR:
|
||||
msg->FindInt8("bar", (int8 *)fNewButtonBar);
|
||||
be_app->PostMessage( PREFS_CHANGED );
|
||||
break;
|
||||
|
||||
default:
|
||||
BWindow::MessageReceived(msg);
|
||||
}
|
||||
|
||||
fFont.GetFamilyAndStyle(&old_family, &old_style);
|
||||
fNewFont->GetFamilyAndStyle(&new_family, &new_style);
|
||||
old_size = (int32) fFont.Size();
|
||||
new_size = (int32) fNewFont->Size();
|
||||
changed = old_size != new_size
|
||||
|| fLevel != *fNewLevel
|
||||
|| fWrap != *fNewWrap
|
||||
|| fAttachAttributes != *fNewAttachAttributes
|
||||
|| fColoredQuotes != *fNewColoredQuotes
|
||||
|| fAccount != *fNewAccount
|
||||
|| fReplyTo != *fNewReplyTo
|
||||
|| strcmp(old_family, new_family)
|
||||
|| strcmp(old_style, new_style)
|
||||
|| strcmp(fReplyPreamble->Text(), *fNewPreamble)
|
||||
|| strcmp(fSignature, *fNewSignature)
|
||||
|| fEncoding != *fNewEncoding
|
||||
|| fWarnUnencodable != *fNewWarnUnencodable
|
||||
|| fSpellCheckStartOn != *fNewSpellCheckStartOn
|
||||
|| fButtonBar != *fNewButtonBar;
|
||||
fRevert->SetEnabled(changed);
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildFontMenu(BFont *font)
|
||||
{
|
||||
|
||||
font_family def_family;
|
||||
font_style def_style;
|
||||
font_family f_family;
|
||||
font_style f_style;
|
||||
|
||||
BPopUpMenu *menu = new BPopUpMenu("");
|
||||
font->GetFamilyAndStyle(&def_family, &def_style);
|
||||
|
||||
int32 family_menu_index=0;
|
||||
int family_count = count_font_families();
|
||||
for (int family_loop = 0; family_loop < family_count; family_loop++) {
|
||||
get_font_family(family_loop, &f_family);
|
||||
BMenu *family_menu = new BMenu(f_family);
|
||||
|
||||
int style_count = count_font_styles(f_family);
|
||||
for (int style_loop = 0; style_loop < style_count; style_loop++) {
|
||||
get_font_style(f_family, style_loop, &f_style);
|
||||
|
||||
BMessage *msg = new BMessage(P_FONT);
|
||||
msg->AddString("font", f_family);
|
||||
msg->AddString("style", f_style);
|
||||
/* we send this to make setting the Family easier when things change */
|
||||
msg->AddInt32("parent_index", family_menu_index);
|
||||
|
||||
BMenuItem *item = new BMenuItem(f_style, msg);
|
||||
family_menu->AddItem(item);
|
||||
if ((strcmp(def_family, f_family) == 0) && (strcmp(def_style, f_style) == 0)) {
|
||||
item->SetMarked(true);
|
||||
}
|
||||
item->SetTarget(this);
|
||||
}
|
||||
|
||||
menu->AddItem(family_menu);
|
||||
BMenuItem *item = menu->ItemAt(family_menu_index);
|
||||
BMessage *msg = new BMessage(P_FONT);
|
||||
msg->AddString("font", f_family);
|
||||
|
||||
item->SetMessage(msg);
|
||||
item->SetTarget(this);
|
||||
if (strcmp(def_family, f_family) == 0) { item->SetMarked(true); }
|
||||
family_menu_index++;
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildLevelMenu(int32 level)
|
||||
{
|
||||
BMenuItem *item;
|
||||
BMessage *msg;
|
||||
BPopUpMenu *menu;
|
||||
|
||||
menu = new BPopUpMenu("");
|
||||
msg = new BMessage(P_LEVEL);
|
||||
msg->AddInt32("level", L_BEGINNER);
|
||||
menu->AddItem(item = new BMenuItem(MDR_DIALECT_CHOICE ("Beginner","初心者"),msg));
|
||||
if (level == L_BEGINNER)
|
||||
item->SetMarked(true);
|
||||
|
||||
msg = new BMessage(P_LEVEL);
|
||||
msg->AddInt32("level", L_EXPERT);
|
||||
menu->AddItem(item = new BMenuItem(MDR_DIALECT_CHOICE ("Expert","上級者"),msg));
|
||||
if (level == L_EXPERT)
|
||||
item->SetMarked(true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildAccountMenu(uint32 account)
|
||||
{
|
||||
BPopUpMenu *menu = new BPopUpMenu("");
|
||||
|
||||
BMenuItem *item;
|
||||
|
||||
//menu->SetRadioMode(true);
|
||||
BList chains;
|
||||
if (GetOutboundMailChains(&chains) < B_OK)
|
||||
{
|
||||
menu->AddItem(item = new BMenuItem("<no account found>",NULL));
|
||||
item->SetEnabled(false);
|
||||
return menu;
|
||||
}
|
||||
|
||||
BMessage *msg;
|
||||
for (int32 i = 0;i < chains.CountItems();i++)
|
||||
{
|
||||
BMailChain *chain = (BMailChain *)chains.ItemAt(i);
|
||||
item = new BMenuItem(chain->Name(),msg = new BMessage(P_ACCOUNT));
|
||||
|
||||
msg->AddInt32("id",chain->ID());
|
||||
|
||||
if (account == chain->ID())
|
||||
item->SetMarked(true);
|
||||
|
||||
menu->AddItem(item);
|
||||
delete chain;
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildReplyToMenu(int32 account)
|
||||
{
|
||||
BPopUpMenu *menu = new BPopUpMenu(B_EMPTY_STRING);
|
||||
|
||||
BMenuItem *item;
|
||||
BMessage *msg;
|
||||
menu->AddItem(item = new BMenuItem(REPLYTO_USE_DEFAULT_TEXT, msg = new BMessage(P_REPLYTO)));
|
||||
msg->AddInt32("replyTo", ACCOUNT_USE_DEFAULT);
|
||||
if (account == ACCOUNT_USE_DEFAULT)
|
||||
item->SetMarked(true);
|
||||
|
||||
menu->AddItem(item = new BMenuItem(REPLYTO_FROM_MAIL_TEXT, msg = new BMessage(P_REPLYTO)));
|
||||
msg->AddInt32("replyTo", ACCOUNT_FROM_MAIL);
|
||||
if (account == ACCOUNT_FROM_MAIL)
|
||||
item->SetMarked(true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BMenu *
|
||||
TPrefsWindow::BuildReplyPreambleMenu()
|
||||
{
|
||||
const char *substitutes[] = {
|
||||
/* To do: Not yet working, leave out for 2.0.0 beta 4:
|
||||
"%f - First name",
|
||||
"%l - Last name",
|
||||
*/
|
||||
MDR_DIALECT_CHOICE ("%n - Full name", "%n - フルネーム"),
|
||||
MDR_DIALECT_CHOICE ("%e - E-mail address", "%e - E-mailアドレス"),
|
||||
MDR_DIALECT_CHOICE ("%d - Date", "%d - 日付"),
|
||||
"",
|
||||
MDR_DIALECT_CHOICE ("\\n - Newline", "\\n - 空行"),
|
||||
NULL
|
||||
};
|
||||
|
||||
BMenu *menu = new BMenu(B_EMPTY_STRING);
|
||||
|
||||
for (int32 i = 0; substitutes[i]; i++)
|
||||
{
|
||||
if (*substitutes[i] == '\0')
|
||||
menu->AddSeparatorItem();
|
||||
else
|
||||
menu->AddItem(new BMenuItem(substitutes[i], new BMessage(P_REPLY_PREAMBLE)));
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildSignatureMenu(char *sig)
|
||||
{
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
BEntry entry;
|
||||
BFile file;
|
||||
BMenuItem *item;
|
||||
BMessage *msg;
|
||||
BPopUpMenu *menu;
|
||||
BQuery query;
|
||||
BVolume vol;
|
||||
BVolumeRoster volume;
|
||||
|
||||
menu = new BPopUpMenu("");
|
||||
|
||||
msg = new BMessage(P_SIG);
|
||||
msg->AddString("signature", SIG_NONE);
|
||||
menu->AddItem(item = new BMenuItem(SIG_NONE, msg));
|
||||
if (!strcmp(sig, SIG_NONE))
|
||||
item->SetMarked(true);
|
||||
|
||||
msg = new BMessage(P_SIG);
|
||||
msg->AddString("signature", SIG_RANDOM);
|
||||
menu->AddItem(item = new BMenuItem(SIG_RANDOM, msg));
|
||||
if (!strcmp(sig, SIG_RANDOM))
|
||||
item->SetMarked(true);
|
||||
menu->AddSeparatorItem();
|
||||
|
||||
volume.GetBootVolume(&vol);
|
||||
query.SetVolume(&vol);
|
||||
query.SetPredicate("_signature = *");
|
||||
query.Fetch();
|
||||
|
||||
while (query.GetNextEntry(&entry) == B_NO_ERROR) {
|
||||
file.SetTo(&entry, O_RDONLY);
|
||||
if (file.InitCheck() == B_NO_ERROR) {
|
||||
msg = new BMessage(P_SIG);
|
||||
file.ReadAttr("_signature", B_STRING_TYPE, 0, name, sizeof(name));
|
||||
msg->AddString("signature", name);
|
||||
menu->AddItem(item = new BMenuItem(name, msg));
|
||||
if (!strcmp(sig, name))
|
||||
item->SetMarked(true);
|
||||
}
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildSizeMenu(BFont *font)
|
||||
{
|
||||
char label[16];
|
||||
uint32 loop;
|
||||
int32 sizes[] = {9, 10, 11, 12, 14, 18, 24};
|
||||
float size;
|
||||
BMenuItem *item;
|
||||
BMessage *msg;
|
||||
BPopUpMenu *menu;
|
||||
|
||||
menu = new BPopUpMenu("");
|
||||
size = font->Size();
|
||||
for (loop = 0; loop < sizeof(sizes) / sizeof(int32); loop++) {
|
||||
msg = new BMessage(P_SIZE);
|
||||
msg->AddInt32("size", sizes[loop]);
|
||||
sprintf(label, "%ld", sizes[loop]);
|
||||
menu->AddItem(item = new BMenuItem(label, msg));
|
||||
if (sizes[loop] == (int32)size)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildBoolMenu(uint32 what,const char *boolItem,bool isTrue)
|
||||
{
|
||||
BMenuItem *item;
|
||||
BMessage *msg;
|
||||
BPopUpMenu *menu;
|
||||
|
||||
menu = new BPopUpMenu("");
|
||||
msg = new BMessage(what);
|
||||
msg->AddBool(boolItem, true);
|
||||
menu->AddItem(item = new BMenuItem("On", msg));
|
||||
if (isTrue)
|
||||
item->SetMarked(true);
|
||||
|
||||
msg = new BMessage(what);
|
||||
msg->AddInt32(boolItem, false);
|
||||
menu->AddItem(item = new BMenuItem("Off", msg));
|
||||
if (!isTrue)
|
||||
item->SetMarked(true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildWrapMenu(bool wrap)
|
||||
{
|
||||
return BuildBoolMenu(P_WRAP,"wrap",wrap);
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildAttachAttributesMenu(bool attachAttributes)
|
||||
{
|
||||
BMenuItem *item;
|
||||
BMessage *msg;
|
||||
BPopUpMenu *menu;
|
||||
|
||||
menu = new BPopUpMenu("");
|
||||
msg = new BMessage(P_ATTACH_ATTRIBUTES);
|
||||
msg->AddBool("attachAttributes", true);
|
||||
menu->AddItem(item = new BMenuItem(ATTRIBUTE_ON_TEXT, msg));
|
||||
if (attachAttributes)
|
||||
item->SetMarked(true);
|
||||
|
||||
msg = new BMessage(P_ATTACH_ATTRIBUTES);
|
||||
msg->AddInt32("attachAttributes", false);
|
||||
menu->AddItem(item = new BMenuItem(ATTRIBUTE_OFF_TEXT, msg));
|
||||
if (!attachAttributes)
|
||||
item->SetMarked(true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildColoredQuotesMenu(bool quote)
|
||||
{
|
||||
return BuildBoolMenu(P_COLORED_QUOTES,"cquotes",quote);
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildEncodingMenu(uint32 encoding)
|
||||
{
|
||||
uint32 loop;
|
||||
BMenuItem *item;
|
||||
BMessage *msg;
|
||||
BPopUpMenu *menu;
|
||||
|
||||
menu = new BPopUpMenu("");
|
||||
for (loop = 0; kEncodings[loop].flavor != B_MAIL_NULL_CONVERSION; loop++) {
|
||||
msg = new BMessage(P_ENC);
|
||||
msg->AddInt32("encoding", kEncodings[loop].flavor);
|
||||
menu->AddItem(item = new BMenuItem(kEncodings[loop].name, msg));
|
||||
if (encoding == kEncodings[loop].flavor)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
return menu;
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildWarnUnencodableMenu(bool warnUnencodable)
|
||||
{
|
||||
return BuildBoolMenu(P_WARN_UNENCODABLE,"warnUnencodable",warnUnencodable);
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildSpellCheckStartOnMenu(bool spellCheckStartOn)
|
||||
{
|
||||
return BuildBoolMenu(P_SPELL_CHECK_START_ON,"spellCheckStartOn",spellCheckStartOn);
|
||||
}
|
||||
|
||||
|
||||
BPopUpMenu *
|
||||
TPrefsWindow::BuildButtonBarMenu(bool show)
|
||||
{
|
||||
BMenuItem *item;
|
||||
BMessage *msg;
|
||||
BPopUpMenu *menu;
|
||||
|
||||
menu = new BPopUpMenu("");
|
||||
|
||||
msg = new BMessage(P_BUTTON_BAR);
|
||||
msg->AddInt8("bar", 1);
|
||||
menu->AddItem(item = new BMenuItem(ICON_LABEL_TEXT, msg));
|
||||
if (show & 1)
|
||||
item->SetMarked(true);
|
||||
|
||||
msg = new BMessage(P_BUTTON_BAR);
|
||||
msg->AddInt8("bar", 2);
|
||||
menu->AddItem(item = new BMenuItem(ICON_TEXT, msg));
|
||||
if (show & 2)
|
||||
item->SetMarked(true);
|
||||
|
||||
msg = new BMessage(P_BUTTON_BAR);
|
||||
msg->AddInt8("bar", 0);
|
||||
menu->AddItem(item = new BMenuItem(HIDE_TEXT, msg));
|
||||
if (!show)
|
||||
item->SetMarked(true);
|
||||
return menu;
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Prefs.h
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef _PREFS_H
|
||||
#define _PREFS_H
|
||||
|
||||
#include <Font.h>
|
||||
#include <Window.h>
|
||||
|
||||
#define ACCOUNT_USE_DEFAULT 0
|
||||
#define ACCOUNT_FROM_MAIL 1
|
||||
|
||||
#define PREF_WIDTH 340
|
||||
#define PREF_HEIGHT 330
|
||||
|
||||
#define SIG_NONE MDR_DIALECT_CHOICE ("None", "無し")
|
||||
#define SIG_RANDOM MDR_DIALECT_CHOICE ("Random", "自動選択")
|
||||
|
||||
struct EncodingItem
|
||||
{
|
||||
char *name;
|
||||
uint32 flavor;
|
||||
};
|
||||
|
||||
extern const EncodingItem kEncodings[];
|
||||
|
||||
|
||||
class Button;
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TPrefsWindow : public BWindow
|
||||
{
|
||||
public:
|
||||
TPrefsWindow(BRect rect, BFont *font, int32 *level, bool *warp,
|
||||
bool *attachAttributes, bool *cquotes, uint32 *account,
|
||||
int32 *replyTo, char **preamble, char **sig, uint32 *encoding,
|
||||
bool *warnUnencodable, bool *spellCheckStartOn, bool *buttonBar);
|
||||
~TPrefsWindow();
|
||||
|
||||
virtual void MessageReceived(BMessage*);
|
||||
|
||||
BPopUpMenu *BuildFontMenu(BFont*);
|
||||
BPopUpMenu *BuildLevelMenu(int32);
|
||||
BPopUpMenu *BuildAccountMenu(uint32);
|
||||
BPopUpMenu *BuildReplyToMenu(int32);
|
||||
BMenu *BuildReplyPreambleMenu();
|
||||
BPopUpMenu *BuildSignatureMenu(char*);
|
||||
BPopUpMenu *BuildSizeMenu(BFont*);
|
||||
BPopUpMenu *BuildWrapMenu(bool);
|
||||
BPopUpMenu *BuildAttachAttributesMenu(bool);
|
||||
BPopUpMenu *BuildColoredQuotesMenu(bool quote);
|
||||
BPopUpMenu *BuildEncodingMenu(uint32 encoding);
|
||||
BPopUpMenu *BuildWarnUnencodableMenu(bool warnUnencodable);
|
||||
BPopUpMenu *BuildSpellCheckStartOnMenu(bool spellCheckStartOn);
|
||||
BPopUpMenu *BuildButtonBarMenu(bool show);
|
||||
|
||||
private:
|
||||
BPopUpMenu *BuildBoolMenu(uint32 msg, const char *boolItem, bool isTrue);
|
||||
|
||||
bool fWrap;
|
||||
bool *fNewWrap;
|
||||
bool fAttachAttributes;
|
||||
bool *fNewAttachAttributes;
|
||||
bool fButtonBar;
|
||||
bool *fNewButtonBar;
|
||||
bool fColoredQuotes, *fNewColoredQuotes;
|
||||
uint32 fAccount;
|
||||
uint32 *fNewAccount;
|
||||
int32 fReplyTo;
|
||||
int32 *fNewReplyTo;
|
||||
char **fNewPreamble;
|
||||
char *fSignature;
|
||||
char **fNewSignature;
|
||||
int32 fLevel;
|
||||
int32 *fNewLevel;
|
||||
BFont fFont;
|
||||
BFont *fNewFont;
|
||||
uint32 fEncoding;
|
||||
uint32 *fNewEncoding;
|
||||
bool fWarnUnencodable;
|
||||
bool *fNewWarnUnencodable;
|
||||
bool fSpellCheckStartOn;
|
||||
bool *fNewSpellCheckStartOn;
|
||||
BButton *fRevert;
|
||||
|
||||
BPopUpMenu *fFontMenu;
|
||||
BPopUpMenu *fSizeMenu;
|
||||
BPopUpMenu *fLevelMenu;
|
||||
BPopUpMenu *fWrapMenu, *fColoredQuotesMenu;
|
||||
BPopUpMenu *fAttachAttributesMenu;
|
||||
BPopUpMenu *fAccountMenu, *fReplyToMenu;
|
||||
BMenu *fReplyPreambleMenu;
|
||||
BTextControl *fReplyPreamble;
|
||||
BPopUpMenu *fSignatureMenu;
|
||||
BPopUpMenu *fEncodingMenu;
|
||||
BPopUpMenu *fWarnUnencodableMenu;
|
||||
BPopUpMenu *fSpellCheckStartOnMenu;
|
||||
BPopUpMenu *fButtonBarMenu;
|
||||
};
|
||||
|
||||
#endif /* _PREFS_H */
|
||||
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include "QueryMenu.h"
|
||||
#include <Query.h>
|
||||
#include <Autolock.h>
|
||||
#include <MenuItem.h>
|
||||
#include <NodeMonitor.h>
|
||||
#include <VolumeRoster.h>
|
||||
#include <Looper.h>
|
||||
#include <Node.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <PopUpMenu.h>
|
||||
|
||||
|
||||
BLooper *QueryMenu::fQueryLooper = NULL;
|
||||
int32 QueryMenu::fMenuCount = 0;
|
||||
|
||||
|
||||
// ***
|
||||
// QHandler
|
||||
// ***
|
||||
|
||||
|
||||
class QHandler : public BHandler
|
||||
{
|
||||
public:
|
||||
QHandler(QueryMenu *queryMenu);
|
||||
virtual void MessageReceived(BMessage *msg);
|
||||
|
||||
QueryMenu *fQueryMenu;
|
||||
};
|
||||
|
||||
|
||||
QHandler::QHandler(QueryMenu *queryMenu)
|
||||
: BHandler((const char *)NULL),
|
||||
fQueryMenu(queryMenu)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void QHandler::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what)
|
||||
{
|
||||
case B_QUERY_UPDATE:
|
||||
fQueryMenu->DoQueryMessage(msg);
|
||||
break;
|
||||
|
||||
default:
|
||||
BHandler::MessageReceived(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ***
|
||||
// QueryMenu
|
||||
// ***
|
||||
|
||||
|
||||
QueryMenu::QueryMenu(const char *title, bool popUp, bool radioMode, bool autoRename)
|
||||
: BPopUpMenu(title, radioMode, autoRename),
|
||||
fTargetHandler(NULL),
|
||||
fPopUp(popUp)
|
||||
{
|
||||
if (atomic_add(&fMenuCount, 1) == 0)
|
||||
{
|
||||
fQueryLooper = new BLooper("Query Watcher");
|
||||
fQueryLooper->Run();
|
||||
}
|
||||
fQueryHandler = new QHandler(this);
|
||||
fQueryLooper->Lock();
|
||||
fQueryLooper->AddHandler(fQueryHandler);
|
||||
fQueryLooper->Unlock();
|
||||
|
||||
BMessenger mercury(fQueryHandler, fQueryLooper);
|
||||
fQuery = new BQuery();
|
||||
fQuery->SetTarget(mercury);
|
||||
}
|
||||
|
||||
|
||||
QueryMenu::~QueryMenu(void)
|
||||
{
|
||||
fCancelQuery = true;
|
||||
fQueryLock.Lock();
|
||||
delete fQuery;
|
||||
fQueryLock.Unlock();
|
||||
|
||||
fQueryLooper->Lock();
|
||||
fQueryLooper->RemoveHandler(fQueryHandler);
|
||||
delete fQueryHandler;
|
||||
if (atomic_add(&fMenuCount, -1) == 1)
|
||||
fQueryLooper->Quit();
|
||||
else
|
||||
fQueryLooper->Unlock();
|
||||
}
|
||||
|
||||
|
||||
void QueryMenu::DoQueryMessage(BMessage *msg)
|
||||
{
|
||||
int32 opcode;
|
||||
int64 directory;
|
||||
int32 device;
|
||||
int64 node;
|
||||
if (msg->FindInt32("opcode", &opcode) == B_OK
|
||||
&& msg->FindInt64("directory", &directory) == B_OK
|
||||
&& msg->FindInt32("device", &device) == B_OK
|
||||
&& msg->FindInt64("node", &node) == B_OK)
|
||||
{
|
||||
const char *name;
|
||||
if (opcode == B_ENTRY_CREATED && msg->FindString("name", &name) == B_OK)
|
||||
{
|
||||
entry_ref ref(device, directory, name);
|
||||
EntryCreated(ref, node);
|
||||
return;
|
||||
}
|
||||
else if (opcode == B_ENTRY_REMOVED)
|
||||
{
|
||||
BAutolock lock(fQueryLock);
|
||||
if (!lock.IsLocked())
|
||||
return;
|
||||
EntryRemoved(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
status_t QueryMenu::SetPredicate(const char *expr, BVolume *volume)
|
||||
{
|
||||
status_t status;
|
||||
|
||||
// Set the volume
|
||||
if (volume == NULL)
|
||||
{
|
||||
BVolume bootVolume;
|
||||
BVolumeRoster().GetBootVolume(&bootVolume);
|
||||
|
||||
if ( (status = fQuery->SetVolume(&bootVolume)) != B_OK)
|
||||
return status;
|
||||
}
|
||||
else if ((status = fQuery->SetVolume(volume)) != B_OK)
|
||||
return status;
|
||||
|
||||
if ((status = fQuery->SetPredicate(expr)) < B_OK)
|
||||
return status;
|
||||
|
||||
// Force query thread to exit if still running
|
||||
fCancelQuery = true;
|
||||
fQueryLock.Lock();
|
||||
|
||||
// Remove all existing menu items (if any... )
|
||||
RemoveEntries();
|
||||
fQueryLock.Unlock();
|
||||
|
||||
// Resolve Query/Build Menu in seperate thread
|
||||
thread_id thread;
|
||||
thread = spawn_thread(query_thread, "query menu thread", B_NORMAL_PRIORITY, this);
|
||||
|
||||
return resume_thread(thread);
|
||||
}
|
||||
|
||||
|
||||
void QueryMenu::RemoveEntries()
|
||||
{
|
||||
int64 node;
|
||||
for (int32 i = CountItems() - 1;i >= 0;i--)
|
||||
{
|
||||
if (ItemAt(i)->Message()->FindInt64("node", &node) == B_OK)
|
||||
RemoveItem(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int32 QueryMenu::query_thread(void *data)
|
||||
{
|
||||
return ((QueryMenu *)(data))->QueryThread();
|
||||
}
|
||||
|
||||
|
||||
int32 QueryMenu::QueryThread()
|
||||
{
|
||||
BAutolock lock(fQueryLock);
|
||||
|
||||
if (!lock.IsLocked())
|
||||
return B_ERROR;
|
||||
|
||||
// Begin resolving query
|
||||
fCancelQuery = false;
|
||||
fQuery->Fetch();
|
||||
|
||||
// Build Menu
|
||||
entry_ref ref;
|
||||
node_ref node;
|
||||
while (fQuery->GetNextRef(&ref) == B_OK && !fCancelQuery)
|
||||
{
|
||||
BEntry entry(&ref);
|
||||
entry.GetNodeRef(&node);
|
||||
EntryCreated(ref, node.node);
|
||||
}
|
||||
|
||||
// Remove the group separator if there are no groups or no items without groups
|
||||
BMenuItem *item;
|
||||
if (dynamic_cast<BSeparatorItem *>(item = ItemAt(0)) != NULL)
|
||||
RemoveItem(item);
|
||||
else if (dynamic_cast<BSeparatorItem *>(item = ItemAt(CountItems() - 1)) != NULL)
|
||||
RemoveItem(item);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t QueryMenu::SetTargetForItems(BHandler *handler)
|
||||
{
|
||||
fTargetHandler = handler;
|
||||
return BMenu::SetTargetForItems(handler);
|
||||
}
|
||||
|
||||
// Include the following version of SetTargetForItems() to eliminate
|
||||
// hidden polymorphism warning. Should be correct, but is unused and untested.
|
||||
|
||||
status_t QueryMenu::SetTargetForItems(BMessenger messenger)
|
||||
{
|
||||
if (messenger.IsTargetLocal())
|
||||
{
|
||||
BLooper *ignore; // don't care what value this gets
|
||||
fTargetHandler = messenger.Target(&ignore);
|
||||
return BMenu::SetTargetForItems(messenger);
|
||||
}
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
void QueryMenu::EntryCreated(const entry_ref &ref, ino_t node)
|
||||
{
|
||||
BMessage *msg;
|
||||
BMenuItem *item;
|
||||
|
||||
msg = new BMessage(B_REFS_RECEIVED);
|
||||
msg->AddRef("refs", &ref);
|
||||
msg->AddInt64("node", node);
|
||||
item = new BMenuItem(ref.name, msg);
|
||||
if (fTargetHandler)
|
||||
item->SetTarget(fTargetHandler);
|
||||
AddItem(item);
|
||||
}
|
||||
|
||||
|
||||
void QueryMenu::EntryRemoved(ino_t node)
|
||||
{
|
||||
// Search for item in menu
|
||||
BMenuItem *item;
|
||||
for (int32 i = 0;(item = ItemAt(i)) != NULL;i++)
|
||||
{
|
||||
// Is it our item?
|
||||
int64 inode;
|
||||
if ((item->Message())->FindInt64("node", &inode) == B_OK
|
||||
&& inode == node)
|
||||
{
|
||||
RemoveItem(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BPoint QueryMenu::ScreenLocation()
|
||||
{
|
||||
if (fPopUp)
|
||||
return BPopUpMenu::ScreenLocation();
|
||||
|
||||
return BMenu::ScreenLocation();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _QUERY_MENU
|
||||
#define _QUERY_MENU
|
||||
|
||||
#include <Locker.h>
|
||||
#include <PopUpMenu.h>
|
||||
|
||||
class BLooper;
|
||||
class BQuery;
|
||||
class BVolume;
|
||||
class QHandler;
|
||||
|
||||
class QueryMenu : public BPopUpMenu {
|
||||
friend QHandler;
|
||||
|
||||
public:
|
||||
QueryMenu(const char *title, bool popUp=false,
|
||||
bool radioMode = false, bool autoRename = false);
|
||||
virtual ~QueryMenu(void);
|
||||
|
||||
virtual BPoint ScreenLocation(void);
|
||||
virtual status_t SetTargetForItems(BHandler *handler);
|
||||
virtual status_t SetTargetForItems(BMessenger messenger);
|
||||
status_t SetPredicate(const char *expr, BVolume *vol = NULL);
|
||||
|
||||
protected:
|
||||
virtual void EntryCreated(const entry_ref &ref, ino_t node);
|
||||
virtual void EntryRemoved(ino_t node);
|
||||
virtual void RemoveEntries(void);
|
||||
|
||||
BHandler *fTargetHandler;
|
||||
static BLooper *fQueryLooper;
|
||||
|
||||
private:
|
||||
virtual void DoQueryMessage(BMessage *msg);
|
||||
static int32 query_thread(void *data);
|
||||
int32 QueryThread(void);
|
||||
|
||||
BLocker fQueryLock;
|
||||
BQuery *fQuery;
|
||||
QHandler *fQueryHandler;
|
||||
bool fCancelQuery;
|
||||
bool fPopUp;
|
||||
static int32 fMenuCount;
|
||||
};
|
||||
|
||||
#endif // #ifndef _QUERY_MENU
|
||||
@@ -0,0 +1,611 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Signature.cpp
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <Clipboard.h>
|
||||
#include <InterfaceKit.h>
|
||||
#include <StorageKit.h>
|
||||
|
||||
#include "Mail.h"
|
||||
#include "Signature.h"
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
extern BRect signature_window;
|
||||
extern int32 level;
|
||||
extern const char *kUndoStrings[];
|
||||
extern const char *kRedoStrings[];
|
||||
|
||||
const char kNameText[] = MDR_DIALECT_CHOICE ("Title:", "署名の名称:");
|
||||
const char kSigText[] = MDR_DIALECT_CHOICE ("Signature:", "署名:");
|
||||
|
||||
|
||||
//====================================================================
|
||||
|
||||
TSignatureWindow::TSignatureWindow(BRect rect)
|
||||
: BWindow (rect, MDR_DIALECT_CHOICE ("Signatures","署名の編集"), B_TITLED_WINDOW, 0),
|
||||
fFile(NULL)
|
||||
{
|
||||
BMenu *menu;
|
||||
BMenuBar *menu_bar;
|
||||
BMenuItem *item;
|
||||
|
||||
BRect r = Bounds();
|
||||
/*** Set up the menus ****/
|
||||
menu_bar = new BMenuBar(r, "MenuBar");
|
||||
menu = new BMenu(MDR_DIALECT_CHOICE ("Signature","S) 署名"));
|
||||
menu->AddItem(fNew = new BMenuItem(MDR_DIALECT_CHOICE ("New","N) 新規"), new BMessage(M_NEW), 'N'));
|
||||
fSignature = new TMenu(MDR_DIALECT_CHOICE ("Open","O) 開く"), INDEX_SIGNATURE, M_SIGNATURE);
|
||||
menu->AddItem(new BMenuItem(fSignature));
|
||||
menu->AddSeparatorItem();
|
||||
menu->AddItem(fSave = new BMenuItem(MDR_DIALECT_CHOICE ("Save","S) 保存"), new BMessage(M_SAVE), 'S'));
|
||||
menu->AddItem(fDelete = new BMenuItem(MDR_DIALECT_CHOICE ("Delete","T) 削除"), new BMessage(M_DELETE), 'T'));
|
||||
menu->AddSeparatorItem();
|
||||
menu->AddItem(new BMenuItem(MDR_DIALECT_CHOICE ("Close","W) 閉じる"), new BMessage(B_CLOSE_REQUESTED), 'W'));
|
||||
menu_bar->AddItem(menu);
|
||||
|
||||
menu = new BMenu(MDR_DIALECT_CHOICE ("Edit","E) 編集"));
|
||||
menu->AddItem(fUndo = new BMenuItem(MDR_DIALECT_CHOICE ("Undo","Z) やり直し"), new BMessage(B_UNDO), 'Z'));
|
||||
fUndo->SetTarget(NULL, this);
|
||||
menu->AddSeparatorItem();
|
||||
menu->AddItem(fCut = new BMenuItem(MDR_DIALECT_CHOICE ("Cut","X) 切り取り"), new BMessage(B_CUT), 'X'));
|
||||
fCut->SetTarget(NULL, this);
|
||||
menu->AddItem(fCopy = new BMenuItem(MDR_DIALECT_CHOICE ("Copy","C) コピー"), new BMessage(B_COPY), 'C'));
|
||||
fCopy->SetTarget(NULL, this);
|
||||
menu->AddItem(fPaste = new BMenuItem(MDR_DIALECT_CHOICE ("Paste","V) 貼り付け"), new BMessage(B_PASTE), 'V'));
|
||||
fPaste->SetTarget(NULL, this);
|
||||
menu->AddItem(item = new BMenuItem(MDR_DIALECT_CHOICE ("Select All","A) 全文選択"), new BMessage(M_SELECT), 'A'));
|
||||
item->SetTarget(NULL, this);
|
||||
menu_bar->AddItem(menu);
|
||||
|
||||
AddChild(menu_bar);
|
||||
/**** Done with the menu set up *****/
|
||||
|
||||
/**** Add on the panel, giving it the width and at least one vertical pixel *****/
|
||||
fSigView = new TSignatureView(BRect(0, menu_bar->Frame().bottom+1,
|
||||
rect.Width(), menu_bar->Frame().bottom+2));
|
||||
AddChild(fSigView);
|
||||
|
||||
/* resize the window to the correct height */
|
||||
fSigView->SetResizingMode(B_FOLLOW_NONE);
|
||||
ResizeTo(rect.Width()-2, fSigView->Frame().bottom-2);
|
||||
fSigView->SetResizingMode(B_FOLLOW_ALL);
|
||||
|
||||
SetSizeLimits(kSigWidth, RIGHT_BOUNDARY, r.top + 100, RIGHT_BOUNDARY);
|
||||
}
|
||||
|
||||
|
||||
TSignatureWindow::~TSignatureWindow()
|
||||
{
|
||||
signature_window = Frame();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSignatureWindow::MenusBeginning()
|
||||
{
|
||||
int32 finish = 0;
|
||||
int32 start = 0;
|
||||
BTextView *text_view;
|
||||
|
||||
fDelete->SetEnabled(fFile);
|
||||
fSave->SetEnabled(IsDirty());
|
||||
fUndo->SetEnabled(false); // ***TODO***
|
||||
|
||||
text_view = (BTextView *)fSigView->fName->ChildAt(0);
|
||||
if (text_view->IsFocus())
|
||||
text_view->GetSelection(&start, &finish);
|
||||
else
|
||||
fSigView->fTextView->GetSelection(&start, &finish);
|
||||
|
||||
fCut->SetEnabled(start != finish);
|
||||
fCopy->SetEnabled(start != finish);
|
||||
|
||||
fNew->SetEnabled(text_view->TextLength() | fSigView->fTextView->TextLength());
|
||||
be_clipboard->Lock();
|
||||
fPaste->SetEnabled(be_clipboard->Data()->HasData("text/plain", B_MIME_TYPE));
|
||||
be_clipboard->Unlock();
|
||||
|
||||
// Undo stuff
|
||||
bool isRedo = false;
|
||||
undo_state undoState = B_UNDO_UNAVAILABLE;
|
||||
|
||||
BTextView *focusTextView = dynamic_cast<BTextView *>(CurrentFocus());
|
||||
if (focusTextView != NULL)
|
||||
undoState = focusTextView->UndoState(&isRedo);
|
||||
|
||||
fUndo->SetLabel((isRedo) ? kRedoStrings[undoState] : kUndoStrings[undoState]);
|
||||
fUndo->SetEnabled(undoState != B_UNDO_UNAVAILABLE);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSignatureWindow::MessageReceived(BMessage* msg)
|
||||
{
|
||||
char *sig;
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
BFont *font;
|
||||
BTextView *text_view;
|
||||
entry_ref ref;
|
||||
off_t size;
|
||||
|
||||
switch(msg->what) {
|
||||
case CHANGE_FONT:
|
||||
msg->FindPointer("font", (void **)&font);
|
||||
fSigView->fTextView->SetFontAndColor(font);
|
||||
fSigView->fTextView->Invalidate(fSigView->fTextView->Bounds());
|
||||
break;
|
||||
|
||||
case M_NEW:
|
||||
if (Clear()) {
|
||||
fSigView->fName->SetText("");
|
||||
fSigView->fTextView->SetText(NULL, (int32)0);
|
||||
fSigView->fName->MakeFocus(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case M_SAVE:
|
||||
Save();
|
||||
break;
|
||||
|
||||
case M_DELETE:
|
||||
if (level == L_BEGINNER) {
|
||||
beep();
|
||||
if (!(new BAlert("",MDR_DIALECT_CHOICE (
|
||||
"Are you sure you want to delete this signature?",
|
||||
"この署名を削除しますか?"),
|
||||
MDR_DIALECT_CHOICE ("Cancel","取消l"),
|
||||
MDR_DIALECT_CHOICE ("Delete","削除"), NULL, B_WIDTH_AS_USUAL,
|
||||
B_WARNING_ALERT))->Go())
|
||||
break;
|
||||
}
|
||||
if (fFile) {
|
||||
delete fFile;
|
||||
fFile = NULL;
|
||||
fEntry.Remove();
|
||||
fSigView->fName->SetText("");
|
||||
fSigView->fTextView->SetText(NULL, (int32)0);
|
||||
fSigView->fName->MakeFocus(true);
|
||||
}
|
||||
break;
|
||||
|
||||
case M_SIGNATURE:
|
||||
if (Clear()) {
|
||||
msg->FindRef("ref", &ref);
|
||||
fEntry.SetTo(&ref);
|
||||
fFile = new BFile(&ref, O_RDWR);
|
||||
if (fFile->InitCheck() == B_NO_ERROR) {
|
||||
fFile->ReadAttr(INDEX_SIGNATURE, B_STRING_TYPE, 0, name, sizeof(name));
|
||||
fSigView->fName->SetText(name);
|
||||
fFile->GetSize(&size);
|
||||
sig = (char *)malloc(size);
|
||||
size = fFile->Read(sig, size);
|
||||
fSigView->fTextView->SetText(sig, size);
|
||||
fSigView->fName->MakeFocus(true);
|
||||
text_view = (BTextView *)fSigView->fName->ChildAt(0);
|
||||
text_view->Select(0, text_view->TextLength());
|
||||
fSigView->fTextView->fDirty = false;
|
||||
}
|
||||
else {
|
||||
fFile = NULL;
|
||||
beep();
|
||||
(new BAlert("", MDR_DIALECT_CHOICE (
|
||||
"An error occurred trying to open this signature.",
|
||||
"署名を開く時にエラーが発生しました。"),
|
||||
MDR_DIALECT_CHOICE ("Sorry","了解")))->Go();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
BWindow::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TSignatureWindow::QuitRequested()
|
||||
{
|
||||
if (Clear()) {
|
||||
BMessage msg(WINDOW_CLOSED);
|
||||
msg.AddInt32("kind", SIG_WINDOW);
|
||||
|
||||
be_app->PostMessage(&msg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSignatureWindow::FrameResized(float width, float height)
|
||||
{
|
||||
fSigView->FrameResized(width, height);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSignatureWindow::Show()
|
||||
{
|
||||
BTextView *text_view;
|
||||
|
||||
Lock();
|
||||
text_view = (BTextView *)fSigView->fName->TextView();
|
||||
fSigView->fName->MakeFocus(true);
|
||||
text_view->Select(0, text_view->TextLength());
|
||||
Unlock();
|
||||
|
||||
BWindow::Show();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TSignatureWindow::Clear()
|
||||
{
|
||||
int32 result;
|
||||
|
||||
if (IsDirty()) {
|
||||
beep();
|
||||
result = (new BAlert("",
|
||||
MDR_DIALECT_CHOICE ("Save changes to signature?","変更した署名を保存しますか?"),
|
||||
MDR_DIALECT_CHOICE ("Don't save","保存しない"),
|
||||
MDR_DIALECT_CHOICE ("Cancel","中止"),
|
||||
MDR_DIALECT_CHOICE ("Save","保存する"),
|
||||
B_WIDTH_AS_USUAL, B_WARNING_ALERT))->Go();
|
||||
if (result == 1)
|
||||
return false;
|
||||
if (result == 2)
|
||||
Save();
|
||||
}
|
||||
|
||||
delete fFile;
|
||||
fFile = NULL;
|
||||
fSigView->fTextView->fDirty = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TSignatureWindow::IsDirty()
|
||||
{
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
|
||||
if (fFile) {
|
||||
fFile->ReadAttr(INDEX_SIGNATURE, B_STRING_TYPE, 0, name, sizeof(name));
|
||||
if ((strcmp(name, fSigView->fName->Text())) || (fSigView->fTextView->fDirty))
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if ((strlen(fSigView->fName->Text())) ||
|
||||
(fSigView->fTextView->TextLength()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSignatureWindow::Save()
|
||||
{
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
int32 index = 0;
|
||||
status_t result;
|
||||
BDirectory dir;
|
||||
BEntry entry;
|
||||
BNodeInfo *node;
|
||||
BPath path;
|
||||
|
||||
if (!fFile) {
|
||||
find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
|
||||
dir.SetTo(path.Path());
|
||||
|
||||
if (dir.FindEntry("bemail", &entry) == B_NO_ERROR)
|
||||
dir.SetTo(&entry);
|
||||
else
|
||||
dir.CreateDirectory("bemail", &dir);
|
||||
|
||||
if (dir.InitCheck() != B_NO_ERROR)
|
||||
goto err_exit;
|
||||
|
||||
if (dir.FindEntry("signatures", &entry) == B_NO_ERROR)
|
||||
dir.SetTo(&entry);
|
||||
else
|
||||
dir.CreateDirectory("signatures", &dir);
|
||||
|
||||
if (dir.InitCheck() != B_NO_ERROR)
|
||||
goto err_exit;
|
||||
|
||||
fFile = new BFile();
|
||||
while(true) {
|
||||
sprintf(name, "signature_%ld", index++);
|
||||
if ((result = dir.CreateFile(name, fFile, true)) == B_NO_ERROR)
|
||||
break;
|
||||
if (result != EEXIST)
|
||||
goto err_exit;
|
||||
}
|
||||
dir.FindEntry(name, &fEntry);
|
||||
node = new BNodeInfo(fFile);
|
||||
node->SetType("text/plain");
|
||||
delete node;
|
||||
}
|
||||
|
||||
fSigView->fTextView->fDirty = false;
|
||||
fFile->Seek(0, 0);
|
||||
fFile->Write(fSigView->fTextView->Text(),
|
||||
fSigView->fTextView->TextLength());
|
||||
fFile->SetSize(fFile->Position());
|
||||
fFile->WriteAttr(INDEX_SIGNATURE, B_STRING_TYPE, 0, fSigView->fName->Text(),
|
||||
strlen(fSigView->fName->Text()) + 1);
|
||||
return;
|
||||
|
||||
err_exit:
|
||||
beep();
|
||||
(new BAlert("", MDR_DIALECT_CHOICE (
|
||||
"An error occurred trying to save this signature.",
|
||||
"署名を保存しようとした時にエラーが発生しました。"),
|
||||
MDR_DIALECT_CHOICE ("Sorry","了解")))->Go();
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TSignatureView::TSignatureView(BRect rect)
|
||||
: BBox(rect, "SigView", B_FOLLOW_ALL, B_WILL_DRAW)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSignatureView::AttachedToWindow()
|
||||
{
|
||||
BRect rect = Bounds();
|
||||
float name_text_length = StringWidth(kNameText);
|
||||
float sig_text_length = StringWidth(kSigText);
|
||||
float divide_length;
|
||||
|
||||
if (name_text_length > sig_text_length)
|
||||
divide_length = name_text_length;
|
||||
else
|
||||
divide_length = sig_text_length;
|
||||
|
||||
rect.InsetBy(8,0);
|
||||
rect.top+= 8;
|
||||
|
||||
fName = new TNameControl(rect, kNameText, new BMessage(NAME_FIELD));
|
||||
AddChild(fName);
|
||||
|
||||
fName->SetDivider(divide_length + 10);
|
||||
fName->SetAlignment(B_ALIGN_RIGHT, B_ALIGN_LEFT);
|
||||
|
||||
rect.OffsetBy(0,fName->Bounds().Height()+5);
|
||||
rect.bottom = rect.top + kSigHeight;
|
||||
rect.left = fName->TextView()->Frame().left;
|
||||
|
||||
BRect text = rect;
|
||||
text.OffsetTo(10,0);
|
||||
fTextView = new TSigTextView(rect, text);
|
||||
BScrollView *scroller = new BScrollView("SigScroller", fTextView, B_FOLLOW_ALL, 0, false, true);
|
||||
AddChild(scroller);
|
||||
scroller->ResizeBy(-1 * scroller->ScrollBar(B_VERTICAL)->Frame().Width() - 9, 0);
|
||||
scroller->MoveBy(7,0);
|
||||
|
||||
/* back up a bit to make room for the label */
|
||||
|
||||
rect = scroller->Frame();
|
||||
BStringView *stringView = new BStringView(rect, "SigLabel", kSigText);
|
||||
AddChild(stringView);
|
||||
|
||||
float tWidth, tHeight;
|
||||
stringView->GetPreferredSize(&tWidth, &tHeight);
|
||||
|
||||
/* the 5 is for the spacer in the TextView */
|
||||
|
||||
rect.OffsetBy(-1 *(tWidth) - 5, 0);
|
||||
rect.right = rect.left + tWidth;
|
||||
rect.bottom = rect.top + tHeight;
|
||||
|
||||
stringView->MoveTo(rect.LeftTop());
|
||||
stringView->ResizeTo(rect.Width(), rect.Height());
|
||||
|
||||
/* Resize the View to the correct height */
|
||||
scroller->SetResizingMode(B_FOLLOW_NONE);
|
||||
ResizeTo(Frame().Width(), scroller->Frame().bottom + 8);
|
||||
scroller->SetResizingMode(B_FOLLOW_ALL);
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TNameControl::TNameControl(BRect rect, const char *label, BMessage *msg)
|
||||
:BTextControl(rect, "", label, "", msg, B_FOLLOW_LEFT_RIGHT)
|
||||
{
|
||||
strcpy(fLabel, label);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TNameControl::AttachedToWindow()
|
||||
{
|
||||
BTextControl::AttachedToWindow();
|
||||
|
||||
SetDivider(StringWidth(fLabel) + 6);
|
||||
TextView()->SetMaxBytes(B_FILE_NAME_LENGTH - 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TNameControl::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what) {
|
||||
case M_SELECT:
|
||||
TextView()->Select(0, TextView()->TextLength());
|
||||
break;
|
||||
|
||||
default:
|
||||
BTextControl::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TSigTextView::TSigTextView(BRect frame, BRect text)
|
||||
:BTextView(frame, "SignatureView", text, B_FOLLOW_ALL, B_NAVIGABLE | B_WILL_DRAW)
|
||||
{
|
||||
fDirty = false;
|
||||
SetDoesUndo(true);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSigTextView::FrameResized(float /*width*/, float /*height*/)
|
||||
{
|
||||
BRect r(Bounds());
|
||||
r.InsetBy(3, 3);
|
||||
SetTextRect(r);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSigTextView::DeleteText(int32 offset, int32 len)
|
||||
{
|
||||
fDirty = true;
|
||||
BTextView::DeleteText(offset, len);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSigTextView::InsertText(const char *text, int32 len, int32 offset,
|
||||
const text_run_array *runs)
|
||||
{
|
||||
fDirty = true;
|
||||
BTextView::InsertText(text, len, offset, runs);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSigTextView::KeyDown(const char *key, int32 count)
|
||||
{
|
||||
bool up = false;
|
||||
int32 height;
|
||||
BRect r;
|
||||
|
||||
switch (key[0]) {
|
||||
case B_HOME:
|
||||
Select(0, 0);
|
||||
ScrollToSelection();
|
||||
break;
|
||||
|
||||
case B_END:
|
||||
Select(TextLength(), TextLength());
|
||||
ScrollToSelection();
|
||||
break;
|
||||
|
||||
case B_PAGE_UP:
|
||||
up = true;
|
||||
case B_PAGE_DOWN:
|
||||
r = Bounds();
|
||||
height = (int32)((up ? r.top - r.bottom : r.bottom - r.top) - 25);
|
||||
if ((up) && (!r.top))
|
||||
break;
|
||||
ScrollBy(0, height);
|
||||
break;
|
||||
|
||||
default:
|
||||
BTextView::KeyDown(key, count);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TSigTextView::MessageReceived(BMessage *msg)
|
||||
{
|
||||
char type[B_FILE_NAME_LENGTH];
|
||||
char *text;
|
||||
int32 end;
|
||||
int32 start;
|
||||
BFile file;
|
||||
BNodeInfo *node;
|
||||
entry_ref ref;
|
||||
off_t size;
|
||||
|
||||
switch (msg->what) {
|
||||
case B_SIMPLE_DATA:
|
||||
if (msg->HasRef("refs")) {
|
||||
msg->FindRef("refs", &ref);
|
||||
file.SetTo(&ref, O_RDONLY);
|
||||
if (file.InitCheck() == B_NO_ERROR) {
|
||||
node = new BNodeInfo(&file);
|
||||
node->GetType(type);
|
||||
delete node;
|
||||
file.GetSize(&size);
|
||||
if ((!strncasecmp(type, "text/", 5)) && (size)) {
|
||||
text = (char *)malloc(size);
|
||||
file.Read(text, size);
|
||||
Delete();
|
||||
GetSelection(&start, &end);
|
||||
Insert(text, size);
|
||||
Select(start, start + size);
|
||||
free(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
BTextView::MessageReceived(msg);
|
||||
break;
|
||||
|
||||
case M_SELECT:
|
||||
if (IsSelectable())
|
||||
Select(0, TextLength());
|
||||
break;
|
||||
|
||||
default:
|
||||
BTextView::MessageReceived(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Signature.h
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef _SIGNATURE_H
|
||||
#define _SIGNATURE_H
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Beep.h>
|
||||
#include <Box.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Font.h>
|
||||
#include <fs_index.h>
|
||||
#include <Menu.h>
|
||||
#include <MenuBar.h>
|
||||
#include <MenuItem.h>
|
||||
#include <Node.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Path.h>
|
||||
#include <TextControl.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
const float kSigHeight = 200;
|
||||
const float kSigWidth = 457;
|
||||
|
||||
#define INDEX_SIGNATURE "_signature"
|
||||
|
||||
class TMenu;
|
||||
class TNameControl;
|
||||
class TScrollView;
|
||||
class TSignatureView;
|
||||
class TSigTextView;
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TSignatureWindow : public BWindow {
|
||||
public:
|
||||
TSignatureWindow(BRect);
|
||||
~TSignatureWindow();
|
||||
virtual void MenusBeginning();
|
||||
virtual void MessageReceived(BMessage*);
|
||||
virtual bool QuitRequested();
|
||||
virtual void Show();
|
||||
void FrameResized(float width, float height);
|
||||
bool Clear();
|
||||
bool IsDirty();
|
||||
void Save();
|
||||
|
||||
private:
|
||||
BMenuItem *fCut;
|
||||
BMenuItem *fCopy;
|
||||
BMenuItem *fDelete;
|
||||
BMenuItem *fNew;
|
||||
BMenuItem *fPaste;
|
||||
BMenuItem *fSave;
|
||||
BMenuItem *fUndo;
|
||||
BEntry fEntry;
|
||||
BFile *fFile;
|
||||
TMenu *fSignature;
|
||||
TSignatureView *fSigView;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
class TSignatureView : public BBox {
|
||||
public:
|
||||
TSignatureView(BRect);
|
||||
virtual void AttachedToWindow();
|
||||
|
||||
TNameControl *fName;
|
||||
TSigTextView *fTextView;
|
||||
|
||||
private:
|
||||
float fOffset;
|
||||
};
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TNameControl : public BTextControl {
|
||||
public:
|
||||
TNameControl(BRect, const char*, BMessage*);
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage*);
|
||||
|
||||
private:
|
||||
char fLabel[100];
|
||||
};
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TSigTextView : public BTextView {
|
||||
public:
|
||||
TSigTextView(BRect, BRect);
|
||||
void FrameResized(float width, float height);
|
||||
|
||||
virtual void DeleteText(int32, int32);
|
||||
virtual void KeyDown(const char*, int32);
|
||||
virtual void InsertText(const char*, int32, int32, const text_run_array*);
|
||||
virtual void MessageReceived(BMessage*);
|
||||
|
||||
bool fDirty;
|
||||
|
||||
private:
|
||||
TSignatureView *fParent;
|
||||
};
|
||||
|
||||
#endif // #ifndef _SIGNATURE_H
|
||||
@@ -0,0 +1,574 @@
|
||||
<!-- This HTML file has been created by texi2html 1.29
|
||||
from ispell.texi on 23 April 1994 -->
|
||||
|
||||
<TITLE>GNU ISPELL V4.0 - GNU ISPELL</TITLE>
|
||||
<P>Go to the <A HREF="ispell_1.html">previous</A> section.<P>
|
||||
<H1><A NAME="SEC2" HREF="ispell_toc.html#SEC2">GNU ISPELL</A></H1>
|
||||
<CODE>Ispell</CODE> is a program that helps you to correct typos in a file,
|
||||
and to find the correct spelling of words. When presented with a
|
||||
word that is not in the dictionary, <CODE>ispell</CODE> attempts to find
|
||||
<DFN>near misses</DFN> that might include the word you meant.
|
||||
<P>
|
||||
This manual describes how to use ispell, as well as a little about
|
||||
its implementation.
|
||||
<P>
|
||||
<H2><A NAME="SEC3" HREF="ispell_toc.html#SEC3">Using ispell from emacs</A></H2>
|
||||
<P>
|
||||
<H3><A NAME="SEC4" HREF="ispell_toc.html#SEC4">Checking a single word</A></H3>
|
||||
<P>
|
||||
The simplest emacs command for calling ispell is 'M-$' (meta-dollar.
|
||||
On some terminals, you must type ESC-$.) This checks the spelling of
|
||||
the word under the cursor. If the word is found in the dictionary,
|
||||
then a message is printed in the echo area. Otherwise, ISPELL
|
||||
attempts to generate near misses.
|
||||
<P>
|
||||
If any near misses are found, they are displayed in a separate window,
|
||||
each preceded by a digit. If one of these is the word you wanted,
|
||||
just type its digit, and it will replace the original word in your
|
||||
buffer.
|
||||
<P>
|
||||
If no near miss is right, or if none are displayed, you
|
||||
have four choices:
|
||||
<P>
|
||||
<DL COMPACT>
|
||||
<DT><KBD>I</KBD>
|
||||
<DD><P>
|
||||
Insert the word in your private dictionary. Use this if you
|
||||
know that the word is spelled correctly.
|
||||
<P>
|
||||
<DT><KBD>A</KBD>
|
||||
<DD><P>
|
||||
Accept the word for the duration of this editing session, but do not
|
||||
put it in your private dictionary. Use this if you are not sure about
|
||||
the spelling of the word, but you do not want to look it up
|
||||
immediately. The next time you start ispell, it will have forgotten
|
||||
any accepted words. You can make it forget accepted words at any time
|
||||
by typing <KBD>M-x reload-ispell</KBD>.
|
||||
<P>
|
||||
<DT><KBD>SPC</KBD>
|
||||
<DD><P>
|
||||
Leave the word alone, and consider it misspelled if it is checked again.
|
||||
<P>
|
||||
<DT><KBD>R</KBD>
|
||||
<DD><P>
|
||||
Replace the word. This command prompts you for a string in the
|
||||
minibuffer. You may type more than one word, and each word you type
|
||||
is checked again, possibly finding other near misses. This command
|
||||
provides a handy way to close in on a word that you have no idea how
|
||||
to spell. You can keep trying different spellings until you find one
|
||||
that is close enough to get a near miss.
|
||||
<P>
|
||||
<DT><KBD>L</KBD>
|
||||
<DD><P>
|
||||
Lookup. Display words from the dictionary that contain a
|
||||
specified substring. The substring is a regular expression,
|
||||
which means it can contain special characters to be more
|
||||
selective about which words get displayed.
|
||||
See section `Regexps' in <CITE>emacs</CITE>. <P>
|
||||
If the only special character in the regular express is a leading
|
||||
<CODE>^</CODE>, then a very fast binary search will be used, instead of
|
||||
scanning the whole file.
|
||||
<P>
|
||||
Only a few matching words can be displayed in the ISPELL window.
|
||||
If you want to see more, use the <CODE>look</CODE> program directly from
|
||||
the shell.
|
||||
</DL>
|
||||
<P>
|
||||
Of course, you can also type ^G to stop the command without
|
||||
changing anything.
|
||||
<P>
|
||||
If you make a change that you don't like, just use emacs' normal undo
|
||||
feature See section `undo' in <CITE>emacs</CITE>.
|
||||
<P>
|
||||
<H3><A NAME="SEC5" HREF="ispell_toc.html#SEC5">Checking a whole buffer</A></H3>
|
||||
<P>
|
||||
If you want to check the spelling of all the words in a buffer, type
|
||||
the command <KBD>M-x ispell</KBD>. This command scans the file, and makes
|
||||
a list of all the misspelled words. When it is done, it moves the
|
||||
cursor to the first word on the list, and acts like you just typed M-$
|
||||
See section <A HREF="ispell_2.html#SEC4">Checking a single word</A>.
|
||||
<P>
|
||||
When you finish with one word, the cursor is automatically moved to the
|
||||
next. If you want to stop in the middle of the list type <KBD>Q</KBD> or
|
||||
<KBD>^G</KBD>. Later, you can pick up where you left off by typing
|
||||
<KBD>C-X $</KBD>.
|
||||
<P>
|
||||
<H3><A NAME="SEC6" HREF="ispell_toc.html#SEC6">Checking a region</A></H3>
|
||||
<P>
|
||||
You may check the words in the region with the command M-x ispell-region.
|
||||
See See section `mark' in <CITE>emacs</CITE>.
|
||||
<P>
|
||||
The commands available are the same as for checking a whole buffer.
|
||||
<P>
|
||||
<H2><A NAME="SEC7" HREF="ispell_toc.html#SEC7">Old Emacs</A></H2>
|
||||
<P>
|
||||
Until ispell becomes part of the standard emacs distribution, you will
|
||||
have to explicitly request that it be loaded. Put the following lines
|
||||
in your emacs init file See section `init file' in <CITE>emacs</CITE>.
|
||||
<P>
|
||||
<PRE>
|
||||
(autoload 'ispell "ispell" "Run ispell over buffer" t)
|
||||
(autoload 'ispell-region "ispell" "Run ispell over region" t)
|
||||
(autoload 'ispell-word "ispell" "Check word under cursor" t)
|
||||
(define-key esc-map "$" 'ispell-word)
|
||||
</PRE>
|
||||
<P>
|
||||
(It will do no harm to have these lines in your init file even after
|
||||
ispell is installed by default.)
|
||||
<P>
|
||||
<H2><A NAME="SEC8" HREF="ispell_toc.html#SEC8">Using ispell by itself</A></H2>
|
||||
<P>
|
||||
To check the words in a file, give the command <CODE>ispell FILE</CODE>. This
|
||||
will present a screen of information, and accept commands for every word
|
||||
that is not found in the dictionary.
|
||||
<P>
|
||||
The screen shows the offending word at the top, as well as two lines of
|
||||
context at the bottom. If any near misses are found, they are shown in the
|
||||
middle of the screen, each preceded by a digit.
|
||||
<P>
|
||||
You may use the same commands as inside of emacs to accept the word,
|
||||
place it in your private dictionary, select a near miss, or type a
|
||||
replacement See section <A HREF="ispell_2.html#SEC4">Checking a single word</A>. You may also choose from the following
|
||||
commands:
|
||||
<P>
|
||||
<DL COMPACT>
|
||||
<DT><KBD>?</KBD>
|
||||
<DD><P>
|
||||
Print a help message.
|
||||
<P>
|
||||
<DT><KBD>Q</KBD>
|
||||
<DD>Quit. Accept the rest of the words in the file and exit.
|
||||
<P>
|
||||
<DT><KBD>X</KBD>
|
||||
<DD>Exit. Abandon any changes made to this file and exit immediately. You
|
||||
are asked if you are sure you want to do this.
|
||||
<P>
|
||||
<DT><KBD>!</KBD>
|
||||
<DD>Shell escape. The shell command that you type is executed as
|
||||
a subprocess.
|
||||
<P>
|
||||
<DT><KBD>^Z</KBD>
|
||||
<DD>Suspend. On systems that support job control, this suspends ISPELL.
|
||||
On other systems it executes a subshell.
|
||||
<P>
|
||||
<DT><KBD>^L</KBD>
|
||||
<DD>Redraw the screen.
|
||||
</DL>
|
||||
<P>
|
||||
If you type your interrupt character (usually ^C or <KBD>DEL</KBD>), then
|
||||
ispell will immediately enter its command loop. If ispell was generating
|
||||
near misses at the time, then all that it had found so far will be
|
||||
displayed, along with a message stating that there might be more, and that
|
||||
you can type <KBD>RET</KBD> to generate them. If it was scanning the file, it
|
||||
will display <SAMP>`(INTERRUPT)'</SAMP> where it would normally display a bad word,
|
||||
and the commands that change the file will be disabled.
|
||||
<P>
|
||||
The feature is handy if you have left out a space between words, and
|
||||
ispell is futilely looking up the 1000 potential near misses for a
|
||||
string that has twenty letters.
|
||||
<P>
|
||||
<H2><A NAME="SEC9" HREF="ispell_toc.html#SEC9">Using ispell to look up individual words
|
||||
</A></H2>
|
||||
<P>
|
||||
When ispell is run with no arguments, it reads words from the standard
|
||||
input. For each one, it prints a message telling whether it is in the
|
||||
dictionary. For any words not in the dictionary, near misses are
|
||||
computed, and any that are found are printed.
|
||||
<P>
|
||||
<PRE>
|
||||
% ispell
|
||||
word: independant
|
||||
how about: independent
|
||||
word: xyzzy
|
||||
not found
|
||||
word: ^D
|
||||
</PRE>
|
||||
<P>
|
||||
<H2><A NAME="SEC10" HREF="ispell_toc.html#SEC10">Your private dictionary</A></H2>
|
||||
<P>
|
||||
Whenever ispell is started the file <TT>`ispell.words'</TT> is read from your
|
||||
home directory (if it exists). This file contains a list of words, one per
|
||||
line, and neither the order nor the case of the words is important. Ispell
|
||||
will consider all of the words good, and will use them as possible near
|
||||
misses.
|
||||
<P>
|
||||
The <KBD>I</KBD> command adds words to <TT>`ispell.words'</TT>, so normally you
|
||||
don't have to worry about the file. You may want to check it from
|
||||
time to time to make sure you have not accidentally inserted a
|
||||
misspelled word.
|
||||
<P>
|
||||
<H2><A NAME="SEC11" HREF="ispell_toc.html#SEC11">Compatibility with the traditional spell program
|
||||
</A></H2>
|
||||
<P>
|
||||
The <SAMP>`-u'</SAMP> flag tells ispell to be compatible with the traditional
|
||||
<SAMP>`spell'</SAMP> program. This flag is automatically turned on if the
|
||||
program is invoked by the name <SAMP>`spell'</SAMP>.
|
||||
<P>
|
||||
This flag causes the following behavior:
|
||||
<P>
|
||||
All of the files listed as arguments (or the standard input if none)
|
||||
are checked, and misspellings are printed on the standard output. The
|
||||
output is sorted, only one instance of each word appears (however,
|
||||
a word may appear more than once with different capitalizations.)
|
||||
<P>
|
||||
You may specify a file containing good words with <SAMP>`+filename'</SAMP>.
|
||||
<P>
|
||||
The troff commands <SAMP>`.so'</SAMP> and <SAMP>`.nx'</SAMP> (to include a file, or
|
||||
switch to a file, respectively) are obeyed, unless you give the flag
|
||||
<SAMP>`-i'</SAMP>.
|
||||
<P>
|
||||
The other <SAMP>`spell'</SAMP> flags <SAMP>`-v'</SAMP>, <SAMP>`-b'</SAMP>, <SAMP>`-x'</SAMP> and
|
||||
<SAMP>`-l'</SAMP> are ignored.
|
||||
<P>
|
||||
By the way, ispell seems to be about three times faster
|
||||
than traditional spell.
|
||||
<P>
|
||||
<H2><A NAME="SEC12" HREF="ispell_toc.html#SEC12">All commands in emacs and standalone modes
|
||||
</A></H2>
|
||||
<P>
|
||||
Commands valid in both modes:
|
||||
<P>
|
||||
DIGIT Select a near miss
|
||||
I Insert into private dictionary
|
||||
A Accept for this session
|
||||
SPACE Skip this time
|
||||
R Replace with one or more words
|
||||
L Lookup: search the dictionary using a regular expression
|
||||
<P>
|
||||
Standalone only:
|
||||
<P>
|
||||
Q Accept rest of file
|
||||
X Abandon changes
|
||||
! Shell escape
|
||||
? Help
|
||||
^Z Suspend
|
||||
^L Redraw screen
|
||||
^C Give up generating near misses, or show position in file
|
||||
<P>
|
||||
Emacs only:
|
||||
<P>
|
||||
M-$ Check word
|
||||
M-x ispell Check buffer
|
||||
M-x ispell-region Check region
|
||||
M-x reload-ispell Reread private dictionary
|
||||
M-x kill-ispell Kill current subprocess, and start a new one
|
||||
next time
|
||||
^G When in M-x ispell, stop working on current
|
||||
bad word list
|
||||
^X $ Resume working on bad word list.
|
||||
<P>
|
||||
<H2><A NAME="SEC13" HREF="ispell_toc.html#SEC13">Definition of a near miss</A></H2>
|
||||
<P>
|
||||
Two words are near each other if they can be made identical with one
|
||||
of the following changes to one of the words:
|
||||
<P>
|
||||
<PRE>
|
||||
Interchange two adjacent letters.
|
||||
Change one letter.
|
||||
Delete one letter.
|
||||
Add one letter.
|
||||
</PRE>
|
||||
<P>
|
||||
Someday, perhaps ispell will be extended so that words that sound
|
||||
alike would also be considered near misses. If you would like to
|
||||
implement this, see Knuth, Volume 3, page 392 for a description of the
|
||||
Soundex algorithm which might apply.
|
||||
<P>
|
||||
<H2><A NAME="SEC14" HREF="ispell_toc.html#SEC14">Flags to the ispell command</A></H2>
|
||||
<P>
|
||||
Ispell's arguments are parsed by getopt(3). Therefore, there is
|
||||
considerable flexibility about where to put spaces between arguments.
|
||||
The way to be safe is to give only one flag per dash, and put a space
|
||||
between a flag and its argument.
|
||||
<P>
|
||||
If ispell is run with no arguments, it enters <SAMP>`ask'</SAMP> mode See section <A HREF="ispell_2.html#SEC9">Using ispell to look up individual words
|
||||
</A>.
|
||||
With one or more file name arguments, it interactively checks each one.
|
||||
<P>
|
||||
<DL COMPACT>
|
||||
<DT><CODE>-p privname</CODE>
|
||||
<DD>Use privname as the private dictionary.
|
||||
<P>
|
||||
<DT><CODE>-d dictname</CODE>
|
||||
<DD>Use dictname as the system dictionary. You may also specify a system
|
||||
dictionary with the environment variable ISPELL_DICTIONARY.
|
||||
<P>
|
||||
<DT><CODE>-l</CODE>
|
||||
<DD>List mode. Scan the file, and print any misspellings on the standard
|
||||
output. This mode is compatible with the traditional spell program,
|
||||
except that the output is not sorted. See section <A HREF="ispell_2.html#SEC11">Compatibility with the traditional spell program
|
||||
</A>.
|
||||
<P>
|
||||
<DT><CODE>-u</CODE>
|
||||
<DD>Compatibility mode. See section <A HREF="ispell_2.html#SEC11">Compatibility with the traditional spell program
|
||||
</A>.
|
||||
<P>
|
||||
<DT><CODE>-a</CODE>
|
||||
<DD>Old style program interface, See section <A HREF="ispell_2.html#SEC15">How other programs can use ispell
|
||||
</A>.
|
||||
<P>
|
||||
<DT><CODE>-S</CODE>
|
||||
<DD>New program interface, See section <A HREF="ispell_2.html#SEC15">How other programs can use ispell
|
||||
</A>.
|
||||
<P>
|
||||
<DT><CODE>-D</CODE>
|
||||
<DD>Print the dictionary on the standard output with flags.
|
||||
<P>
|
||||
<DT><CODE>-E</CODE>
|
||||
<DD>Print the dictionary on the standard output with all flags expanded.
|
||||
<P>
|
||||
</DL>
|
||||
<P>
|
||||
<H2><A NAME="SEC15" HREF="ispell_toc.html#SEC15">How other programs can use ispell</A></H2>
|
||||
<P>
|
||||
Ispell can be used as a subprocess communicating through a pipe. Two
|
||||
interfaces are available:
|
||||
<P>
|
||||
<H2><A NAME="SEC16" HREF="ispell_toc.html#SEC16">New style, for EMACS</A></H2>
|
||||
<P>
|
||||
To use this interface, start ispell with the '-S' flag. Ispell will
|
||||
print a version number and greeting message that looks like:
|
||||
<P>
|
||||
<PRE>
|
||||
(1 "ISPELL V4.0")=
|
||||
</PRE>
|
||||
<P>
|
||||
The number is the version number of the protocol to be spoken over
|
||||
the pipe. The string is a message possibly of interest to the user.
|
||||
<P>
|
||||
All messages from ispell end in an equal sign, and ispell guarantees not to
|
||||
print an equal sign except to end a message. Therefore, if you do not want
|
||||
to deal with the greeting, just throw away characters until you get to an
|
||||
equals.
|
||||
<P>
|
||||
Ispell then reads one line commands from the standard input, and
|
||||
writes responses on the standard output.
|
||||
<P>
|
||||
If a command does not start with a colon, then it is considered a
|
||||
single word. The word is looked up in the dictionary, and if it is
|
||||
found, the response is <CODE>t</CODE>. If the word is not in the
|
||||
dictionary, and no near misses can be found, then the response is
|
||||
<CODE>nil</CODE>. If there are near misses, the response is a line containing
|
||||
a list of strings in lisp form. For example:
|
||||
<P>
|
||||
INPUT OUTPUT
|
||||
the t
|
||||
xxx nil
|
||||
teh ("tea" "ten" "the")
|
||||
<P>
|
||||
The near miss response is suitable for passing directly to the lisp
|
||||
<CODE>read</CODE> function, but it can also be parsed simply in C. In
|
||||
particular, ispell promises that the list will appear all on one line,
|
||||
and that the structure will not change. A parser that reads the whole
|
||||
line, then treats the parentheses and quotes as whitespace will work fine.
|
||||
<P>
|
||||
The list will contain a maximum of ten strings, and each string will be
|
||||
no longer than 40 characters. Also, the capitalization of the near
|
||||
misses is the same as the input word.
|
||||
<P>
|
||||
<H3><A NAME="SEC17" HREF="ispell_toc.html#SEC17">Colon commands</A></H3>
|
||||
<P>
|
||||
If the input line starts with a colon, then it is one of the following
|
||||
commands:
|
||||
<P>
|
||||
<CODE>:file <VAR>filename</VAR></CODE>
|
||||
Run the word checker over the named <VAR>filename</VAR>. The response is zero or
|
||||
more lines each containing a number. The numbers are file offsets of
|
||||
words that do not appear in the dictionary. Since the near miss
|
||||
checker is not run, this is fairly fast.
|
||||
<P>
|
||||
After the last number, there will be a line containing either <CODE>t</CODE> if
|
||||
the checker got to the end of the file, or <CODE>nil</CODE> if it received an
|
||||
interrupt. If ispell ignores any interrupts received except while
|
||||
scanning a file.
|
||||
<P>
|
||||
<CODE>:insert <VAR>word</VAR></CODE>
|
||||
Place <VAR>word</VAR> in the private dictionary.
|
||||
<P>
|
||||
<CODE>:accept <VAR>word</VAR></CODE>
|
||||
Do not complain about <VAR>word</VAR> for the rest of the session.
|
||||
<P>
|
||||
<CODE>:dump</CODE>
|
||||
Write the private dictionary.
|
||||
<P>
|
||||
<CODE>:reload</CODE>
|
||||
Reread the private dictionary.
|
||||
<P>
|
||||
<CODE>:tex</CODE>
|
||||
Enable the tex parser for future <CODE>:file</CODE> commands.
|
||||
<P>
|
||||
<CODE>:troff</CODE>
|
||||
Enable the tex parser for future <CODE>:file</CODE> commands.
|
||||
<P>
|
||||
<CODE>:generic</CODE>
|
||||
Disable any text formatter parsers for future <CODE>:file</CODE> commands.
|
||||
<P>
|
||||
<H2><A NAME="SEC18" HREF="ispell_toc.html#SEC18">Old style, like ITS</A></H2>
|
||||
<P>
|
||||
To use this interface, start ispell with the '-a' flag. Ispell
|
||||
will read words from its standard input (one per line), and write
|
||||
a one line of output for each one.
|
||||
<P>
|
||||
If the first character of the line is <CODE>*</CODE>, then word was found in the
|
||||
dictionary. (Other versions of ispell made a distinction between words
|
||||
that were found directly, and words that were found after suffix
|
||||
removal. These lines began with <CODE>+</CODE>, followed by a space, then
|
||||
followed by the root word. To remain compatible with these version,
|
||||
treat <CODE>+</CODE> and <CODE>*</CODE> the same.)
|
||||
<P>
|
||||
If the line starts with <CODE>&</CODE>, then the input word was not found, but
|
||||
some near misses were found. They are listed on the output line
|
||||
separated by spaces. Also, the output words will have the same
|
||||
capitalization as the input.
|
||||
<P>
|
||||
Finally, if the line starts with <CODE>#</CODE>, then the word was not in the
|
||||
dictionaries, and no near misses were found.
|
||||
<P>
|
||||
INPUT OUTPUT
|
||||
the *
|
||||
xxx #
|
||||
teh & tea ten the
|
||||
<P>
|
||||
<H2><A NAME="SEC19" HREF="ispell_toc.html#SEC19">How the suffix stripper works</A></H2>
|
||||
<P>
|
||||
This section is excerpted from the ITS spell.info file.
|
||||
<P>
|
||||
Words in SPELL's main dictionary (but not the private dictionary) may
|
||||
have flags associated with them to indicate the legality of suffixes
|
||||
without the need to keep the full suffixed words in the dictionary. The
|
||||
flags have "names" consisting of single letters. Their meaning is as
|
||||
follows:
|
||||
<P>
|
||||
Let # and @ be "variables" that can stand for any letter. Upper case
|
||||
letters are constants. "..." stands for any string of zero or more
|
||||
letters, but note that no word may exist in the dictionary which is not at
|
||||
least 2 letters long, so, for example, FLY may not be produced by placing
|
||||
the "Y" flag on "F". Also, no flag is effective unless the word that it
|
||||
creates is at least 4 letters long, so, for example, WED may not be
|
||||
produced by placing the "D" flag on "WE".
|
||||
<P>
|
||||
"V" flag:
|
||||
...E --> ...IVE as in CREATE --> CREATIVE
|
||||
if # .ne. E, ...# --> ...#IVE as in PREVENT --> PREVENTIVE
|
||||
<P>
|
||||
"N" flag:
|
||||
...E --> ...ION as in CREATE --> CREATION
|
||||
...Y --> ...ICATION as in MULTIPLY --> MULTIPLICATION
|
||||
if # .ne. E or Y, ...# --> ...#EN as in FALL --> FALLEN
|
||||
<P>
|
||||
"X" flag:
|
||||
...E --> ...IONS as in CREATE --> CREATIONS
|
||||
...Y --> ...ICATIONS as in MULTIPLY --> MULTIPLICATIONS
|
||||
if # .ne. E or Y, ...# --> ...#ENS as in WEAK --> WEAKENS
|
||||
<P>
|
||||
"H" flag:
|
||||
...Y --> ...IETH as in TWENTY --> TWENTIETH
|
||||
if # .ne. Y, ...# --> ...#TH as in HUNDRED --> HUNDREDTH
|
||||
<P>
|
||||
"Y" FLAG:
|
||||
... --> ...LY as in QUICK --> QUICKLY
|
||||
<P>
|
||||
"G" FLAG:
|
||||
...E --> ...ING as in FILE --> FILING
|
||||
if # .ne. E, ...# --> ...#ING as in CROSS --> CROSSING
|
||||
<P>
|
||||
"J" FLAG"
|
||||
...E --> ...INGS as in FILE --> FILINGS
|
||||
if # .ne. E, ...# --> ...#INGS as in CROSS --> CROSSINGS
|
||||
<P>
|
||||
"D" FLAG:
|
||||
...E --> ...ED as in CREATE --> CREATED
|
||||
if @ .ne. A, E, I, O, or U,
|
||||
...@Y --> ...@IED as in IMPLY --> IMPLIED
|
||||
if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
|
||||
...@# --> ...@#ED as in CROSS --> CROSSED
|
||||
or CONVEY --> CONVEYED
|
||||
<P>
|
||||
"T" FLAG:
|
||||
...E --> ...EST as in LATE --> LATEST
|
||||
if @ .ne. A, E, I, O, or U,
|
||||
...@Y --> ...@IEST as in DIRTY --> DIRTIEST
|
||||
if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
|
||||
...@# --> ...@#EST as in SMALL --> SMALLEST
|
||||
or GRAY --> GRAYEST
|
||||
<P>
|
||||
"R" FLAG:
|
||||
...E --> ...ER as in SKATE --> SKATER
|
||||
if @ .ne. A, E, I, O, or U,
|
||||
...@Y --> ...@IER as in MULTIPLY --> MULTIPLIER
|
||||
if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
|
||||
...@# --> ...@#ER as in BUILD --> BUILDER
|
||||
or CONVEY --> CONVEYER
|
||||
<P>
|
||||
"Z FLAG:
|
||||
...E --> ...ERS as in SKATE --> SKATERS
|
||||
if @ .ne. A, E, I, O, or U,
|
||||
...@Y --> ...@IERS as in MULTIPLY --> MULTIPLIERS
|
||||
if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
|
||||
...@# --> ...@#ERS as in BUILD --> BUILDERS
|
||||
or SLAY --> SLAYERS
|
||||
<P>
|
||||
"S" FLAG:
|
||||
if @ .ne. A, E, I, O, or U,
|
||||
...@Y --> ...@IES as in IMPLY --> IMPLIES
|
||||
if # .eq. S, X, Z, or H,
|
||||
...# --> ...#ES as in FIX --> FIXES
|
||||
if # .ne. S, X, Z, H, or Y, or (# = Y and @ = A, E, I, O, or U)
|
||||
...# --> ...#S as in BAT --> BATS
|
||||
or CONVEY --> CONVEYS
|
||||
<P>
|
||||
"P" FLAG:
|
||||
if @ .ne. A, E, I, O, or U,
|
||||
...@Y --> ...@INESS as in CLOUDY --> CLOUDINESS
|
||||
if # .ne. Y, or @ = A, E, I, O, or U,
|
||||
...@# --> ...@#NESS as in LATE --> LATENESS
|
||||
or GRAY --> GRAYNESS
|
||||
<P>
|
||||
"M" FLAG:
|
||||
... --> ...'S as in DOG --> DOG'S
|
||||
<P>
|
||||
Note: The existence of a flag on a root word in the directory is not by
|
||||
itself sufficient to cause SPELL to recognize the indicated word ending.
|
||||
If there is more than one root for which a flag will indicate a given word,
|
||||
only one of the roots is the correct one for which the flag is effective;
|
||||
generally it is the longest root. For example, the "D" rule implies that
|
||||
either PASS or PASSE, with a "D" flag, will yield PASSED. The flag must be
|
||||
on PASSE; it will be ineffective on PASS. This is because, when SPELL
|
||||
encounters the word PASSED and fails to find it in its dictionary, it
|
||||
strips off the "D" and looks up PASSE. Upon finding PASSE, it then accepts
|
||||
PASSED if and only if PASSE has the "D" flag. Only if the word PASSE is
|
||||
not in the main dictionary at all does the program strip off the "E" and
|
||||
search for PASS.
|
||||
<P>
|
||||
Therefore, never install a flag by hand. Instead, just add complete
|
||||
new words to the dictionary file, then use the build program with the
|
||||
options '-a -r' to replace as many roots with flags as possible.
|
||||
<P>
|
||||
<H2><A NAME="SEC20" HREF="ispell_toc.html#SEC20">Where it came from</A></H2>
|
||||
<P>
|
||||
I first came across ispell on TOPS-20 systems at MIT. I tracked it
|
||||
down to ITS where I found the PDP-10 assembly program. It appeared
|
||||
that it had been in use at the MIT-AI lab since at least the late
|
||||
1970's. I think it case from California before then.
|
||||
<P>
|
||||
I wrote the first C implementation in the spring of 1983, mostly
|
||||
working from the ITS INFO file.
|
||||
<P>
|
||||
The present version was created in early 1988, and was motivated by
|
||||
the desire to make it run on 80286's, and to provide a better interface
|
||||
for GNU EMACS.
|
||||
<P>
|
||||
There is another widely distributed version of ispell, which was forked
|
||||
from my 1983 version and has a different set of features and clever
|
||||
extensions. It is available from the directory /u/public/ispell at
|
||||
celray.cs.yale.edu.
|
||||
<P>
|
||||
People who have contributed to various versions of ispell include: Walt
|
||||
Buehring, Mark Davies, Geoff Kuenning, Rober McQueer, Ashwin Ram, Greg
|
||||
Schaffer, Perry Smith, Ken Stevens, and Andrew Vignaux.
|
||||
<P>
|
||||
Pace Willisson <BR>
|
||||
[email protected] [email protected] <BR>
|
||||
(617) 625--3452
|
||||
<P>
|
||||
<P>Go to the <A HREF="ispell_1.html">previous</A> section.<P>
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Status.cpp
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <StorageKit.h>
|
||||
|
||||
#include "Mail.h"
|
||||
#include "Status.h"
|
||||
|
||||
|
||||
//====================================================================
|
||||
|
||||
TStatusWindow::TStatusWindow(BRect rect, BWindow *window, const char *status)
|
||||
: BWindow(rect, "", B_MODAL_WINDOW, B_NOT_RESIZABLE)
|
||||
{
|
||||
BRect r(0, 0, STATUS_WIDTH, STATUS_HEIGHT);
|
||||
|
||||
r.InsetBy(-1, -1);
|
||||
fView = new TStatusView(r, window, status);
|
||||
Lock();
|
||||
AddChild(fView);
|
||||
Unlock();
|
||||
Show();
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// #pragma mark -
|
||||
|
||||
|
||||
TStatusView::TStatusView(BRect rect, BWindow *window, const char *status)
|
||||
: BBox(rect, "", B_FOLLOW_ALL, B_WILL_DRAW)
|
||||
{
|
||||
fWindow = window;
|
||||
fString = status;
|
||||
|
||||
SetViewColor(VIEW_COLOR, VIEW_COLOR, VIEW_COLOR);
|
||||
|
||||
BFont font = *be_plain_font;
|
||||
font.SetSize(FONT_SIZE);
|
||||
SetFont(&font);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TStatusView::AttachedToWindow()
|
||||
{
|
||||
BRect r(STATUS_FIELD_H, STATUS_FIELD_V,
|
||||
STATUS_FIELD_WIDTH, STATUS_FIELD_V + STATUS_FIELD_HEIGHT);
|
||||
|
||||
fStatus = new BTextControl(r, "", STATUS_TEXT, fString, new BMessage(STATUS));
|
||||
AddChild(fStatus);
|
||||
|
||||
BFont font = *be_plain_font;
|
||||
font.SetSize(FONT_SIZE);
|
||||
fStatus->SetFont(&font);
|
||||
fStatus->SetDivider(StringWidth(STATUS_TEXT) + 6);
|
||||
fStatus->BTextControl::MakeFocus(true);
|
||||
|
||||
r.Set(S_OK_BUTTON_X1, S_OK_BUTTON_Y1, S_OK_BUTTON_X2, S_OK_BUTTON_Y2);
|
||||
BButton *button = new BButton(r, "", S_OK_BUTTON_TEXT, new BMessage(OK));
|
||||
AddChild(button);
|
||||
button->SetTarget(this);
|
||||
button->MakeDefault(true);
|
||||
|
||||
r.Set(S_CANCEL_BUTTON_X1, S_CANCEL_BUTTON_Y1, S_CANCEL_BUTTON_X2, S_CANCEL_BUTTON_Y2);
|
||||
button = new BButton(r, "", S_CANCEL_BUTTON_TEXT, new BMessage(CANCEL));
|
||||
AddChild(button);
|
||||
button->SetTarget(this);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TStatusView::MessageReceived(BMessage *msg)
|
||||
{
|
||||
char name[B_FILE_NAME_LENGTH];
|
||||
char new_name[B_FILE_NAME_LENGTH];
|
||||
int32 index = 0;
|
||||
uint32 loop;
|
||||
status_t result;
|
||||
BDirectory dir;
|
||||
BEntry entry;
|
||||
BFile file;
|
||||
BNodeInfo *node;
|
||||
BPath path;
|
||||
|
||||
switch (msg->what)
|
||||
{
|
||||
case STATUS:
|
||||
break;
|
||||
|
||||
case OK:
|
||||
if (!Exists(fStatus->Text())) {
|
||||
find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
|
||||
dir.SetTo(path.Path());
|
||||
if (dir.FindEntry("bemail", &entry) == B_NO_ERROR)
|
||||
dir.SetTo(&entry);
|
||||
else
|
||||
dir.CreateDirectory("bemail", &dir);
|
||||
if (dir.InitCheck() != B_NO_ERROR)
|
||||
goto err_exit;
|
||||
if (dir.FindEntry("status", &entry) == B_NO_ERROR)
|
||||
dir.SetTo(&entry);
|
||||
else
|
||||
dir.CreateDirectory("status", &dir);
|
||||
if (dir.InitCheck() == B_NO_ERROR) {
|
||||
sprintf(name, "%s", fStatus->Text());
|
||||
if (strlen(name) > B_FILE_NAME_LENGTH - 10)
|
||||
name[B_FILE_NAME_LENGTH - 10] = 0;
|
||||
for (loop = 0; loop < strlen(name); loop++) {
|
||||
if (name[loop] == '/')
|
||||
name[loop] = '\\';
|
||||
}
|
||||
strcpy(new_name, name);
|
||||
while (1) {
|
||||
if ((result = dir.CreateFile(new_name, &file, true)) == B_NO_ERROR)
|
||||
break;
|
||||
if (result != EEXIST)
|
||||
goto err_exit;
|
||||
sprintf(new_name, "%s_%ld", name, index++);
|
||||
}
|
||||
dir.FindEntry(new_name, &entry);
|
||||
node = new BNodeInfo(&file);
|
||||
node->SetType("text/plain");
|
||||
delete node;
|
||||
file.Write(fStatus->Text(), strlen(fStatus->Text()) + 1);
|
||||
file.SetSize(file.Position());
|
||||
file.WriteAttr(INDEX_STATUS, B_STRING_TYPE, 0, fStatus->Text(),
|
||||
strlen(fStatus->Text()) + 1);
|
||||
}
|
||||
}
|
||||
err_exit:
|
||||
{
|
||||
BMessage closeCstmMsg(M_CLOSE_CUSTOM);
|
||||
closeCstmMsg.AddString("status", fStatus->Text());
|
||||
fWindow->PostMessage(&closeCstmMsg);
|
||||
// will fall through
|
||||
}
|
||||
case CANCEL:
|
||||
Window()->Quit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TStatusView::Exists(const char *status)
|
||||
{
|
||||
BVolume volume;
|
||||
BVolumeRoster().GetBootVolume(&volume);
|
||||
|
||||
BQuery query;
|
||||
query.SetVolume(&volume);
|
||||
query.PushAttr(INDEX_STATUS);
|
||||
query.PushString(status);
|
||||
query.PushOp(B_EQ);
|
||||
query.Fetch();
|
||||
|
||||
BEntry entry;
|
||||
if (query.GetNextEntry(&entry) == B_NO_ERROR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Status.h
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef _STATUS_H
|
||||
#define _STATUS_H
|
||||
|
||||
#include <Beep.h>
|
||||
#include <Box.h>
|
||||
#include <Button.h>
|
||||
#include <fs_index.h>
|
||||
#include <Node.h>
|
||||
#include <NodeInfo.h>
|
||||
#include <Path.h>
|
||||
#include <Query.h>
|
||||
#include <TextControl.h>
|
||||
#include <Volume.h>
|
||||
#include <VolumeRoster.h>
|
||||
#include <Window.h>
|
||||
|
||||
#define STATUS_WIDTH 220
|
||||
#define STATUS_HEIGHT 80
|
||||
|
||||
#define STATUS_TEXT "Status:"
|
||||
#define STATUS_FIELD_H 10
|
||||
#define STATUS_FIELD_V 8
|
||||
#define STATUS_FIELD_WIDTH (STATUS_WIDTH - STATUS_FIELD_H)
|
||||
#define STATUS_FIELD_HEIGHT 16
|
||||
|
||||
#define BUTTON_WIDTH 70
|
||||
#define BUTTON_HEIGHT 20
|
||||
|
||||
#define S_OK_BUTTON_X1 (STATUS_WIDTH - BUTTON_WIDTH - 6)
|
||||
#define S_OK_BUTTON_Y1 (STATUS_HEIGHT - (BUTTON_HEIGHT + 10))
|
||||
#define S_OK_BUTTON_X2 (S_OK_BUTTON_X1 + BUTTON_WIDTH)
|
||||
#define S_OK_BUTTON_Y2 (S_OK_BUTTON_Y1 + BUTTON_HEIGHT)
|
||||
#define S_OK_BUTTON_TEXT "OK"
|
||||
|
||||
#define S_CANCEL_BUTTON_X1 (S_OK_BUTTON_X1 - (BUTTON_WIDTH + 10))
|
||||
#define S_CANCEL_BUTTON_Y1 S_OK_BUTTON_Y1
|
||||
#define S_CANCEL_BUTTON_X2 (S_CANCEL_BUTTON_X1 + BUTTON_WIDTH)
|
||||
#define S_CANCEL_BUTTON_Y2 S_OK_BUTTON_Y2
|
||||
#define S_CANCEL_BUTTON_TEXT "Cancel"
|
||||
|
||||
#define INDEX_STATUS "_status"
|
||||
|
||||
enum status_messages {
|
||||
STATUS = 128,
|
||||
OK,
|
||||
CANCEL
|
||||
};
|
||||
|
||||
class TStatusView;
|
||||
|
||||
//====================================================================
|
||||
|
||||
class TStatusWindow : public BWindow
|
||||
{
|
||||
public:
|
||||
TStatusWindow(BRect, BWindow *, const char *status);
|
||||
|
||||
private:
|
||||
TStatusView *fView;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
class TStatusView : public BBox
|
||||
{
|
||||
public:
|
||||
TStatusView(BRect, BWindow *, const char *);
|
||||
|
||||
virtual void AttachedToWindow();
|
||||
virtual void MessageReceived(BMessage *);
|
||||
bool Exists(const char *);
|
||||
|
||||
private:
|
||||
const char *fString;
|
||||
BTextControl *fStatus;
|
||||
BWindow *fWindow;
|
||||
};
|
||||
|
||||
#endif // #ifndef _STATUS_H
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Utilities.cpp
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <String.h>
|
||||
#include <Node.h>
|
||||
#include <TypeConstants.h>
|
||||
#include <fs_attr.h>
|
||||
|
||||
#include <MailMessage.h>
|
||||
|
||||
#include <MDRLanguage.h>
|
||||
|
||||
#include "Utilities.h"
|
||||
|
||||
|
||||
status_t
|
||||
WriteAttrString(BNode *node, const char *attr, const char *value)
|
||||
{
|
||||
if (!value)
|
||||
value = B_EMPTY_STRING;
|
||||
|
||||
ssize_t size = node->WriteAttr(attr, B_STRING_TYPE, 0, value, strlen(value) + 1);
|
||||
|
||||
return size >= 0 ? B_OK : size;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ReadAttrString(BNode *node, const char *attr, BString *value)
|
||||
{
|
||||
attr_info attrInfo;
|
||||
|
||||
value->SetTo("");
|
||||
status_t status = node->GetAttrInfo(attr, &attrInfo);
|
||||
if (status < B_OK)
|
||||
return status;
|
||||
|
||||
ssize_t size = node->ReadAttr(attr, B_STRING_TYPE, 0, value->LockBuffer(attrInfo.size + 1), attrInfo.size);
|
||||
value->UnlockBuffer();
|
||||
|
||||
return size >= 0 ? B_OK : size;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// case-insensitive version of strcmp
|
||||
//
|
||||
|
||||
int32
|
||||
cistrcmp(const char *str1, const char *str2)
|
||||
{
|
||||
char c1;
|
||||
char c2;
|
||||
int32 len;
|
||||
int32 loop;
|
||||
|
||||
len = strlen(str1) + 1;
|
||||
for (loop = 0; loop < len; loop++)
|
||||
{
|
||||
c1 = str1[loop];
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
c2 = str2[loop];
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
if (c1 == c2)
|
||||
{
|
||||
}
|
||||
else if (c1 < c2)
|
||||
return -1;
|
||||
else if (c1 > c2 || !c2)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//====================================================================
|
||||
// case-insensitive version of strncmp
|
||||
//
|
||||
|
||||
int32
|
||||
cistrncmp(const char *str1, const char *str2, int32 max)
|
||||
{
|
||||
char c1;
|
||||
char c2;
|
||||
int32 loop;
|
||||
|
||||
for (loop = 0; loop < max; loop++)
|
||||
{
|
||||
c1 = *str1++;
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
c2 = *str2++;
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
if (c1 == c2)
|
||||
{
|
||||
}
|
||||
else if (c1 < c2)
|
||||
return -1;
|
||||
else if (c1 > c2 || !c2)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// case-insensitive version of strstr
|
||||
//
|
||||
|
||||
char *
|
||||
cistrstr(const char *cs, const char *ct)
|
||||
{
|
||||
char c1;
|
||||
char c2;
|
||||
int32 cs_len;
|
||||
int32 ct_len;
|
||||
int32 loop1;
|
||||
int32 loop2;
|
||||
|
||||
cs_len = strlen(cs);
|
||||
ct_len = strlen(ct);
|
||||
for (loop1 = 0; loop1 < cs_len; loop1++)
|
||||
{
|
||||
if (cs_len - loop1 < ct_len)
|
||||
return NULL;
|
||||
|
||||
for (loop2 = 0; loop2 < ct_len; loop2++)
|
||||
{
|
||||
c1 = cs[loop1 + loop2];
|
||||
if ((c1 >= 'A') && (c1 <= 'Z'))
|
||||
c1 += ('a' - 'A');
|
||||
c2 = ct[loop2];
|
||||
if ((c2 >= 'A') && (c2 <= 'Z'))
|
||||
c2 += ('a' - 'A');
|
||||
if (c1 != c2)
|
||||
goto next;
|
||||
}
|
||||
return const_cast<char *>(&cs[loop1]);
|
||||
next:
|
||||
// label must be followed by a statement
|
||||
;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// return length of \n terminated line
|
||||
//
|
||||
|
||||
int32
|
||||
linelen(char *str, int32 len, bool header)
|
||||
{
|
||||
int32 loop;
|
||||
|
||||
for (loop = 0; loop < len; loop++)
|
||||
{
|
||||
if (str[loop] == '\n')
|
||||
{
|
||||
if (!header || loop < 2
|
||||
|| (header && str[loop + 1] != ' ' && str[loop + 1] != '\t'))
|
||||
return loop + 1;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//
|
||||
// Utilities.h
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#ifndef _UTILITIES_H
|
||||
#define _UTILITIES_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
class BEmailMessage;
|
||||
|
||||
//====================================================================
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
class BNode;
|
||||
extern status_t WriteAttrString(BNode *node, const char *attr, const char *value);
|
||||
extern status_t ReadAttrString(BNode *node, const char *attr, BString *value);
|
||||
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int32 cistrcmp(const char *, const char *);
|
||||
int32 cistrncmp(const char *, const char *, int32);
|
||||
char *cistrstr(const char *, const char *);
|
||||
int32 linelen(char*, int32, bool);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef _UTILITIES_H
|
||||
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <File.h>
|
||||
#include <Node.h>
|
||||
#include <fs_attr.h>
|
||||
#include <Message.h>
|
||||
#include "WIndex.h"
|
||||
|
||||
#define IVERSION 1
|
||||
|
||||
static int32 kCRCTable = 0;
|
||||
|
||||
int32 cmp_i_entries( const WIndexEntry *e1, const WIndexEntry *e2 );
|
||||
void gen_crc_table();
|
||||
unsigned long update_crc( unsigned long crc_accum, const char *data_blk_ptr, int data_blk_size );
|
||||
|
||||
|
||||
FileEntry::FileEntry( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FileEntry::FileEntry( const char *entryStr )
|
||||
: BString( entryStr )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
status_t WIndex::SetTo( const char *dataPath, const char *indexPath )
|
||||
{
|
||||
BFile *dataFile;
|
||||
BFile indexFile;
|
||||
|
||||
dataFile = new BFile();
|
||||
|
||||
if( dataFile->SetTo( dataPath, B_READ_ONLY ) != B_OK )
|
||||
return B_ERROR;
|
||||
else
|
||||
{
|
||||
bool buildIndex = true;
|
||||
SetTo( dataFile );
|
||||
|
||||
time_t mtime;
|
||||
time_t modified;
|
||||
|
||||
dataFile->GetModificationTime( &mtime );
|
||||
|
||||
if( indexFile.SetTo( indexPath, B_READ_ONLY ) == B_OK )
|
||||
{
|
||||
attr_info info;
|
||||
if( (indexFile.GetAttrInfo( "WINDEX:version", &info ) == B_NO_ERROR) )
|
||||
{
|
||||
uint32 version = 0;
|
||||
indexFile.ReadAttr( "WINDEX:version", B_UINT32_TYPE, 0, &version, 4 );
|
||||
if( IVERSION == version )
|
||||
{
|
||||
if( (indexFile.GetAttrInfo( "WINDEX:modified", &info ) == B_NO_ERROR) )
|
||||
{
|
||||
indexFile.ReadAttr( "WINDEX:modified", B_UINT32_TYPE, 0, &modified, 4 );
|
||||
if( mtime == modified )
|
||||
{
|
||||
if (UnflattenIndex( &indexFile ) == B_OK)
|
||||
buildIndex = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
indexFile.Unset();
|
||||
}
|
||||
if( buildIndex )
|
||||
{
|
||||
// printf( "Building Index...\n" );
|
||||
InitIndex();
|
||||
BuildIndex();
|
||||
if( indexFile.SetTo( indexPath, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE ) == B_OK )
|
||||
{
|
||||
FlattenIndex( &indexFile );
|
||||
indexFile.WriteAttr( "WINDEX:modified", B_UINT32_TYPE, 0, &mtime, 4 );
|
||||
uint32 version = IVERSION;
|
||||
indexFile.WriteAttr( "WINDEX:version", B_UINT32_TYPE, 0, &version, 4 );
|
||||
}
|
||||
}
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
FileEntry::~FileEntry( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WIndex::WIndex( int32 count )
|
||||
{
|
||||
entryList = NULL;
|
||||
dataFile = NULL;
|
||||
ePerB = count;
|
||||
entrySize = sizeof( WIndexEntry );
|
||||
if( !atomic_or( &kCRCTable, 1 ) )
|
||||
gen_crc_table();
|
||||
}
|
||||
|
||||
WIndex::WIndex( BPositionIO *dataFile, int32 count )
|
||||
{
|
||||
entryList = NULL;
|
||||
this->dataFile = dataFile;
|
||||
ePerB = count;
|
||||
entrySize = sizeof( WIndexEntry );
|
||||
if( !atomic_or( &kCRCTable, 1 ) )
|
||||
gen_crc_table();
|
||||
}
|
||||
|
||||
WIndex::~WIndex( void )
|
||||
{
|
||||
if( entryList )
|
||||
free( entryList );
|
||||
delete dataFile;
|
||||
}
|
||||
|
||||
status_t WIndex::UnflattenIndex( BPositionIO *io )
|
||||
{
|
||||
if( entryList )
|
||||
free( entryList );
|
||||
WIndexHead head;
|
||||
|
||||
io->Seek( 0, SEEK_SET );
|
||||
io->Read( &head, sizeof( head ) );
|
||||
io->Seek( head.offset, SEEK_SET );
|
||||
|
||||
entrySize = head.entrySize;
|
||||
entries = head.entries;
|
||||
maxEntries = ePerB;
|
||||
blockSize = ePerB * entrySize;
|
||||
blocks = entries/ePerB+1;;
|
||||
isSorted = true;
|
||||
|
||||
int32 size = (head.entries+1) * head.entrySize;
|
||||
if( !(entryList = (uint8 *)malloc( size )) )
|
||||
return B_ERROR;
|
||||
|
||||
if( entries )
|
||||
io->Read( entryList, size );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t WIndex::FlattenIndex( BPositionIO *io )
|
||||
{
|
||||
if( entries && !isSorted )
|
||||
SortItems();
|
||||
WIndexHead head;
|
||||
|
||||
head.entries = entries;
|
||||
head.entrySize = entrySize;
|
||||
head.offset = sizeof( WIndexHead );
|
||||
io->Seek( 0, SEEK_SET );
|
||||
io->Write( &head, sizeof( head ) );
|
||||
if( entries )
|
||||
io->Write( entryList, head.entries * head.entrySize );
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int32 WIndex::Lookup( int32 key )
|
||||
{
|
||||
if( !entries )
|
||||
return -1;
|
||||
if( !isSorted )
|
||||
SortItems();
|
||||
|
||||
// Binary Search
|
||||
int32 M, Lb, Ub;
|
||||
Lb = 0;
|
||||
Ub = entries-1;
|
||||
while( true )
|
||||
{
|
||||
M = (Lb + Ub)/2;
|
||||
if( key < ((WIndexEntry *)(entryList+(M*entrySize)))->key )
|
||||
Ub = M - 1;
|
||||
else if(key > ((WIndexEntry *)(entryList+(M*entrySize)))->key )
|
||||
Lb = M + 1;
|
||||
else
|
||||
return M;
|
||||
if( Lb > Ub )
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
status_t WIndex::AddItem( WIndexEntry *entry )
|
||||
{
|
||||
if( BlockCheck() == B_ERROR )
|
||||
return B_ERROR;
|
||||
memcpy( ((WIndexEntry *)(entryList+(entries*entrySize))), entry, entrySize );
|
||||
entries++;
|
||||
isSorted = false;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void WIndex::SortItems( void )
|
||||
{
|
||||
qsort( entryList, entries, entrySize, (int (*)(const void *, const void *))cmp_i_entries );
|
||||
isSorted = true;
|
||||
//for( int32 i = 0; i < entries; i++ )
|
||||
// printf( "Key = %ld\n", entryList[i].key );
|
||||
}
|
||||
|
||||
status_t WIndex::BlockCheck( void )
|
||||
{
|
||||
if( entries < maxEntries )
|
||||
return B_OK;
|
||||
blocks = entries/ePerB+1;
|
||||
entryList = (uint8 *)realloc( entryList, blockSize*blocks );
|
||||
if( !entryList )
|
||||
return B_ERROR;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
status_t WIndex::InitIndex( void )
|
||||
{
|
||||
if( entryList )
|
||||
free( entryList );
|
||||
isSorted = 0;
|
||||
entries = 0;
|
||||
maxEntries = ePerB;
|
||||
blockSize = ePerB * entrySize;
|
||||
blocks = 1;
|
||||
entryList = (uint8 *)malloc( blockSize );
|
||||
if( !entryList )
|
||||
return B_ERROR;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
int32 WIndex::GetKey( const char *s )
|
||||
{
|
||||
|
||||
int32 key = 0;
|
||||
/*int32 x;
|
||||
int32 a = 84589;
|
||||
int32 b = 45989;
|
||||
int32 m = 217728;
|
||||
while( *s )
|
||||
{
|
||||
x = *s++ - 'a';
|
||||
|
||||
key ^= (a*x + b) % m;
|
||||
key <<= 1;
|
||||
}*/
|
||||
|
||||
key = update_crc( 0, s, strlen(s) );
|
||||
|
||||
if( key < 0 ) // No negavite values!
|
||||
key = ~key;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
int32 cmp_i_entries( const WIndexEntry *e1, const WIndexEntry *e2 )
|
||||
{
|
||||
return e1->key - e2->key;
|
||||
}
|
||||
|
||||
status_t WIndex::SetTo( BPositionIO *dataFile )
|
||||
{
|
||||
this->dataFile = dataFile;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
void WIndex::Unset( void )
|
||||
{
|
||||
dataFile = NULL;
|
||||
}
|
||||
|
||||
int32 WIndex::FindFirst( const char *word )
|
||||
{
|
||||
if( !entries )
|
||||
return -1;
|
||||
|
||||
int32 index;
|
||||
char nword[256];
|
||||
int32 key;
|
||||
|
||||
NormalizeWord( word, nword );
|
||||
key = GetKey( nword );
|
||||
|
||||
if( (index = Lookup( key )) < 0 )
|
||||
return -1;
|
||||
// Find first instance of key
|
||||
while( (ItemAt( index-1 ))->key == key )
|
||||
index--;
|
||||
return index;
|
||||
}
|
||||
|
||||
FileEntry *WIndex::GetEntry( int32 index )
|
||||
{
|
||||
if( (index >= entries)||(index < 0) )
|
||||
return NULL;
|
||||
WIndexEntry *ientry;
|
||||
FileEntry *dentry;
|
||||
char *buffer;
|
||||
|
||||
dentry = new FileEntry();
|
||||
|
||||
ientry = ItemAt( index );
|
||||
|
||||
int32 size;
|
||||
|
||||
dataFile->Seek( ientry->offset, SEEK_SET );
|
||||
buffer = dentry->LockBuffer( 256 );
|
||||
dataFile->Read( buffer, 256 );
|
||||
size = GetEntrySize( ientry, buffer );
|
||||
//buffer[256] = 0;
|
||||
//printf( "Entry: = %s\n", buffer );
|
||||
dentry->UnlockBuffer( size );
|
||||
return dentry;
|
||||
}
|
||||
|
||||
size_t WIndex::GetEntrySize( WIndexEntry *entry, const char *entryData )
|
||||
{
|
||||
// eliminate unused parameter warning
|
||||
(void)entry;
|
||||
|
||||
return strcspn( entryData, "\n\r" );
|
||||
}
|
||||
|
||||
FileEntry *WIndex::GetEntry( const char *word )
|
||||
{
|
||||
return GetEntry( FindFirst( word ) );
|
||||
}
|
||||
|
||||
char *WIndex::NormalizeWord( const char *word, char *dest )
|
||||
{
|
||||
const char *src;
|
||||
char *dst;
|
||||
|
||||
// remove dots and copy
|
||||
src = word;
|
||||
dst = dest;
|
||||
while( *src )
|
||||
{
|
||||
if( *src != '.' )
|
||||
*dst++ = *src;
|
||||
src++;
|
||||
}
|
||||
*dst = 0;
|
||||
|
||||
// convert to lower-case
|
||||
dst = dest;
|
||||
while( *dst )
|
||||
*dst++ = tolower( *dst );
|
||||
return dest;
|
||||
}
|
||||
|
||||
/* crc32h.c -- package to compute 32-bit CRC one byte at a time using */
|
||||
/* the high-bit first (Big-Endian) bit ordering convention */
|
||||
/* */
|
||||
/* Synopsis: */
|
||||
/* gen_crc_table() -- generates a 256-word table containing all CRC */
|
||||
/* remainders for every possible 8-bit byte. It */
|
||||
/* must be executed (once) before any CRC updates. */
|
||||
/* */
|
||||
/* unsigned update_crc(crc_accum, data_blk_ptr, data_blk_size) */
|
||||
/* unsigned crc_accum; char *data_blk_ptr; int data_blk_size; */
|
||||
/* Returns the updated value of the CRC accumulator after */
|
||||
/* processing each byte in the addressed block of data. */
|
||||
/* */
|
||||
/* It is assumed that an unsigned long is at least 32 bits wide and */
|
||||
/* that the predefined type char occupies one 8-bit byte of storage. */
|
||||
/* */
|
||||
/* The generator polynomial used for this version of the package is */
|
||||
/* x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 */
|
||||
/* as specified in the Autodin/Ethernet/ADCCP protocol standards. */
|
||||
/* Other degree 32 polynomials may be substituted by re-defining the */
|
||||
/* symbol POLYNOMIAL below. Lower degree polynomials must first be */
|
||||
/* multiplied by an appropriate power of x. The representation used */
|
||||
/* is that the coefficient of x^0 is stored in the LSB of the 32-bit */
|
||||
/* word and the coefficient of x^31 is stored in the most significant */
|
||||
/* bit. The CRC is to be appended to the data most significant byte */
|
||||
/* first. For those protocols in which bytes are transmitted MSB */
|
||||
/* first and in the same order as they are encountered in the block */
|
||||
/* this convention results in the CRC remainder being transmitted with */
|
||||
/* the coefficient of x^31 first and with that of x^0 last (just as */
|
||||
/* would be done by a hardware shift register mechanization). */
|
||||
/* */
|
||||
/* The table lookup technique was adapted from the algorithm described */
|
||||
/* by Avram Perez, Byte-wise CRC Calculations, IEEE Micro 3, 40 (1983).*/
|
||||
|
||||
#define POLYNOMIAL 0x04c11db7L
|
||||
|
||||
static unsigned long crc_table[256];
|
||||
|
||||
void gen_crc_table()
|
||||
/* generate the table of CRC remainders for all possible bytes */
|
||||
{ register int i, j; register unsigned long crc_accum;
|
||||
for ( i = 0; i < 256; i++ )
|
||||
{ crc_accum = ( (unsigned long) i << 24 );
|
||||
for ( j = 0; j < 8; j++ )
|
||||
{ if ( crc_accum & 0x80000000L )
|
||||
crc_accum =
|
||||
( crc_accum << 1 ) ^ POLYNOMIAL;
|
||||
else
|
||||
crc_accum =
|
||||
( crc_accum << 1 ); }
|
||||
crc_table[i] = crc_accum; }
|
||||
return; }
|
||||
|
||||
unsigned long update_crc( unsigned long crc_accum, const char *data_blk_ptr, int data_blk_size )
|
||||
/* update the CRC on the data block one byte at a time */
|
||||
{ register int i, j;
|
||||
for ( j = 0; j < data_blk_size; j++ )
|
||||
{ i = ( (int) ( crc_accum >> 24) ^ *data_blk_ptr++ ) & 0xff;
|
||||
crc_accum = ( crc_accum << 8 ) ^ crc_table[i]; }
|
||||
return crc_accum; }
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _WORD_INDEX_H
|
||||
#define _WORD_INDEX_H
|
||||
|
||||
#include <DataIO.h>
|
||||
#include <String.h>
|
||||
|
||||
struct WIndexHead {
|
||||
int32 entries;
|
||||
int32 entrySize;
|
||||
int32 offset;
|
||||
};
|
||||
|
||||
struct WIndexEntry {
|
||||
int32 key;
|
||||
int32 offset;
|
||||
};
|
||||
|
||||
class FileEntry : public BString {
|
||||
public:
|
||||
FileEntry(void);
|
||||
FileEntry(const char *entryStr);
|
||||
virtual ~FileEntry(void);
|
||||
};
|
||||
|
||||
class WIndex {
|
||||
public:
|
||||
WIndex(BPositionIO *dataFile, int32 count = 100);
|
||||
WIndex(int32 count = 100);
|
||||
virtual ~WIndex(void);
|
||||
|
||||
status_t InitIndex(void);
|
||||
status_t UnflattenIndex(BPositionIO *io);
|
||||
status_t FlattenIndex(BPositionIO *io);
|
||||
|
||||
int32 Lookup(int32 key);
|
||||
|
||||
inline WIndexEntry *ItemAt(int32 index)
|
||||
{ return (WIndexEntry *)(entryList+(index*entrySize)); }
|
||||
status_t AddItem(WIndexEntry *entry);
|
||||
inline int32 CountItems(void)
|
||||
{ return entries; }
|
||||
void SortItems(void);
|
||||
|
||||
virtual int32 GetKey(const char *s);
|
||||
virtual char *NormalizeWord(const char *word, char *dest);
|
||||
|
||||
status_t SetTo(BPositionIO *dataFile);
|
||||
status_t SetTo(const char *dataPath, const char *indexPath);
|
||||
void Unset(void);
|
||||
|
||||
virtual status_t BuildIndex(void) = 0;
|
||||
|
||||
virtual int32 FindFirst(const char *word);
|
||||
virtual FileEntry *GetEntry(int32 index);
|
||||
FileEntry *GetEntry(const char *word);
|
||||
|
||||
protected:
|
||||
status_t BlockCheck(void);
|
||||
virtual size_t GetEntrySize(WIndexEntry *entry, const char *entryData);
|
||||
|
||||
int32 entrySize;
|
||||
int32 entries;
|
||||
int32 maxEntries;
|
||||
int32 ePerB;
|
||||
int32 blockSize;
|
||||
int32 blocks;
|
||||
bool isSorted;
|
||||
uint8 *entryList;
|
||||
BPositionIO *dataFile;
|
||||
};
|
||||
|
||||
#endif // #ifndef _WORD_INDEX_H
|
||||
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2001, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <List.h>
|
||||
#include "Words.h"
|
||||
|
||||
/*
|
||||
** File METAPHON.C
|
||||
*/
|
||||
|
||||
/*
|
||||
** MAXMETAPH is the length of the Metaphone code.
|
||||
**
|
||||
** Four is a good compromise value for English names. For comparing words
|
||||
** which are not names or for some non-English names, use a longer code
|
||||
** length for more precise matches.
|
||||
**
|
||||
** The default here is 5.
|
||||
*/
|
||||
|
||||
#define MAXMETAPH 6
|
||||
|
||||
static const char *gCmpKey;
|
||||
static int word_cmp( BString **firstArg, BString **secondArg );
|
||||
|
||||
static int word_cmp( BString **firstArg, BString **secondArg )
|
||||
{
|
||||
return word_match( gCmpKey, (*firstArg)->String() ) - word_match( gCmpKey, (*secondArg)->String() );
|
||||
}
|
||||
|
||||
Words::Words( bool useMetaphone )
|
||||
: fUseMetaphone( useMetaphone )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Words::Words( BPositionIO *thes, bool useMetaphone )
|
||||
: WIndex( thes ),
|
||||
fUseMetaphone( useMetaphone )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Words::~Words( void )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Words::Words( const char *dataPath, const char *indexPath, bool useMetaphone )
|
||||
: fUseMetaphone( useMetaphone )
|
||||
{
|
||||
if( !useMetaphone )
|
||||
entrySize = sizeof( uint32 );
|
||||
SetTo( dataPath, indexPath );
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
FIND_WORD,
|
||||
GET_WORD,
|
||||
GET_FLAGS
|
||||
};
|
||||
|
||||
// Parse the Words file...
|
||||
status_t Words::BuildIndex( void )
|
||||
{
|
||||
// Buffer Stuff
|
||||
char buffer[16384];
|
||||
char *nptr, *eptr;
|
||||
int64 blockOffset;
|
||||
int32 blockSize;
|
||||
|
||||
// The Word Entry
|
||||
WIndexEntry entry;
|
||||
char entryName[256], *namePtr = entryName;
|
||||
char suffixName[256];
|
||||
char flags[32], *flagsPtr = flags;
|
||||
|
||||
// State Info
|
||||
int32 state = FIND_WORD;
|
||||
|
||||
// Make sure we are at start of file
|
||||
dataFile->Seek( 0, SEEK_SET );
|
||||
entry.offset = -1;
|
||||
|
||||
// Read blocks from thes until eof
|
||||
while( true )
|
||||
{
|
||||
// Get next block
|
||||
blockOffset = dataFile->Position();
|
||||
if( (blockSize = dataFile->Read( buffer, 16384 )) == 0 )
|
||||
break;
|
||||
|
||||
// parse block
|
||||
for( nptr = buffer, eptr = buffer + blockSize; nptr < eptr; nptr++ )
|
||||
{
|
||||
// Looking for start of word?
|
||||
if( state == FIND_WORD )
|
||||
{
|
||||
// Is start of word?
|
||||
if( isalpha(*nptr) )
|
||||
{
|
||||
state = GET_WORD;
|
||||
*namePtr++ = *nptr; // copy word
|
||||
entry.offset = blockOffset + (nptr - buffer);
|
||||
}
|
||||
else
|
||||
entry.offset++;
|
||||
}
|
||||
// End of word?
|
||||
else if( (*nptr == '\n')||(*nptr == '\r') )
|
||||
{
|
||||
if( namePtr != entryName )
|
||||
{
|
||||
// Add previous entry to word index
|
||||
*namePtr = 0; // terminate word
|
||||
*flagsPtr = 0; // terminate flags
|
||||
NormalizeWord( entryName, entryName );
|
||||
// Add base word
|
||||
entry.key = GetKey( entryName );
|
||||
AddItem( &entry );
|
||||
|
||||
// Add suffixed words if any
|
||||
if( flagsPtr != flags )
|
||||
{
|
||||
//printf( "Base: %s, flags: %s\n", entryName, flags );
|
||||
for( flagsPtr=flags; *flagsPtr != 0; flagsPtr++ )
|
||||
{
|
||||
if( suffix_word( suffixName, entryName, *flagsPtr ) )
|
||||
{
|
||||
//printf( "Suffix: %s\n", suffixName );
|
||||
entry.key = GetKey( suffixName );
|
||||
AddItem( &entry );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Init new entry
|
||||
state = FIND_WORD;
|
||||
namePtr = entryName;
|
||||
flagsPtr = flags;
|
||||
}
|
||||
else if( state == GET_WORD ) // Are we looking for a word?
|
||||
{
|
||||
// Start of flags?
|
||||
if( *nptr == '/' )
|
||||
{
|
||||
*namePtr = 0; // terminate word
|
||||
//printf( "Found word: %s\n", entryName );
|
||||
|
||||
// Set state to get flags
|
||||
state = GET_FLAGS;
|
||||
}
|
||||
else
|
||||
*namePtr++ = *nptr; // copy word
|
||||
}
|
||||
else if( state == GET_FLAGS ) // Are we getting the flags?
|
||||
*flagsPtr++ = *nptr; // copy flag
|
||||
} // End for( nptr = buffer, eptr = buffer + blockSize; nptr < eptr; nptr++, entry.size++ )
|
||||
} // End while( true )
|
||||
|
||||
SortItems();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Character coding array
|
||||
*/
|
||||
|
||||
static char vsvfn[26] = {
|
||||
1,16,4,16,9,2,4,16,9,2,0,2,2,2,1,4,0,2,4,4,1,0,0,0,8,0};
|
||||
/* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z */
|
||||
|
||||
int32 Words::GetKey( const char *s )
|
||||
{
|
||||
if( fUseMetaphone )
|
||||
{
|
||||
char Metaph[12];
|
||||
const char *sPtr;
|
||||
int32 key = 0;
|
||||
int32 offset;
|
||||
char c;
|
||||
|
||||
metaphone( s, Metaph, GENERATE );
|
||||
// Compact Metaphone from 6 bytes to 4
|
||||
|
||||
// printf( "%s -> %s: \n", s, Metaph );
|
||||
|
||||
for( sPtr = Metaph, offset = 25; *sPtr; sPtr++, offset -= 5 )
|
||||
{
|
||||
c = *sPtr - 'A';
|
||||
// printf( "%d,", int16(c) );
|
||||
key |= int32(c) << offset;
|
||||
}
|
||||
for( ; offset >= 0; offset -= 5 )
|
||||
key |= int32(31) << offset;
|
||||
// printf( ": %ld\n", key );
|
||||
return key;
|
||||
}
|
||||
else
|
||||
return WIndex::GetKey( s );
|
||||
}
|
||||
|
||||
/*
|
||||
** Macros to access the character coding array
|
||||
*/
|
||||
|
||||
#define vowel(x) (vsvfn[(x) - 'A'] & 1) /* AEIOU */
|
||||
#define same(x) (vsvfn[(x) - 'A'] & 2) /* FJLMNR */
|
||||
#define varson(x) (vsvfn[(x) - 'A'] & 4) /* CGPST */
|
||||
#define frontv(x) (vsvfn[(x) - 'A'] & 8) /* EIY */
|
||||
#define noghf(x) (vsvfn[(x) - 'A'] & 16) /* BDH */
|
||||
#define NUL '\0'
|
||||
/*
|
||||
** metaphone()
|
||||
**
|
||||
** Arguments: 1 - The word to be converted to a metaphone code.
|
||||
** 2 - A MAXMETAPH+1 char field for the result.
|
||||
** 3 - Function flag:
|
||||
** If 0: Compute the Metaphone code for the first argument,
|
||||
** then compare it to the Metaphone code passed in
|
||||
** the second argument.
|
||||
** If 1: Compute the Metaphone code for the first argument,
|
||||
** then store the result in the area pointed to by the
|
||||
** second argument.
|
||||
**
|
||||
** Returns: If function code is 0, returns Success_ for a match, else Error_.
|
||||
** If function code is 1, returns Success_.
|
||||
*/
|
||||
|
||||
bool metaphone(const char *Word, char *Metaph, metaphlag Flag)
|
||||
{
|
||||
char *n, *n_start, *n_end; /* Pointers to string */
|
||||
char *metaph = NULL, *metaph_end; /* Pointers to metaph */
|
||||
char ntrans[512]; /* Word with uppercase letters */
|
||||
char newm[MAXMETAPH + 4]; /* New metaph for comparison */
|
||||
int KSflag; /* State flag for X translation */
|
||||
|
||||
/*
|
||||
** Copy word to internal buffer, dropping non-alphabetic characters
|
||||
** and converting to upper case.
|
||||
*/
|
||||
|
||||
for (n = ntrans + 1, n_end = ntrans + sizeof(ntrans) - 2;
|
||||
*Word && n < n_end; ++Word)
|
||||
{
|
||||
if (isalpha(*Word))
|
||||
*n++ = toupper(*Word);
|
||||
}
|
||||
|
||||
if (n == ntrans + 1)
|
||||
return false; /* Return if zero characters */
|
||||
else n_end = n; /* Set end of string pointer */
|
||||
|
||||
/*
|
||||
** Pad with NULs, front and rear
|
||||
*/
|
||||
|
||||
*n++ = NUL;
|
||||
*n = NUL;
|
||||
n = ntrans;
|
||||
*n++ = NUL;
|
||||
|
||||
/*
|
||||
** If doing comparison, redirect pointers
|
||||
*/
|
||||
|
||||
if (COMPARE == Flag)
|
||||
{
|
||||
metaph = Metaph;
|
||||
Metaph = newm;
|
||||
}
|
||||
|
||||
/*
|
||||
** Check for PN, KN, GN, WR, WH, and X at start
|
||||
*/
|
||||
|
||||
switch (*n)
|
||||
{
|
||||
case 'P':
|
||||
case 'K':
|
||||
case 'G':
|
||||
if ('N' == *(n + 1))
|
||||
*n++ = NUL;
|
||||
break;
|
||||
|
||||
case 'A':
|
||||
if ('E' == *(n + 1))
|
||||
*n++ = NUL;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
if ('R' == *(n + 1))
|
||||
*n++ = NUL;
|
||||
else if ('H' == *(n + 1))
|
||||
{
|
||||
*(n + 1) = *n;
|
||||
*n++ = NUL;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
*n = 'S';
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
** Now loop through the string, stopping at the end of the string
|
||||
** or when the computed Metaphone code is MAXMETAPH characters long.
|
||||
*/
|
||||
|
||||
KSflag = false; /* State flag for KStranslation */
|
||||
for (metaph_end = Metaph + MAXMETAPH, n_start = n;
|
||||
n <= n_end && Metaph < metaph_end; ++n)
|
||||
{
|
||||
if (KSflag)
|
||||
{
|
||||
KSflag = false;
|
||||
*Metaph++ = *n;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Drop duplicates except for CC */
|
||||
|
||||
if (*(n - 1) == *n && *n != 'C')
|
||||
continue;
|
||||
|
||||
/* Check for F J L M N R or first letter vowel */
|
||||
|
||||
if (same(*n) || (n == n_start && vowel(*n)))
|
||||
*Metaph++ = *n;
|
||||
else switch (*n)
|
||||
{
|
||||
case 'B':
|
||||
if (n < n_end || *(n - 1) != 'M')
|
||||
*Metaph++ = *n;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
if (*(n - 1) != 'S' || !frontv(*(n + 1)))
|
||||
{
|
||||
if ('I' == *(n + 1) && 'A' == *(n + 2))
|
||||
*Metaph++ = 'X';
|
||||
else if (frontv(*(n + 1)))
|
||||
*Metaph++ = 'S';
|
||||
else if ('H' == *(n + 1))
|
||||
*Metaph++ = ((n == n_start &&
|
||||
!vowel(*(n + 2))) ||
|
||||
'S' == *(n - 1)) ? 'K' : 'X';
|
||||
else *Metaph++ = 'K';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
*Metaph++ = ('G' == *(n + 1) && frontv(*(n + 2))) ?
|
||||
'J' : 'T';
|
||||
break;
|
||||
|
||||
case 'G':
|
||||
if ((*(n + 1) != 'H' || vowel(*(n + 2))) &&
|
||||
(*(n + 1) != 'N' || ((n + 1) < n_end &&
|
||||
(*(n + 2) != 'E' || *(n + 3) != 'D'))) &&
|
||||
(*(n - 1) != 'D' || !frontv(*(n + 1))))
|
||||
{
|
||||
*Metaph++ = (frontv(*(n + 1)) &&
|
||||
*(n + 2) != 'G') ? 'J' : 'K';
|
||||
}
|
||||
else if ('H' == *(n + 1) && !noghf(*(n - 3)) &&
|
||||
*(n - 4) != 'H')
|
||||
{
|
||||
*Metaph++ = 'F';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
if (!varson(*(n - 1)) && (!vowel(*(n - 1)) ||
|
||||
vowel(*(n + 1))))
|
||||
{
|
||||
*Metaph++ = 'H';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'K':
|
||||
if (*(n - 1) != 'C')
|
||||
*Metaph++ = 'K';
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
*Metaph++ = ('H' == *(n + 1)) ? 'F' : 'P';
|
||||
break;
|
||||
|
||||
case 'Q':
|
||||
*Metaph++ = 'K';
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
*Metaph++ = ('H' == *(n + 1) || ('I' == *(n + 1) &&
|
||||
('O' == *(n + 2) || 'A' == *(n + 2)))) ?
|
||||
'X' : 'S';
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
if ('I' == *(n + 1) && ('O' == *(n + 2) ||
|
||||
'A' == *(n + 2)))
|
||||
{
|
||||
*Metaph++ = 'X';
|
||||
}
|
||||
else if ('H' == *(n + 1))
|
||||
*Metaph++ = 'O';
|
||||
else if (*(n + 1) != 'C' || *(n + 2) != 'H')
|
||||
*Metaph++ = 'T';
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
*Metaph++ = 'F';
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
case 'Y':
|
||||
if (vowel(*(n + 1)))
|
||||
*Metaph++ = *n;
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
if (n == n_start)
|
||||
*Metaph++ = 'S';
|
||||
else
|
||||
{
|
||||
*Metaph++ = 'K';
|
||||
KSflag = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Z':
|
||||
*Metaph++ = 'S';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Compare new Metaphone code with old
|
||||
*/
|
||||
|
||||
if (COMPARE == Flag &&
|
||||
*(Metaph - 1) != metaph[(Metaph - newm) - 1])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** If comparing, check if Metaphone codes were equal in length
|
||||
*/
|
||||
|
||||
if (COMPARE == Flag && metaph[Metaph - newm])
|
||||
return false;
|
||||
|
||||
*Metaph = NUL;
|
||||
return true;
|
||||
}
|
||||
|
||||
int word_match( const char *reference, const char *test )
|
||||
{
|
||||
const char *s1, *s2;
|
||||
int32 x = 0;
|
||||
char c1, c2;
|
||||
s1 = test;
|
||||
s2 = reference;
|
||||
|
||||
bool a, b;
|
||||
|
||||
while( *s2 || *s1 )
|
||||
{
|
||||
c1 = tolower(*s1);
|
||||
c2 = tolower(*s2);
|
||||
|
||||
if( *s2 && *s1 )
|
||||
{
|
||||
if( c1 != c2 )
|
||||
{
|
||||
a = (tolower(s1[1]) == c2);
|
||||
b = (tolower(s2[1]) == c1);
|
||||
// Reversed pair
|
||||
if( a && b )
|
||||
{
|
||||
x += 1;
|
||||
s1++;
|
||||
s2++;
|
||||
}
|
||||
// Extra character
|
||||
if( a )
|
||||
{
|
||||
x += 1;
|
||||
s1++;
|
||||
}
|
||||
// Missing Character
|
||||
else if( b )
|
||||
{
|
||||
x += 1;
|
||||
s2++;
|
||||
}
|
||||
// Equivalent Character
|
||||
else if( vsvfn[c1] == vsvfn[c2] )
|
||||
x++;
|
||||
// Unrelated Character
|
||||
else
|
||||
x += 3;
|
||||
}
|
||||
}
|
||||
else
|
||||
x += 1;
|
||||
if( *s2 )
|
||||
s2++;
|
||||
if( *s1 )
|
||||
s1++;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
int32 suffix_word( char *dst, const char *src, char flag )
|
||||
{
|
||||
char *end;
|
||||
|
||||
end = stpcpy( dst, src );
|
||||
flag = toupper( flag );
|
||||
switch( flag )
|
||||
{
|
||||
case 'V':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "ive" );
|
||||
break;
|
||||
default:
|
||||
end = stpcpy( end, "ive" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'N':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "ion" );
|
||||
break;
|
||||
case 'y':
|
||||
end = stpcpy( end-1, "ication" );
|
||||
break;
|
||||
default:
|
||||
end = stpcpy( end, "en" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'X':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "ions" );
|
||||
break;
|
||||
case 'y':
|
||||
end = stpcpy( end-1, "ications" );
|
||||
break;
|
||||
default:
|
||||
end = stpcpy( end, "ens" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'H':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'y':
|
||||
end = stpcpy( end-1, "ieth" );
|
||||
break;
|
||||
default:
|
||||
end = stpcpy( end, "th" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'Y':
|
||||
end = stpcpy( end, "ly" );
|
||||
break;
|
||||
case 'G':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "ing" );
|
||||
break;
|
||||
default:
|
||||
end = stpcpy( end, "ing" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'J':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "ings" );
|
||||
break;
|
||||
default:
|
||||
end = stpcpy( end, "ings" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'D':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "ed" );
|
||||
break;
|
||||
case 'y':
|
||||
if( !strchr( "aeiou", end[-2] ) )
|
||||
{
|
||||
end = stpcpy( end-1, "ied" );
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
end = stpcpy( end, "ed" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "est" );
|
||||
break;
|
||||
case 'y':
|
||||
if( !strchr( "aeiou", end[-2] ) )
|
||||
{
|
||||
end = stpcpy( end-1, "iest" );
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
end = stpcpy( end, "est" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'R':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "er" );
|
||||
break;
|
||||
case 'y':
|
||||
if( !strchr( "aeiou", end[-2] ) )
|
||||
{
|
||||
end = stpcpy( end-1, "ier" );
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
end = stpcpy( end, "er" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'Z':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'e':
|
||||
end = stpcpy( end-1, "ers" );
|
||||
break;
|
||||
case 'y':
|
||||
if( !strchr( "aeiou", end[-2] ) )
|
||||
{
|
||||
end = stpcpy( end-1, "iers" );
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
end = stpcpy( end, "ers" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 's':
|
||||
case 'x':
|
||||
case 'z':
|
||||
case 'h':
|
||||
end = stpcpy( end, "es" );
|
||||
break;
|
||||
case 'y':
|
||||
if( !strchr( "aeiou", end[-2] ) )
|
||||
{
|
||||
end = stpcpy( end-1, "ies" );
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
end = stpcpy( end, "s" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'P':
|
||||
switch( end[-1] )
|
||||
{
|
||||
case 'y':
|
||||
if( !strchr( "aeiou", end[-2] ) )
|
||||
{
|
||||
end = stpcpy( end-1, "iness" );
|
||||
break;
|
||||
}
|
||||
// Fall through
|
||||
default:
|
||||
end = stpcpy( end, "ness" );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
end = stpcpy( end, "'s" );
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return end-dst;
|
||||
}
|
||||
|
||||
int32 Words::FindBestMatches( BList *matches, const char *s )
|
||||
{
|
||||
int32 index;
|
||||
// printf( "*** Looking for %s: ***\n", s );
|
||||
|
||||
if( (index = FindFirst( s )) >= 0 )
|
||||
{
|
||||
BString srcWord( s );
|
||||
FileEntry *entry;
|
||||
WIndexEntry *indexEntry;
|
||||
|
||||
int32 key = (ItemAt( index ))->key;
|
||||
int32 suffixLength;
|
||||
char word[128], suffixWord[128];
|
||||
const char *src, *testWord;
|
||||
const char *suffixFlags;
|
||||
char *dst;
|
||||
|
||||
gCmpKey = srcWord.String();
|
||||
|
||||
uint8 hashTable[32];
|
||||
uint8 hashValue, highHash, lowHash;
|
||||
for( int32 i=0; i<32; i++ )
|
||||
hashTable[i] = 0;
|
||||
|
||||
do
|
||||
{
|
||||
indexEntry = ItemAt( index );
|
||||
// Hash the entry offset; we use this to make sure we don't add
|
||||
// the same word file entry twice;
|
||||
// It is possible for the same entry in the words file to have
|
||||
// multiple entries in the index.
|
||||
|
||||
hashValue = indexEntry->offset % 256;
|
||||
highHash = hashValue >> 3;
|
||||
lowHash = 0x01 << (hashValue & 0x07);
|
||||
|
||||
//printf( "Testing Entry: %ld: hash=%d, highHash=%d, lowHash=%d\n", indexEntry->offset, hashValue, (uint16)highHash, (uint16)lowHash );
|
||||
|
||||
// Has this entry offset been seen before?
|
||||
if( !(hashTable[highHash] & lowHash) )
|
||||
{
|
||||
//printf( "New Entry\n" );
|
||||
hashTable[highHash] |= lowHash; // Mark this offset so we don't add it twice
|
||||
|
||||
entry = GetEntry( index );
|
||||
src = entry->String();
|
||||
while( *src && !isalpha(*src) )
|
||||
src++;
|
||||
dst = word;
|
||||
while( *src && *src != '/' )
|
||||
*dst++ = *src++;
|
||||
*dst = 0;
|
||||
if( *src == '/' )
|
||||
suffixFlags = src+1;
|
||||
else
|
||||
suffixFlags = src;
|
||||
|
||||
//printf( "Base Word: %s\n", word );
|
||||
//printf( "Flags: %s\n", suffixFlags );
|
||||
testWord = word; // Test the base word first
|
||||
do
|
||||
{
|
||||
//printf( "Testing: %s\n", testWord );
|
||||
// Does this word match the key
|
||||
if( (GetKey( testWord ) == key) &&
|
||||
// And does it look close enough to the compare key?
|
||||
//word_match( gCmpKey, testWord ) <= int32((strlen( gCmpKey )-1)/2) )
|
||||
word_match( gCmpKey, testWord ) <= int32(float(strlen( gCmpKey )-1)*.75) )
|
||||
{
|
||||
//printf( "Added: %s\n", testWord );
|
||||
matches->AddItem( (void *)(new BString( testWord )) ); // Add it to the list
|
||||
}
|
||||
|
||||
// If suffix, transform and test
|
||||
if( *suffixFlags )
|
||||
{
|
||||
// Repeat until valid suffix found or end is reached
|
||||
suffixLength = 0;
|
||||
while( *suffixFlags && !(suffixLength=suffix_word( suffixWord, word, *suffixFlags++ )) ) {}
|
||||
if( suffixLength )
|
||||
testWord = suffixWord;
|
||||
else
|
||||
testWord = NULL;
|
||||
}
|
||||
else
|
||||
testWord = NULL;
|
||||
}while( testWord );
|
||||
delete entry;
|
||||
}
|
||||
//else
|
||||
//printf( "Redundant entry\n" );
|
||||
index++;
|
||||
}while( key == (ItemAt( index ))->key );
|
||||
|
||||
return matches->CountItems();
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sort_word_list( BList *matches, const char *reference )
|
||||
{
|
||||
if( matches->CountItems() > 0 )
|
||||
{
|
||||
BString srcWord( reference );
|
||||
gCmpKey = srcWord.String();
|
||||
matches->SortItems( (int (*)(const void *, const void *))word_cmp );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Open Tracker License
|
||||
|
||||
Terms and Conditions
|
||||
|
||||
Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice applies to all licensees
|
||||
and shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Be Incorporated shall not be
|
||||
used in advertising or otherwise to promote the sale, use or other dealings in
|
||||
this Software without prior written authorization from Be Incorporated.
|
||||
|
||||
BeMail(TM), Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
|
||||
of Be Incorporated in the United States and other countries. Other brand product
|
||||
names are registered trademarks or trademarks of their respective holders.
|
||||
All rights reserved.
|
||||
*/
|
||||
#ifndef _WORDS_H
|
||||
#define _WORDS_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "WIndex.h"
|
||||
|
||||
typedef enum {
|
||||
COMPARE,
|
||||
GENERATE
|
||||
} metaphlag;
|
||||
|
||||
class Words;
|
||||
|
||||
bool metaphone(const char *Word, char *Metaph, metaphlag Flag);
|
||||
int word_match(const char *reference, const char *test);
|
||||
int32 suffix_word(char *dst, const char *src, char flag);
|
||||
void sort_word_list(BList *matches, const char *reference);
|
||||
|
||||
class Words : public WIndex {
|
||||
public:
|
||||
Words(bool useMetaphone = true);
|
||||
Words(BPositionIO *thes, bool useMetaphone = true);
|
||||
Words(const char *dataPath, const char *indexPath, bool useMetaphone);
|
||||
virtual ~Words(void);
|
||||
|
||||
virtual status_t BuildIndex(void);
|
||||
virtual int32 GetKey(const char *s);
|
||||
|
||||
int32 FindBestMatches(BList *matches, const char *word);
|
||||
|
||||
protected:
|
||||
bool fUseMetaphone;
|
||||
};
|
||||
|
||||
#endif // #ifndef _WORDS_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user