diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/DeleCmdHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/DeleCmdHandler.java index 10038bd..1439ade 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/DeleCmdHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/DeleCmdHandler.java @@ -60,9 +60,9 @@ public class DeleCmdHandler implements CommandHandler { StringBuilder responseBuffer = new StringBuilder(64).append("Message (").append(num).append(") does not exist."); return new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString()); } - List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); + List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); - Long uid = meta.getUid(); + String uid = meta.getUid(); if (deletedUidList.contains(uid)) { StringBuilder responseBuffer = new StringBuilder(64).append("Message (").append(num).append(") already deleted."); diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/ExtraDotInputStream.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/ExtraDotInputStream.java index 8be8d9e..08c286f 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/ExtraDotInputStream.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/ExtraDotInputStream.java @@ -38,7 +38,6 @@ public class ExtraDotInputStream extends InputStream { this.in = new PushbackInputStream(in, 2); startLine = true; } - @Override public int read() throws IOException { diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/ListCmdHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/ListCmdHandler.java index 1b3b256..7f00f59 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/ListCmdHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/ListCmdHandler.java @@ -54,7 +54,7 @@ public class ListCmdHandler implements CommandHandler { public Response onCommand(POP3Session session, Request request) { String parameters = request.getArgument(); List uidList = (List) session.getAttachment(POP3Session.UID_LIST, State.Transaction); - List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); + List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); if (session.getHandlerState() == POP3Session.TRANSACTION) { POP3Response response = null; @@ -95,7 +95,6 @@ public class ListCmdHandler implements CommandHandler { } if (deletedUidList.contains(data.getUid()) == false) { - StringBuilder responseBuffer = new StringBuilder(64).append(num).append(" ").append(data.getSize()); response = new POP3Response(POP3Response.OK_RESPONSE, responseBuffer.toString()); } else { diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/MessageMetaDataUtils.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/MessageMetaDataUtils.java index ae0cc85..0678fdf 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/MessageMetaDataUtils.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/MessageMetaDataUtils.java @@ -44,4 +44,24 @@ public class MessageMetaDataUtils { return uidList.get(number -1); } } + + /** + * Check whether POP3 UID is compatible with RFC1939 + * + * @param uid + * @return + */ + public static boolean isRFC1939Compatible(String uid) { + if (uid == null) { + return false; + } + + for (int i = 0; i < uid.length(); i++) { + if ((uid.charAt(i) >= 0x21 && uid.charAt(i) < 0x7E) == false) { + return false; + } + } + + return true; + } } diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/QuitCmdHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/QuitCmdHandler.java index ee4e2a3..edb77d7 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/QuitCmdHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/QuitCmdHandler.java @@ -59,20 +59,16 @@ public class QuitCmdHandler implements CommandHandler { if (session.getHandlerState() == POP3Session.AUTHENTICATION_READY || session.getHandlerState() == POP3Session.AUTHENTICATION_USERSET) { return SIGN_OFF; } - List toBeRemoved = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); + List toBeRemoved = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); Mailbox mailbox = session.getUserMailbox(); try { - ; - long uids[] = new long[toBeRemoved.size()]; - for (int i = 0;i < toBeRemoved.size(); i++) { - uids[i] = toBeRemoved.get(i); - } + String[] uids = toBeRemoved.toArray(new String[toBeRemoved.size()]); mailbox.remove(uids); response = SIGN_OFF; } catch (Exception ex) { response = SIGN_OFF_NOT_CLEAN; session.getLogger().error("Some deleted messages were not removed", ex); - } + } try { mailbox.close(); } catch (IOException e) { diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/RetrCmdHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/RetrCmdHandler.java index aa7f0c6..5ce0fa4 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/RetrCmdHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/RetrCmdHandler.java @@ -67,9 +67,9 @@ public class RetrCmdHandler implements CommandHandler { response = new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString()); return response; } - List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); + List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); - Long uid = data.getUid(); + String uid = data.getUid(); if (deletedUidList.contains(uid) == false) { InputStream content = session.getUserMailbox().getMessage(uid); diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/RsetCmdHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/RsetCmdHandler.java index b5aae4e..6faf798 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/RsetCmdHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/RsetCmdHandler.java @@ -66,7 +66,7 @@ public class RsetCmdHandler implements CommandHandler { List messages = session.getUserMailbox().getMessages(); session.setAttachment(POP3Session.UID_LIST, messages, State.Transaction); - session.setAttachment(POP3Session.DELETED_UID_LIST, new ArrayList(), State.Transaction); + session.setAttachment(POP3Session.DELETED_UID_LIST, new ArrayList(), State.Transaction); } catch (IOException e) { // In the event of an exception being thrown there may or may not be // anything in userMailbox diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/StatCmdHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/StatCmdHandler.java index 04762c5..5b8fdee 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/StatCmdHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/StatCmdHandler.java @@ -48,7 +48,7 @@ public class StatCmdHandler implements CommandHandler { if (session.getHandlerState() == POP3Session.TRANSACTION) { List uidList = (List) session.getAttachment(POP3Session.UID_LIST, State.Transaction); - List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); + List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); long size = 0; int count = 0; if (uidList.isEmpty() == false) { diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java index 16e9efe..d5886c2 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/TopCmdHandler.java @@ -88,9 +88,9 @@ public class TopCmdHandler extends RetrCmdHandler implements CapaCapability { return new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString()); } - List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); + List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); - Long uid = data.getUid(); + String uid = data.getUid(); if (deletedUidList.contains(uid) == false) { InputStream body = new CountingBodyInputStream(new ExtraDotInputStream(new CRLFTerminatedInputStream(session.getUserMailbox().getMessageBody(uid))), lines); diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/UidlCmdHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/UidlCmdHandler.java index cf03e5c..45db866 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/UidlCmdHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/UidlCmdHandler.java @@ -53,16 +53,16 @@ public class UidlCmdHandler implements CommandHandler, CapaCapabili String parameters = request.getArgument(); if (session.getHandlerState() == POP3Session.TRANSACTION) { List uidList = (List) session.getAttachment(POP3Session.UID_LIST, State.Transaction); - List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); + List deletedUidList = (List) session.getAttachment(POP3Session.DELETED_UID_LIST, State.Transaction); try { String identifier = session.getUserMailbox().getIdentifier(); if (parameters == null) { response = new POP3Response(POP3Response.OK_RESPONSE, "unique-id listing follows"); + for (int i = 0; i < uidList.size(); i++) { - Long uid = uidList.get(i).getUid(); - if (deletedUidList.contains(uid) == false) { - // construct unique UIDL. See JAMES-1264 - StringBuilder responseBuffer = new StringBuilder(64).append(i + 1).append(" ").append(identifier).append("-").append(uid); + MessageMetaData metadata = uidList.get(i); + if (deletedUidList.contains(metadata.getUid()) == false) { + StringBuilder responseBuffer = new StringBuilder().append(i + 1).append(" ").append(metadata.getUid(identifier)); response.appendLine(responseBuffer.toString()); } } @@ -73,18 +73,16 @@ public class UidlCmdHandler implements CommandHandler, CapaCapabili try { num = Integer.parseInt(parameters); - MessageMetaData data = MessageMetaDataUtils.getMetaData(session, num); - if (data == null) { + MessageMetaData metadata = MessageMetaDataUtils.getMetaData(session, num); + + if (metadata == null) { StringBuilder responseBuffer = new StringBuilder(64).append("Message (").append(num).append(") does not exist."); return new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString()); } - long uid = data.getUid(); - - if (deletedUidList.contains(uid) == false) { - // construct unique UIDL. See JAMES-1264 - StringBuilder responseBuffer = new StringBuilder(64).append(num).append(" ").append(identifier).append("-").append(uid); - response = new POP3Response(POP3Response.OK_RESPONSE, responseBuffer.toString()); + if (deletedUidList.contains(metadata.getUid()) == false) { + StringBuilder responseBuffer = new StringBuilder(64).append(num).append(" ").append(metadata.getUid(identifier)); + response = new POP3Response(POP3Response.OK_RESPONSE, responseBuffer.toString()); } else { StringBuilder responseBuffer = new StringBuilder(64).append("Message (").append(num).append(") already deleted."); response = new POP3Response(POP3Response.ERR_RESPONSE, responseBuffer.toString()); diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java b/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java index d233dbb..4a2e615 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/core/WelcomeMessageHandler.java @@ -45,7 +45,5 @@ public class WelcomeMessageHandler implements ConnectHandler { POP3Response response = new POP3Response(POP3Response.OK_RESPONSE, responseBuffer.toString()); return response; } - - - -} + +} \ No newline at end of file diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/AbstractMailbox.java b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/AbstractMailbox.java index 4add30d..f4d0f75 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/AbstractMailbox.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/AbstractMailbox.java @@ -34,13 +34,12 @@ public abstract class AbstractMailbox implements Mailbox { /* * (non-Javadoc) * - * @see org.apache.james.protocols.pop3.mailbox.Mailbox#getMessage(long) + * @see org.apache.james.protocols.pop3.mailbox.Mailbox#getMessage(String) */ - public InputStream getMessage(long uid) throws IOException { + public InputStream getMessage(String uid) throws IOException { return new CombinedInputStream(getMessageHeaders(uid), getMessageBody(uid)); } - /** * Does nothing */ diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/ImapMailbox.java b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/ImapMailbox.java new file mode 100644 index 0000000..00c2195 --- /dev/null +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/ImapMailbox.java @@ -0,0 +1,90 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ +package org.apache.james.protocols.pop3.mailbox; + +import java.io.IOException; +import java.io.InputStream; + +/** + * An IMAP Mailbox adapter which is used in POP3 to retrieve messages + * + * + */ +@Deprecated +public abstract class ImapMailbox implements Mailbox { + + /** + * Returns the message body as {@link InputStream} or null if + * no message can be found for the given uid + * + * @param uid + * @return body + * @throws IOException + */ + public abstract InputStream getMessageBody(long uid) throws IOException; + + public InputStream getMessageBody(String uid) throws NumberFormatException, IOException { + return this.getMessageBody(Long.parseLong(uid)); + } + + /** + * Returns the message headers as {@link InputStream} or null + * if no message can be found for the given uid + * + * @param uid + * @return headers + * @throws IOException + */ + public abstract InputStream getMessageHeaders(long uid) throws IOException; + + public InputStream getMessageHeaders(String uid) throws NumberFormatException, IOException { + return this.getMessageHeaders(Long.parseLong(uid)); + } + + /** + * Return the full message (headers + body) as {@link InputStream} or + * null if no message can be found for the given + * uid + * + * @param uid + * @return message + * @throws IOException + */ + public abstract InputStream getMessage(long uid) throws IOException; + + public InputStream getMessage(String uid) throws NumberFormatException, IOException { + return this.getMessage(Long.parseLong(uid)); + } + + /** + * Remove the messages with the given uids + * + * @param uids + */ + public abstract void remove(long... uids) throws IOException; + + public void remove(String... uids) throws NumberFormatException, IOException { + long imapUids[] = new long[uids.length]; + for (int i = 0; i < uids.length; i++) { + imapUids[i] = Long.parseLong(uids[i]); + } + this.remove(imapUids); + } + +} diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/ImapMessageMetaData.java b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/ImapMessageMetaData.java new file mode 100644 index 0000000..e95f02c --- /dev/null +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/ImapMessageMetaData.java @@ -0,0 +1,36 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ +package org.apache.james.protocols.pop3.mailbox; + +/** + * Hold meta data for a IMAP message. Construct unique POP3 UIDL from IMAP UID. + * See JAMES-1264. + */ +public final class ImapMessageMetaData extends MessageMetaData { + + public ImapMessageMetaData(Long uid, long size) { + super(uid.toString(), size); + } + + @Override + public String getUid(String mailboxId) { + return mailboxId + "-" + super.getUid(); + } + +} diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/Mailbox.java b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/Mailbox.java index 5efb604..ee96d5c 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/Mailbox.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/Mailbox.java @@ -37,7 +37,7 @@ public interface Mailbox { * @return body * @throws IOException */ - InputStream getMessageBody(long uid) throws IOException; + InputStream getMessageBody(String uid) throws IOException; /** * Returns the message headers as {@link InputStream} or null @@ -47,7 +47,7 @@ public interface Mailbox { * @return headers * @throws IOException */ - InputStream getMessageHeaders(long uid) throws IOException; + InputStream getMessageHeaders(String uid) throws IOException; /** * Return the full message (headers + body) as {@link InputStream} or @@ -58,7 +58,7 @@ public interface Mailbox { * @return message * @throws IOException */ - InputStream getMessage(long uid) throws IOException; + InputStream getMessage(String uid) throws IOException; /** * Return a immutable {@link List} which holds the {@link MessageMetaData} @@ -67,14 +67,14 @@ public interface Mailbox { * @return messages * @throws IOException */ - List getMessages() throws IOException;; + List getMessages() throws IOException; /** * Remove the messages with the given uids * * @param uids */ - void remove(long... uids) throws IOException; + void remove(String... uids) throws IOException; /** * Return the identifier for the mailbox. This MUST not change diff --git a/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/MessageMetaData.java b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/MessageMetaData.java index 1dc60a9..3faa026 100644 --- a/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/MessageMetaData.java +++ b/pop3/src/main/java/org/apache/james/protocols/pop3/mailbox/MessageMetaData.java @@ -18,25 +18,43 @@ ****************************************************************/ package org.apache.james.protocols.pop3.mailbox; +import org.apache.james.protocols.pop3.core.MessageMetaDataUtils; + /** * Hold meta data for a message */ -public final class MessageMetaData { +public class MessageMetaData { - private final long uid; + private final String uid; private final long size; - public MessageMetaData(long uid, long size) { + public MessageMetaData(String uid, long size) { this.uid = uid; this.size = size; - } - /** + if(!MessageMetaDataUtils.isRFC1939Compatible(uid)) { + throw new IllegalArgumentException("UID is not RFC1939 compatible"); + } + } + + /** * Return the uid of the message * * @return uid */ - public long getUid() { + public String getUid() { + return uid; + } + + /** + * Return the uid of the message. This method uses extra Mailbox ID argument to make + * UID unique when it is not globally unique. By default assuming UID globally unique. + * + * @param mailboxId + * Mailbox ID + * @return + */ + public String getUid(String mailboxId) { return uid; } @@ -48,4 +66,5 @@ public final class MessageMetaData { public long getSize() { return size; } + } diff --git a/pop3/src/test/java/org/apache/james/protocols/pop3/utils/MockMailbox.java b/pop3/src/test/java/org/apache/james/protocols/pop3/utils/MockMailbox.java index bc641eb..bc9c0e2 100644 --- a/pop3/src/test/java/org/apache/james/protocols/pop3/utils/MockMailbox.java +++ b/pop3/src/test/java/org/apache/james/protocols/pop3/utils/MockMailbox.java @@ -28,10 +28,11 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicLong; -import org.apache.james.protocols.pop3.mailbox.Mailbox; +import org.apache.james.protocols.pop3.mailbox.ImapMailbox; +import org.apache.james.protocols.pop3.mailbox.ImapMessageMetaData; import org.apache.james.protocols.pop3.mailbox.MessageMetaData; -public class MockMailbox implements Mailbox { +public class MockMailbox extends ImapMailbox { private final Map messages = new HashMap(); private final String identifier; @@ -39,13 +40,14 @@ public class MockMailbox implements Mailbox { public MockMailbox(String identifier, Message... messages) { this.identifier = identifier; for (Message m: messages) { - this.messages.put(m.meta.getUid(), m); + this.messages.put(Long.parseLong(m.meta.getUid()), m); } } public MockMailbox(String identifier) { this(identifier, new Message[0]); } + public InputStream getMessageBody(long uid) throws IOException { Message m = messages.get(uid); if (m == null) { @@ -102,7 +104,7 @@ public class MockMailbox implements Mailbox { public Message(String headers, String body) { this.headers = headers; this.body = body; - this.meta = new MessageMetaData(UIDS.incrementAndGet(), headers.length() + body.length() + 2); + this.meta = new ImapMessageMetaData(UIDS.incrementAndGet(), headers.length() + body.length() + 2); } public String toString() {