001    /*
002     * Copyright 2010 the original author or authors.
003     * 
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package com.hs.mail.smtp.processor;
017    
018    import java.util.StringTokenizer;
019    
020    import com.hs.mail.container.config.Config;
021    import com.hs.mail.container.server.socket.TcpTransport;
022    import com.hs.mail.smtp.SmtpException;
023    import com.hs.mail.smtp.SmtpSession;
024    import com.hs.mail.smtp.message.MailAddress;
025    import com.hs.mail.smtp.message.SmtpMessage;
026    
027    /**
028     * Handler for MAIL command. Starts a mail transaction to deliver mail as the
029     * stated sender.
030     * 
031     * @author Won Chul Doh
032     * @since May 29, 2010
033     * 
034     */
035    public class MailProcessor extends AbstractSmtpProcessor {
036    
037            @Override
038            protected void doProcess(SmtpSession session, TcpTransport trans,
039                            StringTokenizer st) throws SmtpException {
040                    // In general, the MAIL command may be sent only when no mail
041                    // transaction is in progress.
042                    SmtpMessage message = session.getMessage();
043                    if (session.getClientDomain() == null || message != null) {
044                            throw new SmtpException(SmtpException.COMMAND_OUT_OF_SEQUENCE);
045                    }
046                    if (Config.isSaslAuthEnabled() && session.getAuthID() < 0) {
047                            throw new SmtpException(SmtpException.AUTH_REQUIRED);
048                    }
049                    if (st.countTokens() < 1) {
050                            throw new SmtpException(SmtpException.INVALID_COMMAND_PARAM);
051                    }
052                    String sender = nextToken(st);
053                    if (!startsWith(sender, "FROM:")) {
054                            throw new SmtpException(SmtpException.INVALID_COMMAND_PARAM);
055                    }
056                    if (sender.length() == 5) {
057                            if (!st.hasMoreTokens())
058                                    throw new SmtpException(SmtpException.MISSING_SENDER_ADDRESS);
059                            sender = nextToken(st);
060                    } else {
061                            sender = sender.substring(5);
062                    }
063                    int lastChar = sender.indexOf('>', sender.indexOf('<'));
064                    if ((lastChar > 0) && (sender.length() > lastChar + 2)
065                                    && (sender.charAt(lastChar) + 1) == ' ') {
066                            String options = sender.substring(lastChar + 2);
067                            sender = sender.substring(0, lastChar + 2);
068                            
069                            StringTokenizer optSt = new StringTokenizer(options, " ");
070                            while (optSt.hasMoreElements()) {
071                                    String option = optSt.nextToken();
072                                    int i = option.indexOf('=');
073                                    String key = option;
074                                    String value = "";
075                                    if (i > 0) {
076                                            key = option.substring(0, i).toUpperCase();
077                                            value = option.substring(i + 1);
078                                    }
079                                    if ("SIZE".equals(key)) {
080                                            // Handle the SIZE extension keyword
081                                            doMailSize(session, value);
082                                    } else {
083                                            
084                                    }
085                            }
086                    }
087                    
088                    MailAddress from = null;
089                    if ("<>".equals(sender)) {
090                            // In the case of delivery notification message, the reverse-path is
091                            // set to null.
092                            from = new MailAddress();
093                    } else {
094                            from = new MailAddress(sender);
095                    }
096                    // Initiate a mail transaction
097                    session.createSmtpMessage(from);
098                    StringBuilder sb = new StringBuilder().append("250 ")
099                                    .append("2.1.0")
100                                    .append(" Sender <")
101                                    .append(from.getMailbox())
102                                    .append("> OK");
103                    session.writeResponse(sb.toString());
104            }
105    
106            private void doMailSize(SmtpSession session, String value)
107                            throws SmtpException {
108                    int size = 0;
109                    try {
110                            size = Integer.parseInt(value);
111                    } catch (NumberFormatException ex) {
112                            logger.error("Rejected syntactically incorrect value '" + value
113                                            + "' for SIZE parameter.");
114                            throw new SmtpException(SmtpException.INVALID_SIZE_PARAM);
115                    }
116                    long maxMessageSize = Config.getMaxMessageSize();
117                    if ((maxMessageSize > 0) && (size > maxMessageSize)) {
118                            StringBuilder errorBuffer = new StringBuilder(256)
119                                            .append("Rejected message from ")
120                                            .append(session.getClientDomain())
121                                            .append(" from host ")
122                                            .append(session.getRemoteHost())
123                                            .append(" (")
124                                            .append(session.getRemoteIP())
125                                            .append(") exceeding system maximum message size of ")
126                                            .append(maxMessageSize)
127                                            .append(" based on SIZE option.");
128                            logger.error(errorBuffer.toString());
129                            throw new SmtpException(SmtpException.MESSAGE_SIZE_LIMIT);
130                    }
131            }
132            
133    }