001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.net.smtp;
019
020import java.io.BufferedReader;
021import java.io.BufferedWriter;
022import java.io.IOException;
023import java.io.InputStreamReader;
024import java.io.OutputStreamWriter;
025import java.util.ArrayList;
026
027import org.apache.commons.net.MalformedServerReplyException;
028import org.apache.commons.net.ProtocolCommandSupport;
029import org.apache.commons.net.SocketClient;
030import org.apache.commons.net.io.CRLFLineReader;
031import org.apache.commons.net.util.NetConstants;
032
033/**
034 * SMTP provides the basic the functionality necessary to implement your
035 * own SMTP client.  To derive the full benefits of the SMTP class requires
036 * some knowledge of the FTP protocol defined in RFC 821.  However, there
037 * is no reason why you should have to use the SMTP class.  The
038 * {@link org.apache.commons.net.smtp.SMTPClient} class,
039 * derived from SMTP,
040 * implements all the functionality required of an SMTP client.  The
041 * SMTP class is made public to provide access to various SMTP constants
042 * and to make it easier for adventurous programmers (or those with
043 * special needs) to interact with the SMTP protocol and implement their
044 * own clients.  A set of methods with names corresponding to the SMTP
045 * command names are provided to facilitate this interaction.
046 * <p>
047 * You should keep in mind that the SMTP server may choose to prematurely
048 * close a connection for various reasons.  The SMTP class will detect a
049 * premature SMTP server connection closing when it receives a
050 * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE }
051 *  response to a command.
052 * When that occurs, the SMTP class method encountering that reply will throw
053 * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException}
054 * .
055 * <code>SMTPConectionClosedException</code>
056 * is a subclass of <code> IOException </code> and therefore need not be
057 * caught separately, but if you are going to catch it separately, its
058 * catch block must appear before the more general <code> IOException </code>
059 * catch block.  When you encounter an
060 * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException}
061 * , you must disconnect the connection with
062 * {@link org.apache.commons.net.SocketClient#disconnect  disconnect() }
063 * to properly clean up the system resources used by SMTP.  Before
064 * disconnecting, you may check the
065 * last reply code and text with
066 * {@link #getReplyCode  getReplyCode },
067 * {@link #getReplyString  getReplyString },
068 * and {@link #getReplyStrings  getReplyStrings}.
069 * <p>
070 * Rather than list it separately for each method, we mention here that
071 * every method communicating with the server and throwing an IOException
072 * can also throw a
073 * {@link org.apache.commons.net.MalformedServerReplyException}
074 * , which is a subclass
075 * of IOException.  A MalformedServerReplyException will be thrown when
076 * the reply received from the server deviates enough from the protocol
077 * specification that it cannot be interpreted in a useful manner despite
078 * attempts to be as lenient as possible.
079 *
080 * @see SMTPClient
081 * @see SMTPConnectionClosedException
082 * @see org.apache.commons.net.MalformedServerReplyException
083 */
084
085public class SMTP extends SocketClient
086{
087    /** The default SMTP port (25). */
088    public static final int DEFAULT_PORT = 25;
089
090    // We have to ensure that the protocol communication is in ASCII
091    // but we use ISO-8859-1 just in case 8-bit characters cross
092    // the wire.
093    private static final String DEFAULT_ENCODING = "ISO-8859-1";
094
095    /**
096     * The encoding to use (user-settable).
097     *
098     * @since 3.1 (changed from private to protected)
099     */
100    protected final String encoding;
101
102    /**
103     * A ProtocolCommandSupport object used to manage the registering of
104     * ProtocolCommandListeners and te firing of ProtocolCommandEvents.
105     */
106    protected ProtocolCommandSupport _commandSupport_;
107
108    BufferedReader reader;
109    BufferedWriter writer;
110
111    private int replyCode;
112    private final ArrayList<String> replyLines;
113    private boolean newReplyString;
114    private String replyString;
115
116    /**
117     * The default SMTP constructor.  Sets the default port to
118     * <code>DEFAULT_PORT</code> and initializes internal data structures
119     * for saving SMTP reply information.
120     */
121    public SMTP()
122    {
123        this(DEFAULT_ENCODING);
124    }
125
126    /**
127     * Overloaded constructor where the user may specify a default encoding.
128     * @param encoding the encoing to use
129     * @since 2.0
130     */
131    public SMTP(final String encoding) {
132        setDefaultPort(DEFAULT_PORT);
133        replyLines = new ArrayList<>();
134        newReplyString = false;
135        replyString = null;
136        _commandSupport_ = new ProtocolCommandSupport(this);
137        this.encoding = encoding;
138    }
139
140    /**
141     * Send a command to the server. May also be used to send text data.
142     *
143     * @param command the command to send (as a plain String)
144     * @param args the command arguments, may be {@code null}
145     * @param includeSpace if {@code true}, add a space between the command and its arguments
146     * @return the reply code
147     * @throws IOException
148     */
149    private int sendCommand(final String command, final String args, final boolean includeSpace)
150    throws IOException
151    {
152        final StringBuilder __commandBuffer = new StringBuilder();
153        __commandBuffer.append(command);
154
155        if (args != null)
156        {
157            if (includeSpace) {
158                __commandBuffer.append(' ');
159            }
160            __commandBuffer.append(args);
161        }
162
163        __commandBuffer.append(SocketClient.NETASCII_EOL);
164
165        final String message = __commandBuffer.toString();
166        writer.write(message);
167        writer.flush();
168
169        fireCommandSent(command, message);
170
171        return getReply();
172    }
173
174    /**
175     *
176     * @param command the command to send (as an int defined in {@link SMPTCommand})
177     * @param args the command arguments, may be {@code null}
178     * @param includeSpace if {@code true}, add a space between the command and its arguments
179     * @return the reply code
180     * @throws IOException
181     */
182    private int sendCommand(final int command, final String args, final boolean includeSpace)
183    throws IOException
184    {
185        return sendCommand(SMTPCommand.getCommand(command), args, includeSpace);
186    }
187
188    /** Initiates control connections and gets initial reply. */
189    @Override
190    protected void _connectAction_() throws IOException
191    {
192        super._connectAction_();
193        reader =
194            new CRLFLineReader(new InputStreamReader(_input_,
195                                                    encoding));
196        writer =
197            new BufferedWriter(new OutputStreamWriter(_output_,
198                                                      encoding));
199        getReply();
200    }
201
202
203    /**
204     * Closes the connection to the SMTP server and sets to null
205     * some internal data so that the memory may be reclaimed by the
206     * garbage collector.  The reply text and code information from the
207     * last command is voided so that the memory it used may be reclaimed.
208     * <p>
209     * @throws IOException If an error occurs while disconnecting.
210     */
211    @Override
212    public void disconnect() throws IOException
213    {
214        super.disconnect();
215        reader = null;
216        writer = null;
217        replyString = null;
218        replyLines.clear();
219        newReplyString = false;
220    }
221
222
223    /**
224     * Sends an SMTP command to the server, waits for a reply and returns the
225     * numerical response code.  After invocation, for more detailed
226     * information, the actual reply text can be accessed by calling
227     * {@link #getReplyString  getReplyString } or
228     * {@link #getReplyStrings  getReplyStrings }.
229     * <p>
230     * @param command  The text representation of the  SMTP command to send.
231     * @param args The arguments to the SMTP command.  If this parameter is
232     *             set to null, then the command is sent with no argument.
233     * @return The integer value of the SMTP reply code returned by the server
234     *         in response to the command.
235     * @throws SMTPConnectionClosedException
236     *      If the SMTP server prematurely closes the connection as a result
237     *      of the client being idle or some other reason causing the server
238     *      to send SMTP reply code 421.  This exception may be caught either
239     *      as an IOException or independently as itself.
240     * @throws IOException  If an I/O error occurs while either sending the
241     *      command or receiving the server reply.
242     */
243    public int sendCommand(final String command, final String args) throws IOException
244    {
245        return sendCommand(command, args, true);
246    }
247
248
249    /**
250     * Sends an SMTP command to the server, waits for a reply and returns the
251     * numerical response code.  After invocation, for more detailed
252     * information, the actual reply text can be accessed by calling
253     * {@link #getReplyString  getReplyString } or
254     * {@link #getReplyStrings  getReplyStrings }.
255     * <p>
256     * @param command  The SMTPCommand constant corresponding to the SMTP command
257     *                 to send.
258     * @param args The arguments to the SMTP command.  If this parameter is
259     *             set to null, then the command is sent with no argument.
260     * @return The integer value of the SMTP reply code returned by the server
261     *         in response to the command.
262     * @throws SMTPConnectionClosedException
263     *      If the SMTP server prematurely closes the connection as a result
264     *      of the client being idle or some other reason causing the server
265     *      to send SMTP reply code 421.  This exception may be caught either
266     *      as an IOException or independently as itself.
267     * @throws IOException  If an I/O error occurs while either sending the
268     *      command or receiving the server reply.
269     */
270    public int sendCommand(final int command, final String args) throws IOException
271    {
272        return sendCommand(SMTPCommand.getCommand(command), args);
273    }
274
275
276    /**
277     * Sends an SMTP command with no arguments to the server, waits for a
278     * reply and returns the numerical response code.  After invocation, for
279     * more detailed information, the actual reply text can be accessed by
280     * calling {@link #getReplyString  getReplyString } or
281     * {@link #getReplyStrings  getReplyStrings }.
282     * <p>
283     * @param command  The text representation of the  SMTP command to send.
284     * @return The integer value of the SMTP reply code returned by the server
285     *         in response to the command.
286     * @throws SMTPConnectionClosedException
287     *      If the SMTP server prematurely closes the connection as a result
288     *      of the client being idle or some other reason causing the server
289     *      to send SMTP reply code 421.  This exception may be caught either
290     *      as an IOException or independently as itself.
291     * @throws IOException  If an I/O error occurs while either sending the
292     *      command or receiving the server reply.
293     */
294    public int sendCommand(final String command) throws IOException
295    {
296        return sendCommand(command, null);
297    }
298
299
300    /**
301     * Sends an SMTP command with no arguments to the server, waits for a
302     * reply and returns the numerical response code.  After invocation, for
303     * more detailed information, the actual reply text can be accessed by
304     * calling {@link #getReplyString  getReplyString } or
305     * {@link #getReplyStrings  getReplyStrings }.
306     * <p>
307     * @param command  The SMTPCommand constant corresponding to the SMTP command
308     *                 to send.
309     * @return The integer value of the SMTP reply code returned by the server
310     *         in response to the command.
311     * @throws SMTPConnectionClosedException
312     *      If the SMTP server prematurely closes the connection as a result
313     *      of the client being idle or some other reason causing the server
314     *      to send SMTP reply code 421.  This exception may be caught either
315     *      as an IOException or independently as itself.
316     * @throws IOException  If an I/O error occurs while either sending the
317     *      command or receiving the server reply.
318     */
319    public int sendCommand(final int command) throws IOException
320    {
321        return sendCommand(command, null);
322    }
323
324
325    /**
326     * Returns the integer value of the reply code of the last SMTP reply.
327     * You will usually only use this method after you connect to the
328     * SMTP server to check that the connection was successful since
329     * <code> connect </code> is of type void.
330     * <p>
331     * @return The integer value of the reply code of the last SMTP reply.
332     */
333    public int getReplyCode()
334    {
335        return replyCode;
336    }
337
338    /**
339     * Fetches a reply from the SMTP server and returns the integer reply
340     * code.  After calling this method, the actual reply text can be accessed
341     * from either  calling {@link #getReplyString  getReplyString } or
342     * {@link #getReplyStrings  getReplyStrings }.  Only use this
343     * method if you are implementing your own SMTP client or if you need to
344     * fetch a secondary response from the SMTP server.
345     * <p>
346     * @return The integer value of the reply code of the fetched SMTP reply.
347     * @throws SMTPConnectionClosedException
348     *      If the SMTP server prematurely closes the connection as a result
349     *      of the client being idle or some other reason causing the server
350     *      to send SMTP reply code 421.  This exception may be caught either
351     *      as an IOException or independently as itself.
352     * @throws IOException  If an I/O error occurs while receiving the
353     *                         server reply.
354     */
355    public int getReply() throws IOException
356    {
357        final int length;
358
359        newReplyString = true;
360        replyLines.clear();
361
362        String line = reader.readLine();
363
364        if (line == null) {
365            throw new SMTPConnectionClosedException(
366                "Connection closed without indication.");
367        }
368
369        // In case we run into an anomaly we don't want fatal index exceptions
370        // to be thrown.
371        length = line.length();
372        if (length < 3) {
373            throw new MalformedServerReplyException(
374                "Truncated server reply: " + line);
375        }
376
377        try
378        {
379            final String code = line.substring(0, 3);
380            replyCode = Integer.parseInt(code);
381        }
382        catch (final NumberFormatException e)
383        {
384            throw new MalformedServerReplyException(
385                "Could not parse response code.\nServer Reply: " + line);
386        }
387
388        replyLines.add(line);
389
390        // Get extra lines if message continues.
391        if (length > 3 && line.charAt(3) == '-')
392        {
393            do
394            {
395                line = reader.readLine();
396
397                if (line == null) {
398                    throw new SMTPConnectionClosedException(
399                        "Connection closed without indication.");
400                }
401
402                replyLines.add(line);
403
404                // The length() check handles problems that could arise from readLine()
405                // returning too soon after encountering a naked CR or some other
406                // anomaly.
407            }
408            while (!(line.length() >= 4 && line.charAt(3) != '-' &&
409                     Character.isDigit(line.charAt(0))));
410            // This is too strong a condition because a non-conforming server
411            // could screw things up like ftp.funet.fi does for FTP
412            // line.startsWith(code)));
413        }
414
415        fireReplyReceived(replyCode, getReplyString());
416
417        if (replyCode == SMTPReply.SERVICE_NOT_AVAILABLE) {
418            throw new SMTPConnectionClosedException(
419                "SMTP response 421 received.  Server closed connection.");
420        }
421        return replyCode;
422    }
423
424
425    /**
426     * Returns the lines of text from the last SMTP server response as an array
427     * of strings, one entry per line.  The end of line markers of each are
428     * stripped from each line.
429     * <p>
430     * @return The lines of text from the last SMTP response as an array.
431     */
432    public String[] getReplyStrings()
433    {
434        return replyLines.toArray(NetConstants.EMPTY_STRING_ARRAY);
435    }
436
437    /**
438     * Returns the entire text of the last SMTP server response exactly
439     * as it was received, including all end of line markers in NETASCII
440     * format.
441     * <p>
442     * @return The entire text from the last SMTP response as a String.
443     */
444    public String getReplyString()
445    {
446        final StringBuilder buffer;
447
448        if (!newReplyString) {
449            return replyString;
450        }
451
452        buffer = new StringBuilder();
453
454        for (final String line : replyLines)
455        {
456            buffer.append(line);
457            buffer.append(SocketClient.NETASCII_EOL);
458        }
459
460        newReplyString = false;
461
462        replyString = buffer.toString();
463        return replyString;
464    }
465
466
467    /**
468     * A convenience method to send the SMTP HELO command to the server,
469     * receive the reply, and return the reply code.
470     * <p>
471     * @param hostname The hostname of the sender.
472     * @return The reply code received from the server.
473     * @throws SMTPConnectionClosedException
474     *      If the SMTP server prematurely closes the connection as a result
475     *      of the client being idle or some other reason causing the server
476     *      to send SMTP reply code 421.  This exception may be caught either
477     *      as an IOException or independently as itself.
478     * @throws IOException  If an I/O error occurs while either sending the
479     *      command or receiving the server reply.
480     */
481    public int helo(final String hostname) throws IOException
482    {
483        return sendCommand(SMTPCommand.HELO, hostname);
484    }
485
486
487    /**
488     * A convenience method to send the SMTP MAIL command to the server,
489     * receive the reply, and return the reply code.
490     * <p>
491     * @param reversePath The reverese path.
492     * @return The reply code received from the server.
493     * @throws SMTPConnectionClosedException
494     *      If the SMTP server prematurely closes the connection as a result
495     *      of the client being idle or some other reason causing the server
496     *      to send SMTP reply code 421.  This exception may be caught either
497     *      as an IOException or independently as itself.
498     * @throws IOException  If an I/O error occurs while either sending the
499     *      command or receiving the server reply.
500     */
501    public int mail(final String reversePath) throws IOException
502    {
503        return sendCommand(SMTPCommand.MAIL, reversePath, false);
504    }
505
506
507    /**
508     * A convenience method to send the SMTP RCPT command to the server,
509     * receive the reply, and return the reply code.
510     * <p>
511     * @param forwardPath The forward path.
512     * @return The reply code received from the server.
513     * @throws SMTPConnectionClosedException
514     *      If the SMTP server prematurely closes the connection as a result
515     *      of the client being idle or some other reason causing the server
516     *      to send SMTP reply code 421.  This exception may be caught either
517     *      as an IOException or independently as itself.
518     * @throws IOException  If an I/O error occurs while either sending the
519     *      command or receiving the server reply.
520     */
521    public int rcpt(final String forwardPath) throws IOException
522    {
523        return sendCommand(SMTPCommand.RCPT, forwardPath, false);
524    }
525
526
527    /**
528     * A convenience method to send the SMTP DATA command to the server,
529     * receive the reply, and return the reply code.
530     * <p>
531     * @return The reply code received from the server.
532     * @throws SMTPConnectionClosedException
533     *      If the SMTP server prematurely closes the connection as a result
534     *      of the client being idle or some other reason causing the server
535     *      to send SMTP reply code 421.  This exception may be caught either
536     *      as an IOException or independently as itself.
537     * @throws IOException  If an I/O error occurs while either sending the
538     *      command or receiving the server reply.
539     */
540    public int data() throws IOException
541    {
542        return sendCommand(SMTPCommand.DATA);
543    }
544
545
546    /**
547     * A convenience method to send the SMTP SEND command to the server,
548     * receive the reply, and return the reply code.
549     * <p>
550     * @param reversePath The reverese path.
551     * @return The reply code received from the server.
552     * @throws SMTPConnectionClosedException
553     *      If the SMTP server prematurely closes the connection as a result
554     *      of the client being idle or some other reason causing the server
555     *      to send SMTP reply code 421.  This exception may be caught either
556     *      as an IOException or independently as itself.
557     * @throws IOException  If an I/O error occurs while either sending the
558     *      command or receiving the server reply.
559     */
560    public int send(final String reversePath) throws IOException
561    {
562        return sendCommand(SMTPCommand.SEND, reversePath);
563    }
564
565
566    /**
567     * A convenience method to send the SMTP SOML command to the server,
568     * receive the reply, and return the reply code.
569     * <p>
570     * @param reversePath The reverese path.
571     * @return The reply code received from the server.
572     * @throws SMTPConnectionClosedException
573     *      If the SMTP server prematurely closes the connection as a result
574     *      of the client being idle or some other reason causing the server
575     *      to send SMTP reply code 421.  This exception may be caught either
576     *      as an IOException or independently as itself.
577     * @throws IOException  If an I/O error occurs while either sending the
578     *      command or receiving the server reply.
579     */
580    public int soml(final String reversePath) throws IOException
581    {
582        return sendCommand(SMTPCommand.SOML, reversePath);
583    }
584
585
586    /**
587     * A convenience method to send the SMTP SAML command to the server,
588     * receive the reply, and return the reply code.
589     * <p>
590     * @param reversePath The reverese path.
591     * @return The reply code received from the server.
592     * @throws SMTPConnectionClosedException
593     *      If the SMTP server prematurely closes the connection as a result
594     *      of the client being idle or some other reason causing the server
595     *      to send SMTP reply code 421.  This exception may be caught either
596     *      as an IOException or independently as itself.
597     * @throws IOException  If an I/O error occurs while either sending the
598     *      command or receiving the server reply.
599     */
600    public int saml(final String reversePath) throws IOException
601    {
602        return sendCommand(SMTPCommand.SAML, reversePath);
603    }
604
605
606    /**
607     * A convenience method to send the SMTP RSET command to the server,
608     * receive the reply, and return the reply code.
609     * <p>
610     * @return The reply code received from the server.
611     * @throws SMTPConnectionClosedException
612     *      If the SMTP server prematurely closes the connection as a result
613     *      of the client being idle or some other reason causing the server
614     *      to send SMTP reply code 421.  This exception may be caught either
615     *      as an IOException or independently as itself.
616     * @throws IOException  If an I/O error occurs while either sending the
617     *      command or receiving the server reply.
618     */
619    public int rset() throws IOException
620    {
621        return sendCommand(SMTPCommand.RSET);
622    }
623
624
625    /**
626     * A convenience method to send the SMTP VRFY command to the server,
627     * receive the reply, and return the reply code.
628     * <p>
629     * @param user The user address to verify.
630     * @return The reply code received from the server.
631     * @throws SMTPConnectionClosedException
632     *      If the SMTP server prematurely closes the connection as a result
633     *      of the client being idle or some other reason causing the server
634     *      to send SMTP reply code 421.  This exception may be caught either
635     *      as an IOException or independently as itself.
636     * @throws IOException  If an I/O error occurs while either sending the
637     *      command or receiving the server reply.
638     */
639    public int vrfy(final String user) throws IOException
640    {
641        return sendCommand(SMTPCommand.VRFY, user);
642    }
643
644
645    /**
646     * A convenience method to send the SMTP VRFY command to the server,
647     * receive the reply, and return the reply code.
648     * <p>
649     * @param name The name to expand.
650     * @return The reply code received from the server.
651     * @throws SMTPConnectionClosedException
652     *      If the SMTP server prematurely closes the connection as a result
653     *      of the client being idle or some other reason causing the server
654     *      to send SMTP reply code 421.  This exception may be caught either
655     *      as an IOException or independently as itself.
656     * @throws IOException  If an I/O error occurs while either sending the
657     *      command or receiving the server reply.
658     */
659    public int expn(final String name) throws IOException
660    {
661        return sendCommand(SMTPCommand.EXPN, name);
662    }
663
664    /**
665     * A convenience method to send the SMTP HELP command to the server,
666     * receive the reply, and return the reply code.
667     * <p>
668     * @return The reply code received from the server.
669     * @throws SMTPConnectionClosedException
670     *      If the SMTP server prematurely closes the connection as a result
671     *      of the client being idle or some other reason causing the server
672     *      to send SMTP reply code 421.  This exception may be caught either
673     *      as an IOException or independently as itself.
674     * @throws IOException  If an I/O error occurs while either sending the
675     *      command or receiving the server reply.
676     */
677    public int help() throws IOException
678    {
679        return sendCommand(SMTPCommand.HELP);
680    }
681
682    /**
683     * A convenience method to send the SMTP HELP command to the server,
684     * receive the reply, and return the reply code.
685     * <p>
686     * @param command  The command name on which to request help.
687     * @return The reply code received from the server.
688     * @throws SMTPConnectionClosedException
689     *      If the SMTP server prematurely closes the connection as a result
690     *      of the client being idle or some other reason causing the server
691     *      to send SMTP reply code 421.  This exception may be caught either
692     *      as an IOException or independently as itself.
693     * @throws IOException  If an I/O error occurs while either sending the
694     *      command or receiving the server reply.
695     */
696    public int help(final String command) throws IOException
697    {
698        return sendCommand(SMTPCommand.HELP, command);
699    }
700
701    /**
702     * A convenience method to send the SMTP NOOP command to the server,
703     * receive the reply, and return the reply code.
704     * <p>
705     * @return The reply code received from the server.
706     * @throws SMTPConnectionClosedException
707     *      If the SMTP server prematurely closes the connection as a result
708     *      of the client being idle or some other reason causing the server
709     *      to send SMTP reply code 421.  This exception may be caught either
710     *      as an IOException or independently as itself.
711     * @throws IOException  If an I/O error occurs while either sending the
712     *      command or receiving the server reply.
713     */
714    public int noop() throws IOException
715    {
716        return sendCommand(SMTPCommand.NOOP);
717    }
718
719
720    /**
721     * A convenience method to send the SMTP TURN command to the server,
722     * receive the reply, and return the reply code.
723     * <p>
724     * @return The reply code received from the server.
725     * @throws SMTPConnectionClosedException
726     *      If the SMTP server prematurely closes the connection as a result
727     *      of the client being idle or some other reason causing the server
728     *      to send SMTP reply code 421.  This exception may be caught either
729     *      as an IOException or independently as itself.
730     * @throws IOException  If an I/O error occurs while either sending the
731     *      command or receiving the server reply.
732     */
733    public int turn() throws IOException
734    {
735        return sendCommand(SMTPCommand.TURN);
736    }
737
738
739    /**
740     * A convenience method to send the SMTP QUIT command to the server,
741     * receive the reply, and return the reply code.
742     * <p>
743     * @return The reply code received from the server.
744     * @throws SMTPConnectionClosedException
745     *      If the SMTP server prematurely closes the connection as a result
746     *      of the client being idle or some other reason causing the server
747     *      to send SMTP reply code 421.  This exception may be caught either
748     *      as an IOException or independently as itself.
749     * @throws IOException  If an I/O error occurs while either sending the
750     *      command or receiving the server reply.
751     */
752    public int quit() throws IOException
753    {
754        return sendCommand(SMTPCommand.QUIT);
755    }
756
757    /**
758     * Removes a ProtocolCommandListener.
759     *
760     * Delegates this incorrectly named method - removeProtocolCommandistener (note the missing "L")- to
761     * the correct method {@link SocketClient#removeProtocolCommandListener}
762     * @param listener The ProtocolCommandListener to remove
763     */
764    public void removeProtocolCommandistener(final org.apache.commons.net.ProtocolCommandListener listener){
765        removeProtocolCommandListener(listener);
766    }
767
768    /**
769     * Provide command support to super-class
770     */
771    @Override
772    protected ProtocolCommandSupport getCommandSupport() {
773        return _commandSupport_;
774    }
775}