1/* Copyright 2016 Software Freedom Conservancy Inc. 2 * 3 * This software is licensed under the GNU Lesser General Public License 4 * (version 2.1 or later). See the COPYING file in this distribution. 5 */ 6 7public class Geary.Smtp.ResponseCode { 8 public const int STRLEN = 3; 9 10 public const int MIN = 100; 11 public const int MAX = 599; 12 13 public const string START_DATA_CODE = "354"; 14 public const string STARTTLS_READY_CODE = "220"; 15 public const string DENIED_CODE = "550"; 16 17 public enum Status { 18 POSITIVE_PRELIMINARY = 1, 19 POSITIVE_COMPLETION = 2, 20 POSITIVE_INTERMEDIATE = 3, 21 TRANSIENT_NEGATIVE = 4, 22 PERMANENT_FAILURE = 5, 23 UNKNOWN = -1; 24 } 25 26 public enum Condition { 27 SYNTAX = 0, 28 ADDITIONAL_INFO = 1, 29 COMM_CHANNEL = 2, 30 MAIL_SYSTEM = 5, 31 UNKNOWN = -1 32 } 33 34 private string str; 35 36 public ResponseCode(string str) throws SmtpError { 37 // these two checks are sufficient to make sure the Status is valid, but not the Condition 38 if (str.length != STRLEN) 39 throw new SmtpError.PARSE_ERROR("Reply code wrong length: %s (%d)", str, str.length); 40 41 int as_int = int.parse(str); 42 if (as_int < MIN || as_int > MAX) 43 throw new SmtpError.PARSE_ERROR("Reply code out of range: %s", str); 44 45 this.str = str; 46 } 47 48 public Status get_status() { 49 int i = Ascii.digit_to_int(str[0]); 50 51 // This works because of the checks in the constructor; Condition can't be checked so 52 // easily 53 return (i != -1) ? (Status) i : Status.UNKNOWN; 54 } 55 56 public Condition get_condition() { 57 switch (Ascii.digit_to_int(str[1])) { 58 case Condition.SYNTAX: 59 return Condition.SYNTAX; 60 61 case Condition.ADDITIONAL_INFO: 62 return Condition.ADDITIONAL_INFO; 63 64 case Condition.COMM_CHANNEL: 65 return Condition.COMM_CHANNEL; 66 67 case Condition.MAIL_SYSTEM: 68 return Condition.MAIL_SYSTEM; 69 70 default: 71 return Condition.UNKNOWN; 72 } 73 } 74 75 public bool is_success_completed() { 76 return get_status() == Status.POSITIVE_COMPLETION; 77 } 78 79 public bool is_success_intermediate() { 80 switch (get_status()) { 81 case Status.POSITIVE_PRELIMINARY: 82 case Status.POSITIVE_INTERMEDIATE: 83 return true; 84 85 default: 86 return false; 87 } 88 } 89 90 public bool is_failure() { 91 switch (get_status()) { 92 case Status.PERMANENT_FAILURE: 93 case Status.TRANSIENT_NEGATIVE: 94 return true; 95 96 default: 97 return false; 98 } 99 } 100 101 public bool is_start_data() { 102 return str == START_DATA_CODE; 103 } 104 105 public bool is_starttls_ready() { 106 return str == STARTTLS_READY_CODE; 107 } 108 109 public bool is_denied() { 110 return str == DENIED_CODE; 111 } 112 113 /** 114 * Returns true for [@link Status.PERMANENT_FAILURE} {@link Condition.SYNTAX} errors. 115 * 116 * Generally this means the command (or sequence of commands) was unknown or unimplemented, 117 * i.e. "500 Syntax error", "502 Command not implemented", etc. 118 * 119 * See [[http://tools.ietf.org/html/rfc5321#section-4.2.2]] 120 */ 121 public bool is_syntax_error() { 122 return get_status() == ResponseCode.Status.PERMANENT_FAILURE 123 && get_condition() == ResponseCode.Condition.SYNTAX; 124 } 125 126 public string serialize() { 127 return str; 128 } 129 130 public string to_string() { 131 return str; 132 } 133} 134 135