diff --git a/res/layout/account_setup_autoconfig.xml b/res/layout/account_setup_autoconfig.xml
index c03815d1b..20b8d7c32 100644
--- a/res/layout/account_setup_autoconfig.xml
+++ b/res/layout/account_setup_autoconfig.xml
@@ -1,65 +1,76 @@
-
+ android:layout_width="fill_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
-
+
+
+ android:textSize="10dp"
+ android:paddingBottom="6dip" />
+
-
+
+
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentLeft="true"
+ android:gravity="center"
+ android:orientation="horizontal" >
-
+ android:text="@string/cancel_action" />
-
-
-
-
+ android:drawableRight="@drawable/button_indicator_next"
+ android:text="@string/next_action" />
+
-
-
+
-
-
-
-
+
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a6c165251..e43381a68 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -384,6 +384,8 @@ http://k9mail.googlecode.com/
failed!
No were settings found, use manual configuration to continue.
Searching other places for configuration settings...
+ Checking for DNS redirects...
+ Retrying autoconfiguration for a new domain.
You\'re almost done!
Your account is set up, and mail is on its way!
diff --git a/src/com/fsck/k9/activity/setup/AccountSetupAutoConfiguration.java b/src/com/fsck/k9/activity/setup/AccountSetupAutoConfiguration.java
index 86345bf74..fb81ebca8 100644
--- a/src/com/fsck/k9/activity/setup/AccountSetupAutoConfiguration.java
+++ b/src/com/fsck/k9/activity/setup/AccountSetupAutoConfiguration.java
@@ -1,11 +1,8 @@
package com.fsck.k9.activity.setup;
import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
import android.content.Intent;
import android.os.*;
-import android.os.Process;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@@ -17,8 +14,13 @@ import com.fsck.k9.activity.K9Activity;
import com.fsck.k9.helper.configxmlparser.AutoconfigInfo;
import com.fsck.k9.helper.configxmlparser.ConfigurationXMLHandler;
import com.fsck.k9.mail.store.TrustManagerFactory;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.util.EntityUtils;
import org.xml.sax.InputSource;
-import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
@@ -27,11 +29,9 @@ import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import java.io.*;
import java.net.*;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.concurrent.TimeoutException;
+import java.util.List;
/**
* User: dzan
@@ -49,6 +49,7 @@ public class AccountSetupAutoConfiguration extends K9Activity implements View.On
// location of mozilla's ispdb
private String databaseBaseUrl = "https://live.mozillamessaging.com/autoconfig/v1.1/";
+ private String dnsMXLookupUrl = "https://live.mozillamessaging.com/dns/mx/";
// for now there are only 2 so I just hardcode them here
// also note: order they are listed is the order they'll be checked
@@ -134,129 +135,16 @@ public class AccountSetupAutoConfiguration extends K9Activity implements View.On
mPassword = getIntent().getStringExtra(PASSWORD);
mMakeDefault = getIntent().getBooleanExtra(MAKEDEFAULT, false);
+ // inform user we start autoconfig
+ setMessage(R.string.account_setup_autoconfig_info, true);
+
+ // divide the address
+ String[] emailParts = splitEmail(mEmailAddress);
+ String user = emailParts[0];
+ String domain = emailParts[1];
+
// The real action, in a separate thread
- new Thread() {
- @Override
- public void run() {
- android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
- // declare some variables
- String data = ""; // used to store downloaded xml before parsing
- String tmpURL = "";
-
- // notify the user we'll get started
- setMessage(R.string.account_setup_autoconfig_info, true);
-
- // divide the address
- String[] emailParts = splitEmail(mEmailAddress);
- String user = emailParts[0];
- String domain = emailParts[1];
-
- /*
- Check if configuration data exists and if it does read in
- */
- int i = 0;
- while( i < urlTemplates.size() && !bFound ){
- try{
- // inform the user
- setMessage(urlInfoStatements.get(i),true);
-
- // to make sure
- bParseFailed = false;
- bForceManual = false;
- bDoneSearching = false;
-
- // preparing the urls
- if( !domain.contains("%user%") ){ // else SHIT
- tmpURL = urlTemplates.get(i).replaceAll("%domain%",domain);
- tmpURL = tmpURL.replaceAll("%address%",mEmailAddress);
- }
-
- data = getXMLData(new URL(tmpURL));
-
- // might be the user cancelled by now or the app was destroyed
- if (mDestroyed) return;
- if (mCanceled) { finish(); return; }
-
- if( !data.isEmpty() ){
- setMessage(R.string.account_setup_autoconfig_found,false);
-
- // parse and finish
- setMessage(R.string.account_setup_autoconfig_processing,true);
- parse(data);
- setMessage(R.string.account_setup_autoconfig_succesful,false);
-
- // alert user these settings might be tampered with!!! ( no https )
- if( i >= UNSAFE_URL_START ) bUnsafe = true;
-
- bFound = true;
- continue;
- }
-
- }catch (SocketTimeoutException ex){
- Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '"+
- tmpURL+"' ( time-out is"+TIMEOUT+" )", ex);
- }catch (MalformedURLException ex){
- Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '"+
- tmpURL+"'", ex);
- }catch (UnknownHostException ex){
- Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '"+
- tmpURL+"'", ex);
- }catch (SSLPeerUnverifiedException ex){
- Log.e(K9.LOG_TAG, "Error while testing settings", ex);
- acceptKeyDialog(R.string.account_setup_failed_dlg_certificate_message_fmt,i,ex);
- }catch (SAXException e) {
- setMessage(R.string.account_setup_autoconfig_fail,false);
- bParseFailed = true;
- }catch (ParserConfigurationException e) {
- setMessage(R.string.account_setup_autoconfig_fail,false);
- bParseFailed = true;
- }catch (ErrorCodeException ex) {
- Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '" +
- tmpURL + "' site didn't respond as expected. Got code: " + ex.getErrorCode(), ex);
- }catch(IOException ex) {
- Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '"+
- tmpURL+"'", ex);
- } finally {
- // might be the user cancelled by now or the app was destroyed
- if (mDestroyed) return;
- if (mCanceled) { finish(); return; }
-
- // check next url
- ++i;
-
- // this was the last option..
- if(i == urlTemplates.size() ){
- bForceManual = true;
- setMessage(R.string.account_setup_autoconfig_forcemanual, true);
- }else{
- if( bParseFailed )
- setMessage(R.string.account_setup_autoconfig_trynext,true);
- }
- }
-
- // no server-side config was found
- closeUserInformationIfNeeded(i-1);
- }
-
- bDoneSearching = true;
- runOnUiThread(new Runnable() {
- public void run() {
- // TODO: set appropriate warning messages in here
- // 1. All good, continue
- // 2. Nothing came up, must manually config.. + help?
- // 3. Data did not came over HTTPS this could be UNSAFE !!!!!!
- mProgressCircle.setVisibility(View.INVISIBLE);
- if( bUnsafe /*&& !bForceManual*/ ) mWarningMsg.setVisibility(View.VISIBLE);
- mNextButton.setEnabled(true);
- if( bForceManual )
- mNextButton.setText(getString(R.string.account_setup_basics_manual_setup_action));
- }
- });
-
- }
- }
- .start();
+ new AutoConfigurationThread(domain).start();
}
@@ -272,6 +160,7 @@ public class AccountSetupAutoConfiguration extends K9Activity implements View.On
mAutoConfigInfo = parser.getAutoconfigInfo();
}
+
/*
Checks if an url is available / exists
*/
@@ -300,12 +189,83 @@ public class AccountSetupAutoConfiguration extends K9Activity implements View.On
}
catch (SocketTimeoutException ex)
{ throw ex; }
+ catch (ConnectException ex){
+ // ignore this, it just means the url doesn't exist which happens often, we test for it!
+ }
finally
{ conn.disconnect(); }
return tmp;
}
+
+ /*
+ * Does an DNS MX lookup of the domain and returns a list of records.
+ * This uses the Mozilla webservice to do so.
+ */
+ private List doMXLookup(String domain) throws IOException{
+ HttpClient httpclient = new DefaultHttpClient();
+ HttpGet method = new HttpGet(dnsMXLookupUrl + domain);
+
+ // do request
+ HttpResponse response = httpclient.execute(method);
+ String data = EntityUtils.toString(response.getEntity());
+ return new ArrayList(Arrays.asList(data.split("[\\r\\n]+")));
+ }
+
+
+ /*
+ * Does two things:
+ * 1. Detect the isp-domain parts of the mxServer hostnames
+ * 2. Filters these so we have a list of uniques also not containing the initial domainname used for mx lookup
+ *
+ * TODO:
+ * Speed this up! There are a lot of options...
+ * Use a Set instead of a list, don't rebuild tmpStr every time,...
+ */
+ private List getDomainPossibilities(List mxServers, String origDomain){
+ List filteredDomains = new ArrayList();
+ String[] serverSplit;
+ String tmpStr, prevAtom;
+ int size = 0; // total atoms in server hostname
+ // number of atoms in last found domain
+ int parts = 2; // to begin with, minimum so never arrayoutofbound
+
+ for( String server : mxServers )
+ {
+ serverSplit = server.toLowerCase().split("\\.");
+ prevAtom = serverSplit[0];
+
+ // speed things up a bit ( ugly )
+ size = serverSplit.length;
+ tmpStr = "";
+ for( int k=size-1; k>(size-parts-1); --k) tmpStr += "."+serverSplit[k];
+ tmpStr = tmpStr.substring(1);
+ if( filteredDomains.contains(tmpStr)) continue;
+
+ // determine right domainname
+ for( int i = 1; i < serverSplit.length; ++i ){
+ // build domainstring to test
+ tmpStr = "";
+ for( int j=i; j mDomainAlternatives;
+
+ public AutoConfigurationThread(String domain) {
+ super();
+ this.mDomain = domain;
+ }
+
+ @Override
+ public void run() {
+ //android.os.Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+
+ // declare some variables
+ String data = ""; // used to store downloaded xml before parsing
+ String tmpURL = "";
+
+ int templateIndex = 0;
+ while( templateIndex < urlTemplates.size() && !bFound ){
+ try{
+ // inform the user
+ setMessage(urlInfoStatements.get(templateIndex),true);
+
+ // to make sure
+ bParseFailed = false;
+ bForceManual = false;
+ bDoneSearching = false;
+
+ // preparing the urls
+ if( !mDomain.contains("%user%") ){ // else SHIT
+ tmpURL = urlTemplates.get(templateIndex).replaceAll("%domain%",mDomain);
+ tmpURL = tmpURL.replaceAll("%address%",mEmailAddress);
+ }
+
+ // get the xml data
+ data = getXMLData(new URL(tmpURL));
+
+ // might be the user cancelled by now or the app was destroyed
+ if (mDestroyed) return;
+ if (mCanceled) { finish(); return; }
+
+ // if we really have data
+ if( !data.isEmpty() ){
+ setMessage(R.string.account_setup_autoconfig_found,false);
+
+ // parse and finish
+ setMessage(R.string.account_setup_autoconfig_processing,true);
+ parse(data);
+ setMessage(R.string.account_setup_autoconfig_succesful,false);
+
+ // alert user these settings might be tampered with!!! ( no https )
+ if( templateIndex >= UNSAFE_URL_START ) bUnsafe = true;
+
+ bFound = true;
+ continue;
+ }
+
+ }catch (SocketTimeoutException ex){
+ Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '"+
+ tmpURL+"' ( time-out is"+TIMEOUT+" )", ex);
+ }catch (MalformedURLException ex){
+ Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '"+
+ tmpURL+"'", ex);
+ }catch (UnknownHostException ex){
+ Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '"+
+ tmpURL+"'", ex);
+ }catch (SSLPeerUnverifiedException ex){
+ Log.e(K9.LOG_TAG, "Error while testing settings", ex);
+ // TODO: use custom trust manager so this exception could get thrown
+ //acceptKeyDialog(R.string.account_setup_failed_dlg_certificate_message_fmt,i,ex);
+ }catch (SAXException e) {
+ setMessage(R.string.account_setup_autoconfig_fail,false);
+ bParseFailed = true;
+ }catch (ParserConfigurationException e) {
+ setMessage(R.string.account_setup_autoconfig_fail,false);
+ bParseFailed = true;
+ }catch (ErrorCodeException ex) {
+ Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '" +
+ tmpURL + "' site didn't respond as expected. Got code: " + ex.getErrorCode(), ex);
+ }catch(IOException ex) {
+ Log.e(K9.LOG_TAG, "Error while attempting auto-configuration with url '"+
+ tmpURL+"'", ex);
+ } finally {
+ // might be the user cancelled by now or the app was destroyed
+ if (mDestroyed) return;
+ if (mCanceled) { finish(); return; }
+
+ // check next url
+ ++templateIndex;
+
+ if( !bFound ) closeUserInformationIfNeeded(templateIndex-1);
+
+ // did parsing fail? tell user
+ if( bParseFailed )
+ setMessage(R.string.account_setup_autoconfig_trynext,true);
+
+ // this is the last domain to try in the list
+ if( templateIndex == urlTemplates.size()){
+ // we can still try DNS MX
+ if( mDomainAlternatives == null ){
+ try {
+ setMessage(R.string.account_setup_autoconfig_trydns, true);
+ mDomainAlternatives = getDomainPossibilities(doMXLookup(mDomain), mDomain);
+ if( mDomainAlternatives.size() > 0 )
+ setMessage(R.string.account_setup_autoconfig_found, false);
+ else
+ setMessage(R.string.account_setup_autoconfig_missing, false);
+ } catch (IOException e) {
+ mDomainAlternatives = new ArrayList(); // setting empty list = no options left
+ setMessage(R.string.account_setup_autoconfig_missing, false);
+ Log.e(K9.LOG_TAG, "Error while getting DNS MX data in autoconfiguration", e);
+ }
+ }
+
+ // still domains remaining to try, restart whole lookup with new domain
+ if( mDomainAlternatives.size() > 0 ){
+ mDomain = mDomainAlternatives.get(0);
+ mDomainAlternatives.remove(0);
+ templateIndex = 0;
+ setMessage(R.string.account_setup_autoconfig_new_domain, true);
+ // out of options... manual configuration
+ }else{
+ bForceManual = true;
+ setMessage(R.string.account_setup_autoconfig_forcemanual, true);
+ }
+
+ }
+ }
+ }
+
+ // remember we've searched already
+ bDoneSearching = true;
+
+ // update ui state
+ runOnUiThread(new Runnable() {
+ public void run() {
+ // hide progress circle & enable button for any case
+ mProgressCircle.setVisibility(View.INVISIBLE);
+ mNextButton.setEnabled(true);
+
+ // 1. All good, continue
+ // all is fine
+
+ // 2. Nothing came up, must manually config.. + help?
+ if( bForceManual ) mNextButton.setText(getString(R.string.account_setup_basics_manual_setup_action));
+
+ // 3. Data did not came over HTTPS this could be UNSAFE !!!!!!
+ if( bUnsafe ) mWarningMsg.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+ }
+
/*
Small custom exception to pass http response codes around
*/