forked from I2P_Developers/i2p.i2p
* SusiMail:
- Use pipelining in SMTP - Rewrite SMTP response processing - Translate SMTP error messages - Right-justify msg size in folder view - String.compareTo() cleanup
This commit is contained in:
@@ -415,10 +415,10 @@ public class WebMail extends HttpServlet
|
||||
}
|
||||
|
||||
if( mailPart.multipart ) {
|
||||
if( mailPart.type.compareTo( "multipart/alternative" ) == 0 ) {
|
||||
if( mailPart.type.equals("multipart/alternative")) {
|
||||
MailPart chosen = null;
|
||||
for( MailPart subPart : mailPart.parts ) {
|
||||
if( subPart.type != null && subPart.type.compareTo( "text/plain" ) == 0 )
|
||||
if( subPart.type != null && subPart.type.equals("text/plain"))
|
||||
chosen = subPart;
|
||||
}
|
||||
if( chosen != null ) {
|
||||
@@ -454,7 +454,7 @@ public class WebMail extends HttpServlet
|
||||
showBody = true;
|
||||
}
|
||||
if( showBody == false && mailPart.type != null ) {
|
||||
if( mailPart.type.compareTo( "text/plain" ) == 0 ) {
|
||||
if( mailPart.type.equals("text/plain")) {
|
||||
showBody = true;
|
||||
}
|
||||
else
|
||||
@@ -559,7 +559,7 @@ public class WebMail extends HttpServlet
|
||||
String pop3Port = request.getParameter( POP3 );
|
||||
String smtpPort = request.getParameter( SMTP );
|
||||
String fixedPorts = Config.getProperty( CONFIG_PORTS_FIXED, "true" );
|
||||
if( fixedPorts.compareToIgnoreCase( "false" ) != 0 ) {
|
||||
if( !fixedPorts.equalsIgnoreCase("false")) {
|
||||
host = Config.getProperty( CONFIG_HOST, DEFAULT_HOST );
|
||||
pop3Port = Config.getProperty( CONFIG_PORTS_POP3, "" + DEFAULT_POP3PORT );
|
||||
smtpPort = Config.getProperty( CONFIG_PORTS_SMTP, "" + DEFAULT_SMTPPORT );
|
||||
@@ -885,7 +885,7 @@ public class WebMail extends HttpServlet
|
||||
private static int getCheckedMessage(RequestWrapper request) {
|
||||
for( Enumeration<String> e = request.getParameterNames(); e.hasMoreElements(); ) {
|
||||
String parameter = e.nextElement();
|
||||
if( parameter.startsWith( "check" ) && request.getParameter( parameter ).compareTo( "1" ) == 0 ) {
|
||||
if( parameter.startsWith( "check" ) && request.getParameter( parameter ).equals("1")) {
|
||||
String number = parameter.substring( 5 );
|
||||
try {
|
||||
int n = Integer.parseInt( number );
|
||||
@@ -972,7 +972,7 @@ public class WebMail extends HttpServlet
|
||||
else if( sessionObject.attachments != null && buttonPressed( request, DELETE_ATTACHMENT ) ) {
|
||||
for( Enumeration<String> e = request.getParameterNames(); e.hasMoreElements(); ) {
|
||||
String parameter = e.nextElement();
|
||||
if( parameter.startsWith( "check" ) && request.getParameter( parameter ).compareTo( "1" ) == 0 ) {
|
||||
if( parameter.startsWith( "check" ) && request.getParameter( parameter ).equals("1")) {
|
||||
String number = parameter.substring( 5 );
|
||||
try {
|
||||
int n = Integer.parseInt( number );
|
||||
@@ -1119,7 +1119,7 @@ public class WebMail extends HttpServlet
|
||||
if( buttonPressed( request, REALLYDELETE ) ) {
|
||||
for( Enumeration<String> e = request.getParameterNames(); e.hasMoreElements(); ) {
|
||||
String parameter = e.nextElement();
|
||||
if( parameter.startsWith( "check" ) && request.getParameter( parameter ).compareTo( "1" ) == 0 ) {
|
||||
if( parameter.startsWith( "check" ) && request.getParameter( parameter ).equals("1")) {
|
||||
String number = parameter.substring( 5 );
|
||||
try {
|
||||
int n = Integer.parseInt( number );
|
||||
@@ -1170,11 +1170,11 @@ public class WebMail extends HttpServlet
|
||||
{
|
||||
String str = request.getParameter( sort_id );
|
||||
if( str != null ) {
|
||||
if( str.compareToIgnoreCase( "up" ) == 0 ) {
|
||||
if( str.equalsIgnoreCase("up")) {
|
||||
sessionObject.folder.setSortingDirection( Folder.UP );
|
||||
sessionObject.folder.sortBy( sort_id );
|
||||
}
|
||||
if( str.compareToIgnoreCase( "down" ) == 0 ) {
|
||||
if( str.equalsIgnoreCase("down")) {
|
||||
sessionObject.folder.setSortingDirection( Folder.DOWN );
|
||||
sessionObject.folder.sortBy( sort_id );
|
||||
}
|
||||
@@ -1471,7 +1471,7 @@ public class WebMail extends HttpServlet
|
||||
|
||||
String prop = Config.getProperty( CONFIG_SENDER_FIXED, "true" );
|
||||
String domain = Config.getProperty( CONFIG_SENDER_DOMAIN, "mail.i2p" );
|
||||
if( prop.compareToIgnoreCase( "false" ) != 0 ) {
|
||||
if( !prop.equalsIgnoreCase("false")) {
|
||||
from = "<" + sessionObject.user + "@" + domain + ">";
|
||||
}
|
||||
ArrayList<String> toList = new ArrayList<String>();
|
||||
@@ -1503,7 +1503,7 @@ public class WebMail extends HttpServlet
|
||||
|
||||
String bccToSelf = request.getParameter( NEW_BCC_TO_SELF );
|
||||
|
||||
if( bccToSelf != null && bccToSelf.compareTo( "1" ) == 0 )
|
||||
if( bccToSelf != null && bccToSelf.equals("1"))
|
||||
recipients.add( sender );
|
||||
|
||||
if( toList.isEmpty() ) {
|
||||
@@ -1619,7 +1619,7 @@ public class WebMail extends HttpServlet
|
||||
String from = request.getParameter( NEW_FROM );
|
||||
String fixed = Config.getProperty( CONFIG_SENDER_FIXED, "true" );
|
||||
|
||||
if( from == null || fixed.compareToIgnoreCase( "false" ) != 0 ) {
|
||||
if( from == null || !fixed.equalsIgnoreCase("false")) {
|
||||
String domain = Config.getProperty( CONFIG_SENDER_DOMAIN, "mail.i2p" );
|
||||
from = "<" + sessionObject.user + "@" + domain + ">";
|
||||
}
|
||||
@@ -1637,12 +1637,12 @@ public class WebMail extends HttpServlet
|
||||
|
||||
out.println( "<table cellspacing=\"0\" cellpadding=\"5\">\n" +
|
||||
"<tr><td colspan=\"2\" align=\"center\"><hr></td></tr>\n" +
|
||||
"<tr><td align=\"right\">" + _("From:") + "</td><td align=\"left\"><input type=\"text\" size=\"80\" name=\"" + NEW_FROM + "\" value=\"" + from + "\" " + ( fixed.compareToIgnoreCase( "false" ) != 0 ? "disabled" : "" ) +"></td></tr>\n" +
|
||||
"<tr><td align=\"right\">" + _("From:") + "</td><td align=\"left\"><input type=\"text\" size=\"80\" name=\"" + NEW_FROM + "\" value=\"" + from + "\" " + ( !fixed.equalsIgnoreCase("false") ? "disabled" : "" ) +"></td></tr>\n" +
|
||||
"<tr><td align=\"right\">" + _("To:") + "</td><td align=\"left\"><input type=\"text\" size=\"80\" name=\"" + NEW_TO + "\" value=\"" + to + "\"></td></tr>\n" +
|
||||
"<tr><td align=\"right\">" + _("Cc:") + "</td><td align=\"left\"><input type=\"text\" size=\"80\" name=\"" + NEW_CC + "\" value=\"" + cc + "\"></td></tr>\n" +
|
||||
"<tr><td align=\"right\">" + _("Bcc:") + "</td><td align=\"left\"><input type=\"text\" size=\"80\" name=\"" + NEW_BCC + "\" value=\"" + bcc + "\"></td></tr>\n" +
|
||||
"<tr><td align=\"right\">" + _("Subject:") + "</td><td align=\"left\"><input type=\"text\" size=\"80\" name=\"" + NEW_SUBJECT + "\" value=\"" + subject + "\"></td></tr>\n" +
|
||||
"<tr><td> </td><td align=\"left\"><input type=\"checkbox\" class=\"optbox\" name=\"" + NEW_BCC_TO_SELF + "\" value=\"1\"" + ( bccToSelf.compareToIgnoreCase( "false" ) != 0 ? "checked" : "" )+ ">" + _("Bcc to self") + "</td></tr>\n" +
|
||||
"<tr><td> </td><td align=\"left\"><input type=\"checkbox\" class=\"optbox\" name=\"" + NEW_BCC_TO_SELF + "\" value=\"1\"" + ( !bccToSelf.equalsIgnoreCase("false") ? "checked" : "" )+ ">" + _("Bcc to self") + "</td></tr>\n" +
|
||||
"<tr><td colspan=\"2\" align=\"center\"><textarea cols=\"" + Config.getProperty( CONFIG_COMPOSER_COLS, 80 )+ "\" rows=\"" + Config.getProperty( CONFIG_COMPOSER_ROWS, 10 )+ "\" name=\"" + NEW_TEXT + "\">" + text + "</textarea>" +
|
||||
"<tr><td colspan=\"2\" align=\"center\"><hr></td></tr>\n" +
|
||||
"<tr><td align=\"right\">" + _("New Attachment:") + "</td><td align=\"left\"><input type=\"file\" size=\"50%\" name=\"" + NEW_FILENAME + "\" value=\"\"><input type=\"submit\" name=\"" + NEW_UPLOAD + "\" value=\"" + _("Upload File") + "\"></td></tr>" );
|
||||
@@ -1668,7 +1668,7 @@ public class WebMail extends HttpServlet
|
||||
private static void showLogin( PrintWriter out )
|
||||
{
|
||||
String fixedPorts = Config.getProperty( CONFIG_PORTS_FIXED, "true" );
|
||||
boolean fixed = fixedPorts.compareToIgnoreCase( "false" ) != 0;
|
||||
boolean fixed = !fixedPorts.equalsIgnoreCase("false");
|
||||
String host = Config.getProperty( CONFIG_HOST, DEFAULT_HOST );
|
||||
String pop3 = Config.getProperty( CONFIG_PORTS_POP3, "" + DEFAULT_POP3PORT );
|
||||
String smtp = Config.getProperty( CONFIG_PORTS_SMTP, "" + DEFAULT_SMTPPORT );
|
||||
@@ -1747,7 +1747,7 @@ public class WebMail extends HttpServlet
|
||||
boolean idChecked = false;
|
||||
String checkId = sessionObject.pageChanged ? null : request.getParameter( "check" + i );
|
||||
|
||||
if( checkId != null && checkId.compareTo( "1" ) == 0 )
|
||||
if( checkId != null && checkId.equals("1"))
|
||||
idChecked = true;
|
||||
|
||||
if( sessionObject.markAll )
|
||||
@@ -1765,7 +1765,7 @@ public class WebMail extends HttpServlet
|
||||
( idChecked ? "checked" : "" ) + ">" + "</td><td>" +
|
||||
link + mail.shortSender + "</a></td><td> </td><td>" + link + mail.shortSubject + "</a></td><td> </td><td>" +
|
||||
// don't let date get split across lines
|
||||
mail.localFormattedDate.replace(" ", " ") + "</td><td> </td><td>" +
|
||||
mail.localFormattedDate.replace(" ", " ") + "</td><td> </td><td align=\"right\">" +
|
||||
DataHelper.formatSize2(mail.size) + "B</td></tr>" );
|
||||
bg = 1 - bg;
|
||||
i++;
|
||||
|
@@ -24,6 +24,7 @@
|
||||
package i2p.susi.webmail.smtp;
|
||||
|
||||
import i2p.susi.debug.Debug;
|
||||
import i2p.susi.webmail.Messages;
|
||||
import i2p.susi.webmail.encoding.Encoding;
|
||||
import i2p.susi.webmail.encoding.EncodingException;
|
||||
import i2p.susi.webmail.encoding.EncodingFactory;
|
||||
@@ -32,6 +33,10 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.i2p.data.DataHelper;
|
||||
|
||||
/**
|
||||
* @author susi
|
||||
@@ -42,6 +47,7 @@ public class SMTPClient {
|
||||
private final byte buffer[];
|
||||
public String error;
|
||||
private String lastResponse;
|
||||
private boolean supportsPipelining;
|
||||
|
||||
private static final Encoding base64;
|
||||
|
||||
@@ -72,61 +78,126 @@ public class SMTPClient {
|
||||
* @since 0.9.13
|
||||
*/
|
||||
private int sendCmd(String cmd, boolean shouldWait)
|
||||
{
|
||||
if( socket == null )
|
||||
return 0;
|
||||
try {
|
||||
if (cmd != null)
|
||||
sendCmdNoWait(cmd);
|
||||
if (!shouldWait)
|
||||
return 100;
|
||||
socket.getOutputStream().flush();
|
||||
return getResult();
|
||||
} catch (IOException e) {
|
||||
error += "IOException occured.<br>";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not flush, wait, or read
|
||||
*
|
||||
* @param cmd non-null
|
||||
* @since 0.9.13
|
||||
*/
|
||||
private void sendCmdNoWait(String cmd) throws IOException
|
||||
{
|
||||
Debug.debug( Debug.DEBUG, "SMTP sendCmd(" + cmd +")" );
|
||||
|
||||
if( socket == null )
|
||||
return 0;
|
||||
|
||||
int result = 0;
|
||||
lastResponse = "";
|
||||
|
||||
try {
|
||||
InputStream in = socket.getInputStream();
|
||||
throw new IOException("no socket");
|
||||
OutputStream out = socket.getOutputStream();
|
||||
|
||||
if( cmd != null ) {
|
||||
cmd += "\r\n";
|
||||
out.write( cmd.getBytes() );
|
||||
}
|
||||
if (!shouldWait)
|
||||
return 100;
|
||||
out.flush();
|
||||
String str = "";
|
||||
boolean doContinue = true;
|
||||
while( doContinue ) {
|
||||
if( in.available() > 0 ) {
|
||||
int read = in.read( buffer );
|
||||
str += new String( buffer, 0, read );
|
||||
lastResponse += str;
|
||||
while( true ) {
|
||||
int i = str.indexOf( "\r\n" );
|
||||
if( i == -1 )
|
||||
|
||||
/**
|
||||
* Pipeline if supported
|
||||
*
|
||||
* @param cmds non-null
|
||||
* @return number of successful commands
|
||||
* @since 0.9.13
|
||||
*/
|
||||
private int sendCmds(List<SendExpect> cmds)
|
||||
{
|
||||
int rv = 0;
|
||||
if (supportsPipelining) {
|
||||
Debug.debug(Debug.DEBUG, "SMTP pipelining " + cmds.size() + " commands");
|
||||
try {
|
||||
for (SendExpect cmd : cmds) {
|
||||
sendCmdNoWait(cmd.send);
|
||||
}
|
||||
socket.getOutputStream().flush();
|
||||
} catch (IOException ioe) {
|
||||
return 0;
|
||||
}
|
||||
for (SendExpect cmd : cmds) {
|
||||
int r = getResult();
|
||||
// stop only on EOF
|
||||
if (r == 0)
|
||||
break;
|
||||
if (r == cmd.expect)
|
||||
rv++;
|
||||
}
|
||||
} else {
|
||||
for (SendExpect cmd : cmds) {
|
||||
int r = sendCmd(cmd.send);
|
||||
// stop at first error
|
||||
if (r != cmd.expect)
|
||||
break;
|
||||
rv++;
|
||||
}
|
||||
}
|
||||
Debug.debug(Debug.DEBUG, "SMTP success in " + rv + " of " + cmds.size() + " commands");
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return result code or 0 for failure
|
||||
* @since 0.9.13
|
||||
*/
|
||||
private int getResult() {
|
||||
return getFullResult().result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return result code and string, all lines combined with \r separators,
|
||||
* first 3 bytes are the ASCII return code or "000" for failure
|
||||
* Result and Result.recv non null
|
||||
* @since 0.9.13
|
||||
*/
|
||||
private Result getFullResult() {
|
||||
int result = 0;
|
||||
StringBuilder fullResponse = new StringBuilder(512);
|
||||
try {
|
||||
InputStream in = socket.getInputStream();
|
||||
StringBuilder buf = new StringBuilder(128);
|
||||
while (DataHelper.readLine(in, buf)) {
|
||||
Debug.debug(Debug.DEBUG, "SMTP rcv \"" + buf.toString().trim() + '"');
|
||||
int len = buf.length();
|
||||
if (len < 4) {
|
||||
result = 0;
|
||||
break; // huh? no nnn\r?
|
||||
}
|
||||
if( result == 0 ) {
|
||||
try {
|
||||
result = Integer.parseInt( str.substring( 0, 3 ) );
|
||||
}
|
||||
catch( NumberFormatException nfe ) {
|
||||
result = 0;
|
||||
doContinue = false;
|
||||
String r = buf.substring(0, 3);
|
||||
result = Integer.parseInt(r);
|
||||
} catch ( NumberFormatException nfe ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( str.substring( 3, 4 ).compareTo( " " ) == 0 ) {
|
||||
doContinue = false;
|
||||
fullResponse.append(buf.substring(4));
|
||||
if (buf.charAt(3) == ' ')
|
||||
break;
|
||||
buf.setLength(0);
|
||||
}
|
||||
str = str.substring( i + 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
} catch (IOException e) {
|
||||
error += "IOException occured.<br>";
|
||||
result = 0;
|
||||
}
|
||||
return result;
|
||||
lastResponse = fullResponse.toString();
|
||||
return new Result(result, lastResponse);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,60 +210,118 @@ public class SMTPClient {
|
||||
|
||||
try {
|
||||
socket = new Socket( host, port );
|
||||
}
|
||||
catch (Exception e) {
|
||||
error += "Cannot connect: " + e.getMessage() + "<br>";
|
||||
} catch (Exception e) {
|
||||
error += _("Cannot connect") + ": " + e.getMessage() + "<br>";
|
||||
ok = false;
|
||||
}
|
||||
try {
|
||||
if( ok && sendCmd( null ) == 220 &&
|
||||
sendCmd( "EHLO localhost" ) == 250 &&
|
||||
sendCmd( "AUTH LOGIN" ) == 334 &&
|
||||
sendCmd( base64.encode( user ) ) == 334 &&
|
||||
sendCmd( base64.encode( pass ) ) == 235 &&
|
||||
sendCmd( "MAIL FROM: " + sender ) == 250 ) {
|
||||
|
||||
for( int i = 0; i < recipients.length; i++ ) {
|
||||
if( sendCmd( "RCPT TO: " + recipients[i] ) != 250 ) {
|
||||
// SMTP ref: RFC 821
|
||||
// Pipelining ref: RFC 2920
|
||||
// AUTH ref: RFC 4954
|
||||
if (ok) {
|
||||
int result = sendCmd(null);
|
||||
if (result != 220) {
|
||||
error += _("Server refused connection") + " (" + result + ")<br>";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if( ok ) {
|
||||
if( sendCmd( "DATA" ) == 354 ) {
|
||||
if (ok) {
|
||||
sendCmdNoWait( "EHLO localhost" );
|
||||
socket.getOutputStream().flush();
|
||||
Result r = getFullResult();
|
||||
if (r.result == 250) {
|
||||
supportsPipelining = r.recv.contains("PIPELINING");
|
||||
} else {
|
||||
error += _("Server refused connection") + " (" + r.result + ")<br>";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
// RFC 4954 says AUTH must be the last but let's assume
|
||||
// that includes the user/pass on following lines
|
||||
List<SendExpect> cmds = new ArrayList<SendExpect>();
|
||||
cmds.add(new SendExpect("AUTH LOGIN", 334));
|
||||
cmds.add(new SendExpect(base64.encode(user), 334));
|
||||
cmds.add(new SendExpect(base64.encode(pass), 235));
|
||||
if (sendCmds(cmds) != 3) {
|
||||
error += _("Login failed") + "<br>";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
List<SendExpect> cmds = new ArrayList<SendExpect>();
|
||||
cmds.add(new SendExpect("MAIL FROM: " + sender, 250));
|
||||
for( int i = 0; i < recipients.length; i++ ) {
|
||||
cmds.add(new SendExpect("RCPT TO: " + recipients[i], 250));
|
||||
}
|
||||
cmds.add(new SendExpect("DATA", 354));
|
||||
if (sendCmds(cmds) != cmds.size()) {
|
||||
// TODO which recipient?
|
||||
error += _("Mail rejected") + "<br>";
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
if( body.indexOf( "\r\n.\r\n" ) != -1 )
|
||||
body = body.replaceAll( "\r\n.\r\n", "\r\n..\r\n" );
|
||||
body += "\r\n.\r\n";
|
||||
try {
|
||||
socket.getOutputStream().write( body.getBytes() );
|
||||
if( sendCmd( null ) == 250 ) {
|
||||
socket.getOutputStream().write("\r\n.\r\n".getBytes() );
|
||||
int result = sendCmd(null);
|
||||
if (result == 250)
|
||||
mailSent = true;
|
||||
else
|
||||
error += _("Error sending mail") + " (" + result + ")<br>";
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
ok = false;
|
||||
error += "Error while sending mail: " + e.getMessage() + "<br>";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
error += _("Error sending mail") + ": " + e.getMessage() + "<br>";
|
||||
|
||||
} catch (EncodingException e) {
|
||||
ok = false;
|
||||
error += e.getMessage();
|
||||
}
|
||||
if( !mailSent && lastResponse.length() > 0 ) {
|
||||
String[] lines = lastResponse.split( "\r\n" );
|
||||
String[] lines = lastResponse.split( "\r" );
|
||||
for( int i = 0; i < lines.length; i++ )
|
||||
error += lines[i] + "<br>";
|
||||
}
|
||||
sendCmd("QUIT", false );
|
||||
sendCmd("QUIT", false);
|
||||
if( socket != null ) {
|
||||
try {
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e1) {
|
||||
// ignore
|
||||
}
|
||||
} catch (IOException e1) {}
|
||||
}
|
||||
return mailSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* A command to send and a result code to expect
|
||||
* @since 0.9.13
|
||||
*/
|
||||
private static class SendExpect {
|
||||
public final String send;
|
||||
public final int expect;
|
||||
|
||||
public SendExpect(String s, int e) {
|
||||
send = s;
|
||||
expect = e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A result string and code
|
||||
* @since 0.9.13
|
||||
*/
|
||||
private static class Result {
|
||||
public final int result;
|
||||
public final String recv;
|
||||
|
||||
public Result(int r, String t) {
|
||||
result = r;
|
||||
recv = t;
|
||||
}
|
||||
}
|
||||
|
||||
/** translate */
|
||||
private static String _(String s) {
|
||||
return Messages.getString(s);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user