View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.common.command;
21  
22  import org.waarp.common.exception.InvalidArgumentException;
23  
24  /**
25   * Reply code references by different RFC.
26   */
27  public enum ReplyCode {
28    /**
29     * unofficial reply code for no value
30     */
31    REPLY_000_SPECIAL_NOSTATUS(0),
32    /**
33     * 110 Restart marker reply. In this case, the text is exact and not left to
34     * the particular implementation),
35     * it must read: MARK yyyy (mmmm Where yyyy is User-process data stream
36     * marker, and mmmm server's equivalent
37     * marker (note the spaces between markers and "=").
38     */
39    REPLY_110_RESTART_MARKER_REPLY(110),
40  
41    /**
42     * 120 Service ready in nnn minutes.
43     */
44    REPLY_120_SERVICE_READY_IN_NNN_MINUTES(120),
45  
46    /**
47     * 125 Data connection already open), transfer starting.
48     */
49    REPLY_125_DATA_CONNECTION_ALREADY_OPEN(125),
50  
51    /**
52     * 150 File status okay), about to open data connection.
53     */
54    REPLY_150_FILE_STATUS_OKAY(150),
55  
56    /**
57     * 200 Command okay.
58     */
59    REPLY_200_COMMAND_OKAY(200),
60  
61    /**
62     * 202 Command not implemented, superfluous at this site.
63     */
64    REPLY_202_COMMAND_NOT_IMPLEMENTED(202),
65  
66    /**
67     * 211 System status, or system help reply.
68     */
69    REPLY_211_SYSTEM_STATUS_REPLY(211),
70  
71    /**
72     * 212 Directory status.
73     */
74    REPLY_212_DIRECTORY_STATUS(212),
75  
76    /**
77     * 213 File status.
78     */
79    REPLY_213_FILE_STATUS(213),
80  
81    /**
82     * 214 Help message. On how to use the server or the meaning of a particular
83     * non-standard command. This reply
84     * is useful only to the human user.
85     */
86    REPLY_214_HELP_MESSAGE(214,
87                           "This FTP server refers to RFC 959, RFC 775, RFC 2389 and RFC 3659"),
88  
89    /**
90     * 215 NAME system type. Where NAME is an official system name from the list
91     * in the Assigned Numbers document.
92     */
93    REPLY_215_NAME_SYSTEM_TYPE(215),
94  
95    /**
96     * 220 Service ready for new user.
97     */
98    REPLY_220_SERVICE_READY(220),
99  
100   /**
101    * Service closing control connection. Logged out if appropriate.
102    */
103   REPLY_221_CLOSING_CONTROL_CONNECTION(221),
104 
105   /**
106    * 225 Data connection open), no transfer in progress.
107    */
108   REPLY_225_DATA_CONNECTION_OPEN_NO_TRANSFER_IN_PROGRESS(225),
109 
110   /**
111    * Closing data connection. Requested file action successful (for example,
112    * file transfer or file abort).
113    */
114   REPLY_226_CLOSING_DATA_CONNECTION(226),
115 
116   /**
117    * 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).
118    */
119   REPLY_227_ENTERING_PASSIVE_MODE(227),
120 
121   /**
122    * 229 Entering Extended Passive Mode (|n|addr|port|).
123    */
124   REPLY_229_ENTERING_PASSIVE_MODE(229),
125 
126   /**
127    * 230 User logged in, proceed.
128    */
129   REPLY_230_USER_LOGGED_IN(230),
130 
131   /**
132    * 232 User logged in, authorized by security data exchange.
133    */
134   REPLY_232_USER_LOGGED_IN(232),
135 
136   /**
137    * 234 Security data exchange complete.
138    */
139   REPLY_234_SECURITY_DATA_EXCHANGE_COMPLETE(234),
140 
141   /**
142    * 250 Requested file action okay, completed.
143    */
144   REPLY_250_REQUESTED_FILE_ACTION_OKAY(250),
145 
146   /**
147    * 257 "PATHNAME" created.
148    */
149   REPLY_257_PATHNAME_CREATED(257),
150 
151   /**
152    * 331 User name okay, need password.
153    */
154   REPLY_331_USER_NAME_OKAY_NEED_PASSWORD(331),
155 
156   /**
157    * 332 Need account for login.
158    */
159   REPLY_332_NEED_ACCOUNT_FOR_LOGIN(332),
160 
161   /**
162    * 350 Requested file action pending further information.
163    */
164   REPLY_350_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFORMATION(350),
165 
166   /**
167    * 400 Bad Request (Http)
168    */
169   REPLY_400_BAD_REQUEST(400),
170 
171   /**
172    * 421 Service not available, closing control connection. This may be a
173    * reply
174    * to any command if the service
175    * knows it must shut down.
176    */
177   REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION(421),
178 
179   /**
180    * 425 Can't open data connection.
181    */
182   REPLY_425_CANT_OPEN_DATA_CONNECTION(425),
183 
184   /**
185    * 426 Connection closed), transfer aborted.
186    */
187   REPLY_426_CONNECTION_CLOSED_TRANSFER_ABORTED(426),
188 
189   /**
190    * 431 Need some unavailable resource to process security.
191    */
192   REPLY_431_NEED_UNAVAILABLE_RESOURCE_TO_PROCESS_SECURITY(431),
193 
194   /**
195    * 450 Requested file action not taken. File unavailable (e.g., file busy).
196    */
197   REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN(450),
198 
199   /**
200    * 451 Requested action aborted: local error in processing.
201    */
202   REPLY_451_REQUESTED_ACTION_ABORTED(451),
203 
204   /**
205    * 452 Requested action not taken. Insufficient storage space in system.
206    */
207   REPLY_452_REQUESTED_ACTION_NOT_TAKEN(452),
208 
209   /**
210    * 500 Syntax error, command unrecognized. This may include errors such as
211    * command line too long.
212    */
213   REPLY_500_SYNTAX_ERROR_COMMAND_UNRECOGNIZED(500),
214 
215   /**
216    * 501 Syntax error in parameters or arguments.
217    */
218   REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS(501),
219 
220   /**
221    * 502 Command not implemented.
222    */
223   REPLY_502_COMMAND_NOT_IMPLEMENTED(502),
224 
225   /**
226    * 503 Bad sequence of commands.
227    */
228   REPLY_503_BAD_SEQUENCE_OF_COMMANDS(503),
229 
230   /**
231    * 504 Command not implemented for that parameter.
232    */
233   REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER(504),
234 
235   /**
236    * 522 Extended Port Failure - unknown network protocol.
237    */
238   REPLY_522_EXTENDED_PORT_FAILURE_UNKNOWN_NETWORK_PROTOCOL(522),
239 
240   /**
241    * 530 Not logged in.
242    */
243   REPLY_530_NOT_LOGGED_IN(530),
244 
245   /**
246    * 532 Need account for storing files.
247    */
248   REPLY_532_NEED_ACCOUNT_FOR_STORING_FILES(532),
249 
250   /**
251    * 533 Command protection level denied for policy reasons.
252    */
253   REPLY_533_COMMAND_PROTECTION_LEVEL_DENIED_FOR_POLICY_REASONS(533),
254 
255   /**
256    * 534 Request denied for policy reasons.
257    */
258   REPLY_534_REQUEST_DENIED_FOR_POLICY_REASONS(534),
259 
260   /**
261    * 535 Failed security check (hash, sequence, etc).
262    */
263   REPLY_535_FAILED_SECURITY_CHECK(535),
264 
265   /**
266    * 536 Requested PROT level not supported by mechanism.
267    */
268   REPLY_536_REQUESTED_PROT_LEVEL_NOT_SUPPORTED(536),
269 
270   /**
271    * 550 Requested action not taken. File unavailable (e.g., file not found,
272    * no
273    * access).
274    */
275   REPLY_550_REQUESTED_ACTION_NOT_TAKEN(550),
276 
277   /**
278    * 551 Requested action aborted: page type unknown.
279    */
280   REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN(551),
281 
282   /**
283    * 552 Requested file action aborted. Exceeded storage allocation (for
284    * current
285    * directory or dataset).
286    */
287   REPLY_552_REQUESTED_FILE_ACTION_ABORTED_EXCEEDED_STORAGE(552),
288 
289   /**
290    * 553 Requested action not taken. File name not allowed.
291    */
292   REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED(553);
293 
294   /**
295    * Numerical code
296    */
297   private final int code;
298 
299   /**
300    * Message associated
301    */
302   private final String mesg;
303 
304   /**
305    * LF
306    */
307   public static final String LF = "\n";
308 
309   /**
310    * CR NUL
311    */
312   public static final String CRNUL = "\r\0";
313 
314   /**
315    * CR LF<br>
316    * A User Telnet MUST be able to send any of the forms: CR LF, CR NUL, and
317    * LF.
318    * A User Telnet on an ASCII host
319    * SHOULD have a user-controllable mode to send either CR LF or CR NUL when
320    * the user presses the "end-of-line"
321    * key, and CR LF SHOULD be the default.
322    */
323   public static final String CRLF = "\r\n";
324 
325   /**
326    * Construct a Reply code from specific message
327    *
328    * @param code
329    * @param mesg
330    */
331   ReplyCode(final int code, final String mesg) {
332     this.code = code;
333     this.mesg = getFinalMsg(code, mesg);
334   }
335 
336   /**
337    * Return the final message formatted as needed from the code and the
338    * message
339    *
340    * @param code
341    * @param msg
342    *
343    * @return the final formatted message
344    */
345   public static String getFinalMsg(final int code, final String msg) {
346     final StringBuilder builder = new StringBuilder();
347     builder.append(code);
348     if (msg.indexOf('\n') == -1) {
349       builder.append(' ').append(msg).append(CRLF);
350     } else {
351       final String[] lines = msg.split("\n");
352       // first line
353       builder.append('-').append(lines[0]).append(CRLF);
354       // next lines
355       for (int i = 1; i < lines.length - 1; i++) {
356         final int firstBlank = lines[i].indexOf(' ');
357         if (firstBlank > 0) {
358           final String firstParam = lines[i].substring(0, firstBlank);
359           boolean isInt = false;
360           try {
361             Integer.parseInt(firstParam);
362             isInt = true;
363           } catch (final NumberFormatException e) {
364             // not a number
365           }
366           if (isInt) {
367             builder.append("  ");
368           }
369         }
370         builder.append(lines[i]).append(CRLF);
371       }
372       // last line
373       builder.append(code).append(' ').append(lines[lines.length - 1])
374              .append(CRLF);
375     }
376     return builder.toString();
377   }
378 
379   /**
380    * Construct a Reply Code from its name in Enum structure
381    *
382    * @param code
383    */
384   ReplyCode(final int code) {
385     this.code = code;
386     mesg = name().substring(6).replace('_', ' ') + CRLF;
387   }
388 
389   /**
390    * @return the code
391    */
392   public final int getCode() {
393     return code;
394   }
395 
396   /**
397    * @return the mesg
398    */
399   public final String getMesg() {
400     return mesg;
401   }
402 
403   /**
404    * @param code
405    *
406    * @return the associated ReplyCode from the given numerical code
407    *
408    * @throws InvalidArgumentException
409    */
410   public static ReplyCode getReplyCode(final int code)
411       throws InvalidArgumentException {
412     switch (code) {
413       case 0:
414         return REPLY_000_SPECIAL_NOSTATUS;
415       case 110:
416         return REPLY_110_RESTART_MARKER_REPLY;
417       case 120:
418         return REPLY_120_SERVICE_READY_IN_NNN_MINUTES;
419       case 125:
420         return REPLY_125_DATA_CONNECTION_ALREADY_OPEN;
421       case 150:
422         return REPLY_150_FILE_STATUS_OKAY;
423       case 200:
424         return REPLY_200_COMMAND_OKAY;
425       case 202:
426         return REPLY_202_COMMAND_NOT_IMPLEMENTED;
427       case 211:
428         return REPLY_211_SYSTEM_STATUS_REPLY;
429       case 212:
430         return REPLY_212_DIRECTORY_STATUS;
431       case 213:
432         return REPLY_213_FILE_STATUS;
433       case 214:
434         return REPLY_214_HELP_MESSAGE;
435       case 215:
436         return REPLY_215_NAME_SYSTEM_TYPE;
437       case 220:
438         return REPLY_220_SERVICE_READY;
439       case 221:
440         return REPLY_221_CLOSING_CONTROL_CONNECTION;
441       case 225:
442         return REPLY_225_DATA_CONNECTION_OPEN_NO_TRANSFER_IN_PROGRESS;
443       case 226:
444         return REPLY_226_CLOSING_DATA_CONNECTION;
445       case 227:
446         return REPLY_227_ENTERING_PASSIVE_MODE;
447       case 229:
448         return REPLY_229_ENTERING_PASSIVE_MODE;
449       case 230:
450         return REPLY_230_USER_LOGGED_IN;
451       case 232:
452         return REPLY_232_USER_LOGGED_IN;
453       case 234:
454         return REPLY_234_SECURITY_DATA_EXCHANGE_COMPLETE;
455       case 250:
456         return REPLY_250_REQUESTED_FILE_ACTION_OKAY;
457       case 257:
458         return REPLY_257_PATHNAME_CREATED;
459       case 331:
460         return REPLY_331_USER_NAME_OKAY_NEED_PASSWORD;
461       case 332:
462         return REPLY_332_NEED_ACCOUNT_FOR_LOGIN;
463       case 350:
464         return REPLY_350_REQUESTED_FILE_ACTION_PENDING_FURTHER_INFORMATION;
465       case 400:
466         return REPLY_400_BAD_REQUEST;
467       case 421:
468         return REPLY_421_SERVICE_NOT_AVAILABLE_CLOSING_CONTROL_CONNECTION;
469       case 425:
470         return REPLY_425_CANT_OPEN_DATA_CONNECTION;
471       case 426:
472         return REPLY_426_CONNECTION_CLOSED_TRANSFER_ABORTED;
473       case 431:
474         return REPLY_431_NEED_UNAVAILABLE_RESOURCE_TO_PROCESS_SECURITY;
475       case 450:
476         return REPLY_450_REQUESTED_FILE_ACTION_NOT_TAKEN;
477       case 451:
478         return REPLY_451_REQUESTED_ACTION_ABORTED;
479       case 452:
480         return REPLY_452_REQUESTED_ACTION_NOT_TAKEN;
481       case 500:
482         return REPLY_500_SYNTAX_ERROR_COMMAND_UNRECOGNIZED;
483       case 501:
484         return REPLY_501_SYNTAX_ERROR_IN_PARAMETERS_OR_ARGUMENTS;
485       case 502:
486         return REPLY_502_COMMAND_NOT_IMPLEMENTED;
487       case 503:
488         return REPLY_503_BAD_SEQUENCE_OF_COMMANDS;
489       case 504:
490         return REPLY_504_COMMAND_NOT_IMPLEMENTED_FOR_THAT_PARAMETER;
491       case 522:
492         return REPLY_522_EXTENDED_PORT_FAILURE_UNKNOWN_NETWORK_PROTOCOL;
493       case 530:
494         return REPLY_530_NOT_LOGGED_IN;
495       case 532:
496         return REPLY_532_NEED_ACCOUNT_FOR_STORING_FILES;
497       case 533:
498         return REPLY_533_COMMAND_PROTECTION_LEVEL_DENIED_FOR_POLICY_REASONS;
499       case 534:
500         return REPLY_534_REQUEST_DENIED_FOR_POLICY_REASONS;
501       case 535:
502         return REPLY_535_FAILED_SECURITY_CHECK;
503       case 536:
504         return REPLY_536_REQUESTED_PROT_LEVEL_NOT_SUPPORTED;
505       case 550:
506         return REPLY_550_REQUESTED_ACTION_NOT_TAKEN;
507       case 551:
508         return REPLY_551_REQUESTED_ACTION_ABORTED_PAGE_TYPE_UNKNOWN;
509       case 552:
510         return REPLY_552_REQUESTED_FILE_ACTION_ABORTED_EXCEEDED_STORAGE;
511       case 553:
512         return REPLY_553_REQUESTED_ACTION_NOT_TAKEN_FILE_NAME_NOT_ALLOWED;
513       default:
514         throw new InvalidArgumentException("Unknown ReplyCode " + code);
515     }
516   }
517 
518   /**
519    * @param httpCode
520    *
521    * @return the associated ReplyCode from the given numerical code
522    *
523    * @throws InvalidArgumentException
524    */
525   public static ReplyCode getReplyCodeFromHttp(final int httpCode)
526       throws InvalidArgumentException {
527     if (httpCode < 200) {
528       return REPLY_000_SPECIAL_NOSTATUS;
529     } else if (httpCode < 300) {
530       return REPLY_200_COMMAND_OKAY;
531     } else if (httpCode < 400) {
532       return REPLY_220_SERVICE_READY;
533     } else if (httpCode < 500) {
534       return REPLY_400_BAD_REQUEST;
535     } else {
536       return REPLY_500_SYNTAX_ERROR_COMMAND_UNRECOGNIZED;
537     }
538   }
539 }