1 21 22 package org.armedbear.j.mail; 23 24 import java.awt.Image ; 25 import java.awt.Rectangle ; 26 import java.io.BufferedReader ; 27 import java.io.BufferedWriter ; 28 import java.io.IOException ; 29 import java.io.OutputStreamWriter ; 30 import java.io.StringReader ; 31 import java.util.List ; 32 import javax.swing.SwingUtilities ; 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 (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 (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 (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 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 completionRunnable = new Runnable () { 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 text) 221 { 222 BufferedReader reader = new BufferedReader (new StringReader (text)); 223 try { 224 String 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 e) { 236 Log.error(e); 237 } 238 return false; 239 } 240 241 private void appendBody(String rawBody) 242 { 243 BufferedReader reader = new BufferedReader (new StringReader (rawBody)); 244 try { 245 String s; 246 while ((s = reader.readLine()) != null) { 247 final int length = s.length(); 248 if (length >= 9 && s.startsWith("begin ") && haveUudecode()) { 249 String trim = s.substring(6).trim(); 252 String 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 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 writer = new BufferedWriter ( 269 new OutputStreamWriter (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 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 name = s.substring(index); 295 String 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 writer = new BufferedWriter ( 303 new OutputStreamWriter (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 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 appendLine(s); 336 } 337 } 338 renumber(); 339 invalidate(); 340 } 341 catch (IOException e) { 342 Log.error(e); 343 } 344 } 345 346 private boolean decode(File encoded, String 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 [] cmdarray = {"/bin/sh", "-c", sb.toString()}; 356 try { 357 Process process = Runtime.getRuntime().exec(cmdarray); 358 if (process != null) { 359 process.waitFor(); 360 return true; 361 } 362 } 363 catch (Throwable 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 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 r = new Rectangle (0, y, imageWidth, 380 Math.min(lineHeight, imageHeight - y)); 381 appendLine(new ImageLine(image, r)); 382 y += lineHeight; 383 } 384 } 385 } 386 387 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; } 412 for (; line != null; line = line.next()) { 413 String s = line.getText(); 414 if (s.startsWith("Inline: ")) { 415 String 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 contentType = message.getContentType(); 473 if (contentType != null && contentType.startsWith("image/")) 474 super.setText(); 475 else { 476 List parts = message.getParts(); 477 if (parts != null && parts.size() > 0) { 478 super.setText(); 479 } else { 480 if (containsBinary(rawBody)) { 482 String 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 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 |