mirror of https://github.com/M66B/FairEmail.git
parent
cc572e67f6
commit
9fff57fa31
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count the number of bytes in the body of the message written to the stream.
|
|
||||||
*/
|
|
||||||
class ContentLengthCounter extends OutputStream {
|
|
||||||
private long size = 0;
|
|
||||||
private boolean inHeader = true;
|
|
||||||
private int lastb1 = -1, lastb2 = -1;
|
|
||||||
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
if (inHeader) {
|
|
||||||
// if line terminator is CR
|
|
||||||
if (b == '\r' && lastb1 == '\r')
|
|
||||||
inHeader = false;
|
|
||||||
else if (b == '\n') {
|
|
||||||
// if line terminator is \n
|
|
||||||
if (lastb1 == '\n')
|
|
||||||
inHeader = false;
|
|
||||||
// if line terminator is CRLF
|
|
||||||
else if (lastb1 == '\r' && lastb2 == '\n')
|
|
||||||
inHeader = false;
|
|
||||||
}
|
|
||||||
lastb2 = lastb1;
|
|
||||||
lastb1 = b;
|
|
||||||
} else
|
|
||||||
size++;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b) throws IOException {
|
|
||||||
if (inHeader)
|
|
||||||
super.write(b);
|
|
||||||
else
|
|
||||||
size += b.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
|
||||||
if (inHeader)
|
|
||||||
super.write(b, off, len);
|
|
||||||
else
|
|
||||||
size += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getSize() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public static void main(String argv[]) throws Exception {
|
|
||||||
int b;
|
|
||||||
ContentLengthCounter os = new ContentLengthCounter();
|
|
||||||
while ((b = System.in.read()) >= 0)
|
|
||||||
os.write(b);
|
|
||||||
System.out.println("size " + os.getSize());
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the Content-Length header in the message written to the stream.
|
|
||||||
*/
|
|
||||||
class ContentLengthUpdater extends FilterOutputStream {
|
|
||||||
private String contentLength;
|
|
||||||
private boolean inHeader = true;
|
|
||||||
private boolean sawContentLength = false;
|
|
||||||
private int lastb1 = -1, lastb2 = -1;
|
|
||||||
private StringBuilder line = new StringBuilder();
|
|
||||||
|
|
||||||
public ContentLengthUpdater(OutputStream os, long contentLength) {
|
|
||||||
super(os);
|
|
||||||
this.contentLength = "Content-Length: " + contentLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
if (inHeader) {
|
|
||||||
String eol = "\n";
|
|
||||||
// First, determine if we're still in the header.
|
|
||||||
if (b == '\r') {
|
|
||||||
// if line terminator is CR
|
|
||||||
if (lastb1 == '\r') {
|
|
||||||
inHeader = false;
|
|
||||||
eol = "\r";
|
|
||||||
// else, if line terminator is CRLF
|
|
||||||
} else if (lastb1 == '\n' && lastb2 == '\r') {
|
|
||||||
inHeader = false;
|
|
||||||
eol = "\r\n";
|
|
||||||
}
|
|
||||||
// else, if line terminator is \n
|
|
||||||
} else if (b == '\n') {
|
|
||||||
if (lastb1 == '\n') {
|
|
||||||
inHeader = false;
|
|
||||||
eol = "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we're no longer in the header, and we haven't seen
|
|
||||||
// a Content-Length header yet, it's time to put one out.
|
|
||||||
if (!inHeader && !sawContentLength) {
|
|
||||||
out.write(contentLength.getBytes("iso-8859-1"));
|
|
||||||
out.write(eol.getBytes("iso-8859-1"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we have a full line, see if it's a Content-Length header.
|
|
||||||
if (b == '\r' || (b == '\n' && lastb1 != '\r')) {
|
|
||||||
if (line.toString().regionMatches(true, 0,
|
|
||||||
"content-length:", 0, 15)) {
|
|
||||||
// yup, got it
|
|
||||||
sawContentLength = true;
|
|
||||||
// put out the new version
|
|
||||||
out.write(contentLength.getBytes("iso-8859-1"));
|
|
||||||
} else {
|
|
||||||
// not a Content-Length header, just write it out
|
|
||||||
out.write(line.toString().getBytes("iso-8859-1"));
|
|
||||||
}
|
|
||||||
line.setLength(0); // clear buffer for next line
|
|
||||||
}
|
|
||||||
if (b == '\r' || b == '\n')
|
|
||||||
out.write(b); // write out line terminator immediately
|
|
||||||
else
|
|
||||||
line.append((char)b); // accumulate characters of the line
|
|
||||||
|
|
||||||
// rotate saved characters for next time through loop
|
|
||||||
lastb2 = lastb1;
|
|
||||||
lastb1 = b;
|
|
||||||
} else
|
|
||||||
out.write(b); // not in the header, just write it out
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b) throws IOException {
|
|
||||||
if (inHeader)
|
|
||||||
write(b, 0, b.length);
|
|
||||||
else
|
|
||||||
out.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
|
||||||
if (inHeader) {
|
|
||||||
for (int i = 0 ; i < len ; i++) {
|
|
||||||
write(b[off + i]);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
out.write(b, off, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// for testing
|
|
||||||
public static void main(String argv[]) throws Exception {
|
|
||||||
int b;
|
|
||||||
ContentLengthUpdater os =
|
|
||||||
new ContentLengthUpdater(System.out, Long.parseLong(argv[0]));
|
|
||||||
while ((b = System.in.read()) >= 0)
|
|
||||||
os.write(b);
|
|
||||||
os.flush();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,106 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public class DefaultMailbox extends Mailbox {
|
|
||||||
private final String home;
|
|
||||||
|
|
||||||
private static final boolean homeRelative =
|
|
||||||
Boolean.getBoolean("mail.mbox.homerelative");
|
|
||||||
|
|
||||||
public DefaultMailbox() {
|
|
||||||
home = System.getProperty("user.home");
|
|
||||||
}
|
|
||||||
|
|
||||||
public MailFile getMailFile(String user, String folder) {
|
|
||||||
return new DefaultMailFile(filename(user, folder));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String filename(String user, String folder) {
|
|
||||||
try {
|
|
||||||
char c = folder.charAt(0);
|
|
||||||
if (c == File.separatorChar) {
|
|
||||||
return folder;
|
|
||||||
} else if (c == '~') {
|
|
||||||
int i = folder.indexOf(File.separatorChar);
|
|
||||||
String tail = "";
|
|
||||||
if (i > 0) {
|
|
||||||
tail = folder.substring(i);
|
|
||||||
folder = folder.substring(0, i);
|
|
||||||
}
|
|
||||||
return home + tail;
|
|
||||||
} else {
|
|
||||||
if (folder.equalsIgnoreCase("INBOX"))
|
|
||||||
folder = "INBOX";
|
|
||||||
if (homeRelative)
|
|
||||||
return home + File.separator + folder;
|
|
||||||
else
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
} catch (StringIndexOutOfBoundsException e) {
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DefaultMailFile extends File implements MailFile {
|
|
||||||
protected transient RandomAccessFile file;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 3713116697523761684L;
|
|
||||||
|
|
||||||
DefaultMailFile(String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean lock(String mode) {
|
|
||||||
try {
|
|
||||||
file = new RandomAccessFile(this, mode);
|
|
||||||
return true;
|
|
||||||
} catch (FileNotFoundException fe) {
|
|
||||||
return false;
|
|
||||||
} catch (IOException ie) {
|
|
||||||
file = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unlock() {
|
|
||||||
if (file != null) {
|
|
||||||
try {
|
|
||||||
file.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// ignore it
|
|
||||||
}
|
|
||||||
file = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void touchlock() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileDescriptor getFD() {
|
|
||||||
if (file == null)
|
|
||||||
return null;
|
|
||||||
try {
|
|
||||||
return file.getFD();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FilenameFilter;
|
|
||||||
|
|
||||||
public interface FileInterface {
|
|
||||||
/**
|
|
||||||
* Gets the name of the file. This method does not include the
|
|
||||||
* directory.
|
|
||||||
* @return the file name.
|
|
||||||
*/
|
|
||||||
public String getName();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the path of the file.
|
|
||||||
* @return the file path.
|
|
||||||
*/
|
|
||||||
public String getPath();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the absolute path of the file.
|
|
||||||
* @return the absolute file path.
|
|
||||||
*/
|
|
||||||
public String getAbsolutePath();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the official, canonical path of the File.
|
|
||||||
* @return canonical path
|
|
||||||
*/
|
|
||||||
// XXX - JDK1.1
|
|
||||||
// public String getCanonicalPath();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the name of the parent directory.
|
|
||||||
* @return the parent directory, or null if one is not found.
|
|
||||||
*/
|
|
||||||
public String getParent();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a boolean indicating whether or not a file exists.
|
|
||||||
*/
|
|
||||||
public boolean exists();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a boolean indicating whether or not a writable file
|
|
||||||
* exists.
|
|
||||||
*/
|
|
||||||
public boolean canWrite();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a boolean indicating whether or not a readable file
|
|
||||||
* exists.
|
|
||||||
*/
|
|
||||||
public boolean canRead();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a boolean indicating whether or not a normal file
|
|
||||||
* exists.
|
|
||||||
*/
|
|
||||||
public boolean isFile();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a boolean indicating whether or not a directory file
|
|
||||||
* exists.
|
|
||||||
*/
|
|
||||||
public boolean isDirectory();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a boolean indicating whether the file name is absolute.
|
|
||||||
*/
|
|
||||||
public boolean isAbsolute();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the last modification time. The return value should
|
|
||||||
* only be used to compare modification dates. It is meaningless
|
|
||||||
* as an absolute time.
|
|
||||||
*/
|
|
||||||
public long lastModified();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the length of the file.
|
|
||||||
*/
|
|
||||||
public long length();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a directory and returns a boolean indicating the
|
|
||||||
* success of the creation. Will return false if the directory already
|
|
||||||
* exists.
|
|
||||||
*/
|
|
||||||
public boolean mkdir();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renames a file and returns a boolean indicating whether
|
|
||||||
* or not this method was successful.
|
|
||||||
* @param dest the new file name
|
|
||||||
*/
|
|
||||||
public boolean renameTo(File dest);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates all directories in this path. This method
|
|
||||||
* returns true if the target (deepest) directory was created,
|
|
||||||
* false if the target directory was not created (e.g., if it
|
|
||||||
* existed previously).
|
|
||||||
*/
|
|
||||||
public boolean mkdirs();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lists the files in a directory. Works only on directories.
|
|
||||||
* @return an array of file names. This list will include all
|
|
||||||
* files in the directory except the equivalent of "." and ".." .
|
|
||||||
*/
|
|
||||||
public String[] list();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Uses the specified filter to list files in a directory.
|
|
||||||
* @param filter the filter used to select file names
|
|
||||||
* @return the filter selected files in this directory.
|
|
||||||
* @see FilenameFilter
|
|
||||||
*/
|
|
||||||
public String[] list(FilenameFilter filter);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the specified file. Returns true
|
|
||||||
* if the file could be deleted.
|
|
||||||
*/
|
|
||||||
public boolean delete();
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
public interface InboxFile extends MailFile {
|
|
||||||
public boolean openLock(String mode);
|
|
||||||
public void closeLock();
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Count number of lines output.
|
|
||||||
*/
|
|
||||||
class LineCounter extends FilterOutputStream {
|
|
||||||
private int lastb = -1;
|
|
||||||
protected int lineCount;
|
|
||||||
|
|
||||||
public LineCounter(OutputStream os) {
|
|
||||||
super(os);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
// If we have a full line, count it.
|
|
||||||
if (b == '\r' || (b == '\n' && lastb != '\r'))
|
|
||||||
lineCount++;
|
|
||||||
out.write(b);
|
|
||||||
lastb = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b) throws IOException {
|
|
||||||
write(b, 0, b.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
|
||||||
for (int i = 0 ; i < len ; i++) {
|
|
||||||
write(b[off + i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLineCount() {
|
|
||||||
return lineCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
// for testing
|
|
||||||
public static void main(String argv[]) throws Exception {
|
|
||||||
int b;
|
|
||||||
LineCounter os =
|
|
||||||
new LineCounter(System.out);
|
|
||||||
while ((b = System.in.read()) >= 0)
|
|
||||||
os.write(b);
|
|
||||||
os.flush();
|
|
||||||
System.out.println(os.getLineCount());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
|
||||||
|
|
||||||
public interface MailFile extends FileInterface {
|
|
||||||
public boolean lock(String mode);
|
|
||||||
public void unlock();
|
|
||||||
public void touchlock();
|
|
||||||
public FileDescriptor getFD();
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
public abstract class Mailbox {
|
|
||||||
/**
|
|
||||||
* Return a MailFile object for the specified user's folder.
|
|
||||||
*/
|
|
||||||
public abstract MailFile getMailFile(String user, String folder);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the file name corresponding to a folder with the given name.
|
|
||||||
*/
|
|
||||||
public abstract String filename(String user, String folder);
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,532 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import javax.activation.*;
|
|
||||||
import javax.mail.*;
|
|
||||||
import javax.mail.internet.*;
|
|
||||||
import javax.mail.event.MessageChangedEvent;
|
|
||||||
import com.sun.mail.util.LineInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents an RFC822 style email message that resides in a file.
|
|
||||||
*
|
|
||||||
* @author Bill Shannon
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class MboxMessage extends MimeMessage {
|
|
||||||
|
|
||||||
boolean writable = false;
|
|
||||||
// original msg flags, used by MboxFolder to detect modification
|
|
||||||
Flags origFlags;
|
|
||||||
/*
|
|
||||||
* A UNIX From line looks like:
|
|
||||||
* From address Day Mon DD HH:MM:SS YYYY
|
|
||||||
*/
|
|
||||||
String unix_from;
|
|
||||||
InternetAddress unix_from_user;
|
|
||||||
Date rcvDate;
|
|
||||||
int lineCount = -1;
|
|
||||||
private static OutputStream nullOutputStream = new OutputStream() {
|
|
||||||
public void write(int b) { }
|
|
||||||
public void write(byte[] b, int off, int len) { }
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct an MboxMessage from the InputStream.
|
|
||||||
*/
|
|
||||||
public MboxMessage(Session session, InputStream is)
|
|
||||||
throws MessagingException, IOException {
|
|
||||||
super(session);
|
|
||||||
BufferedInputStream bis;
|
|
||||||
if (is instanceof BufferedInputStream)
|
|
||||||
bis = (BufferedInputStream)is;
|
|
||||||
else
|
|
||||||
bis = new BufferedInputStream(is);
|
|
||||||
LineInputStream dis = new LineInputStream(bis);
|
|
||||||
bis.mark(1024);
|
|
||||||
String line = dis.readLine();
|
|
||||||
if (line != null && line.startsWith("From "))
|
|
||||||
this.unix_from = line;
|
|
||||||
else
|
|
||||||
bis.reset();
|
|
||||||
parse(bis);
|
|
||||||
saved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Construct an MboxMessage using the given InternetHeaders object
|
|
||||||
* and content from an InputStream.
|
|
||||||
*/
|
|
||||||
public MboxMessage(MboxFolder folder, InternetHeaders hdrs, InputStream is,
|
|
||||||
int msgno, String unix_from, boolean writable)
|
|
||||||
throws MessagingException {
|
|
||||||
super(folder, hdrs, null, msgno);
|
|
||||||
setFlagsFromHeaders();
|
|
||||||
origFlags = getFlags();
|
|
||||||
this.unix_from = unix_from;
|
|
||||||
this.writable = writable;
|
|
||||||
this.contentStream = is;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the "From" attribute. The "From" attribute contains
|
|
||||||
* the identity of the person(s) who wished this message to
|
|
||||||
* be sent. <p>
|
|
||||||
*
|
|
||||||
* If our superclass doesn't have a value, we return the address
|
|
||||||
* from the UNIX From line.
|
|
||||||
*
|
|
||||||
* @return array of Address objects
|
|
||||||
* @exception MessagingException
|
|
||||||
*/
|
|
||||||
public Address[] getFrom() throws MessagingException {
|
|
||||||
Address[] ret = super.getFrom();
|
|
||||||
if (ret == null) {
|
|
||||||
InternetAddress ia = getUnixFrom();
|
|
||||||
if (ia != null)
|
|
||||||
ret = new InternetAddress[] { ia };
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the address from the UNIX "From" line.
|
|
||||||
*
|
|
||||||
* @return UNIX From address
|
|
||||||
* @exception MessagingException
|
|
||||||
*/
|
|
||||||
public synchronized InternetAddress getUnixFrom()
|
|
||||||
throws MessagingException {
|
|
||||||
if (unix_from_user == null && unix_from != null) {
|
|
||||||
int i;
|
|
||||||
// find the space after the address, before the date
|
|
||||||
i = unix_from.indexOf(' ', 5);
|
|
||||||
if (i > 5) {
|
|
||||||
try {
|
|
||||||
unix_from_user =
|
|
||||||
new InternetAddress(unix_from.substring(5, i));
|
|
||||||
} catch (AddressException e) {
|
|
||||||
// ignore it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return unix_from_user != null ?
|
|
||||||
(InternetAddress)unix_from_user.clone() : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getUnixFromLine() {
|
|
||||||
if (unix_from != null)
|
|
||||||
return unix_from;
|
|
||||||
String from = "unknown";
|
|
||||||
try {
|
|
||||||
Address[] froma = getFrom();
|
|
||||||
if (froma != null && froma.length > 0 &&
|
|
||||||
froma[0] instanceof InternetAddress)
|
|
||||||
from = ((InternetAddress)froma[0]).getAddress();
|
|
||||||
} catch (MessagingException ex) { }
|
|
||||||
Date d = null;
|
|
||||||
try {
|
|
||||||
d = getSentDate();
|
|
||||||
} catch (MessagingException ex) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
if (d == null)
|
|
||||||
d = new Date();
|
|
||||||
// From shannon Mon Jun 10 12:06:52 2002
|
|
||||||
SimpleDateFormat fmt = new SimpleDateFormat("EEE LLL dd HH:mm:ss yyyy");
|
|
||||||
return "From " + from + " " + fmt.format(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the date this message was received, from the UNIX From line.
|
|
||||||
*
|
|
||||||
* @return the date this message was received
|
|
||||||
* @exception MessagingException
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation") // for Date constructor
|
|
||||||
public Date getReceivedDate() throws MessagingException {
|
|
||||||
if (rcvDate == null && unix_from != null) {
|
|
||||||
int i;
|
|
||||||
// find the space after the address, before the date
|
|
||||||
i = unix_from.indexOf(' ', 5);
|
|
||||||
if (i > 5) {
|
|
||||||
try {
|
|
||||||
rcvDate = new Date(unix_from.substring(i));
|
|
||||||
} catch (IllegalArgumentException iae) {
|
|
||||||
// ignore it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rcvDate == null ? null : new Date(rcvDate.getTime());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the number of lines for the content of this message.
|
|
||||||
* Return -1 if this number cannot be determined. <p>
|
|
||||||
*
|
|
||||||
* Note that this number may not be an exact measure of the
|
|
||||||
* content length and may or may not account for any transfer
|
|
||||||
* encoding of the content. <p>
|
|
||||||
*
|
|
||||||
* This implementation returns -1.
|
|
||||||
*
|
|
||||||
* @return number of lines in the content.
|
|
||||||
* @exception MessagingException
|
|
||||||
*/
|
|
||||||
public int getLineCount() throws MessagingException {
|
|
||||||
if (lineCount < 0 && isMimeType("text/plain")) {
|
|
||||||
LineCounter lc = null;
|
|
||||||
// writeTo will set the SEEN flag, remember the original state
|
|
||||||
boolean seen = isSet(Flags.Flag.SEEN);
|
|
||||||
try {
|
|
||||||
lc = new LineCounter(nullOutputStream);
|
|
||||||
getDataHandler().writeTo(lc);
|
|
||||||
lineCount = lc.getLineCount();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
// ignore it, can't happen
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (lc != null)
|
|
||||||
lc.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
// can't happen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!seen)
|
|
||||||
setFlag(Flags.Flag.SEEN, false);
|
|
||||||
}
|
|
||||||
return lineCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the specified flags on this message to the specified value.
|
|
||||||
*
|
|
||||||
* @param flags the flags to be set
|
|
||||||
* @param set the value to be set
|
|
||||||
*/
|
|
||||||
public void setFlags(Flags newFlags, boolean set)
|
|
||||||
throws MessagingException {
|
|
||||||
Flags oldFlags = (Flags)flags.clone();
|
|
||||||
super.setFlags(newFlags, set);
|
|
||||||
if (!flags.equals(oldFlags)) {
|
|
||||||
setHeadersFromFlags(this);
|
|
||||||
if (folder != null)
|
|
||||||
((MboxFolder)folder).notifyMessageChangedListeners(
|
|
||||||
MessageChangedEvent.FLAGS_CHANGED, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the content type, mapping from SunV3 types to MIME types
|
|
||||||
* as necessary.
|
|
||||||
*/
|
|
||||||
public String getContentType() throws MessagingException {
|
|
||||||
String ct = super.getContentType();
|
|
||||||
if (ct.indexOf('/') < 0)
|
|
||||||
ct = SunV3BodyPart.MimeV3Map.toMime(ct);
|
|
||||||
return ct;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Produce the raw bytes of the content. This method is used during
|
|
||||||
* parsing, to create a DataHandler object for the content. Subclasses
|
|
||||||
* that can provide a separate input stream for just the message
|
|
||||||
* content might want to override this method. <p>
|
|
||||||
*
|
|
||||||
* This implementation just returns a ByteArrayInputStream constructed
|
|
||||||
* out of the <code>content</code> byte array.
|
|
||||||
*
|
|
||||||
* @see #content
|
|
||||||
*/
|
|
||||||
protected InputStream getContentStream() throws MessagingException {
|
|
||||||
if (folder != null)
|
|
||||||
((MboxFolder)folder).checkOpen();
|
|
||||||
if (isExpunged())
|
|
||||||
throw new MessageRemovedException("mbox message expunged");
|
|
||||||
if (!isSet(Flags.Flag.SEEN))
|
|
||||||
setFlag(Flags.Flag.SEEN, true);
|
|
||||||
return super.getContentStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a DataHandler for this Message's content.
|
|
||||||
* If this is a SunV3 multipart message, handle it specially.
|
|
||||||
*
|
|
||||||
* @exception MessagingException
|
|
||||||
*/
|
|
||||||
public synchronized DataHandler getDataHandler()
|
|
||||||
throws MessagingException {
|
|
||||||
if (dh == null) {
|
|
||||||
// XXX - Following is a kludge to avoid having to register
|
|
||||||
// the "multipart/x-sun-attachment" data type with the JAF.
|
|
||||||
String ct = getContentType();
|
|
||||||
if (ct.equalsIgnoreCase("multipart/x-sun-attachment"))
|
|
||||||
dh = new DataHandler(
|
|
||||||
new SunV3Multipart(new MimePartDataSource(this)), ct);
|
|
||||||
else
|
|
||||||
return super.getDataHandler(); // will set "dh"
|
|
||||||
}
|
|
||||||
return dh;
|
|
||||||
}
|
|
||||||
|
|
||||||
// here only to allow package private access from MboxFolder
|
|
||||||
protected void setMessageNumber(int msgno) {
|
|
||||||
super.setMessageNumber(msgno);
|
|
||||||
}
|
|
||||||
|
|
||||||
// here to synchronize access to expunged field
|
|
||||||
public synchronized boolean isExpunged() {
|
|
||||||
return super.isExpunged();
|
|
||||||
}
|
|
||||||
|
|
||||||
// here to synchronize and to allow access from MboxFolder
|
|
||||||
protected synchronized void setExpunged(boolean expunged) {
|
|
||||||
super.setExpunged(expunged);
|
|
||||||
}
|
|
||||||
|
|
||||||
// XXX - We assume that only body parts that are part of a SunV3
|
|
||||||
// multipart will use the SunV3 headers (X-Sun-Content-Length,
|
|
||||||
// X-Sun-Content-Lines, X-Sun-Data-Type, X-Sun-Encoding-Info,
|
|
||||||
// X-Sun-Data-Description, X-Sun-Data-Name) so we don't handle
|
|
||||||
// them here.
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the flags for this message based on the Status,
|
|
||||||
* X-Status, and X-Dt-Delete-Time headers.
|
|
||||||
*
|
|
||||||
* SIMS 2.0:
|
|
||||||
* "X-Status: DFAT", deleted, flagged, answered, draft.
|
|
||||||
* Unset flags represented as "$".
|
|
||||||
* User flags not supported.
|
|
||||||
*
|
|
||||||
* University of Washington IMAP server:
|
|
||||||
* "X-Status: DFAT", deleted, flagged, answered, draft.
|
|
||||||
* Unset flags not present.
|
|
||||||
* "X-Keywords: userflag1 userflag2"
|
|
||||||
*/
|
|
||||||
private synchronized void setFlagsFromHeaders() {
|
|
||||||
flags = new Flags(Flags.Flag.RECENT);
|
|
||||||
try {
|
|
||||||
String s = getHeader("Status", null);
|
|
||||||
if (s != null) {
|
|
||||||
if (s.indexOf('R') >= 0)
|
|
||||||
flags.add(Flags.Flag.SEEN);
|
|
||||||
if (s.indexOf('O') >= 0)
|
|
||||||
flags.remove(Flags.Flag.RECENT);
|
|
||||||
}
|
|
||||||
s = getHeader("X-Dt-Delete-Time", null); // set by dtmail
|
|
||||||
if (s != null)
|
|
||||||
flags.add(Flags.Flag.DELETED);
|
|
||||||
s = getHeader("X-Status", null); // set by IMAP server
|
|
||||||
if (s != null) {
|
|
||||||
if (s.indexOf('D') >= 0)
|
|
||||||
flags.add(Flags.Flag.DELETED);
|
|
||||||
if (s.indexOf('F') >= 0)
|
|
||||||
flags.add(Flags.Flag.FLAGGED);
|
|
||||||
if (s.indexOf('A') >= 0)
|
|
||||||
flags.add(Flags.Flag.ANSWERED);
|
|
||||||
if (s.indexOf('T') >= 0)
|
|
||||||
flags.add(Flags.Flag.DRAFT);
|
|
||||||
}
|
|
||||||
s = getHeader("X-Keywords", null); // set by IMAP server
|
|
||||||
if (s != null) {
|
|
||||||
StringTokenizer st = new StringTokenizer(s);
|
|
||||||
while (st.hasMoreTokens())
|
|
||||||
flags.add(st.nextToken());
|
|
||||||
}
|
|
||||||
} catch (MessagingException e) {
|
|
||||||
// ignore it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the various header fields that represent the message flags.
|
|
||||||
*/
|
|
||||||
static void setHeadersFromFlags(MimeMessage msg) {
|
|
||||||
try {
|
|
||||||
Flags flags = msg.getFlags();
|
|
||||||
StringBuilder status = new StringBuilder();
|
|
||||||
if (flags.contains(Flags.Flag.SEEN))
|
|
||||||
status.append('R');
|
|
||||||
if (!flags.contains(Flags.Flag.RECENT))
|
|
||||||
status.append('O');
|
|
||||||
if (status.length() > 0)
|
|
||||||
msg.setHeader("Status", status.toString());
|
|
||||||
else
|
|
||||||
msg.removeHeader("Status");
|
|
||||||
|
|
||||||
boolean sims = false;
|
|
||||||
String s = msg.getHeader("X-Status", null);
|
|
||||||
// is it a SIMS 2.0 format X-Status header?
|
|
||||||
sims = s != null && s.length() == 4 && s.indexOf('$') >= 0;
|
|
||||||
status.setLength(0);
|
|
||||||
if (flags.contains(Flags.Flag.DELETED))
|
|
||||||
status.append('D');
|
|
||||||
else if (sims)
|
|
||||||
status.append('$');
|
|
||||||
if (flags.contains(Flags.Flag.FLAGGED))
|
|
||||||
status.append('F');
|
|
||||||
else if (sims)
|
|
||||||
status.append('$');
|
|
||||||
if (flags.contains(Flags.Flag.ANSWERED))
|
|
||||||
status.append('A');
|
|
||||||
else if (sims)
|
|
||||||
status.append('$');
|
|
||||||
if (flags.contains(Flags.Flag.DRAFT))
|
|
||||||
status.append('T');
|
|
||||||
else if (sims)
|
|
||||||
status.append('$');
|
|
||||||
if (status.length() > 0)
|
|
||||||
msg.setHeader("X-Status", status.toString());
|
|
||||||
else
|
|
||||||
msg.removeHeader("X-Status");
|
|
||||||
|
|
||||||
String[] userFlags = flags.getUserFlags();
|
|
||||||
if (userFlags.length > 0) {
|
|
||||||
status.setLength(0);
|
|
||||||
for (int i = 0; i < userFlags.length; i++)
|
|
||||||
status.append(userFlags[i]).append(' ');
|
|
||||||
status.setLength(status.length() - 1); // smash trailing space
|
|
||||||
msg.setHeader("X-Keywords", status.toString());
|
|
||||||
}
|
|
||||||
if (flags.contains(Flags.Flag.DELETED)) {
|
|
||||||
s = msg.getHeader("X-Dt-Delete-Time", null);
|
|
||||||
if (s == null)
|
|
||||||
// XXX - should be time
|
|
||||||
msg.setHeader("X-Dt-Delete-Time", "1");
|
|
||||||
}
|
|
||||||
} catch (MessagingException e) {
|
|
||||||
// ignore it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateHeaders() throws MessagingException {
|
|
||||||
super.updateHeaders();
|
|
||||||
setHeadersFromFlags(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Save any changes made to this message.
|
|
||||||
*/
|
|
||||||
public void saveChanges() throws MessagingException {
|
|
||||||
if (folder != null)
|
|
||||||
((MboxFolder)folder).checkOpen();
|
|
||||||
if (isExpunged())
|
|
||||||
throw new MessageRemovedException("mbox message expunged");
|
|
||||||
if (!writable)
|
|
||||||
throw new MessagingException("Message is read-only");
|
|
||||||
|
|
||||||
super.saveChanges();
|
|
||||||
|
|
||||||
try {
|
|
||||||
/*
|
|
||||||
* Count the size of the body, in order to set the Content-Length
|
|
||||||
* header. (Should we only do this to update an existing
|
|
||||||
* Content-Length header?)
|
|
||||||
* XXX - We could cache the content bytes here, for use later
|
|
||||||
* in writeTo.
|
|
||||||
*/
|
|
||||||
ContentLengthCounter cos = new ContentLengthCounter();
|
|
||||||
OutputStream os = new NewlineOutputStream(cos);
|
|
||||||
super.writeTo(os);
|
|
||||||
os.flush();
|
|
||||||
setHeader("Content-Length", String.valueOf(cos.getSize()));
|
|
||||||
// setContentSize((int)cos.getSize());
|
|
||||||
} catch (MessagingException e) {
|
|
||||||
throw e;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new MessagingException("unexpected exception " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expose modified flag to MboxFolder.
|
|
||||||
*/
|
|
||||||
boolean isModified() {
|
|
||||||
return modified;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Put out a byte stream suitable for saving to a file.
|
|
||||||
* XXX - ultimately implement "ignore headers" here?
|
|
||||||
*/
|
|
||||||
public void writeToFile(OutputStream os) throws IOException {
|
|
||||||
try {
|
|
||||||
if (getHeader("Content-Length") == null) {
|
|
||||||
/*
|
|
||||||
* Count the size of the body, in order to set the
|
|
||||||
* Content-Length header.
|
|
||||||
*/
|
|
||||||
ContentLengthCounter cos = new ContentLengthCounter();
|
|
||||||
OutputStream oos = new NewlineOutputStream(cos);
|
|
||||||
super.writeTo(oos, null);
|
|
||||||
oos.flush();
|
|
||||||
setHeader("Content-Length", String.valueOf(cos.getSize()));
|
|
||||||
// setContentSize((int)cos.getSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
os = new NewlineOutputStream(os, true);
|
|
||||||
PrintStream pos = new PrintStream(os, false, "iso-8859-1");
|
|
||||||
|
|
||||||
pos.println(getUnixFromLine());
|
|
||||||
super.writeTo(pos, null);
|
|
||||||
pos.flush();
|
|
||||||
} catch (MessagingException e) {
|
|
||||||
throw new IOException("unexpected exception " + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeTo(OutputStream os, String[] ignoreList)
|
|
||||||
throws IOException, MessagingException {
|
|
||||||
// set the SEEN flag now, which will normally be set by
|
|
||||||
// getContentStream, so it will show up in our headers
|
|
||||||
if (!isSet(Flags.Flag.SEEN))
|
|
||||||
setFlag(Flags.Flag.SEEN, true);
|
|
||||||
super.writeTo(os, ignoreList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interpose on superclass method to make sure folder is still open
|
|
||||||
* and message hasn't been expunged.
|
|
||||||
*/
|
|
||||||
public String[] getHeader(String name)
|
|
||||||
throws MessagingException {
|
|
||||||
if (folder != null)
|
|
||||||
((MboxFolder)folder).checkOpen();
|
|
||||||
if (isExpunged())
|
|
||||||
throw new MessageRemovedException("mbox message expunged");
|
|
||||||
return super.getHeader(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Interpose on superclass method to make sure folder is still open
|
|
||||||
* and message hasn't been expunged.
|
|
||||||
*/
|
|
||||||
public String getHeader(String name, String delimiter)
|
|
||||||
throws MessagingException {
|
|
||||||
if (folder != null)
|
|
||||||
((MboxFolder)folder).checkOpen();
|
|
||||||
if (isExpunged())
|
|
||||||
throw new MessageRemovedException("mbox message expunged");
|
|
||||||
return super.getHeader(name, delimiter);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import javax.mail.Provider;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Mbox protocol provider.
|
|
||||||
*/
|
|
||||||
public class MboxProvider extends Provider {
|
|
||||||
public MboxProvider() {
|
|
||||||
super(Provider.Type.STORE, "mbox", MboxStore.class.getName(),
|
|
||||||
"Oracle", null);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,113 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import javax.mail.*;
|
|
||||||
|
|
||||||
public class MboxStore extends Store {
|
|
||||||
|
|
||||||
String user;
|
|
||||||
String home;
|
|
||||||
Mailbox mb;
|
|
||||||
static Flags permFlags;
|
|
||||||
|
|
||||||
static {
|
|
||||||
// we support all flags
|
|
||||||
permFlags = new Flags();
|
|
||||||
permFlags.add(Flags.Flag.SEEN);
|
|
||||||
permFlags.add(Flags.Flag.RECENT);
|
|
||||||
permFlags.add(Flags.Flag.DELETED);
|
|
||||||
permFlags.add(Flags.Flag.FLAGGED);
|
|
||||||
permFlags.add(Flags.Flag.ANSWERED);
|
|
||||||
permFlags.add(Flags.Flag.DRAFT);
|
|
||||||
permFlags.add(Flags.Flag.USER);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MboxStore(Session session, URLName url) {
|
|
||||||
super(session, url);
|
|
||||||
|
|
||||||
// XXX - handle security exception
|
|
||||||
user = System.getProperty("user.name");
|
|
||||||
home = System.getProperty("user.home");
|
|
||||||
String os = System.getProperty("os.name");
|
|
||||||
try {
|
|
||||||
String cl = "com.sun.mail.mbox." + os + "Mailbox";
|
|
||||||
mb = (Mailbox)Class.forName(cl).
|
|
||||||
getDeclaredConstructor().newInstance();
|
|
||||||
} catch (Exception e) {
|
|
||||||
mb = new DefaultMailbox();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Since we do not have any authentication
|
|
||||||
* to do and we do not want a dialog put up asking the user for a
|
|
||||||
* password we always succeed in connecting.
|
|
||||||
* But if we're given a password, that means the user is
|
|
||||||
* doing something wrong so fail the request.
|
|
||||||
*/
|
|
||||||
protected boolean protocolConnect(String host, int port, String user,
|
|
||||||
String passwd) throws MessagingException {
|
|
||||||
|
|
||||||
if (passwd != null)
|
|
||||||
throw new AuthenticationFailedException(
|
|
||||||
"mbox does not allow passwords");
|
|
||||||
// XXX - should we use the user?
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void setURLName(URLName url) {
|
|
||||||
// host, user, password, and file don't matter so we strip them out
|
|
||||||
if (url != null && (url.getUsername() != null ||
|
|
||||||
url.getHost() != null ||
|
|
||||||
url.getFile() != null))
|
|
||||||
url = new URLName(url.getProtocol(), null, -1, null, null, null);
|
|
||||||
super.setURLName(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public Folder getDefaultFolder() throws MessagingException {
|
|
||||||
checkConnected();
|
|
||||||
|
|
||||||
return new MboxFolder(this, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Folder getFolder(String name) throws MessagingException {
|
|
||||||
checkConnected();
|
|
||||||
|
|
||||||
return new MboxFolder(this, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Folder getFolder(URLName url) throws MessagingException {
|
|
||||||
checkConnected();
|
|
||||||
return getFolder(url.getFile());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkConnected() throws MessagingException {
|
|
||||||
if (!isConnected())
|
|
||||||
throw new MessagingException("Not connected");
|
|
||||||
}
|
|
||||||
|
|
||||||
MailFile getMailFile(String folder) {
|
|
||||||
return mb.getMailFile(user, folder);
|
|
||||||
}
|
|
||||||
|
|
||||||
Session getSession() {
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,285 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A support class that contains the state and logic needed when
|
|
||||||
* loading messages from a folder.
|
|
||||||
*/
|
|
||||||
final class MessageLoader {
|
|
||||||
private final TempFile temp;
|
|
||||||
private FileInputStream fis = null;
|
|
||||||
private OutputStream fos = null;
|
|
||||||
private int pos, len; // position in and length of buffer
|
|
||||||
private long off; // current offset in temp file
|
|
||||||
private long prevend; // the end of the previous message in temp file
|
|
||||||
private MboxFolder.MessageMetadata md;
|
|
||||||
private byte[] buf = null;
|
|
||||||
// the length of the longest header we'll need to look at
|
|
||||||
private static final int LINELEN = "Content-Length: XXXXXXXXXX".length();
|
|
||||||
private char[] line;
|
|
||||||
|
|
||||||
public MessageLoader(TempFile temp) {
|
|
||||||
this.temp = temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load messages from the given file descriptor, starting at the
|
|
||||||
* specified offset, adding the MessageMetadata to the list. <p>
|
|
||||||
*
|
|
||||||
* The data is assumed to be in UNIX mbox format, with newlines
|
|
||||||
* only as the line terminators.
|
|
||||||
*/
|
|
||||||
public int load(FileDescriptor fd, long offset,
|
|
||||||
List<MboxFolder.MessageMetadata> msgs)
|
|
||||||
throws IOException {
|
|
||||||
// XXX - could allocate and deallocate buffers here
|
|
||||||
int loaded = 0;
|
|
||||||
try {
|
|
||||||
fis = new FileInputStream(fd);
|
|
||||||
if (fis.skip(offset) != offset)
|
|
||||||
throw new EOFException("Failed to skip to offset " + offset);
|
|
||||||
this.off = prevend = temp.length();
|
|
||||||
pos = len = 0;
|
|
||||||
line = new char[LINELEN];
|
|
||||||
buf = new byte[64 * 1024];
|
|
||||||
fos = temp.getAppendStream();
|
|
||||||
int n;
|
|
||||||
// keep loading messages as long as we have headers
|
|
||||||
while ((n = skipHeader(loaded == 0)) >= 0) {
|
|
||||||
long start;
|
|
||||||
if (n == 0) {
|
|
||||||
// didn't find a Content-Length, skip the body
|
|
||||||
start = skipBody();
|
|
||||||
if (start < 0) {
|
|
||||||
// md.end = -1;
|
|
||||||
md.dataend = -1;
|
|
||||||
msgs.add(md);
|
|
||||||
loaded++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
md.dataend = start;
|
|
||||||
} else {
|
|
||||||
// skip over the body
|
|
||||||
skip(n);
|
|
||||||
md.dataend = off;
|
|
||||||
int b;
|
|
||||||
// skip any blank lines after the body
|
|
||||||
while ((b = get()) >= 0) {
|
|
||||||
if (b != '\n')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
start = off;
|
|
||||||
if (b >= 0)
|
|
||||||
start--; // back up one byte if not at EOF
|
|
||||||
}
|
|
||||||
// md.end = start;
|
|
||||||
prevend = start;
|
|
||||||
msgs.add(md);
|
|
||||||
loaded++;
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
fis.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
fos.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
line = null;
|
|
||||||
buf = null;
|
|
||||||
}
|
|
||||||
return loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skip over the message header, returning the content length
|
|
||||||
* of the body, or 0 if no Content-Length header was seen.
|
|
||||||
* Update the MessageMetadata based on the headers seen.
|
|
||||||
* return -1 on EOF.
|
|
||||||
*/
|
|
||||||
private int skipHeader(boolean first) throws IOException {
|
|
||||||
int clen = 0;
|
|
||||||
boolean bol = true;
|
|
||||||
int lpos = -1;
|
|
||||||
int b;
|
|
||||||
boolean saw_unix_from = false;
|
|
||||||
int lineno = 0;
|
|
||||||
md = new MboxFolder.MessageMetadata();
|
|
||||||
md.start = prevend;
|
|
||||||
md.recent = true;
|
|
||||||
while ((b = get()) >= 0) {
|
|
||||||
if (bol) {
|
|
||||||
if (b == '\n')
|
|
||||||
break;
|
|
||||||
lpos = 0;
|
|
||||||
}
|
|
||||||
if (b == '\n') {
|
|
||||||
bol = true;
|
|
||||||
lineno++;
|
|
||||||
// newline at end of line, was the line one of the headers
|
|
||||||
// we're looking for?
|
|
||||||
if (lpos > 7) {
|
|
||||||
// XXX - make this more efficient?
|
|
||||||
String s = new String(line, 0, lpos);
|
|
||||||
// fast check for Content-Length header
|
|
||||||
if (lineno == 1 && line[0] == 'F' && isPrefix(s, "From ")) {
|
|
||||||
saw_unix_from = true;
|
|
||||||
} else if (line[7] == '-' &&
|
|
||||||
isPrefix(s, "Content-Length:")) {
|
|
||||||
s = s.substring(15).trim();
|
|
||||||
try {
|
|
||||||
clen = Integer.parseInt(s);
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
// ignore it
|
|
||||||
}
|
|
||||||
// fast check for Status header
|
|
||||||
} else if ((line[1] == 't' || line[1] == 'T') &&
|
|
||||||
isPrefix(s, "Status:")) {
|
|
||||||
if (s.indexOf('O') >= 0)
|
|
||||||
md.recent = false;
|
|
||||||
// fast check for X-Status header
|
|
||||||
} else if ((line[3] == 't' || line[3] == 'T') &&
|
|
||||||
isPrefix(s, "X-Status:")) {
|
|
||||||
if (s.indexOf('D') >= 0)
|
|
||||||
md.deleted = true;
|
|
||||||
// fast check for X-Dt-Delete-Time header
|
|
||||||
} else if (line[4] == '-' &&
|
|
||||||
isPrefix(s, "X-Dt-Delete-Time:")) {
|
|
||||||
md.deleted = true;
|
|
||||||
// fast check for X-IMAP header
|
|
||||||
} else if (line[5] == 'P' && s.startsWith("X-IMAP:")) {
|
|
||||||
md.imap = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// accumlate data in line buffer
|
|
||||||
bol = false;
|
|
||||||
if (lpos < 0) // ignoring this line
|
|
||||||
continue;
|
|
||||||
if (lpos == 0 && (b == ' ' || b == '\t'))
|
|
||||||
lpos = -1; // ignore continuation lines
|
|
||||||
else if (lpos < line.length)
|
|
||||||
line[lpos++] = (char)b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we hit EOF, or this is the first message we're loading and
|
|
||||||
// it doesn't have a UNIX From line, return EOF.
|
|
||||||
// (After the first message, UNIX From lines are seen by skipBody
|
|
||||||
// to terminate the message.)
|
|
||||||
if (b < 0 || (first && !saw_unix_from))
|
|
||||||
return -1;
|
|
||||||
else
|
|
||||||
return clen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Does "s" start with "pre", ignoring case?
|
|
||||||
*/
|
|
||||||
private static final boolean isPrefix(String s, String pre) {
|
|
||||||
return s.regionMatches(true, 0, pre, 0, pre.length());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skip over the body of the message looking for a line that starts
|
|
||||||
* with "From ". If found, return the offset of the beginning of
|
|
||||||
* that line. Return -1 on EOF.
|
|
||||||
*/
|
|
||||||
private long skipBody() throws IOException {
|
|
||||||
boolean bol = true;
|
|
||||||
int lpos = -1;
|
|
||||||
long loff = off;
|
|
||||||
int b;
|
|
||||||
while ((b = get()) >= 0) {
|
|
||||||
if (bol) {
|
|
||||||
lpos = 0;
|
|
||||||
loff = off - 1;
|
|
||||||
}
|
|
||||||
if (b == '\n') {
|
|
||||||
bol = true;
|
|
||||||
if (lpos >= 5) { // have enough data to test?
|
|
||||||
if (line[0] == 'F' && line[1] == 'r' && line[2] == 'o' &&
|
|
||||||
line[3] == 'm' && line[4] == ' ')
|
|
||||||
return loff;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
bol = false;
|
|
||||||
if (lpos < 0)
|
|
||||||
continue;
|
|
||||||
if (lpos == 0 && b != 'F')
|
|
||||||
lpos = -1; // ignore lines that don't start with F
|
|
||||||
else if (lpos < 5) // only need first 5 chars to test
|
|
||||||
line[lpos++] = (char)b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Skip "n" bytes, returning how much we were able to skip.
|
|
||||||
*/
|
|
||||||
private final int skip(int n) throws IOException {
|
|
||||||
int n0 = n;
|
|
||||||
if (pos + n < len) {
|
|
||||||
pos += n; // can do it all within this buffer
|
|
||||||
off += n;
|
|
||||||
} else {
|
|
||||||
do {
|
|
||||||
n -= (len - pos); // skip rest of this buffer
|
|
||||||
off += (len - pos);
|
|
||||||
fill();
|
|
||||||
if (len <= 0) // ran out of data
|
|
||||||
return n0 - n;
|
|
||||||
} while (n > len);
|
|
||||||
pos += n;
|
|
||||||
off += n;
|
|
||||||
}
|
|
||||||
return n0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the next byte.
|
|
||||||
*/
|
|
||||||
private final int get() throws IOException {
|
|
||||||
if (pos >= len)
|
|
||||||
fill();
|
|
||||||
if (pos >= len)
|
|
||||||
return -1;
|
|
||||||
else {
|
|
||||||
off++;
|
|
||||||
return buf[pos++] & 0xff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Fill our buffer with more data.
|
|
||||||
* Every buffer we read is also written to the temp file.
|
|
||||||
*/
|
|
||||||
private final void fill() throws IOException {
|
|
||||||
len = fis.read(buf);
|
|
||||||
pos = 0;
|
|
||||||
if (len > 0)
|
|
||||||
fos.write(buf, 0, len);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert the various newline conventions to the local platform's
|
|
||||||
* newline convention. Optionally, make sure the output ends with
|
|
||||||
* a blank line.
|
|
||||||
*/
|
|
||||||
public class NewlineOutputStream extends FilterOutputStream {
|
|
||||||
private int lastb = -1;
|
|
||||||
private int bol = 1; // number of times in a row we're at beginning of line
|
|
||||||
private final boolean endWithBlankLine;
|
|
||||||
private static final byte[] newline;
|
|
||||||
|
|
||||||
static {
|
|
||||||
String s = null;
|
|
||||||
try {
|
|
||||||
s = System.lineSeparator();
|
|
||||||
} catch (SecurityException sex) {
|
|
||||||
// ignore, should never happen
|
|
||||||
}
|
|
||||||
if (s == null || s.length() <= 0)
|
|
||||||
s = "\n";
|
|
||||||
newline = s.getBytes(StandardCharsets.ISO_8859_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NewlineOutputStream(OutputStream os) {
|
|
||||||
this(os, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public NewlineOutputStream(OutputStream os, boolean endWithBlankLine) {
|
|
||||||
super(os);
|
|
||||||
this.endWithBlankLine = endWithBlankLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
if (b == '\r') {
|
|
||||||
out.write(newline);
|
|
||||||
bol++;
|
|
||||||
} else if (b == '\n') {
|
|
||||||
if (lastb != '\r') {
|
|
||||||
out.write(newline);
|
|
||||||
bol++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
out.write(b);
|
|
||||||
bol = 0; // no longer at beginning of line
|
|
||||||
}
|
|
||||||
lastb = b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte b[]) throws IOException {
|
|
||||||
write(b, 0, b.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte b[], int off, int len) throws IOException {
|
|
||||||
for (int i = 0 ; i < len ; i++) {
|
|
||||||
write(b[off + i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() throws IOException {
|
|
||||||
if (endWithBlankLine) {
|
|
||||||
if (bol == 0) {
|
|
||||||
// not at bol, return to bol and add a blank line
|
|
||||||
out.write(newline);
|
|
||||||
out.write(newline);
|
|
||||||
} else if (bol == 1) {
|
|
||||||
// at bol, add a blank line
|
|
||||||
out.write(newline);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bol = 2;
|
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,81 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public class SolarisMailbox extends Mailbox {
|
|
||||||
private final String home;
|
|
||||||
private final String user;
|
|
||||||
|
|
||||||
private static final boolean homeRelative =
|
|
||||||
Boolean.getBoolean("mail.mbox.homerelative");
|
|
||||||
|
|
||||||
public SolarisMailbox() {
|
|
||||||
String h = System.getenv("HOME");
|
|
||||||
if (h == null)
|
|
||||||
h = System.getProperty("user.home");
|
|
||||||
home = h;
|
|
||||||
user = System.getProperty("user.name");
|
|
||||||
}
|
|
||||||
|
|
||||||
public MailFile getMailFile(String user, String folder) {
|
|
||||||
if (folder.equalsIgnoreCase("INBOX"))
|
|
||||||
return new UNIXInbox(user, filename(user, folder));
|
|
||||||
else
|
|
||||||
return new UNIXFolder(filename(user, folder));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a name of a mailbox folder, expand it to a full path name.
|
|
||||||
*/
|
|
||||||
public String filename(String user, String folder) {
|
|
||||||
try {
|
|
||||||
switch (folder.charAt(0)) {
|
|
||||||
case '/':
|
|
||||||
return folder;
|
|
||||||
case '~':
|
|
||||||
int i = folder.indexOf(File.separatorChar);
|
|
||||||
String tail = "";
|
|
||||||
if (i > 0) {
|
|
||||||
tail = folder.substring(i);
|
|
||||||
folder = folder.substring(0, i);
|
|
||||||
}
|
|
||||||
if (folder.length() == 1)
|
|
||||||
return home + tail;
|
|
||||||
else
|
|
||||||
return "/home/" + folder.substring(1) + tail; // XXX
|
|
||||||
default:
|
|
||||||
if (folder.equalsIgnoreCase("INBOX")) {
|
|
||||||
if (user == null) // XXX - should never happen
|
|
||||||
user = this.user;
|
|
||||||
String inbox = System.getenv("MAIL");
|
|
||||||
if (inbox == null)
|
|
||||||
inbox = "/var/mail/" + user;
|
|
||||||
return inbox;
|
|
||||||
} else {
|
|
||||||
if (homeRelative)
|
|
||||||
return home + File.separator + folder;
|
|
||||||
else
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (StringIndexOutOfBoundsException e) {
|
|
||||||
return folder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
public class SunOSMailbox extends SolarisMailbox {
|
|
||||||
}
|
|
@ -1,314 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import javax.mail.*;
|
|
||||||
import javax.mail.internet.*;
|
|
||||||
import javax.activation.*;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This class represents a SunV3 BodyPart.
|
|
||||||
*
|
|
||||||
* @author Bill Shannon
|
|
||||||
* @see javax.mail.Part
|
|
||||||
* @see javax.mail.internet.MimePart
|
|
||||||
* @see javax.mail.internet.MimeBodyPart
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class SunV3BodyPart extends MimeBodyPart {
|
|
||||||
/**
|
|
||||||
* Constructs a SunV3BodyPart using the given header and
|
|
||||||
* content bytes. <p>
|
|
||||||
*
|
|
||||||
* Used by providers.
|
|
||||||
*
|
|
||||||
* @param headers The header of this part
|
|
||||||
* @param content bytes representing the body of this part.
|
|
||||||
*/
|
|
||||||
public SunV3BodyPart(InternetHeaders headers, byte[] content)
|
|
||||||
throws MessagingException {
|
|
||||||
super(headers, content);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the size of the content of this BodyPart in bytes.
|
|
||||||
* Return -1 if the size cannot be determined. <p>
|
|
||||||
*
|
|
||||||
* Note that this number may not be an exact measure of the
|
|
||||||
* content size and may or may not account for any transfer
|
|
||||||
* encoding of the content. <p>
|
|
||||||
*
|
|
||||||
* @return size in bytes
|
|
||||||
*/
|
|
||||||
public int getSize() throws MessagingException {
|
|
||||||
String s = getHeader("X-Sun-Content-Length", null);
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(s);
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the number of lines for the content of this Part.
|
|
||||||
* Return -1 if this number cannot be determined. <p>
|
|
||||||
*
|
|
||||||
* Note that this number may not be an exact measure of the
|
|
||||||
* content length and may or may not account for any transfer
|
|
||||||
* encoding of the content.
|
|
||||||
*/
|
|
||||||
public int getLineCount() throws MessagingException {
|
|
||||||
String s = getHeader("X-Sun-Content-Lines", null);
|
|
||||||
try {
|
|
||||||
return Integer.parseInt(s);
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is just enough to get us going.
|
|
||||||
*
|
|
||||||
* For more complete transformation from V3 to MIME, refer to
|
|
||||||
* sun_att.c from the Sun IMAP server code.
|
|
||||||
*/
|
|
||||||
static class MimeV3Map {
|
|
||||||
String mime;
|
|
||||||
String v3;
|
|
||||||
|
|
||||||
MimeV3Map(String mime, String v3) {
|
|
||||||
this.mime = mime;
|
|
||||||
this.v3 = v3;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MimeV3Map[] mimeV3Table = new MimeV3Map[] {
|
|
||||||
new MimeV3Map("text/plain", "text"),
|
|
||||||
new MimeV3Map("text/plain", "default"),
|
|
||||||
new MimeV3Map("multipart/x-sun-attachment", "X-sun-attachment"),
|
|
||||||
new MimeV3Map("application/postscript", "postscript-file"),
|
|
||||||
new MimeV3Map("image/gif", "gif-file")
|
|
||||||
// audio-file
|
|
||||||
// cshell-script
|
|
||||||
};
|
|
||||||
|
|
||||||
// V3 Content-Type to MIME Content-Type
|
|
||||||
static String toMime(String s) {
|
|
||||||
for (int i = 0; i < mimeV3Table.length; i++) {
|
|
||||||
if (mimeV3Table[i].v3.equalsIgnoreCase(s))
|
|
||||||
return mimeV3Table[i].mime;
|
|
||||||
}
|
|
||||||
return "application/x-" + s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// MIME Content-Type to V3 Content-Type
|
|
||||||
static String toV3(String s) {
|
|
||||||
for (int i = 0; i < mimeV3Table.length; i++) {
|
|
||||||
if (mimeV3Table[i].mime.equalsIgnoreCase(s))
|
|
||||||
return mimeV3Table[i].v3;
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the RFC822 "Content-Type" header field.
|
|
||||||
* This represents the content-type of the content of this
|
|
||||||
* BodyPart. This value must not be null. If this field is
|
|
||||||
* unavailable, "text/plain" should be returned. <p>
|
|
||||||
*
|
|
||||||
* This implementation uses <code>getHeader(name)</code>
|
|
||||||
* to obtain the requisite header field.
|
|
||||||
*
|
|
||||||
* @return Content-Type of this BodyPart
|
|
||||||
*/
|
|
||||||
public String getContentType() throws MessagingException {
|
|
||||||
String ct = getHeader("Content-Type", null);
|
|
||||||
if (ct == null)
|
|
||||||
ct = getHeader("X-Sun-Data-Type", null);
|
|
||||||
if (ct == null)
|
|
||||||
ct = "text/plain";
|
|
||||||
else if (ct.indexOf('/') < 0)
|
|
||||||
ct = MimeV3Map.toMime(ct);
|
|
||||||
return ct;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the value of the "Content-Transfer-Encoding" header
|
|
||||||
* field. Returns <code>null</code> if the header is unavailable
|
|
||||||
* or its value is absent. <p>
|
|
||||||
*
|
|
||||||
* This implementation uses <code>getHeader(name)</code>
|
|
||||||
* to obtain the requisite header field.
|
|
||||||
*
|
|
||||||
* @see #headers
|
|
||||||
*/
|
|
||||||
public String getEncoding() throws MessagingException {
|
|
||||||
String enc = super.getEncoding();
|
|
||||||
if (enc == null)
|
|
||||||
enc = getHeader("X-Sun-Encoding-Info", null);
|
|
||||||
return enc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the "Content-Description" header field of this BodyPart.
|
|
||||||
* This typically associates some descriptive information with
|
|
||||||
* this part. Returns null if this field is unavailable or its
|
|
||||||
* value is absent. <p>
|
|
||||||
*
|
|
||||||
* If the Content-Description field is encoded as per RFC 2047,
|
|
||||||
* it is decoded and converted into Unicode. If the decoding or
|
|
||||||
* conversion fails, the raw data is returned as-is <p>
|
|
||||||
*
|
|
||||||
* This implementation uses <code>getHeader(name)</code>
|
|
||||||
* to obtain the requisite header field.
|
|
||||||
*
|
|
||||||
* @return content-description
|
|
||||||
*/
|
|
||||||
public String getDescription() throws MessagingException {
|
|
||||||
String desc = super.getDescription();
|
|
||||||
if (desc == null)
|
|
||||||
desc = getHeader("X-Sun-Data-Description", null);
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the "Content-Description" header field for this BodyPart.
|
|
||||||
* If the description parameter is <code>null</code>, then any
|
|
||||||
* existing "Content-Description" fields are removed. <p>
|
|
||||||
*
|
|
||||||
* If the description contains non US-ASCII characters, it will
|
|
||||||
* be encoded using the platform's default charset. If the
|
|
||||||
* description contains only US-ASCII characters, no encoding
|
|
||||||
* is done and it is used as-is.
|
|
||||||
*
|
|
||||||
* @param description content-description
|
|
||||||
* @exception IllegalWriteException if the underlying
|
|
||||||
* implementation does not support modification
|
|
||||||
* @exception IllegalStateException if this BodyPart is
|
|
||||||
* obtained from a READ_ONLY folder.
|
|
||||||
*/
|
|
||||||
public void setDescription(String description) throws MessagingException {
|
|
||||||
throw new MethodNotSupportedException("SunV3BodyPart not writable");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the "Content-Description" header field for this BodyPart.
|
|
||||||
* If the description parameter is <code>null</code>, then any
|
|
||||||
* existing "Content-Description" fields are removed. <p>
|
|
||||||
*
|
|
||||||
* If the description contains non US-ASCII characters, it will
|
|
||||||
* be encoded using the specified charset. If the description
|
|
||||||
* contains only US-ASCII characters, no encoding is done and
|
|
||||||
* it is used as-is
|
|
||||||
*
|
|
||||||
* @param description Description
|
|
||||||
* @param charset Charset for encoding
|
|
||||||
* @exception IllegalWriteException if the underlying
|
|
||||||
* implementation does not support modification
|
|
||||||
* @exception IllegalStateException if this BodyPart is
|
|
||||||
* obtained from a READ_ONLY folder.
|
|
||||||
*/
|
|
||||||
public void setDescription(String description, String charset)
|
|
||||||
throws MessagingException {
|
|
||||||
throw new MethodNotSupportedException("SunV3BodyPart not writable");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the filename associated with this BodyPart. <p>
|
|
||||||
*
|
|
||||||
* Returns the value of the "filename" parameter from the
|
|
||||||
* "Content-Disposition" header field of this BodyPart. If its
|
|
||||||
* not available, returns the value of the "name" parameter from
|
|
||||||
* the "Content-Type" header field of this BodyPart.
|
|
||||||
* Returns <code>null</code> if both are absent.
|
|
||||||
*
|
|
||||||
* @return filename
|
|
||||||
*/
|
|
||||||
public String getFileName() throws MessagingException {
|
|
||||||
String name = super.getFileName();
|
|
||||||
if (name == null)
|
|
||||||
name = getHeader("X-Sun-Data-Name", null);
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the filename associated with this BodyPart, if possible. <p>
|
|
||||||
*
|
|
||||||
* Sets the "filename" parameter of the "Content-Disposition"
|
|
||||||
* header field of this BodyPart.
|
|
||||||
*
|
|
||||||
* @exception IllegalWriteException if the underlying
|
|
||||||
* implementation does not support modification
|
|
||||||
* @exception IllegalStateException if this BodyPart is
|
|
||||||
* obtained from a READ_ONLY folder.
|
|
||||||
*/
|
|
||||||
public void setFileName(String filename) throws MessagingException {
|
|
||||||
throw new MethodNotSupportedException("SunV3BodyPart not writable");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method provides the mechanism to set this BodyPart's content.
|
|
||||||
* The given DataHandler object should wrap the actual content.
|
|
||||||
*
|
|
||||||
* @param dh The DataHandler for the content
|
|
||||||
* @exception IllegalWriteException if the underlying
|
|
||||||
* implementation does not support modification
|
|
||||||
* @exception IllegalStateException if this BodyPart is
|
|
||||||
* obtained from a READ_ONLY folder.
|
|
||||||
*/
|
|
||||||
public void setDataHandler(DataHandler dh)
|
|
||||||
throws MessagingException {
|
|
||||||
throw new MethodNotSupportedException("SunV3BodyPart not writable");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Output the BodyPart as a RFC822 format stream.
|
|
||||||
*
|
|
||||||
* @exception MessagingException
|
|
||||||
* @exception IOException if an error occurs writing to the
|
|
||||||
* stream or if an error is generated
|
|
||||||
* by the javax.activation layer.
|
|
||||||
* @see javax.activation.DataHandler#writeTo()
|
|
||||||
*/
|
|
||||||
public void writeTo(OutputStream os)
|
|
||||||
throws IOException, MessagingException {
|
|
||||||
throw new MethodNotSupportedException("SunV3BodyPart writeTo");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the method that has the 'smarts' to query the 'content'
|
|
||||||
* and update the appropriate headers. Typical headers that get
|
|
||||||
* set here are: Content-Type, Content-Encoding, boundary (for
|
|
||||||
* multipart). Now, the tricky part here is when to actually
|
|
||||||
* activate this method:
|
|
||||||
*
|
|
||||||
* - A Message being crafted by a mail-application will certainly
|
|
||||||
* need to activate this method at some point to fill up its internal
|
|
||||||
* headers. Typically this is triggered off by our writeTo() method.
|
|
||||||
*
|
|
||||||
* - A message read-in from a MessageStore will have obtained
|
|
||||||
* all its headers from the store, and so does'nt need this.
|
|
||||||
* However, if this message is editable and if any edits have
|
|
||||||
* been made to either the content or message-structure, we might
|
|
||||||
* need to resync our headers. Typically this is triggered off by
|
|
||||||
* the Message.saveChanges() methods.
|
|
||||||
*/
|
|
||||||
protected void updateHeaders() throws MessagingException {
|
|
||||||
throw new MethodNotSupportedException("SunV3BodyPart updateHeaders");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,201 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import javax.mail.*;
|
|
||||||
import javax.mail.internet.*;
|
|
||||||
import javax.activation.*;
|
|
||||||
import java.util.*;
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import com.sun.mail.util.LineInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The SunV3Multipart class is an implementation of the abstract Multipart
|
|
||||||
* class that uses SunV3 conventions for the multipart data. <p>
|
|
||||||
*
|
|
||||||
* @author Bill Shannon
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class SunV3Multipart extends MimeMultipart {
|
|
||||||
private boolean parsing;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a SunV3Multipart object and its bodyparts from the
|
|
||||||
* given DataSource. <p>
|
|
||||||
*
|
|
||||||
* @param ds DataSource, can be a MultipartDataSource
|
|
||||||
*/
|
|
||||||
public SunV3Multipart(DataSource ds) throws MessagingException {
|
|
||||||
super(ds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the subtype. Throws MethodNotSupportedException.
|
|
||||||
*
|
|
||||||
* @param subtype Subtype
|
|
||||||
*/
|
|
||||||
public void setSubType(String subtype) throws MessagingException {
|
|
||||||
throw new MethodNotSupportedException(
|
|
||||||
"can't change SunV3Multipart subtype");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the BodyPart referred to by the given ContentID (CID).
|
|
||||||
* Throws MethodNotSupportException.
|
|
||||||
*/
|
|
||||||
public synchronized BodyPart getBodyPart(String CID)
|
|
||||||
throws MessagingException {
|
|
||||||
throw new MethodNotSupportedException(
|
|
||||||
"SunV3Multipart doesn't support Content-ID");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update headers. Throws MethodNotSupportException.
|
|
||||||
*/
|
|
||||||
protected void updateHeaders() throws MessagingException {
|
|
||||||
throw new MethodNotSupportedException("SunV3Multipart not writable");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterates through all the parts and outputs each SunV3 part
|
|
||||||
* separated by a boundary.
|
|
||||||
*/
|
|
||||||
public void writeTo(OutputStream os)
|
|
||||||
throws IOException, MessagingException {
|
|
||||||
throw new MethodNotSupportedException(
|
|
||||||
"SunV3Multipart writeTo not supported");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final String boundary = "----------";
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse the contents of this multipart message and create the
|
|
||||||
* child body parts.
|
|
||||||
*/
|
|
||||||
protected synchronized void parse() throws MessagingException {
|
|
||||||
/*
|
|
||||||
* If the data has already been parsed, or we're in the middle of
|
|
||||||
* parsing it, there's nothing to do. The latter will occur when
|
|
||||||
* we call addBodyPart, which will call parse again. We really
|
|
||||||
* want to be able to call super.super.addBodyPart.
|
|
||||||
*/
|
|
||||||
if (parsed || parsing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
InputStream in = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
in = ds.getInputStream();
|
|
||||||
if (!(in instanceof ByteArrayInputStream) &&
|
|
||||||
!(in instanceof BufferedInputStream))
|
|
||||||
in = new BufferedInputStream(in);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
throw new MessagingException("No inputstream from datasource");
|
|
||||||
} catch (RuntimeException ex) {
|
|
||||||
throw new MessagingException("No inputstream from datasource");
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bndbytes = boundary.getBytes(StandardCharsets.ISO_8859_1);
|
|
||||||
int bl = bndbytes.length;
|
|
||||||
|
|
||||||
String line;
|
|
||||||
parsing = true;
|
|
||||||
try {
|
|
||||||
/*
|
|
||||||
* Skip any kind of junk until we get to the first
|
|
||||||
* boundary line.
|
|
||||||
*/
|
|
||||||
LineInputStream lin = new LineInputStream(in);
|
|
||||||
while ((line = lin.readLine()) != null) {
|
|
||||||
if (line.trim().equals(boundary))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (line == null)
|
|
||||||
throw new MessagingException("Missing start boundary");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read and process body parts until we see the
|
|
||||||
* terminating boundary line (or EOF).
|
|
||||||
*/
|
|
||||||
for (;;) {
|
|
||||||
/*
|
|
||||||
* Collect the headers for this body part.
|
|
||||||
*/
|
|
||||||
InternetHeaders headers = new InternetHeaders(in);
|
|
||||||
|
|
||||||
if (!in.markSupported())
|
|
||||||
throw new MessagingException("Stream doesn't support mark");
|
|
||||||
|
|
||||||
ByteArrayOutputStream buf = new ByteArrayOutputStream();
|
|
||||||
int b;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read and save the content bytes in buf.
|
|
||||||
*/
|
|
||||||
while ((b = in.read()) >= 0) {
|
|
||||||
if (b == '\r' || b == '\n') {
|
|
||||||
/*
|
|
||||||
* Found the end of a line, check whether the
|
|
||||||
* next line is a boundary.
|
|
||||||
*/
|
|
||||||
int i;
|
|
||||||
in.mark(bl + 4 + 1); // "4" for possible "--\r\n"
|
|
||||||
if (b == '\r' && in.read() != '\n') {
|
|
||||||
in.reset();
|
|
||||||
in.mark(bl + 4);
|
|
||||||
}
|
|
||||||
// read bytes, matching against the boundary
|
|
||||||
for (i = 0; i < bl; i++)
|
|
||||||
if (in.read() != bndbytes[i])
|
|
||||||
break;
|
|
||||||
if (i == bl) {
|
|
||||||
int b2 = in.read();
|
|
||||||
// check for end of line
|
|
||||||
if (b2 == '\n')
|
|
||||||
break; // got it! break out of the while loop
|
|
||||||
if (b2 == '\r') {
|
|
||||||
in.mark(1);
|
|
||||||
if (in.read() != '\n')
|
|
||||||
in.reset();
|
|
||||||
break; // got it! break out of the while loop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// failed to match, reset and proceed normally
|
|
||||||
in.reset();
|
|
||||||
}
|
|
||||||
buf.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create a SunV3BodyPart to represent this body part.
|
|
||||||
*/
|
|
||||||
SunV3BodyPart body =
|
|
||||||
new SunV3BodyPart(headers, buf.toByteArray());
|
|
||||||
addBodyPart(body);
|
|
||||||
if (b < 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new MessagingException("IO Error"); // XXX
|
|
||||||
} finally {
|
|
||||||
parsing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed = true;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,183 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2010, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.net.*;
|
|
||||||
import java.io.*;
|
|
||||||
import java.security.*;
|
|
||||||
|
|
||||||
import com.sun.mail.util.PropUtil;
|
|
||||||
import javax.mail.util.SharedFileInputStream;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A temporary file used to cache messages.
|
|
||||||
*/
|
|
||||||
class TempFile {
|
|
||||||
|
|
||||||
private File file; // the temp file name
|
|
||||||
private WritableSharedFile sf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a temp file in the specified directory (if not null).
|
|
||||||
* The file will be deleted when the JVM exits.
|
|
||||||
*/
|
|
||||||
public TempFile(File dir) throws IOException {
|
|
||||||
file = File.createTempFile("mbox.", ".mbox", dir);
|
|
||||||
// XXX - need JDK 6 to set permissions on the file to owner-only
|
|
||||||
file.deleteOnExit();
|
|
||||||
sf = new WritableSharedFile(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a stream for appending to the temp file.
|
|
||||||
*/
|
|
||||||
public AppendStream getAppendStream() throws IOException {
|
|
||||||
return sf.getAppendStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a stream for reading from part of the file.
|
|
||||||
*/
|
|
||||||
public InputStream newStream(long start, long end) {
|
|
||||||
return sf.newStream(start, end);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long length() {
|
|
||||||
return file.length();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close and remove this temp file.
|
|
||||||
*/
|
|
||||||
public void close() {
|
|
||||||
try {
|
|
||||||
sf.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
// ignore it
|
|
||||||
}
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void finalize() throws Throwable {
|
|
||||||
try {
|
|
||||||
close();
|
|
||||||
} finally {
|
|
||||||
super.finalize();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A subclass of SharedFileInputStream that also allows writing.
|
|
||||||
*/
|
|
||||||
class WritableSharedFile extends SharedFileInputStream {
|
|
||||||
private RandomAccessFile raf;
|
|
||||||
private AppendStream af;
|
|
||||||
|
|
||||||
public WritableSharedFile(File file) throws IOException {
|
|
||||||
super(file);
|
|
||||||
try {
|
|
||||||
raf = new RandomAccessFile(file, "rw");
|
|
||||||
} catch (IOException ex) {
|
|
||||||
// if anything goes wrong opening the writable file,
|
|
||||||
// close the readable file too
|
|
||||||
super.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the writable version of this file.
|
|
||||||
*/
|
|
||||||
public RandomAccessFile getWritableFile() {
|
|
||||||
return raf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Close the readable and writable files.
|
|
||||||
*/
|
|
||||||
public void close() throws IOException {
|
|
||||||
try {
|
|
||||||
super.close();
|
|
||||||
} finally {
|
|
||||||
raf.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the size of the readable file after writing
|
|
||||||
* to the file. Updates the length to be the current
|
|
||||||
* size of the file.
|
|
||||||
*/
|
|
||||||
synchronized long updateLength() throws IOException {
|
|
||||||
datalen = in.length();
|
|
||||||
af = null;
|
|
||||||
return datalen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a new AppendStream, but only if one isn't in active use.
|
|
||||||
*/
|
|
||||||
public synchronized AppendStream getAppendStream() throws IOException {
|
|
||||||
if (af != null)
|
|
||||||
throw new IOException(
|
|
||||||
"file cache only supports single threaded access");
|
|
||||||
af = new AppendStream(this);
|
|
||||||
return af;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A stream for writing to the temp file, and when done
|
|
||||||
* can return a stream for reading the data just written.
|
|
||||||
* NOTE: We assume that only one thread is writing to the
|
|
||||||
* file at a time.
|
|
||||||
*/
|
|
||||||
class AppendStream extends OutputStream {
|
|
||||||
private final WritableSharedFile tf;
|
|
||||||
private RandomAccessFile raf;
|
|
||||||
private final long start;
|
|
||||||
private long end;
|
|
||||||
|
|
||||||
public AppendStream(WritableSharedFile tf) throws IOException {
|
|
||||||
this.tf = tf;
|
|
||||||
raf = tf.getWritableFile();
|
|
||||||
start = raf.length();
|
|
||||||
raf.seek(start);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(int b) throws IOException {
|
|
||||||
raf.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b) throws IOException {
|
|
||||||
raf.write(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void write(byte[] b, int off, int len) throws IOException {
|
|
||||||
raf.write(b, off, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized void close() throws IOException {
|
|
||||||
end = tf.updateLength();
|
|
||||||
raf = null; // no more writing allowed
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized InputStream getInputStream() throws IOException {
|
|
||||||
return tf.newStream(start, end);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.util.StringTokenizer;
|
|
||||||
|
|
||||||
public class UNIXFile extends File {
|
|
||||||
protected static final boolean loaded;
|
|
||||||
protected static final int lockType;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -7972156315284146651L;
|
|
||||||
|
|
||||||
public UNIXFile(String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
// lock type enum
|
|
||||||
protected static final int NONE = 0;
|
|
||||||
protected static final int NATIVE = 1;
|
|
||||||
protected static final int JAVA = 2;
|
|
||||||
|
|
||||||
static {
|
|
||||||
String lt = System.getProperty("mail.mbox.locktype", "native");
|
|
||||||
int type = NATIVE;
|
|
||||||
if (lt.equalsIgnoreCase("none"))
|
|
||||||
type = NONE;
|
|
||||||
else if (lt.equalsIgnoreCase("java"))
|
|
||||||
type = JAVA;
|
|
||||||
lockType = type;
|
|
||||||
|
|
||||||
boolean lloaded = false;
|
|
||||||
if (lockType == NATIVE) {
|
|
||||||
try {
|
|
||||||
System.loadLibrary("mbox");
|
|
||||||
lloaded = true;
|
|
||||||
} catch (UnsatisfiedLinkError e) {
|
|
||||||
String classpath = System.getProperty("java.class.path");
|
|
||||||
String sep = System.getProperty("path.separator");
|
|
||||||
String arch = System.getProperty("os.arch");
|
|
||||||
StringTokenizer st = new StringTokenizer(classpath, sep);
|
|
||||||
while (st.hasMoreTokens()) {
|
|
||||||
String path = st.nextToken();
|
|
||||||
if (path.endsWith("/classes") ||
|
|
||||||
path.endsWith("/mail.jar") ||
|
|
||||||
path.endsWith("/javax.mail.jar")) {
|
|
||||||
int i = path.lastIndexOf('/');
|
|
||||||
String libdir = path.substring(0, i + 1) + "lib/";
|
|
||||||
String lib = libdir + arch + "/libmbox.so";
|
|
||||||
try {
|
|
||||||
System.load(lib);
|
|
||||||
lloaded = true;
|
|
||||||
break;
|
|
||||||
} catch (UnsatisfiedLinkError e2) {
|
|
||||||
lib = libdir + "libmbox.so";
|
|
||||||
try {
|
|
||||||
System.load(lib);
|
|
||||||
lloaded = true;
|
|
||||||
break;
|
|
||||||
} catch (UnsatisfiedLinkError e3) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
loaded = lloaded;
|
|
||||||
if (loaded)
|
|
||||||
initIDs(FileDescriptor.class, FileDescriptor.in);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the access time of the file.
|
|
||||||
*/
|
|
||||||
public static long lastAccessed(File file) {
|
|
||||||
return lastAccessed0(file.getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
public long lastAccessed() {
|
|
||||||
return lastAccessed0(getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native void initIDs(Class<FileDescriptor> fdClass,
|
|
||||||
FileDescriptor stdin);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lock the file referred to by fd. The string mode is "r"
|
|
||||||
* for a read lock or "rw" for a write lock. Don't block
|
|
||||||
* if lock can't be acquired.
|
|
||||||
*/
|
|
||||||
public static boolean lock(FileDescriptor fd, String mode) {
|
|
||||||
return lock(fd, mode, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lock the file referred to by fd. The string mode is "r"
|
|
||||||
* for a read lock or "rw" for a write lock. If block is set,
|
|
||||||
* block waiting for the lock if necessary.
|
|
||||||
*/
|
|
||||||
private static boolean lock(FileDescriptor fd, String mode, boolean block) {
|
|
||||||
//return loaded && lock0(fd, mode);
|
|
||||||
if (loaded) {
|
|
||||||
boolean ret;
|
|
||||||
//System.out.println("UNIXFile.lock(" + fd + ", " + mode + ")");
|
|
||||||
ret = lock0(fd, mode, block);
|
|
||||||
//System.out.println("UNIXFile.lock returns " + ret);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native boolean lock0(FileDescriptor fd, String mode,
|
|
||||||
boolean block);
|
|
||||||
|
|
||||||
public static native long lastAccessed0(String name);
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public class UNIXFolder extends UNIXFile implements MailFile {
|
|
||||||
protected transient RandomAccessFile file;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = -254578891263785591L;
|
|
||||||
|
|
||||||
public UNIXFolder(String name) {
|
|
||||||
super(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean lock(String mode) {
|
|
||||||
try {
|
|
||||||
file = new RandomAccessFile(this, mode);
|
|
||||||
switch (lockType) {
|
|
||||||
case NONE:
|
|
||||||
return true;
|
|
||||||
case NATIVE:
|
|
||||||
default:
|
|
||||||
return UNIXFile.lock(file.getFD(), mode);
|
|
||||||
case JAVA:
|
|
||||||
return file.getChannel().
|
|
||||||
tryLock(0L, Long.MAX_VALUE, !mode.equals("rw")) != null;
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException fe) {
|
|
||||||
return false;
|
|
||||||
} catch (IOException ie) {
|
|
||||||
file = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unlock() {
|
|
||||||
if (file != null) {
|
|
||||||
try {
|
|
||||||
file.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// ignore it
|
|
||||||
}
|
|
||||||
file = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void touchlock() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileDescriptor getFD() {
|
|
||||||
if (file == null)
|
|
||||||
return null;
|
|
||||||
try {
|
|
||||||
return file.getFD();
|
|
||||||
} catch (IOException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,123 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 1997, 2018 Oracle and/or its affiliates. All rights reserved.
|
|
||||||
*
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* This Source Code may also be made available under the following Secondary
|
|
||||||
* Licenses when the conditions for such availability set forth in the
|
|
||||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
|
||||||
* version 2 with the GNU Classpath Exception, which is available at
|
|
||||||
* https://www.gnu.org/software/classpath/license.html.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.sun.mail.mbox;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
public class UNIXInbox extends UNIXFolder implements InboxFile {
|
|
||||||
private final String user;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 651261842162777620L;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Superclass UNIXFile loads the library containing all the
|
|
||||||
* native code and sets the "loaded" flag if successful.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public UNIXInbox(String user, String name) {
|
|
||||||
super(name);
|
|
||||||
this.user = user;
|
|
||||||
if (user == null)
|
|
||||||
throw new NullPointerException("user name is null in UNIXInbox");
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean lock(String mode) {
|
|
||||||
if (lockType == NATIVE) {
|
|
||||||
if (!loaded)
|
|
||||||
return false;
|
|
||||||
if (!maillock(user, 5))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!super.lock(mode)) {
|
|
||||||
if (loaded)
|
|
||||||
mailunlock();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unlock() {
|
|
||||||
super.unlock();
|
|
||||||
if (loaded)
|
|
||||||
mailunlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void touchlock() {
|
|
||||||
if (loaded)
|
|
||||||
touchlock0();
|
|
||||||
}
|
|
||||||
|
|
||||||
private transient RandomAccessFile lockfile; // the user's ~/.Maillock file
|
|
||||||
private transient String lockfileName; // its name
|
|
||||||
|
|
||||||
public boolean openLock(String mode) {
|
|
||||||
if (mode.equals("r"))
|
|
||||||
return true;
|
|
||||||
if (lockfileName == null) {
|
|
||||||
String home = System.getProperty("user.home");
|
|
||||||
lockfileName = home + File.separator + ".Maillock";
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
lockfile = new RandomAccessFile(lockfileName, mode);
|
|
||||||
boolean ret;
|
|
||||||
switch (lockType) {
|
|
||||||
case NONE:
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
case NATIVE:
|
|
||||||
default:
|
|
||||||
ret = UNIXFile.lock(lockfile.getFD(), mode);
|
|
||||||
break;
|
|
||||||
case JAVA:
|
|
||||||
ret = lockfile.getChannel().
|
|
||||||
tryLock(0L, Long.MAX_VALUE, !mode.equals("rw")) != null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!ret)
|
|
||||||
closeLock();
|
|
||||||
return ret;
|
|
||||||
} catch (IOException ex) {
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closeLock() {
|
|
||||||
if (lockfile == null)
|
|
||||||
return;
|
|
||||||
try {
|
|
||||||
lockfile.close();
|
|
||||||
} catch (IOException ex) {
|
|
||||||
} finally {
|
|
||||||
lockfile = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (!(o instanceof UNIXInbox))
|
|
||||||
return false;
|
|
||||||
UNIXInbox other = (UNIXInbox)o;
|
|
||||||
return user.equals(other.user) && super.equals(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int hashCode() {
|
|
||||||
return super.hashCode() + user.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
private native boolean maillock(String user, int retryCount);
|
|
||||||
private native void mailunlock();
|
|
||||||
private native void touchlock0();
|
|
||||||
}
|
|
Loading…
Reference in new issue