KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > mail > MessageFormatter


1 /*
2  * MessageFormatter.java
3  *
4  * Copyright (C) 1998-2003 Peter Graves
5  * $Id: MessageFormatter.java,v 1.8 2003/07/03 18:08:13 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

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     // Message formats must not overlap with diff formats!
39
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     // Includes '/' for "Parts/Attachments".
53
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 JavaDoc text = getDetabbedText(line);
70         clearSegmentList();
71         if (line.flags() == MESSAGE_FORMAT_SIGNATURE) {
72             addSegment(text, MESSAGE_FORMAT_SIGNATURE);
73             return segmentList;
74         }
75         String JavaDoc trim = text.trim();
76         if (trim.length() == 0) {
77             // Line is empty or all whitespace.
78
addSegment(text, MESSAGE_FORMAT_TEXT);
79             return segmentList;
80         }
81         if (startOfBody == null || line.lineNumber() < startOfBody.lineNumber()) {
82             // We're in the message headers.
83
if (text.length() > 0) {
84                 int i = text.indexOf(':');
85                 if (i >= 0 && headerRE.getMatch(text) != null) {
86                     String JavaDoc 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                 // Supercite attribution line.
104
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 JavaDoc 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 JavaDoc 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                 // We're in the body of the message.
155
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                     // Fall through...
168
} 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                 // Neutral state.
180
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                         // See if line is all underscores or all hyphens.
187
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 JavaDoc 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 JavaDoc 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 JavaDoc 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