Source Code Cross Referenced for SendMail.java in  » IDE » J » org » armedbear » j » mail » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE » J » org.armedbear.j.mail 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * SendMail.java
0003:         *
0004:         * Copyright (C) 2000-2003 Peter Graves
0005:         * $Id: SendMail.java,v 1.9 2003/08/09 17:42:30 piso Exp $
0006:         *
0007:         * This program is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU General Public License
0009:         * as published by the Free Software Foundation; either version 2
0010:         * of the License, or (at your option) any later version.
0011:         *
0012:         * This program is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015:         * GNU General Public License for more details.
0016:         *
0017:         * You should have received a copy of the GNU General Public License
0018:         * along with this program; if not, write to the Free Software
0019:         * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
0020:         */
0021:
0022:        package org.armedbear.j.mail;
0023:
0024:        import gnu.regexp.RE;
0025:        import gnu.regexp.REMatch;
0026:        import gnu.regexp.UncheckedRE;
0027:        import java.io.BufferedInputStream;
0028:        import java.io.BufferedReader;
0029:        import java.io.BufferedWriter;
0030:        import java.io.FileInputStream;
0031:        import java.io.FileWriter;
0032:        import java.io.IOException;
0033:        import java.io.InputStreamReader;
0034:        import java.io.OutputStreamWriter;
0035:        import java.io.Writer;
0036:        import java.text.SimpleDateFormat;
0037:        import java.util.ArrayList;
0038:        import java.util.Calendar;
0039:        import java.util.List;
0040:        import java.util.Random;
0041:        import javax.swing.Icon;
0042:        import javax.swing.SwingUtilities;
0043:        import javax.swing.undo.CompoundEdit;
0044:        import org.armedbear.j.Buffer;
0045:        import org.armedbear.j.BufferIterator;
0046:        import org.armedbear.j.Debug;
0047:        import org.armedbear.j.Directories;
0048:        import org.armedbear.j.Editor;
0049:        import org.armedbear.j.EditorIterator;
0050:        import org.armedbear.j.Expansion;
0051:        import org.armedbear.j.File;
0052:        import org.armedbear.j.FastStringBuffer;
0053:        import org.armedbear.j.Headers;
0054:        import org.armedbear.j.Line;
0055:        import org.armedbear.j.Log;
0056:        import org.armedbear.j.MessageDialog;
0057:        import org.armedbear.j.OpenFileDialog;
0058:        import org.armedbear.j.Platform;
0059:        import org.armedbear.j.Position;
0060:        import org.armedbear.j.Preferences;
0061:        import org.armedbear.j.Property;
0062:        import org.armedbear.j.Region;
0063:        import org.armedbear.j.Sidebar;
0064:        import org.armedbear.j.SimpleEdit;
0065:        import org.armedbear.j.Utilities;
0066:        import org.armedbear.j.Version;
0067:
0068:        public final class SendMail extends Buffer {
0069:            private final static String HEADER_SEPARATOR = "--text follows this line--";
0070:            private final static String DEFAULT_TITLE = "Compose";
0071:
0072:            private static Preferences preferences;
0073:
0074:            private boolean reply;
0075:            private List group;
0076:            private Mailbox mailbox;
0077:            private MailboxEntry entryRepliedTo;
0078:            private String boundary;
0079:            private String smtp;
0080:            private SmtpSession session;
0081:            private boolean hasBeenSent;
0082:
0083:            public SendMail() {
0084:                super ();
0085:                init();
0086:                try {
0087:                    lockWrite();
0088:                } catch (InterruptedException e) {
0089:                    Log.debug(e);
0090:                    return;
0091:                }
0092:                try {
0093:                    appendFrom();
0094:                    appendLine("To: ");
0095:                    appendLine("Subject: ");
0096:                    appendDefaultHeaders();
0097:                    appendLine(HEADER_SEPARATOR);
0098:                    appendLine("");
0099:                    appendSignature();
0100:                    renumber();
0101:                    formatter.parseBuffer();
0102:                    setLoaded(true);
0103:                } finally {
0104:                    unlockWrite();
0105:                }
0106:            }
0107:
0108:            // Re-opening an unsent message.
0109:            public SendMail(File file) {
0110:                super ();
0111:                setFile(file);
0112:                init();
0113:            }
0114:
0115:            // Forward.
0116:            public SendMail(MessageBuffer messageBuffer) {
0117:                super ();
0118:                init();
0119:                mailbox = messageBuffer.getMailbox();
0120:                entryRepliedTo = messageBuffer.getMailboxEntry();
0121:                try {
0122:                    lockWrite();
0123:                } catch (InterruptedException e) {
0124:                    Log.debug(e);
0125:                    return;
0126:                }
0127:                try {
0128:                    appendFrom();
0129:                    appendLine("To: ");
0130:                    appendLine("Subject: [Fwd: " + entryRepliedTo.getSubject()
0131:                            + "]");
0132:                    appendDefaultHeaders();
0133:                    appendLine(HEADER_SEPARATOR);
0134:                    appendLine("");
0135:                    Position pos = new Position(getLastLine(), 0);
0136:                    insertString(pos, "----- Forwarded message -----\n\n");
0137:                    insertString(pos, messageBuffer.getText());
0138:                    insertString(pos,
0139:                            "\n\n----- End of forwarded message -----");
0140:                    unmodified();
0141:                    renumber();
0142:                    formatter.parseBuffer();
0143:                    setLoaded(true);
0144:                } finally {
0145:                    unlockWrite();
0146:                }
0147:            }
0148:
0149:            // Reply.
0150:            public SendMail(MessageBuffer messageBuffer, boolean replyToGroup) {
0151:                super ();
0152:                init();
0153:                mailbox = messageBuffer.getMailbox();
0154:                entryRepliedTo = messageBuffer.getMailboxEntry();
0155:                reply = true;
0156:                MailAddress[] replyTo = entryRepliedTo.getReplyTo();
0157:                MailAddress[] from = entryRepliedTo.getFrom();
0158:                MailAddress[] to = entryRepliedTo.getTo();
0159:                MailAddress[] cc = entryRepliedTo.getCc();
0160:                boolean skipTo = false;
0161:                try {
0162:                    lockWrite();
0163:                } catch (InterruptedException e) {
0164:                    Log.debug(e);
0165:                    return;
0166:                }
0167:                try {
0168:                    appendFrom();
0169:                    // Get senders.
0170:                    List senders = null;
0171:                    if (replyTo != null && replyTo.length > 0) {
0172:                        senders = new ArrayList();
0173:                        for (int i = 0; i < replyTo.length; i++)
0174:                            senders.add(replyTo[i]);
0175:                    } else if (from != null && from.length > 0) {
0176:                        senders = new ArrayList();
0177:                        for (int i = 0; i < from.length; i++)
0178:                            senders.add(from[i]);
0179:                    }
0180:                    if (senders != null) {
0181:                        Debug.assertTrue(senders.size() > 0);
0182:                        // Remove user's address from list of senders.
0183:                        for (int i = senders.size(); i-- > 0;) {
0184:                            MailAddress a = (MailAddress) senders.get(i);
0185:                            if (a.addressMatches(Mail.getUserMailAddress()))
0186:                                senders.remove(i);
0187:                        }
0188:                        if (senders.size() == 0) {
0189:                            // User was the only sender of the original message.
0190:                            // Use "To" addresses instead.
0191:                            for (int i = 0; i < to.length; i++)
0192:                                senders.add(to[i]);
0193:                            // Don't add "To" addresses to group.
0194:                            skipTo = true;
0195:                        }
0196:                        removeDuplicateAddresses(senders);
0197:                        appendAddressHeader("To: ", senders);
0198:                    }
0199:                    // Gather addresses for reply to group.
0200:                    group = new ArrayList();
0201:                    if (!skipTo && to != null) {
0202:                        for (int i = 0; i < to.length; i++) {
0203:                            MailAddress a = to[i];
0204:                            if (!a.addressMatches(Mail.getUserMailAddress()))
0205:                                group.add(a);
0206:                        }
0207:                    }
0208:                    if (cc != null) {
0209:                        for (int i = 0; i < cc.length; i++) {
0210:                            MailAddress a = cc[i];
0211:                            if (!a.addressMatches(Mail.getUserMailAddress()))
0212:                                group.add(a);
0213:                        }
0214:                    }
0215:                    removeDuplicateAddresses(group);
0216:                    if (senders != null) {
0217:                        // Make sure we don't duplicate entries in the "To:" header.
0218:                        for (int i = senders.size(); i-- > 0;) {
0219:                            MailAddress toAddress = (MailAddress) senders
0220:                                    .get(i);
0221:                            for (int j = group.size(); j-- > 0;) {
0222:                                MailAddress a = (MailAddress) group.get(j);
0223:                                if (a.equals(toAddress)) {
0224:                                    // It's a duplicate. Remove it from the group.
0225:                                    group.remove(j);
0226:                                    break;
0227:                                }
0228:                            }
0229:                        }
0230:                    }
0231:                    // Add group to recipients if applicable.
0232:                    if (replyToGroup && group.size() > 0)
0233:                        appendAddressHeader("Cc: ", group);
0234:                    String subject = entryRepliedTo.getSubject();
0235:                    if (!subject.toLowerCase().startsWith("re:"))
0236:                        subject = "Re: ".concat(subject);
0237:                    appendLine("Subject: ".concat(subject));
0238:                    appendLine("In-Reply-To: " + entryRepliedTo.getMessageId());
0239:                    appendReferences();
0240:                    appendDefaultHeaders();
0241:                    appendLine(HEADER_SEPARATOR);
0242:                    String attribution = getAttribution(messageBuffer);
0243:                    if (attribution != null)
0244:                        appendLine(attribution);
0245:                    String s = messageBuffer
0246:                            .quoteBody(getIntegerProperty(Property.WRAP_COL));
0247:                    if (s != null)
0248:                        append(s);
0249:                    appendLine("");
0250:                    appendSignature();
0251:                    unmodified();
0252:                    renumber();
0253:                    formatter.parseBuffer();
0254:                    setLoaded(true);
0255:                } finally {
0256:                    unlockWrite();
0257:                }
0258:            }
0259:
0260:            private void init() {
0261:                if (preferences == null)
0262:                    preferences = Editor.preferences();
0263:                initializeUndo();
0264:                type = TYPE_NORMAL;
0265:                title = DEFAULT_TITLE;
0266:                if (getFile() == null) {
0267:                    final File dir = Directories.getDraftsFolder();
0268:                    if (!dir.isDirectory())
0269:                        dir.mkdirs();
0270:                    if (dir.isDirectory()) {
0271:                        setFile(Utilities.getTempFile(dir));
0272:                    } else {
0273:                        // Use temp directory as fallback. (Shouldn't happen.)
0274:                        setFile(Utilities.getTempFile());
0275:                    }
0276:                }
0277:                autosaveEnabled = true;
0278:                mode = SendMailMode.getMode();
0279:                formatter = mode.getFormatter(this );
0280:                if (!getFile().isFile())
0281:                    lineSeparator = "\n";
0282:                setInitialized(true);
0283:            }
0284:
0285:            public int load() {
0286:                super .load();
0287:                title = getSubject();
0288:                if (title == null || title.length() == 0)
0289:                    title = DEFAULT_TITLE;
0290:                return LOAD_COMPLETED;
0291:            }
0292:
0293:            public boolean save() {
0294:                boolean result = super .save();
0295:                for (BufferIterator it = new BufferIterator(); it.hasNext();) {
0296:                    Buffer buf = it.nextBuffer();
0297:                    if (buf instanceof  Drafts) {
0298:                        Drafts drafts = (Drafts) buf;
0299:                        drafts.reload();
0300:                        break;
0301:                    }
0302:                }
0303:                return result;
0304:            }
0305:
0306:            public boolean hasBeenSent() {
0307:                return hasBeenSent;
0308:            }
0309:
0310:            private static void removeDuplicateAddresses(List list) {
0311:                // Remove duplicate entries from list.
0312:                for (int i = list.size(); i-- > 0;) {
0313:                    MailAddress ma = (MailAddress) list.get(i);
0314:                    String addr = ma.getAddress();
0315:                    for (int j = i - 1; j >= 0; j--) {
0316:                        MailAddress ma2 = (MailAddress) list.get(j);
0317:                        if (ma.equals(ma2)) {
0318:                            list.remove(i);
0319:                            break;
0320:                        }
0321:                        // Not strictly equal. Check for same address.
0322:                        String addr2 = ma2.getAddress();
0323:                        if (addr.equals(addr2)) {
0324:                            list.remove(i);
0325:                            // We've removed ma from the list.
0326:                            // Don't lose any extra information it may have.
0327:                            if (ma2.getPersonal() == null
0328:                                    || ma2.getPersonal().length() == 0) {
0329:                                if (ma.getPersonal() != null
0330:                                        && ma.getPersonal().length() > 0)
0331:                                    list.set(j, ma);
0332:                            }
0333:                        }
0334:                    }
0335:                }
0336:            }
0337:
0338:            private void appendAddressHeader(String prefix, List list) {
0339:                if (list == null)
0340:                    return;
0341:                if (list.size() == 0)
0342:                    return;
0343:                append(MailUtilities.constructAddressHeader(prefix, list));
0344:            }
0345:
0346:            private void appendFrom() {
0347:                if (!preferences.getBooleanProperty(Property.CONFIRM_SEND)) {
0348:                    MailAddress ma = Mail.getUserMailAddress();
0349:                    if (ma != null)
0350:                        appendLine("From: ".concat(ma.toString()));
0351:                }
0352:            }
0353:
0354:            private void replaceFrom(String from) {
0355:                final Editor editor = Editor.currentEditor();
0356:                final Position savedDot = editor.getDotCopy();
0357:                try {
0358:                    lockWrite();
0359:                } catch (InterruptedException e) {
0360:                    Log.error(e);
0361:                    return;
0362:                }
0363:                try {
0364:                    CompoundEdit compoundEdit = editor.beginCompoundEdit();
0365:                    // Remove existing "From:" header(s).
0366:                    removeHeaders(editor, "from:");
0367:                    // Move dot to beginning of buffer.
0368:                    editor.addUndo(SimpleEdit.MOVE);
0369:                    editor.getDot().moveTo(getFirstLine(), 0);
0370:                    // Insert new "From:" header.
0371:                    editor.addUndo(SimpleEdit.INSERT_STRING);
0372:                    insertString(editor.getDot(), "From: ".concat(from).concat(
0373:                            "\n"));
0374:                    // Restore dot to saved position if possible.
0375:                    Line dotLine = savedDot.getLine();
0376:                    if (contains(dotLine)) {
0377:                        int dotOffset = savedDot.getOffset();
0378:                        if (dotOffset > dotLine.length())
0379:                            dotOffset = dotLine.length();
0380:                        editor.addUndo(SimpleEdit.MOVE);
0381:                        editor.getDot().moveTo(dotLine, dotOffset);
0382:                    }
0383:                    editor.addUndo(SimpleEdit.MOVE);
0384:                    editor.moveCaretToDotCol();
0385:                    editor.endCompoundEdit(compoundEdit);
0386:                    getFormatter().parseBuffer();
0387:                } finally {
0388:                    unlockWrite();
0389:                }
0390:                repaint();
0391:            }
0392:
0393:            private void replaceBcc(List bccList) {
0394:                final Editor editor = Editor.currentEditor();
0395:                final Position savedDot = editor.getDotCopy();
0396:                try {
0397:                    lockWrite();
0398:                } catch (InterruptedException e) {
0399:                    Log.error(e);
0400:                    return;
0401:                }
0402:                try {
0403:                    CompoundEdit compoundEdit = editor.beginCompoundEdit();
0404:                    // Remove existing "Bcc:" header(s).
0405:                    removeHeaders(editor, "bcc:");
0406:                    // Move dot to end of header area and insert new "Bcc:" header.
0407:                    for (Line line = getFirstLine(); line != null; line = line
0408:                            .next()) {
0409:                        if (line.getText().equals(HEADER_SEPARATOR)) {
0410:                            editor.addUndo(SimpleEdit.MOVE);
0411:                            editor.getDot().moveTo(line, 0);
0412:                            editor.addUndo(SimpleEdit.INSERT_STRING);
0413:                            insertString(editor.getDot(), MailUtilities
0414:                                    .constructAddressHeader("Bcc: ", bccList)
0415:                                    .concat("\n"));
0416:                            break;
0417:                        }
0418:                    }
0419:                    // Restore dot to saved position.
0420:                    Line dotLine = savedDot.getLine();
0421:                    if (contains(dotLine)) {
0422:                        int dotOffset = savedDot.getOffset();
0423:                        if (dotOffset > dotLine.length())
0424:                            dotOffset = dotLine.length();
0425:                        editor.addUndo(SimpleEdit.MOVE);
0426:                        editor.getDot().moveTo(dotLine, dotOffset);
0427:                    }
0428:                    editor.addUndo(SimpleEdit.MOVE);
0429:                    editor.moveCaretToDotCol();
0430:                    editor.endCompoundEdit(compoundEdit);
0431:                    getFormatter().parseBuffer();
0432:                } finally {
0433:                    unlockWrite();
0434:                }
0435:                repaint();
0436:            }
0437:
0438:            private void appendReferences() {
0439:                if (entryRepliedTo != null) {
0440:                    final String prefix = "References: ";
0441:                    FastStringBuffer sb = new FastStringBuffer(prefix);
0442:                    int length = prefix.length();
0443:                    String[] oldReferences = entryRepliedTo.getReferences();
0444:                    final String[] references;
0445:                    if (oldReferences != null) {
0446:                        references = new String[oldReferences.length + 1];
0447:                        System.arraycopy(oldReferences, 0, references, 0,
0448:                                oldReferences.length);
0449:                    } else
0450:                        references = new String[1];
0451:                    references[references.length - 1] = entryRepliedTo
0452:                            .getMessageId();
0453:                    for (int i = 0; i < references.length; i++) {
0454:                        String s = references[i];
0455:                        if (i > 0 && length + s.length() > 990) {
0456:                            // Won't fit on current line.
0457:                            sb.append(lineSeparator);
0458:                            final String indent = "        ";
0459:                            sb.append(indent); // Continuation.
0460:                            sb.append(s);
0461:                            length = indent.length() + s.length();
0462:                        } else {
0463:                            if (i > 0) {
0464:                                sb.append(" ");
0465:                                length++;
0466:                            }
0467:                            sb.append(s);
0468:                            length += s.length();
0469:                        }
0470:                    }
0471:                    append(sb.toString());
0472:                }
0473:            }
0474:
0475:            private void appendDefaultHeaders() {
0476:                String bcc = preferences.getStringProperty("bcc");
0477:                if (bcc != null)
0478:                    appendLine("Bcc: ".concat(bcc));
0479:            }
0480:
0481:            private void appendSignature() {
0482:                File file = null;
0483:                String fileName = preferences
0484:                        .getStringProperty(Property.SIGNATURE);
0485:                if (fileName != null)
0486:                    file = File.getInstance(fileName);
0487:                else if (Platform.isPlatformUnix())
0488:                    file = File.getInstance(Directories.getUserHomeDirectory(),
0489:                            ".signature");
0490:                if (file == null || !file.isFile())
0491:                    return;
0492:                FastStringBuffer sb = new FastStringBuffer();
0493:                try {
0494:                    BufferedReader reader = new BufferedReader(
0495:                            new InputStreamReader(file.getInputStream()));
0496:                    while (true) {
0497:                        String s = reader.readLine();
0498:                        if (s == null)
0499:                            break;
0500:                        if (sb.length() > 0)
0501:                            sb.append('\n');
0502:                        sb.append(s);
0503:                    }
0504:                    reader.close();
0505:                } catch (IOException e) {
0506:                    Log.error(e);
0507:                }
0508:                if (sb.length() > 0)
0509:                    append(sb.toString());
0510:            }
0511:
0512:            public static final String getHeaderSeparator() {
0513:                return HEADER_SEPARATOR;
0514:            }
0515:
0516:            public void modified() {
0517:                super .modified();
0518:                setTitle();
0519:            }
0520:
0521:            private void setTitle() {
0522:                String s = getSubject();
0523:                if (s == null || s.length() == 0)
0524:                    s = DEFAULT_TITLE;
0525:                if (title == null || !title.equals(s)) {
0526:                    title = s;
0527:                    Sidebar
0528:                            .setUpdateFlagInAllFrames(SIDEBAR_BUFFER_LIST_CHANGED);
0529:                }
0530:            }
0531:
0532:            public void attachFile() {
0533:                Editor editor = Editor.currentEditor();
0534:                File file = OpenFileDialog.getLocalFile(editor, "Attach File");
0535:                if (file != null && file.isFile()) {
0536:                    for (Line line = getFirstLine(); line != null; line = line
0537:                            .next()) {
0538:                        if (line.getText().equals(HEADER_SEPARATOR)) {
0539:                            Position pos = new Position(line, 0);
0540:                            insertString(pos, "Attachment: "
0541:                                    + file.canonicalPath() + "\n");
0542:                            break;
0543:                        }
0544:                    }
0545:                }
0546:            }
0547:
0548:            public void send() {
0549:                if (!checkHeader())
0550:                    return;
0551:                checkRecipients();
0552:                checkEmpty();
0553:                if (preferences.getBooleanProperty(Property.CONFIRM_SEND)) {
0554:                    if (!confirmSend())
0555:                        return;
0556:                }
0557:                Runnable sendRunnable = new Runnable() {
0558:                    public void run() {
0559:                        boolean succeeded = false;
0560:                        if (smtp != null)
0561:                            session = SmtpSession.getSession(smtp);
0562:                        else
0563:                            session = SmtpSession.getDefaultSession();
0564:                        if (session != null) {
0565:                            File messageFile = Utilities.getTempFile();
0566:                            try {
0567:                                OutputStreamWriter writer = new OutputStreamWriter(
0568:                                        messageFile.getOutputStream());
0569:                                writeMessageText(writer);
0570:                                writer.flush();
0571:                                writer.close();
0572:                                succeeded = session.sendMessage(SendMail.this ,
0573:                                        messageFile);
0574:                                if (succeeded)
0575:                                    writeFcc(messageFile);
0576:                                messageFile.delete();
0577:                            } catch (IOException e) {
0578:                                Log.error(e);
0579:                            }
0580:                        }
0581:                        hasBeenSent = succeeded;
0582:                        SwingUtilities
0583:                                .invokeLater(succeeded ? succeededRunnable
0584:                                        : errorRunnable);
0585:                    }
0586:                };
0587:                setBusy(true);
0588:                new Thread(sendRunnable).start();
0589:            }
0590:
0591:            private boolean confirmSend() {
0592:                final Editor editor = Editor.currentEditor();
0593:                ConfirmSendDialog d = new ConfirmSendDialog(editor, this );
0594:                editor.centerDialog(d);
0595:                d.show();
0596:                if (d.cancelled())
0597:                    return false;
0598:                String from = d.getFrom();
0599:                if (from != null)
0600:                    replaceFrom(from);
0601:                if (d.bccAddSender() || d.bccAddOther()) {
0602:                    List bccList = new ArrayList();
0603:                    MailAddress[] bcc = MailAddress.parseAddresses(getBcc());
0604:                    if (bcc != null) {
0605:                        for (int i = 0; i < bcc.length; i++)
0606:                            bccList.add(bcc[i]);
0607:                    }
0608:                    if (d.bccAddSender() && from != null)
0609:                        bccList.add(MailAddress.parseAddress(from));
0610:                    if (d.bccAddOther()) {
0611:                        String bccOther = d.getBccOther();
0612:                        if (bccOther != null && bccOther.length() > 0)
0613:                            bccList.add(MailAddress.parseAddress(bccOther));
0614:                    }
0615:                    if (bccList.size() > 0) {
0616:                        removeDuplicateAddresses(bccList);
0617:                        replaceBcc(bccList);
0618:                    }
0619:                }
0620:                smtp = d.getSmtp();
0621:                return true;
0622:            }
0623:
0624:            private boolean checkHeader() {
0625:                for (Line line = getFirstLine(); line != null; line = line
0626:                        .next()) {
0627:                    if (line.getText().equals(HEADER_SEPARATOR))
0628:                        return true;
0629:                }
0630:                MessageDialog.showMessageDialog(Editor.currentEditor(),
0631:                        "Message separator line is missing", "Error");
0632:                return false;
0633:                // BUG!! Should confirm here that we have a valid "From" address!
0634:            }
0635:
0636:            // Make sure all continued address header lines end with commas.
0637:            private void checkRecipients() {
0638:                for (Line line = getFirstLine(); line != null; line = line
0639:                        .next()) {
0640:                    String text = line.getText();
0641:                    if (text.equals(HEADER_SEPARATOR))
0642:                        return;
0643:                    String lower = text.toLowerCase();
0644:                    if (lower.startsWith("to:") || lower.startsWith("cc:")
0645:                            || lower.startsWith("bcc:")) {
0646:                        Line continuation = line.next();
0647:                        while (continuation != null
0648:                                && continuation.length() > 0) {
0649:                            char c = continuation.charAt(0);
0650:                            if (c == ' ' || c == '\t') {
0651:                                // It's really a continuation line. Make sure the
0652:                                // preceding line ends with a comma.
0653:                                String s = trimTrailing(line.getText());
0654:                                int length = s.length();
0655:                                if (length > 0 && s.charAt(length - 1) != ',')
0656:                                    line.setText(s.concat(","));
0657:                                line = continuation;
0658:                                continuation = continuation.next();
0659:                            } else
0660:                                break;
0661:                        }
0662:                    }
0663:                }
0664:            }
0665:
0666:            // Trims trailing whitespace.
0667:            private static String trimTrailing(String s) {
0668:                int length = s.length();
0669:                if (length == 0
0670:                        || !Character.isWhitespace(s.charAt(length - 1)))
0671:                    return s;
0672:                do {
0673:                    --length;
0674:                } while (length > 0
0675:                        && Character.isWhitespace(s.charAt(length - 1)));
0676:                return s.substring(0, length);
0677:            }
0678:
0679:            private void checkEmpty() {
0680:                String eom = getStringProperty(Property.EOM);
0681:                if (eom == null || eom.length() == 0)
0682:                    return;
0683:                Line subjectLine = null;
0684:                Line line;
0685:                for (line = getFirstLine(); line != null; line = line.next()) {
0686:                    String text = line.getText();
0687:                    if (text.toLowerCase().startsWith("subject:"))
0688:                        subjectLine = line;
0689:                    else if (text.toLowerCase().startsWith("attachment:"))
0690:                        return; // Not empty.
0691:                    else if (text.equals(HEADER_SEPARATOR))
0692:                        break;
0693:                }
0694:                if (subjectLine == null)
0695:                    return;
0696:                if (line != null) {
0697:                    line = line.next();
0698:                    // Now we're on the first line of the message body.
0699:                    while (line != null) {
0700:                        if (!line.isBlank())
0701:                            return; // Not empty.
0702:                        line = line.next();
0703:                    }
0704:                }
0705:                // Empty.
0706:                String text = subjectLine.getText();
0707:                if (!text.endsWith(eom))
0708:                    subjectLine.setText(text + eom);
0709:            }
0710:
0711:            private Runnable succeededRunnable = new Runnable() {
0712:                public void run() {
0713:                    unmodified();
0714:                    if (reply && mailbox != null && entryRepliedTo != null)
0715:                        mailbox.setAnsweredFlag(entryRepliedTo);
0716:                    File file = getFile();
0717:                    if (file.isFile()) {
0718:                        Log.debug("deleting draft " + file);
0719:                        file.delete();
0720:                        for (BufferIterator it = new BufferIterator(); it
0721:                                .hasNext();) {
0722:                            Buffer buf = it.nextBuffer();
0723:                            if (buf instanceof  Drafts) {
0724:                                Drafts drafts = (Drafts) buf;
0725:                                drafts.reload();
0726:                                break;
0727:                            }
0728:                        }
0729:                    }
0730:                    setBusy(false);
0731:                    kill();
0732:                    EditorIterator iter = new EditorIterator();
0733:                    while (iter.hasNext())
0734:                        iter.nextEditor().updateDisplay();
0735:                }
0736:            };
0737:
0738:            private Runnable errorRunnable = new Runnable() {
0739:                public void run() {
0740:                    setBusy(false);
0741:                    final Editor editor = Editor.currentEditor();
0742:                    editor.updateDisplay();
0743:                    MessageDialog.showMessageDialog(editor,
0744:                            session != null ? session.getErrorText()
0745:                                    : "Unable to send message", "Send Mail");
0746:                }
0747:            };
0748:
0749:            private void writeMessageText(Writer writer) {
0750:                final String separator = "\n";
0751:                try {
0752:                    writer.write("Date: " + RFC822Date.getDateTimeString()
0753:                            + separator);
0754:                    if (getFrom() == null)
0755:                        writer.write("From: " + getDefaultFromAddress()
0756:                                + separator);
0757:                    Line line;
0758:                    // Headers.
0759:                    boolean inBcc = false;
0760:                    List attachments = null;
0761:                    for (line = getFirstLine(); line != null; line = line
0762:                            .next()) {
0763:                        String text = line.getText();
0764:                        if (text.length() == 0) {
0765:                            // Found empty line before reaching end of headers.
0766:                            // Discard it.
0767:                            continue;
0768:                        }
0769:                        if (text.equals(HEADER_SEPARATOR)) {
0770:                            // Reached end of headers.
0771:                            writer.write("Message-ID: "
0772:                                    + Mail.generateMessageId() + separator);
0773:                            writer.write("User-Agent: "
0774:                                    + Version.getLongVersionString()
0775:                                    + separator);
0776:                            attachments = parseAttachments();
0777:                            if (attachments != null)
0778:                                writer.write(generateMimeHeaders(separator));
0779:                            // Skip header separator line.
0780:                            line = line.next();
0781:                            break;
0782:                        }
0783:                        if (inBcc) {
0784:                            char c = text.charAt(0);
0785:                            if (c == ' ' || c == '\t') {
0786:                                // It's a continuation line. Skip it.
0787:                                continue;
0788:                            } else {
0789:                                // Start of next header.
0790:                                inBcc = false;
0791:                            }
0792:                        }
0793:                        if (text.toLowerCase().startsWith("bcc:")) {
0794:                            inBcc = true;
0795:                            continue;
0796:                        }
0797:                        if (text.toLowerCase().startsWith("attachment:"))
0798:                            continue;
0799:                        writer.write(line.getText());
0800:                        writer.write(separator);
0801:                    }
0802:                    final Line startOfBody = line;
0803:                    // Scan body of message.
0804:                    boolean qp = false;
0805:                    for (line = startOfBody; line != null; line = line.next()) {
0806:                        if (requiresEncoding(line)) {
0807:                            qp = true;
0808:                            break;
0809:                        }
0810:                    }
0811:                    String transferEncoding = qp ? "quoted-printable" : "7bit";
0812:                    String characterEncoding = getStringProperty(Property.DEFAULT_ENCODING);
0813:                    if (attachments != null) {
0814:                        // Append extra separator at end of headers.
0815:                        writer.write(separator);
0816:                        writer
0817:                                .write("This is a multi-part message in MIME format.");
0818:                        writer.write(separator);
0819:                        writer.write("--");
0820:                        writer.write(getBoundary());
0821:                        writer.write(separator);
0822:                        writer.write("Content-Type: text/plain");
0823:                        if (qp) {
0824:                            writer.write("; charset=");
0825:                            writer.write(getCharSetName(characterEncoding));
0826:                        }
0827:                        writer.write(separator);
0828:                        writer.write("Content-Transfer-Encoding: ");
0829:                        writer.write(transferEncoding);
0830:                        writer.write(separator);
0831:                        writer.write(separator);
0832:                    } else {
0833:                        // No attachments.
0834:                        if (qp) {
0835:                            writer.write("Content-Type: text/plain");
0836:                            if (qp) {
0837:                                writer.write("; charset=");
0838:                                writer.write(getCharSetName(characterEncoding));
0839:                            }
0840:                            writer.write(separator);
0841:                            writer.write("Content-Transfer-Encoding: ");
0842:                            writer.write(transferEncoding);
0843:                            writer.write(separator);
0844:                        }
0845:                        // Append extra separator at end of headers.
0846:                        writer.write(separator);
0847:                    }
0848:                    // Body.
0849:                    for (line = startOfBody; line != null; line = line.next()) {
0850:                        String s = line.getText();
0851:                        if (qp) {
0852:                            writer.write(QuotedPrintableEncoder.encode(s,
0853:                                    characterEncoding, separator));
0854:                        } else {
0855:                            // Dot stuffing.
0856:                            if (s.length() > 0 && s.charAt(0) == '.')
0857:                                writer.write('.');
0858:                            writer.write(s);
0859:                        }
0860:                        writer.write(separator);
0861:                    }
0862:                    // Attachments.
0863:                    if (attachments != null) {
0864:                        for (int i = 0; i < attachments.size(); i++) {
0865:                            String fullPath = (String) attachments.get(i);
0866:                            File file = File.getInstance(fullPath);
0867:                            String contentType = getContentTypeForFile(file);
0868:                            Log.debug("contentType = " + contentType);
0869:                            writer.write("--");
0870:                            writer.write(getBoundary());
0871:                            writer.write(separator);
0872:                            writer.write("Content-Type: ");
0873:                            writer.write(contentType);
0874:                            writer.write(separator);
0875:                            writer.write("Content-Transfer-Encoding: base64");
0876:                            writer.write(separator);
0877:                            writer
0878:                                    .write("Content-Disposition: attachment; filename=\"");
0879:                            writer.write(file.getName());
0880:                            writer.write('"');
0881:                            writer.write(separator);
0882:                            writer.write(separator);
0883:                            writeEncodedFile(file, writer, separator);
0884:                            writer.write(separator);
0885:                        }
0886:                        writer.write("--");
0887:                        writer.write(getBoundary());
0888:                        writer.write("--");
0889:                        writer.write(separator);
0890:                    }
0891:                } catch (IOException e) {
0892:                    Log.error(e);
0893:                }
0894:            }
0895:
0896:            private void writeEncodedFile(File file, Writer writer,
0897:                    String separator) {
0898:                if (file == null || !file.isFile() || !file.canRead())
0899:                    return;
0900:                try {
0901:                    FileInputStream inputStream = file.getInputStream();
0902:                    Base64Encoder encoder = new Base64Encoder(inputStream);
0903:                    String s;
0904:                    while ((s = encoder.encodeLine()) != null) {
0905:                        writer.write(s);
0906:                        writer.write(separator);
0907:                    }
0908:                    writer.flush();
0909:                    inputStream.close();
0910:                } catch (IOException e) {
0911:                    Log.error(e);
0912:                }
0913:            }
0914:
0915:            public String getFrom() {
0916:                return getHeaderValue("from");
0917:            }
0918:
0919:            public String getFromAddress() {
0920:                String from = getFrom();
0921:                if (from != null)
0922:                    return getAddress(from);
0923:                // No "From:" header.
0924:                return Mail.getUserMailAddress().getAddress();
0925:            }
0926:
0927:            private final String getDefaultFromAddress() {
0928:                return Mail.getUserMailAddress().toString();
0929:            }
0930:
0931:            // Given "Piso Mojado <piso@armedbear.yi.org>", returns
0932:            // "piso@armedbear.yi.org".
0933:            public static String getAddress(String s) {
0934:                if (s == null)
0935:                    return null;
0936:                int index = s.indexOf('@');
0937:                if (index < 0)
0938:                    return null;
0939:                int begin = 0;
0940:                int end = s.length();
0941:                for (int i = index; i-- > 0;) {
0942:                    char c = s.charAt(i);
0943:                    if (c == ',' || c == '"' || c == '<'
0944:                            || Character.isWhitespace(c)) {
0945:                        begin = i + 1;
0946:                        break;
0947:                    }
0948:                }
0949:                for (int i = index + 1; i < end; i++) {
0950:                    char c = s.charAt(i);
0951:                    if (c == ',' || c == '"' || c == '>'
0952:                            || Character.isWhitespace(c)) {
0953:                        end = i;
0954:                        break;
0955:                    }
0956:                }
0957:                return s.substring(begin, end);
0958:            }
0959:
0960:            public String getTo() {
0961:                Log.debug("getTo to = |" + getHeaderValue("to") + "|");
0962:                return getHeaderValue("to");
0963:            }
0964:
0965:            public String getCc() {
0966:                Log.debug("getCc cc = |" + getHeaderValue("cc") + "|");
0967:                return getHeaderValue("cc");
0968:            }
0969:
0970:            public String getBcc() {
0971:                Log.debug("getBcc bcc = |" + getHeaderValue("bcc") + "|");
0972:                return getHeaderValue("bcc");
0973:            }
0974:
0975:            public void ccGroup() {
0976:                if (group == null)
0977:                    return;
0978:                // Entries from the original group will come first in the new list.
0979:                List newList = new ArrayList(group);
0980:                // Add the entries from the existing "Cc:" header (if any) back in.
0981:                MailAddress[] cc = MailAddress.parseAddresses(getCc());
0982:                if (cc != null) {
0983:                    for (int i = 0; i < cc.length; i++) {
0984:                        MailAddress oldAddress = cc[i];
0985:                        // Skip entries that are already in the list.
0986:                        boolean isDuplicate = false;
0987:                        for (int j = newList.size() - 1; j >= 0; j--) {
0988:                            MailAddress a = (MailAddress) newList.get(j);
0989:                            if (oldAddress.equals(a)) {
0990:                                isDuplicate = true;
0991:                                break;
0992:                            }
0993:                        }
0994:                        if (!isDuplicate)
0995:                            newList.add(oldAddress);
0996:                    }
0997:                }
0998:                // Make sure we don't duplicate entries in the "To:" header.
0999:                MailAddress[] to = MailAddress.parseAddresses(getTo());
1000:                if (to != null) {
1001:                    for (int i = to.length - 1; i >= 0; i--) {
1002:                        MailAddress toAddress = to[i];
1003:                        for (int j = newList.size() - 1; j >= 0; j--) {
1004:                            MailAddress a = (MailAddress) newList.get(j);
1005:                            if (a.equals(toAddress)) {
1006:                                // It's a duplicate. Remove it from the new list.
1007:                                Log.debug("removing "
1008:                                        + (MailAddress) newList.get(j));
1009:                                newList.remove(j);
1010:                                break;
1011:                            }
1012:                        }
1013:                    }
1014:                }
1015:                final Editor editor = Editor.currentEditor();
1016:                final Position savedDot = editor.getDotCopy();
1017:                try {
1018:                    lockWrite();
1019:                } catch (InterruptedException e) {
1020:                    Log.error(e);
1021:                    return;
1022:                }
1023:                try {
1024:                    CompoundEdit compoundEdit = editor.beginCompoundEdit();
1025:                    // Remove all existing "Cc:" headers (there can be more than one).
1026:                    removeHeaders(editor, "cc:");
1027:                    // Move dot to line after "To:" header.
1028:                    for (Line line = getFirstLine(); line != null; line = line
1029:                            .next()) {
1030:                        if (line.getText().toLowerCase().startsWith("to:")) {
1031:                            // Found first line of "To:" header.
1032:                            for (Line next = line.next(); next != null; next = next
1033:                                    .next()) {
1034:                                if (next.length() == 0 || next.charAt(0) == ' '
1035:                                        || next.charAt(0) == '\t') {
1036:                                    // Continuation line.
1037:                                    continue;
1038:                                } else {
1039:                                    // Found next header. Put dot here.
1040:                                    editor.addUndo(SimpleEdit.MOVE);
1041:                                    editor.getDot().moveTo(next, 0);
1042:                                    break;
1043:                                }
1044:                            }
1045:                            break;
1046:                        }
1047:                    }
1048:                    // Insert new "Cc:" header.
1049:                    editor.addUndo(SimpleEdit.INSERT_STRING);
1050:                    FastStringBuffer sb = new FastStringBuffer();
1051:                    sb.append(MailUtilities.constructAddressHeader("Cc: ",
1052:                            newList));
1053:                    sb.append(lineSeparator);
1054:                    insertString(editor.getDot(), sb.toString());
1055:                    // Restore dot to saved position if possible.
1056:                    Line dotLine = savedDot.getLine();
1057:                    if (contains(dotLine)) {
1058:                        int dotOffset = savedDot.getOffset();
1059:                        if (dotOffset > dotLine.length())
1060:                            dotOffset = dotLine.length();
1061:                        editor.addUndo(SimpleEdit.MOVE);
1062:                        editor.getDot().moveTo(dotLine, dotOffset);
1063:                    }
1064:                    editor.addUndo(SimpleEdit.MOVE);
1065:                    editor.moveCaretToDotCol();
1066:                    editor.endCompoundEdit(compoundEdit);
1067:                    getFormatter().parseBuffer();
1068:                } finally {
1069:                    unlockWrite();
1070:                }
1071:                repaint();
1072:            }
1073:
1074:            // Remove all header lines for hdr (e.g "from:", "cc:", "bcc:"). We assume
1075:            // the buffer is write-locked and beginCompoundEdit has been called. The
1076:            // current editor gets passed in to manage undo.
1077:            private void removeHeaders(Editor editor, String hdr) {
1078:                // Make sure hdr is all lower case and ends with a colon.
1079:                hdr = hdr.toLowerCase();
1080:                if (!hdr.endsWith(":"))
1081:                    hdr = hdr.concat(":");
1082:                while (true) {
1083:                    // Find appropriate line in message headers.
1084:                    Line beginLine = null;
1085:                    // Always start at top of buffer.
1086:                    for (Line line = getFirstLine(); line != null; line = line
1087:                            .next()) {
1088:                        String text = line.getText();
1089:                        if (text.equals(HEADER_SEPARATOR))
1090:                            return;
1091:                        if (text.toLowerCase().startsWith(hdr)) {
1092:                            beginLine = line;
1093:                            break;
1094:                        }
1095:                    }
1096:                    // Not found.
1097:                    if (beginLine == null)
1098:                        return;
1099:                    // We want to delete the region up to the start of the next header
1100:                    // line.
1101:                    Line endLine = null;
1102:                    for (Line line = beginLine.next(); line != null; line = line
1103:                            .next()) {
1104:                        String text = line.getText();
1105:                        if (text.length() == 0)
1106:                            continue;
1107:                        if (text.equals(HEADER_SEPARATOR)) {
1108:                            endLine = line;
1109:                            break;
1110:                        }
1111:                        char c = line.getText().charAt(0);
1112:                        if (c != ' ' && c != '\t') {
1113:                            endLine = line;
1114:                            break;
1115:                        }
1116:                    }
1117:                    // endLine should never be null here, since at worst we should
1118:                    // always hit the header separator line. But the user might have
1119:                    // deleted the header separator...
1120:                    if (endLine == null)
1121:                        return;
1122:                    // Delete the region from beginLine to endLine.
1123:                    Region r = new Region(this , new Position(beginLine, 0),
1124:                            new Position(endLine, 0));
1125:                    editor.addUndo(SimpleEdit.MOVE);
1126:                    editor.getDot().moveTo(r.getBegin());
1127:                    editor.addUndoDeleteRegion(r);
1128:                    r.delete();
1129:                }
1130:            }
1131:
1132:            public List getAddressees() {
1133:                ArrayList list = new ArrayList();
1134:                appendAddressesFromString(list, getTo());
1135:                appendAddressesFromString(list, getCc());
1136:                appendAddressesFromString(list, getBcc());
1137:                for (int i = 0; i < list.size(); i++)
1138:                    Log.debug("|" + (String) list.get(i) + "|");
1139:                return list;
1140:            }
1141:
1142:            private static void appendAddressesFromString(List list, String s) {
1143:                if (s == null)
1144:                    return;
1145:                s = s.trim();
1146:                int length = s.length();
1147:                if (length == 0)
1148:                    return;
1149:                FastStringBuffer sb = new FastStringBuffer(64);
1150:                boolean inQuote = false;
1151:                for (int i = 0; i < length; i++) {
1152:                    char c = s.charAt(i);
1153:                    switch (c) {
1154:                    case '"':
1155:                        inQuote = !inQuote;
1156:                        sb.append(c);
1157:                        break;
1158:                    case ',':
1159:                        if (inQuote) {
1160:                            // A comma inside a quoted string is just an ordinary
1161:                            // character.
1162:                            sb.append(c);
1163:                        } else {
1164:                            // Otherwise a comma marks the end of the address.
1165:                            String address = sb.toString().trim();
1166:                            if (address.length() > 0)
1167:                                list.add(address);
1168:                            sb.setLength(0);
1169:                        }
1170:                        break;
1171:                    default:
1172:                        sb.append(c);
1173:                        break;
1174:                    }
1175:                }
1176:                if (sb.length() > 0) {
1177:                    String address = sb.toString().trim();
1178:                    if (address.length() > 0)
1179:                        list.add(address);
1180:                }
1181:            }
1182:
1183:            public String getSubject() {
1184:                return getHeaderValue("subject");
1185:            }
1186:
1187:            // Combines multiple occurrences of "To:", "Cc:", "Bcc:".
1188:            private String getHeaderValue(String headerName) {
1189:                boolean combine = false;
1190:                String key = headerName.toLowerCase() + ':';
1191:                if (key.equals("to:") || key.equals("cc:")
1192:                        || key.equals("bcc:"))
1193:                    combine = true;
1194:                FastStringBuffer sb = null;
1195:                for (Line line = getFirstLine(); line != null; line = line
1196:                        .next()) {
1197:                    String text = line.getText();
1198:                    if (text.equals(HEADER_SEPARATOR))
1199:                        break;
1200:                    if (text.toLowerCase().startsWith(key)) {
1201:                        if (sb == null) {
1202:                            sb = new FastStringBuffer();
1203:                        } else {
1204:                            // Make sure there's a proper separator when we're
1205:                            // combining address headers.
1206:                            sb.append(", ");
1207:                        }
1208:                        sb.append(text.substring(key.length()).trim());
1209:                        Line continuation = line.next();
1210:                        while (continuation != null
1211:                                && continuation.length() > 0) {
1212:                            char c = continuation.charAt(0);
1213:                            if (c == ' ' || c == '\t') {
1214:                                // This is in fact a continuation line.
1215:                                sb.append(continuation.getText());
1216:                                line = continuation;
1217:                                continuation = continuation.next();
1218:                                continue;
1219:                            } else
1220:                                break;
1221:                        }
1222:                        if (!combine)
1223:                            break;
1224:                    }
1225:                }
1226:                return sb != null ? sb.toString() : null;
1227:            }
1228:
1229:            public Position getInitialDotPos() {
1230:                if (reply) {
1231:                    for (Line line = getFirstLine(); line != null; line = line
1232:                            .next()) {
1233:                        if (line.getText().equals(HEADER_SEPARATOR)) {
1234:                            line = line.next();
1235:                            if (line != null)
1236:                                return new Position(line, 0);
1237:                        }
1238:                    }
1239:                } else {
1240:                    for (Line line = getFirstLine(); line != null; line = line
1241:                            .next()) {
1242:                        if (line.getText().startsWith("To: "))
1243:                            return new Position(line, line.length());
1244:                    }
1245:                }
1246:                // Under normal circumstances we shouldn't get here, but anything can
1247:                // happen with a postponed message...
1248:                return new Position(getFirstLine(), 0);
1249:            }
1250:
1251:            private List parseAttachments() {
1252:                ArrayList attachments = null;
1253:                for (Line line = getFirstLine(); line != null; line = line
1254:                        .next()) {
1255:                    if (line.getText().equals(HEADER_SEPARATOR))
1256:                        break;
1257:                    if (line.getText().toLowerCase().startsWith("attachment:")) {
1258:                        String filename = line.getText().substring(11).trim();
1259:                        if (filename.length() > 0) {
1260:                            if (attachments == null)
1261:                                attachments = new ArrayList();
1262:                            attachments.add(filename);
1263:                        }
1264:                    }
1265:                }
1266:                return attachments;
1267:            }
1268:
1269:            private String generateMimeHeaders(String separator) {
1270:                FastStringBuffer sb = new FastStringBuffer();
1271:                sb.append("MIME-Version: 1.0");
1272:                sb.append(separator);
1273:                sb.append("Content-Type: multipart/mixed; boundary=\"");
1274:                sb.append(getBoundary());
1275:                sb.append('"');
1276:                sb.append(separator);
1277:                return sb.toString();
1278:            }
1279:
1280:            private String getBoundary() {
1281:                if (boundary == null) {
1282:                    FastStringBuffer sb = new FastStringBuffer(16);
1283:                    Random random = new Random();
1284:                    char[] chars = getBoundaryChars();
1285:                    for (int i = 0; i < 16; i++) {
1286:                        int index = random.nextInt(chars.length);
1287:                        sb.append(chars[index]);
1288:                    }
1289:                    boundary = sb.toString();
1290:                }
1291:                return boundary;
1292:            }
1293:
1294:            private char[] getBoundaryChars() {
1295:                return Base64Encoder.getBase64Chars();
1296:            }
1297:
1298:            private String getContentTypeForFile(File file) {
1299:                boolean isBinary = false;
1300:                try {
1301:                    BufferedInputStream inputStream = new BufferedInputStream(
1302:                            file.getInputStream());
1303:                    int c;
1304:                    while ((c = inputStream.read()) >= 0) {
1305:                        if (c >= ' ' && c < 127)
1306:                            continue;
1307:                        if (c == '\r')
1308:                            continue;
1309:                        if (c == '\n')
1310:                            continue;
1311:                        if (c == '\t')
1312:                            continue;
1313:                        if (c == '\f')
1314:                            continue;
1315:                        // If none of the above, it's not text.
1316:                        isBinary = true;
1317:                        break;
1318:                    }
1319:                    inputStream.close();
1320:                } catch (IOException e) {
1321:                    Log.error(e);
1322:                    isBinary = true;
1323:                }
1324:                String extension = Utilities.getExtension(file);
1325:                if (extension != null)
1326:                    extension = extension.toLowerCase();
1327:                if (isBinary) {
1328:                    if (extension != null) {
1329:                        // Check for known image types.
1330:                        extension = extension.toLowerCase();
1331:                        if (extension.equals(".jpeg")
1332:                                || extension.equals(".jpg"))
1333:                            return "image/jpeg";
1334:                        if (extension.equals(".gif"))
1335:                            return "image/gif";
1336:                        if (extension.equals(".png"))
1337:                            return "image/png";
1338:                    }
1339:                    // No extension or not a known type.
1340:                    return "application/octet-stream";
1341:                } else {
1342:                    if (extension != null) {
1343:                        if (extension.equals(".html")
1344:                                || extension.equals(".htm"))
1345:                            return "text/html";
1346:                        if (extension.equals(".xml"))
1347:                            return "text/xml";
1348:                    }
1349:                    // No extension or not a known type.
1350:                    return "text/plain";
1351:                }
1352:            }
1353:
1354:            public File getCurrentDirectory() {
1355:                return Directories.getUserHomeDirectory();
1356:            }
1357:
1358:            public File getCompletionDirectory() {
1359:                return Directories.getUserHomeDirectory();
1360:            }
1361:
1362:            // For the buffer list.
1363:            public Icon getIcon() {
1364:                if (isModified())
1365:                    return Utilities.getIconFromFile("compose_modified.png");
1366:                return Utilities.getIconFromFile("compose.png");
1367:            }
1368:
1369:            public String getFileNameForDisplay() {
1370:                return "";
1371:            }
1372:
1373:            private static boolean requiresEncoding(Line line) {
1374:                final String text = line.getText();
1375:                if (text.length() > 990)
1376:                    return true;
1377:                if (text.length() == 0)
1378:                    return false;
1379:                for (int i = text.length() - 1; i >= 0; i--) {
1380:                    char c = text.charAt(i);
1381:                    if (c < ' ' && c != '\t')
1382:                        return true;
1383:                    if (c >= 127)
1384:                        return true;
1385:                }
1386:                if (text.startsWith("From "))
1387:                    return true;
1388:                if (text.charAt(0) == '.')
1389:                    return true;
1390:                return false;
1391:            }
1392:
1393:            private static final String getCharSetName(String characterEncoding) {
1394:                if (characterEncoding.equals("ASCII"))
1395:                    return "us-ascii";
1396:                if (characterEncoding.startsWith("ISO8859_"))
1397:                    return "iso-8859-" + characterEncoding.substring(8);
1398:                // BUG! There are more cases!
1399:                return characterEncoding;
1400:            }
1401:
1402:            public boolean isHeaderLine(Line maybe) {
1403:                for (Line line = getFirstLine(); line != null; line = line
1404:                        .next()) {
1405:                    if (line == maybe)
1406:                        return true;
1407:                    if (line.getText().equals(HEADER_SEPARATOR))
1408:                        return false;
1409:                }
1410:                return false;
1411:            }
1412:
1413:            public void tab(Editor editor) {
1414:                Line dotLine = editor.getDotLine();
1415:                if (dotLine.getText().equals(HEADER_SEPARATOR)) {
1416:                    Line line = dotLine.next();
1417:                    if (line != null)
1418:                        editor.moveDotTo(line, 0);
1419:                    return;
1420:                }
1421:                for (Line line = getFirstLine(); line != null; line = line
1422:                        .next()) {
1423:                    if (line == dotLine) {
1424:                        break;
1425:                    } else if (line.getText().equals(HEADER_SEPARATOR)) {
1426:                        // We're in the body of the message. Just do the normal thing.
1427:                        editor.insertTab();
1428:                        return;
1429:                    }
1430:                }
1431:                // Reaching here, dot is in the header area. Advance to the end of the
1432:                // next header.
1433:                Line line = null;
1434:                for (line = dotLine.next(); line != null; line = line.next()) {
1435:                    if (!isContinuationLine(line))
1436:                        break;
1437:                }
1438:                if (line == null)
1439:                    return;
1440:                // Have we reached the header separator line?
1441:                if (line.getText().equals(HEADER_SEPARATOR)) {
1442:                    line = line.next();
1443:                    if (line != null)
1444:                        editor.moveDotTo(line, 0);
1445:                    return;
1446:                }
1447:                // We're at start of next header. Put dot at end of it.
1448:                while (true) {
1449:                    Line next = line.next();
1450:                    if (next == null)
1451:                        return;
1452:                    if (!isContinuationLine(next)) {
1453:                        // Next line is not a continuation line of current header.
1454:                        // Move dot to end of current line.
1455:                        editor.moveDotTo(line, line.length());
1456:                        return;
1457:                    }
1458:                    line = next;
1459:                }
1460:            }
1461:
1462:            public void backTab(Editor editor) {
1463:                Line dotLine = editor.getDotLine();
1464:                // Check to see whether dot is in the header area or in the body of
1465:                // the message.
1466:                for (Line line = getFirstLine(); line != null; line = line
1467:                        .next()) {
1468:                    if (line == dotLine) {
1469:                        break;
1470:                    } else if (line.getText().equals(HEADER_SEPARATOR)) {
1471:                        // Dot is in the body of the message. Go back to the end of
1472:                        // the last header line.
1473:                        line = line.previous();
1474:                        if (line != null)
1475:                            editor.moveDotTo(line, line.length());
1476:                        return;
1477:                    }
1478:                }
1479:                // Reaching here, dot is in the header area. Find the first line of
1480:                // the header dot is in.
1481:                Line line = dotLine;
1482:                while (isContinuationLine(line)) {
1483:                    line = line.previous();
1484:                    if (line == null)
1485:                        return; // Shouldn't happen.
1486:                }
1487:                // Now we're on the first line of the header dot was in. Put dot at
1488:                // the end of the previous line.
1489:                line = line.previous();
1490:                if (line != null)
1491:                    editor.moveDotTo(line, line.length());
1492:            }
1493:
1494:            private static final boolean isContinuationLine(Line line) {
1495:                if (line.length() == 0)
1496:                    return false;
1497:                char c = line.charAt(0);
1498:                return c == ' ' || c == '\t';
1499:            }
1500:
1501:            // Append message to sent messages file (if so configured).
1502:            private void writeFcc(File messageFile) {
1503:                final File sentMessagesFile = Mail.getSentMessagesFile();
1504:                if (sentMessagesFile == null)
1505:                    return;
1506:                try {
1507:                    BufferedReader reader = new BufferedReader(
1508:                            new InputStreamReader(messageFile.getInputStream()));
1509:                    BufferedWriter writer = new BufferedWriter(new FileWriter(
1510:                            sentMessagesFile.canonicalPath(), true));
1511:                    writer.write("From - ");
1512:                    SimpleDateFormat dateFormatter = new SimpleDateFormat(
1513:                            "EEE MMM d HH:mm:ss yyyy");
1514:                    Calendar cal = Calendar.getInstance();
1515:                    String dateString = dateFormatter.format(cal.getTime());
1516:                    writer.write(dateString);
1517:                    writer.write('\n');
1518:                    String s;
1519:                    while ((s = reader.readLine()) != null) {
1520:                        writer.write(s);
1521:                        writer.write('\n');
1522:                    }
1523:                    writer.write('\n');
1524:                    writer.flush();
1525:                    writer.close();
1526:                    reader.close();
1527:                } catch (IOException e) {
1528:                    Log.error(e);
1529:                }
1530:            }
1531:
1532:            public Expansion getExpansion(Position dot) {
1533:                int endOfHeaders = -1;
1534:                for (Line line = getFirstLine(); line != null; line = line
1535:                        .next()) {
1536:                    if (line.getText().equals(HEADER_SEPARATOR)) {
1537:                        endOfHeaders = line.lineNumber();
1538:                        break;
1539:                    }
1540:                }
1541:                if (dot.lineNumber() < endOfHeaders)
1542:                    return new MailAddressExpansion(dot);
1543:                else
1544:                    return super .getExpansion(dot);
1545:            }
1546:
1547:            private static final RE dateRE = new UncheckedRE(
1548:                    "[A-Za-z]+, [0-9][0-9]? [A-Za-z]+ [0-9][0-9][0-9][0-9]");
1549:            private static final RE timeRE = new UncheckedRE(
1550:                    "[0-9:]+ [+-][0-9][0-9][0-9][0-9]");
1551:
1552:            private static String getAttribution(MessageBuffer messageBuffer) {
1553:                if (messageBuffer == null)
1554:                    return null;
1555:                Mailbox mailbox = messageBuffer.getMailbox();
1556:                if (mailbox == null)
1557:                    return null;
1558:                MailboxEntry entry = messageBuffer.getMailboxEntry();
1559:                if (entry == null)
1560:                    return null;
1561:                String template = preferences
1562:                        .getStringProperty(Property.ATTRIBUTION);
1563:                if (template == null || template.length() == 0)
1564:                    return null;
1565:                FastStringBuffer sb = new FastStringBuffer();
1566:                final int limit = template.length();
1567:                for (int i = 0; i < limit; i++) {
1568:                    char c = template.charAt(i);
1569:                    if (c == '%' && ++i < limit) {
1570:                        c = template.charAt(i);
1571:                        switch (c) {
1572:                        case 'd': {
1573:                            // Date/time in sender's time zone.
1574:                            Message message = messageBuffer.getMessage();
1575:                            if (message == null)
1576:                                return null;
1577:                            String dateTime = message
1578:                                    .getHeaderValue(Headers.DATE);
1579:                            REMatch m1 = dateRE.getMatch(dateTime);
1580:                            if (m1 != null) {
1581:                                REMatch m2 = timeRE.getMatch(dateTime
1582:                                        .substring(m1.getEndIndex()));
1583:                                if (m2 != null) {
1584:                                    sb.append(m1.toString());
1585:                                    sb.append(" at ");
1586:                                    sb.append(m2.toString());
1587:                                }
1588:                            }
1589:                            break;
1590:                        }
1591:                        case 'n': {
1592:                            // Author's real name (or address if missing).
1593:                            MailAddress[] from = entry.getFrom();
1594:                            if (from == null || from.length == 0)
1595:                                return null;
1596:                            String personal = from[0].getPersonal();
1597:                            if (personal != null && personal.length() > 0)
1598:                                sb.append(personal);
1599:                            else {
1600:                                String addr = from[0].getAddress();
1601:                                if (addr != null && addr.length() > 0)
1602:                                    sb.append(addr);
1603:                                else
1604:                                    return null;
1605:                            }
1606:                            break;
1607:                        }
1608:                        default:
1609:                            Log.error("invalid format sequence \"%" + c + '"'
1610:                                    + " in attribution");
1611:                            return null;
1612:                        }
1613:                    } else
1614:                        sb.append(c);
1615:                }
1616:                return sb.toString();
1617:            }
1618:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.