Ignore:
Timestamp:
09/05/10 14:03:08 (17 months ago)
Author:
octorian
Message:

Initial refactoring to make NetworkConnector separate from the Connection class

Location:
trunk/LogicMail/src/org/logicprobe/LogicMail
Files:
3 added
1 deleted
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/MailClientFactory.java

    r256 r698  
    4242import org.logicprobe.LogicMail.mail.pop.PopClient; 
    4343import org.logicprobe.LogicMail.mail.smtp.SmtpClient; 
     44import org.logicprobe.LogicMail.util.UtilFactory; 
    4445 
    4546/** 
     
    4849 */ 
    4950public class MailClientFactory { 
    50     private static Hashtable incomingClientTable = new Hashtable(); 
    51     private static Hashtable outgoingClientTable = new Hashtable(); 
     51    private static final Hashtable incomingClientTable = new Hashtable(); 
     52    private static final Hashtable outgoingClientTable = new Hashtable(); 
    5253     
    5354    private MailClientFactory() { } 
     
    6768            GlobalConfig globalConfig = MailSettings.getInstance().getGlobalConfig(); 
    6869            if(acctConfig instanceof PopConfig) { 
    69                 client = new PopClient(globalConfig, (PopConfig)acctConfig); 
     70                client = new PopClient( 
     71                        UtilFactory.getInstance().getNetworkConnector(globalConfig, acctConfig), 
     72                        globalConfig, (PopConfig)acctConfig); 
    7073                incomingClientTable.put(acctConfig, client); 
    7174            } 
    7275            else if(acctConfig instanceof ImapConfig) { 
    73                 client = new ImapClient(globalConfig, (ImapConfig)acctConfig); 
     76                client = new ImapClient( 
     77                        UtilFactory.getInstance().getNetworkConnector(globalConfig, acctConfig), 
     78                        globalConfig, (ImapConfig)acctConfig); 
    7479                incomingClientTable.put(acctConfig, client); 
    7580            } 
     
    105110            if(client == null) { 
    106111                GlobalConfig globalConfig = MailSettings.getInstance().getGlobalConfig(); 
    107                 client = new SmtpClient(globalConfig, outgoingConfig); 
     112                client = new SmtpClient( 
     113                        UtilFactory.getInstance().getNetworkConnector(globalConfig, outgoingConfig), 
     114                        globalConfig, outgoingConfig); 
    108115                outgoingClientTable.put(outgoingConfig, client); 
    109116            } 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/imap/ImapClient.java

    r694 r698  
    6565import org.logicprobe.LogicMail.message.UnsupportedPart; 
    6666import org.logicprobe.LogicMail.util.Connection; 
    67 import org.logicprobe.LogicMail.util.UtilFactory; 
     67import org.logicprobe.LogicMail.util.NetworkConnector; 
    6868import org.logicprobe.LogicMail.util.DataStore; 
    6969import org.logicprobe.LogicMail.util.DataStoreFactory; 
     
    7575 */ 
    7676public class ImapClient extends AbstractIncomingMailClient { 
    77     private MailSettings mailSettings; 
    78     private ImapConfig accountConfig; 
     77    private final NetworkConnector networkConnector; 
     78    private final MailSettings mailSettings; 
     79    private final ImapConfig accountConfig; 
     80    private final ImapProtocol imapProtocol; 
    7981    private Connection connection; 
    80     private ImapProtocol imapProtocol; 
    8182    private String username; 
    8283    private String password; 
    8384    private boolean openStarted; 
    84     private boolean configChanged; 
    8585 
    8686    /** 
     
    132132    private static String CAPABILITY_IDLE = "IDLE"; 
    133133     
    134     public ImapClient(GlobalConfig globalConfig, ImapConfig accountConfig) { 
     134    public ImapClient(NetworkConnector networkConnector, GlobalConfig globalConfig, ImapConfig accountConfig) { 
     135        this.networkConnector = networkConnector; 
    135136        this.accountConfig = accountConfig; 
    136137        this.mailSettings = MailSettings.getInstance(); 
    137         connection = UtilFactory.getInstance().createConnection(accountConfig); 
    138         imapProtocol = new ImapProtocol(connection); 
     138        imapProtocol = new ImapProtocol(); 
    139139        username = accountConfig.getServerUser(); 
    140140        password = accountConfig.getServerPass(); 
    141141        openStarted = false; 
    142         configChanged = false; 
    143142        mailSettings.addMailSettingsListener(mailSettingsListener); 
    144143    } 
     
    165164            username = accountConfig.getServerUser(); 
    166165            password = accountConfig.getServerPass(); 
    167  
    168             if(!isConnected()) { 
    169                 // Rebuild the connection to include new settings 
    170                 connection = UtilFactory.getInstance().createConnection(accountConfig); 
    171                 imapProtocol = new ImapProtocol(connection); 
    172             } 
    173             else { 
    174                 // Set a flag to make sure we rebuild the Connection object 
    175                 // the next time we close the connection. 
    176                 configChanged = true; 
    177             } 
    178166        } 
    179167    } 
     
    185173        try { 
    186174            if(!openStarted) { 
    187                 connection.open(); 
     175                connection = networkConnector.open(accountConfig); 
     176                imapProtocol.setConnection(connection); 
     177                 
    188178                activeMailbox = null; 
    189179 
    190180                // Swallow the initial "* OK" line from the server 
    191181                connection.receive(); 
    192  
     182                 
    193183                // Find out server capabilities 
    194184                capabilities = imapProtocol.executeCapability(); 
     
    202192                    || (serverSecurity == ConnectionConfig.SECURITY_TLS)) { 
    203193                imapProtocol.executeStartTLS(); 
    204                 connection.startTLS(); 
     194                connection = networkConnector.getConnectionAsTLS(connection); 
     195                imapProtocol.setConnection(connection); 
    205196            } 
    206197 
     
    251242    public void close() throws IOException, MailException { 
    252243        if(connection.isConnected()) { 
    253             // Not closing to avoid expunging deleted messages 
    254             //if(activeMailbox != null && !activeMailbox.equals("")) { 
    255             //    imapProtocol.executeClose(); 
    256             //} 
     244            // Note: Active mailbox is not closed to avoid unintentionally 
     245            // expunging deleted messages. 
    257246            try { 
    258247                imapProtocol.executeLogout(); 
     
    261250        activeMailbox = null; 
    262251        connection.close(); 
    263  
    264         if(configChanged) { 
    265             // Rebuild the connection to include new settings 
    266             connection = UtilFactory.getInstance().createConnection(accountConfig); 
    267             imapProtocol = new ImapProtocol(connection); 
    268             configChanged = false; 
    269         } 
     252        connection = null; 
    270253    } 
    271254 
     
    274257     */ 
    275258    public boolean isConnected() { 
    276         return connection.isConnected(); 
     259        return connection != null && connection.isConnected(); 
    277260    } 
    278261 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/imap/ImapProtocol.java

    r692 r698  
    4949import java.util.Vector; 
    5050 
    51  
    5251/** 
    5352 * This class implements the commands for the IMAP protocol 
    5453 */ 
    5554public class ImapProtocol { 
    56  
    5755    private Connection connection; 
    5856    private String idleCommandTag; 
     
    6563 
    6664    /** Creates a new instance of ImapProtocol */ 
    67     public ImapProtocol(Connection connection) { 
     65    public ImapProtocol() { 
     66    } 
     67 
     68    /** 
     69     * Sets the connection instance used by this class. 
     70     * This must be set after opening the connection, and prior to calling any 
     71     * command methods. 
     72     * 
     73     * @param connection the new connection instance 
     74     */ 
     75    public void setConnection(Connection connection) { 
    6876        this.connection = connection; 
    6977    } 
    70  
     78     
    7179    /** 
    7280     * Execute the "STARTTLS" command. 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/pop/PopClient.java

    r658 r698  
    5858import org.logicprobe.LogicMail.message.MimeMessagePart; 
    5959import org.logicprobe.LogicMail.util.Connection; 
    60 import org.logicprobe.LogicMail.util.UtilFactory; 
     60import org.logicprobe.LogicMail.util.NetworkConnector; 
    6161import org.logicprobe.LogicMail.util.MailMessageParser; 
    6262import org.logicprobe.LogicMail.util.StringParser; 
     
    6868 */ 
    6969public class PopClient extends AbstractIncomingMailClient { 
    70     private MailSettings mailSettings; 
    71     private GlobalConfig globalConfig; 
    72     private PopConfig accountConfig; 
     70    private final NetworkConnector networkConnector; 
     71    private final MailSettings mailSettings; 
     72    private final GlobalConfig globalConfig; 
     73    private final PopConfig accountConfig; 
     74    private final PopProtocol popProtocol; 
    7375    private Connection connection; 
    74     private PopProtocol popProtocol; 
    7576    private String username; 
    7677    private String password; 
    7778    private boolean openStarted; 
    78     private boolean configChanged; 
    7979     
    8080    /** 
     
    9191     
    9292    /** Creates a new instance of PopClient */ 
    93     public PopClient(GlobalConfig globalConfig, PopConfig accountConfig) { 
     93    public PopClient(NetworkConnector networkConnector, GlobalConfig globalConfig, PopConfig accountConfig) { 
     94        this.networkConnector = networkConnector; 
    9495        this.globalConfig = globalConfig; 
    9596        this.accountConfig = accountConfig; 
    9697        this.mailSettings = MailSettings.getInstance(); 
    97         connection = UtilFactory.getInstance().createConnection(accountConfig); 
    98         popProtocol = new PopProtocol(connection); 
     98        popProtocol = new PopProtocol(); 
    9999        username = accountConfig.getServerUser(); 
    100100        password = accountConfig.getServerPass(); 
     
    104104        activeMailbox.setMsgCount(0); 
    105105        openStarted = false; 
    106         configChanged = false; 
    107106        mailSettings.addMailSettingsListener(mailSettingsListener); 
    108107    } 
     
    129128            username = accountConfig.getServerUser(); 
    130129            password = accountConfig.getServerPass(); 
    131  
    132             if(!isConnected()) { 
    133                 // Rebuild the connection to include new settings 
    134                 connection = UtilFactory.getInstance().createConnection(accountConfig); 
    135                 popProtocol = new PopProtocol(connection); 
    136             } 
    137             else { 
    138                 // Set a flag to make sure we rebuild the Connection object 
    139                 // the next time we close the connection. 
    140                 configChanged = true; 
    141             } 
    142130        } 
    143131    } 
     
    162150    public boolean open() throws IOException, MailException { 
    163151        if(!openStarted) { 
    164             connection.open(); 
     152            connection = networkConnector.open(accountConfig); 
     153            popProtocol.setConnection(connection); 
     154             
    165155            // Eat the initial server response 
    166156            connection.receive(); 
     
    177167                        || (serverSecurity == ConnectionConfig.SECURITY_TLS)) { 
    178168                if(popProtocol.executeStartTLS()) { 
    179                     connection.startTLS(); 
     169                    connection = networkConnector.getConnectionAsTLS(connection); 
     170                    popProtocol.setConnection(connection); 
    180171                } 
    181172                else { 
     
    185176        else if(capabilities == null && serverSecurity == ConnectionConfig.SECURITY_TLS_IF_AVAILABLE) { 
    186177            if(popProtocol.executeStartTLS()) { 
    187                 connection.startTLS(); 
     178                connection = networkConnector.getConnectionAsTLS(connection); 
     179                popProtocol.setConnection(connection); 
    188180            } 
    189181        } 
     
    213205        } 
    214206        connection.close(); 
    215          
    216         if(configChanged) { 
    217                 // Rebuild the connection to include new settings 
    218             connection = UtilFactory.getInstance().createConnection(accountConfig); 
    219             popProtocol = new PopProtocol(connection); 
    220             configChanged = false; 
    221         } 
     207        connection = null; 
    222208    } 
    223209 
     
    226212     */ 
    227213    public boolean isConnected() { 
    228         return connection.isConnected(); 
     214        return connection != null && connection.isConnected(); 
    229215    } 
    230216 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/pop/PopProtocol.java

    r694 r698  
    4949     
    5050    /** Creates a new instance of PopProtocol */ 
    51     public PopProtocol(Connection connection) { 
     51    public PopProtocol() { 
     52    } 
     53     
     54    /** 
     55     * Sets the connection instance used by this class. 
     56     * This must be set after opening the connection, and prior to calling any 
     57     * command methods. 
     58     * 
     59     * @param connection the new connection instance 
     60     */ 
     61    public void setConnection(Connection connection) { 
    5262        this.connection = connection; 
    5363    } 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/smtp/SmtpClient.java

    r677 r698  
    4444import org.logicprobe.LogicMail.message.MessageMimeConverter; 
    4545import org.logicprobe.LogicMail.util.Connection; 
    46 import org.logicprobe.LogicMail.util.UtilFactory; 
     46import org.logicprobe.LogicMail.util.NetworkConnector; 
    4747import org.logicprobe.LogicMail.util.MailMessageParser; 
    4848 
     
    5555 */ 
    5656public class SmtpClient implements OutgoingMailClient { 
     57    private final NetworkConnector networkConnector; 
    5758    private final MailSettings mailSettings; 
    5859    private final GlobalConfig globalConfig; 
    5960    private final OutgoingConfig outgoingConfig; 
     61    private final SmtpProtocol smtpProtocol; 
    6062    private String hostname; 
    6163    private Connection connection; 
    62     private SmtpProtocol smtpProtocol; 
    6364    private boolean isFresh; 
    6465    private boolean openStarted; 
    6566    private String username; 
    6667    private String password; 
    67     private boolean configChanged; 
    6868     
    6969    /** 
     
    7979 
    8080    /** Creates a new instance of SmtpClient */ 
    81     public SmtpClient(GlobalConfig globalConfig, OutgoingConfig outgoingConfig) { 
     81    public SmtpClient(NetworkConnector networkConnector, GlobalConfig globalConfig, OutgoingConfig outgoingConfig) { 
     82        this.networkConnector = networkConnector; 
    8283        this.globalConfig = globalConfig; 
    8384        this.outgoingConfig = outgoingConfig; 
    8485        this.mailSettings = MailSettings.getInstance(); 
    85         connection = UtilFactory.getInstance().createConnection(outgoingConfig); 
    86         smtpProtocol = new SmtpProtocol(connection); 
     86        smtpProtocol = new SmtpProtocol(); 
    8787 
    8888        if (outgoingConfig.getUseAuth() > 0) { 
     
    9595 
    9696        openStarted = false; 
    97         configChanged = false; 
    9897        mailSettings.addMailSettingsListener(mailSettingsListener); 
    9998    } 
     
    114113            username = outgoingConfig.getServerUser(); 
    115114            password = outgoingConfig.getServerPass(); 
    116  
    117             if(!isConnected()) { 
    118                 // Rebuild the connection to include new settings 
    119                 connection = UtilFactory.getInstance().createConnection(outgoingConfig); 
    120                 smtpProtocol = new SmtpProtocol(connection); 
    121             } 
    122             else { 
    123                 // Set a flag to make sure we rebuild the Connection object 
    124                 // the next time we close the connection. 
    125                 configChanged = true; 
    126             } 
    127115        } 
    128116    } 
     
    130118    public boolean open() throws IOException, MailException { 
    131119        if (!openStarted) { 
    132             connection.open(); 
     120            connection = networkConnector.open(outgoingConfig); 
     121            smtpProtocol.setConnection(connection); 
    133122 
    134123            // Eat the initial server response 
     
    154143                        || (serverSecurity == ConnectionConfig.SECURITY_TLS)) { 
    155144                smtpProtocol.executeStartTLS(); 
    156                 connection.startTLS(); 
     145                connection = networkConnector.getConnectionAsTLS(connection); 
     146                smtpProtocol.setConnection(connection); 
    157147                 
    158148                // Re-execute the EHLO command, since some servers require this 
     
    182172 
    183173        connection.close(); 
    184  
    185         if (configChanged) { 
    186             // Rebuild the connection to include new settings 
    187             connection = UtilFactory.getInstance().createConnection(outgoingConfig); 
    188             smtpProtocol = new SmtpProtocol(connection); 
    189             configChanged = false; 
    190         } 
     174        connection = null; 
    191175    } 
    192176 
     
    196180 
    197181    public boolean isConnected() { 
    198         return connection.isConnected(); 
     182        return connection != null && connection.isConnected(); 
    199183    } 
    200184 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/mail/smtp/SmtpProtocol.java

    r689 r698  
    4343import org.logicprobe.LogicMail.util.Connection; 
    4444import org.logicprobe.LogicMail.util.MD5; 
    45 import org.logicprobe.LogicMail.util.StringParser; 
    4645 
    4746/** 
     
    4948 */ 
    5049public class SmtpProtocol { 
    51     private final Connection connection; 
     50    private Connection connection; 
    5251     
    5352    /** Specifies the PLAIN authentication mechanism */ 
     
    6160     
    6261    /** Creates a new instance of SmtpProtocol */ 
    63     public SmtpProtocol(Connection connection) { 
     62    public SmtpProtocol() { 
     63    } 
     64     
     65    /** 
     66     * Sets the connection instance used by this class. 
     67     * This must be set after opening the connection, and prior to calling any 
     68     * command methods. 
     69     * 
     70     * @param connection the new connection instance 
     71     */ 
     72    public void setConnection(Connection connection) { 
    6473        this.connection = connection; 
    6574    } 
     
    140149             
    141150            result = execute(Base64OutputStream.encodeAsString(eval, 0, eval.length, false, false)); 
    142             if(!result.startsWith(CODE_235)) { 
    143                 return false; 
    144             } 
    145         } 
    146         else if(mech == AUTH_DIGEST_MD5) { 
    147             // Note: This code does not currently work correctly 
    148             result = execute("AUTH DIGEST-MD5"); 
    149             if(!result.startsWith(CODE_334)) { 
    150                 throw new MailException(result.substring(4)); 
    151             } 
    152              
    153             String challenge = new String(Base64InputStream.decode(result.substring(4))); 
    154             System.err.println("-->Challenge: " + challenge); 
    155             // Note, the fields with CSV string values will get mucked up 
    156             String[] fields = StringParser.parseTokenString(challenge, ","); 
    157             int i; 
    158             String realm = null; 
    159             String nonce = null; 
    160             String qop = null; 
    161             String algorithm = null; 
    162             String charset = null; 
    163             for(i = 0; i < fields.length; i++) { 
    164                 if(fields[i].startsWith("realm")) { 
    165                     realm = parseValue(fields[i]); 
    166                 } 
    167                 else if(fields[i].startsWith("nonce")) { 
    168                     nonce = parseValue(fields[i]); 
    169                 } 
    170                 else if(fields[i].startsWith("qop")) { 
    171                     qop = parseValue(fields[i]); 
    172                 } 
    173                 else if(fields[i].startsWith("algorithm")) { 
    174                     algorithm = parseValue(fields[i]); 
    175                 } 
    176                 else if(fields[i].startsWith("charset")) { 
    177                     charset = parseValue(fields[i]); 
    178                 } 
    179             } 
    180             System.err.println("-->  Realm: "+realm); 
    181             System.err.println("-->  Nonce: "+nonce); 
    182             System.err.println("-->  Qop: "+qop); 
    183             System.err.println("-->  Algorithm: "+algorithm); 
    184             System.err.println("-->  Charset: "+charset); 
    185              
    186             StringBuffer buf = new StringBuffer(); 
    187             MD5 md5 = new MD5(); 
    188             // Generate the response 
    189             // If authzid is not specified, then A1 is: 
    190             // A1 = { H( { username-value, ":", realm-value, ":", passwd } ), 
    191             //       ":", nonce-value, ":", cnonce-value } 
    192             buf.append(username); 
    193             buf.append(':'); 
    194             buf.append(realm); 
    195             buf.append(':'); 
    196             buf.append(password); 
    197             md5.update(buf.toString().getBytes(charset)); 
    198             String A1 = byteArrayToHexString(md5.getDigest()); // HEX(H(A1)) 
    199             System.err.println("A1: HEX(H( { "+buf.toString()+" )) = " + A1); 
    200              
    201             // If the "qop" directive's value is "auth", then A2 is: 
    202             // A2 = { "AUTHENTICATE:", digest-uri-value } 
    203             buf = new StringBuffer(); 
    204             md5.reset(); 
    205             buf.append("AUTHENTICATE:"); 
    206             buf.append("smtp/"); 
    207             buf.append(connection.getServerName()); 
    208             md5.update(buf.toString().getBytes(charset)); 
    209             String A2 = byteArrayToHexString(md5.getDigest()); // HEX(H(A2)) 
    210             System.err.println("A2: HEX(H("+buf.toString()+")) = " + A2); 
    211              
    212             String cnonce = "K4esOhbue3/urOGXWiEivkF9WUeZziawEHFC9nEz4BA="; 
    213             String nc = "00000001"; 
    214  
    215             //HEX( KD ( HEX(H(A1)), 
    216             //     { nonce-value, ":" nc-value, ":", 
    217             //       cnonce-value, ":", qop-value, ":", HEX(H(A2)) })) 
    218             buf = new StringBuffer(); 
    219             md5.reset(); 
    220             buf.append(A1); 
    221             buf.append(':'); 
    222             buf.append(nonce); 
    223             buf.append(':'); 
    224             buf.append(nc); 
    225             buf.append(':'); 
    226             buf.append(cnonce); 
    227             buf.append(':'); 
    228             buf.append("auth"); 
    229             buf.append(':'); 
    230             buf.append(A2); 
    231             md5.update(buf.toString().getBytes(charset)); 
    232             String resp = byteArrayToHexString(md5.getDigest()); 
    233             System.err.println("HEX(MD5("+buf.toString()+")) = " + resp); 
    234              
    235             // Craft the reply 
    236             buf = new StringBuffer(); 
    237             buf.append("charset="+charset+","); 
    238             buf.append("username=\""+username+"\","); 
    239             buf.append("realm=\""+realm+"\","); 
    240             buf.append("nonce=\""+nonce+"\","); 
    241             buf.append("nc="+nc+","); 
    242             buf.append("cnonce=\""+cnonce+"\","); 
    243             buf.append("digest-uri=\"smtp/"+connection.getServerName()+"\","); 
    244             buf.append("response="+resp+","); 
    245             buf.append("qop=auth"); 
    246             System.err.println("-->Response: " + buf.toString()); 
    247             byte[] response = buf.toString().getBytes(charset); 
    248             result = execute(Base64OutputStream.encodeAsString(response, 0, response.length, false, false)); 
    249             if(!result.startsWith(CODE_334)) { 
    250                 return false; 
    251             } 
    252             System.err.println("-->Result: "+(new String(Base64InputStream.decode(result)))); 
    253151            if(!result.startsWith(CODE_235)) { 
    254152                return false; 
     
    488386         
    489387        return digest; 
    490     } 
    491  
    492     private static String parseValue(String input) { 
    493         int p, q; 
    494         p = input.indexOf('=') + 1; 
    495         q = input.length() - 1; 
    496         if(q <= p) { 
    497             return null; 
    498         } 
    499         if(input.charAt(p) == '\"') { 
    500             p++; 
    501         } 
    502         if(input.charAt(q) == '\"') { 
    503             q--; 
    504         } 
    505         return input.substring(p, q+1); 
    506388    } 
    507389 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/util/Connection.java

    r696 r698  
    3232package org.logicprobe.LogicMail.util; 
    3333 
    34 import net.rim.device.api.crypto.tls.tls10.TLS10Connection; 
    35 import net.rim.device.api.i18n.ResourceBundle; 
    3634import net.rim.device.api.io.NoCopyByteArrayOutputStream; 
    3735import net.rim.device.api.system.EventLogger; 
    3836import net.rim.device.api.util.Arrays; 
    39 import net.rim.device.cldc.io.ssl.TLSException; 
    4037 
    4138import org.logicprobe.LogicMail.AppInfo; 
    42 import org.logicprobe.LogicMail.LogicMailResource; 
    43 import org.logicprobe.LogicMail.conf.ConnectionConfig; 
    4439import org.logicprobe.LogicMail.conf.GlobalConfig; 
    4540import org.logicprobe.LogicMail.conf.MailSettings; 
    4641 
    4742import java.io.ByteArrayOutputStream; 
    48 import java.io.DataInputStream; 
    49 import java.io.DataOutputStream; 
    5043import java.io.IOException; 
    5144import java.io.InputStream; 
     
    5346 
    5447import javax.microedition.io.SocketConnection; 
    55 import javax.microedition.io.StreamConnection; 
    5648 
    5749 
    5850/** 
    59  * This is the abstract base class for socket connections used inside the SMTP, 
    60  * POP3, and IMAP protocols of the mail package.  It handles the details of 
    61  * sending data in what ever manner is appropriate to the mail protocol, and 
    62  * receiving data in whole lines.  The specifics of opening network connections 
    63  * on the BlackBerry platform is delegated to subclasses. 
     51 * This class serves as a facade for socket connections used by the various 
     52 * protocols supported by this application.  It handles the details of sending 
     53 * and receiving data in whole lines, with customizable logic to meet protocol 
     54 * specific needs. 
    6455 */ 
    65 public abstract class Connection { 
    66     protected static ResourceBundle resources = ResourceBundle.getBundle(LogicMailResource.BUNDLE_ID, LogicMailResource.BUNDLE_NAME); 
    67      
    68     /** Select everything except WiFi */ 
    69     protected static final int TRANSPORT_AUTO = 0xFE; 
    70     /** Select WiFi */ 
    71     protected static final int TRANSPORT_WIFI = 0x01; 
    72     /** Select Direct TCP */ 
    73     protected static final int TRANSPORT_DIRECT_TCP = 0x02; 
    74     /** Select MDS */ 
    75     protected static final int TRANSPORT_MDS = 0x04; 
    76     /** Select WAP 2.0 */ 
    77     protected static final int TRANSPORT_WAP2 = 0x08; 
    78  
     56public class Connection { 
    7957    private static final byte CR = (byte)0x0D; 
    8058    private static final byte LF = (byte)0x0A; 
     
    8260    private static String strCRLF = "\r\n"; 
    8361 
    84     private UtilFactory utilFactory; 
    85     protected String serverName; 
    86     protected int serverPort; 
    87     protected boolean useSSL; 
    88     protected int transports; 
    89     private StreamConnection socket; 
     62    private SocketConnection socket; 
    9063    private String localAddress; 
    91     private String connectionUrl; 
    92     protected GlobalConfig globalConfig; 
    93     protected boolean useWiFi; 
     64    private GlobalConfig globalConfig; 
    9465    private InputStream input; 
    9566    private OutputStream output; 
     
    11485     * Initializes a new connection object. 
    11586     *  
    116      * @param connectionConfig Configuration data for the connection 
    117      */ 
    118     protected Connection(ConnectionConfig connectionConfig) { 
     87     * @param socket Socket representing the connection 
     88     * @throws IOException Thrown if an I/O error occurs 
     89     */ 
     90    protected Connection(SocketConnection socket) throws IOException { 
    11991        this.globalConfig = MailSettings.getInstance().getGlobalConfig(); 
    120         this.utilFactory = UtilFactory.getInstance(); 
    121          
    122         this.serverName = connectionConfig.getServerName(); 
    123         this.serverPort = connectionConfig.getServerPort(); 
    124         this.useSSL = (connectionConfig.getServerSecurity() == ConnectionConfig.SECURITY_SSL); 
    125          
    126         int transportType; 
    127         boolean enableWiFi; 
    128         if(connectionConfig.getTransportType() == ConnectionConfig.TRANSPORT_GLOBAL) { 
    129             transportType = globalConfig.getTransportType(); 
    130             enableWiFi = globalConfig.getEnableWiFi(); 
    131         } 
    132         else { 
    133             transportType = connectionConfig.getTransportType(); 
    134             enableWiFi = connectionConfig.getEnableWiFi(); 
    135         } 
    136  
    137         // Populate the bit-flags for the selected transport types 
    138         // based on the configuration parameters. 
    139         switch(transportType) { 
    140         case ConnectionConfig.TRANSPORT_WIFI_ONLY: 
    141             transports = Connection.TRANSPORT_WIFI; 
    142             break; 
    143         case ConnectionConfig.TRANSPORT_AUTO: 
    144             transports = Connection.TRANSPORT_AUTO; 
    145             break; 
    146         case ConnectionConfig.TRANSPORT_DIRECT_TCP: 
    147             transports = Connection.TRANSPORT_DIRECT_TCP; 
    148             break; 
    149         case ConnectionConfig.TRANSPORT_MDS: 
    150             transports = Connection.TRANSPORT_MDS; 
    151             break; 
    152         case ConnectionConfig.TRANSPORT_WAP2: 
    153             transports = Connection.TRANSPORT_WAP2; 
    154             break; 
    155         default: 
    156             // Should only get here in rare cases of invalid configuration 
    157             // data, so we select full automatic with WiFi. 
    158             transports = Connection.TRANSPORT_AUTO; 
    159             enableWiFi = true; 
    160             break; 
    161         } 
    162         if(enableWiFi) { transports |= Connection.TRANSPORT_WIFI; } 
    163          
    164         this.input = null; 
    165         this.output = null; 
    166         this.socket = null; 
    167     } 
    168      
    169     /** 
    170      * Opens a connection. 
    171      */ 
    172     public void open() throws IOException { 
    173         if ((input != null) || (output != null) || (socket != null)) { 
    174             close(); 
    175         } 
    176          
    177         utilFactory.addOpenConnection(this); 
    178  
    179         synchronized(socketLock) { 
    180             socket = openStreamConnection(); 
    181             if(socket == null) { 
    182                 throw new IOException(resources.getString(LogicMailResource.ERROR_UNABLE_TO_OPEN_CONNECTION)); 
    183             } 
    184              
    185             input = socket.openDataInputStream(); 
    186             output = socket.openDataOutputStream(); 
    187             localAddress = ((SocketConnection) socket).getLocalAddress(); 
    188             bytesSent = 0; 
    189             bytesReceived = 0; 
    190         } 
    191          
    192         if (EventLogger.getMinimumLevel() >= EventLogger.INFORMATION) { 
    193             String msg = "Connection established:\r\n" + "Socket: " + 
    194             socket.getClass().toString() + strCRLF + "Local address: " + 
    195             localAddress + strCRLF; 
    196             EventLogger.logEvent(AppInfo.GUID, msg.getBytes(), 
    197                     EventLogger.INFORMATION); 
    198         } 
    199     } 
    200      
    201     /** 
    202      * Open a stream connection. 
    203      * This method should encapsulate all platform-specific logic for opening 
    204      * network connections.  If the connection is successfully opened, this 
    205      * method should also call {@link #setConnectionUrl(String)} to set the 
    206      * chosen connection string. 
    207      *  
    208      * @return the stream connection 
    209      *  
    210      * @throws IOException Signals that an I/O exception has occurred. 
    211      */ 
    212     protected abstract StreamConnection openStreamConnection() throws IOException; 
    213  
    214     /** 
    215      * Sets the connection string used to open the current connection. 
    216      * 
    217      * @param connectionUrl the new connection string 
    218      */ 
    219     protected void setConnectionUrl(String connectionUrl) { 
    220         this.connectionUrl = connectionUrl; 
    221     } 
    222      
    223     /** 
    224      * Gets the connection string used to open the current connection. 
    225      * 
    226      * @return the connection string 
    227      */ 
    228     public String getConnectionUrl() { 
    229         return connectionUrl; 
     92         
     93        this.socket = socket; 
     94        this.input = socket.openDataInputStream(); 
     95        this.output = socket.openDataOutputStream(); 
     96        this.localAddress = socket.getLocalAddress(); 
     97        this.bytesSent = 0; 
     98        this.bytesReceived = 0; 
    23099    } 
    231100     
     
    233102     * Closes a connection. 
    234103     */ 
    235     public void close() throws IOException { 
     104    public void close() { 
    236105        synchronized(socketLock) { 
    237106            try { 
    238                 if (input != null) { 
    239                     input.close(); 
    240                     input = null; 
    241                 } 
     107                input.close(); 
     108                output.close(); 
     109                socket.close(); 
    242110            } catch (Exception exp) { 
     111                EventLogger.logEvent(AppInfo.GUID, 
     112                        ("Error closing connection: " + exp.getMessage()).getBytes(), 
     113                        EventLogger.WARNING); 
     114            } finally { 
    243115                input = null; 
    244             } 
    245      
    246             try { 
    247                 if (output != null) { 
    248                     output.close(); 
    249                     output = null; 
    250                 } 
    251             } catch (Exception exp) { 
    252116                output = null; 
    253             } 
    254      
    255             try { 
    256                 if (socket != null) { 
    257                     socket.close(); 
    258                     socket = null; 
    259                 } 
    260             } catch (Exception exp) { 
    261117                socket = null; 
    262118            } 
    263             setConnectionUrl(null); 
    264         } 
    265          
    266         utilFactory.removeOpenConnection(this); 
     119        } 
    267120         
    268121        EventLogger.logEvent(AppInfo.GUID, "Connection closed".getBytes(), 
     
    288141    public String getLocalAddress() { 
    289142        return localAddress; 
    290     } 
    291  
    292     /** 
    293      * Get the server name used when this connection was created 
    294      * @return Server name 
    295      */ 
    296     public String getServerName() { 
    297         return serverName; 
    298143    } 
    299144 
     
    327172 
    328173    /** 
     174     * Gets the socket used by this connection instance. 
     175     * This method should only be called by <code>NetworkConnector</code> 
     176     * for the purpose of creating new wrapped sockets. 
     177     * 
     178     * @return the connection socket 
     179     */ 
     180    SocketConnection getSocket() { 
     181        return socket; 
     182    } 
     183     
     184    /** 
     185     * Gets the input stream used by this connection instance. 
     186     * This method should only be called by <code>NetworkConnector</code> 
     187     * for the purpose of creating new wrapped sockets. 
     188     * 
     189     * @return the connection socket's input stream 
     190     */ 
     191    InputStream getInput() { 
     192        return input; 
     193    } 
     194     
     195    /** 
     196     * Gets the output stream used by this connection instance. 
     197     * This method should only be called by <code>NetworkConnector</code> 
     198     * for the purpose of creating new wrapped sockets. 
     199     * 
     200     * @return the connection socket's output stream 
     201     */ 
     202    OutputStream getOutput() { 
     203        return output; 
     204    } 
     205     
     206    /** 
    329207     * Sends a string to the server, terminating it with a CRLF. 
    330208     * No cleanup is performed, as it is expected that the string 
     
    382260     */ 
    383261    public int available() throws IOException { 
    384         if (fakeAvailable == -1) { 
    385             return input.available(); 
    386         } else { 
    387             return fakeAvailable; 
     262        synchronized(socketLock) { 
     263            if (fakeAvailable == -1) { 
     264                return input.available(); 
     265            } else { 
     266                return fakeAvailable; 
     267            } 
    388268        } 
    389269    } 
     
    401281        return receive(lineResponseTester); 
    402282    } 
    403      
    404283     
    405284    /** 
     
    471350                        EventLogger.INFORMATION); 
    472351     
    473                 try { 
    474                     close(); 
    475                 } catch (IOException e) { } 
     352                close(); 
    476353     
    477354                throw new IOException("Connection closed"); 
     
    548425        }; 
    549426    }; 
    550      
    551     /** 
    552      * Switches the underlying connection to SSL mode, as commonly done after 
    553      * sending a <tt>STARTTLS</tt> command to the server. 
    554      *  
    555      * @throws IOException Signals that an I/O exception has occurred. 
    556      */ 
    557     public void startTLS() throws IOException { 
    558         synchronized(socketLock) { 
    559             // Shortcut the method if we're already in SSL mode 
    560             if(socket instanceof TLS10Connection) { return; } 
    561              
    562             if(socket == null || connectionUrl == null) { 
    563                 throw new IOException("Connection has not been opened"); 
    564             } 
    565      
    566             try { 
    567                 TLS10Connection tlsSocket = new TLS10Connection( 
    568                         new StreamConnectionWrapper( 
    569                                 socket, 
    570                                 (DataInputStream)input, 
    571                                 (DataOutputStream)output), 
    572                                 connectionUrl, 
    573                                 true); 
    574      
    575                 socket = tlsSocket; 
    576                 input = socket.openDataInputStream(); 
    577                 output = socket.openDataOutputStream(); 
    578             } catch (IOException e) { 
    579                 EventLogger.logEvent(AppInfo.GUID, 
    580                         ("Unable to switch to TLS mode: " + e.getMessage()).getBytes(), EventLogger.ERROR); 
    581                 throw new IOException("Unable to switch to TLS mode"); 
    582             } catch (TLSException e) { 
    583                 EventLogger.logEvent(AppInfo.GUID, 
    584                         ("Unable to switch to TLS mode: " + e.getMessage()).getBytes(), EventLogger.ERROR); 
    585                 throw new IOException("Unable to switch to TLS mode"); 
    586             } 
    587         } 
    588     } 
    589  
    590     /** 
    591      * Decorator to wrap an existing stream connection so its I/O streams 
    592      * can be reopened without throwing exceptions. 
    593      */ 
    594     private static class StreamConnectionWrapper implements StreamConnection { 
    595         private StreamConnection stream; 
    596         private DataInputStream dataInputStream; 
    597         private DataOutputStream dataOutputStream; 
    598  
    599         public StreamConnectionWrapper(StreamConnection stream, DataInputStream dataInputStream, DataOutputStream dataOutputStream) { 
    600             this.stream = stream; 
    601             this.dataInputStream = dataInputStream; 
    602             this.dataOutputStream = dataOutputStream; 
    603         } 
    604  
    605         public DataInputStream openDataInputStream() throws IOException { 
    606             return dataInputStream; 
    607         } 
    608         public InputStream openInputStream() throws IOException { 
    609             return dataInputStream; 
    610         } 
    611         public void close() throws IOException { 
    612             stream.close(); 
    613         } 
    614         public DataOutputStream openDataOutputStream() throws IOException { 
    615             return dataOutputStream; 
    616         } 
    617         public OutputStream openOutputStream() throws IOException { 
    618             return dataOutputStream; 
    619         } 
    620     } 
    621427} 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/util/UtilFactory.java

    r614 r698  
    3131package org.logicprobe.LogicMail.util; 
    3232 
    33 import java.io.IOException; 
    34 import java.util.Vector; 
    35  
    3633import org.logicprobe.LogicMail.conf.ConnectionConfig; 
     34import org.logicprobe.LogicMail.conf.GlobalConfig; 
    3735 
    3836/** 
     
    5351    }; 
    5452 
    55     private Vector openConnections = new Vector(); 
    56  
    5753    /** 
    5854     * Gets the single instance of UtilFactory. 
     
    7066    } 
    7167 
    72     void addOpenConnection(Connection connection) { 
    73         synchronized (openConnections) { 
    74             if (!openConnections.contains(connection)) { 
    75                 openConnections.addElement(connection); 
    76             } 
    77         } 
    78     } 
    79      
    80     void removeOpenConnection(Connection connection) { 
    81         synchronized (openConnections) { 
    82             if (openConnections.contains(connection)) { 
    83                 openConnections.removeElement(connection); 
    84             } 
    85         } 
    86     } 
    87      
    8868    /** 
    89      * Determine whether open connections exist 
    90      * 
    91      * @return True if there are open connections 
     69     * Gets the connector used to open network connections. 
     70     *  
     71     * @return platform-specific connector instance 
    9272     */ 
    93     public boolean hasOpenConnections() { 
    94         boolean result; 
    95  
    96         synchronized (openConnections) { 
    97             result = !openConnections.isEmpty(); 
    98         } 
    99  
    100         return result; 
    101     } 
    102  
    103     /** 
    104      * Close all open connections 
    105      */ 
    106     public void closeAllConnections() { 
    107         synchronized (openConnections) { 
    108             int size = openConnections.size(); 
    109  
    110             for (int i = 0; i < size; i++) { 
    111                 try { 
    112                     ((Connection) openConnections.elementAt(i)).close(); 
    113                 } catch (IOException e) { } 
    114             } 
    115  
    116             openConnections.removeAllElements(); 
    117         } 
    118     } 
    119      
    120     /** 
    121      * Creates a new connection object. 
    122      *  
    123      * connectionConfig Configuration data for the connection 
    124      *  
    125      * @return the connection object 
    126      */ 
    127     public abstract Connection createConnection(ConnectionConfig connectionConfig); 
     73    public abstract NetworkConnector getNetworkConnector(GlobalConfig globalConfig, ConnectionConfig connectionConfig); 
    12874} 
  • trunk/LogicMail/src/org/logicprobe/LogicMail/util/UtilFactoryBB42.java

    r608 r698  
    3232 
    3333import org.logicprobe.LogicMail.conf.ConnectionConfig; 
     34import org.logicprobe.LogicMail.conf.GlobalConfig; 
    3435 
    3536public class UtilFactoryBB42 extends UtilFactory { 
     
    3839    } 
    3940     
    40     /* (non-Javadoc) 
    41      * @see org.logicprobe.LogicMail.util.UtilFactory#createConnection(org.logicprobe.LogicMail.conf.ConnectionConfig) 
    42      */ 
    43     public Connection createConnection(ConnectionConfig connectionConfig) { 
    44         return new ConnectionBB42(connectionConfig); 
     41    public NetworkConnector getNetworkConnector(GlobalConfig globalConfig, ConnectionConfig connectionConfig) { 
     42        return new NetworkConnectorBB42(globalConfig, connectionConfig); 
    4543    } 
    4644} 
Note: See TracChangeset for help on using the changeset viewer.