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