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:
Nathan Whitehorn
2004-09-20 22:31:50 +00:00
parent 48061f2026
commit f7215ac853
154 changed files with 75670 additions and 0 deletions
@@ -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 */
+151
View File
@@ -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 */
+56
View File
@@ -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 */
+51
View File
@@ -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 */
+35
View File
@@ -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 */
+17
View File
@@ -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 */
+57
View File
@@ -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 */
+85
View File
@@ -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 */
+606
View File
@@ -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__ */
+83
View File
@@ -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 */
+1
View File
@@ -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",&regex);
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",&regex);
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
View File
@@ -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.
+387
View File
@@ -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(&copy);
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(&copy);
}
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;
}
+87
View File
@@ -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
+185
View File
@@ -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;
}
+80
View File
@@ -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
+224
View File
@@ -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
+291
View File
@@ -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 */
+556
View File
@@ -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>");
}
+129
View File
@@ -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
+50
View File
@@ -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
+295
View File
@@ -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);
}
+105
View File
@@ -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
+149
View File
@@ -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 */
+24
View File
@@ -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 ;
+321
View File
@@ -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");
}
}
+77
View File
@@ -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);
};
+31
View File
@@ -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
+350
View File
@@ -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
+792
View File
@@ -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 &copyThis, CompareFunction);
T *BinaryInsertCopy(const T &copyThis, 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 &copyThis, CompareFunction);
T *BinaryInsertCopyUnique(const T &copyThis, 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 &copyThis, CompareFunction func)
{
int32 index = _PointerList_::BinarySearchIndex(&copyThis,
(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 &copyThis, CompareFunctionWithState func, void *state)
{
int32 index = _PointerList_::BinarySearchIndex(&copyThis,
(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 &copyThis, CompareFunction func)
{
int32 index = _PointerList_::BinarySearchIndex(&copyThis,
(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 &copyThis, CompareFunctionWithState func,
void *state)
{
int32 index = _PointerList_::BinarySearchIndex(&copyThis,
(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__
+966
View File
@@ -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;
}
+139
View File
@@ -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 */
+306
View File
@@ -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();
}
+80
View File
@@ -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
+611
View File
@@ -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);
}
}
+145
View File
@@ -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
+574
View File
@@ -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>&#38;</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 &#38; 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 --&#62; ...IVE as in CREATE --&#62; CREATIVE
if # .ne. E, ...# --&#62; ...#IVE as in PREVENT --&#62; PREVENTIVE
<P>
"N" flag:
...E --&#62; ...ION as in CREATE --&#62; CREATION
...Y --&#62; ...ICATION as in MULTIPLY --&#62; MULTIPLICATION
if # .ne. E or Y, ...# --&#62; ...#EN as in FALL --&#62; FALLEN
<P>
"X" flag:
...E --&#62; ...IONS as in CREATE --&#62; CREATIONS
...Y --&#62; ...ICATIONS as in MULTIPLY --&#62; MULTIPLICATIONS
if # .ne. E or Y, ...# --&#62; ...#ENS as in WEAK --&#62; WEAKENS
<P>
"H" flag:
...Y --&#62; ...IETH as in TWENTY --&#62; TWENTIETH
if # .ne. Y, ...# --&#62; ...#TH as in HUNDRED --&#62; HUNDREDTH
<P>
"Y" FLAG:
... --&#62; ...LY as in QUICK --&#62; QUICKLY
<P>
"G" FLAG:
...E --&#62; ...ING as in FILE --&#62; FILING
if # .ne. E, ...# --&#62; ...#ING as in CROSS --&#62; CROSSING
<P>
"J" FLAG"
...E --&#62; ...INGS as in FILE --&#62; FILINGS
if # .ne. E, ...# --&#62; ...#INGS as in CROSS --&#62; CROSSINGS
<P>
"D" FLAG:
...E --&#62; ...ED as in CREATE --&#62; CREATED
if @ .ne. A, E, I, O, or U,
...@Y --&#62; ...@IED as in IMPLY --&#62; IMPLIED
if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
...@# --&#62; ...@#ED as in CROSS --&#62; CROSSED
or CONVEY --&#62; CONVEYED
<P>
"T" FLAG:
...E --&#62; ...EST as in LATE --&#62; LATEST
if @ .ne. A, E, I, O, or U,
...@Y --&#62; ...@IEST as in DIRTY --&#62; DIRTIEST
if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
...@# --&#62; ...@#EST as in SMALL --&#62; SMALLEST
or GRAY --&#62; GRAYEST
<P>
"R" FLAG:
...E --&#62; ...ER as in SKATE --&#62; SKATER
if @ .ne. A, E, I, O, or U,
...@Y --&#62; ...@IER as in MULTIPLY --&#62; MULTIPLIER
if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
...@# --&#62; ...@#ER as in BUILD --&#62; BUILDER
or CONVEY --&#62; CONVEYER
<P>
"Z FLAG:
...E --&#62; ...ERS as in SKATE --&#62; SKATERS
if @ .ne. A, E, I, O, or U,
...@Y --&#62; ...@IERS as in MULTIPLY --&#62; MULTIPLIERS
if # .ne. E or Y, or (# = Y and @ = A, E, I, O, or U)
...@# --&#62; ...@#ERS as in BUILD --&#62; BUILDERS
or SLAY --&#62; SLAYERS
<P>
"S" FLAG:
if @ .ne. A, E, I, O, or U,
...@Y --&#62; ...@IES as in IMPLY --&#62; IMPLIES
if # .eq. S, X, Z, or H,
...# --&#62; ...#ES as in FIX --&#62; FIXES
if # .ne. S, X, Z, H, or Y, or (# = Y and @ = A, E, I, O, or U)
...# --&#62; ...#S as in BAT --&#62; BATS
or CONVEY --&#62; CONVEYS
<P>
"P" FLAG:
if @ .ne. A, E, I, O, or U,
...@Y --&#62; ...@INESS as in CLOUDY --&#62; CLOUDINESS
if # .ne. Y, or @ = A, E, I, O, or U,
...@# --&#62; ...@#NESS as in LATE --&#62; LATENESS
or GRAY --&#62; GRAYNESS
<P>
"M" FLAG:
... --&#62; ...'S as in DOG --&#62; 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>
+205
View File
@@ -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;
}
+119
View File
@@ -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
+212
View File
@@ -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;
}
+69
View File
@@ -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
+447
View File
@@ -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; }
+106
View File
@@ -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
+864
View File
@@ -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 );
}
}
+69
View File
@@ -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