KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * NewsGroupMessageBuffer.java
3  *
4  * Copyright (C) 2000-2003 Peter Graves
5  * $Id: NewsGroupMessageBuffer.java,v 1.12 2003/06/29 00:19:34 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 java.awt.Image JavaDoc;
25 import java.awt.Rectangle JavaDoc;
26 import java.io.BufferedReader JavaDoc;
27 import java.io.BufferedWriter JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.OutputStreamWriter JavaDoc;
30 import java.io.StringReader JavaDoc;
31 import java.util.List JavaDoc;
32 import javax.swing.SwingUtilities JavaDoc;
33 import org.armedbear.j.BackgroundProcess;
34 import org.armedbear.j.Buffer;
35 import org.armedbear.j.Directories;
36 import org.armedbear.j.Editor;
37 import org.armedbear.j.EditorIterator;
38 import org.armedbear.j.FastStringBuffer;
39 import org.armedbear.j.File;
40 import org.armedbear.j.Headers;
41 import org.armedbear.j.ImageLine;
42 import org.armedbear.j.ImageLoader;
43 import org.armedbear.j.Line;
44 import org.armedbear.j.Log;
45 import org.armedbear.j.Platform;
46 import org.armedbear.j.ProgressNotifier;
47 import org.armedbear.j.Property;
48 import org.armedbear.j.Sidebar;
49 import org.armedbear.j.StatusBarProgressNotifier;
50 import org.armedbear.j.TextLine;
51 import org.armedbear.j.Utilities;
52
53 public final class NewsGroupMessageBuffer extends MessageBuffer
54 {
55     private NewsGroupSummary summary;
56     private boolean cancelled;
57
58     public NewsGroupMessageBuffer(NewsGroupSummary summary,
59         NewsGroupSummaryEntry entry)
60     {
61         super();
62         this.mailbox = this.summary = summary;
63         setEntry(entry);
64         initializeUndo();
65         type = TYPE_NORMAL;
66         lineSeparator = "\n";
67         mode = MessageMode.getMode();
68         formatter = mode.getFormatter(this);
69         readOnly = true;
70         setLoaded(true);
71         setBusy(true);
72         new Thread JavaDoc(loadProcess).start();
73     }
74
75     public NewsGroupSummary getSummary()
76     {
77         return summary;
78     }
79
80     public NewsGroupSummaryEntry getNewsGroupSummaryEntry()
81     {
82         return (NewsGroupSummaryEntry) entry;
83     }
84
85     private void setEntry(NewsGroupSummaryEntry entry)
86     {
87         this.entry = entry;
88         reset();
89         title = entry.formatSubject();
90         Sidebar.setUpdateFlagInAllFrames(SIDEBAR_REPAINT_BUFFER_LIST);
91     }
92
93     public void nextArticle()
94     {
95         NewsGroupSummaryEntry nextEntry =
96             (NewsGroupSummaryEntry) summary.getNextUndeleted(entry);
97         if (nextEntry != null) {
98             empty();
99             for (EditorIterator it = new EditorIterator(); it.hasNext();) {
100                 Editor ed = it.nextEditor();
101                 if (ed.getBuffer() == this) {
102                     ed.setDot(null);
103                     ed.setMark(null);
104                     ed.setTopLine(null);
105                     ed.repaintNow();
106                 }
107             }
108             setBusy(true);
109             setEntry(nextEntry);
110             new Thread JavaDoc(loadProcess).start();
111         } else
112             Editor.currentEditor().status("Last article");
113     }
114
115     public void previousArticle()
116     {
117         NewsGroupSummaryEntry prevEntry =
118             (NewsGroupSummaryEntry) summary.getPreviousUndeleted(entry);
119         if (prevEntry != null) {
120             empty();
121             for (EditorIterator it = new EditorIterator(); it.hasNext();) {
122                 Editor ed = it.nextEditor();
123                 if (ed.getBuffer() == this) {
124                     ed.setDot(null);
125                     ed.setMark(null);
126                     ed.setTopLine(null);
127                     ed.repaintNow();
128                 }
129             }
130             setBusy(true);
131             setEntry(prevEntry);
132             new Thread JavaDoc(loadProcess).start();
133         } else
134             Editor.currentEditor().status("First article");
135     }
136
137     private final BackgroundProcess loadProcess = new BackgroundProcess()
138     {
139         private ProgressNotifier progressNotifier;
140
141         public void run()
142         {
143             setBackgroundProcess(this);
144             progressNotifier =
145                 new StatusBarProgressNotifier(NewsGroupMessageBuffer.this);
146             cancelled = false;
147             loadMessage(progressNotifier);
148             progressNotifier.setText("");
149             progressNotifier.progressStop();
150             setBackgroundProcess(null);
151         }
152
153         public void cancel()
154         {
155             cancelled = true;
156             progressNotifier.cancel();
157             summary.getSession().abort();
158             setBusy(false);
159             kill();
160         }
161     };
162
163     protected void loadMessage(ProgressNotifier progressNotifier)
164     {
165         final String JavaDoc rawText =
166             summary.getArticle(((NewsGroupSummaryEntry)entry).getArticleNumber(),
167                 progressNotifier);
168         if (cancelled)
169             return;
170         message = new Message(rawText != null ? rawText : "");
171         parseMessage();
172         title = message.getHeaderValue(Headers.SUBJECT);
173         if (title == null)
174             title = "";
175         allHeaders = message.getAllHeaders();
176         defaultHeaders = getDefaultHeaders(allHeaders);
177         rawBody = message.getRawBody();
178         setText();
179         setLoaded(true);
180         formatter.parseBuffer();
181         entry.setFlags(entry.getFlags() | MailboxEntry.SEEN);
182         if (rawText == null)
183             entry.setFlags(entry.getFlags() | MailboxEntry.DELETED);
184         summary.updateEntry(entry);
185         final MailboxLine mailboxLine =
186             summary.findLineForEntry(entry);
187         Runnable JavaDoc completionRunnable = new Runnable JavaDoc() {
188             public void run()
189             {
190                 setBusy(false);
191                 if (rawText != null) {
192                     for (EditorIterator it = new EditorIterator(); it.hasNext();) {
193                         Editor ed = it.nextEditor();
194                         if (ed.getBuffer() == NewsGroupMessageBuffer.this) {
195                             ed.setDot(getFirstLine(), 0);
196                             ed.moveCaretToDotCol();
197                             ed.getDisplay().setTopLine(getFirstLine());
198                             ed.setUpdateFlag(REPAINT);
199                             ed.updateDisplay();
200                         } else if (ed.getBuffer() == summary) {
201                             if (ed.getDot() != null) {
202                                 if (mailboxLine != null) {
203                                     ed.updateDotLine();
204                                     ed.getDot().moveTo(mailboxLine, 0);
205                                     ed.updateDotLine();
206                                     ed.moveCaretToDotCol();
207                                 }
208                             }
209                             ed.clearStatusText();
210                             ed.updateDisplay();
211                         }
212                     }
213                     Sidebar.repaintBufferListInAllFrames();
214                 }
215             }
216         };
217         SwingUtilities.invokeLater(completionRunnable);
218     }
219
220     private static boolean containsBinary(String JavaDoc text)
221     {
222         BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new StringReader JavaDoc(text));
223         try {
224             String JavaDoc s;
225             while ((s = reader.readLine()) != null) {
226                 final int length = s.length();
227                 if (length >= 9 && s.startsWith("begin "))
228                     return true;
229                 if (length > 7 && s.startsWith("=ybegin"))
230                     return true;
231                 if (length > 0 && s.charAt(0) == 0)
232                     return true;
233             }
234         }
235         catch (IOException JavaDoc e) {
236             Log.error(e);
237         }
238         return false;
239     }
240
241     private void appendBody(String JavaDoc rawBody)
242     {
243         BufferedReader JavaDoc reader = new BufferedReader JavaDoc(new StringReader JavaDoc(rawBody));
244         try {
245             String JavaDoc s;
246             while ((s = reader.readLine()) != null) {
247                 final int length = s.length();
248                 if (length >= 9 && s.startsWith("begin ") && haveUudecode()) {
249                     // "begin 644 filename" or "begin 0644 filename"
250
// Skip "begin ".
251
String JavaDoc trim = s.substring(6).trim();
252                     // Next token is permission.
253
String JavaDoc permission = null;
254                     int index = trim.indexOf(' ');
255                     if (index >= 0) {
256                         permission = trim.substring(0, index);
257                         trim = trim.substring(index+1);
258                     }
259                     String JavaDoc extension = Utilities.getExtension(trim);
260                     File encoded =
261                         Utilities.getTempFile(Directories.getTempDirectory(),
262                                               ".encoded");
263                     File decoded =
264                         Utilities.getTempFile(Directories.getTempDirectory(),
265                                               extension);
266                     FastStringBuffer sb = new FastStringBuffer("begin 644 ");
267                     sb.append(decoded.getName());
268                     BufferedWriter JavaDoc writer = new BufferedWriter JavaDoc(
269                         new OutputStreamWriter JavaDoc(encoded.getOutputStream(),
270                             "ISO-8859-1"));
271                     writer.write(sb.toString());
272                     writer.write('\n');
273                     while ((s = reader.readLine()) != null) {
274                         writer.write(s);
275                         writer.write('\n');
276                         if (s.equals("end")) {
277                             writer.flush();
278                             writer.close();
279                             break;
280                         }
281                     }
282                     if (decode(encoded, "uudecode"))
283                         appendImageLine(decoded);
284                     encoded.delete();
285                     decoded.delete();
286                 } else if (length > 7 && s.startsWith("=ybegin") && haveYydecode()) {
287                     final String JavaDoc lookFor = " name=";
288                     int index = s.indexOf(lookFor);
289                     if (index < 0) {
290                         s = s.concat(lookFor);
291                         index = s.length();
292                     } else
293                         index += lookFor.length();
294                     String JavaDoc name = s.substring(index);
295                     String JavaDoc extension = Utilities.getExtension(name);
296                     File encoded =
297                         Utilities.getTempFile(Directories.getTempDirectory(),
298                                               ".encoded");
299                     File decoded =
300                         Utilities.getTempFile(Directories.getTempDirectory(),
301                                               extension);
302                     BufferedWriter JavaDoc writer = new BufferedWriter JavaDoc(
303                         new OutputStreamWriter JavaDoc(encoded.getOutputStream(),
304                             "ISO-8859-1"));
305                     FastStringBuffer sb =
306                         new FastStringBuffer(s.substring(0, index));
307                     sb.append(decoded.getName());
308                     writer.write(sb.toString());
309                     writer.write('\n');
310                     while ((s = reader.readLine()) != null) {
311                         writer.write(s);
312                         if (s.startsWith("=yend")) {
313                             writer.flush();
314                             writer.close();
315                             break;
316                         }
317                         writer.write('\n');
318                     }
319                     if (decode(encoded, "yydecode -b"))
320                         appendImageLine(decoded);
321                     encoded.delete();
322                     decoded.delete();
323                 } else if (length > 0 && s.charAt(0) == 0) {
324                     // Don't append a string composed entirely of null bytes.
325
boolean empty = true;
326                     for (int i = length; i-- > 0;) {
327                         if (s.charAt(i) != 0) {
328                             empty = false;
329                             break;
330                         }
331                     }
332                     appendLine(empty ? "" : s);
333                 } else {
334                     // Normal text.
335
appendLine(s);
336                 }
337             }
338             renumber();
339             invalidate();
340         }
341         catch (IOException JavaDoc e) {
342             Log.error(e);
343         }
344     }
345
346     private boolean decode(File encoded, String JavaDoc decodeCommand)
347     {
348         FastStringBuffer sb = new FastStringBuffer("(\\cd \"");
349         sb.append(Directories.getTempDirectory().canonicalPath());
350         sb.append("\" && ");
351         sb.append(decodeCommand);
352         sb.append(" \"");
353         sb.append(encoded.getName());
354         sb.append("\")");
355         String JavaDoc[] cmdarray = {"/bin/sh", "-c", sb.toString()};
356         try {
357             Process JavaDoc process = Runtime.getRuntime().exec(cmdarray);
358             if (process != null) {
359                 process.waitFor();
360                 return true;
361             }
362         }
363         catch (Throwable JavaDoc t) {
364             Log.error(t);
365         }
366         return false;
367     }
368
369     private void appendImageLine(File decoded)
370     {
371         ImageLoader loader = new ImageLoader(decoded);
372         Image JavaDoc image = loader.loadImage();
373         if (image != null) {
374             final int lineHeight = new TextLine("").getHeight();
375             final int imageHeight = image.getHeight(null);
376             final int imageWidth = image.getWidth(null);
377             int y = 0;
378             while (y < imageHeight) {
379                 Rectangle JavaDoc r = new Rectangle JavaDoc(0, y, imageWidth,
380                     Math.min(lineHeight, imageHeight - y));
381                 appendLine(new ImageLine(image, r));
382                 y += lineHeight;
383             }
384         }
385     }
386
387     // We only look for uudecode and yydecode on Unix platforms.
388
private static int haveUudecode = Platform.isPlatformUnix() ? -1 : 0;
389     private static int haveYydecode = Platform.isPlatformUnix() ? -1 : 0;
390
391     private static boolean haveUudecode()
392     {
393         if (haveUudecode < 0)
394             haveUudecode = Utilities.have("uudecode -h") ? 1 : 0;
395         return haveUudecode == 1;
396     }
397
398     private static boolean haveYydecode()
399     {
400         if (haveYydecode < 0)
401             haveYydecode = Utilities.have("yydecode -h") ? 1 : 0;
402         return haveYydecode == 1;
403     }
404
405     public void viewInline()
406     {
407         Line line;
408         for (line = getFirstLine(); line != null; line = line.next()) {
409             if (line.length() == 0)
410                 break; // Reached end of headers.
411
}
412         for (; line != null; line = line.next()) {
413             String JavaDoc s = line.getText();
414             if (s.startsWith("Inline: ")) {
415                 String JavaDoc filename = s.substring(8);
416                 File f =
417                     File.getInstance(Directories.getTempDirectory(), filename);
418                 if (f.isFile()) {
419                     Editor editor = Editor.currentEditor();
420                     Buffer buf = editor.openFile(f);
421                     editor.makeNext(buf);
422                     editor.activate(buf);
423                     editor.maybeKillBuffer(this);
424                     return;
425                 }
426             }
427         }
428     }
429
430     public void toggleHeaders()
431     {
432         showFullHeaders = !showFullHeaders;
433         empty();
434         setText();
435         formatter.parseBuffer();
436         for (EditorIterator it = new EditorIterator(); it.hasNext();) {
437             Editor ed = it.nextEditor();
438             if (ed.getBuffer() == this) {
439                 ed.setDot(getFirstLine(), 0);
440                 ed.setTopLine(ed.getDotLine());
441                 ed.setMark(null);
442                 ed.repaintDisplay();
443             }
444         }
445     }
446
447     public void toggleRaw()
448     {
449         showRawText = !showRawText;
450         empty();
451         setText();
452         formatter.parseBuffer();
453         for (EditorIterator it = new EditorIterator(); it.hasNext();) {
454             Editor ed = it.nextEditor();
455             if (ed.getBuffer() == this) {
456                 ed.setDot(getFirstLine(), 0);
457                 ed.setTopLine(ed.getDotLine());
458                 ed.setMark(null);
459                 ed.repaintDisplay();
460             }
461         }
462         Editor.currentEditor().status("Raw mode ".concat((showRawText ? "on" : "off")));
463     }
464
465     protected void setText()
466     {
467         empty();
468         if (showRawText) {
469             super.setText();
470             return;
471         }
472         String JavaDoc contentType = message.getContentType();
473         if (contentType != null && contentType.startsWith("image/"))
474             super.setText();
475         else {
476             List JavaDoc parts = message.getParts();
477             if (parts != null && parts.size() > 0) {
478                 super.setText();
479             } else {
480                 // Not MIME multipart.
481
if (containsBinary(rawBody)) {
482                     String JavaDoc headers;
483                     if (showFullHeaders)
484                         headers = allHeaders;
485                     else if (Editor.preferences().getBooleanProperty(Property.BEAUTIFY_HEADERS))
486                         headers = getBeautifiedHeaders();
487                     else
488                         headers = defaultHeaders;
489                     try {
490                         lockWrite();
491                     }
492                     catch (InterruptedException JavaDoc e) {
493                         Log.error(e);
494                         return;
495                     }
496                     try {
497                         appendHeaderLines(headers);
498                         headerLineCount = Utilities.countLines(headers);
499                         appendHeaderLine("");
500                         appendBody(rawBody);
501                     }
502                     finally {
503                         unlockWrite();
504                     }
505                 } else
506                     super.setText();
507             }
508         }
509     }
510 }
511
Popular Tags