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