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