1 /**************************************************************** 2 * Licensed to the Apache Software Foundation (ASF) under one * 3 * or more contributor license agreements. See the NOTICE file * 4 * distributed with this work for additional information * 5 * regarding copyright ownership. The ASF licenses this file * 6 * to you under the Apache License, Version 2.0 (the * 7 * "License"); you may not use this file except in compliance * 8 * with the License. You may obtain a copy of the License at * 9 * * 10 * http://www.apache.org/licenses/LICENSE-2.0 * 11 * * 12 * Unless required by applicable law or agreed to in writing, * 13 * software distributed under the License is distributed on an * 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * 15 * KIND, either express or implied. See the License for the * 16 * specific language governing permissions and limitations * 17 * under the License. * 18 ****************************************************************/ 19 20 package org.apache.james.mime4j.field; 21 22 import java.util.regex.Matcher; 23 import java.util.regex.Pattern; 24 25 /** 26 * The base class of all field classes. 27 * 28 * 29 * @version $Id: Field.java,v 1.6 2004/10/25 07:26:46 ntherning Exp $ 30 */ 31 public abstract class Field { 32 public static final String SENDER = "Sender"; 33 public static final String FROM = "From"; 34 public static final String TO = "To"; 35 public static final String CC = "Cc"; 36 public static final String BCC = "Bcc"; 37 public static final String REPLY_TO = "Reply-To"; 38 public static final String RESENT_SENDER = "Resent-Sender"; 39 public static final String RESENT_FROM = "Resent-From"; 40 public static final String RESENT_TO = "Resent-To"; 41 public static final String RESENT_CC = "Resent-Cc"; 42 public static final String RESENT_BCC = "Resent-Bcc"; 43 44 public static final String DATE = "Date"; 45 public static final String RESENT_DATE = "Resent-Date"; 46 47 public static final String SUBJECT = "Subject"; 48 public static final String CONTENT_TYPE = "Content-Type"; 49 public static final String CONTENT_TRANSFER_ENCODING = 50 "Content-Transfer-Encoding"; 51 52 private static final String FIELD_NAME_PATTERN = 53 "^([\\x21-\\x39\\x3b-\\x7e]+)[ \t]*:"; 54 private static final Pattern fieldNamePattern = 55 Pattern.compile(FIELD_NAME_PATTERN); 56 57 private static final DefaultFieldParser parser = new DefaultFieldParser(); 58 59 private final String name; 60 private final String body; 61 private final String raw; 62 63 protected Field(final String name, final String body, final String raw) { 64 this.name = name; 65 this.body = body; 66 this.raw = raw; 67 } 68 69 /** 70 * Parses the given string and returns an instance of the 71 * <code>Field</code> class. The type of the class returned depends on 72 * the field name: 73 * <table> 74 * <tr> 75 * <td><em>Field name</em></td><td><em>Class returned</em></td> 76 * <td>Content-Type</td><td>org.apache.james.mime4j.field.ContentTypeField</td> 77 * <td>other</td><td>org.apache.james.mime4j.field.UnstructuredField</td> 78 * </tr> 79 * </table> 80 * 81 * @param s the string to parse. 82 * @return a <code>Field</code> instance. 83 * @throws IllegalArgumentException on parse errors. 84 */ 85 public static Field parse(final String raw) { 86 87 /* 88 * Unfold the field. 89 */ 90 final String unfolded = raw.replaceAll("\r|\n", ""); 91 92 /* 93 * Split into name and value. 94 */ 95 final Matcher fieldMatcher = fieldNamePattern.matcher(unfolded); 96 if (!fieldMatcher.find()) { 97 throw new IllegalArgumentException("Invalid field in string"); 98 } 99 final String name = fieldMatcher.group(1); 100 101 String body = unfolded.substring(fieldMatcher.end()); 102 if (body.length() > 0 && body.charAt(0) == ' ') { 103 body = body.substring(1); 104 } 105 106 return parser.parse(name, body, raw); 107 } 108 109 /** 110 * Gets the default parser used to parse fields. 111 * @return the default field parser 112 */ 113 public static DefaultFieldParser getParser() { 114 return parser; 115 } 116 117 /** 118 * Gets the name of the field (<code>Subject</code>, 119 * <code>From</code>, etc). 120 * 121 * @return the field name. 122 */ 123 public String getName() { 124 return name; 125 } 126 127 /** 128 * Gets the original raw field string. 129 * 130 * @return the original raw field string. 131 */ 132 public String getRaw() { 133 return raw; 134 } 135 136 /** 137 * Gets the unfolded, unparsed and possibly encoded (see RFC 2047) field 138 * body string. 139 * 140 * @return the unfolded unparsed field body string. 141 */ 142 public String getBody() { 143 return body; 144 } 145 146 /** 147 * Determines if this is a <code>Content-Type</code> field. 148 * 149 * @return <code>true</code> if this is a <code>Content-Type</code> field, 150 * <code>false</code> otherwise. 151 */ 152 public boolean isContentType() { 153 return CONTENT_TYPE.equalsIgnoreCase(name); 154 } 155 156 /** 157 * Determines if this is a <code>Subject</code> field. 158 * 159 * @return <code>true</code> if this is a <code>Subject</code> field, 160 * <code>false</code> otherwise. 161 */ 162 public boolean isSubject() { 163 return SUBJECT.equalsIgnoreCase(name); 164 } 165 166 /** 167 * Determines if this is a <code>From</code> field. 168 * 169 * @return <code>true</code> if this is a <code>From</code> field, 170 * <code>false</code> otherwise. 171 */ 172 public boolean isFrom() { 173 return FROM.equalsIgnoreCase(name); 174 } 175 176 /** 177 * Determines if this is a <code>To</code> field. 178 * 179 * @return <code>true</code> if this is a <code>To</code> field, 180 * <code>false</code> otherwise. 181 */ 182 public boolean isTo() { 183 return TO.equalsIgnoreCase(name); 184 } 185 186 /** 187 * @see #getRaw() 188 */ 189 public String toString() { 190 return raw; 191 } 192 } 193