View Javadoc

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