mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-19 09:30:44 +00:00
bug 307150 - Incomplete implementation of javax.mail.Message in grendel.storage.MessageReadOnly. r=rj.keller@beonex.com. Patch by Kieran Maclean <kieran [at] eternal.undonet.com>
This commit is contained in:
parent
9bea533899
commit
142ac2d257
@ -41,8 +41,9 @@
|
||||
<mkdir dir="dist"/>
|
||||
<antcall target="unzipResources"/>
|
||||
|
||||
<echo message="-- Compiling WikiRadio"/>
|
||||
<echo message="-- Compiling Grendel"/>
|
||||
<javac srcdir="." destdir="dist"
|
||||
classpath="**/*.jar"
|
||||
optimize="false"
|
||||
debug="true"
|
||||
includes="**/*.java"/>
|
||||
|
@ -20,6 +20,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* Created: Terry Weissman <terry@netscape.com>, 22 Aug 1997.
|
||||
* Kieran Maclean
|
||||
*/
|
||||
|
||||
package grendel.storage;
|
||||
@ -94,8 +95,9 @@ abstract class FolderBase extends Folder implements FolderExtra {
|
||||
void noticeInitialMessage(Message m) {
|
||||
fMessages.addElement(m);
|
||||
// #### How the hell are we supposed to do this?
|
||||
BerkeleyMessage bm=(BerkeleyMessage)m;
|
||||
bm.setMessageNumber(fMessages.size() - 1);
|
||||
// XXX This is not a good idea, this a general class
|
||||
//BerkeleyMessage bm=(BerkeleyMessage)m;
|
||||
//bm.setMessageNumber(fMessages.size() - 1);
|
||||
}
|
||||
|
||||
ByteStringTable getStringTable() {
|
||||
|
@ -17,7 +17,8 @@
|
||||
* Copyright (C) 1997 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Contributor(s):
|
||||
* Kieran Maclean
|
||||
*/
|
||||
|
||||
|
||||
@ -36,6 +37,7 @@ import java.util.NoSuchElementException;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
import javax.activation.MimeType;
|
||||
import javax.mail.Address;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Folder;
|
||||
@ -50,23 +52,23 @@ import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.InternetHeaders;
|
||||
|
||||
|
||||
abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
|
||||
public abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
|
||||
/* **********************************************************
|
||||
Class variables
|
||||
**********************************************************
|
||||
**********************************************************
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
/* Don't confuse these flags with the values used in X-Mozilla-Status
|
||||
headers: they occupy a different space, and range. There is a
|
||||
difference between the in-memory format, and the storage format.
|
||||
This is partially because there are potentially in-memory flags
|
||||
that don't get saved to disk.
|
||||
|
||||
|
||||
Parsing of the X-Mozilla-Status header (and conversion to this form)
|
||||
happens in the BerkeleyMessage class.
|
||||
|
||||
|
||||
There can be up to 64 flag-bits (the in-memory flags.)
|
||||
There can only be up to 16 X-Mozilla-Status flags (the persistent flags.)
|
||||
*/
|
||||
@ -81,12 +83,12 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
public static final long FLAG_SMTP_AUTH = 0x00000100; // Gag
|
||||
public static final long FLAG_PARTIAL = 0x00000200; // POP3
|
||||
public static final long FLAG_QUEUED = 0x00000400; // Offline
|
||||
|
||||
|
||||
|
||||
|
||||
// The mapping between our internal flag bits and javamail's flag strings.
|
||||
// The editable entry defines whether this flag can be changed from the
|
||||
// outside.
|
||||
|
||||
|
||||
static class FlagMap {
|
||||
long flag;
|
||||
Flags.Flag builtin;
|
||||
@ -119,14 +121,14 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
FLAGDEFS[i++] = new FlagMap(FLAG_QUEUED, "Queued", false);
|
||||
Assert.Assertion(i == FLAGDEFS.length);
|
||||
};
|
||||
|
||||
|
||||
// This bit, when set, means that some change has been made to the flags
|
||||
// which should be written out to the X-Mozilla-Status header in the
|
||||
// folder's disk file. This is done so that we can lazily update the
|
||||
// file, rather than writing it every time the flags change.
|
||||
public static final long FLAG_DIRTY = 0x00000800;
|
||||
|
||||
|
||||
|
||||
|
||||
/* Some string-constants in bytebuf form that we use for interrogating
|
||||
headers during parsing.
|
||||
*/
|
||||
@ -139,19 +141,19 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
protected static final ByteBuf MESSAGE_ID = new ByteBuf("message-id");
|
||||
protected static final ByteBuf REFERENCES = new ByteBuf("references");
|
||||
protected static final ByteBuf IN_REPLY_TO = new ByteBuf("in-reply-to");
|
||||
|
||||
|
||||
/* For simplifiedDate() */
|
||||
private static Date scratch_date = new Date();
|
||||
private static DateFormat date_format = null;
|
||||
|
||||
|
||||
|
||||
|
||||
/* ***********************************************************
|
||||
Instance variables -- add them sparingly, memory is scarce.
|
||||
***********************************************************
|
||||
***********************************************************
|
||||
*/
|
||||
long flags; // see `FLAG_READ', etc, above.
|
||||
long sentDate; // milliseconds since the Epoch.
|
||||
|
||||
|
||||
// These slots are ints but really represent ByteStrings: they are indexes
|
||||
// into a ByteStringTable. It's quite likely that we could live with these
|
||||
// being of type `short' instead of `int'. Should memory usage be a problem,
|
||||
@ -160,60 +162,60 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
int author_name; // name (not address) of the From or Sender.
|
||||
int recipient_name; // name of first To, or CC, or newsgroup.
|
||||
int subject; // subject minus "Re:" (see `FLAG_HAS_RE').
|
||||
|
||||
|
||||
// These slots are as above, but represent MessageID objects instead of
|
||||
// ByteString objects. These also could stand to be of type `short'.
|
||||
//
|
||||
int message_id; // will never be -1 (meaning null).
|
||||
int references[]; // may be null; else length > 0.
|
||||
|
||||
|
||||
|
||||
|
||||
/* **********************************************************
|
||||
Methods
|
||||
**********************************************************
|
||||
**********************************************************
|
||||
*/
|
||||
|
||||
|
||||
MessageBase(FolderBase f) {
|
||||
super();
|
||||
this.folder = f;
|
||||
}
|
||||
|
||||
|
||||
// New constructor copied from above but sets msgnum correctly.
|
||||
MessageBase(FolderBase f, int num) {
|
||||
super(f, num);
|
||||
this.folder = f;
|
||||
}
|
||||
|
||||
|
||||
MessageBase(FolderBase f, InternetHeaders h) {
|
||||
this(f);
|
||||
initialize(f, h);
|
||||
}
|
||||
|
||||
|
||||
// New constructor copied from above but sets msgnum correctly.
|
||||
MessageBase(FolderBase f, int num, InternetHeaders h) {
|
||||
this(f, num);
|
||||
initialize(f, h);
|
||||
}
|
||||
|
||||
|
||||
MessageBase(FolderBase f,
|
||||
long date,
|
||||
long flags,
|
||||
ByteBuf author,
|
||||
ByteBuf recipient,
|
||||
ByteBuf subj,
|
||||
ByteBuf id,
|
||||
ByteBuf refs[]) {
|
||||
long date,
|
||||
long flags,
|
||||
ByteBuf author,
|
||||
ByteBuf recipient,
|
||||
ByteBuf subj,
|
||||
ByteBuf id,
|
||||
ByteBuf refs[]) {
|
||||
this(f);
|
||||
ByteStringTable string_table = f.getStringTable();
|
||||
MessageIDTable id_table = f.getMessageIDTable();
|
||||
|
||||
|
||||
if (id == null || id.length() == 0) {
|
||||
// #### In previous versions, we did this by getting the MD5 hash
|
||||
// #### of the whole header block. We should do that here too...
|
||||
if (id == null) id = new ByteBuf();
|
||||
id.append(grendel.util.MessageIDGenerator.generate("missing-id"));
|
||||
}
|
||||
|
||||
|
||||
this.folder = f;
|
||||
this.flags = flags;
|
||||
this.sentDate = date;
|
||||
@ -221,7 +223,7 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
this.recipient_name = string_table.intern(recipient);
|
||||
this.subject = string_table.intern(subj);
|
||||
this.message_id = id_table.intern(id);
|
||||
|
||||
|
||||
if (refs == null || refs.length == 0)
|
||||
this.references = null;
|
||||
else {
|
||||
@ -231,28 +233,28 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
references[i] = id_table.intern(refs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// New constructor copied from above but sets msgnum correctly.
|
||||
MessageBase(FolderBase f,
|
||||
int num,
|
||||
long date,
|
||||
long flags,
|
||||
ByteBuf author,
|
||||
ByteBuf recipient,
|
||||
ByteBuf subj,
|
||||
ByteBuf id,
|
||||
ByteBuf refs[]) {
|
||||
int num,
|
||||
long date,
|
||||
long flags,
|
||||
ByteBuf author,
|
||||
ByteBuf recipient,
|
||||
ByteBuf subj,
|
||||
ByteBuf id,
|
||||
ByteBuf refs[]) {
|
||||
this(f, num);
|
||||
ByteStringTable string_table = f.getStringTable();
|
||||
MessageIDTable id_table = f.getMessageIDTable();
|
||||
|
||||
|
||||
if (id == null || id.length() == 0) {
|
||||
// #### In previous versions, we did this by getting the MD5 hash
|
||||
// #### of the whole header block. We should do that here too...
|
||||
if (id == null) id = new ByteBuf();
|
||||
id.append(grendel.util.MessageIDGenerator.generate("missing-id"));
|
||||
}
|
||||
|
||||
|
||||
this.folder = f;
|
||||
this.flags = flags;
|
||||
this.sentDate = date;
|
||||
@ -260,7 +262,7 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
this.recipient_name = string_table.intern(recipient);
|
||||
this.subject = string_table.intern(subj);
|
||||
this.message_id = id_table.intern(id);
|
||||
|
||||
|
||||
if (refs == null || refs.length == 0)
|
||||
this.references = null;
|
||||
else {
|
||||
@ -270,36 +272,36 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
references[i] = id_table.intern(refs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MessageBase(FolderBase f,
|
||||
long date,
|
||||
long flags,
|
||||
ByteBuf author,
|
||||
ByteBuf recipient,
|
||||
ByteBuf subj,
|
||||
MessageID id,
|
||||
MessageID refs[]) {
|
||||
long date,
|
||||
long flags,
|
||||
ByteBuf author,
|
||||
ByteBuf recipient,
|
||||
ByteBuf subj,
|
||||
MessageID id,
|
||||
MessageID refs[]) {
|
||||
this(f);
|
||||
ByteStringTable string_table = f.getStringTable();
|
||||
MessageIDTable id_table = f.getMessageIDTable();
|
||||
|
||||
|
||||
if (id != null) {
|
||||
this.message_id = id_table.intern(id);
|
||||
} else {
|
||||
// #### In previous versions, we did this by getting the MD5 hash
|
||||
// #### of the whole header block. We should do that here too...
|
||||
ByteBuf b =
|
||||
new ByteBuf(grendel.util.MessageIDGenerator.generate("missing-id"));
|
||||
new ByteBuf(grendel.util.MessageIDGenerator.generate("missing-id"));
|
||||
this.message_id = id_table.intern(b);
|
||||
}
|
||||
|
||||
|
||||
this.folder = f;
|
||||
this.flags = flags;
|
||||
this.sentDate = date;
|
||||
this.author_name = string_table.intern(author);
|
||||
this.recipient_name = string_table.intern(recipient);
|
||||
this.subject = string_table.intern(subj);
|
||||
|
||||
|
||||
if (refs == null || refs.length == 0)
|
||||
this.references = null;
|
||||
else {
|
||||
@ -309,38 +311,38 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
references[i] = id_table.intern(refs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// New constructor copied from above but sets msgnum correctly.
|
||||
MessageBase(FolderBase f,
|
||||
int num,
|
||||
long date,
|
||||
long flags,
|
||||
ByteBuf author,
|
||||
ByteBuf recipient,
|
||||
ByteBuf subj,
|
||||
MessageID id,
|
||||
MessageID refs[]) {
|
||||
int num,
|
||||
long date,
|
||||
long flags,
|
||||
ByteBuf author,
|
||||
ByteBuf recipient,
|
||||
ByteBuf subj,
|
||||
MessageID id,
|
||||
MessageID refs[]) {
|
||||
this(f, num);
|
||||
ByteStringTable string_table = f.getStringTable();
|
||||
MessageIDTable id_table = f.getMessageIDTable();
|
||||
|
||||
|
||||
if (id != null) {
|
||||
this.message_id = id_table.intern(id);
|
||||
} else {
|
||||
// #### In previous versions, we did this by getting the MD5 hash
|
||||
// #### of the whole header block. We should do that here too...
|
||||
ByteBuf b =
|
||||
new ByteBuf(grendel.util.MessageIDGenerator.generate("missing-id"));
|
||||
new ByteBuf(grendel.util.MessageIDGenerator.generate("missing-id"));
|
||||
this.message_id = id_table.intern(b);
|
||||
}
|
||||
|
||||
|
||||
this.folder = f;
|
||||
this.flags = flags;
|
||||
this.sentDate = date;
|
||||
this.author_name = string_table.intern(author);
|
||||
this.recipient_name = string_table.intern(recipient);
|
||||
this.subject = string_table.intern(subj);
|
||||
|
||||
|
||||
if (refs == null || refs.length == 0)
|
||||
this.references = null;
|
||||
else {
|
||||
@ -350,40 +352,40 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
references[i] = id_table.intern(refs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void initialize(Folder f, InternetHeaders h) {
|
||||
folder = f;
|
||||
FolderBase fb = (FolderBase) f;
|
||||
ByteStringTable string_table = fb.getStringTable();
|
||||
MessageIDTable id_table = fb.getMessageIDTable();
|
||||
String hh[];
|
||||
|
||||
|
||||
hh = h.getHeader("From");
|
||||
author_name = (hh == null || hh.length == 0 ? -1 :
|
||||
string_table.intern(hh[0].trim()));
|
||||
|
||||
// #### need an address parser here...
|
||||
string_table.intern(hh[0].trim()));
|
||||
|
||||
// #### need an address parser here...
|
||||
recipient_name = -1;
|
||||
/*
|
||||
hh = h.getHeader("To");
|
||||
// #### deal with multiple to fields
|
||||
recipient_name = (hh == null || hh.length == 0 ? -1 :
|
||||
string_table.intern(hh[0].trim()));
|
||||
|
||||
|
||||
if (recipient == -1) {
|
||||
// #### deal with multiple cc fields
|
||||
hh = h.getHeader("CC");
|
||||
recipient_name = (hh == null || hh.length == 0 ? -1 :
|
||||
string_table.intern(hh[0].trim()));
|
||||
}
|
||||
|
||||
|
||||
if (recipient == -1) {
|
||||
hh = h.getHeader("Newsgroups");
|
||||
recipient_name = (hh == null || hh.length == 0 ? -1 :
|
||||
string_table.intern(hh[0].trim()));
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
hh = h.getHeader("Subject");
|
||||
if (hh != null && hh.length != 0) {
|
||||
// Much of this code is duplicated in MessageExtraFactory. Sigh. ###
|
||||
@ -398,19 +400,19 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
flags |= FLAG_HAS_RE; // yes, we found it.
|
||||
} else if (c == '[' || c == '(') {
|
||||
int i = 3; // skip over "Re[" or "Re("
|
||||
|
||||
|
||||
// Skip forward over digits after the "[" or "(".
|
||||
int length = value.length();
|
||||
while (i < length &&
|
||||
value.byteAt(i) >= '0' &&
|
||||
value.byteAt(i) <= '9') {
|
||||
value.byteAt(i) >= '0' &&
|
||||
value.byteAt(i) <= '9') {
|
||||
i++;
|
||||
}
|
||||
// Now ensure that the following thing is "]:" or "):"
|
||||
// Only if it is do we treat this all as a "Re"-ish thing.
|
||||
if (i < (length-1) &&
|
||||
(value.byteAt(i) == ']' ||
|
||||
value.byteAt(i) == ')') &&
|
||||
value.byteAt(i) == ')') &&
|
||||
value.byteAt(i+1) == ':') {
|
||||
value.remove(0, i+2); // Skip the whole thing.
|
||||
value.trim(); // Remove any whitespace after colon
|
||||
@ -420,11 +422,11 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
}
|
||||
subject = string_table.intern(value);
|
||||
}
|
||||
|
||||
|
||||
hh = h.getHeader("Date");
|
||||
if (hh != null && hh.length != 0)
|
||||
sentDate = NetworkDate.parseLong(new ByteBuf(hh[0]), true);
|
||||
|
||||
|
||||
hh = h.getHeader("Message-ID");
|
||||
if (hh != null && hh.length != 0) {
|
||||
ByteBuf value = new ByteBuf(hh[0]);
|
||||
@ -438,7 +440,7 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
}
|
||||
message_id = id_table.intern(value.trim());
|
||||
}
|
||||
|
||||
|
||||
// There must be a message ID on every message.
|
||||
if (message_id == -1) {
|
||||
// #### In previous versions, we did this by getting the MD5 hash
|
||||
@ -446,25 +448,26 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
String id = grendel.util.MessageIDGenerator.generate("missing-id");
|
||||
message_id = id_table.intern(new ByteBuf(id));
|
||||
}
|
||||
|
||||
|
||||
hh = h.getHeader("References");
|
||||
if (hh != null && hh.length != 0) {
|
||||
ByteBuf value = new ByteBuf(hh[0]);
|
||||
references = internReferences(id_table, value.trim());
|
||||
}
|
||||
|
||||
|
||||
// Only examine the In-Reply-To header if there is no References header.
|
||||
if (references == null) {
|
||||
|
||||
|
||||
hh = h.getHeader("In-Reply-To");
|
||||
if (hh != null && hh.length != 0) {
|
||||
ByteBuf value = new ByteBuf(hh[0]);
|
||||
references = internReferences(id_table, value.trim());
|
||||
}
|
||||
}
|
||||
base_headers = h;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Ported from akbar's "msg_intern_references", mailsum.c.
|
||||
protected int[] internReferences(MessageIDTable id_table, ByteBuf refs) {
|
||||
byte data[] = refs.toBytes();
|
||||
@ -476,17 +479,17 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
n_refs++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (n_refs == 0)
|
||||
return null;
|
||||
|
||||
|
||||
int result[] = new int[n_refs];
|
||||
int start = 0;
|
||||
int cur = 0;
|
||||
|
||||
|
||||
s = 0;
|
||||
while (s < length) {
|
||||
|
||||
|
||||
// The old way was to skip over whitespace, then skip an optional "<".
|
||||
// The new way is to skip over everything up to and including "<".
|
||||
// This lets us deal better with In-Reply-To headers, in addition to
|
||||
@ -520,21 +523,21 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
//
|
||||
while (start < length && data[start] != '<')
|
||||
start++;
|
||||
|
||||
|
||||
// skip over consecutive "<" -- I've seen "<<ID@HOST>>".
|
||||
while (start < length && data[start] == '<')
|
||||
start++;
|
||||
|
||||
|
||||
s = start;
|
||||
while (s < length && data[s] != '>')
|
||||
s++;
|
||||
|
||||
|
||||
if (s > start &&
|
||||
s < length &&
|
||||
data[s] == '>') {
|
||||
result[cur++] = id_table.intern(data, start, s - start);
|
||||
start = s + 1;
|
||||
|
||||
|
||||
// skip over consecutive ">" -- I've seen "<<ID@HOST>>".
|
||||
while (start < length && data[start] == '>')
|
||||
start++;
|
||||
@ -542,7 +545,7 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (cur != n_refs) {
|
||||
// Whoops! Something's funny about this line, and the number of
|
||||
// ">" characters didn't equal the number of IDs we extracted.
|
||||
@ -556,75 +559,75 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
result = r2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public Object getMessageID() {
|
||||
MessageIDTable id_table = ((FolderBase)folder).getMessageIDTable();
|
||||
return (MessageID) id_table.getObject(message_id);
|
||||
}
|
||||
|
||||
|
||||
public String getSubject() {
|
||||
String result = simplifiedSubject();
|
||||
if (subjectIsReply()) result = "Re: " + result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public String getAuthor() {
|
||||
ByteStringTable string_table = ((FolderBase)folder).getStringTable();
|
||||
ByteString a = (ByteString)
|
||||
string_table.getObject(author_name);
|
||||
string_table.getObject(author_name);
|
||||
if (a == null) return "";
|
||||
else return a.toString();
|
||||
}
|
||||
|
||||
|
||||
public String getRecipient() {
|
||||
ByteStringTable string_table = ((FolderBase)folder).getStringTable();
|
||||
ByteString r = (ByteString) string_table.getObject(recipient_name);
|
||||
if (r == null) return "";
|
||||
else return r.toString();
|
||||
}
|
||||
|
||||
|
||||
public Object[] messageThreadReferences() {
|
||||
if (references == null) return null;
|
||||
int count = references.length;
|
||||
if (count == 0) return null;
|
||||
|
||||
|
||||
// Note: this conses.
|
||||
MessageIDTable id_table = ((FolderBase)folder).getMessageIDTable();
|
||||
Object result[] = new Object[count];
|
||||
for (int i = 0; i < result.length; i++)
|
||||
result[i] = id_table.getObject(references[i]);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public long getSentDateAsLong() {
|
||||
return sentDate;
|
||||
}
|
||||
|
||||
|
||||
public Date getSentDate() {
|
||||
return new Date(sentDate);
|
||||
}
|
||||
|
||||
|
||||
public Date getReceivedDate() {
|
||||
// ### We don't currently remember this info. Should we?
|
||||
return getSentDate();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public Folder getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// #### Warning, this is untested -- the "javax.mail.Flags" class changed
|
||||
// around a bunch since the last time we tried to use this code, and I had
|
||||
// to beat on this.
|
||||
|
||||
|
||||
public Flags getFlags() {
|
||||
Flags result = new Flags();
|
||||
for (int i=0 ; i<FLAGDEFS.length ; i++) {
|
||||
@ -638,7 +641,7 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSet(Flags.Flag flag) {
|
||||
for (int i=0; i < FLAGDEFS.length ; i++) {
|
||||
if (flag.equals(FLAGDEFS[i].builtin)) {
|
||||
@ -647,7 +650,7 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public boolean isSet(String flag) {
|
||||
for (int i=0; i < FLAGDEFS.length ; i++) {
|
||||
if (flag.equals(FLAGDEFS[i].non_builtin)) {
|
||||
@ -656,39 +659,39 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public void setFlags(Flags flag, boolean set) throws MessagingException {
|
||||
|
||||
|
||||
Flags.Flag[] builtin_flags = flag.getSystemFlags();
|
||||
String [] non_builtin_flags = flag.getUserFlags();
|
||||
|
||||
NEXT_BUILTIN:
|
||||
for (int i = 0; i < builtin_flags.length ; i++) {
|
||||
Flags.Flag name = builtin_flags[i];
|
||||
for (int j=0 ; j<FLAGDEFS.length ; j++) {
|
||||
if (FLAGDEFS[j].editable && name.equals(FLAGDEFS[j].builtin)) {
|
||||
setFlagBit(FLAGDEFS[j].flag, set);
|
||||
continue NEXT_BUILTIN;
|
||||
|
||||
NEXT_BUILTIN:
|
||||
for (int i = 0; i < builtin_flags.length ; i++) {
|
||||
Flags.Flag name = builtin_flags[i];
|
||||
for (int j=0 ; j<FLAGDEFS.length ; j++) {
|
||||
if (FLAGDEFS[j].editable && name.equals(FLAGDEFS[j].builtin)) {
|
||||
setFlagBit(FLAGDEFS[j].flag, set);
|
||||
continue NEXT_BUILTIN;
|
||||
}
|
||||
}
|
||||
throw new IllegalWriteException("Can't change flag " + name +
|
||||
" on message " + this);
|
||||
}
|
||||
throw new IllegalWriteException("Can't change flag " + name +
|
||||
" on message " + this);
|
||||
}
|
||||
|
||||
NEXT_NON_BUILTIN:
|
||||
for (int i = 0; i < non_builtin_flags.length ; i++) {
|
||||
String name = non_builtin_flags[i];
|
||||
for (int j=0 ; j<FLAGDEFS.length ; j++) {
|
||||
if (FLAGDEFS[j].editable && name.equals(FLAGDEFS[j].non_builtin)) {
|
||||
setFlagBit(FLAGDEFS[j].flag, set);
|
||||
continue NEXT_NON_BUILTIN;
|
||||
|
||||
NEXT_NON_BUILTIN:
|
||||
for (int i = 0; i < non_builtin_flags.length ; i++) {
|
||||
String name = non_builtin_flags[i];
|
||||
for (int j=0 ; j<FLAGDEFS.length ; j++) {
|
||||
if (FLAGDEFS[j].editable && name.equals(FLAGDEFS[j].non_builtin)) {
|
||||
setFlagBit(FLAGDEFS[j].flag, set);
|
||||
continue NEXT_NON_BUILTIN;
|
||||
}
|
||||
}
|
||||
throw new IllegalWriteException("Can't change flag " + name +
|
||||
" on message " + this);
|
||||
}
|
||||
}
|
||||
throw new IllegalWriteException("Can't change flag " + name +
|
||||
" on message " + this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected synchronized void setFlagBit(long flag, boolean value) {
|
||||
long newflags = flags;
|
||||
if (value) {
|
||||
@ -699,138 +702,155 @@ abstract class MessageBase extends MessageReadOnly implements MessageExtra {
|
||||
if (flags != newflags) {
|
||||
flags = newflags;
|
||||
((FolderBase)folder).doNotifyMessageChangedListeners
|
||||
(MessageChangedEvent.FLAGS_CHANGED, this);
|
||||
(MessageChangedEvent.FLAGS_CHANGED, this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// #### are these still part of the JavaMail spec? I don't see them in
|
||||
// http://www.javasoft.com/products/javamail/javadocs/javax/mail/Message.html
|
||||
|
||||
|
||||
public boolean isRead() {
|
||||
return ((flags & FLAG_READ) != 0);
|
||||
}
|
||||
public void setIsRead(boolean value) {
|
||||
setFlagBit(FLAG_READ, value);
|
||||
}
|
||||
|
||||
|
||||
public boolean isReplied() {
|
||||
return ((flags & FLAG_REPLIED) != 0);
|
||||
}
|
||||
public void setReplied(boolean value) {
|
||||
setFlagBit(FLAG_REPLIED, value);
|
||||
}
|
||||
|
||||
|
||||
public boolean isForwarded() {
|
||||
return ((flags & FLAG_FORWARDED) != 0);
|
||||
}
|
||||
public void setForwarded(boolean value) {
|
||||
setFlagBit(FLAG_FORWARDED, value);
|
||||
}
|
||||
|
||||
|
||||
public boolean isFlagged() {
|
||||
return ((flags & FLAG_MARKED) != 0);
|
||||
}
|
||||
public void setFlagged(boolean value) {
|
||||
setFlagBit(FLAG_MARKED, value);
|
||||
}
|
||||
|
||||
|
||||
public boolean isDeleted() {
|
||||
return ((flags & FLAG_DELETED) != 0);
|
||||
}
|
||||
public void setDeleted(boolean value) {
|
||||
setFlagBit(FLAG_DELETED, value);
|
||||
}
|
||||
|
||||
|
||||
public boolean isSigned() {
|
||||
return ((flags & FLAG_SIGNED) != 0);
|
||||
}
|
||||
public boolean isEncrypted() {
|
||||
return ((flags & FLAG_ENCRYPTED) != 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public boolean flagsAreDirty() {
|
||||
return ((flags & FLAG_DIRTY) != 0);
|
||||
}
|
||||
public void setFlagsDirty(boolean value) {
|
||||
setFlagBit(FLAG_DIRTY, value);
|
||||
}
|
||||
|
||||
|
||||
public void saveChanges() {
|
||||
// ### Should this actually do something?
|
||||
}
|
||||
|
||||
|
||||
public InputStream getRawText() throws IOException {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public String simplifiedSubject() {
|
||||
ByteStringTable string_table = ((FolderBase)folder).getStringTable();
|
||||
ByteString s = (ByteString) string_table.getObject(subject);
|
||||
if (s == null) return "";
|
||||
else return s.toString(); // #### fix me
|
||||
}
|
||||
|
||||
|
||||
public boolean subjectIsReply() {
|
||||
return ((flags & FLAG_HAS_RE) != 0);
|
||||
}
|
||||
|
||||
|
||||
public String simplifiedDate() {
|
||||
return SimplifyADate(sentDate);
|
||||
}
|
||||
|
||||
static String SimplifyADate(long ldate) {
|
||||
|
||||
public static String SimplifyADate(long ldate) {
|
||||
if (ldate <= 0) return "";
|
||||
|
||||
|
||||
synchronized(scratch_date) {
|
||||
if (date_format == null) {
|
||||
date_format = DateFormat.getDateTimeInstance();
|
||||
}
|
||||
scratch_date.setTime(ldate);
|
||||
|
||||
|
||||
/* #### This needs to be more clever. I guess we should make our
|
||||
own subclass of DateFormat and put the cleverness there. */
|
||||
return date_format.format(scratch_date);
|
||||
}
|
||||
}
|
||||
|
||||
public void putByteStream(OutputStream out) throws MessagingException {
|
||||
throw new MethodNotSupportedException("MessageBase.putByteStream");
|
||||
}
|
||||
|
||||
|
||||
public DataHandler getDataHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object getContent() {
|
||||
try
|
||||
{
|
||||
StringBuffer buff=new StringBuffer();
|
||||
Reader r=new InputStreamReader(getInputStream());
|
||||
char[] b = new char[1024];
|
||||
while(r.read(b)!=-1)
|
||||
{
|
||||
buff.append(b);
|
||||
|
||||
private DataHandler data_handler = null;
|
||||
|
||||
public DataHandler getDataHandler() throws MessagingException {
|
||||
if (data_handler==null) {
|
||||
String type = "text/plain"; //XXX lie to it...
|
||||
String[] content_types = getHeader("Content-Type");
|
||||
if ((content_types!=null)&&(content_types.length>0)) {
|
||||
type = content_types[0];
|
||||
}
|
||||
data_handler = new DataHandler(getContentAsString(),type);
|
||||
}
|
||||
r.close();
|
||||
return buff.toString();
|
||||
}
|
||||
catch(Exception e) {e.printStackTrace(); return null;}
|
||||
return data_handler;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private String getContentAsString() {
|
||||
try {
|
||||
StringWriter writer =new StringWriter();
|
||||
Reader r=new InputStreamReader(getInputStream());
|
||||
int read = r.read();;
|
||||
while(read!=-1) {
|
||||
writer.write(read);
|
||||
read = r.read();
|
||||
}
|
||||
r.close();
|
||||
return writer.toString();
|
||||
} catch(Exception e) {e.printStackTrace(); return null;}
|
||||
}
|
||||
|
||||
public Object getContent() throws IOException, MessagingException {
|
||||
return getDataHandler().getContent();
|
||||
}
|
||||
|
||||
private InternetHeaders base_headers = null;
|
||||
private InternetHeaders full_headers = null;
|
||||
|
||||
/** Get the InternetHeaders object. Someday, maybe we'll keep this around
|
||||
in a weak link or something. But for now, we always recreate it.
|
||||
Subclasses might want to redefine just this, or they might want to
|
||||
redefine all the routines below that use this. */
|
||||
* in a weak link or something. But for now, we always recreate it.
|
||||
* Subclasses might want to redefine just this, or they might want to
|
||||
* redefine all the routines below that use this. */
|
||||
protected InternetHeaders getHeadersObj() throws MessagingException {
|
||||
InputStream is=getInputStreamWithHeaders();
|
||||
InternetHeaders ih=new InternetHeaders(is);
|
||||
try { is.close(); } catch(Exception e) {e.printStackTrace();}
|
||||
return ih;
|
||||
// return new InternetHeaders(getInputStreamWithHeaders());
|
||||
if (full_headers==null) {
|
||||
try {
|
||||
InputStream is=getInputStreamWithHeaders();
|
||||
full_headers=new InternetHeaders(is);
|
||||
try { is.close(); } catch(Exception e) {e.printStackTrace();}
|
||||
} catch (IOException ioe) {
|
||||
if (session.getDebug()) {
|
||||
ioe.printStackTrace();
|
||||
}
|
||||
return base_headers;
|
||||
}
|
||||
}
|
||||
return full_headers;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -20,10 +20,12 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* Created: Terry Weissman <terry@netscape.com>, 22 Oct 1997.
|
||||
* Kieran Maclean
|
||||
*/
|
||||
|
||||
package grendel.storage;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.mail.MessagingException;
|
||||
|
||||
@ -68,7 +70,7 @@ public interface MessageExtra {
|
||||
|
||||
/** Gets the input stream for the message, in RFC822 format: a bunch of
|
||||
headers, and then a blank line, and then the message itself. */
|
||||
public InputStream getInputStreamWithHeaders() throws MessagingException;
|
||||
public InputStream getInputStreamWithHeaders() throws MessagingException, IOException;
|
||||
|
||||
};
|
||||
|
||||
|
@ -309,7 +309,7 @@ class MessageExtraWrapper implements MessageExtra
|
||||
|
||||
// Removes leading "Re:" or similar from the given StringBuffer. Returns
|
||||
// true if it found such a string to remove; false otherwise.
|
||||
protected boolean stripRe(StringBuffer buf)
|
||||
protected static boolean stripRe(StringBuffer buf)
|
||||
{
|
||||
// Much of this code is duplicated in MessageBase. Sigh. ###
|
||||
if (buf==null) {
|
||||
|
@ -20,40 +20,44 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* Created: Terry Weissman <terry@netscape.com>, 24 Nov 1997.
|
||||
* Kieran Maclean
|
||||
*/
|
||||
|
||||
package grendel.storage;
|
||||
|
||||
import calypso.util.NetworkDate;
|
||||
|
||||
import calypso.util.Assert;
|
||||
import calypso.util.ByteBuf;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.SequenceInputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
import javax.activation.DataHandler;
|
||||
|
||||
import javax.mail.Address;
|
||||
import javax.mail.Flags;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Header;
|
||||
import javax.mail.IllegalWriteException;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.MethodNotSupportedException;
|
||||
import javax.mail.Multipart;
|
||||
import javax.mail.Part;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.mail.internet.InternetHeaders;
|
||||
import javax.mail.internet.MimeMessage;
|
||||
import javax.mail.internet.MimeUtility;
|
||||
|
||||
/** This implements those methods on Message which are commonly used in all
|
||||
of our read-only message implementations. It also provides an
|
||||
implementation for the header-reading routines, all of which assume that
|
||||
the subclass implements getHeadersObj, a method to get an InternetHeaders
|
||||
object for this message. */
|
||||
* of our read-only message implementations. It also provides an
|
||||
* implementation for the header-reading routines, all of which assume that
|
||||
* the subclass implements getHeadersObj, a method to get an InternetHeaders
|
||||
* object for this message. */
|
||||
|
||||
abstract class MessageReadOnly extends Message {
|
||||
|
||||
@ -101,7 +105,7 @@ abstract class MessageReadOnly extends Message {
|
||||
readonly();
|
||||
}
|
||||
|
||||
public String getContentType() {
|
||||
public String getContentType() throws MessagingException {
|
||||
return "message/rfc822";
|
||||
}
|
||||
|
||||
@ -129,8 +133,8 @@ abstract class MessageReadOnly extends Message {
|
||||
readonly();
|
||||
}
|
||||
|
||||
public void setDataHandler(DataHandler d) {
|
||||
Assert.NotYetImplemented("Can't set a datahandler on our readonly messages!");
|
||||
public void setDataHandler(DataHandler d) throws MessagingException {
|
||||
readonly();
|
||||
}
|
||||
|
||||
public void setText(String s) throws MessagingException {
|
||||
@ -141,12 +145,12 @@ abstract class MessageReadOnly extends Message {
|
||||
readonly();
|
||||
}
|
||||
|
||||
public void setContent(Object o, String s) {
|
||||
Assert.NotYetImplemented("Can't set content on our readonly messages!");
|
||||
public void setContent(Object o, String s) throws MessagingException {
|
||||
readonly();
|
||||
}
|
||||
|
||||
public void setContent(Multipart m) {
|
||||
Assert.NotYetImplemented("Can't set content on our readonly messages!");
|
||||
public void setContent(Multipart m) throws MessagingException {
|
||||
readonly();
|
||||
}
|
||||
|
||||
public void addHeader(String s1, String s2) throws MessagingException {
|
||||
@ -235,70 +239,67 @@ abstract class MessageReadOnly extends Message {
|
||||
return getOneHeader("Subject");
|
||||
}
|
||||
|
||||
public Enumeration getAllHeaders() {
|
||||
Assert.NotYetImplemented("MessageBase.getAllHeaders -- don't know what it's really supposed to do!");
|
||||
return null;
|
||||
public Enumeration getAllHeaders() throws MessagingException {
|
||||
return getHeadersObj().getAllHeaders();
|
||||
}
|
||||
|
||||
public Enumeration getMatchingHeaders(String s[]) {
|
||||
Assert.NotYetImplemented("MessageBase.getMatchingHeaders -- don't know what it's really supposed to do!");
|
||||
return null;
|
||||
public Enumeration getMatchingHeaders(String s[]) throws MessagingException {
|
||||
return getHeadersObj().getMatchingHeaders(s);
|
||||
}
|
||||
|
||||
public Enumeration getNonMatchingHeaders(String s[]) {
|
||||
Assert.NotYetImplemented("MessageBase.getNonMatchingHeaders -- don't know what it's really supposed to do!");
|
||||
return null;
|
||||
public Enumeration getNonMatchingHeaders(String s[]) throws MessagingException {
|
||||
return getHeadersObj().getNonMatchingHeaders(s);
|
||||
}
|
||||
|
||||
|
||||
public Message reply(boolean replyToAll) {
|
||||
Assert.NotYetImplemented("MessageReadOnly.reply");
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isMimeType(String mimeType) {
|
||||
Assert.NotYetImplemented("MessageReadOnly.isMimeType");
|
||||
return false;
|
||||
}
|
||||
|
||||
/** This default implementation of getInputStream() works in terms of
|
||||
getInputStreamWithHeaders. Subclasses are encouraged to define this
|
||||
more directly if they have an easy way of doing so. */
|
||||
public InputStream getInputStream() throws MessagingException {
|
||||
InputStream in = getInputStreamWithHeaders();
|
||||
if (in == null) return null;
|
||||
// Now read until we hit a blank line.
|
||||
int b1 = 0;
|
||||
int b2 = 0;
|
||||
try {
|
||||
while ((b2 = in.read()) >= 0) {
|
||||
if (b1 == '\r') {
|
||||
if (b2 == '\r') {
|
||||
// Two CR's in a row; done.
|
||||
break;
|
||||
}
|
||||
} else if (b1 == '\n') {
|
||||
if (b2 == '\n') {
|
||||
// Two LF's in a row; done.
|
||||
break;
|
||||
} else if (b2 == '\r') {
|
||||
// We have a LFCR. It's gotta be the middle of a CRLFCRLF. So,
|
||||
// we need to read one more character and then we're done.
|
||||
b1 = b2;
|
||||
b2 = in.read();
|
||||
if (b2 == '\n') break;
|
||||
}
|
||||
}
|
||||
b1 = b2;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new MessagingException("Can't skip headers in stream", e);
|
||||
public Message reply(boolean replyToAll) throws MessagingException {
|
||||
MimeMessage mm = new MimeMessage(this.session);
|
||||
Address[] reply_to = this.getReplyTo();
|
||||
if ((reply_to==null)||(reply_to.length==0)) {
|
||||
reply_to = this.getFrom();
|
||||
}
|
||||
return in;
|
||||
if (replyToAll) {
|
||||
Address[] recipitants = this.getRecipients(Message.RecipientType.TO);
|
||||
List<Address> recipitants_list = new ArrayList<Address>();
|
||||
if ((recipitants!=null)&&(recipitants.length>0)) {
|
||||
recipitants_list.addAll(Arrays.asList(recipitants));
|
||||
}
|
||||
if ((reply_to!=null)&&(reply_to.length>0)) {
|
||||
recipitants_list.addAll(Arrays.asList(reply_to));
|
||||
}
|
||||
|
||||
public InputStream getInputStreamWithHeaders() throws MessagingException {
|
||||
throw new MethodNotSupportedException("MessageBase.getInputStreamWithHeaders");
|
||||
|
||||
mm.setRecipients(Message.RecipientType.TO,recipitants_list.toArray(new Address[0]));
|
||||
|
||||
recipitants = this.getRecipients(Message.RecipientType.CC);
|
||||
mm.setRecipients(Message.RecipientType.CC,recipitants);
|
||||
|
||||
recipitants = this.getRecipients(Message.RecipientType.BCC);
|
||||
mm.setRecipients(Message.RecipientType.BCC,recipitants);
|
||||
} else {
|
||||
if ((reply_to==null)||(reply_to.length==0)) {
|
||||
throw new MessagingException("No Addresses to send reply to, failed!");
|
||||
}
|
||||
|
||||
mm.setRecipients(Message.RecipientType.TO,new Address[]{reply_to[0]});
|
||||
}
|
||||
|
||||
StringBuffer subject = new StringBuffer(getSubject());
|
||||
MessageExtraWrapper.stripRe(subject);
|
||||
subject.insert(0,"Re: ");
|
||||
mm.setSubject(subject.toString());
|
||||
|
||||
return mm;
|
||||
}
|
||||
|
||||
public boolean isMimeType(String mimeType) throws MessagingException {
|
||||
return getContentType().equalsIgnoreCase(mimeType);
|
||||
}
|
||||
|
||||
/** This default implementation of getInputStream() works in terms of
|
||||
* getInputStreamWithHeaders. Subclasses are encouraged to define this
|
||||
* more directly if they have an easy way of doing so. */
|
||||
public InputStream getInputStream() throws MessagingException, IOException {
|
||||
return getDataHandler().getInputStream();
|
||||
}
|
||||
|
||||
public abstract InputStream getInputStreamWithHeaders() throws MessagingException, IOException;
|
||||
}
|
||||
|
@ -20,6 +20,7 @@
|
||||
* Contributor(s):
|
||||
*
|
||||
* Created: Jamie Zawinski <jwz@netscape.com>, 1 Dec 1997.
|
||||
* Kieran Maclean
|
||||
*/
|
||||
|
||||
package grendel.storage;
|
||||
@ -29,18 +30,19 @@ import calypso.util.ByteBuf;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import javax.mail.Flags;
|
||||
import java.util.Enumeration;
|
||||
import javax.mail.Folder;
|
||||
import javax.mail.Message;
|
||||
import javax.mail.Header;
|
||||
import javax.mail.MessagingException;
|
||||
import javax.mail.internet.InternetHeaders;
|
||||
|
||||
|
||||
class NewsMessage extends MessageBase {
|
||||
class NewsMessage extends MessageBase
|
||||
{
|
||||
|
||||
int article_number = -1;
|
||||
|
||||
int byte_length = -1;
|
||||
|
||||
int line_length = -1;
|
||||
|
||||
NewsMessage(NewsFolder f, InternetHeaders h) {
|
||||
@ -69,6 +71,18 @@ class NewsMessage extends MessageBase {
|
||||
super(f, date, flags, author, recipient, subj, id, refs);
|
||||
}
|
||||
|
||||
public String getContentType() throws MessagingException {
|
||||
String[] content_types = getHeader("Content-Type");
|
||||
if ((content_types == null) || (content_types.length == 0)) {
|
||||
return getDataHandler().getContentType();
|
||||
}
|
||||
for (int i = content_types.length - 1; i > -1; i++) {
|
||||
if (content_types[i].contains("/")) {
|
||||
return content_types[i];
|
||||
}
|
||||
}
|
||||
return content_types[0];
|
||||
}
|
||||
|
||||
void setSize(int l) {
|
||||
byte_length = l;
|
||||
|
@ -17,9 +17,10 @@
|
||||
* Copyright (C) 1997 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Contributor(s):
|
||||
*
|
||||
* Created: Jamie Zawinski <jwz@netscape.com>, 20 Nov 1997.
|
||||
* Kieran Maclean
|
||||
*/
|
||||
|
||||
package grendel.storage;
|
||||
@ -49,49 +50,49 @@ import grendel.util.Constants;
|
||||
|
||||
|
||||
/** Store for News (NNTP) folders.
|
||||
<p>
|
||||
This class really shouldn't be public, but I haven't figured out how to
|
||||
tie into javamail's Session class properly. So, instead of using
|
||||
<tt>Session.getStore(String)</tt>, you instead need to call
|
||||
<tt>NewsStore.GetDefaultStore(Session)</tt>.
|
||||
*/
|
||||
* <p>
|
||||
* This class really shouldn't be public, but I haven't figured out how to
|
||||
* tie into javamail's Session class properly. So, instead of using
|
||||
* <tt>Session.getStore(String)</tt>, you instead need to call
|
||||
* <tt>NewsStore.GetDefaultStore(Session)</tt>.
|
||||
*/
|
||||
|
||||
public class NewsStore extends Store {
|
||||
|
||||
|
||||
protected NNTPConnection nntp = null;
|
||||
protected NewsRC newsrc = null;
|
||||
protected NewsFolderRoot root_folder = null;
|
||||
|
||||
|
||||
static protected NewsStore DefaultStore = null;
|
||||
|
||||
|
||||
public static Store GetDefaultStore(Session s) {
|
||||
if (DefaultStore == null) {
|
||||
DefaultStore = new NewsStore(s);
|
||||
}
|
||||
return DefaultStore;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public NewsStore(Session s) {
|
||||
super(s, null);
|
||||
}
|
||||
|
||||
|
||||
public NewsStore(Session s, URLName u) {
|
||||
super(s, u);
|
||||
}
|
||||
|
||||
|
||||
NewsRC getNewsRC() {
|
||||
return newsrc;
|
||||
}
|
||||
|
||||
|
||||
private void loadNewsRC(String host) throws IOException {
|
||||
Assert.Assertion(newsrc == null);
|
||||
String dir = System.getProperty("user.home");
|
||||
boolean secure = false; // ####
|
||||
String name = null;
|
||||
|
||||
|
||||
if (Constants.ISUNIX) {
|
||||
|
||||
|
||||
String name1 = (secure ? ".snewsrc" : ".newsrc");
|
||||
String name2 = name1 + "-" + host;
|
||||
if (new File(dir, name2).exists())
|
||||
@ -100,9 +101,9 @@ public class NewsStore extends Store {
|
||||
name = name1;
|
||||
else
|
||||
name = name2;
|
||||
|
||||
|
||||
} else if (Constants.ISWINDOWS) {
|
||||
|
||||
|
||||
String name1 = (secure ? "snews" : "news");
|
||||
String name2 = name1 + "-" + host + ".rc";
|
||||
String name3 = name1 + ".rc";
|
||||
@ -112,14 +113,14 @@ public class NewsStore extends Store {
|
||||
name = name3;
|
||||
else
|
||||
name = name2;
|
||||
|
||||
|
||||
} else {
|
||||
Assert.NotYetImplemented("newsrc names only implemented for windows 'n' unix...");
|
||||
}
|
||||
|
||||
|
||||
File f = new File(dir, name);
|
||||
newsrc = new NewsRC(f);
|
||||
|
||||
|
||||
// If the newsrc file didn't exist, subscribe to some default newsgroups.
|
||||
if (!f.exists()) {
|
||||
String subs[] = getDefaultSubscriptions();
|
||||
@ -128,19 +129,19 @@ public class NewsStore extends Store {
|
||||
ng.setSubscribed(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected boolean protocolConnect(String host,
|
||||
int port,
|
||||
String user,
|
||||
String password)
|
||||
throws MessagingException {
|
||||
|
||||
int port,
|
||||
String user,
|
||||
String password)
|
||||
throws MessagingException {
|
||||
|
||||
if (nntp != null)
|
||||
return true; // Already connected.
|
||||
|
||||
|
||||
if (host == null) {
|
||||
// #### better name?
|
||||
host = session.getProperty("mail.default_nntp_server");
|
||||
@ -149,45 +150,45 @@ public class NewsStore extends Store {
|
||||
host = "news";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
loadNewsRC(host);
|
||||
} catch (IOException e) {
|
||||
throw new MessagingException("loading newsrc file", e);
|
||||
}
|
||||
|
||||
|
||||
nntp = new NNTPConnection();
|
||||
|
||||
|
||||
try {
|
||||
boolean status = nntp.connect(host, port, user, password);
|
||||
if (!status) return false;
|
||||
|
||||
|
||||
} catch (UnknownHostException e) { // This sucks, Beavis!
|
||||
throw new MessagingException("Unknown host", e);
|
||||
} catch (IOException e) {
|
||||
throw new MessagingException("I/O Error", e);
|
||||
}
|
||||
|
||||
|
||||
if (!newsrc.file().exists()) {
|
||||
// #### subscribe to the server's default groups
|
||||
}
|
||||
|
||||
|
||||
notifyStoreListeners(StoreEvent.NOTICE, "opened"); // #### ???
|
||||
// notifyConnectionListeners(ConnectionEvent.OPENED);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public void close() {
|
||||
|
||||
|
||||
if (nntp == null) {
|
||||
// already closed.
|
||||
Assert.Assertion(newsrc == null);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
nntp.close();
|
||||
nntp = null;
|
||||
|
||||
|
||||
Assert.Assertion(newsrc != null);
|
||||
if (newsrc != null) {
|
||||
try {
|
||||
@ -197,13 +198,13 @@ public class NewsStore extends Store {
|
||||
// Just ignore it, I guess...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
notifyStoreListeners(StoreEvent.NOTICE, "closed"); // #### ???
|
||||
// notifyConnectionListeners(ConnectionEvent.CLOSED);
|
||||
root_folder = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public Folder getDefaultFolder() {
|
||||
if (root_folder == null) {
|
||||
synchronized (this) {
|
||||
@ -214,23 +215,28 @@ public class NewsStore extends Store {
|
||||
}
|
||||
return root_folder;
|
||||
}
|
||||
|
||||
|
||||
public Folder getFolder(String name) throws MessagingException {
|
||||
return getDefaultFolder().getFolder(name);
|
||||
}
|
||||
|
||||
public Folder getFolder(URL url) {
|
||||
Assert.NotYetImplemented("NewsStore.getFolder(URL)");
|
||||
return null;
|
||||
|
||||
public Folder getFolder(URL url) throws MessagingException {
|
||||
return getFolder(new URLName(url));
|
||||
}
|
||||
|
||||
public Folder getFolder(URLName urlName) {
|
||||
Assert.NotYetImplemented("NewsStore.getFolder(URLName)");
|
||||
return null;
|
||||
|
||||
public Folder getFolder(URLName urlName) throws MessagingException {
|
||||
if (! urlName.getHost().equalsIgnoreCase(url.getHost()))
|
||||
throw new MessagingException("Not the same host.");
|
||||
if (urlName.getPort() != url.getPort())
|
||||
throw new MessagingException("Not the same port.");
|
||||
String file = urlName.getFile();
|
||||
if (file.contains("/"))
|
||||
throw new MessagingException("Invalid URL.");
|
||||
return getFolder(file);
|
||||
}
|
||||
|
||||
|
||||
InputStream getMessageStream(NewsMessage message, boolean headers_too)
|
||||
throws NNTPException, IOException {
|
||||
throws NNTPException, IOException {
|
||||
Folder f = message.getFolder();
|
||||
String group = (f == null ? null : f.getFullName());
|
||||
int n = (group == null ? -1 : message.getStorageFolderIndex());
|
||||
@ -251,9 +257,9 @@ public class NewsStore extends Store {
|
||||
return nntp.BODY(group, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Returns array of int: [ nmessages low hi ]
|
||||
*/
|
||||
*/
|
||||
int[] getGroupCounts(NewsFolder folder) {
|
||||
String group = folder.getFullName();
|
||||
try {
|
||||
@ -262,11 +268,11 @@ public class NewsStore extends Store {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Returns a list of newsgroups to which new users should be subscribed,
|
||||
if they don't have a newsrc file. Tries to ask the news server for
|
||||
this list; otherwise, uses some builtin defaults.
|
||||
*/
|
||||
* if they don't have a newsrc file. Tries to ask the news server for
|
||||
* this list; otherwise, uses some builtin defaults.
|
||||
*/
|
||||
String[] getDefaultSubscriptions() {
|
||||
String s[] = null;
|
||||
try {
|
||||
@ -276,13 +282,13 @@ public class NewsStore extends Store {
|
||||
}
|
||||
if (s == null || s.length == 0)
|
||||
s = new String[] { "news.announce.newusers",
|
||||
"news.newusers.questions",
|
||||
"news.groups.questions",
|
||||
"alt.fan.mozilla"
|
||||
};
|
||||
return s;
|
||||
"news.newusers.questions",
|
||||
"news.groups.questions",
|
||||
"alt.fan.mozilla"
|
||||
};
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
void openNewsgroup(NewsFolder folder, long from, long to) {
|
||||
Enumeration e;
|
||||
try {
|
||||
@ -292,7 +298,7 @@ public class NewsStore extends Store {
|
||||
} catch (IOException ex) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while (e.hasMoreElements()) {
|
||||
Message m = (Message) e.nextElement();
|
||||
folder.noticeInitialMessage(m);
|
||||
|
Loading…
x
Reference in New Issue
Block a user