package net.bradmont.openmpd.controllers; import net.bradmont.openmpd.models.*; import net.bradmont.openmpd.*; import net.bradmont.supergreen.models.ModelList; import org.apache.http.*; import org.apache.http.auth.*; import org.apache.http.client.methods.*; import org.apache.http.impl.client.*; import org.apache.http.client.entity.*; import org.apache.http.message.*; import org.apache.http.conn.HttpHostConnectException; import org.apache.http.impl.conn.SingleClientConnManager; import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; import javax.net.ssl.TrustManager; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.ClientConnectionManager; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; import java.lang.StackTraceElement; import java.lang.Thread; import java.io.IOException; import java.io.StringReader; import java.math.BigDecimal; import java.net.Socket; import java.net.UnknownHostException; import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.params.HttpProtocolParams; import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; import org.apache.http.protocol.HTTP; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.SharedPreferences; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.widget.ProgressBar; import net.bradmont.openmpd.helpers.Log; import android.support.v4.app.NotificationCompat; import android.support.v4.app.TaskStackBuilder; import java.lang.StringBuffer; import java.lang.Runnable; import java.lang.RuntimeException; import java.lang.Thread; import java.net.URL; import java.text.DateFormat; import java.text.DecimalFormat; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Vector; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PrintWriter; import java.io.StringWriter; import java.io.BufferedReader; import net.bradmont.openmpd.activities.ImportActivity; import org.ini4j.Ini; /** Controller to connect to and import data from TntDataServer instances. * */ public class TntImporter { private ProgressBar progressbar=null; private NotificationCompat.Builder builder = null; private NotificationManager notifyManager = null; private Context context; private HashMap<String, String> data ; // Initialize this HashMap only once to save time private ServiceAccount account; private TntService service = null; private int progress = 0; private int progressmax=0; private static int notification_id=ContactsEvaluator.NOTIFICATION_ID; private static String EPOCH_DATE="01/01/1970"; public TntImporter(Context context, ServiceAccount account){ this.context = context; this.account = account; service = (TntService) account.getRelated("tnt_service_id"); } public TntImporter(Context context, ServiceAccount account, ProgressBar progressbar){ this.context = context; this.account = account; service = (TntService) account.getRelated("tnt_service_id"); this.progressbar = progressbar; } public TntImporter(Context context, ServiceAccount account, NotificationCompat.Builder builder){ this.context = context; this.account = account; service = (TntService) account.getRelated("tnt_service_id"); this.builder = builder; notifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); //notification_id = account.getID(); } public boolean run() throws Exception{ if (progressbar != null){ progressbar.setIndeterminate(true); } if (builder != null){ builder.setProgress(progressmax, progress, true); notifyManager.notify(notification_id, builder.build()); } try { Thread.sleep(500); // we tend to get to this point before the accounts listview // on the importing screen gets populated, so the progress bar // for the first account doesn't get set to indeterminate, // leaving the user thinking the app has hung. Hackish workaround, // but it does the job. } catch(Exception ex) { } ImportActivity.setProgress(account.getID(), progressmax, progress, true); // upgrade from legacy tnt_service to using query.ini properly if (service.getUsernameKey() == null || service.getUsernameKey().length() < 2){ processQueryIni(service); service.dirtySave(); } if (getContacts() == false){ return false; } if (progressbar != null){ progressbar.setIndeterminate(false); } if (builder != null){ builder.setProgress(progressmax, progress, false); notifyManager.notify(notification_id, builder.build()); } ImportActivity.setProgress(account.getID(), progressmax, progress, false); if (getGifts() == false){ return false; } account.setValue("last_import", getTodaysDate()); account.dirtySave(); return true; } public boolean getContacts(){ ArrayList<BasicNameValuePair> arguments = new ArrayList<BasicNameValuePair>(4); if (builder != null){ builder.setContentTitle("Importing Contacts"); builder.setProgress(2, 3, true); notifyManager.notify(notification_id, builder.build()); } ImportActivity.setProgress(account.getID(), 2, 3, true); ImportActivity.setStatus(account.getID(), R.string.importing_contacts); arguments.add(new BasicNameValuePair( "Action", service.getAddressesAction())); arguments.add(new BasicNameValuePair( service.getUsernameKey(), account.getString("username"))); arguments.add(new BasicNameValuePair( service.getPasswordKey(), account.getString("password"))); // Always download contacts from all time, since TNTDataService only // gives donor info for donors who are new TO THE ORGANISATION, // not new to the user. So if I gain a new supporter who has // already given to someone else, they will not show up in my donor // query unless we query from before their most recent address // change. Annoying, but donor import is much faster than gift // import, so it doesn't really cause much of a slow-down. arguments.add(new BasicNameValuePair( "DateFrom", EPOCH_DATE)); ArrayList<String> content = null; try { content = getStringsFromUrl(service.getString("base_url") + service.getString("addresses_url"), arguments); } catch (ServerException e){ return false; } if (content == null){ return false; } String header_line = content.remove(0); // p2c's server pads the header line with some fugly non-ascii // characters; strip out anything like that header_line = header_line.replaceAll("[^\\w,]", ""); String [] headers = header_line.split(","); data = new HashMap<String, String>(headers.length); if (progressbar != null){ progressbar.setIndeterminate(false); progressbar.setMax(content.size()*2); } if (builder != null){ progressmax = content.size(); builder.setProgress(progressmax, progress, false); notifyManager.notify(notification_id, builder.build()); } ImportActivity.setProgress(account.getID(), progressmax, progress, false); Contact temp = new Contact(); Contact.beginTransaction(); for(String s:content){ //Log.i(Config.PACKAGE, s); progress++; try{ parseAddressLine(headers, s); } catch (Exception e){ LogItem.logError(header_line, s, e); } if (progressbar != null){ progressbar.incrementProgressBy(1); } if (builder != null){ builder.setProgress(progressmax, progress, false); notifyManager.notify(notification_id, builder.build()); if (progress % 1000 == 0){ Contact.endTransaction(); Contact.beginTransaction(); } } ImportActivity.setProgress(account.getID(), progressmax, progress, false); } // clean up orphaned contacts Cursor cc = MPDDBHelper.get().getWritableDatabase().rawQuery( "select * from contact a left outer join contact b "+ "on a.spouse_id = b._id where a.spouse_id > 0 and b._id is null", null); cc.moveToFirst(); while (!cc.isAfterLast()){ int id = cc.getInt(0); MPDDBHelper.get().getWritableDatabase().delete("contact", "_id = ?", new String [] { Integer.toString(id) }); cc.moveToNext(); } Contact.endTransaction(); cc.close(); return true; } public boolean getGifts(){ if (builder != null){ builder.setContentTitle("Importing Gifts"); builder.setProgress(progressmax, progress, true); notifyManager.notify(notification_id, builder.build()); } ImportActivity.setProgress(account.getID(), progressmax, progress, true); ImportActivity.setStatus(account.getID(), R.string.importing_gifts); ArrayList<BasicNameValuePair> arguments = new ArrayList<BasicNameValuePair>(4); arguments.add(new BasicNameValuePair( "Action", service.getDonationsAction())); arguments.add(new BasicNameValuePair( service.getUsernameKey(), account.getString("username"))); arguments.add(new BasicNameValuePair( service.getPasswordKey(), account.getString("password"))); if (account.getString("last_import") == null){ arguments.add(new BasicNameValuePair( "DateFrom", EPOCH_DATE)); } else { Calendar cal = account.getCalendar("last_import"); cal.add(Calendar.DAY_OF_MONTH, -14); // gifts can take a while to // appear in the system DateFormat format = new SimpleDateFormat("MM/dd/yyyy"); arguments.add(new BasicNameValuePair( "DateFrom", format.format(cal.getTime()) )); } arguments.add(new BasicNameValuePair( "DateTo", stupidDateFormat(getTodaysDate()))); ArrayList<String> content = null; try { content = getStringsFromUrl(service.getString("base_url") + service.getString("donations_url"), arguments); } catch (ServerException e){ return false; } if (content == null){ return false; } if (content.size() == 1 ){ // no data; consider update accomplished return true; } String header_line = content.remove(0); header_line = header_line.replaceAll("[^\\w,]", ""); String [] headers = header_line.split(","); data = new HashMap<String, String>(headers.length); if (progressbar != null){ progressbar.setMax((progressbar.getMax()/2) + content.size()); } progressmax = content.size(); progress = 0; if (builder != null){ builder.setProgress(progressmax, progress, false); notifyManager.notify(notification_id, builder.build()); } ImportActivity.setProgress(account.getID(), progressmax, progress, false); Gift temp = new Gift(); Gift.beginTransaction(); for(String s:content){ try { parseGiftLine(headers, s); } catch (Exception e){ LogItem.logError(header_line, s, e); } if (progressbar != null){ progressbar.incrementProgressBy(1); } if (builder != null){ builder.setProgress(progressmax, ++progress, false); notifyManager.notify(notification_id, builder.build()); } ImportActivity.setProgress(account.getID(), progressmax, progress, false); if (progress % 1000 == 0){ Gift.endTransaction(); Gift.beginTransaction(); } } Gift.endTransaction(); ImportActivity.setStatus(account.getID(), R.string.done); return true; } /** Takes an ISO 8601 date string and converts it to a MM/DD/YYYY string, * as required by TntDataServer. */ public String stupidDateFormat(String date){ String [] parts = date.split("-"); return String.format("%s/%s/%s", parts[1], parts[2], parts[0]); } /** Returns today's date in ISO 8601 format */ public static String getTodaysDate(){ DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Calendar cal = Calendar.getInstance(); return dateFormat.format(cal.getTime()); } public void parseGiftLine(String [] headers, String line){ String [] values = csvLineSplit(line); for (int i=0; i < headers.length; i++){ data.put(headers[i], values[i]); //Log.i("net.bradmont.openmpd", "" + headers[i] + ":'" + values[i]+"'"); } // if this gift has already been imported, skip it. ModelList gifts = MPDDBHelper.filter("gift", "tnt_donation_id", data.get("DONATION_ID")); if (gifts.size() != 0){ return; } Gift gift = new Gift(); String date = data.get("DISPLAY_DATE"); String [] dateParts = date.split("/"); date = String.format("%04d-%02d-%02d", Integer.parseInt(dateParts[2]), Integer.parseInt(dateParts[0]), Integer.parseInt(dateParts[1])); String month = String.format("%04d-%02d", Integer.parseInt(dateParts[2]), Integer.parseInt(dateParts[0])); gift.setValue("tnt_people_id", data.get("PEOPLE_ID")); gift.setValue("date", date); gift.setValue("month", month); gift.setValue("amount", data.get("AMOUNT")); gift.setValue("motivation_code", data.get("MOTIVATION")); gift.setValue("account", data.get("DESIGNATION")); gift.setValue("tnt_donation_id", data.get("DONATION_ID")); gift.dirtySave(); } public void parseAddressLine(String [] headers, String line){ String [] values = csvLineSplit(line); for (int i=0; i < headers.length; i++){ data.put(headers[i], values[i]); } ModelList contacts = MPDDBHelper.filter("contact", "tnt_people_id", data.get("PEOPLE_ID")); Contact contact; if (contacts.size() != 0){ contact = (Contact) contacts.get(0); } else { contact = new Contact(); } contact.setValue("tnt_people_id", data.get("PEOPLE_ID")); contact.setValue("tnt_account_name", data.get("ACCT_NAME")); contact.setValue("tnt_person_type", data.get("PERSON_TYPE")); contact.setValue("lname", data.get("LAST_NAME_ORG")); contact.setValue("fname", data.get("FIRST_NAME")); contact.setValue("mname", data.get("MIDDLE_NAME")); contact.setValue("title", data.get("TITLE")); contact.setValue("suffix", data.get("SUFFIX")); contact.setValue("account", account); if (contact.getString("fname") != "" || contact.getString("lname") != ""){ contact.dirtySave(); } if (data.get("SP_FIRST_NAME") != null && data.get("SP_FIRST_NAME").length() > 1){ Contact spouse = null; if (contacts.size() != 0){ try { spouse = (Contact) contact.getRelated("spouse"); } catch (Exception e){ spouse = new Contact(); } } else { spouse = new Contact(); } // create spouse object spouse.setValue("tnt_people_id", "-" + data.get("PEOPLE_ID")); // kind of silly to set a negative people_id, but this // allows us to make the field unique and still support // married people as individual contacts spouse.setValue("tnt_account_name", data.get("ACCT_NAME")); spouse.setValue("tnt_person_type", data.get("PERSON_TYPE")); spouse.setValue("lname", data.get("SP_LAST_NAME")); spouse.setValue("fname", data.get("SP_FIRST_NAME")); spouse.setValue("mname", data.get("SP_MIDDLE_NAME")); spouse.setValue("title", data.get("SP_TITLE")); spouse.setValue("suffix", data.get("SP_SUFFIX")); spouse.setValue("primary_contact", false); spouse.setValue("spouse", contact); spouse.setValue("account", account); if ((spouse.getString("fname") != "" && spouse.getString("fname") != null ) || (spouse.getString("lname") != "" && spouse.getString("lname") != null)){ spouse.dirtySave(); contact.setValue("spouse", spouse); } else { contact.setValue("spouse_id", 0); spouse.delete(); } if (contact.getString("fname") != "" || contact.getString("lname") != ""){ contact.dirtySave(); } } Address address = null; PhoneNumber phone = null; EmailAddress email = null; if (contacts.size() == 0){ address = new Address(); phone = new PhoneNumber(); email = new EmailAddress(); } else { address = contact.getAddress(); phone = contact.getPhone(); email = contact.getEmail(); } if (address != null && (address.getString("valid_from") == null || !address.getString("valid_from").equals(data.get("ADDR_CHANGED")) ) ){ // TODO: evaluate if address has changed. address.setValue("addr1", data.get("ADDR1")); address.setValue("addr2", data.get("ADDR2")); address.setValue("addr3", data.get("ADDR3")); address.setValue("addr4", data.get("ADDR4")); address.setValue("city", data.get("CITY")); address.setValue("region", data.get("STATE")); address.setValue("post_code", data.get("ZIP")); address.setValue("country_short", data.get("COUNTRY")); address.setValue("country_long", data.get("COUNTRY_DESCR")); // TODO: address.setValue("valid_from", data.get("ADDR_CHANGED")); //address.setValue("deliverable", data.get("ADDR_DELIVERABLE")); address.setValue("contact_id", contact); address.dirtySave(); } if (phone != null && ( phone.getString("added_date") == null || !phone.getString("added_date").equals(data.get("PHONE_CHANGED"))) ){ phone.setValue("number", data.get("PHONE")); phone.setValue("added_date", data.get("PHONE_CHANGED")); //phone.setValue("operational", data.get("PHONE_OPERATIONAL")); phone.setValue("label", "Default"); phone.setValue("contact_id", contact); phone.dirtySave(); } if (phone != null && (email.getString("added_date") == null || !email.getString("added_date").equals(data.get("EMAIL_CHANGED"))) ){ email.setValue("address", data.get("EMAIL")); email.setValue("added_date", data.get("EMAIL_CHANGED")); //email.setValue("operational", data.get("EMAIL_OPERATIONAL")); email.setValue("label", "Default"); email.setValue("contact_id", contact); email.dirtySave(); } } /** Split a line of CSV data into a string array * */ public static String [] csvLineSplit(String line){ Vector<String> result = new Vector<String>(); StringBuffer element = new StringBuffer(); if (line==null){ return null;} boolean inQuotes=false; for (int i=0; i < line.length(); i++){ char ch = line.charAt(i); if (ch == ','){ if (inQuotes){ element.append(ch); } else { result.add(element.toString()); element = new StringBuffer(); } } else if (ch == '\"'){ inQuotes = inQuotes?false:true; } else { element.append(ch); } } result.add(element.toString()); String [] return_value = new String[result.size()]; return_value = result.toArray(return_value); return return_value; } public ArrayList<String> getStringsFromUrl(String url, ArrayList arguments) throws ServerException{ return getStringsFromUrl(url, arguments, true); } public ArrayList<String> getStringsFromUrl(String url_raw, ArrayList arguments, boolean handleCertError) throws ServerException{ URL url = null; try { url = new URL(url_raw); } catch (Exception e){ return null; } if (builder != null){ builder.setContentText(url.getHost()); notifyManager.notify(notification_id, builder.build()); } InputStream stream = getStreamFromUrl(url_raw, arguments, handleCertError, builder, notifyManager, account.getID()); if (stream == null){ return null; } BufferedReader rd = new BufferedReader( new InputStreamReader(stream), 4096); String line; ArrayList<String> lines = new ArrayList<String>(50); try{ while ((line = rd.readLine()) != null) { lines.add(line); //Log.i("net.bradmont.openmpd", line); } rd.close(); //Log.i("net.bradmont.openmpd", "finished reading"); } catch (Exception e){ StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); Log.i("net.bradmont.openmpd.controllers.TntImporter",sw.toString()); } Log.i("net.bradmont.openmpd", String.format("returning %d lines", lines.size())); /*for (String l : lines){ Log.i("net.bradmont.openmpd", l); }*/ if (lines == null || lines.get(0).contains("ERROR") || lines.get(0).contains("BAD_PASSWORD")){ // TODO: we may need to detect other errors here.... String error = ""; for (String s : lines){ error += s; } throw new ServerException(error); } return lines; } public class ServerException extends Exception{ public ServerException() { super(); } public ServerException(String message) { super(message); } public ServerException(String message, Throwable cause) { super(message, cause); } public ServerException(Throwable cause) { super(cause); } } /** * Check if the account login is valid */ public boolean verifyAccount(){ processQueryIni(service); try { getBalance(); } catch (ServerException e){ Log.i("net.bradmont.openmpd", "server error"); return false; } catch (RuntimeException e){ Log.i("net.bradmont.openmpd", "runtime exception"); URL u = null; Log.i("net.bradmont.openmpd", "url"); try { u = new URL(service.getString("base_url") + service.getString("balance_url")); } catch (Exception f){ Log.i("net.bradmont.openmpd", "url exception"); Log.i("net.bradmont.openmpd", f.toString()); } if (u.getHost().contains("focus.powertochange.org") || u.getHost().contains("tntmpd.powertochange.org")){ Log.i("net.bradmont.openmpd", "setting ignore ssl for p2c"); SharedPreferences.Editor prefs = OpenMPD.get().getSharedPreferences("openmpd", Context.MODE_PRIVATE).edit(); prefs.putBoolean("ignore_ssl_" + u.getHost(), true); prefs.commit(); try { Log.i("net.bradmont.openmpd", "recalling getBalance"); getBalance(); } catch (Exception f){ return false; } } else { Log.i("net.bradmont.openmpd", "unexpected RuntimeException"); for (StackTraceElement l : e.getStackTrace()){ Log.i("net.bradmont.openmpd", l.toString()); } throw e; } } return true; } /** * returns account balance in cents */ public int getBalance() throws ServerException{ ArrayList<BasicNameValuePair> arguments = new ArrayList<BasicNameValuePair>(4); arguments.add(new BasicNameValuePair( "Action", service.getBalanceAction())); arguments.add(new BasicNameValuePair( service.getUsernameKey(), account.getString("username"))); arguments.add(new BasicNameValuePair( service.getPasswordKey(), account.getString("password"))); ArrayList<String> content = null; content = getStringsFromUrl(service.getString("base_url") + service.getString("balance_url"), arguments, false); if (content.size() == 1){ // Query was succesful, but no result returned // this happens, eg, for CRU US accounts that redirect funds to // an international ministry return 0; } String [] headers = csvLineSplit(content.get(0)); String [] values = csvLineSplit(content.get(1)); for (int i = 0; i < headers.length; i++){ if (headers[i].equals("BALANCE")){ DecimalFormat format = new DecimalFormat(); format.setParseBigDecimal(true); BigDecimal balance = null; try { balance = (BigDecimal) format.parse(values[i]); } catch (Exception e){ Log.i("net.bradmont.openmpd", "Invalid balance format: " + values[i]); return 0; } balance = balance.multiply(new BigDecimal(100)); return balance.intValue(); } } return 0; } private static StringReader getCleanedStringReaderFromUrl(String url){ try { InputStream stream = getStreamFromUrl(url, null, false); if (stream == null) { return null; } StringBuilder sb = new StringBuilder(); int character = 0; boolean started = false; // read and chop off non-ascii gunk at the beginning character = stream.read(); while (character != -1){ if ( (char) character == '['){ started=true; } if (started){ sb.append( (char) character); } character = stream.read(); } stream.close(); return new StringReader(sb.toString()); } catch (IOException e){ StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); Log.i("net.bradmont.openmpd",sw.toString()); return null; } } public static InputStream getStreamFromUrl(String url_raw, ArrayList arguments, boolean handleCertError){ return getStreamFromUrl(url_raw, arguments, handleCertError, null, null, -1); } public static InputStream getStreamFromUrl(String url_raw, ArrayList arguments, boolean handleCertError, NotificationCompat.Builder builder, NotificationManager notifyManager, int accountId){ InputStream content = null; URL url = null; try { url = new URL(url_raw); } catch (Exception e){ return null; } try { DefaultHttpClient httpclient = null; SharedPreferences prefs = OpenMPD.get().getSharedPreferences("openmpd", Context.MODE_PRIVATE); if (prefs.getBoolean("ignore_ssl_" + url.getHost(), false) == true){ httpclient = getNewHttpClient(); } else { httpclient = new DefaultHttpClient(); } HttpHost targetHost; if (url.getProtocol() == "https"){ targetHost = new HttpHost(url.getHost(), 443, url.getProtocol()); } else if (url.getProtocol() == "http"){ targetHost = new HttpHost(url.getHost(), 80, url.getProtocol()); } else { targetHost = new HttpHost(url.getHost(), 443, url.getProtocol()); } HttpUriRequest httpRequest = null; if (arguments != null){ HttpPost httpPost = new HttpPost(url_raw); httpPost.setEntity(new UrlEncodedFormEntity(arguments)); httpclient.getCredentialsProvider().setCredentials( new AuthScope(targetHost.getHostName(), targetHost.getPort()), new UsernamePasswordCredentials( ((BasicNameValuePair) arguments.get(1)).getValue(), // username ((BasicNameValuePair) arguments.get(2)).getValue() )); httpRequest = httpPost; } else { httpRequest = new HttpGet(url_raw); } // Execute HTTP Post Request HttpResponse response = httpclient.execute(httpRequest); content = response.getEntity().getContent(); return content; } catch (org.apache.http.conn.HttpHostConnectException e){ if (builder != null){ builder.setProgress(0, 0, false); builder.setContentTitle("Error connecting to server."); notifyManager.notify(notification_id, builder.build()); } ImportActivity.setProgress(accountId, 0, 0, false); ImportActivity.setStatus(accountId, R.string.error_connecting_to_server); } catch (javax.net.ssl.SSLPeerUnverifiedException e){ // SSL certs on the server are not accepted if (handleCertError == false){ throw new RuntimeException("SSLError Certificate not accepted"); } NotificationManager notificationManager = (NotificationManager) OpenMPD.get().getSystemService(Context.NOTIFICATION_SERVICE); NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(OpenMPD.get()) .setSmallIcon(R.drawable.notification_icon); nBuilder.setContentTitle("SSL Certificate Error"); nBuilder.setContentText(url.getHost()); ImportActivity.setStatus(accountId, R.string.ssl_certificate_error); Intent sslCertIntent = new Intent(OpenMPD.get(), HomeActivity.class); sslCertIntent.putExtra("net.bradmont.openmpd.SSLErrorServer", url.getHost()); TaskStackBuilder stackBuilder = TaskStackBuilder.create(OpenMPD.get()); stackBuilder.addParentStack(HomeActivity.class); stackBuilder.addNextIntent(sslCertIntent); PendingIntent sslPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); nBuilder.setContentIntent(sslPendingIntent); notificationManager.notify(666, nBuilder.build()); return null; } catch (Exception e){ StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); Log.i("net.bradmont.openmpd",sw.toString()); } return content; } public static boolean processQueryIni(TntService service){ Ini ini = null; StringReader reader = null; try { URL u = new URL(service.getString("query_ini_url")); } catch (Exception e){ Log.i("net.bradmont.openmpd", "malformed query.ini url"); return false; } try { //ini = new Ini(getStreamFromUrl(service.getString("query_ini_url"), null, false)); reader = getCleanedStringReaderFromUrl(service.getString("query_ini_url")); if (reader == null){ Log.i("net.bradmont.openmpd", "StringReader is null"); return false; } ini = new Ini(reader); } catch (IOException e){ Log.i("net.bradmont.openmpd", "IOException"); StringWriter sw = new StringWriter(); e.printStackTrace(new PrintWriter(sw)); Log.i("net.bradmont.openmpd",sw.toString()); return false; } if (!ini.containsKey("ORGANIZATION")){ Log.i("net.bradmont.openmpd", "no section ORGANIZATION. huh."); Log.i("net.bradmont.openmpd", service.getString("query_ini_url")); StringBuilder sb = new StringBuilder(); try { reader = getCleanedStringReaderFromUrl(service.getString("query_ini_url")); int character = reader.read(); while (character != -1){ sb.append((char) character); character = reader.read(); } } catch (Exception e){} Log.i("net.bradmont.openmpd", "No ORGANIZATION section in query.ini"); return false; } Ini.Section org = ini.get("ORGANIZATION"); if (org.containsKey("RedirectQueryIni") && org.get("RedirectQueryIni").startsWith("http")){ // if this query.ini url is outdated, it should redirect to a current one. service.setValue("query_ini_url", org.get("RedirectQueryIni")); return processQueryIni(service); } service.setValue("base_url", ""); // eventually get rid of base_url; for the moment leave // it blank for new services if (org.containsKey("Code")){ service.setValue("name_short", org.get("Code")); } if (org.containsKey("QueryAuthentication") && org.get("QueryAuthentication") == "1"){ service.setValue("http_auth", true); } if (!ini.containsKey("ACCOUNT_BALANCE") || !ini.containsKey("DONATIONS") || !ini.containsKey("ADDRESSES") || !ini.containsKey("ADDRESSES_BY_PERSONIDS") ){ Log.i("net.bradmont.openmpd", "query.ini missing section(s)"); return false; } Ini.Section balance = ini.get("ACCOUNT_BALANCE"); Ini.Section donations = ini.get("DONATIONS"); Ini.Section addresses = ini.get("ADDRESSES"); Ini.Section addresses_by_personids = ini.get("ADDRESSES_BY_PERSONIDS"); if (!balance.containsKey("Url") || !balance.containsKey("Post") || !donations.containsKey("Url") || !donations.containsKey("Post") || !addresses.containsKey("Url") || !addresses.containsKey("Post") || !addresses_by_personids.containsKey("Url") || !addresses_by_personids.containsKey("Post") ){ Log.i("net.bradmont.openmpd", "query.ini missing url"); return false; } service.setValue("balance_url", balance.get("Url")); service.setValue("balance_formdata", balance.get("Post")); service.setValue("donations_url", donations.get("Url")); service.setValue("donations_formdata", donations.get("Post")); service.setValue("addresses_url", addresses.get("Url")); service.setValue("addresses_formdata", addresses.get("Post")); service.setValue("addresses_by_personids_url", addresses_by_personids.get("Url")); service.setValue("addresses_by_personids_formdata", addresses_by_personids.get("Post")); service.dirtySave(); return true; } public static DefaultHttpClient getNewHttpClient() { try { KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(null, null); SSLSocketFactory sf = new MySSLSocketFactory(trustStore); sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); HttpParams params = new BasicHttpParams(); HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); registry.register(new Scheme("https", sf, 443)); ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); return new DefaultHttpClient(ccm, params); } catch (Exception e) { return new DefaultHttpClient(); } } public static class MySSLSocketFactory extends SSLSocketFactory { SSLContext sslContext = SSLContext.getInstance("TLS"); public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { super(truststore); TrustManager tm = new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public X509Certificate[] getAcceptedIssuers() { return null; } }; sslContext.init(null, new TrustManager[] { tm }, null); } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); } @Override public Socket createSocket() throws IOException { return sslContext.getSocketFactory().createSocket(); } } }