Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master' into releases/1.5.x
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelmay committed Jan 15, 2017
2 parents 3728fc5 + 0c12abb commit bfc0aee
Show file tree
Hide file tree
Showing 43 changed files with 1,017 additions and 88 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Go to the [project site][greenmail_project_site] for details:
* [JavaDoc][greenmail_javadoc]
* [FAQ][greenmail_faq]
* [Download][greenmail_download]
* [Maven coordinates][maven_repository_com]: com.icegreen:greenmail:1.5.1
* [Maven coordinates][maven_repository_com]: com.icegreen:greenmail:1.5.2

The GreenMail project welcomes any contribution, so go ahead and fork/open a pull request! See the guidelines below.

Expand Down
25 changes: 25 additions & 0 deletions greenmail-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,29 @@
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>de.m3y.maven</groupId>
<artifactId>inject-maven-plugin</artifactId>
<configuration>
<injections>
<injection>
<value>${project.version}</value>
<pointCut>com.icegreen.greenmail.server.BuildInfo.getProjectVersion</pointCut>
</injection>
</injections>
</configuration>
<executions>
<execution>
<phase>process-classes</phase>
<goals>
<goal>inject</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
package com.icegreen.greenmail.imap;

import com.icegreen.greenmail.server.BuildInfo;
import com.icegreen.greenmail.server.ProtocolHandler;
import com.icegreen.greenmail.user.UserManager;
import org.slf4j.Logger;
Expand Down Expand Up @@ -58,7 +59,8 @@ public void run() {
response = new ImapResponse(outs);

// Write welcome message
String responseBuffer = VERSION + " Server GreenMail ready";
String responseBuffer = VERSION + " Server GreenMail v" +
BuildInfo.INSTANCE.getProjectVersion() + " ready";
response.okResponse(null, responseBuffer);

session = new ImapSessionImpl(imapHost,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -221,11 +221,11 @@ private void handleBodyFetch(MimeMessage mimeMessage,
} else if ("TEXT".equalsIgnoreCase(sectionSpecifier)) {
handleBodyFetchForText(mimeMessage, partial, response);
} else {
String contentType = mimeMessage.getContentType();
if (contentType.toLowerCase().startsWith("text/plain") && "1".equals(sectionSpecifier)) {
Object content = mimeMessage.getContent();
if (content instanceof String) {
handleBodyFetchForText(mimeMessage, partial, response);
} else {
MimeMultipart mp = (MimeMultipart) mimeMessage.getContent();
MimeMultipart mp = (MimeMultipart) content;
BodyPart part = null;

// Find part by number spec, eg "1" or "2.1" or "4.3.1" ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@

import java.io.Serializable;
import java.util.*;
import java.util.regex.Pattern;

/**
* Represents a range of UID values.
*/
public class IdRange implements Serializable {

/** Matches a sequence of a single id or id range */
public static final Pattern SEQUENCE = Pattern.compile("\\d+|\\d+\\:\\d+");
private long lowVal;
private long highVal;

Expand Down Expand Up @@ -48,7 +50,7 @@ public boolean includes(long uid) {
* @return a list of ranges, never null.
*/
public static List<IdRange> parseRangeSequence(String idRangeSequence) {
StringTokenizer tokenizer = new StringTokenizer(idRangeSequence, ",");
StringTokenizer tokenizer = new StringTokenizer(idRangeSequence, " ");
List<IdRange> ranges = new ArrayList<>();
while (tokenizer.hasMoreTokens()) {
ranges.add(parseRange(tokenizer.nextToken()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import javax.mail.search.NotTerm;
import javax.mail.search.SearchTerm;

import static com.icegreen.greenmail.imap.commands.IdRange.SEQUENCE;

/**
* Handles processing for the SEARCH imap command.
*
Expand Down Expand Up @@ -50,7 +52,7 @@ public SearchTerm searchTerm(ImapRequestLineReader request)
continue;
}
}
if (!quoted && (next == 32 || next == '\n')) {
if (!quoted && (next == 32 || next == '\n') && sb.length()>0) {
if (log.isDebugEnabled()) {
log.debug("Search request is '" + sb.toString() + '\'');
}
Expand All @@ -65,11 +67,29 @@ public SearchTerm searchTerm(ImapRequestLineReader request)
&& keyValue.charAt(keyValue.length() - 1) == ')') {
keyValue = keyValue.substring(1, keyValue.length() - 1);
}
SearchKey key = SearchKey.valueOf(keyValue);
if (SearchKey.NOT == key) {
negated = true;

// Message set?
if (SEQUENCE.matcher(keyValue).matches()) {
b = SearchTermBuilder.create(SearchKey.SEQUENCE_SET);

// Try to get additional number sequences.
// Sequence can be a whitespace separated list of either a number or number range
// Example: '2 5:9 9'
next = request.nextChar();
while(next == 32 || (next >= '0' && next <= '9') || next == ':') {
request.consume();
sb.append(next);
next = request.nextChar();
}
b.addParameter(sb.toString());
} else {
b = SearchTermBuilder.create(key);
// Term?
SearchKey key = SearchKey.valueOf(keyValue);
if (SearchKey.NOT == key) {
negated = true;
} else {
b = SearchTermBuilder.create(key);
}
}
} catch (IllegalArgumentException ex) {
// Ignore for now instead of breaking. See issue#35 .
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Read more: https://tools.ietf.org/html/rfc3501
* </p>
* <ul>
* <li>SEQUENCE_SET &lt;SEQUENCE SET&gt; of message ids</li>
* <li>ALL All messages in the mailbox; the default initial key for ANDing</li>
* <li>ANSWERED Messages with the \Answered flag set.</li>
* <li>BCC Messages that contain the specified string in the envelope structure's BCC field.</li>
Expand Down Expand Up @@ -88,7 +89,12 @@ public enum SearchKey {
UNDRAFT(),
UNFLAGGED(),
UNKEYWORD(1),
UNSEEN();
UNSEEN(),
/**
* &lt;sequence set&gt; - Messages with message sequence numbers corresponding
* to the specified message sequence number set.
*/
SEQUENCE_SET(1);

private int minArgs = 0; // expected additional arguments
private boolean operator = false; // Is an operator, such as AND, OR, NOT ...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ public static SearchTermBuilder create(final SearchKey key) {
case UNKEYWORD:
builder = createKeywordSearchTermBuilder(key);
break;
case SEQUENCE_SET:
builder = createSequenceSetTermBuilder();
break;
default:
throw new IllegalStateException("Unsupported search term '" + key + '\'');
}
Expand Down Expand Up @@ -225,6 +228,16 @@ public SearchTerm build() {
};
}

private static SearchTermBuilder createSequenceSetTermBuilder() {
return new SearchTermBuilder() {
@Override
public SearchTerm build() {
final List<IdRange> idRanges = IdRange.parseRangeSequence(getParameter(0));
return new MessageNumberSearchTerm(idRanges);
}
};
}

private static javax.mail.Flags.Flag toFlag(String pFlag) {
if (pFlag == null || pFlag.trim().length() < 1) {
throw new IllegalArgumentException("Can not convert empty string to mail flag");
Expand Down Expand Up @@ -271,14 +284,73 @@ public boolean match(Message msg) {
}
}

// Not very efficient due to underlying JavaMail based impl.
// The term compares each mail if matching.
public static class UidSearchTerm extends SearchTerm {
/**
* Supports general searching by id sequences such as MSN or UID.
*
* Note:
* Not very efficient due to underlying JavaMail based impl.
* The term compares each mail if matching.
*
* @see MessageNumberSearchTerm
* @see UidSearchTerm
*/
public abstract static class AbstractIdSearchTerm extends SearchTerm {
private static final long serialVersionUID = -5935470270189992292L;
private final List<IdRange> idRanges;

public AbstractIdSearchTerm(final List<IdRange> idRanges) {
this.idRanges = idRanges;
}

@Override
public abstract boolean match(Message msg);

/**
* Matches id against sequence numbers.
*
* @param id the identifier
* @return true, if matching
*/
public boolean match(final long id) {
for (IdRange idRange : idRanges) {
if (idRange.includes(id)) {
return true;
}
}
return false;
}
}

/**
* Term for searching by message number ids.
*/
public static class MessageNumberSearchTerm extends AbstractIdSearchTerm {
private static final long serialVersionUID = -2792493451441320161L;

/**
* @param idRanges the MSNs to search for.
*/
public MessageNumberSearchTerm(List<IdRange> idRanges) {
super(idRanges);
}

@Override
public boolean match(Message msg) {
return match(msg.getMessageNumber());
}
}

/**
* Term for searching uids.
*/
public static class UidSearchTerm extends AbstractIdSearchTerm {
private static final long serialVersionUID = 1135219503729412087L;
private final List<IdRange> uidSetList;

public UidSearchTerm(List<IdRange> uidSetList) {
this.uidSetList = uidSetList;
/**
* @param idRanges the UIDs to search for.
*/
public UidSearchTerm(List<IdRange> idRanges) {
super(idRanges);
}

@Override
Expand All @@ -292,14 +364,5 @@ public boolean match(Message msg) {
return false;
}
}

public boolean match(long uid) {
for (IdRange uidSet : uidSetList) {
if (uidSet.includes(uid)) {
return true;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,28 @@

import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import java.io.UnsupportedEncodingException;
import java.util.regex.Pattern;

public class MailAddress {
String host;
String user;
String email;
String name;

static final Pattern RFC6531_VALIDATION_PATTERN = Pattern.compile("[^\\s@]+@[^\\s@]+\\.[^\\s@]+");

public MailAddress(String str)
throws AddressException {
InternetAddress address = new InternetAddress(str);

// Decoding the mail address in
// case it contains non us-ascii characters
String decoded = decodeStr(str);

assertValidEmailAddress(decoded);
InternetAddress address = new InternetAddress();
address.setAddress(decoded);
email = address.getAddress();
name = address.getPersonal();

Expand Down Expand Up @@ -51,4 +63,29 @@ public String getEmail() {
return email;
}

private void assertValidEmailAddress(String str) {

if (str == null || !RFC6531_VALIDATION_PATTERN.matcher(str).matches()) {
new AddressException("Invalid email address!");
}
}

/**
* Returns the decoded string, in case it contains non us-ascii characters.
* Returns the same string if it doesn't or the passed value in case
* of an UnsupportedEncodingException.
*
* @param str string to be decoded
* @return the decoded string, in case it contains non us-ascii characters;
* or the same string if it doesn't or the passed value in case
* of an UnsupportedEncodingException.
*/
private String decodeStr(String str) {

try {
return MimeUtility.decodeText(str);
} catch (UnsupportedEncodingException e) {
return str;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.icegreen.greenmail.pop3.commands.Pop3Command;
import com.icegreen.greenmail.pop3.commands.Pop3CommandRegistry;
import com.icegreen.greenmail.server.BuildInfo;
import com.icegreen.greenmail.server.ProtocolHandler;
import com.icegreen.greenmail.user.UserManager;

Expand Down Expand Up @@ -63,7 +64,7 @@ public void run() {
}

void sendGreetings() {
_conn.println("+OK POP3 GreenMail Server ready");
_conn.println("+OK POP3 GreenMail Server v" + BuildInfo.INSTANCE.getProjectVersion() + " ready");
}

void handleCommand()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ public final void stopService() {
* @return the session.
*/
public Session createSession(Properties properties) {
return createSession(properties, false);
return createSession(properties, setup.isVerbose());
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.icegreen.greenmail.server;

/**
* Defines project build info such as version.
*
* Note: Actual values will be replaced by build compilation
*/
public enum BuildInfo {
INSTANCE;

/**
* @return the project version
*/
public String getProjectVersion() {
return "<replaced>";
}
}
Loading

0 comments on commit bfc0aee

Please sign in to comment.