Source Code Cross Referenced for IMAPServer.java in  » Mail-Clients » columba-1.4 » org » columba » mail » imap » 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 » Mail Clients » columba 1.4 » org.columba.mail.imap 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        // The contents of this file are subject to the Mozilla Public License Version
0002:        // 1.1
0003:        //(the "License"); you may not use this file except in compliance with the
0004:        //License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
0005:        //
0006:        //Software distributed under the License is distributed on an "AS IS" basis,
0007:        //WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0008:        //for the specific language governing rights and
0009:        //limitations under the License.
0010:        //
0011:        //The Original Code is "The Columba Project"
0012:        //
0013:        //The Initial Developers of the Original Code are Frederik Dietz and Timo
0014:        // Stich.
0015:        //Portions created by Frederik Dietz and Timo Stich are Copyright (C) 2003.
0016:        //
0017:        //All Rights Reserved.
0018:        package org.columba.mail.imap;
0019:
0020:        import java.io.IOException;
0021:        import java.io.InputStream;
0022:        import java.nio.charset.Charset;
0023:        import java.text.DateFormat;
0024:        import java.text.MessageFormat;
0025:        import java.util.ArrayList;
0026:        import java.util.Arrays;
0027:        import java.util.Collections;
0028:        import java.util.Iterator;
0029:        import java.util.LinkedList;
0030:        import java.util.List;
0031:        import java.util.Observable;
0032:        import java.util.Observer;
0033:        import java.util.logging.Logger;
0034:
0035:        import javax.net.ssl.SSLException;
0036:        import javax.swing.JOptionPane;
0037:
0038:        import org.columba.api.command.IStatusObservable;
0039:        import org.columba.core.base.Blowfish;
0040:        import org.columba.core.base.ListTools;
0041:        import org.columba.core.command.CommandCancelledException;
0042:        import org.columba.core.filter.FilterCriteria;
0043:        import org.columba.core.filter.FilterRule;
0044:        import org.columba.core.filter.IFilterCriteria;
0045:        import org.columba.core.filter.IFilterRule;
0046:        import org.columba.core.gui.base.MultiLineLabel;
0047:        import org.columba.core.gui.frame.FrameManager;
0048:        import org.columba.mail.config.AccountItem;
0049:        import org.columba.mail.config.ImapItem;
0050:        import org.columba.mail.config.IncomingItem;
0051:        import org.columba.mail.filter.MailFilterCriteria;
0052:        import org.columba.mail.folder.IMailbox;
0053:        import org.columba.mail.folder.command.MarkMessageCommand;
0054:        import org.columba.mail.folder.headercache.CachedHeaderfields;
0055:        import org.columba.mail.folder.imap.IMAPFolder;
0056:        import org.columba.mail.folder.imap.IMAPRootFolder;
0057:        import org.columba.mail.gui.util.PasswordDialog;
0058:        import org.columba.mail.message.ColumbaHeader;
0059:        import org.columba.mail.message.IHeaderList;
0060:        import org.columba.mail.util.AuthenticationManager;
0061:        import org.columba.mail.util.AuthenticationSecurityComparator;
0062:        import org.columba.mail.util.MailResourceLoader;
0063:        import org.columba.ristretto.auth.AuthenticationException;
0064:        import org.columba.ristretto.auth.AuthenticationFactory;
0065:        import org.columba.ristretto.imap.IMAPDate;
0066:        import org.columba.ristretto.imap.IMAPDisconnectedException;
0067:        import org.columba.ristretto.imap.IMAPException;
0068:        import org.columba.ristretto.imap.IMAPFlags;
0069:        import org.columba.ristretto.imap.IMAPHeader;
0070:        import org.columba.ristretto.imap.IMAPListener;
0071:        import org.columba.ristretto.imap.IMAPProtocol;
0072:        import org.columba.ristretto.imap.IMAPResponse;
0073:        import org.columba.ristretto.imap.ListInfo;
0074:        import org.columba.ristretto.imap.MailboxStatus;
0075:        import org.columba.ristretto.imap.NamespaceCollection;
0076:        import org.columba.ristretto.imap.SearchKey;
0077:        import org.columba.ristretto.imap.SequenceSet;
0078:        import org.columba.ristretto.io.SequenceInputStream;
0079:        import org.columba.ristretto.message.Header;
0080:        import org.columba.ristretto.message.MailboxInfo;
0081:        import org.columba.ristretto.message.MimeTree;
0082:
0083:        /**
0084:         * IMAPStore encapsulates IMAPProtocol and the parsers for IMAPFolder.
0085:         * <p>
0086:         * This way {@link IMAPFolder}doesn't need to do any parsing work, etc.
0087:         * <p>
0088:         * Every {@link IMAPFolder}of a single account has also an
0089:         * {@link IMAPRootFolder}, which keeps a reference to {@link IMAPServer}.
0090:         * Which itself uses {@link IMAPProtocol}.
0091:         * <p>
0092:         * IMAPStore handles the current state of connection:
0093:         * <ul>
0094:         * <li>STATE_NONAUTHENTICATE - not authenticated</li>
0095:         * <li>STATE_AUTHENTICATE - authenticated</li>
0096:         * <li>STATE_SELECTED - mailbox is selected</li>
0097:         * </ul>
0098:         * <p>
0099:         * It keeps a reference to the currently selected mailbox.
0100:         * <p>
0101:         * IMAPFolder shouldn't use IMAPProtocol directly, instead it should use
0102:         * IMAPStore.
0103:         *
0104:         * @author fdietz
0105:         */
0106:        public class IMAPServer implements  IMAPListener, Observer, IImapServer {
0107:
0108:            private static final int STEP_SIZE = 50;
0109:
0110:            private static final int UID_FETCH_STEPS = 500;
0111:
0112:            private static final Logger LOG = Logger
0113:                    .getLogger("org.columba.mail.imap");
0114:
0115:            private static final Charset UTF8 = Charset.forName("UTF-8");
0116:
0117:            private static final Charset DEFAULT = Charset.forName(System
0118:                    .getProperty("file.encoding"));
0119:
0120:            /**
0121:             * currently selected mailbox
0122:             */
0123:            private IMailbox selectedFolder;
0124:
0125:            /**
0126:             * Holds the actual MailboxStatus. Updated by the IMAPListener.
0127:             */
0128:            private MailboxStatus selectedStatus;
0129:
0130:            /**
0131:             * mailbox name delimiter
0132:             * <p>
0133:             * example: "/" (uw-imap), or "." (cyrus)
0134:             */
0135:            private String delimiter;
0136:
0137:            /**
0138:             * reference to IMAP protocol
0139:             */
0140:            private IMAPProtocol protocol;
0141:
0142:            /**
0143:             * configuration options of this IMAP account
0144:             */
0145:            private ImapItem item;
0146:
0147:            private MimeTree aktMimeTree;
0148:
0149:            private Object aktMessageUid;
0150:
0151:            private MailboxInfo messageFolderInfo;
0152:
0153:            private boolean firstLogin;
0154:
0155:            boolean usingSSL;
0156:
0157:            String[] capabilities;
0158:
0159:            private long lastCommunication;
0160:
0161:            private IStatusObservable observable;
0162:
0163:            // minimal unchecked time is 30 Seconds
0164:            private int MIN_IDLE = 30 * 1000; // in ms
0165:
0166:            // Used to control the state in which
0167:            // the automatic updated mechanism is
0168:            private boolean updatesEnabled = true;
0169:
0170:            private IFirstLoginAction firstLoginAction;
0171:
0172:            private IUpdateFlagAction updateFlagAction;
0173:
0174:            private IExistsChangedAction existsChangedAction;
0175:
0176:            private boolean statusDirty;
0177:
0178:            public IMAPServer(ImapItem item) {
0179:                this .item = item;
0180:
0181:                item.getRoot().addObserver(this );
0182:
0183:                // create IMAP protocol
0184:                protocol = new IMAPProtocol(item.get("host"), item
0185:                        .getInteger("port"));
0186:                // register interest on status updates
0187:                protocol.addIMAPListener(this );
0188:
0189:                firstLogin = true;
0190:                usingSSL = false;
0191:
0192:                lastCommunication = System.currentTimeMillis();
0193:            }
0194:
0195:            /**
0196:             * @return
0197:             */
0198:            protected IStatusObservable getObservable() {
0199:                return observable;
0200:            }
0201:
0202:            /**
0203:             * @param message
0204:             */
0205:            protected void printStatusMessage(String message) {
0206:                if (getObservable() != null) {
0207:                    getObservable().setMessage(
0208:                            item.get("host") + ": " + message);
0209:                }
0210:            }
0211:
0212:            /**
0213:             * Returns mailbox name delimiter
0214:             * <p/>
0215:             * example: "/" (uw-imap), or "." (cyrus)
0216:             *
0217:             * @return mailbox name delimiter
0218:             */
0219:            /* (non-Javadoc)
0220:             * @see org.columba.mail.imap.IImapServer#getDelimiter()
0221:             */
0222:            public String getDelimiter() throws IOException, IMAPException,
0223:                    CommandCancelledException {
0224:                if (delimiter == null) {
0225:                    // try to determine delimiter
0226:                    delimiter = fetchDelimiter();
0227:                }
0228:
0229:                return delimiter;
0230:            }
0231:
0232:            /* (non-Javadoc)
0233:             * @see org.columba.mail.imap.IImapServer#logout()
0234:             */
0235:            public void logout() throws Exception {
0236:                if (protocol.getState() != IMAPProtocol.NOT_CONNECTED) {
0237:                    try {
0238:                        protocol.logout();
0239:                    } catch (Exception e) {
0240:                        // don't care
0241:                    }
0242:                }
0243:            }
0244:
0245:            private void openConnection() throws IOException, IMAPException,
0246:                    CommandCancelledException {
0247:                printStatusMessage(MailResourceLoader.getString("statusbar",
0248:                        "message", "connecting"));
0249:
0250:                int sslType = item.getIntegerWithDefault("ssl_type",
0251:                        IncomingItem.TLS);
0252:                boolean sslEnabled = item.getBoolean("enable_ssl");
0253:
0254:                // open a port to the server
0255:                if (sslEnabled && sslType == IncomingItem.IMAPS_POP3S) {
0256:                    try {
0257:                        protocol.openSSLPort();
0258:                        usingSSL = true;
0259:                    } catch (SSLException e) {
0260:                        int result = showErrorDialog(MailResourceLoader
0261:                                .getString("dialog", "error",
0262:                                        "ssl_handshake_error")
0263:                                + ": "
0264:                                + e.getLocalizedMessage()
0265:                                + "\n"
0266:                                + MailResourceLoader.getString("dialog",
0267:                                        "error", "ssl_turn_off"));
0268:
0269:                        if (result == 1) {
0270:                            throw new CommandCancelledException();
0271:                        }
0272:
0273:                        // turn off SSL for the future
0274:                        item.setBoolean("enable_ssl", false);
0275:                        item.setInteger("port", IMAPProtocol.DEFAULT_PORT);
0276:
0277:                        // reopen the port
0278:                        protocol.openPort();
0279:                    }
0280:                } else {
0281:                    protocol.openPort();
0282:                }
0283:
0284:                // shall we switch to SSL?
0285:                if (!usingSSL && sslEnabled && sslType == IncomingItem.TLS) {
0286:                    // if CAPA was not support just give it a try...
0287:                    if (isSupported("STLS") || isSupported("STARTTLS")
0288:                            || (capabilities.length == 0)) {
0289:                        try {
0290:                            protocol.startTLS();
0291:
0292:                            usingSSL = true;
0293:                            LOG.info("Switched to SSL");
0294:                        } catch (IOException e) {
0295:                            int result = showErrorDialog(MailResourceLoader
0296:                                    .getString("dialog", "error",
0297:                                            "ssl_handshake_error")
0298:                                    + ": "
0299:                                    + e.getLocalizedMessage()
0300:                                    + "\n"
0301:                                    + MailResourceLoader.getString("dialog",
0302:                                            "error", "ssl_turn_off"));
0303:
0304:                            if (result == 1) {
0305:                                throw new CommandCancelledException();
0306:                            }
0307:
0308:                            // turn off SSL for the future
0309:                            item.setBoolean("enable_ssl", false);
0310:
0311:                            // reopen the port
0312:                            protocol.openPort();
0313:                        } catch (IMAPException e) {
0314:                            int result = showErrorDialog(MailResourceLoader
0315:                                    .getString("dialog", "error",
0316:                                            "ssl_not_supported")
0317:                                    + "\n"
0318:                                    + MailResourceLoader.getString("dialog",
0319:                                            "error", "ssl_turn_off"));
0320:
0321:                            if (result == 1) {
0322:                                throw new CommandCancelledException();
0323:                            }
0324:
0325:                            // turn off SSL for the future
0326:                            item.setBoolean("enable_ssl", false);
0327:                        }
0328:                    } else {
0329:                        // CAPAs say that SSL is not supported
0330:                        int result = showErrorDialog(MailResourceLoader
0331:                                .getString("dialog", "error",
0332:                                        "ssl_not_supported")
0333:                                + "\n"
0334:                                + MailResourceLoader.getString("dialog",
0335:                                        "error", "ssl_turn_off"));
0336:
0337:                        if (result == 1) {
0338:                            throw new CommandCancelledException();
0339:                        }
0340:
0341:                        // turn off SSL for the future
0342:                        item.setBoolean("enable_ssl", false);
0343:                    }
0344:                }
0345:
0346:            }
0347:
0348:            /* (non-Javadoc)
0349:             * @see org.columba.mail.imap.IImapServer#checkSupportedAuthenticationMethods()
0350:             */
0351:            public List checkSupportedAuthenticationMethods()
0352:                    throws IOException {
0353:
0354:                ArrayList supportedMechanisms = new ArrayList();
0355:                // LOGIN is always supported
0356:                supportedMechanisms
0357:                        .add(new Integer(AuthenticationManager.LOGIN));
0358:
0359:                try {
0360:                    String serverSaslMechansims[] = getCapas("AUTH");
0361:                    // combine them to one string
0362:                    StringBuffer oneLine = new StringBuffer("AUTH");
0363:                    for (int i = 0; i < serverSaslMechansims.length; i++) {
0364:                        oneLine.append(' ');
0365:                        oneLine.append(serverSaslMechansims[i].substring(5)); // remove
0366:                        // the
0367:                        // 'AUTH='
0368:                    }
0369:
0370:                    // AUTH?
0371:                    if (serverSaslMechansims != null) {
0372:                        List authMechanisms = AuthenticationFactory
0373:                                .getInstance().getSupportedMechanisms(
0374:                                        oneLine.toString());
0375:                        Iterator it = authMechanisms.iterator();
0376:                        while (it.hasNext()) {
0377:                            supportedMechanisms.add(new Integer(
0378:                                    AuthenticationManager
0379:                                            .getSaslCode((String) it.next())));
0380:                        }
0381:                    }
0382:                } catch (IOException e) {
0383:                }
0384:
0385:                return supportedMechanisms;
0386:            }
0387:
0388:            /**
0389:             * @param command
0390:             * @return
0391:             */
0392:            private String[] getCapas(String command) throws IOException {
0393:                fetchCapas();
0394:                ArrayList list = new ArrayList();
0395:
0396:                for (int i = 0; i < capabilities.length; i++) {
0397:                    if (capabilities[i].startsWith(command)) {
0398:                        list.add(capabilities[i]);
0399:                    }
0400:                }
0401:
0402:                return (String[]) list.toArray(new String[0]);
0403:            }
0404:
0405:            /* (non-Javadoc)
0406:             * @see org.columba.mail.imap.IImapServer#isSupported(java.lang.String)
0407:             */
0408:            public boolean isSupported(String command) throws IOException {
0409:                fetchCapas();
0410:
0411:                for (int i = 0; i < capabilities.length; i++) {
0412:                    if (capabilities[i].startsWith(command)) {
0413:                        return true;
0414:                    }
0415:                }
0416:
0417:                return false;
0418:            }
0419:
0420:            /**
0421:             * @throws IOException
0422:             */
0423:            private void fetchCapas() throws IOException {
0424:                if (capabilities == null) {
0425:                    try {
0426:                        ensureConnectedState();
0427:
0428:                        capabilities = protocol.capability();
0429:                    } catch (IMAPException e) {
0430:                        // CAPA not supported
0431:                        capabilities = new String[0];
0432:                    } catch (CommandCancelledException e) {
0433:
0434:                    }
0435:                }
0436:            }
0437:
0438:            /**
0439:             * Gets the selected Authentication method or else the most secure.
0440:             *
0441:             * @return the authentication method
0442:             */
0443:            private int getLoginMethod() throws CommandCancelledException,
0444:                    IOException {
0445:                String loginMethod = item.get("login_method");
0446:                int result = 0;
0447:
0448:                try {
0449:                    result = Integer.parseInt(loginMethod);
0450:                } catch (NumberFormatException e) {
0451:                    // Just use the default as fallback
0452:                }
0453:
0454:                if (result == 0) {
0455:                    List supported = checkSupportedAuthenticationMethods();
0456:
0457:                    if (usingSSL) {
0458:                        // NOTE if SSL is possible we just need the plain login
0459:                        // since SSL does the encryption for us.
0460:                        result = ((Integer) supported.get(0)).intValue();
0461:                    } else {
0462:                        Collections.sort(supported,
0463:                                new AuthenticationSecurityComparator());
0464:                        result = ((Integer) supported.get(supported.size() - 1))
0465:                                .intValue();
0466:                    }
0467:
0468:                }
0469:
0470:                return result;
0471:            }
0472:
0473:            /**
0474:             * Login to IMAP server.
0475:             * <p>
0476:             * Ask user for password.
0477:             *
0478:             * TODO (@author tstich): cleanup if all these ugly if, else cases
0479:             *
0480:             * @throws Exception
0481:             */
0482:            private void login() throws IOException, IMAPException,
0483:                    CommandCancelledException {
0484:                PasswordDialog dialog = new PasswordDialog();
0485:                ensureConnectedState();
0486:
0487:                boolean authenticated = false;
0488:                boolean first = true;
0489:
0490:                char[] password = new char[0];
0491:
0492:                printStatusMessage(MailResourceLoader.getString("statusbar",
0493:                        "message", "authenticating"));
0494:
0495:                int loginMethod = getLoginMethod();
0496:
0497:                // Try to get Password from Configuration
0498:                if (item.get("password").length() != 0) {
0499:                    password = Blowfish.decrypt(item.get("password"));
0500:                }
0501:                // Login loop until authenticated
0502:                while (!authenticated) {
0503:                    // On the first try check if we need to show the password dialog
0504:                    // -> not necessary when password was stored
0505:                    if (!first || password.length == 0) {
0506:                        // Show the password dialog
0507:                        dialog.showDialog(MessageFormat.format(
0508:                                MailResourceLoader.getString("dialog",
0509:                                        "password", "enter_password"),
0510:                                new Object[] { item.get("user"),
0511:                                        item.get("host") }), new String(
0512:                                password), item.getBoolean("save_password"));
0513:                        if (dialog.success()) {
0514:                            // User pressed OK
0515:                            password = dialog.getPassword();
0516:
0517:                            // Save or Clear the password in the configuration
0518:                            item.setBoolean("save_password", dialog.getSave());
0519:                            if (dialog.getSave()) {
0520:                                item.setString("password", Blowfish
0521:                                        .encrypt(password));
0522:                            } else {
0523:                                item.setString("password", "");
0524:                            }
0525:                        } else {
0526:                            // User cancelled authentication
0527:
0528:                            throw new CommandCancelledException();
0529:                        }
0530:                    }
0531:
0532:                    // From this point we have a username and password
0533:                    // from configuration of from the dialog
0534:
0535:                    try {
0536:                        if (loginMethod == AuthenticationManager.LOGIN) {
0537:                            protocol.login(item.get("user"), password);
0538:
0539:                            // If no exception happened we have successfully logged
0540:                            // in
0541:                            authenticated = true;
0542:                        } else {
0543:                            try {
0544:                                // AUTH
0545:                                protocol.authenticate(AuthenticationManager
0546:                                        .getSaslName(loginMethod), item
0547:                                        .get("user"), password);
0548:
0549:                                // If no exception happened we have successfully logged
0550:                                // in
0551:                                authenticated = true;
0552:                            } catch (AuthenticationException e) {
0553:                                // If the cause is a IMAPExcpetion then only password
0554:                                // wrong
0555:                                // else bogus authentication mechanism
0556:                                if (e.getCause() instanceof  IMAPException)
0557:                                    throw (IMAPException) e.getCause();
0558:
0559:                                // Some error in the client/server communication
0560:                                // --> fall back to default login process
0561:                                int result = JOptionPane
0562:                                        .showConfirmDialog(
0563:                                                FrameManager.getInstance()
0564:                                                        .getActiveFrame(),
0565:                                                new MultiLineLabel(
0566:                                                        e.getMessage()
0567:                                                                + "\n"
0568:                                                                + MailResourceLoader
0569:                                                                        .getString(
0570:                                                                                "dialog",
0571:                                                                                "error",
0572:                                                                                "authentication_fallback_to_default")),
0573:                                                MailResourceLoader
0574:                                                        .getString("dialog",
0575:                                                                "error",
0576:                                                                "authentication_process_error"),
0577:                                                JOptionPane.OK_CANCEL_OPTION);
0578:
0579:                                if (result == JOptionPane.OK_OPTION) {
0580:                                    loginMethod = AuthenticationManager.LOGIN;
0581:                                    item.setString("login_method", Integer
0582:                                            .toString(loginMethod));
0583:                                } else {
0584:                                    throw new CommandCancelledException();
0585:                                }
0586:                            }
0587:                        }
0588:
0589:                    } catch (IMAPException ex) {
0590:                        // login failed?
0591:                        IMAPResponse response = ex.getResponse();
0592:                        if (response == null || !response.isNO()) {
0593:                            // This exception is not because wrong username or
0594:                            // password
0595:                            throw ex;
0596:                        }
0597:                    }
0598:                    first = false;
0599:                }
0600:
0601:                // Sync subscribed folders if this is the first login
0602:                // in this session
0603:                if (firstLogin) {
0604:                    if (firstLoginAction != null) {
0605:                        firstLoginAction.actionPerformed();
0606:                    }
0607:                }
0608:
0609:                firstLogin = false;
0610:            }
0611:
0612:            /* (non-Javadoc)
0613:             * @see org.columba.mail.imap.IImapServer#setFirstLoginAction(org.columba.mail.imap.IFirstLoginAction)
0614:             */
0615:            public void setFirstLoginAction(IFirstLoginAction action) {
0616:                this .firstLoginAction = action;
0617:            }
0618:
0619:            /* (non-Javadoc)
0620:             * @see org.columba.mail.imap.IImapServer#ensureSelectedState(org.columba.mail.folder.imap.IMAPFolder)
0621:             */
0622:            public void ensureSelectedState(IMAPFolder folder)
0623:                    throws IOException, IMAPException,
0624:                    CommandCancelledException {
0625:                // ensure that we are logged in already
0626:                ensureLoginState();
0627:                String path = folder.getImapPath();
0628:
0629:                // if mailbox is not already selected select it
0630:                if (protocol.getState() != IMAPProtocol.SELECTED
0631:                        || !protocol.getSelectedMailbox().equals(path)) {
0632:
0633:                    printStatusMessage(MessageFormat.format(MailResourceLoader
0634:                            .getString("statusbar", "message", "select"),
0635:                            new Object[] { folder.getName() }));
0636:
0637:                    // Here we get the new mailboxinfo for the folder
0638:                    messageFolderInfo = protocol.select(path);
0639:
0640:                    // Set the readOnly flag
0641:                    folder.setReadOnly(!messageFolderInfo.isWriteAccess());
0642:
0643:                    // Convert to a MailboxStatus
0644:                    selectedStatus = new MailboxStatus(messageFolderInfo);
0645:                    statusDirty = false;
0646:
0647:                    selectedFolder = folder;
0648:
0649:                    // delete any cached information
0650:                    aktMimeTree = null;
0651:                    aktMessageUid = null;
0652:                }
0653:            }
0654:
0655:            public int getLargestRemoteUid(IMAPFolder folder)
0656:                    throws IOException, IMAPException,
0657:                    CommandCancelledException {
0658:                MailboxStatus status = getStatus(folder);
0659:                if (status.getUidNext() < 0 && status.getMessages() > 0) {
0660:                    return fetchUid(new SequenceSet(status.getMessages()),
0661:                            folder);
0662:                } else {
0663:                    return (int) (status.getUidNext() - 1);
0664:                }
0665:
0666:            }
0667:
0668:            /* (non-Javadoc)
0669:             * @see org.columba.mail.imap.IImapServer#getStatus(org.columba.mail.folder.imap.IMAPFolder)
0670:             */
0671:            public MailboxStatus getStatus(IMAPFolder folder)
0672:                    throws IOException, IMAPException,
0673:                    CommandCancelledException {
0674:                ensureLoginState();
0675:
0676:                if (selectedFolder != null && selectedFolder.equals(folder)
0677:                        && !statusDirty) {
0678:                    // We don't need to issue a additional NOOP
0679:                    // here since the ensureLogin() call above
0680:                    // ensures also the correct Status in a
0681:                    // MIN_IDLE interval timeframe.
0682:
0683:                    return selectedStatus;
0684:                }
0685:
0686:                if (selectedFolder == null
0687:                        || protocol.getState() < IMAPProtocol.SELECTED) {
0688:                    // if none selected select this folder instead of getting the status
0689:                    ensureSelectedState(folder);
0690:                    return selectedStatus;
0691:                }
0692:
0693:                printStatusMessage(MessageFormat.format(MailResourceLoader
0694:                        .getString("statusbar", "message", "status"),
0695:                        new Object[] { folder.getName() }));
0696:
0697:                MailboxStatus result = protocol.status(folder.getImapPath(),
0698:                        new String[] { "MESSAGES", "UIDNEXT", "RECENT",
0699:                                "UNSEEN", "UIDVALIDITY" });
0700:
0701:                // No response means zero!
0702:                if (result.getUnseen() == -1)
0703:                    result.setUnseen(0);
0704:                if (result.getRecent() == -1)
0705:                    result.setRecent(0);
0706:                statusDirty = false;
0707:
0708:                return result;
0709:            }
0710:
0711:            /**
0712:             * Fetch delimiter.
0713:             *
0714:             */
0715:            protected String fetchDelimiter() throws IOException,
0716:                    IMAPException, CommandCancelledException {
0717:                // make sure we are already logged in
0718:                ensureLoginState();
0719:
0720:                try {
0721:                    ListInfo[] listInfo = protocol.list("", "");
0722:                    return listInfo[0].getDelimiter();
0723:                } catch (IMAPDisconnectedException e1) {
0724:                    ListInfo[] listInfo = protocol.list("", "");
0725:                    return listInfo[0].getDelimiter();
0726:                }
0727:            }
0728:
0729:            /* (non-Javadoc)
0730:             * @see org.columba.mail.imap.IImapServer#list(java.lang.String, java.lang.String)
0731:             */
0732:            public ListInfo[] list(String reference, String pattern)
0733:                    throws Exception {
0734:                ensureLoginState();
0735:
0736:                try {
0737:                    return protocol.list(reference, pattern);
0738:                } catch (IMAPDisconnectedException e) {
0739:                    return protocol.list(reference, pattern);
0740:                }
0741:            }
0742:
0743:            /* (non-Javadoc)
0744:             * @see org.columba.mail.imap.IImapServer#append(java.io.InputStream, org.columba.ristretto.imap.IMAPFlags, org.columba.mail.folder.imap.IMAPFolder)
0745:             */
0746:            public Integer append(InputStream messageSource, IMAPFlags flags,
0747:                    IMAPFolder folder) throws Exception {
0748:                // make sure we are already logged in
0749:                ensureLoginState();
0750:
0751:                // close the mailbox if it is selected
0752:                if (protocol.getState() == IMAPProtocol.SELECTED
0753:                        && protocol.getSelectedMailbox().equals(folder)) {
0754:                    protocol.close();
0755:                }
0756:
0757:                MailboxStatus status = protocol.status(folder.getImapPath(),
0758:                        new String[] { "UIDNEXT" });
0759:
0760:                if (flags != null) {
0761:                    protocol.append(folder.getImapPath(), messageSource,
0762:                            new Object[] { flags });
0763:                } else {
0764:                    protocol.append(folder.getImapPath(), messageSource);
0765:
0766:                }
0767:
0768:                return new Integer((int) status.getUidNext());
0769:            }
0770:
0771:            /* (non-Javadoc)
0772:             * @see org.columba.mail.imap.IImapServer#append(java.io.InputStream, org.columba.mail.folder.imap.IMAPFolder)
0773:             */
0774:            public Integer append(InputStream messageSource, IMAPFolder folder)
0775:                    throws Exception {
0776:                return append(messageSource, null, folder);
0777:            }
0778:
0779:            /* (non-Javadoc)
0780:             * @see org.columba.mail.imap.IImapServer#createMailbox(java.lang.String, org.columba.mail.folder.imap.IMAPFolder)
0781:             */
0782:            public void createMailbox(String mailboxName, IMAPFolder folder)
0783:                    throws IOException, IMAPException,
0784:                    CommandCancelledException {
0785:                // make sure we are logged in
0786:                ensureLoginState();
0787:
0788:                // concate the full name of the new mailbox
0789:                String fullName;
0790:                String path = (folder == null ? "" : folder.getImapPath());
0791:
0792:                if (path.length() > 0)
0793:                    fullName = path + getDelimiter() + mailboxName;
0794:                else
0795:                    fullName = mailboxName;
0796:
0797:                // check if the mailbox already exists -> subscribe only
0798:                if (protocol.list("", fullName).length == 0) {
0799:                    // create the mailbox on the server
0800:                    protocol.create(fullName);
0801:                }
0802:
0803:                // subscribe to the new mailbox
0804:                protocol.subscribe(fullName);
0805:            }
0806:
0807:            /* (non-Javadoc)
0808:             * @see org.columba.mail.imap.IImapServer#deleteFolder(java.lang.String)
0809:             */
0810:            public void deleteFolder(String path) throws Exception {
0811:                // make sure we are already logged in
0812:                ensureLoginState();
0813:
0814:                if (protocol.getState() == IMAPProtocol.SELECTED
0815:                        && protocol.getSelectedMailbox().equals(path)) {
0816:                    protocol.close();
0817:                }
0818:
0819:                protocol.unsubscribe(path);
0820:
0821:                protocol.delete(path);
0822:            }
0823:
0824:            /* (non-Javadoc)
0825:             * @see org.columba.mail.imap.IImapServer#renameFolder(java.lang.String, java.lang.String)
0826:             */
0827:            public void renameFolder(String oldMailboxName,
0828:                    String newMailboxName) throws IOException, IMAPException,
0829:                    CommandCancelledException {
0830:                // make sure we are already logged in
0831:                ensureLoginState();
0832:                protocol.rename(oldMailboxName, newMailboxName);
0833:                protocol.unsubscribe(oldMailboxName);
0834:                protocol.subscribe(newMailboxName);
0835:            }
0836:
0837:            /* (non-Javadoc)
0838:             * @see org.columba.mail.imap.IImapServer#subscribeFolder(java.lang.String)
0839:             */
0840:            public void subscribeFolder(String mailboxName) throws IOException,
0841:                    IMAPException, CommandCancelledException {
0842:                // make sure we are already logged in
0843:                ensureLoginState();
0844:
0845:                protocol.subscribe(mailboxName);
0846:            }
0847:
0848:            /* (non-Javadoc)
0849:             * @see org.columba.mail.imap.IImapServer#unsubscribeFolder(java.lang.String)
0850:             */
0851:            public void unsubscribeFolder(String mailboxName)
0852:                    throws IOException, IMAPException,
0853:                    CommandCancelledException {
0854:                // make sure we are already logged in
0855:                ensureLoginState();
0856:
0857:                protocol.unsubscribe(mailboxName);
0858:            }
0859:
0860:            /* (non-Javadoc)
0861:             * @see org.columba.mail.imap.IImapServer#expunge(org.columba.mail.folder.imap.IMAPFolder)
0862:             */
0863:            public void expunge(IMAPFolder folder) throws IOException,
0864:                    IMAPException, CommandCancelledException {
0865:                ensureSelectedState(folder);
0866:
0867:                updatesEnabled = false;
0868:                protocol.expunge();
0869:                updatesEnabled = true;
0870:                statusDirty = true;
0871:            }
0872:
0873:            /* (non-Javadoc)
0874:             * @see org.columba.mail.imap.IImapServer#copy(org.columba.mail.folder.imap.IMAPFolder, java.lang.Object[], org.columba.mail.folder.imap.IMAPFolder)
0875:             */
0876:            public Integer[] copy(IMAPFolder destFolder, Object[] uids,
0877:                    IMAPFolder folder) throws Exception {
0878:
0879:                ensureSelectedState(folder);
0880:
0881:                // We need to sort the uids in order
0882:                // to have the correct association
0883:                // between the new and old uid
0884:                List sortedUids = Arrays.asList(uids);
0885:                Collections.sort(sortedUids);
0886:
0887:                MailboxStatus statusBefore = protocol.status(destFolder
0888:                        .getImapPath(), new String[] { "UIDNEXT" });
0889:
0890:                protocol.uidCopy(new SequenceSet(Arrays.asList(uids)),
0891:                        destFolder.getImapPath());
0892:
0893:                MailboxStatus statusAfter = protocol.status(destFolder
0894:                        .getImapPath(), new String[] { "UIDNEXT" });
0895:
0896:                // the UIDS start UIDNext till UIDNext + uids.length
0897:                int copied = (int) (statusAfter.getUidNext() - statusBefore
0898:                        .getUidNext());
0899:                Integer[] destUids = new Integer[copied];
0900:                for (int i = 0; i < copied; i++) {
0901:                    destUids[i] = new Integer(
0902:                            (int) (statusBefore.getUidNext() + i));
0903:                }
0904:
0905:                return destUids;
0906:            }
0907:
0908:            /* (non-Javadoc)
0909:             * @see org.columba.mail.imap.IImapServer#fetchUid(org.columba.ristretto.imap.SequenceSet, org.columba.mail.folder.imap.IMAPFolder)
0910:             */
0911:            public int fetchUid(SequenceSet set, IMAPFolder folder)
0912:                    throws IOException, IMAPException,
0913:                    CommandCancelledException {
0914:                ensureSelectedState(folder);
0915:                Integer[] result = protocol.fetchUid(set);
0916:                if (result.length == 1)
0917:                    return result[0].intValue();
0918:                else
0919:                    return -1;
0920:
0921:            }
0922:
0923:            /* (non-Javadoc)
0924:             * @see org.columba.mail.imap.IImapServer#fetchUids(org.columba.ristretto.imap.SequenceSet, org.columba.mail.folder.imap.IMAPFolder)
0925:             */
0926:            public Integer[] fetchUids(SequenceSet set, IMAPFolder folder)
0927:                    throws IOException, IMAPException,
0928:                    CommandCancelledException {
0929:                IStatusObservable observable = getObservable();
0930:                printStatusMessage(MailResourceLoader.getString("statusbar",
0931:                        "message", "fetch_uid_list"));
0932:
0933:                ensureSelectedState(folder);
0934:                if (messageFolderInfo.getExists() > 0) {
0935:                    SequenceSet[] packs = divide(set);
0936:                    Integer[] result = new Integer[set
0937:                            .getLength(messageFolderInfo.getExists())];
0938:
0939:                    // update the progress
0940:                    if (observable != null) {
0941:                        observable.setCurrent(0);
0942:                        observable.setMax(result.length);
0943:                    }
0944:
0945:                    int pos = 0;
0946:
0947:                    for (int i = 0; i < packs.length; i++) {
0948:                        int packLength = packs[i].getLength(messageFolderInfo
0949:                                .getExists());
0950:                        System.arraycopy(protocol.fetchUid(packs[i]), 0,
0951:                                result, pos, packLength);
0952:                        pos += packLength;
0953:
0954:                        // update the progress
0955:                        if (observable != null) {
0956:                            observable.setCurrent(pos);
0957:                        }
0958:                    }
0959:
0960:                    return result;
0961:                } else {
0962:                    return new Integer[0];
0963:                }
0964:            }
0965:
0966:            private SequenceSet[] divide(SequenceSet in) {
0967:                int length = in.getLength(messageFolderInfo.getExists());
0968:
0969:                if (length > UID_FETCH_STEPS) {
0970:                    int[] decomposed = in
0971:                            .toArray(messageFolderInfo.getExists());
0972:
0973:                    List result = new ArrayList();
0974:                    int pos = 0;
0975:                    // divide in packs
0976:                    while (decomposed.length - pos > UID_FETCH_STEPS) {
0977:                        result.add(new SequenceSet(decomposed, pos,
0978:                                UID_FETCH_STEPS));
0979:                        pos += UID_FETCH_STEPS;
0980:                    }
0981:                    // dont forget the rest
0982:                    if (decomposed.length - pos > 0) {
0983:                        result.add(new SequenceSet(decomposed, pos,
0984:                                decomposed.length - pos));
0985:                    }
0986:
0987:                    return (SequenceSet[]) result.toArray(new SequenceSet[0]);
0988:                } else {
0989:                    return new SequenceSet[] { in };
0990:                }
0991:
0992:            }
0993:
0994:            /* (non-Javadoc)
0995:             * @see org.columba.mail.imap.IImapServer#fetchFlagsListStartFrom(int, org.columba.mail.folder.imap.IMAPFolder)
0996:             */
0997:            public IMAPFlags[] fetchFlagsListStartFrom(int startIdx,
0998:                    IMAPFolder folder) throws IOException, IMAPException,
0999:                    CommandCancelledException {
1000:                IStatusObservable observable = getObservable();
1001:
1002:                ensureSelectedState(folder);
1003:                if (selectedStatus.getMessages() - startIdx >= 0) {
1004:                    SequenceSet set = new SequenceSet();
1005:                    set.addOpenRange(startIdx);
1006:
1007:                    SequenceSet[] packs = divide(set);
1008:
1009:                    // update the progress
1010:                    if (observable != null) {
1011:                        observable.setCurrent(0);
1012:                        observable.setMax(set.getLength(selectedStatus
1013:                                .getMessages()));
1014:                    }
1015:
1016:                    List allResults = new ArrayList(packs.length);
1017:
1018:                    int pos = 0;
1019:
1020:                    // store the intermediate results in a list
1021:                    for (int i = 0; i < packs.length; i++) {
1022:                        try {
1023:                            IMAPFlags[] r = protocol.fetchFlags(packs[i]);
1024:                            pos += r.length;
1025:
1026:                            allResults.add(r);
1027:                        } catch (IMAPException e) {
1028:                            // Entry does not exist on server
1029:                            // -> add nothing
1030:                        }
1031:
1032:                        // update the progress
1033:                        if (observable != null) {
1034:                            observable.setCurrent(pos);
1035:                        }
1036:                    }
1037:
1038:                    // Combine the results in one array
1039:                    IMAPFlags[] result = new IMAPFlags[pos];
1040:                    Iterator it = allResults.iterator();
1041:
1042:                    pos = 0;
1043:                    while (it.hasNext()) {
1044:                        IMAPFlags[] r = (IMAPFlags[]) it.next();
1045:                        System.arraycopy(r, 0, result, pos, r.length);
1046:
1047:                        pos += r.length;
1048:                    }
1049:
1050:                    return result;
1051:                } else {
1052:                    return new IMAPFlags[0];
1053:                }
1054:            }
1055:
1056:            /* (non-Javadoc)
1057:             * @see org.columba.mail.imap.IImapServer#fetchFlagsListStartFrom2(int, org.columba.mail.folder.imap.IMAPFolder)
1058:             */
1059:            public IMAPFlags[] fetchFlagsListStartFrom2(int startIdx,
1060:                    IMAPFolder folder) throws IOException, IMAPException,
1061:                    CommandCancelledException {
1062:                ensureSelectedState(folder);
1063:                if (selectedStatus.getMessages() - startIdx >= 0) {
1064:                    SequenceSet set = new SequenceSet();
1065:                    set.add(startIdx, Math.min(startIdx + 9, selectedStatus
1066:                            .getMessages()));
1067:
1068:                    IMAPFlags[] result = protocol.fetchFlags(set);
1069:
1070:                    return result;
1071:                } else {
1072:                    return new IMAPFlags[0];
1073:                }
1074:            }
1075:
1076:            /* (non-Javadoc)
1077:             * @see org.columba.mail.imap.IImapServer#fetchNamespaces()
1078:             */
1079:            public NamespaceCollection fetchNamespaces() throws IOException,
1080:                    IMAPException, CommandCancelledException {
1081:                ensureLoginState();
1082:                return protocol.namespace();
1083:            }
1084:
1085:            /* (non-Javadoc)
1086:             * @see org.columba.mail.imap.IImapServer#fetchHeaderList(org.columba.mail.message.IHeaderList, java.util.List, org.columba.mail.folder.imap.IMAPFolder)
1087:             */
1088:            public void fetchHeaderList(IHeaderList headerList, List list,
1089:                    IMAPFolder folder) throws Exception {
1090:                // make sure this mailbox is selected
1091:                ensureSelectedState(folder);
1092:
1093:                printStatusMessage(MailResourceLoader.getString("statusbar",
1094:                        "message", "fetch_header_list"));
1095:
1096:                int count = list.size() / IMAPServer.STEP_SIZE;
1097:                int rest = list.size() % IMAPServer.STEP_SIZE;
1098:                getObservable().setCurrent(0);
1099:                getObservable().setMax(count + 1);
1100:                for (int i = 0; i < count; i++) {
1101:                    doFetchHeaderList(headerList, list.subList(i
1102:                            * IMAPServer.STEP_SIZE, (i + 1)
1103:                            * IMAPServer.STEP_SIZE));
1104:                    getObservable().setCurrent(i);
1105:                }
1106:
1107:                if (rest > 0) {
1108:                    doFetchHeaderList(headerList, list.subList(count
1109:                            * IMAPServer.STEP_SIZE, count
1110:                            * IMAPServer.STEP_SIZE + rest));
1111:                }
1112:
1113:                getObservable().setCurrent(count + 1);
1114:            }
1115:
1116:            /**
1117:             * @param headerList
1118:             * @param list
1119:             * @throws IOException
1120:             * @throws IMAPException
1121:             */
1122:            private void doFetchHeaderList(IHeaderList headerList, List list)
1123:                    throws IOException, IMAPException {
1124:                // get list of user-defined headerfields
1125:                String[] headerFields = CachedHeaderfields
1126:                        .getDefaultHeaderfields();
1127:
1128:                IMAPHeader[] headers = protocol.uidFetchHeaderFields(
1129:                        new SequenceSet(list), headerFields);
1130:
1131:                for (int i = 0; i < headers.length; i++) {
1132:                    // add it to the headerlist
1133:                    ColumbaHeader header = new ColumbaHeader(headers[i]
1134:                            .getHeader());
1135:                    Object uid = headers[i].getUid();
1136:
1137:                    header.getAttributes().put("columba.uid", uid);
1138:                    header.getAttributes().put("columba.size",
1139:                            headers[i].getSize());
1140:                    header.getAttributes().put("columba.accountuid",
1141:                            getAccountUid());
1142:
1143:                    // set the attachment flag
1144:                    header.getAttributes().put("columba.attachment",
1145:                            header.hasAttachments());
1146:
1147:                    // make sure that we have a Message-ID
1148:                    String messageID = (String) header.get("Message-Id");
1149:                    if (messageID != null)
1150:                        header.set("Message-ID", header.get("Message-Id"));
1151:
1152:                    headerList.add(header, uid);
1153:                }
1154:            }
1155:
1156:            protected Integer getAccountUid() {
1157:                AccountItem accountItem = new AccountItem(item.getRoot()
1158:                        .getParent());
1159:                return new Integer(accountItem.getInteger("uid"));
1160:            }
1161:
1162:            protected synchronized void ensureConnectedState()
1163:                    throws CommandCancelledException, IOException,
1164:                    IMAPException {
1165:                if (Math.abs(System.currentTimeMillis() - lastCommunication) > MIN_IDLE) {
1166:                    try {
1167:                        protocol.noop();
1168:                    } catch (IOException e) {
1169:                        // Now the state of the procotol is more certain correct
1170:                    } catch (IMAPDisconnectedException e) {
1171:
1172:                    }
1173:                }
1174:
1175:                if (protocol.getState() < IMAPProtocol.NON_AUTHENTICATED) {
1176:                    printStatusMessage(MailResourceLoader.getString(
1177:                            "statusbar", "message", "connecting"));
1178:                    openConnection();
1179:                }
1180:
1181:                // update this point of time as last communication
1182:                // since every functio calls this before communicating with
1183:                // the server
1184:                lastCommunication = System.currentTimeMillis();
1185:            }
1186:
1187:            /**
1188:             * Ensure that we are in login state.
1189:             *
1190:             * @throws Exception
1191:             */
1192:            protected void ensureLoginState() throws IOException,
1193:                    IMAPException, CommandCancelledException {
1194:                ensureConnectedState();
1195:
1196:                if (protocol.getState() < IMAPProtocol.AUTHENTICATED) {
1197:                    printStatusMessage(MailResourceLoader.getString(
1198:                            "statusbar", "message", "authenticating"));
1199:                    login();
1200:                }
1201:            }
1202:
1203:            /* (non-Javadoc)
1204:             * @see org.columba.mail.imap.IImapServer#getMimeTree(java.lang.Object, org.columba.mail.folder.imap.IMAPFolder)
1205:             */
1206:            public MimeTree getMimeTree(Object uid, IMAPFolder folder)
1207:                    throws IOException, IMAPException,
1208:                    CommandCancelledException {
1209:                try {
1210:                    ensureSelectedState(folder);
1211:
1212:                    // Use a caching mechanism for this
1213:                    if (aktMimeTree == null || !aktMessageUid.equals(uid)) {
1214:                        aktMimeTree = protocol
1215:                                .uidFetchBodystructure(((Integer) uid)
1216:                                        .intValue());
1217:                        aktMessageUid = uid;
1218:                    }
1219:
1220:                    return aktMimeTree;
1221:                } catch (IMAPDisconnectedException e) {
1222:                    return getMimeTree(uid, folder);
1223:                }
1224:            }
1225:
1226:            /* (non-Javadoc)
1227:             * @see org.columba.mail.imap.IImapServer#getMimePartBodyStream(java.lang.Object, java.lang.Integer[], org.columba.mail.folder.imap.IMAPFolder)
1228:             */
1229:            public InputStream getMimePartBodyStream(Object uid,
1230:                    Integer[] address, IMAPFolder folder) throws IOException,
1231:                    IMAPException, CommandCancelledException {
1232:                try {
1233:                    ensureSelectedState(folder);
1234:
1235:                    return protocol.uidFetchBody(((Integer) uid).intValue(),
1236:                            address);
1237:                } catch (IMAPDisconnectedException e) {
1238:                    return getMimePartBodyStream(uid, address, folder);
1239:                }
1240:            }
1241:
1242:            /* (non-Javadoc)
1243:             * @see org.columba.mail.imap.IImapServer#getHeaders(java.lang.Object, java.lang.String[], org.columba.mail.folder.imap.IMAPFolder)
1244:             */
1245:            public Header getHeaders(Object uid, String[] keys,
1246:                    IMAPFolder folder) throws IOException, IMAPException,
1247:                    CommandCancelledException {
1248:                try {
1249:                    ensureSelectedState(folder);
1250:
1251:                    IMAPHeader[] headers = protocol.uidFetchHeaderFields(
1252:                            new SequenceSet(((Integer) uid).intValue()), keys);
1253:
1254:                    return headers[0].getHeader();
1255:                } catch (IMAPDisconnectedException e) {
1256:                    return getHeaders(uid, keys, folder);
1257:                }
1258:            }
1259:
1260:            /* (non-Javadoc)
1261:             * @see org.columba.mail.imap.IImapServer#getAllHeaders(java.lang.Object, org.columba.mail.folder.imap.IMAPFolder)
1262:             */
1263:            public Header getAllHeaders(Object uid, IMAPFolder folder)
1264:                    throws IOException, IMAPException,
1265:                    CommandCancelledException {
1266:                try {
1267:                    ensureSelectedState(folder);
1268:
1269:                    IMAPHeader[] headers = protocol
1270:                            .uidFetchHeader(new SequenceSet(((Integer) uid)
1271:                                    .intValue()));
1272:
1273:                    return headers[0].getHeader();
1274:                } catch (IMAPDisconnectedException e) {
1275:                    return getAllHeaders(uid, folder);
1276:                }
1277:            }
1278:
1279:            /* (non-Javadoc)
1280:             * @see org.columba.mail.imap.IImapServer#getMimePartSourceStream(java.lang.Object, java.lang.Integer[], org.columba.mail.folder.imap.IMAPFolder)
1281:             */
1282:            public InputStream getMimePartSourceStream(Object uid,
1283:                    Integer[] address, IMAPFolder folder) throws IOException,
1284:                    IMAPException, CommandCancelledException {
1285:                try {
1286:                    ensureSelectedState(folder);
1287:
1288:                    InputStream headerSource = protocol
1289:                            .uidFetchMimeHeaderSource(((Integer) uid)
1290:                                    .intValue(), address);
1291:                    InputStream bodySource = protocol.uidFetchBody(
1292:                            ((Integer) uid).intValue(), address);
1293:
1294:                    return new SequenceInputStream(headerSource, bodySource);
1295:                } catch (IMAPDisconnectedException e) {
1296:                    return getMimePartSourceStream(uid, address, folder);
1297:                }
1298:            }
1299:
1300:            /* (non-Javadoc)
1301:             * @see org.columba.mail.imap.IImapServer#getMessageSourceStream(java.lang.Object, org.columba.mail.folder.imap.IMAPFolder)
1302:             */
1303:            public InputStream getMessageSourceStream(Object uid,
1304:                    IMAPFolder folder) throws IOException, IMAPException,
1305:                    CommandCancelledException {
1306:                try {
1307:                    ensureSelectedState(folder);
1308:
1309:                    return protocol.uidFetchMessage(((Integer) uid).intValue());
1310:                } catch (IMAPDisconnectedException e) {
1311:                    return getMessageSourceStream(uid, folder);
1312:                }
1313:            }
1314:
1315:            /* (non-Javadoc)
1316:             * @see org.columba.mail.imap.IImapServer#markMessage(java.lang.Object[], int, org.columba.mail.folder.imap.IMAPFolder)
1317:             */
1318:            public void markMessage(Object[] uids, int variant,
1319:                    IMAPFolder folder) throws IOException, IMAPException,
1320:                    CommandCancelledException {
1321:                try {
1322:                    ensureSelectedState(folder);
1323:
1324:                    SequenceSet uidSet = new SequenceSet(Arrays.asList(uids));
1325:
1326:                    protocol.uidStore(uidSet, variant > 0,
1327:                            convertToFlags(variant));
1328:
1329:                    statusDirty = true;
1330:                } catch (IMAPDisconnectedException e) {
1331:                    markMessage(uids, variant, folder);
1332:                }
1333:            }
1334:
1335:            /* (non-Javadoc)
1336:             * @see org.columba.mail.imap.IImapServer#setFlags(java.lang.Object[], org.columba.ristretto.imap.IMAPFlags, org.columba.mail.folder.imap.IMAPFolder)
1337:             */
1338:            public void setFlags(Object[] uids, IMAPFlags flags,
1339:                    IMAPFolder folder) throws IOException, IMAPException,
1340:                    CommandCancelledException {
1341:                try {
1342:                    ensureSelectedState(folder);
1343:                    SequenceSet uidSet = new SequenceSet(Arrays.asList(uids));
1344:
1345:                    protocol.uidStore(uidSet, true, flags);
1346:                } catch (IMAPDisconnectedException e) {
1347:                    setFlags(uids, flags, folder);
1348:                }
1349:            }
1350:
1351:            /* (non-Javadoc)
1352:             * @see org.columba.mail.imap.IImapServer#search(java.lang.Object[], org.columba.core.filter.FilterRule, org.columba.mail.folder.imap.IMAPFolder)
1353:             */
1354:            public List search(Object[] uids, IFilterRule filterRule,
1355:                    IMAPFolder folder) throws Exception {
1356:                LinkedList result = new LinkedList(search(filterRule, folder));
1357:
1358:                ListTools.intersect(result, Arrays.asList(uids));
1359:
1360:                return result;
1361:            }
1362:
1363:            /* (non-Javadoc)
1364:             * @see org.columba.mail.imap.IImapServer#getIndex(java.lang.Integer, org.columba.mail.folder.imap.IMAPFolder)
1365:             */
1366:            public int getIndex(Integer uid, IMAPFolder folder)
1367:                    throws IOException, IMAPException,
1368:                    CommandCancelledException {
1369:
1370:                try {
1371:                    ensureSelectedState(folder);
1372:
1373:                    SearchKey key = new SearchKey(SearchKey.UID, uid);
1374:
1375:                    Integer[] index = protocol.search(new SearchKey[] { key });
1376:                    if (index.length > 0) {
1377:                        return index[0].intValue();
1378:                    } else {
1379:                        return -1;
1380:                    }
1381:                } catch (IMAPDisconnectedException e) {
1382:                    return getIndex(uid, folder);
1383:                }
1384:            }
1385:
1386:            /* (non-Javadoc)
1387:             * @see org.columba.mail.imap.IImapServer#search(org.columba.ristretto.imap.SearchKey, org.columba.mail.folder.imap.IMAPFolder)
1388:             */
1389:            public Integer[] search(SearchKey key, IMAPFolder folder)
1390:                    throws IOException, IMAPException,
1391:                    CommandCancelledException {
1392:                try {
1393:                    ensureSelectedState(folder);
1394:
1395:                    return protocol.uidSearch(new SearchKey[] { key });
1396:                } catch (IMAPDisconnectedException e) {
1397:                    return search(key, folder);
1398:                }
1399:            }
1400:
1401:            /* (non-Javadoc)
1402:             * @see org.columba.mail.imap.IImapServer#search(org.columba.core.filter.FilterRule, org.columba.mail.folder.imap.IMAPFolder)
1403:             */
1404:            public List search(IFilterRule filterRule, IMAPFolder folder)
1405:                    throws IOException, IMAPException,
1406:                    CommandCancelledException {
1407:
1408:                try {
1409:                    ensureSelectedState(folder);
1410:
1411:                    SearchKey[] searchRequest;
1412:
1413:                    searchRequest = createSearchKey(filterRule);
1414:
1415:                    Integer[] result = null;
1416:                    Charset charset = UTF8;
1417:
1418:                    while (result == null) {
1419:                        try {
1420:                            result = protocol.uidSearch(charset, searchRequest);
1421:                        } catch (IMAPException e) {
1422:                            if (e.getResponse().isNO() && charset != null) {
1423:                                // Server does not support UTF-8
1424:                                // -> fall back to System default
1425:                                if (charset.equals(UTF8)) {
1426:                                    charset = DEFAULT;
1427:                                } else if (charset == DEFAULT) {
1428:                                    // If this also does not work
1429:                                    // -> fall back to no charset specified
1430:                                    charset = null;
1431:                                } else {
1432:                                    // something else is wrong
1433:                                    throw e;
1434:                                }
1435:                            } else
1436:                                throw e;
1437:                        }
1438:                    }
1439:
1440:                    return Arrays.asList(result);
1441:                } catch (IMAPDisconnectedException e) {
1442:                    return search(filterRule, folder);
1443:                }
1444:            }
1445:
1446:            /**
1447:             * @param filterRule
1448:             */
1449:            private SearchKey[] createSearchKey(IFilterRule filterRule) {
1450:                SearchKey[] searchRequest;
1451:                int argumentSize = filterRule.getChildCount();
1452:                // One or many arguments?
1453:                if (argumentSize == 1) {
1454:                    // One is the easiest case
1455:                    searchRequest = new SearchKey[] { getSearchKey(filterRule
1456:                            .get(0)) };
1457:                } else {
1458:                    // AND or OR ? -> AND is implicit, OR must be specified
1459:                    if (filterRule.getConditionInt() == FilterRule.MATCH_ALL) {
1460:                        // AND : simply create a list of arguments
1461:                        searchRequest = new SearchKey[argumentSize];
1462:
1463:                        for (int i = 0; i < argumentSize; i++) {
1464:                            searchRequest[i] = getSearchKey(filterRule.get(i));
1465:                        }
1466:
1467:                    } else {
1468:                        // OR : the arguments must be glued by a OR SearchKey
1469:                        SearchKey orKey;
1470:
1471:                        orKey = new SearchKey(SearchKey.OR,
1472:                                getSearchKey(filterRule.get(argumentSize - 1)),
1473:                                getSearchKey(filterRule.get(argumentSize - 2)));
1474:
1475:                        for (int i = argumentSize - 3; i >= 0; i--) {
1476:                            orKey = new SearchKey(SearchKey.OR,
1477:                                    getSearchKey(filterRule.get(i)), orKey);
1478:                        }
1479:
1480:                        searchRequest = new SearchKey[] { orKey };
1481:                    }
1482:                }
1483:
1484:                return searchRequest;
1485:            }
1486:
1487:            /**
1488:             * @param criteria
1489:             * @return
1490:             */
1491:            private SearchKey getSearchKey(IFilterCriteria criteria) {
1492:                int operator = criteria.getCriteria();
1493:                int type = new MailFilterCriteria(criteria).getType();
1494:
1495:                switch (type) {
1496:                case MailFilterCriteria.FROM: {
1497:                    if (operator == FilterCriteria.CONTAINS) {
1498:                        return new SearchKey(SearchKey.FROM, criteria
1499:                                .getPatternString());
1500:                    } else {
1501:                        // contains not
1502:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1503:                                SearchKey.FROM, criteria.getPatternString()));
1504:                    }
1505:                }
1506:
1507:                case MailFilterCriteria.CC: {
1508:                    if (operator == FilterCriteria.CONTAINS) {
1509:                        return new SearchKey(SearchKey.CC, criteria
1510:                                .getPatternString());
1511:                    } else {
1512:                        // contains not
1513:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1514:                                SearchKey.CC, criteria.getPatternString()));
1515:                    }
1516:                }
1517:
1518:                case MailFilterCriteria.BCC: {
1519:                    if (operator == FilterCriteria.CONTAINS) {
1520:                        return new SearchKey(SearchKey.BCC, criteria
1521:                                .getPatternString());
1522:                    } else {
1523:                        // contains not
1524:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1525:                                SearchKey.BCC, criteria.getPatternString()));
1526:                    }
1527:                }
1528:
1529:                case MailFilterCriteria.TO: {
1530:                    if (operator == FilterCriteria.CONTAINS) {
1531:                        return new SearchKey(SearchKey.TO, criteria
1532:                                .getPatternString());
1533:                    } else {
1534:                        // contains not
1535:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1536:                                SearchKey.TO, criteria.getPatternString()));
1537:                    }
1538:                }
1539:
1540:                case MailFilterCriteria.SUBJECT: {
1541:                    if (operator == FilterCriteria.CONTAINS) {
1542:                        return new SearchKey(SearchKey.SUBJECT, criteria
1543:                                .getPatternString());
1544:                    } else {
1545:                        // contains not
1546:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1547:                                SearchKey.SUBJECT, criteria.getPatternString()));
1548:                    }
1549:                }
1550:
1551:                case MailFilterCriteria.BODY: {
1552:                    if (operator == FilterCriteria.CONTAINS) {
1553:                        return new SearchKey(SearchKey.BODY, criteria
1554:                                .getPatternString());
1555:                    } else {
1556:                        // contains not
1557:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1558:                                SearchKey.BODY, criteria.getPatternString()));
1559:                    }
1560:                }
1561:
1562:                case MailFilterCriteria.CUSTOM_HEADERFIELD: {
1563:                    if (operator == FilterCriteria.CONTAINS) {
1564:                        return new SearchKey(SearchKey.HEADER,
1565:                                new MailFilterCriteria(criteria)
1566:                                        .getHeaderfieldString(), criteria
1567:                                        .getPatternString());
1568:                    } else {
1569:                        // contains not
1570:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1571:                                SearchKey.HEADER, new MailFilterCriteria(
1572:                                        criteria).getHeaderfieldString(),
1573:                                criteria.getPatternString()));
1574:                    }
1575:                }
1576:
1577:                case MailFilterCriteria.DATE: {
1578:                    DateFormat df = DateFormat.getDateInstance();
1579:
1580:                    IMAPDate searchPattern = null;
1581:
1582:                    try {
1583:                        searchPattern = new IMAPDate(df.parse(criteria
1584:                                .getPatternString()));
1585:                    } catch (java.text.ParseException ex) {
1586:                        // should never happen
1587:                        ex.printStackTrace();
1588:                    }
1589:
1590:                    if (operator == FilterCriteria.DATE_BEFORE) {
1591:                        return new SearchKey(SearchKey.BEFORE, searchPattern);
1592:                    } else {
1593:                        // AFTER
1594:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1595:                                SearchKey.BEFORE, searchPattern));
1596:                    }
1597:                }
1598:
1599:                case MailFilterCriteria.SIZE: {
1600:                    if (operator == FilterCriteria.SIZE_SMALLER) {
1601:                        return new SearchKey(SearchKey.SMALLER, criteria
1602:                                .getPatternString());
1603:                    } else {
1604:                        // contains not
1605:                        return new SearchKey(SearchKey.NOT, new SearchKey(
1606:                                SearchKey.SMALLER, criteria.getPatternString()));
1607:                    }
1608:                }
1609:                }
1610:
1611:                return null;
1612:            }
1613:
1614:            /**
1615:             * Check if string contains US-ASCII characters.
1616:             *
1617:             * @param s
1618:             * @return true, if string contains US-ASCII characters
1619:             */
1620:            protected static boolean isAscii(String s) {
1621:                int l = s.length();
1622:
1623:                for (int i = 0; i < l; i++) {
1624:                    if ((int) s.charAt(i) > 0177) { // non-ascii
1625:
1626:                        return false;
1627:                    }
1628:                }
1629:
1630:                return true;
1631:            }
1632:
1633:            /**
1634:             * Create string representation of {@ link MarkMessageCommand}constants.
1635:             *
1636:             * @param variant
1637:             * @return
1638:             */
1639:            private IMAPFlags convertToFlags(int variant) {
1640:                IMAPFlags result = new IMAPFlags();
1641:
1642:                switch (variant) {
1643:                case MarkMessageCommand.MARK_AS_READ:
1644:                case MarkMessageCommand.MARK_AS_UNREAD: {
1645:                    result.setSeen(true);
1646:
1647:                    break;
1648:                }
1649:
1650:                case MarkMessageCommand.MARK_AS_FLAGGED:
1651:                case MarkMessageCommand.MARK_AS_UNFLAGGED: {
1652:                    result.setFlagged(true);
1653:
1654:                    break;
1655:                }
1656:
1657:                case MarkMessageCommand.MARK_AS_EXPUNGED:
1658:                case MarkMessageCommand.MARK_AS_UNEXPUNGED: {
1659:                    result.setDeleted(true);
1660:
1661:                    break;
1662:                }
1663:
1664:                case MarkMessageCommand.MARK_AS_ANSWERED: {
1665:                    result.setAnswered(true);
1666:
1667:                    break;
1668:                }
1669:
1670:                case MarkMessageCommand.MARK_AS_SPAM:
1671:                case MarkMessageCommand.MARK_AS_NOTSPAM: {
1672:                    result.setJunk(true);
1673:
1674:                    break;
1675:                }
1676:                case MarkMessageCommand.MARK_AS_DRAFT: {
1677:                    result.setDraft(true);
1678:
1679:                    break;
1680:                }
1681:                }
1682:
1683:                return result;
1684:            }
1685:
1686:            /* (non-Javadoc)
1687:             * @see org.columba.mail.imap.IImapServer#getMessageFolderInfo(org.columba.mail.folder.imap.IMAPFolder)
1688:             */
1689:            public MailboxInfo getMessageFolderInfo(IMAPFolder folder)
1690:                    throws IOException, IMAPException,
1691:                    CommandCancelledException {
1692:                ensureSelectedState(folder);
1693:
1694:                return messageFolderInfo;
1695:            }
1696:
1697:            /* (non-Javadoc)
1698:             * @see org.columba.mail.imap.IImapServer#fetchSubscribedFolders()
1699:             */
1700:            public ListInfo[] fetchSubscribedFolders() throws IOException,
1701:                    IMAPException, CommandCancelledException {
1702:                try {
1703:                    ensureLoginState();
1704:                    ListInfo[] lsub = protocol.lsub("", "*");
1705:
1706:                    // Also set the delimiter
1707:                    if (lsub.length > 0) {
1708:                        delimiter = lsub[0].getDelimiter();
1709:                    }
1710:
1711:                    return lsub;
1712:                } catch (IMAPDisconnectedException e) {
1713:                    return fetchSubscribedFolders();
1714:                }
1715:            }
1716:
1717:            /* (non-Javadoc)
1718:             * @see org.columba.mail.imap.IImapServer#isSelected(org.columba.mail.folder.imap.IMAPFolder)
1719:             */
1720:            public boolean isSelected(IMAPFolder folder) throws IOException,
1721:                    IMAPException, CommandCancelledException {
1722:                ensureLoginState();
1723:
1724:                return (protocol.getState() == IMAPProtocol.SELECTED && protocol
1725:                        .getSelectedMailbox().equals(folder.getImapPath()));
1726:            }
1727:
1728:            /**
1729:             * @param e
1730:             * @return
1731:             */
1732:            private int showErrorDialog(String message) {
1733:                Object[] options = new String[] {
1734:                        MailResourceLoader.getString("", "global", "ok")
1735:                                .replaceAll("&", ""),
1736:                        MailResourceLoader.getString("", "global", "cancel")
1737:                                .replaceAll("&", "") };
1738:
1739:                int result = JOptionPane.showOptionDialog(FrameManager
1740:                        .getInstance().getActiveFrame(), message, "Warning",
1741:                        JOptionPane.DEFAULT_OPTION,
1742:                        JOptionPane.WARNING_MESSAGE, null, options, options[0]);
1743:                return result;
1744:            }
1745:
1746:            /* (non-Javadoc)
1747:             * @see org.columba.mail.imap.IImapServer#alertMessage(java.lang.String)
1748:             */
1749:            public void alertMessage(String arg0) {
1750:                // TODO: Show dialog
1751:                LOG.warning(arg0);
1752:            }
1753:
1754:            /* (non-Javadoc)
1755:             * @see org.columba.mail.imap.IImapServer#connectionClosed(java.lang.String, java.lang.String)
1756:             */
1757:            public void connectionClosed(String arg0, String arg1) {
1758:                LOG.info(arg0);
1759:                selectedFolder = null;
1760:            }
1761:
1762:            /* (non-Javadoc)
1763:             * @see org.columba.mail.imap.IImapServer#existsChanged(java.lang.String, int)
1764:             */
1765:            public void existsChanged(String arg0, int arg1) {
1766:                if (selectedStatus == null)
1767:                    return;
1768:
1769:                selectedStatus.setMessages(arg1);
1770:                statusDirty = true;
1771:
1772:                if (updatesEnabled) {
1773:                    if (existsChangedAction != null) {
1774:                        existsChangedAction.actionPerformed(selectedFolder);
1775:                    }
1776:
1777:                    LOG.fine("Exists changed -> triggering update");
1778:
1779:                }
1780:            }
1781:
1782:            /* (non-Javadoc)
1783:             * @see org.columba.mail.imap.IImapServer#flagsChanged(java.lang.String, org.columba.ristretto.imap.IMAPFlags)
1784:             */
1785:            public void flagsChanged(String arg0, IMAPFlags arg1) {
1786:                LOG.fine("Flag changed -> triggering update");
1787:
1788:                if (updateFlagAction != null) {
1789:                    updateFlagAction.actionPerformed(selectedFolder, arg1);
1790:                }
1791:
1792:            }
1793:
1794:            /* (non-Javadoc)
1795:             * @see org.columba.mail.imap.IImapServer#parseError(java.lang.String)
1796:             */
1797:            public void parseError(String arg0) {
1798:                LOG.warning(arg0);
1799:            }
1800:
1801:            /* (non-Javadoc)
1802:             * @see org.columba.mail.imap.IImapServer#recentChanged(java.lang.String, int)
1803:             */
1804:            public void recentChanged(String arg0, int arg1) {
1805:                if (selectedStatus == null)
1806:                    return;
1807:
1808:                selectedStatus.setRecent(arg1);
1809:                statusDirty = true;
1810:
1811:                // We trigger an update only when the exists changed
1812:                // which should be equal with a Recent change.
1813:            }
1814:
1815:            /* (non-Javadoc)
1816:             * @see org.columba.mail.imap.IImapServer#warningMessage(java.lang.String)
1817:             */
1818:            public void warningMessage(String arg0) {
1819:                LOG.warning(arg0);
1820:            }
1821:
1822:            /**
1823:             * Returns configuration options of this IMAP account
1824:             *
1825:             * @return configuration options of this IMAP account
1826:             */
1827:            /* (non-Javadoc)
1828:             * @see org.columba.mail.imap.IImapServer#getItem()
1829:             */
1830:            public ImapItem getItem() {
1831:                return item;
1832:            }
1833:
1834:            /* (non-Javadoc)
1835:             * @see org.columba.mail.imap.IImapServer#update(java.util.Observable, java.lang.Object)
1836:             */
1837:            public void update(Observable o, Object arg) {
1838:                protocol = new IMAPProtocol(item.get("host"), item
1839:                        .getInteger("port"));
1840:            }
1841:
1842:            /* (non-Javadoc)
1843:             * @see org.columba.mail.imap.IImapServer#setExistsChangedAction(org.columba.mail.imap.IExistsChangedAction)
1844:             */
1845:            public void setExistsChangedAction(
1846:                    IExistsChangedAction existsChangedAction) {
1847:                this .existsChangedAction = existsChangedAction;
1848:            }
1849:
1850:            /* (non-Javadoc)
1851:             * @see org.columba.mail.imap.IImapServer#setUpdateFlagAction(org.columba.mail.imap.IUpdateFlagAction)
1852:             */
1853:            public void setUpdateFlagAction(IUpdateFlagAction updateFlagAction) {
1854:                this .updateFlagAction = updateFlagAction;
1855:            }
1856:
1857:            /* (non-Javadoc)
1858:             * @see org.columba.mail.imap.IImapServer#setObservable(org.columba.api.command.IStatusObservable)
1859:             */
1860:            public void setObservable(IStatusObservable observable) {
1861:                this.observable = observable;
1862:            }
1863:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.