Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/finj/FTPResponse.java


1   package org.finj;
2   
3   import java.util.Locale;
4   import java.util.MissingResourceException;
5   import java.util.ResourceBundle;
6   import java.util.StringTokenizer;
7   
8   /**
9    * This class contains constants and methods that simplify handling 
10   * and internationalization of FTP server replies.
11   *
12   * Codes according to RFC959-4.2 <tt>http://www.rfc.net/rfc959.html</tt>
13   * (October 1995).
14   *
15   * Copyright (C)
16   *
17   * This library is free software; you can redistribute it and/or
18   * modify it under the terms of the GNU Lesser General Public
19   * License as published by the Free Software Foundation; either
20   * version 2.1 of the License, or (at your option) any later version.
21   *
22   * This library is distributed in the hope that it will be useful,
23   * but WITHOUT ANY WARRANTY; without even the implied warranty of
24   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25   * Lesser General Public License for more details.
26   *
27   * You should have received a copy of the GNU Lesser General Public
28   * License along with this library; if not, write to the Free Software
29   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30   *
31   * @author Javier Iglesias -- jiglesias@users.sourceforge.net 
32   * @version $Id: FTPResponse.java,v 1.2 2003/10/22 08:14:57 jiglesia Exp $
33   */
34  public class FTPResponse extends Object {
35  
36    /**
37     * No response will ever (as RFC959 is concerned...) match this code !
38     *
39     * Used for comparisions purposes.
40     *
41     * @since v1.0.2
42     */
43    private static final int NOT_A_REAL_RESPONSE_CODE = -1;
44    
45    // ----- 100 SERIES CODES -----
46    // Requested action is being initiated, expect 
47    // another response before proceeding with a new command
48    /** 
49     * Restart marker response. 
50     *
51     * In this case, the text is exact and not 
52     * left to the particular implementation; it must read :
53     * <code>MARK yyyy = mmmm</code>
54     * Where <code>yyyy</code> is User-process data stream marker, 
55     * and <code>mmmm</code> server's equivalent marker 
56     * (note the spaces between markers and '=`).
57     *
58     * @see "RFC959-4:2:'110'"
59     * @since v1.0
60     */
61    public static final int RESTART_MARKER_RESPONSE_CODE = 110;
62    /** 
63     * Service ready in <code>nnn</code> minutes.
64     *  
65     * @see "RFC959-4:2:'120'"
66     * @since v1.0
67     */
68    public static final int WILL_BE_READY_IN_MINUTES_CODE = 120;
69    /** 
70     * Data Connection already open; transfer starting.
71     *
72     * @see "RFC959-4:2:'125'"
73     * @since v1.0
74     */
75    public static final int DATA_CONNECTION_ALREADY_OPENED_CODE = 125;
76    /** 
77     * File status okay; about to open data connection.
78     *
79     * @see "RFC959-4:2:'150'"
80     * @since v1.0
81     */
82    public static final int DATA_CONNECTION_ABOUT_TO_BE_OPENED_CODE = 150;
83    
84    // ----- 200 SERIES CODES -----
85    // Requested action has been successfully completed
86    /** 
87     * Command okay.
88     *
89     * @see "RFC959-4:2:'200'"
90     * @since v1.0
91     */
92    public static final int POSITIVE_COMPLETION_RESPONSE_CODE = 200;
93    /** 
94     * Command not implemented, superfluous at this site.
95     *
96     * @see "RFC959-4:2:'202'"
97     * @since v1.0
98     */
99    public static final int SUPERFLOUS_COMMAND_CODE = 202;
100   /** 
101    * System status, or system help response.
102    *
103    * @see "RFC959-4:2:'211'"
104    * @since v1.0
105    */
106   public static final int SYSTEM_STATUS_OR_HELP_RESPONSE_CODE = 211;
107   /** 
108    * Directory status
109    *
110    * @see "RFC959-4:2:'212'"
111    * @since v1.0
112    */
113   public static final int DIRECTORY_STATUS_CODE = 212;
114   /** 
115    * File status.
116    *
117    * @see "RFC959-4:2:'213'"
118    * @since v1.0
119    */
120   public static final int FILE_STATUS_CODE = 213;
121   /** 
122    * Help message.
123    *
124    * On how to use the server or the meaning of a particular 
125    * non-standard command. This response is useful only to the 
126    * human user.
127    *
128    * @see "RFC959-4:2:'214'"
129    * @since v1.0
130    */
131   public static final int HELP_MESSAGE_CODE = 214;
132   /** 
133    * <code>NAME</code> system type.
134    *
135    * Where <code>NAME</code> is an official system name from 
136    * the list in the Assigned Numbers document.
137    *
138    * @see "RFC959-4:2:'215'"
139    * @see "RFC1700"
140    * @since v1.0
141    */
142   public static final int SYSTEM_TYPE_NAME_CODE = 215;
143   /** 
144    * Service ready for new user.
145    *
146    * @see "RFC959-4:2:'220'"
147    * @since v1.0
148    */
149   public static final int CONTROL_CONNECTION_OPENED_CODE = 220;
150   /** 
151    * Service closing control connection.
152    *
153    * Logged out if appropriate.
154    *
155    * @see "RFC959-4:2:'221'"
156    * @since v1.0
157    */
158   public static final int CONTROL_CONNECTION_CLOSED_CODE = 221;
159   /** 
160    * Data connection open; no transfer in progress.
161    *
162    * @see "RFC959-4:2:'225'"
163    * @since v1.0
164    */
165   public static final int DATA_CONNECTION_OPENED_CODE = 225;
166   /** 
167    * Closing data connection.
168    *
169    * Requested file action successful (e.g., file transfer or 
170    * file abort).
171    *
172    * @see "RFC959-4:2:'226'"
173    * @since v1.0
174    */
175   public static final int DATA_CONNECTION_CLOSED_CODE = 226;
176   /** 
177    * Entering Passive Mode (h1,h2,h3,h4,p1,p2).
178    *
179    * @see "RFC959-4:2:'227'"
180    * @since v1.0
181    */
182   public static final int ENTERING_PASSIVE_MODE_CODE = 227;
183   /** 
184    * User logged in, proceed.
185    *
186    * @see "RFC959-4:2:'230'"
187    * @since v1.0
188    */
189   public static final int USER_LOGGED_IN_CODE = 230;
190   /** 
191    * Requested file action okay, completed.
192    *
193    * @see "RFC959-4:2:'250'"
194    * @since v1.0
195    */
196   public static final int REQUESTED_FILE_ACTION_OK_CODE = 250;
197   /** 
198    * "PATHNAME" created.
199    *
200    * @see "RFC959-4:2:'257'"
201    * @since v1.0
202    */
203   public static final int PATHNAME_CREATED_CODE = 257;
204   
205   // ----- 300 SERIES CODES -----
206   // Command has been accepted, but requested action 
207   // is  being held abeyance, pending receipt of 
208   // further information
209   /** 
210    * User name okay, need password.
211    *
212    * @see "RFC959-4:2;'331'"
213    * @since v1.0
214    */
215   public static final int USERNAME_OK_NEED_PASSWORD_CODE = 331;
216   /** 
217    * Need account for login.
218    *
219    * @see "RFC959-4:2:'332'"
220    * @since v1.0
221    */
222   public static final int NEED_ACCOUNT_FOR_LOGIN_CODE = 332;
223   /** 
224    * Requested file action pending further information.
225    *
226    * @see "RFC959-4:2:'350'"
227    * @since v1.0
228    */
229   public static final int REQUESTED_FILE_ACTION_PENDING_CODE = 350;
230   
231   // ----- 400 SERIES CODES -----
232   // Command was not accepted and the requested action 
233   // did NOT take place, but the error condition is 
234   // temporary and the action may be requested again
235   /** 
236    * Service not available, closing control connection.
237    *
238    * This may be a response to any command if the service 
239    * knows it must shut down.
240    *
241    * @see "RFC959-4:2:'421'"
242    * @since v1.0
243    */
244   public static final int SERVICE_NOT_AVAILABLE_CODE = 421;
245   /** 
246    * Can't open data connection.
247    *
248    * @see "RFC959-4:2:'425'"
249    * @since v1.0
250    */
251   public static final int CAN_T_OPEN_DATA_CONNECTION_CODE = 425;
252   /** 
253    * Connection closed; transfer aborted.
254    *
255    * @see "RFC959-4:2:'426'"
256    * @since v1.0
257    */
258   public static final int DATA_CONNECTION_ABORTED_CODE = 426;
259   /** 
260    * Requested file action not taken.
261    *
262    * File unavailable (e.g., file busy).
263    *
264    * @see "RFC959-4:2:'450'"
265    * @since v1.0
266    */
267   public static final int TRANSIENT_UNAVAILABLE_FILE_CODE = 450;
268   /** 
269    * Requested action aborted: local error in processing.
270    *
271    * @see "RFC959-4:2:'451'"
272    * @since v1.0
273    */
274   public static final int TRANSIENT_LOCAL_PROCESSING_ERROR_CODE = 451;
275   /** 
276    * Requested action not taken.
277    *
278    * Insufficient storage space in system.
279    *
280    * @see "RFC959-4:2:'452'"
281    * @since v1.0
282    */
283   public static final int TRANSIENT_INSUFFICIENT_STORAGE_SPACE_CODE = 452;
284   
285   // ----- 500 SERIES CODES -----
286   // Command was not accepted and the requested action 
287   // did NOT take place
288   /** 
289    * Syntax error, command unrecognized.
290    *
291    * This may include errors such as command line too long.
292    *
293    * @see "RFC959-4:2:'500'"
294    * @since v1.0
295    */
296   public static final int PERMANENT_NEGATIVE_COMPLETION_RESPONSE_CODE = 500;
297   /** 
298    * Syntax error n parameters or arguments.
299    *
300    * @see "RFC959-4:2:'501'"
301    * @since v1.0
302    */
303   public static final int SYNTAX_ERROR_IN_ARGUMENTS_CODE = 501;
304   /** 
305    * Command not implemented.
306    *
307    * @see "RFC959-4:2:'502'"
308    * @since v1.0
309    */
310   public static final int COMMAND_NOT_IMPLEMENTED_CODE = 502;
311   /** 
312    * Bad sequence of commands.
313    *
314    * @see "RFC959-4:2:'503'"
315    * @since v1.0
316    */
317   public static final int BAD_COMMAND_SEQUENCE_CODE = 503;
318   /** 
319    * Command not implemented for that parameter.
320    *
321    * @see "RFC959-4:2:'504'"
322    * @since v1.0
323    */
324   public static final int COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER_CODE = 504;
325   /** 
326    * Not logged in.
327    *
328    * @see "RFC959-4:2:'530'"
329    * @since v1.0
330    */
331   public static final int NOT_LOGGED_IN_CODE = 530;
332   /** 
333    * Need account for storing files.
334    *
335    * @see "RFC959-4:2:'532'"
336    * @since v1.0
337    */
338   public static final int NEED_ACCOUNT_FOR_STORING_FILES_CODE = 532;
339   /** 
340    * Requested action not taken.
341    *
342    * File unavailable (e.g., file not found, no access).
343    *
344    * @see "RFC959-4:2:'550'"
345    * @since v1.0
346    */
347   public static final int PERMANENTLY_UNAVAILABLE_FILE_CODE = 550;
348   /** 
349    * Requested action aborted: page type unknown.
350    *
351    * @see "RFC959-4:2:'551'"
352    * @since v1.0
353    */
354   public static final int PAGE_TYPE_UNKNOWN_CODE = 551;
355   /** 
356    * Requested file action aborted.
357    *
358    * Exceed storage allocation (for current directory or dataset).
359    *
360    * @see "RFC959-4:2:'552'"
361    * @since v1.0
362    */
363   public static final int EXCEEDED_STORAGE_ALLOCATION_CODE = 552;
364   /** 
365    * Requested action not taken.
366    *
367    * File name not allowed.
368    *
369    * @see "RFC959-4:2:'553'"
370    * @since v1.0
371    */
372   public static final int FINE_NAME_NOT_ALLOWED_CODE = 553;
373   
374   
375   // Messages are stored in resource files
376   private static final String MESSAGE_BUNDLE_NAME  = "org/finj/i18n/Responses";
377   private static final String MESSAGE_NAME_PREFIX  = "code_";
378   private static final String DEFAULT_MESSAGE_NAME = "code_default";
379   private ResourceBundle resources = null;
380   
381   private int      code = 0;
382   private String   text = null;
383   private String[] multi = null;
384   
385   /**
386    * Defeat parameterless constructor.
387    *
388    * @since v1.0
389    */
390   private FTPResponse ( ) {;}
391   
392   /**
393    * Constructs a new instance of this class that will 
394    * use <code>FTPConstants.DEFAULT_LOCALE</code> as 
395    * default locale.
396    *
397    * @param response original response message received on the 
398    *              control connection.
399    * @since v1.0
400    */
401   public FTPResponse ( String response ) {
402     this(response, null, FTPConstants.DEFAULT_LOCALE);
403   }
404 
405   /**
406    * Constructs a new instance of this class that will 
407    * use <code>FTPConstants.DEFAULT_LOCALE</code> as 
408    * default locale, and will store a multiline answer.
409    *
410    * @param response original response message received on the 
411    *              control connection.
412    * @param multiline text received with this response.
413    * @since v1.0
414    */
415   public FTPResponse ( String   response,
416            String[] multiline ) {
417     this(response, multiline, FTPConstants.DEFAULT_LOCALE);
418   }
419 
420   /**
421    * Constructs a new instance of this class 
422    * that will use <code>locale</code> as 
423    * message language. If not available, 
424    * messages for default language 
425    * (<code>Locale.US</code>) will be used.
426    *
427    * @param response original response message received on the 
428    *              control connection.
429    * @param locale language to use for message.
430    * @since v1.0
431    */
432   public FTPResponse ( String response,
433            Locale locale ) throws IllegalArgumentException {
434     this(response, null, locale);
435   }
436 
437   /**
438    * Constructs a new instance of this class 
439    * that will use <code>locale</code> as 
440    * message language. If not available, 
441    * messages for default language 
442    * (<code>Locale.US</code>) will be used.
443    *
444    * @param response original response message received on the 
445    *              control connection.
446    * @param multiline text received with this response.
447    * @param locale language to use for message.
448    * @since v1.0
449    */
450   public FTPResponse ( String   response,
451            String[] multiline,
452            Locale   locale ) throws IllegalArgumentException {
453     this(parseCode(response),
454          parseOriginalMessage(response),
455          multiline,
456          locale);
457   }
458   
459   /**
460    * Initializes the current instance with the info provided.
461    *
462    * @param code   valid FTP code.
463    * @param text   original message found in the response.
464    * @param multi  multiline info received with this message.
465    * @param locale language to use for message.
466    * @since v1.0
467    */
468   public FTPResponse ( int      code,
469            String   text,
470            String[] multi,
471            Locale   locale ) {
472     this.code  = code;
473     this.multi = multi;
474     this.text  = text;
475     resources  = ResourceBundle.getBundle(MESSAGE_BUNDLE_NAME, locale);
476   }
477       
478       
479 
480   /**
481    * Returns the FTP code of this response.
482    *
483    * @return FTP code
484    * @since v1.0
485    */
486   public int getCode ( ) {
487     return code;
488   }
489   
490   /**
491    * Returns a localized version of the message corresponding 
492    * to the original one's code. This will only work if a 
493    * localized version of the messages are provided.
494    *
495    * @return code of the response sent by FTP server.
496    * @since v1.0
497    */
498   public String getMessage ( ) {
499     return getMessageFromCode(code);
500   }
501   
502   /**
503    * Returns the original message received from the FTP server 
504    * and passed at construction time.
505    * 
506    * @return original message text.
507    * @since v1.0
508    */
509   public String getOriginalMessage ( ) {
510     return text;
511   }
512   
513   /**
514    * Returns true if this response anounces a multi line response, 
515    * e.g., <code>STAT</code> command.
516    *
517    * @return <code>true</code> if more lines are coming next 
518    *         the one used to construct this instance.
519    * @see "RFC959-4:2"
520    * @since v1.0
521    */
522   public boolean isMultiline ( ) {
523     return (multi != null);
524   }
525   
526   /**
527    * Returns the multiline answer received with this response.
528    *
529    * @return multiline answer if exists, <code>null</code> else.
530    * @since v1.0
531    */
532   public String[] getMultilineText ( ) {
533     return multi;
534   }
535 
536 
537 
538 
539 
540 
541   /**
542    * Returns the message that corresponds to the 
543    * <code>code</code> given as parameter.
544    *
545    * @param code one of the codes defined in this class.
546    * @since v1.0
547    */
548   protected String getMessageFromCode ( int code ) {
549     try {
550       return resources.getString(new StringBuffer(MESSAGE_NAME_PREFIX).append(code).toString());
551     } catch ( MissingResourceException mre ) {
552       return resources.getString(DEFAULT_MESSAGE_NAME);
553     }
554   }
555   
556   
557   
558   
559   
560   
561 
562   /**
563    * Tests the first line of a response to know if it opens 
564    * a multiline answer.
565    *
566    * @param response FTP server response to interpret.
567    * @since v1.0.2
568    */
569   public static boolean opensMultilineResponse ( String response ) {
570     return (response.charAt (3) == '-');
571   } // DONE
572   
573   /**
574    * Tests a line of a response to know if it closes
575    * a multiline answer.
576    *
577    * @param response FTP server response to interpret.
578    * @since v1.0.2
579    */
580   public static boolean closesMultilineResponse ( String response, 
581                     int    code ) {
582     int responseCode = NOT_A_REAL_RESPONSE_CODE;
583     try {
584       responseCode = parseCode(response);
585     } catch ( IllegalArgumentException iae ) {;}
586     return (code == responseCode && 
587       response.charAt(3) == ' ');
588   } // DONE
589   
590   
591   /**
592    * Returns the code contained in the 
593    * <code>response</code> passed as parameter.
594    * This code are in fact the 3 first characters 
595    * of the <code>response</code>.
596    *
597    * @param response FTP server response to interpret.
598    * @exception IllegalArgumentException 
599    *            when <code>response</code>'s 3 first characters 
600    *            are not a valid three digit number
601    * @since v1.0
602    */
603   public static int parseCode ( String response ) throws IllegalArgumentException {
604     try {
605       return Integer.parseInt(response.substring(0, 3));
606     } catch ( NumberFormatException nfe ) {
607       throw new IllegalArgumentException(response.substring (0, 3) + " is obviously not a valid FTP error code !"); // FIXME : internationalize
608     } catch ( Exception e ) {
609       throw new IllegalArgumentException("There is obviously no valid FTP error code on line : '"+response+"'"); // FIXME : internationalize
610     }
611   }
612 
613   /**
614    * Returns the message contained in the 
615    * <code>response</code> passed as parameter.
616    *
617    * @param response FTP server response to interpret.
618    * @exception IllegalArgumentException 
619    *            when <code>response</code> isn't parsable.
620    * @since v1.0
621    */
622   public static String parseOriginalMessage ( String response ) throws IllegalArgumentException {
623     try {
624       return (response.substring(4, response.length()).trim());
625     } catch ( Exception e ) {
626       throw new IllegalArgumentException("Impossible to extract the message part of : '" + response + "' !"); // FIXME : internationalize
627     }
628   }
629 
630 
631 
632 
633 
634 
635 
636   /**
637    * Returns the host passive port parsed from the original text of response.
638    * The author of this method is Syed Meerkasim.
639    * 
640    * @return a <code>java.lang.String[]</code>
641    * @exception FTPException Response doesn't contain the required information
642    * @since v1.0
643    */
644   // FIXME : change method name    public String[] getHostNPortFromMessage ( ) throws FTPException {
645   // FIXME : is it really the right place to do that ? are there no exception to check ?
646   public String[] parseServerPassivePort ( ) throws FTPException {
647     int infoStartIndex = 0;
648     int infoStopIndex  = 0;
649     String answer[] = null;
650     
651     infoStartIndex = text.indexOf("(");
652     infoStopIndex  = text.indexOf(")");
653     
654     if ( infoStartIndex == -1  || 
655          infoStopIndex  == -1 ) {
656       throw new FTPException(this, -1, "This is not a valid answer to the PASV command."); // FIXME : what kind of exception ?? + internationalize
657     }
658     
659     // ok : info is in the message.
660     // let's parse it
661     String tmp1 = "";
662     answer = new String[2];
663     
664     String tmp = text.substring(infoStartIndex + 1, infoStopIndex);
665     
666     StringTokenizer tokenizer = new StringTokenizer(tmp,",");
667     
668     int tokenIndex = 0;
669     while ( tokenizer.hasMoreTokens() ) {
670       if ( tokenIndex == 4 ) {
671         answer[0] = tmp1; // first half of answer : ??
672         try{
673           tmp1 = Integer.toString(Integer.parseInt(tokenizer.nextToken())*256);
674         } catch ( Exception e ) {
675           tmp1="0";
676         }
677       }
678       if ( tokenIndex > 0  &&  tokenIndex < 4 ) {
679         tmp1 = new StringBuffer(tmp1).append(".").toString();
680       }
681       if ( tokenIndex < 4 ) {
682         tmp1 = new StringBuffer(tmp1).append(tokenizer.nextToken()).toString();
683       } else {
684         if ( tokenIndex == 5 ) {
685           try {
686             tmp1 = Integer.toString(Integer.parseInt(tmp1) + Integer.parseInt(tokenizer.nextToken()));
687           } catch ( Exception e ) {;}
688         }
689       }
690       tokenIndex++;
691     }
692     answer[1] = tmp1; // second half of answer : ??
693     return answer;
694   }
695 
696   /**
697    * This command causes the name of the current working directory to be 
698    * returned.
699    * 
700    * @see "RFC959-4:1:3:'PWD'"
701    * @return current working directory pathname.
702    * @since v1.0
703    */
704   // FIXME : is it really the right place to do that ? are there no exception to check ?
705   public String parseWorkingDirectory ( ) {
706     String answer = text;
707     answer = answer.substring(answer.indexOf('"')+1, answer.length());
708     answer = answer.substring(0, answer.indexOf('"'));
709     return answer;
710   }
711 }