1 21 22 package org.armedbear.j.mail; 23 24 import gnu.regexp.RE; 25 import gnu.regexp.UncheckedRE; 26 import org.armedbear.j.Buffer; 27 import org.armedbear.j.Debug; 28 import org.armedbear.j.DiffFormatter; 29 import org.armedbear.j.Editor; 30 import org.armedbear.j.FormatTable; 31 import org.armedbear.j.Formatter; 32 import org.armedbear.j.Line; 33 import org.armedbear.j.LineSegmentList; 34 import org.armedbear.j.Utilities; 35 36 public final class MessageFormatter extends Formatter 37 { 38 private static final int MESSAGE_FORMAT_FIRST = 40 DiffFormatter.DIFF_FORMAT_LAST + 1; 41 42 private static final byte MESSAGE_FORMAT_TEXT = MESSAGE_FORMAT_FIRST; 43 private static final byte MESSAGE_FORMAT_COMMENT = MESSAGE_FORMAT_FIRST + 1; 44 private static final byte MESSAGE_FORMAT_HEADER_NAME = MESSAGE_FORMAT_FIRST + 2; 45 private static final byte MESSAGE_FORMAT_HEADER_VALUE = MESSAGE_FORMAT_FIRST + 3; 46 private static final byte MESSAGE_FORMAT_QUOTE = MESSAGE_FORMAT_FIRST + 4; 47 private static final byte MESSAGE_FORMAT_SIGNATURE = MESSAGE_FORMAT_FIRST + 5; 48 private static final byte MESSAGE_FORMAT_DIFF = MESSAGE_FORMAT_FIRST + 6; 49 50 private static final RE quoteRE = new UncheckedRE("^[a-zA-Z]*>"); 51 52 private static final RE headerRE = new UncheckedRE("^ *[a-zA-Z\\-/]+:"); 54 55 private Line startOfBody; 56 57 private final DiffFormatter diffFormatter; 58 59 public MessageFormatter(Buffer buffer) 60 { 61 this.buffer = buffer; 62 diffFormatter = new DiffFormatter(buffer); 63 } 64 65 public synchronized LineSegmentList formatLine(Line line) 66 { 67 if (line.flags() == MESSAGE_FORMAT_DIFF) 68 return diffFormatter.formatLine(line); 69 final String text = getDetabbedText(line); 70 clearSegmentList(); 71 if (line.flags() == MESSAGE_FORMAT_SIGNATURE) { 72 addSegment(text, MESSAGE_FORMAT_SIGNATURE); 73 return segmentList; 74 } 75 String trim = text.trim(); 76 if (trim.length() == 0) { 77 addSegment(text, MESSAGE_FORMAT_TEXT); 79 return segmentList; 80 } 81 if (startOfBody == null || line.lineNumber() < startOfBody.lineNumber()) { 82 if (text.length() > 0) { 84 int i = text.indexOf(':'); 85 if (i >= 0 && headerRE.getMatch(text) != null) { 86 String headerName = text.substring(0, i).trim(); 87 if (isKeyword(headerName)) { 88 addSegment(text, 0, i+1, MESSAGE_FORMAT_HEADER_NAME); 89 addSegment(text, i+1, MESSAGE_FORMAT_HEADER_VALUE); 90 return segmentList; 91 } 92 } 93 } 94 if (line.flags() == MESSAGE_FORMAT_HEADER_VALUE) 95 addSegment(text, MESSAGE_FORMAT_HEADER_VALUE); 96 else 97 addSegment(text, MESSAGE_FORMAT_COMMENT); 98 return segmentList; 99 } 100 char c = trim.charAt(0); 101 if (c == '>') { 102 if (trim.startsWith(">>>>> ")) { 103 addSegment(text, MESSAGE_FORMAT_TEXT); 105 } else if (trim.startsWith(">From ")) { 106 addSegment(text, MESSAGE_FORMAT_TEXT); 107 } else { 108 addSegment(text, MESSAGE_FORMAT_QUOTE); 109 } 110 return segmentList; 111 } 112 if (quoteRE.getMatch(text) != null) { 113 addSegment(text, MESSAGE_FORMAT_QUOTE); 114 return segmentList; 115 } 116 addSegment(text, MESSAGE_FORMAT_TEXT); 117 return segmentList; 118 } 119 120 public synchronized boolean parseBuffer() 121 { 122 startOfBody = null; 123 boolean inDiff = false; 124 boolean inSig = false; 125 if (buffer.needsRenumbering()) 126 buffer.renumber(); 127 for (Line line = buffer.getFirstLine(); line != null; line = line.next()) { 128 if (buffer instanceof MessageBuffer) { 129 if (line.lineNumber() == ((MessageBuffer)buffer).getHeaderLineCount()) { 130 if (startOfBody != null) 131 Debug.bug(); 132 startOfBody = line; 133 } 134 } 135 String text = line.getText(); 136 if (text == null) 137 continue; 138 if (startOfBody == null) { 139 if (buffer instanceof SendMail && text.equals(SendMail.getHeaderSeparator())) 140 startOfBody = line.next(); 141 else { 142 int i = text.indexOf(':'); 143 if (i >= 0 && headerRE.getMatch(text) != null) { 144 String headerName = text.substring(0, i).trim(); 145 if (isKeyword(headerName)) 146 line.setFlags(MESSAGE_FORMAT_HEADER_VALUE); 147 else 148 line.setFlags(0); 149 } 150 else if (line.previous() != null) 151 line.setFlags(line.previous().flags()); 152 } 153 } else { 154 if (text.equals("-- ")) { 156 inSig = true; 157 inDiff = false; 158 line.setFlags(MESSAGE_FORMAT_SIGNATURE); 159 continue; 160 } 161 if (inDiff) { 162 if (isDiffContinuation(line)) { 163 line.setFlags(MESSAGE_FORMAT_DIFF); 164 continue; 165 } 166 inDiff = false; 167 } else if (isDiffStart(line)) { 169 inDiff = true; 170 line.setFlags(MESSAGE_FORMAT_DIFF); 171 continue; 172 } 173 if (inDiff) 174 Debug.bug(); 175 if (inSig) { 176 line.setFlags(MESSAGE_FORMAT_SIGNATURE); 177 continue; 178 } 179 line.setFlags(0); 181 if (text.length() == 0) 182 continue; 183 final char c = text.charAt(0); 184 if (buffer.getLineCount() - line.lineNumber() < 16) { 185 if (c == '_' || c == '-') { 186 text = text.trim(); 188 boolean all = true; 189 for (int i = text.length(); i-- > 0;) { 190 if (text.charAt(i) != c) { 191 all = false; 192 break; 193 } 194 } 195 if (all) { 196 inSig = true; 197 line.setFlags(MESSAGE_FORMAT_SIGNATURE); 198 continue; 199 } 200 } 201 } 202 } 203 } 204 buffer.setNeedsParsing(false); 205 return true; 206 } 207 208 public static boolean isDiffStart(Line line) 209 { 210 String text = line.trim(); 211 if (text.startsWith("+++ ")) 212 return true; 213 if (text.startsWith("--- ")) 214 return true; 215 if (text.startsWith("@@ ")) 216 return true; 217 if (text.startsWith("@") && text.endsWith("@")) 218 return true; 219 if (text.startsWith("diff ")) { 220 Line nextLine = line.next(); 221 if (nextLine != null && nextLine.trim().startsWith("---")) 222 return true; 223 } else if (text.startsWith("Index: ")) { 224 Line nextLine = line.next(); 225 if (nextLine != null) { 226 String s = nextLine.trim(); 227 if (s.startsWith("diff ") || s.startsWith("========")) 228 return true; 229 } 230 } 231 return false; 232 } 233 234 public static boolean isDiffContinuation(Line line) 235 { 236 if (line.length() == 0) 237 return true; 238 final char c = line.charAt(0); 239 if (c == ' ') 240 return true; 241 if (c == '+') 242 return true; 243 if (c == '-') { 244 Line nextLine = line.next(); 245 return (nextLine != null && isDiffContinuation(nextLine)); 246 } 247 String text = line.getText(); 248 if (text.startsWith("diff ")) 249 return true; 250 if (text.startsWith("Index: ")) 251 return true; 252 if (text.startsWith("========")) 253 return true; 254 if (text.startsWith("RCS file: ")) 255 return true; 256 if (text.startsWith("retrieving ")) 257 return true; 258 if (text.startsWith("@@")) 259 return true; 260 if (text.startsWith("@") && text.endsWith("@")) 261 return true; 262 return false; 263 } 264 265 public FormatTable getFormatTable() 266 { 267 if (formatTable == null) { 268 formatTable = diffFormatter.getFormatTable(); 269 formatTable.setModeName("MessageMode"); 270 formatTable.addEntryFromPrefs(MESSAGE_FORMAT_TEXT, "text"); 271 formatTable.addEntryFromPrefs(MESSAGE_FORMAT_COMMENT, "comment"); 272 formatTable.addEntryFromPrefs(MESSAGE_FORMAT_HEADER_NAME, "headerName", "keyword"); 273 formatTable.addEntryFromPrefs(MESSAGE_FORMAT_HEADER_VALUE, "headerValue", "operator"); 274 formatTable.addEntryFromPrefs(MESSAGE_FORMAT_QUOTE, "string"); 275 formatTable.addEntryFromPrefs(MESSAGE_FORMAT_SIGNATURE, "signature", "comment"); 276 } 277 return formatTable; 278 } 279 280 public void reset() 281 { 282 diffFormatter.reset(); 283 super.reset(); 284 } 285 } 286 | Popular Tags |