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