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