Skip to content
This repository was archived by the owner on Jun 7, 2023. It is now read-only.

Commit f133289

Browse files
author
Rustam Aliyev
committed
Major part of POP3 commands implemented
1 parent 84796ae commit f133289

File tree

11 files changed

+534
-45
lines changed

11 files changed

+534
-45
lines changed

config/logback.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,16 @@
3030
</encoder>
3131
</appender>
3232

33-
<!-- do not log LMTPProtocols connection info, increase log level -->
33+
<!-- do not log LMTP connection info, increase log level -->
3434
<logger name="com.elasticinbox.lmtp.utils.LMTPProtocolLogger" level="WARN">
3535
<appender-ref ref="FILE" />
3636
</logger>
3737

38+
<!-- do not log POP3 connection info, increase log level -->
39+
<logger name="com.elasticinbox.pop3.utils.POP3ProtocolLogger" level="WARN">
40+
<appender-ref ref="FILE" />
41+
</logger>
42+
3843
<root level="INFO">
3944
<appender-ref ref="FILE" />
4045
</root>

modules/common/pom.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,14 @@
122122
<version>${bundle.guava.version}</version>
123123
<scope>provided</scope>
124124
</dependency>
125+
126+
<!-- Test -->
127+
<dependency>
128+
<groupId>junit</groupId>
129+
<artifactId>junit</artifactId>
130+
<version>4.10</version>
131+
<scope>test</scope>
132+
</dependency>
125133

126134
</dependencies>
127135

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
* Copyright (c) 2011-2013 Optimax Software Ltd.
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without
6+
* modification, are permitted provided that the following conditions are met:
7+
*
8+
* * Redistributions of source code must retain the above copyright notice,
9+
* this list of conditions and the following disclaimer.
10+
* * Redistributions in binary form must reproduce the above copyright notice,
11+
* this list of conditions and the following disclaimer in the documentation
12+
* and/or other materials provided with the distribution.
13+
* * Neither the name of Optimax Software, ElasticInbox, nor the names
14+
* of its contributors may be used to endorse or promote products derived
15+
* from this software without specific prior written permission.
16+
*
17+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
21+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
24+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27+
*/
28+
29+
package com.elasticinbox.common.utils;
30+
31+
import java.io.FilterInputStream;
32+
import java.io.IOException;
33+
import java.io.InputStream;
34+
35+
/**
36+
* A Filter for use with POP3 or other protocols in which lines must end with
37+
* CRLF. Converts every "isolated" occurrence of \r or \n with \r\n.
38+
*
39+
* @author Rustam Aliev
40+
*/
41+
public class CRLFInputStream extends FilterInputStream
42+
{
43+
/**
44+
* Last char indicator (CR, LF, or OTHER).
45+
*/
46+
private int statusLast;
47+
private final static int LAST_WAS_OTHER = 0;
48+
private final static int LAST_WAS_CR = 1;
49+
private final static int LAST_WAS_LF = 2;
50+
51+
private static final int CR = 13;
52+
private static final int LF = 10;
53+
54+
private static final int EMPTY_BUFFER = -1;
55+
private static int buffer = EMPTY_BUFFER;
56+
57+
public CRLFInputStream(InputStream in)
58+
{
59+
super(in);
60+
statusLast = LAST_WAS_LF; // we already assume a CRLF at beginning
61+
}
62+
63+
@Override
64+
public int read(byte[] b) throws IOException {
65+
return read(b, 0, b.length);
66+
}
67+
68+
@Override
69+
public int read() throws IOException
70+
{
71+
// if buffer not empty, return buffer first
72+
if (buffer > EMPTY_BUFFER) {
73+
int b = buffer;
74+
buffer = EMPTY_BUFFER;
75+
return b;
76+
}
77+
78+
// read byte from stream
79+
int b = super.read();
80+
81+
switch (b)
82+
{
83+
case CR:
84+
statusLast = LAST_WAS_CR;
85+
break;
86+
case LF:
87+
if (statusLast != LAST_WAS_CR) {
88+
// return CR instead
89+
b = CR;
90+
statusLast = LAST_WAS_CR;
91+
} else {
92+
statusLast = LAST_WAS_LF;
93+
}
94+
break;
95+
default:
96+
if (statusLast == LAST_WAS_CR) {
97+
// add current byte to buffer and return LF
98+
buffer = b;
99+
b = LF;
100+
statusLast = LAST_WAS_LF;
101+
} else {
102+
// we're no longer at the start of a line
103+
statusLast = LAST_WAS_OTHER;
104+
}
105+
break;
106+
}
107+
108+
return b;
109+
}
110+
111+
@Override
112+
public int read(byte[] b, int off, int len) throws IOException
113+
{
114+
// TODO: should be implemented
115+
// we don't need it right now and it's a bit complicated
116+
return -1;
117+
}
118+
}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one *
3+
* or more contributor license agreements. See the NOTICE file *
4+
* distributed with this work for additional information *
5+
* regarding copyright ownership. The ASF licenses this file *
6+
* to you under the Apache License, Version 2.0 (the *
7+
* "License"); you may not use this file except in compliance *
8+
* with the License. You may obtain a copy of the License at *
9+
* *
10+
* http://www.apache.org/licenses/LICENSE-2.0 *
11+
* *
12+
* Unless required by applicable law or agreed to in writing, *
13+
* software distributed under the License is distributed on an *
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15+
* KIND, either express or implied. See the License for the *
16+
* specific language governing permissions and limitations *
17+
* under the License. *
18+
****************************************************************/
19+
20+
package com.elasticinbox.common.utils;
21+
22+
import java.io.FilterOutputStream;
23+
import java.io.IOException;
24+
import java.io.OutputStream;
25+
26+
/**
27+
* Modified version of the CRLFOutputStream from Apache James project.
28+
*
29+
* A Filter for use with LMTP or other protocols in which lines must end with
30+
* CRLF. Converts every "isolated" occurrence of \r or \n with \r\n.
31+
*
32+
* RFC 2821 #2.3.7 mandates that line termination is CRLF, and that CR and LF
33+
* must not be transmitted except in that pairing. If we get a naked LF, convert
34+
* to CRLF.
35+
*/
36+
public class CRLFOutputStream extends FilterOutputStream
37+
{
38+
/**
39+
* Counter for number of last (0A or 0D).
40+
*/
41+
private int statusLast;
42+
private final static int LAST_WAS_OTHER = 0;
43+
private final static int LAST_WAS_CR = 1;
44+
private final static int LAST_WAS_LF = 2;
45+
46+
/**
47+
* Constructor that wraps an OutputStream.
48+
*
49+
* @param out
50+
* the OutputStream to be wrapped
51+
*/
52+
public CRLFOutputStream(OutputStream out)
53+
{
54+
super(out);
55+
statusLast = LAST_WAS_LF; // we already assume a CRLF at beginning
56+
// (otherwise TOP would not work correctly!)
57+
}
58+
59+
/**
60+
* Writes a byte to the stream Fixes any naked CR or LF to the RFC 2821
61+
* mandated CFLF pairing.
62+
*
63+
* @param b
64+
* the byte to write
65+
*
66+
* @throws IOException
67+
* if an error occurs writing the byte
68+
*/
69+
public void write(int b) throws IOException
70+
{
71+
switch (b) {
72+
case '\r':
73+
out.write('\r');
74+
out.write('\n');
75+
statusLast = LAST_WAS_CR;
76+
break;
77+
case '\n':
78+
if (statusLast != LAST_WAS_CR) {
79+
out.write('\r');
80+
out.write('\n');
81+
}
82+
statusLast = LAST_WAS_LF;
83+
break;
84+
default:
85+
// we're no longer at the start of a line
86+
out.write(b);
87+
statusLast = LAST_WAS_OTHER;
88+
break;
89+
}
90+
}
91+
92+
/**
93+
* @see java.io.FilterOutputStream#write(byte[], int, int)
94+
*/
95+
public synchronized void write(byte buffer[], int offset, int length) throws IOException
96+
{
97+
/* optimized */
98+
int lineStart = offset;
99+
100+
for (int i = offset; i < length + offset; i++)
101+
{
102+
switch (buffer[i])
103+
{
104+
case '\r':
105+
// CR case. Write down the last line
106+
// and position the new lineStart at the next char
107+
out.write(buffer, lineStart, i - lineStart);
108+
out.write('\r');
109+
out.write('\n');
110+
lineStart = i + 1;
111+
statusLast = LAST_WAS_CR;
112+
break;
113+
case '\n':
114+
if (statusLast != LAST_WAS_CR) {
115+
out.write(buffer, lineStart, i - lineStart);
116+
out.write('\r');
117+
out.write('\n');
118+
}
119+
lineStart = i + 1;
120+
statusLast = LAST_WAS_LF;
121+
break;
122+
default:
123+
statusLast = LAST_WAS_OTHER;
124+
}
125+
}
126+
127+
if (length + offset > lineStart) {
128+
out.write(buffer, lineStart, length + offset - lineStart);
129+
}
130+
}
131+
132+
/**
133+
* Ensure that the stream is CRLF terminated.
134+
*
135+
* @throws IOException
136+
* if an error occurs writing the byte
137+
*/
138+
public void checkCRLFTerminator() throws IOException
139+
{
140+
if (statusLast == LAST_WAS_OTHER)
141+
{
142+
out.write('\r');
143+
out.write('\n');
144+
statusLast = LAST_WAS_CR;
145+
}
146+
}
147+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/****************************************************************
2+
* Licensed to the Apache Software Foundation (ASF) under one *
3+
* or more contributor license agreements. See the NOTICE file *
4+
* distributed with this work for additional information *
5+
* regarding copyright ownership. The ASF licenses this file *
6+
* to you under the Apache License, Version 2.0 (the *
7+
* "License"); you may not use this file except in compliance *
8+
* with the License. You may obtain a copy of the License at *
9+
* *
10+
* http://www.apache.org/licenses/LICENSE-2.0 *
11+
* *
12+
* Unless required by applicable law or agreed to in writing, *
13+
* software distributed under the License is distributed on an *
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY *
15+
* KIND, either express or implied. See the License for the *
16+
* specific language governing permissions and limitations *
17+
* under the License. *
18+
****************************************************************/
19+
package com.elasticinbox.common.utils;
20+
21+
import java.io.ByteArrayOutputStream;
22+
import java.io.IOException;
23+
import java.io.InputStream;
24+
import junit.framework.TestCase;
25+
26+
public abstract class AbstractInputStreamTest extends TestCase
27+
{
28+
protected void checkRead(InputStream in, String expected)
29+
throws IOException
30+
{
31+
ByteArrayOutputStream out = new ByteArrayOutputStream();
32+
int i = -1;
33+
while ((i = in.read()) != -1) {
34+
out.write(i);
35+
}
36+
in.close();
37+
out.close();
38+
assertEquals(expected, new String(out.toByteArray()));
39+
40+
}
41+
42+
protected void checkReadViaArray(InputStream in, String expected)
43+
throws IOException
44+
{
45+
ByteArrayOutputStream out = new ByteArrayOutputStream();
46+
47+
byte[] buf = new byte[3];
48+
int i = 0;
49+
while ((i = in.read(buf)) != -1) {
50+
out.write(buf, 0, i);
51+
}
52+
53+
in.close();
54+
out.close();
55+
assertEquals(expected, new String(out.toByteArray()));
56+
}
57+
}

0 commit comments

Comments
 (0)