Java tutorial
package carnero.cgeo; import android.app.Activity; import android.content.Context; import android.content.Intent; import java.io.InputStreamReader; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.BufferedReader; import java.io.IOException; import java.net.URL; import java.net.URLEncoder; import java.net.URLConnection; import java.net.HttpURLConnection; import java.util.Map; import java.util.Calendar; import java.util.Locale; import java.util.HashMap; import java.util.ArrayList; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.text.DateFormat; import java.text.SimpleDateFormat; import android.util.Log; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.text.Html; import android.text.Spannable; import android.text.style.StrikethroughSpan; import android.view.Display; import android.view.View; import android.view.WindowManager; import android.widget.ProgressBar; import android.widget.TextView; import com.google.android.apps.analytics.GoogleAnalyticsTracker; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; import java.math.BigInteger; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.URLDecoder; import java.security.MessageDigest; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Date; import java.util.Enumeration; import java.util.List; import java.util.Set; import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.json.JSONArray; import org.json.JSONObject; public class cgBase { public static HashMap<String, String> cacheTypes = new HashMap<String, String>(); public static HashMap<String, String> cacheTypesInv = new HashMap<String, String>(); public static HashMap<String, String> cacheIDs = new HashMap<String, String>(); public static HashMap<String, String> cacheIDsChoices = new HashMap<String, String>(); public static HashMap<String, String> waypointTypes = new HashMap<String, String>(); public static HashMap<String, Integer> logTypes = new HashMap<String, Integer>(); public static HashMap<String, Integer> logTypes0 = new HashMap<String, Integer>(); public static HashMap<Integer, String> logTypes1 = new HashMap<Integer, String>(); public static HashMap<Integer, String> logTypes2 = new HashMap<Integer, String>(); public static HashMap<Integer, String> logTypesTrackable = new HashMap<Integer, String>(); public static HashMap<Integer, String> logTypesTrackableAction = new HashMap<Integer, String>(); public static HashMap<Integer, String> errorRetrieve = new HashMap<Integer, String>(); public static SimpleDateFormat dateIn = new SimpleDateFormat("MM/dd/yyyy"); public static SimpleDateFormat dateEvIn = new SimpleDateFormat("dd MMMMM yyyy", Locale.ENGLISH); // 28 March 2009 public static SimpleDateFormat dateTbIn1 = new SimpleDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009 public static SimpleDateFormat dateTbIn2 = new SimpleDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009 public static SimpleDateFormat dateSqlIn = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 2010-07-25 14:44:01 public static SimpleDateFormat dateGPXIn = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); // 2010-04-20T07:00:00Z public static DateFormat dateOut = DateFormat.getDateInstance(DateFormat.LONG, Locale.getDefault()); public static DateFormat timeOut = DateFormat.getTimeInstance(DateFormat.SHORT, Locale.getDefault()); public static DateFormat dateOutShort = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()); private Resources res = null; private HashMap<String, String> cookies = new HashMap<String, String>(); private final String passMatch = "[/\\?&]*[Pp]ass(word)?=[^&^#^$]+"; private final Pattern patternLoggedIn = Pattern.compile( "<span class=\"Success\">You are logged in as[^<]*<strong[^>]*>([^<]+)</strong>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); private final Pattern patternLogged2In = Pattern.compile( "<strong>[^\\w]*Hello,[^<]*<a[^>]+>([^<]+)</a>[^<]*</strong>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); private final Pattern patternViewstate = Pattern.compile( "id=\"__VIEWSTATE\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); private final Pattern patternViewstate1 = Pattern.compile( "id=\"__VIEWSTATE1\"[^(value)]+value=\"([^\"]+)\"[^>]+>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); public static final double kmInMiles = 1 / 1.609344; public static final double deg2rad = Math.PI / 180; public static final double rad2deg = 180 / Math.PI; public static final float erad = 6371.0f; public static final int mapAppAny = 0; public static final int mapAppLocus = 1; public static final int mapAppRmaps = 2; private cgeoapplication app = null; private cgSettings settings = null; private SharedPreferences prefs = null; public String version = null; private String idBrowser = "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4"; Context context = null; final private static HashMap<String, Integer> gcIcons = new HashMap<String, Integer>(); final private static HashMap<String, Integer> wpIcons = new HashMap<String, Integer>(); public static final int LOG_FOUND_IT = 2; public static final int LOG_DIDNT_FIND_IT = 3; public static final int LOG_NOTE = 4; public static final int LOG_PUBLISH_LISTING = 1003; // unknown ID; used number doesn't match any GC.com's ID public static final int LOG_ENABLE_LISTING = 23; public static final int LOG_ARCHIVE = 5; public static final int LOG_TEMP_DISABLE_LISTING = 22; public static final int LOG_NEEDS_ARCHIVE = 7; public static final int LOG_WILL_ATTEND = 9; public static final int LOG_ATTENDED = 10; public static final int LOG_RETRIEVED_IT = 13; public static final int LOG_PLACED_IT = 14; public static final int LOG_GRABBED_IT = 19; public static final int LOG_NEEDS_MAINTENANCE = 45; public static final int LOG_OWNER_MAINTENANCE = 46; public static final int LOG_UPDATE_COORDINATES = 47; public static final int LOG_DISCOVERED_IT = 48; public static final int LOG_POST_REVIEWER_NOTE = 18; public static final int LOG_VISIT = 1001; // unknown ID; used number doesn't match any GC.com's ID public static final int LOG_WEBCAM_PHOTO_TAKEN = 11; public static final int LOG_ANNOUNCEMENT = 74; public cgBase(cgeoapplication appIn, cgSettings settingsIn, SharedPreferences prefsIn) { context = appIn.getBaseContext(); res = appIn.getBaseContext().getResources(); // cache types cacheTypes.put("traditional cache", "traditional"); cacheTypes.put("multi-cache", "multi"); cacheTypes.put("unknown cache", "mystery"); cacheTypes.put("letterbox hybrid", "letterbox"); cacheTypes.put("event cache", "event"); cacheTypes.put("mega-event cache", "mega"); cacheTypes.put("earthcache", "earth"); cacheTypes.put("cache in trash out event", "cito"); cacheTypes.put("webcam cache", "webcam"); cacheTypes.put("virtual cache", "virtual"); cacheTypes.put("wherigo cache", "wherigo"); cacheTypes.put("lost & found", "lostfound"); cacheTypes.put("project ape cache", "ape"); cacheTypes.put("groundspeak hq", "gchq"); cacheTypes.put("gps cache exhibit", "gps"); // cache types inverted cacheTypesInv.put("traditional", res.getString(R.string.traditional)); cacheTypesInv.put("multi", res.getString(R.string.multi)); cacheTypesInv.put("mystery", res.getString(R.string.mystery)); cacheTypesInv.put("letterbox", res.getString(R.string.letterbox)); cacheTypesInv.put("event", res.getString(R.string.event)); cacheTypesInv.put("mega", res.getString(R.string.mega)); cacheTypesInv.put("earth", res.getString(R.string.earth)); cacheTypesInv.put("cito", res.getString(R.string.cito)); cacheTypesInv.put("webcam", res.getString(R.string.webcam)); cacheTypesInv.put("virtual", res.getString(R.string.virtual)); cacheTypesInv.put("wherigo", res.getString(R.string.wherigo)); cacheTypesInv.put("lostfound", res.getString(R.string.lostfound)); cacheTypesInv.put("ape", res.getString(R.string.ape)); cacheTypesInv.put("gchq", res.getString(R.string.gchq)); cacheTypesInv.put("gps", res.getString(R.string.gps)); // cache ids cacheIDs.put("all", "9a79e6ce-3344-409c-bbe9-496530baf758"); // hard-coded also in cgSettings cacheIDs.put("traditional", "32bc9333-5e52-4957-b0f6-5a2c8fc7b257"); cacheIDs.put("multi", "a5f6d0ad-d2f2-4011-8c14-940a9ebf3c74"); cacheIDs.put("mystery", "40861821-1835-4e11-b666-8d41064d03fe"); cacheIDs.put("letterbox", "4bdd8fb2-d7bc-453f-a9c5-968563b15d24"); cacheIDs.put("event", "69eb8534-b718-4b35-ae3c-a856a55b0874"); cacheIDs.put("mega-event", "69eb8535-b718-4b35-ae3c-a856a55b0874"); cacheIDs.put("earth", "c66f5cf3-9523-4549-b8dd-759cd2f18db8"); cacheIDs.put("cito", "57150806-bc1a-42d6-9cf0-538d171a2d22"); cacheIDs.put("webcam", "31d2ae3c-c358-4b5f-8dcd-2185bf472d3d"); cacheIDs.put("virtual", "294d4360-ac86-4c83-84dd-8113ef678d7e"); cacheIDs.put("wherigo", "0544fa55-772d-4e5c-96a9-36a51ebcf5c9"); cacheIDs.put("lostfound", "3ea6533d-bb52-42fe-b2d2-79a3424d4728"); cacheIDs.put("ape", "2555690d-b2bc-4b55-b5ac-0cb704c0b768"); cacheIDs.put("gchq", "416f2494-dc17-4b6a-9bab-1a29dd292d8c"); cacheIDs.put("gps", "72e69af2-7986-4990-afd9-bc16cbbb4ce3"); // cache choices cacheIDsChoices.put(res.getString(R.string.all), cacheIDs.get("all")); cacheIDsChoices.put(res.getString(R.string.traditional), cacheIDs.get("traditional")); cacheIDsChoices.put(res.getString(R.string.multi), cacheIDs.get("multi")); cacheIDsChoices.put(res.getString(R.string.mystery), cacheIDs.get("mystery")); cacheIDsChoices.put(res.getString(R.string.letterbox), cacheIDs.get("letterbox")); cacheIDsChoices.put(res.getString(R.string.event), cacheIDs.get("event")); cacheIDsChoices.put(res.getString(R.string.mega), cacheIDs.get("mega")); cacheIDsChoices.put(res.getString(R.string.earth), cacheIDs.get("earth")); cacheIDsChoices.put(res.getString(R.string.cito), cacheIDs.get("cito")); cacheIDsChoices.put(res.getString(R.string.webcam), cacheIDs.get("webcam")); cacheIDsChoices.put(res.getString(R.string.virtual), cacheIDs.get("virtual")); cacheIDsChoices.put(res.getString(R.string.wherigo), cacheIDs.get("whereigo")); cacheIDsChoices.put(res.getString(R.string.lostfound), cacheIDs.get("lostfound")); cacheIDsChoices.put(res.getString(R.string.ape), cacheIDs.get("ape")); cacheIDsChoices.put(res.getString(R.string.gchq), cacheIDs.get("gchq")); cacheIDsChoices.put(res.getString(R.string.gps), cacheIDs.get("gps")); // waypoint types waypointTypes.put("flag", res.getString(R.string.wp_final)); waypointTypes.put("stage", res.getString(R.string.wp_stage)); waypointTypes.put("puzzle", res.getString(R.string.wp_puzzle)); waypointTypes.put("pkg", res.getString(R.string.wp_pkg)); waypointTypes.put("trailhead", res.getString(R.string.wp_trailhead)); waypointTypes.put("waypoint", res.getString(R.string.wp_waypoint)); // log types logTypes.put("icon_smile", LOG_FOUND_IT); logTypes.put("icon_sad", LOG_DIDNT_FIND_IT); logTypes.put("icon_note", LOG_NOTE); logTypes.put("icon_greenlight", LOG_PUBLISH_LISTING); logTypes.put("icon_enabled", LOG_ENABLE_LISTING); logTypes.put("traffic_cone", LOG_ARCHIVE); logTypes.put("icon_disabled", LOG_TEMP_DISABLE_LISTING); logTypes.put("icon_remove", LOG_NEEDS_ARCHIVE); logTypes.put("icon_rsvp", LOG_WILL_ATTEND); logTypes.put("icon_attended", LOG_ATTENDED); logTypes.put("picked_up", LOG_RETRIEVED_IT); logTypes.put("dropped_off", LOG_PLACED_IT); logTypes.put("transfer", LOG_GRABBED_IT); logTypes.put("icon_needsmaint", LOG_NEEDS_MAINTENANCE); logTypes.put("icon_maint", LOG_OWNER_MAINTENANCE); logTypes.put("coord_update", LOG_UPDATE_COORDINATES); logTypes.put("icon_discovered", LOG_DISCOVERED_IT); logTypes.put("big_smile", LOG_POST_REVIEWER_NOTE); logTypes.put("icon_visited", LOG_VISIT); // unknown ID; used number doesn't match any GC.com's ID logTypes.put("icon_camera", LOG_WEBCAM_PHOTO_TAKEN); // unknown ID; used number doesn't match any GC.com's ID logTypes.put("icon_announcement", LOG_ANNOUNCEMENT); // unknown ID; used number doesn't match any GC.com's ID logTypes0.put("found it", LOG_FOUND_IT); logTypes0.put("didn't find it", LOG_DIDNT_FIND_IT); logTypes0.put("write note", LOG_NOTE); logTypes0.put("publish listing", LOG_PUBLISH_LISTING); logTypes0.put("enable listing", LOG_ENABLE_LISTING); logTypes0.put("archive", LOG_ARCHIVE); logTypes0.put("temporarily disable listing", LOG_TEMP_DISABLE_LISTING); logTypes0.put("needs archived", LOG_NEEDS_ARCHIVE); logTypes0.put("will attend", LOG_WILL_ATTEND); logTypes0.put("attended", LOG_ATTENDED); logTypes0.put("retrieved it", LOG_RETRIEVED_IT); logTypes0.put("placed it", LOG_PLACED_IT); logTypes0.put("grabbed it", LOG_GRABBED_IT); logTypes0.put("needs maintenance", LOG_NEEDS_MAINTENANCE); logTypes0.put("owner maintenance", LOG_OWNER_MAINTENANCE); logTypes0.put("update coordinates", LOG_UPDATE_COORDINATES); logTypes0.put("discovered it", LOG_DISCOVERED_IT); logTypes0.put("post reviewer note", LOG_POST_REVIEWER_NOTE); logTypes0.put("visit", LOG_VISIT); // unknown ID; used number doesn't match any GC.com's ID logTypes0.put("webcam photo taken", LOG_WEBCAM_PHOTO_TAKEN); // unknown ID; used number doesn't match any GC.com's ID logTypes0.put("announcement", LOG_ANNOUNCEMENT); // unknown ID; used number doesn't match any GC.com's ID logTypes1.put(LOG_FOUND_IT, res.getString(R.string.log_found)); logTypes1.put(LOG_DIDNT_FIND_IT, res.getString(R.string.log_dnf)); logTypes1.put(LOG_NOTE, res.getString(R.string.log_note)); logTypes1.put(LOG_PUBLISH_LISTING, res.getString(R.string.log_published)); logTypes1.put(LOG_ENABLE_LISTING, res.getString(R.string.log_enabled)); logTypes1.put(LOG_ARCHIVE, res.getString(R.string.log_archived)); logTypes1.put(LOG_TEMP_DISABLE_LISTING, res.getString(R.string.log_disabled)); logTypes1.put(LOG_NEEDS_ARCHIVE, res.getString(R.string.log_needs_archived)); logTypes1.put(LOG_WILL_ATTEND, res.getString(R.string.log_attend)); logTypes1.put(LOG_ATTENDED, res.getString(R.string.log_attended)); logTypes1.put(LOG_RETRIEVED_IT, res.getString(R.string.log_retrieved)); logTypes1.put(LOG_PLACED_IT, res.getString(R.string.log_placed)); logTypes1.put(LOG_GRABBED_IT, res.getString(R.string.log_grabbed)); logTypes1.put(LOG_NEEDS_MAINTENANCE, res.getString(R.string.log_maintenance_needed)); logTypes1.put(LOG_OWNER_MAINTENANCE, res.getString(R.string.log_maintained)); logTypes1.put(LOG_UPDATE_COORDINATES, res.getString(R.string.log_update)); logTypes1.put(LOG_DISCOVERED_IT, res.getString(R.string.log_discovered)); logTypes1.put(LOG_POST_REVIEWER_NOTE, res.getString(R.string.log_reviewed)); logTypes1.put(LOG_VISIT, res.getString(R.string.log_taken)); logTypes1.put(LOG_WEBCAM_PHOTO_TAKEN, res.getString(R.string.log_webcam)); logTypes1.put(LOG_ANNOUNCEMENT, res.getString(R.string.log_announcement)); logTypes2.put(LOG_FOUND_IT, res.getString(R.string.log_found)); // traditional, multi, unknown, earth, wherigo, virtual, letterbox logTypes2.put(LOG_DIDNT_FIND_IT, res.getString(R.string.log_dnf)); // traditional, multi, unknown, earth, wherigo, virtual, letterbox, webcam logTypes2.put(LOG_NOTE, res.getString(R.string.log_note)); // traditional, multi, unknown, earth, wherigo, virtual, event, letterbox, webcam, trackable logTypes2.put(LOG_PUBLISH_LISTING, res.getString(R.string.log_published)); // X logTypes2.put(LOG_ENABLE_LISTING, res.getString(R.string.log_enabled)); // owner logTypes2.put(LOG_ARCHIVE, res.getString(R.string.log_archived)); // traditional, multi, unknown, earth, event, wherigo, virtual, letterbox, webcam logTypes2.put(LOG_TEMP_DISABLE_LISTING, res.getString(R.string.log_disabled)); // owner logTypes2.put(LOG_NEEDS_ARCHIVE, res.getString(R.string.log_needs_archived)); // traditional, multi, unknown, earth, event, wherigo, virtual, letterbox, webcam logTypes2.put(LOG_WILL_ATTEND, res.getString(R.string.log_attend)); // event logTypes2.put(LOG_ATTENDED, res.getString(R.string.log_attended)); // event logTypes2.put(LOG_WEBCAM_PHOTO_TAKEN, res.getString(R.string.log_webcam)); // webcam logTypes2.put(LOG_RETRIEVED_IT, res.getString(R.string.log_retrieved)); //trackable logTypes2.put(LOG_GRABBED_IT, res.getString(R.string.log_grabbed)); //trackable logTypes2.put(LOG_NEEDS_MAINTENANCE, res.getString(R.string.log_maintenance_needed)); // traditional, unknown, multi, wherigo, virtual, letterbox, webcam logTypes2.put(LOG_OWNER_MAINTENANCE, res.getString(R.string.log_maintained)); // owner logTypes2.put(LOG_DISCOVERED_IT, res.getString(R.string.log_discovered)); //trackable logTypes2.put(LOG_POST_REVIEWER_NOTE, res.getString(R.string.log_reviewed)); // X logTypes2.put(LOG_ANNOUNCEMENT, res.getString(R.string.log_announcement)); // X // trackables for logs logTypesTrackable.put(0, res.getString(R.string.log_tb_nothing)); // do nothing logTypesTrackable.put(1, res.getString(R.string.log_tb_visit)); // visit cache logTypesTrackable.put(2, res.getString(R.string.log_tb_drop)); // drop here logTypesTrackableAction.put(0, ""); // do nothing logTypesTrackableAction.put(1, "_Visited"); // visit cache logTypesTrackableAction.put(2, "_DroppedOff"); // drop here // retrieving errors (because of ____ ) errorRetrieve.put(1, res.getString(R.string.err_none)); errorRetrieve.put(0, res.getString(R.string.err_start)); errorRetrieve.put(-1, res.getString(R.string.err_parse)); errorRetrieve.put(-2, res.getString(R.string.err_server)); errorRetrieve.put(-3, res.getString(R.string.err_login)); errorRetrieve.put(-4, res.getString(R.string.err_unknown)); errorRetrieve.put(-5, res.getString(R.string.err_comm)); errorRetrieve.put(-6, res.getString(R.string.err_wrong)); errorRetrieve.put(-7, res.getString(R.string.err_license)); // init app = appIn; settings = settingsIn; prefs = prefsIn; try { PackageManager manager = app.getPackageManager(); PackageInfo info = manager.getPackageInfo(app.getPackageName(), 0); version = info.versionName; } catch (Exception e) { // nothing } if (settings.asBrowser == 1) { final long rndBrowser = Math.round(Math.random() * 6); if (rndBrowser == 0) { idBrowser = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US) AppleWebKit/533.1 (KHTML, like Gecko) Chrome/5.0.322.2 Safari/533.1"; } else if (rndBrowser == 1) { idBrowser = "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; MDDC)"; } else if (rndBrowser == 2) { idBrowser = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3"; } else if (rndBrowser == 3) { idBrowser = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-us) AppleWebKit/531.21.8 (KHTML, like Gecko) Version/4.0.4 Safari/531.21.10"; } else if (rndBrowser == 4) { idBrowser = "Mozilla/5.0 (iPod; U; CPU iPhone OS 2_2_1 like Mac OS X; en-us) AppleWebKit/525.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile/5H11a Safari/525.20"; } else if (rndBrowser == 5) { idBrowser = "Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2"; } else if (rndBrowser == 6) { idBrowser = "Mozilla/5.0 (X11; U; Linux i686; en-US) AppleWebKit/533.4 (KHTML, like Gecko) Chrome/5.0.375.86 Safari/533.4"; } else { idBrowser = "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/532.9 (KHTML, like Gecko) Chrome/5.0.307.11 Safari/532.9"; } } } public String findViewstate(String page, int index) { String viewstate = null; if (index == 0) { final Matcher matcherViewstate = patternViewstate.matcher(page); while (matcherViewstate.find()) { if (matcherViewstate.groupCount() > 0) { viewstate = matcherViewstate.group(1); } } } else if (index == 1) { final Matcher matcherViewstate = patternViewstate1.matcher(page); while (matcherViewstate.find()) { if (matcherViewstate.groupCount() > 0) { viewstate = matcherViewstate.group(1); } } } return viewstate; } public class loginThread extends Thread { @Override public void run() { login(); } } public int login() { final String host = "www.geocaching.com"; final String path = "/login/default.aspx"; cgResponse loginResponse = null; String loginData = null; String viewstate = null; String viewstate1 = null; final HashMap<String, String> loginStart = settings.getLogin(); if (loginStart == null) { return -3; // no login information stored } loginResponse = request(true, host, path, "GET", new HashMap<String, String>(), false, false, false); loginData = loginResponse.getData(); if (loginData != null && loginData.length() > 0) { if (checkLogin(loginData) == true) { Log.i(cgSettings.tag, "Already logged in Geocaching.com as " + loginStart.get("username")); switchToEnglish(viewstate, viewstate1); return 1; // logged in } viewstate = findViewstate(loginData, 0); viewstate1 = findViewstate(loginData, 1); if (viewstate == null || viewstate.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.login: Failed to find viewstate"); return -1; // no viewstate } } else { Log.e(cgSettings.tag, "cgeoBase.login: Failed to retrieve login page (1st)"); return -2; // no loginpage } final HashMap<String, String> login = settings.getLogin(); final HashMap<String, String> params = new HashMap<String, String>(); if (login == null || login.get("username") == null || login.get("username").length() == 0 || login.get("password") == null || login.get("password").length() == 0) { Log.e(cgSettings.tag, "cgeoBase.login: No login information stored"); return -3; } settings.deleteCookies(); params.put("__EVENTTARGET", ""); params.put("__EVENTARGUMENT", ""); params.put("__VIEWSTATE", viewstate); if (viewstate1 != null) { params.put("__VIEWSTATE1", viewstate1); params.put("__VIEWSTATEFIELDCOUNT", "2"); } params.put("ctl00$SiteContent$tbUsername", login.get("username")); params.put("ctl00$SiteContent$tbPassword", login.get("password")); params.put("ctl00$SiteContent$cbRememberMe", "on"); params.put("ctl00$SiteContent$btnSignIn", "Login"); loginResponse = request(true, host, path, "POST", params, false, false, false); loginData = loginResponse.getData(); if (loginData != null && loginData.length() > 0) { if (checkLogin(loginData) == true) { Log.i(cgSettings.tag, "Successfully logged in Geocaching.com as " + login.get("username")); switchToEnglish(findViewstate(loginData, 0), findViewstate(loginData, 1)); return 1; // logged in } else { if (loginData.indexOf("Your username/password combination does not match.") != -1) { Log.i(cgSettings.tag, "Failed to log in Geocaching.com as " + login.get("username") + " because of wrong username/password"); return -6; // wrong login } else { Log.i(cgSettings.tag, "Failed to log in Geocaching.com as " + login.get("username") + " for some unknown reason"); return -4; // can't login } } } else { Log.e(cgSettings.tag, "cgeoBase.login: Failed to retrieve login page (2nd)"); return -5; // no login page } } public Boolean checkLogin(String page) { if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.checkLogin: No page given"); return false; } // on every page final Matcher matcherLogged2In = patternLogged2In.matcher(page); while (matcherLogged2In.find()) { return true; } // after login final Matcher matcherLoggedIn = patternLoggedIn.matcher(page); while (matcherLoggedIn.find()) { return true; } return false; } public String switchToEnglish(String viewstate, String viewstate1) { final String host = "www.geocaching.com"; final String path = "/default.aspx"; final HashMap<String, String> params = new HashMap<String, String>(); if (viewstate != null) { params.put("__VIEWSTATE", viewstate); } if (viewstate1 != null) { params.put("__VIEWSTATE1", viewstate1); params.put("__VIEWSTATEFIELDCOUNT", "2"); } params.put("__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem"); // switch to english params.put("__EVENTARGUMENT", ""); return request(false, host, path, "POST", params, false, false, false).getData(); } public cgCacheWrap parseSearch(cgSearchThread thread, String url, String page, boolean showCaptcha) { if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.parseSearch: No page given"); return null; } final cgCacheWrap caches = new cgCacheWrap(); final ArrayList<String> cids = new ArrayList<String>(); final ArrayList<String> guids = new ArrayList<String>(); String recaptchaChallenge = null; String recaptchaText = null; caches.url = url; final Pattern patternCacheType = Pattern.compile( "<td class=\"Merge\">[^<]*<a href=\"[^\"]*/seek/cache_details\\.aspx\\?guid=[^\"]+\"[^>]+>[^<]*<img src=\"[^\"]*/images/wpttypes/[^\\.]+\\.gif\" alt=\"([^\"]+)\" title=\"[^\"]+\"[^>]*>[^<]*</a>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternGuidAndDisabled = Pattern.compile( "<img src=\"[^\"]*/images/wpttypes/[^>]*>[^<]*</a></td><td class=\"Merge\">[^<]*<a href=\"[^\"]*/seek/cache_details\\.aspx\\?guid=([a-z0-9\\-]+)\" class=\"lnk([^\"]*)\">([^<]*<span>)?([^<]*)(</span>[^<]*)?</a>[^<]+<br />([^<]*)<span[^>]+>([^<]*)</span>([^<]*<img[^>]+>)?[^<]*<br />[^<]*</td>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternTbs = Pattern.compile( "<a id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxTravelBugList\" class=\"tblist\" data-tbcount=\"([0-9]+)\" data-id=\"[^\"]*\"[^>]*>(.*)</a>", Pattern.CASE_INSENSITIVE); final Pattern patternTbsInside = Pattern.compile( "(<img src=\"[^\"]+\" alt=\"([^\"]+)\" title=\"[^\"]*\" />[^<]*)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternDirection = Pattern.compile( "<img id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxDistanceAndHeading\" title=\"[^\"]*\" src=\"[^\"]*/seek/CacheDir\\.ashx\\?k=([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE); final Pattern patternCode = Pattern.compile("\\|[^\\w]*(GC[a-z0-9]+)[^\\|]*\\|", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternId = Pattern.compile("name=\"CID\"[^v]*value=\"([0-9]+)\"", Pattern.CASE_INSENSITIVE); final Pattern patternFavourite = Pattern.compile( "<span id=\"ctl00_ContentBody_dlResults_ctl[0-9]+_uxFavoritesValue\" title=\"[^\"]*\" class=\"favorite-rank\">([0-9]+)</span>", Pattern.CASE_INSENSITIVE); final Pattern patternTotalCnt = Pattern.compile( "<td class=\"PageBuilderWidget\"><span>Total Records[^<]*<b>(\\d+)<\\/b>", Pattern.CASE_INSENSITIVE); final Pattern patternRecaptcha = Pattern.compile( "<script[^>]*src=\"[^\"]*/recaptcha/api/challenge\\?k=([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE); final Pattern patternRecaptchaChallenge = Pattern.compile("challenge : '([^']+)'", Pattern.CASE_INSENSITIVE); caches.viewstate = findViewstate(page, 0); caches.viewstate1 = findViewstate(page, 1); // recaptcha if (showCaptcha == true) { try { String recaptchaJsParam = null; final Matcher matcherRecaptcha = patternRecaptcha.matcher(page); while (matcherRecaptcha.find()) { if (matcherRecaptcha.groupCount() > 0) { recaptchaJsParam = matcherRecaptcha.group(1); } } if (recaptchaJsParam != null) { final String recaptchaJs = request(false, "www.google.com", "/recaptcha/api/challenge", "GET", "k=" + urlencode_rfc3986(recaptchaJsParam.trim()), 0, true).getData(); if (recaptchaJs != null && recaptchaJs.length() > 0) { final Matcher matcherRecaptchaChallenge = patternRecaptchaChallenge.matcher(recaptchaJs); while (matcherRecaptchaChallenge.find()) { if (matcherRecaptchaChallenge.groupCount() > 0) { recaptchaChallenge = matcherRecaptchaChallenge.group(1).trim(); } } } } } catch (Exception e) { // failed to parse recaptcha challenge Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse recaptcha challenge"); } if (thread != null && recaptchaChallenge != null && recaptchaChallenge.length() > 0) { thread.setChallenge(recaptchaChallenge); thread.notifyNeed(); } } int startPos = -1; int endPos = -1; startPos = page.indexOf("<div id=\"ctl00_ContentBody_ResultsPanel\""); if (startPos == -1) { Log.e(cgSettings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_dlResults\" not found on page"); return null; } page = page.substring(startPos); // cut on <table startPos = page.indexOf(">"); endPos = page.indexOf("ctl00_ContentBody_UnitTxt"); if (startPos == -1 || endPos == -1) { Log.e(cgSettings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page"); return null; } page = page.substring(startPos + 1, endPos - startPos + 1); // cut between <table> and </table> final String[] rows = page.split("<tr class="); final int rows_count = rows.length; for (int z = 1; z < rows_count; z++) { cgCache cache = new cgCache(); String row = rows[z]; // check for cache type presence if (row.indexOf("images/wpttypes") == -1) { continue; } try { final Matcher matcherGuidAndDisabled = patternGuidAndDisabled.matcher(row); while (matcherGuidAndDisabled.find()) { if (matcherGuidAndDisabled.groupCount() > 0) { guids.add(matcherGuidAndDisabled.group(1)); cache.guid = matcherGuidAndDisabled.group(1); if (matcherGuidAndDisabled.group(4) != null) { cache.name = Html.fromHtml(matcherGuidAndDisabled.group(4).trim()).toString(); } if (matcherGuidAndDisabled.group(6) != null) { cache.location = Html.fromHtml(matcherGuidAndDisabled.group(6).trim()).toString(); } final String attr = matcherGuidAndDisabled.group(2); if (attr != null) { if (attr.contains("Strike") == true) { cache.disabled = true; } else { cache.disabled = false; } if (attr.contains("OldWarning") == true) { cache.archived = true; } else { cache.archived = false; } } } } } catch (Exception e) { // failed to parse GUID and/or Disabled Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse GUID and/or Disabled data"); } if (settings.excludeDisabled == 1 && (cache.disabled == true || cache.archived == true)) { // skip disabled and archived caches cache = null; continue; } String inventoryPre = null; // GC* code try { final Matcher matcherCode = patternCode.matcher(row); while (matcherCode.find()) { if (matcherCode.groupCount() > 0) { cache.geocode = matcherCode.group(1).toUpperCase(); } } } catch (Exception e) { // failed to parse code Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache code"); } // cache type try { final Matcher matcherCacheType = patternCacheType.matcher(row); while (matcherCacheType.find()) { if (matcherCacheType.groupCount() > 0) { cache.type = cacheTypes.get(matcherCacheType.group(1).toLowerCase()); } } } catch (Exception e) { // failed to parse type Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache type"); } // cache direction - image try { final Matcher matcherDirection = patternDirection.matcher(row); while (matcherDirection.find()) { if (matcherDirection.groupCount() > 0) { cache.directionImg = matcherDirection.group(1); } } } catch (Exception e) { // failed to parse direction image Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache direction image"); } // cache inventory try { final Matcher matcherTbs = patternTbs.matcher(row); while (matcherTbs.find()) { if (matcherTbs.groupCount() > 0) { cache.inventoryItems = Integer.parseInt(matcherTbs.group(1)); inventoryPre = matcherTbs.group(2); } } } catch (Exception e) { // failed to parse inventory Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache inventory (1)"); } if (inventoryPre != null && inventoryPre.trim().length() > 0) { try { final Matcher matcherTbsInside = patternTbsInside.matcher(inventoryPre); while (matcherTbsInside.find()) { if (matcherTbsInside.groupCount() == 2 && matcherTbsInside.group(2) != null) { final String inventoryItem = matcherTbsInside.group(2).toLowerCase(); if (inventoryItem.equals("premium member only cache")) { continue; } else { if (cache.inventoryItems <= 0) { cache.inventoryItems = 1; } } } } } catch (Exception e) { // failed to parse cache inventory info Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache inventory info"); } } // premium cache if (row.indexOf("/images/small_profile.gif") != -1) { cache.members = true; } else { cache.members = false; } // found it if (row.indexOf("/images/icons/icon_smile.gif") != -1) { cache.found = true; } else { cache.found = false; } // own it if (row.indexOf("/images/silk/star.png") != -1) { cache.own = true; } else { cache.own = false; } // id try { final Matcher matcherId = patternId.matcher(row); while (matcherId.find()) { if (matcherId.groupCount() > 0) { cache.cacheid = matcherId.group(1); cids.add(cache.cacheid); } } } catch (Exception e) { // failed to parse cache id Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache id"); } // favourite count try { final Matcher matcherFavourite = patternFavourite.matcher(row); while (matcherFavourite.find()) { if (matcherFavourite.groupCount() > 0) { cache.favouriteCnt = Integer.parseInt(matcherFavourite.group(1)); } } } catch (Exception e) { // failed to parse favourite count Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse favourite count"); } if (cache.nameSp == null) { cache.nameSp = (new Spannable.Factory()).newSpannable(cache.name); if (cache.disabled == true || cache.archived == true) { // strike cache.nameSp.setSpan(new StrikethroughSpan(), 0, cache.nameSp.toString().length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } } caches.cacheList.add(cache); } // total caches found try { final Matcher matcherTotalCnt = patternTotalCnt.matcher(page); while (matcherTotalCnt.find()) { if (matcherTotalCnt.groupCount() > 0) { if (matcherTotalCnt.group(1) != null) { caches.totalCnt = new Integer(matcherTotalCnt.group(1)); } } } } catch (Exception e) { // failed to parse cache count Log.w(cgSettings.tag, "cgeoBase.parseSearch: Failed to parse cache count"); } if (thread != null && recaptchaChallenge != null) { if (thread.getText() == null) { thread.waitForUser(); } recaptchaText = thread.getText(); } if (cids.size() > 0 && (recaptchaChallenge == null || (recaptchaChallenge != null && recaptchaText != null && recaptchaText.length() > 0))) { Log.i(cgSettings.tag, "Trying to get .loc for " + cids.size() + " caches"); try { // get coordinates for parsed caches final String host = "www.geocaching.com"; final String path = "/seek/nearest.aspx"; final StringBuilder params = new StringBuilder(); params.append("__EVENTTARGET="); params.append("&"); params.append("__EVENTARGUMENT="); params.append("&"); params.append("__VIEWSTATE="); params.append(urlencode_rfc3986(caches.viewstate)); if (caches.viewstate1 != null) { params.append("&"); params.append("__VIEWSTATE1="); params.append(urlencode_rfc3986(caches.viewstate1)); params.append("&"); params.append("__VIEWSTATEFIELDCOUNT=2"); } for (String cid : cids) { params.append("&"); params.append("CID="); params.append(urlencode_rfc3986(cid)); } if (recaptchaChallenge != null && recaptchaText != null && recaptchaText.length() > 0) { params.append("&"); params.append("recaptcha_challenge_field="); params.append(urlencode_rfc3986(recaptchaChallenge)); params.append("&"); params.append("recaptcha_response_field="); params.append(urlencode_rfc3986(recaptchaText)); } params.append("&"); params.append("ctl00%24ContentBody%24uxDownloadLoc=Download+Waypoints"); final String coordinates = request(false, host, path, "POST", params.toString(), 0, true).getData(); if (coordinates != null && coordinates.length() > 0) { if (coordinates.indexOf( "You have not agreed to the license agreement. The license agreement is required before you can start downloading GPX or LOC files from Geocaching.com") > -1) { Log.i(cgSettings.tag, "User has not agreed to the license agreement. Can\'t download .loc file."); caches.error = errorRetrieve.get(-7); return caches; } } if (coordinates != null && coordinates.length() > 0) { final HashMap<String, cgCoord> cidCoords = new HashMap<String, cgCoord>(); final Pattern patternCidCode = Pattern.compile("name id=\"([^\"]+)\""); final Pattern patternCidLat = Pattern.compile("lat=\"([^\"]+)\""); final Pattern patternCidLon = Pattern.compile("lon=\"([^\"]+)\""); // premium only >> final Pattern patternCidDif = Pattern.compile("<difficulty>([^<]+)</difficulty>"); final Pattern patternCidTer = Pattern.compile("<terrain>([^<]+)</terrain>"); final Pattern patternCidCon = Pattern.compile("<container>([^<]+)</container>"); // >> premium only final String[] points = coordinates.split("<waypoint>"); // parse coordinates for (String point : points) { final cgCoord pointCoord = new cgCoord(); final Matcher matcherCidCode = patternCidCode.matcher(point); final Matcher matcherLatCode = patternCidLat.matcher(point); final Matcher matcherLonCode = patternCidLon.matcher(point); final Matcher matcherDifCode = patternCidDif.matcher(point); final Matcher matcherTerCode = patternCidTer.matcher(point); final Matcher matcherConCode = patternCidCon.matcher(point); HashMap<String, Object> tmp = null; if (matcherCidCode.find() == true) { pointCoord.name = matcherCidCode.group(1).trim().toUpperCase(); } if (matcherLatCode.find() == true) { tmp = parseCoordinate(matcherLatCode.group(1), "lat"); pointCoord.latitude = (Double) tmp.get("coordinate"); } if (matcherLonCode.find() == true) { tmp = parseCoordinate(matcherLonCode.group(1), "lon"); pointCoord.longitude = (Double) tmp.get("coordinate"); } if (matcherDifCode.find() == true) { pointCoord.difficulty = new Float(matcherDifCode.group(1)); } if (matcherTerCode.find() == true) { pointCoord.terrain = new Float(matcherTerCode.group(1)); } if (matcherConCode.find() == true) { final int size = Integer.parseInt(matcherConCode.group(1)); if (size == 1) { pointCoord.size = "not chosen"; } else if (size == 2) { pointCoord.size = "micro"; } else if (size == 3) { pointCoord.size = "regular"; } else if (size == 4) { pointCoord.size = "large"; } else if (size == 5) { pointCoord.size = "virtual"; } else if (size == 6) { pointCoord.size = "other"; } else if (size == 8) { pointCoord.size = "small"; } else { pointCoord.size = "unknown"; } } cidCoords.put(pointCoord.name, pointCoord); } Log.i(cgSettings.tag, "Coordinates found in .loc file: " + cidCoords.size()); // save found cache coordinates for (cgCache oneCache : caches.cacheList) { if (cidCoords.containsKey(oneCache.geocode) == true) { cgCoord thisCoords = cidCoords.get(oneCache.geocode); oneCache.latitude = thisCoords.latitude; oneCache.longitude = thisCoords.longitude; oneCache.difficulty = thisCoords.difficulty; oneCache.terrain = thisCoords.terrain; oneCache.size = thisCoords.size; } } } } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.parseSearch.CIDs: " + e.toString()); } } // get direction images cgDirectionImg dirImgDownloader = new cgDirectionImg(settings); for (cgCache oneCache : caches.cacheList) { if (oneCache.latitude == null && oneCache.longitude == null && oneCache.direction == null && oneCache.directionImg != null) { dirImgDownloader.getDrawable(oneCache.geocode, oneCache.directionImg); } } dirImgDownloader = null; // get ratings if (guids.size() > 0) { Log.i(cgSettings.tag, "Trying to get ratings for " + cids.size() + " caches"); try { final HashMap<String, cgRating> ratings = getRating(guids, null); if (ratings != null) { // save found cache coordinates for (cgCache oneCache : caches.cacheList) { if (ratings.containsKey(oneCache.guid) == true) { cgRating thisRating = ratings.get(oneCache.guid); oneCache.rating = thisRating.rating; oneCache.votes = thisRating.votes; oneCache.myVote = thisRating.myVote; } } } } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.parseSearch.GCvote: " + e.toString()); } } return caches; } public cgCacheWrap parseMapJSON(String url, String data) { if (data == null || data.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.parseMapJSON: No page given"); return null; } final cgCacheWrap caches = new cgCacheWrap(); caches.url = url; try { final JSONObject yoDawg = new JSONObject(data); final String json = yoDawg.getString("d"); if (json == null || json.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.parseMapJSON: No JSON inside JSON"); return null; } final JSONObject dataJSON = new JSONObject(json); final JSONObject extra = dataJSON.getJSONObject("cs"); if (extra != null && extra.length() > 0) { int count = extra.getInt("count"); if (count > 0 && extra.has("cc")) { final JSONArray cachesData = extra.getJSONArray("cc"); if (cachesData != null && cachesData.length() > 0) { JSONObject oneCache = null; for (int i = 0; i < count; i++) { oneCache = cachesData.getJSONObject(i); if (oneCache == null) { break; } final cgCache cacheToAdd = new cgCache(); cacheToAdd.reliableLatLon = false; cacheToAdd.geocode = oneCache.getString("gc"); cacheToAdd.latitude = oneCache.getDouble("lat"); cacheToAdd.longitude = oneCache.getDouble("lon"); cacheToAdd.name = oneCache.getString("nn"); cacheToAdd.found = oneCache.getBoolean("f"); cacheToAdd.own = oneCache.getBoolean("o"); cacheToAdd.disabled = !oneCache.getBoolean("ia"); int ctid = oneCache.getInt("ctid"); if (ctid == 2) { cacheToAdd.type = "traditional"; } else if (ctid == 3) { cacheToAdd.type = "multi"; } else if (ctid == 4) { cacheToAdd.type = "virtual"; } else if (ctid == 5) { cacheToAdd.type = "letterbox"; } else if (ctid == 6) { cacheToAdd.type = "event"; } else if (ctid == 8) { cacheToAdd.type = "mystery"; } else if (ctid == 11) { cacheToAdd.type = "webcam"; } else if (ctid == 13) { cacheToAdd.type = "cito"; } else if (ctid == 137) { cacheToAdd.type = "earth"; } else if (ctid == 453) { cacheToAdd.type = "mega"; } else if (ctid == 1858) { cacheToAdd.type = "wherigo"; } else if (ctid == 3653) { cacheToAdd.type = "lost"; } caches.cacheList.add(cacheToAdd); } } } else { Log.w(cgSettings.tag, "There are no caches in viewport"); } caches.totalCnt = caches.cacheList.size(); } } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.parseMapJSON: " + e.toString()); } return caches; } public cgCacheWrap parseCache(String page, int reason) { if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.parseCache: No page given"); return null; } final Pattern patternGeocode = Pattern.compile( "<meta name=\"og:url\" content=\"[^\"]+/(GC[0-9A-Z]+)\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternCacheId = Pattern.compile("/seek/log\\.aspx\\?ID=(\\d+)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternCacheGuid = Pattern.compile( "<link rel=\"alternate\" href=\"[^\"]*/datastore/rss_galleryimages\\.ashx\\?guid=([0-9a-z\\-]+)\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternType = Pattern.compile( "<img src=\"[^\"]*/WptTypes/\\d+\\.gif\" alt=\"([^\"]+)\" (title=\"[^\"]*\" )?width=\"32\" height=\"32\"[^>]*>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternName = Pattern.compile( "<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_CacheName\">([^<]+)<\\/span>[^<]*<\\/h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternSize = Pattern.compile( "<div class=\"CacheSize[^\"]*\">[^<]*<p[^>]*>[^S]*Size[^:]*:[^<]*<span[^>]*>[^<]*<img src=\"[^\"]*/icons/container/[a-z_]+\\.gif\" alt=\"Size: ([^\"]+)\"[^>]*>[^<]*<small>[^<]*</small>[^<]*</span>[^<]*</p>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternDifficulty = Pattern.compile( "<span id=\"ctl00_ContentBody_uxLegendScale\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\" alt=\"[^\"]+\"[^>]*>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternTerrain = Pattern.compile( "<span id=\"ctl00_ContentBody_Localize6\"[^>]*>[^<]*<img src=\"[^\"]*/images/stars/stars([0-9_]+)\\.gif\" alt=\"[^\"]+\"[^>]*>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternOwner = Pattern.compile( "<span class=\"minorCacheDetails\">[^\\w]*An?([^\\w]*Event)?[^\\w]*cache[^\\w]*by[^<]*<a href=\"[^\"]+\">([^<]+)</a>[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternOwnerReal = Pattern.compile( "<a id=\"ctl00_ContentBody_uxFindLinksHiddenByThisUser\" href=\"[^\"]*/seek/nearest\\.aspx\\?u=*([^\"]+)\">[^<]+</a>", Pattern.CASE_INSENSITIVE); final Pattern patternHidden = Pattern.compile( "<span[^>]*>[^\\w]*Hidden[^:]*:[^\\d]*((\\d+)\\/(\\d+)\\/(\\d+))[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternHiddenEvent = Pattern.compile( "<span[^>]*>[^\\w]*Event[^\\w]*Date[^:]*:[^\\w]*[a-zA-Z]+,[^\\d]*((\\d+)[^\\w]*(\\w+)[^\\d]*(\\d+))[^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternFavourite = Pattern.compile( "<a id=\"uxFavContainerLink\"[^>]*>[^<]*<div[^<]*<span class=\"favorite-value\">[^\\d]*([0-9]+)[^\\d^<]*</span>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternFound = Pattern.compile( "<p>[^<]*<a id=\"ctl00_ContentBody_hlFoundItLog\"[^<]*<img src=\".*/images/stockholm/16x16/check\\.gif\"[^>]*>[^<]*</a>[^<]*</p>", Pattern.CASE_INSENSITIVE); final Pattern patternLatLon = Pattern.compile( "<span id=\"ctl00_ContentBody_LatLon\"[^>]*>(<b>)?([^<]*)(<\\/b>)?<\\/span>", Pattern.CASE_INSENSITIVE); final Pattern patternLocation = Pattern.compile("<span id=\"ctl00_ContentBody_Location\"[^>]*>In ([^<]*)", Pattern.CASE_INSENSITIVE); final Pattern patternHint = Pattern.compile( "<p>([^<]*<strong>)?[^\\w]*Additional Hints([^<]*<\\/strong>)?[^\\(]*\\(<a[^>]+>Encrypt</a>\\)[^<]*<\\/p>[^<]*<div id=\"div_hint\"[^>]*>(.*)</div>[^<]*<div id=[\\'|\"]dk[\\'|\"]", Pattern.CASE_INSENSITIVE); final Pattern patternDescShort = Pattern.compile( "<div class=\"UserSuppliedContent\">[^<]*<span id=\"ctl00_ContentBody_ShortDescription\"[^>]*>((?:(?!</span>[^\\w^<]*</div>).)*)</span>[^\\w^<]*</div>", Pattern.CASE_INSENSITIVE); final Pattern patternDesc = Pattern.compile( "<div class=\"UserSuppliedContent\">[^<]*<span id=\"ctl00_ContentBody_LongDescription\"[^>]*>((?:(?!</span>[^\\w^<]*</div>).)*)</span>[^<]*</div>[^<]*<p>[^<]*</p>[^<]*<p>[^<]*<strong>[^\\w]*Additional Hints</strong>", Pattern.CASE_INSENSITIVE); final Pattern patternCountLogs = Pattern.compile( "<span id=\"ctl00_ContentBody_lblFindCounts\"><p>(.*)<\\/p><\\/span>", Pattern.CASE_INSENSITIVE); final Pattern patternCountLog = Pattern.compile( " src=\"\\/images\\/icons\\/([^\\.]*).gif\" alt=\"[^\"]*\" title=\"[^\"]*\" />([0-9]*)[^0-9]+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternLogs = Pattern.compile( "<table class=\"LogsTable[^\"]*\"[^>]*>[^<]*<tr>(.*)</tr>[^<]*</table>[^<]*<p", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternLog = Pattern.compile( "<td[^>]*>[^<]*<strong>[^<]*<img src=\"[^\"]*/images/icons/([^\\.]+)\\.[a-z]{2,5}\"[^>]*> ([a-zA-Z]+) (\\d+)(, (\\d+))? by <a href=[^>]+>([^<]+)</a>[<^]*</strong>([^\\(]*\\((\\d+) found\\))?(<br[^>]*>)+((?:(?!<small>).)*)(<br[^>]*>)+<small>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Pattern patternAttributes = Pattern.compile( "<h3 class=\"WidgetHeader\">[^<]*<img[^>]+>[^\\w]*Attributes[^<]*</h3>[^<]*<div class=\"WidgetBody\">(([^<]*<img src=\"[^\"]+\" alt=\"[^\"]+\"[^>]*>)+)[^<]*<p", Pattern.CASE_INSENSITIVE); final Pattern patternAttributesInside = Pattern.compile("[^<]*<img src=\"([^\"]+)\" alt=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE); final Pattern patternSpoilers = Pattern.compile( "<span id=\"ctl00_ContentBody_Images\">((<a href=\"[^\"]+\"[^>]*>[^<]*<img[^>]+>[^<]*<span>[^>]+</span>[^<]*</a>[^<]*<br[^>]*>([^<]*(<br[^>]*>)+)?)+)[^<]*</span>", Pattern.CASE_INSENSITIVE); final Pattern patternSpoilersInside = Pattern.compile( "[^<]*<a href=\"([^\"]+)\"[^>]*>[^<]*<img[^>]+>[^<]*<span>([^>]+)</span>[^<]*</a>[^<]*<br[^>]*>(([^<]*)(<br[^<]*>)+)?", Pattern.CASE_INSENSITIVE); final Pattern patternInventory = Pattern.compile( "<span id=\"ctl00_ContentBody_uxTravelBugList_uxInventoryLabel\">[^\\w]*Inventory[^<]*</span>[^<]*</h3>[^<]*<div class=\"WidgetBody\">([^<]*<ul>(([^<]*<li>[^<]*<a href=\"[^\"]+\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>[^<]+<\\/span>[^<]*<\\/a>[^<]*<\\/li>)+)[^<]*<\\/ul>)?", Pattern.CASE_INSENSITIVE); final Pattern patternInventoryInside = Pattern.compile( "[^<]*<li>[^<]*<a href=\"[a-z0-9\\-\\_\\.\\?\\/\\:\\@]*\\/track\\/details\\.aspx\\?guid=([0-9a-z\\-]+)[^\"]*\"[^>]*>[^<]*<img src=\"[^\"]+\"[^>]*>[^<]*<span>([^<]+)<\\/span>[^<]*<\\/a>[^<]*<\\/li>", Pattern.CASE_INSENSITIVE); final cgCacheWrap caches = new cgCacheWrap(); final cgCache cache = new cgCache(); if (page.indexOf("Cache is Unpublished") > -1) { caches.error = "cache was unpublished"; return caches; } if (page.indexOf("Sorry, the owner of this listing has made it viewable to Premium Members only.") != -1) { caches.error = "requested cache is for premium members only"; return caches; } if (page.indexOf("has chosen to make this cache listing visible to Premium Members only.") != -1) { caches.error = "requested cache is for premium members only"; return caches; } if (page.indexOf("<li>This cache is temporarily unavailable.") != -1) { cache.disabled = true; } else { cache.disabled = false; } if (page.indexOf("<li>This cache has been archived,") != -1) { cache.archived = true; } else { cache.archived = false; } if (page.indexOf("<p class=\"Warning\">This is a Premium Member Only cache.</p>") != -1) { cache.members = true; } else { cache.members = false; } cache.reason = reason; // cache geocode try { final Matcher matcherGeocode = patternGeocode.matcher(page); while (matcherGeocode.find()) { if (matcherGeocode.groupCount() > 0) { cache.geocode = (String) matcherGeocode.group(1); } } } catch (Exception e) { // failed to parse cache geocode Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache geocode"); } // cache id try { final Matcher matcherCacheId = patternCacheId.matcher(page); while (matcherCacheId.find()) { if (matcherCacheId.groupCount() > 0) { cache.cacheid = (String) matcherCacheId.group(1); } } } catch (Exception e) { // failed to parse cache id Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache id"); } // cache guid try { final Matcher matcherCacheGuid = patternCacheGuid.matcher(page); while (matcherCacheGuid.find()) { if (matcherCacheGuid.groupCount() > 0) { cache.guid = (String) matcherCacheGuid.group(1); } } } catch (Exception e) { // failed to parse cache guid Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache guid"); } // name try { final Matcher matcherName = patternName.matcher(page); while (matcherName.find()) { if (matcherName.groupCount() > 0) { cache.name = Html.fromHtml(matcherName.group(1)).toString(); } } } catch (Exception e) { // failed to parse cache name Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache name"); } // owner real name try { final Matcher matcherOwnerReal = patternOwnerReal.matcher(page); while (matcherOwnerReal.find()) { if (matcherOwnerReal.groupCount() > 0) { cache.ownerReal = URLDecoder.decode(matcherOwnerReal.group(1)); } } } catch (Exception e) { // failed to parse owner real name Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache owner real name"); } final String username = settings.getUsername(); if (cache.ownerReal != null && username != null && cache.ownerReal.equalsIgnoreCase(username)) { cache.own = true; } int pos = -1; String tableInside = page; pos = tableInside.indexOf("id=\"cacheDetails\""); if (pos == -1) { Log.e(cgSettings.tag, "cgeoBase.parseCache: ID \"cacheDetails\" not found on page"); return null; } tableInside = tableInside.substring(pos); pos = tableInside.indexOf("<div class=\"CacheInformationTable\""); if (pos == -1) { Log.e(cgSettings.tag, "cgeoBase.parseCache: ID \"CacheInformationTable\" not found on page"); return null; } tableInside = tableInside.substring(0, pos); if (tableInside != null && tableInside.length() > 0) { // cache terrain try { final Matcher matcherTerrain = patternTerrain.matcher(tableInside); while (matcherTerrain.find()) { if (matcherTerrain.groupCount() > 0) { cache.terrain = new Float( Pattern.compile("_").matcher(matcherTerrain.group(1)).replaceAll(".")); } } } catch (Exception e) { // failed to parse terrain Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache terrain"); } // cache difficulty try { final Matcher matcherDifficulty = patternDifficulty.matcher(tableInside); while (matcherDifficulty.find()) { if (matcherDifficulty.groupCount() > 0) { cache.difficulty = new Float( Pattern.compile("_").matcher(matcherDifficulty.group(1)).replaceAll(".")); } } } catch (Exception e) { // failed to parse difficulty Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache difficulty"); } // owner try { final Matcher matcherOwner = patternOwner.matcher(tableInside); while (matcherOwner.find()) { if (matcherOwner.groupCount() > 0) { cache.owner = Html.fromHtml(matcherOwner.group(2)).toString(); } } } catch (Exception e) { // failed to parse owner Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache owner"); } // hidden try { final Matcher matcherHidden = patternHidden.matcher(tableInside); while (matcherHidden.find()) { if (matcherHidden.groupCount() > 0) { cache.hidden = dateIn.parse(matcherHidden.group(1)); } } } catch (Exception e) { // failed to parse cache hidden date Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache hidden date"); } if (cache.hidden == null) { // event date try { final Matcher matcherHiddenEvent = patternHiddenEvent.matcher(tableInside); while (matcherHiddenEvent.find()) { if (matcherHiddenEvent.groupCount() > 0) { cache.hidden = dateEvIn.parse(matcherHiddenEvent.group(1)); } } } catch (Exception e) { // failed to parse cache event date Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache event date"); } } // favourite try { final Matcher matcherFavourite = patternFavourite.matcher(tableInside); while (matcherFavourite.find()) { if (matcherFavourite.groupCount() > 0) { cache.favouriteCnt = Integer.parseInt(matcherFavourite.group(1)); } } } catch (Exception e) { // failed to parse favourite count Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse favourite count"); } // cache size try { final Matcher matcherSize = patternSize.matcher(tableInside); while (matcherSize.find()) { if (matcherSize.groupCount() > 0) { cache.size = matcherSize.group(1).toLowerCase(); } } } catch (Exception e) { // failed to parse size Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache size"); } } // cache found try { final Matcher matcherFound = patternFound.matcher(page); while (matcherFound.find()) { if (matcherFound.group() != null && matcherFound.group().length() > 0) { cache.found = true; } } } catch (Exception e) { // failed to parse found Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse found"); } // cache type try { final Matcher matcherType = patternType.matcher(page); while (matcherType.find()) { if (matcherType.groupCount() > 0) { cache.type = cacheTypes.get(matcherType.group(1).toLowerCase()); } } } catch (Exception e) { // failed to parse type Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache type"); } // latitude and logitude try { final Matcher matcherLatLon = patternLatLon.matcher(page); while (matcherLatLon.find()) { if (matcherLatLon.groupCount() > 0) { cache.latlon = matcherLatLon.group(2); // first is <b> HashMap<String, Object> tmp = this.parseLatlon(cache.latlon); if (tmp.size() > 0) { cache.latitude = (Double) tmp.get("latitude"); cache.longitude = (Double) tmp.get("longitude"); cache.latitudeString = (String) tmp.get("latitudeString"); cache.longitudeString = (String) tmp.get("longitudeString"); cache.reliableLatLon = true; } tmp = null; } } } catch (Exception e) { // failed to parse latitude and/or longitude Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache coordinates"); } // cache location try { final Matcher matcherLocation = patternLocation.matcher(page); while (matcherLocation.find()) { if (matcherLocation.groupCount() > 0) { cache.location = matcherLocation.group(1); } } } catch (Exception e) { // failed to parse location Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache location"); } // cache hint try { final Matcher matcherHint = patternHint.matcher(page); while (matcherHint.find()) { if (matcherHint.groupCount() > 2 && matcherHint.group(3) != null) { // replace linebreak and paragraph tags String hint = Pattern.compile("<(br|p)[^>]*>").matcher(matcherHint.group(3)).replaceAll("\n"); if (hint != null) { cache.hint = hint.replaceAll(Pattern.quote("</p>"), "").trim(); } } } } catch (Exception e) { // failed to parse hint Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache hint"); } /* // short info debug Log.d(cgSettings.tag, "gc-code: " + cache.geocode); Log.d(cgSettings.tag, "id: " + cache.cacheid); Log.d(cgSettings.tag, "guid: " + cache.guid); Log.d(cgSettings.tag, "name: " + cache.name); Log.d(cgSettings.tag, "terrain: " + cache.terrain); Log.d(cgSettings.tag, "difficulty: " + cache.difficulty); Log.d(cgSettings.tag, "owner: " + cache.owner); Log.d(cgSettings.tag, "owner (real): " + cache.ownerReal); Log.d(cgSettings.tag, "hidden: " + dateOutShort.format(cache.hidden)); Log.d(cgSettings.tag, "favorite: " + cache.favouriteCnt); Log.d(cgSettings.tag, "size: " + cache.size); if (cache.found) { Log.d(cgSettings.tag, "found!"); } else { Log.d(cgSettings.tag, "not found"); } Log.d(cgSettings.tag, "type: " + cache.type); Log.d(cgSettings.tag, "latitude: " + String.format("%.6f", cache.latitude)); Log.d(cgSettings.tag, "longitude: " + String.format("%.6f", cache.longitude)); Log.d(cgSettings.tag, "location: " + cache.location); Log.d(cgSettings.tag, "hint: " + cache.hint); */ // cache short description try { final Matcher matcherDescShort = patternDescShort.matcher(page); while (matcherDescShort.find()) { if (matcherDescShort.groupCount() > 0) { cache.shortdesc = matcherDescShort.group(1).trim(); } } } catch (Exception e) { // failed to parse short description Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache short description"); } // cache description try { final Matcher matcherDesc = patternDesc.matcher(page); while (matcherDesc.find()) { if (matcherDesc.groupCount() > 0) { cache.description = matcherDesc.group(1); } } } catch (Exception e) { // failed to parse short description Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache description"); } // cache attributes try { final Matcher matcherAttributes = patternAttributes.matcher(page); while (matcherAttributes.find()) { if (matcherAttributes.groupCount() > 0) { final String attributesPre = matcherAttributes.group(1); final Matcher matcherAttributesInside = patternAttributesInside.matcher(attributesPre); while (matcherAttributesInside.find()) { if (matcherAttributesInside.groupCount() > 1 && matcherAttributesInside.group(2).equalsIgnoreCase("blank") != true) { if (cache.attributes == null) { cache.attributes = new ArrayList<String>(); } // by default, use the tooltip of the attribute String attribute = matcherAttributesInside.group(2).toLowerCase(); // if the image name can be recognized, use the image name as attribute String imageName = matcherAttributesInside.group(1).trim(); if (imageName.length() > 0) { int start = imageName.lastIndexOf('/'); int end = imageName.lastIndexOf('.'); if (start >= 0 && end >= 0) { attribute = imageName.substring(start + 1, end).replace('-', '_'); } } cache.attributes.add(attribute); } } } } } catch (Exception e) { // failed to parse cache attributes Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache attributes"); } // cache spoilers try { final Matcher matcherSpoilers = patternSpoilers.matcher(page); while (matcherSpoilers.find()) { if (matcherSpoilers.groupCount() > 0) { final String spoilersPre = matcherSpoilers.group(1); final Matcher matcherSpoilersInside = patternSpoilersInside.matcher(spoilersPre); while (matcherSpoilersInside.find()) { if (matcherSpoilersInside.groupCount() > 0) { final cgSpoiler spoiler = new cgSpoiler(); spoiler.url = matcherSpoilersInside.group(1); if (matcherSpoilersInside.group(2) != null) { spoiler.title = matcherSpoilersInside.group(2); } if (matcherSpoilersInside.group(4) != null) { spoiler.description = matcherSpoilersInside.group(4); } if (cache.spoilers == null) { cache.spoilers = new ArrayList<cgSpoiler>(); } cache.spoilers.add(spoiler); } } } } } catch (Exception e) { // failed to parse cache spoilers Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache spoilers"); } // cache inventory try { cache.inventoryItems = 0; final Matcher matcherInventory = patternInventory.matcher(page); while (matcherInventory.find()) { if (cache.inventory == null) { cache.inventory = new ArrayList<cgTrackable>(); } if (matcherInventory.groupCount() > 1) { final String inventoryPre = matcherInventory.group(2); if (inventoryPre != null && inventoryPre.length() > 0) { final Matcher matcherInventoryInside = patternInventoryInside.matcher(inventoryPre); while (matcherInventoryInside.find()) { if (matcherInventoryInside.groupCount() > 0) { final cgTrackable inventoryItem = new cgTrackable(); inventoryItem.guid = matcherInventoryInside.group(1); inventoryItem.name = matcherInventoryInside.group(2); cache.inventory.add(inventoryItem); cache.inventoryItems++; } } } } } } catch (Exception e) { // failed to parse cache inventory Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache inventory (2)"); } // cache logs counts try { final Matcher matcherLogCounts = patternCountLogs.matcher(page); while (matcherLogCounts.find()) { if (matcherLogCounts.groupCount() > 0) { final String[] logs = matcherLogCounts.group(1).split("<img"); final int logsCnt = logs.length; for (int k = 1; k < logsCnt; k++) { Integer type = null; Integer count = null; final Matcher matcherLog = patternCountLog.matcher(logs[k]); if (matcherLog.find()) { String typeStr = matcherLog.group(1); String countStr = matcherLog.group(2); if (typeStr != null && typeStr.length() > 0) { if (logTypes.containsKey(typeStr.toLowerCase()) == true) { type = logTypes.get(typeStr.toLowerCase()); } } if (countStr != null && countStr.length() > 0) { count = Integer.parseInt(countStr); } if (type != null && count != null) { cache.logCounts.put(type, count); } } } } } } catch (Exception e) { // failed to parse logs Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache log count"); } // cache logs try { final Matcher matcherLogs = patternLogs.matcher(page); while (matcherLogs.find()) { if (matcherLogs.groupCount() > 0) { final String[] logs = matcherLogs.group(1).split("</tr><tr>"); final int logsCnt = logs.length; for (int k = 0; k < logsCnt; k++) { final Matcher matcherLog = patternLog.matcher(logs[k]); if (matcherLog.find()) { final cgLog logDone = new cgLog(); String logTmp = matcherLog.group(10); int day = -1; try { day = Integer.parseInt(matcherLog.group(3)); } catch (Exception e) { Log.w(cgSettings.tag, "Failed to parse logs date (day): " + e.toString()); } int month = -1; // January | February | March | April | May | June | July | August | September | October | November | December if (matcherLog.group(2).equalsIgnoreCase("January")) { month = 0; } else if (matcherLog.group(2).equalsIgnoreCase("February")) { month = 1; } else if (matcherLog.group(2).equalsIgnoreCase("March")) { month = 2; } else if (matcherLog.group(2).equalsIgnoreCase("April")) { month = 3; } else if (matcherLog.group(2).equalsIgnoreCase("May")) { month = 4; } else if (matcherLog.group(2).equalsIgnoreCase("June")) { month = 5; } else if (matcherLog.group(2).equalsIgnoreCase("July")) { month = 6; } else if (matcherLog.group(2).equalsIgnoreCase("August")) { month = 7; } else if (matcherLog.group(2).equalsIgnoreCase("September")) { month = 8; } else if (matcherLog.group(2).equalsIgnoreCase("October")) { month = 9; } else if (matcherLog.group(2).equalsIgnoreCase("November")) { month = 10; } else if (matcherLog.group(2).equalsIgnoreCase("December")) { month = 11; } else { Log.w(cgSettings.tag, "Failed to parse logs date (month)."); } int year = -1; final String yearPre = matcherLog.group(5); if (yearPre == null) { Calendar date = Calendar.getInstance(); year = date.get(Calendar.YEAR); } else { try { year = Integer.parseInt(matcherLog.group(5)); } catch (Exception e) { Log.w(cgSettings.tag, "Failed to parse logs date (year): " + e.toString()); } } long logDate; if (year > 0 && month >= 0 && day > 0) { Calendar date = Calendar.getInstance(); date.set(year, month, day, 12, 0, 0); logDate = date.getTimeInMillis(); logDate = (long) (Math.ceil(logDate / 1000)) * 1000; } else { logDate = 0; } if (logTypes.containsKey(matcherLog.group(1).toLowerCase()) == true) { logDone.type = logTypes.get(matcherLog.group(1).toLowerCase()); } else { logDone.type = logTypes.get("icon_note"); } logDone.author = Html.fromHtml(matcherLog.group(6)).toString(); logDone.date = logDate; if (matcherLog.group(8) != null) { logDone.found = new Integer(matcherLog.group(8)); } logDone.log = logTmp; if (cache.logs == null) { cache.logs = new ArrayList<cgLog>(); } cache.logs.add(logDone); } } } } } catch (Exception e) { // failed to parse logs Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache logs"); } int wpBegin = 0; int wpEnd = 0; wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">"); if (wpBegin != -1) { // parse waypoints final Pattern patternWpType = Pattern.compile("\\/wpttypes\\/sm\\/(.+)\\.jpg", Pattern.CASE_INSENSITIVE); final Pattern patternWpPrefixOrLookupOrLatlon = Pattern .compile(">([^<]*<[^>]+>)?([^<]+)(<[^>]+>[^<]*)?<\\/td>", Pattern.CASE_INSENSITIVE); final Pattern patternWpName = Pattern.compile(">[^<]*<a[^>]+>([^<]*)<\\/a>", Pattern.CASE_INSENSITIVE); final Pattern patternWpNote = Pattern.compile("colspan=\"6\">(.*)<\\/td>", Pattern.CASE_INSENSITIVE); String wpList = page.substring(wpBegin); wpEnd = wpList.indexOf("</p>"); if (wpEnd > -1 && wpEnd <= wpList.length()) { wpList = wpList.substring(0, wpEnd); } if (wpList.indexOf("No additional waypoints to display.") == -1) { wpEnd = wpList.indexOf("</table>"); wpList = wpList.substring(0, wpEnd); wpBegin = wpList.indexOf("<tbody>"); wpEnd = wpList.indexOf("</tbody>"); if (wpBegin >= 0 && wpEnd >= 0 && wpEnd <= wpList.length()) { wpList = wpList.substring(wpBegin + 7, wpEnd); } final String[] wpItems = wpList.split("<tr"); String[] wp; for (int j = 1; j < wpItems.length; j++) { final cgWaypoint waypoint = new cgWaypoint(); wp = wpItems[j].split("<td"); // waypoint type try { final Matcher matcherWpType = patternWpType.matcher(wp[3]); while (matcherWpType.find()) { if (matcherWpType.groupCount() > 0) { waypoint.type = matcherWpType.group(1); if (waypoint.type != null) { waypoint.type = waypoint.type.trim(); } } } } catch (Exception e) { // failed to parse type Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint type"); } // waypoint prefix try { final Matcher matcherWpPrefix = patternWpPrefixOrLookupOrLatlon.matcher(wp[4]); while (matcherWpPrefix.find()) { if (matcherWpPrefix.groupCount() > 1) { waypoint.prefix = matcherWpPrefix.group(2); if (waypoint.prefix != null) { waypoint.prefix = waypoint.prefix.trim(); } } } } catch (Exception e) { // failed to parse prefix Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint prefix"); } // waypoint lookup try { final Matcher matcherWpLookup = patternWpPrefixOrLookupOrLatlon.matcher(wp[5]); while (matcherWpLookup.find()) { if (matcherWpLookup.groupCount() > 1) { waypoint.lookup = matcherWpLookup.group(2); if (waypoint.lookup != null) { waypoint.lookup = waypoint.lookup.trim(); } } } } catch (Exception e) { // failed to parse lookup Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint lookup"); } // waypoint name try { final Matcher matcherWpName = patternWpName.matcher(wp[6]); while (matcherWpName.find()) { if (matcherWpName.groupCount() > 0) { waypoint.name = matcherWpName.group(1); if (waypoint.name != null) { waypoint.name = waypoint.name.trim(); } } } } catch (Exception e) { // failed to parse name Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint name"); } // waypoint latitude and logitude try { final Matcher matcherWpLatLon = patternWpPrefixOrLookupOrLatlon.matcher(wp[7]); while (matcherWpLatLon.find()) { if (matcherWpLatLon.groupCount() > 1) { waypoint.latlon = Html.fromHtml(matcherWpLatLon.group(2)).toString(); final HashMap<String, Object> tmp = this.parseLatlon(waypoint.latlon); if (tmp.size() > 0) { waypoint.latitude = (Double) tmp.get("latitude"); waypoint.longitude = (Double) tmp.get("longitude"); waypoint.latitudeString = (String) tmp.get("latitudeString"); waypoint.longitudeString = (String) tmp.get("longitudeString"); } } } } catch (Exception e) { // failed to parse latitude and/or longitude Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint coordinates"); } j++; if (wpItems.length > j) { wp = wpItems[j].split("<td"); } // waypoint note try { final Matcher matcherWpNote = patternWpNote.matcher(wp[3]); while (matcherWpNote.find()) { if (matcherWpNote.groupCount() > 0) { waypoint.note = matcherWpNote.group(1); if (waypoint.note != null) { waypoint.note = waypoint.note.trim(); } } } } catch (Exception e) { // failed to parse note Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse waypoint note"); } if (cache.waypoints == null) cache.waypoints = new ArrayList<cgWaypoint>(); cache.waypoints.add(waypoint); } } } if (cache.latitude != null && cache.longitude != null) { cache.elevation = getElevation(cache.latitude, cache.longitude); } final cgRating rating = getRating(cache.guid, cache.geocode); if (rating != null) { cache.rating = rating.rating; cache.votes = rating.votes; cache.myVote = rating.myVote; } cache.updated = System.currentTimeMillis(); cache.detailedUpdate = System.currentTimeMillis(); cache.detailed = true; caches.cacheList.add(cache); return caches; } public cgRating getRating(String guid, String geocode) { ArrayList<String> guids = null; ArrayList<String> geocodes = null; if (guid != null && guid.length() > 0) { guids = new ArrayList<String>(); guids.add(guid); } else if (geocode != null && geocode.length() > 0) { geocodes = new ArrayList<String>(); geocodes.add(geocode); } else { return null; } final HashMap<String, cgRating> ratings = getRating(guids, geocodes); if (ratings != null) { final Set<String> ratingKeys = ratings.keySet(); for (String ratingKey : ratingKeys) { return ratings.get(ratingKey); } } return null; } public HashMap<String, cgRating> getRating(ArrayList<String> guids, ArrayList<String> geocodes) { if (guids == null && geocodes == null) { return null; } final HashMap<String, cgRating> ratings = new HashMap<String, cgRating>(); try { final HashMap<String, String> params = new HashMap<String, String>(); if (settings.isLogin() == true) { final HashMap<String, String> login = settings.getGCvoteLogin(); if (login != null) { params.put("userName", login.get("username")); params.put("password", login.get("password")); } } if (guids != null && guids.size() > 0) { params.put("cacheIds", implode(",", guids.toArray())); } else { params.put("waypoints", implode(",", geocodes.toArray())); } params.put("version", "cgeo"); final String votes = request(false, "gcvote.com", "/getVotes.php", "GET", params, false, false, false) .getData(); if (votes == null) { return null; } final Pattern patternLogIn = Pattern.compile("loggedIn='([^']+)'", Pattern.CASE_INSENSITIVE); final Pattern patternGuid = Pattern.compile("cacheId='([^']+)'", Pattern.CASE_INSENSITIVE); final Pattern patternRating = Pattern.compile("voteAvg='([0-9\\.]+)'", Pattern.CASE_INSENSITIVE); final Pattern patternVotes = Pattern.compile("voteCnt='([0-9]+)'", Pattern.CASE_INSENSITIVE); final Pattern patternVote = Pattern.compile("voteUser='([0-9\\.]+)'", Pattern.CASE_INSENSITIVE); String voteData = null; final Pattern patternVoteElement = Pattern.compile("<vote ([^>]+)>", Pattern.CASE_INSENSITIVE); final Matcher matcherVoteElement = patternVoteElement.matcher(votes); while (matcherVoteElement.find()) { if (matcherVoteElement.groupCount() > 0) { voteData = matcherVoteElement.group(1); } if (voteData == null) { continue; } String guid = null; cgRating rating = new cgRating(); boolean loggedIn = false; try { final Matcher matcherGuid = patternGuid.matcher(voteData); if (matcherGuid.find()) { if (matcherGuid.groupCount() > 0) { guid = (String) matcherGuid.group(1); } } } catch (Exception e) { Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse guid"); } try { final Matcher matcherLoggedIn = patternLogIn.matcher(votes); if (matcherLoggedIn.find()) { if (matcherLoggedIn.groupCount() > 0) { if (matcherLoggedIn.group(1).equalsIgnoreCase("true") == true) { loggedIn = true; } } } } catch (Exception e) { Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse loggedIn"); } try { final Matcher matcherRating = patternRating.matcher(voteData); if (matcherRating.find()) { if (matcherRating.groupCount() > 0) { rating.rating = Float.parseFloat(matcherRating.group(1)); } } } catch (Exception e) { Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse rating"); } try { final Matcher matcherVotes = patternVotes.matcher(voteData); if (matcherVotes.find()) { if (matcherVotes.groupCount() > 0) { rating.votes = Integer.parseInt(matcherVotes.group(1)); } } } catch (Exception e) { Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse vote count"); } if (loggedIn == true) { try { final Matcher matcherVote = patternVote.matcher(voteData); if (matcherVote.find()) { if (matcherVote.groupCount() > 0) { rating.myVote = Float.parseFloat(matcherVote.group(1)); } } } catch (Exception e) { Log.w(cgSettings.tag, "cgBase.getRating: Failed to parse user's vote"); } } if (guid != null) { ratings.put(guid, rating); } } } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.getRating: " + e.toString()); } return ratings; } public boolean setRating(String guid, int vote) { if (guid == null || guid.length() == 0) { return false; } if (vote < 0 || vote > 5) { return false; } final HashMap<String, String> login = settings.getGCvoteLogin(); if (login == null) { return false; } final HashMap<String, String> params = new HashMap<String, String>(); params.put("userName", login.get("username")); params.put("password", login.get("password")); params.put("cacheId", guid); params.put("voteUser", Integer.toString(vote)); params.put("version", "cgeo"); final String result = request(false, "gcvote.com", "/setVote.php", "GET", params, false, false, false) .getData(); if (result.trim().equalsIgnoreCase("ok") == true) { return true; } return false; } public Long parseGPX(cgeoapplication app, File file, int listId, Handler handler) { cgSearch search = new cgSearch(); long searchId = 0l; try { cgGPXParser GPXparser = new cgGPXParser(app, this, listId, search); searchId = GPXparser.parse(file, 10, handler); if (searchId == 0l) { searchId = GPXparser.parse(file, 11, handler); } } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.parseGPX: " + e.toString()); } Log.i(cgSettings.tag, "Caches found in .gpx file: " + app.getCount(searchId)); return search.getCurrentId(); } public cgTrackable parseTrackable(String page) { if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.parseTrackable: No page given"); return null; } final Pattern patternTrackableId = Pattern.compile( "<a id=\"ctl00_ContentBody_LogLink\" title=\"[^\"]*\" href=\".*log\\.aspx\\?wid=([a-z0-9\\-]+)\"[^>]*>[^<]*</a>", Pattern.CASE_INSENSITIVE); final Pattern patternGeocode = Pattern.compile( "<span id=\"ctl00_ContentBody_BugDetails_BugTBNum\" String=\"[^\"]*\">Use[^<]*<strong>(TB[0-9a-z]+)[^<]*</strong> to reference this item.[^<]*</span>", Pattern.CASE_INSENSITIVE); final Pattern patternName = Pattern.compile( "<h2>([^<]*<img[^>]*>)?[^<]*<span id=\"ctl00_ContentBody_lbHeading\">([^<]+)</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE); final Pattern patternOwner = Pattern.compile( "<dt>[^\\w]*Owner:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugOwner\" title=\"[^\"]*\" href=\"[^\"]*/profile/\\?guid=([a-z0-9\\-]+)\">([^<]+)<\\/a>[^<]*</dd>", Pattern.CASE_INSENSITIVE); final Pattern patternReleased = Pattern.compile( "<dt>[^\\w]*Released:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugReleaseDate\">([^<]+)<\\/span>[^<]*</dd>", Pattern.CASE_INSENSITIVE); final Pattern patternOrigin = Pattern.compile( "<dt>[^\\w]*Origin:[^<]*</dt>[^<]*<dd>[^<]*<span id=\"ctl00_ContentBody_BugDetails_BugOrigin\">([^<]+)<\\/span>[^<]*</dd>", Pattern.CASE_INSENSITIVE); final Pattern patternSpottedCache = Pattern.compile( "<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\" title=\"[^\"]*\" href=\"[^\"]*/seek/cache_details.aspx\\?guid=([a-z0-9\\-]+)\">In ([^<]+)</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE); final Pattern patternSpottedUser = Pattern.compile( "<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\" href=\"[^\"]*/profile/\\?guid=([a-z0-9\\-]+)\">In the hands of ([^<]+).</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE); final Pattern patternSpottedUnknown = Pattern.compile( "<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">Unknown Location[^<]*</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE); final Pattern patternSpottedOwner = Pattern.compile( "<dt>[^\\w]*Recently Spotted:[^<]*</dt>[^<]*<dd>[^<]*<a id=\"ctl00_ContentBody_BugDetails_BugLocation\">In the hands of the owner[^<]*</a>[^<]*</dd>", Pattern.CASE_INSENSITIVE); final Pattern patternGoal = Pattern.compile( "<h3>[^\\w]*Current GOAL[^<]*</h3>[^<]*<p[^>]*>(.*)</p>[^<]*<h3>[^\\w]*About This Item[^<]*</h3>", Pattern.CASE_INSENSITIVE); final Pattern patternDetailsImage = Pattern.compile( "<h3>[^\\w]*About This Item[^<]*</h3>([^<]*<p>([^<]*<img id=\"ctl00_ContentBody_BugDetails_BugImage\" class=\"[^\"]+\" src=\"([^\"]+)\"[^>]*>)?[^<]*</p>)?[^<]*<p[^>]*>(.*)</p>[^<]*<div id=\"ctl00_ContentBody_BugDetails_uxAbuseReport\">", Pattern.CASE_INSENSITIVE); final Pattern patternLogs = Pattern.compile( "<table class=\"TrackableItemLogTable Table\">(.*)<\\/table>[^<]*<ul", Pattern.CASE_INSENSITIVE); final Pattern patternIcon = Pattern.compile( "<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE); final Pattern patternType = Pattern.compile( "<img id=\"ctl00_ContentBody_BugTypeImage\" class=\"TravelBugHeaderIcon\" src=\"[^\"]+\" alt=\"([^\"]+)\"[^>]*>", Pattern.CASE_INSENSITIVE); final Pattern patternDistance = Pattern.compile( "<h4[^>]*[^\\w]*Tracking History \\(([0-9\\.,]+(km|mi))[^\\)]*\\)", Pattern.CASE_INSENSITIVE); final cgTrackable trackable = new cgTrackable(); // trackable geocode try { final Matcher matcherGeocode = patternGeocode.matcher(page); while (matcherGeocode.find()) { if (matcherGeocode.groupCount() > 0) { trackable.geocode = matcherGeocode.group(1).toUpperCase(); } } } catch (Exception e) { // failed to parse trackable geocode Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable geocode"); } // trackable id try { final Matcher matcherTrackableId = patternTrackableId.matcher(page); while (matcherTrackableId.find()) { if (matcherTrackableId.groupCount() > 0) { trackable.guid = matcherTrackableId.group(1); } } } catch (Exception e) { // failed to parse trackable id Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable id"); } // trackable icon try { final Matcher matcherTrackableIcon = patternIcon.matcher(page); while (matcherTrackableIcon.find()) { if (matcherTrackableIcon.groupCount() > 0) { trackable.iconUrl = matcherTrackableIcon.group(1); } } } catch (Exception e) { // failed to parse trackable icon Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable icon"); } // trackable name try { final Matcher matcherName = patternName.matcher(page); while (matcherName.find()) { if (matcherName.groupCount() > 1) { trackable.name = matcherName.group(2); } } } catch (Exception e) { // failed to parse trackable name Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable name"); } // trackable type if (trackable.name != null && trackable.name.length() > 0) { try { final Matcher matcherType = patternType.matcher(page); while (matcherType.find()) { if (matcherType.groupCount() > 0) { trackable.type = matcherType.group(1); } } } catch (Exception e) { // failed to parse trackable type Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable type"); } } // trackable owner name try { final Matcher matcherOwner = patternOwner.matcher(page); while (matcherOwner.find()) { if (matcherOwner.groupCount() > 0) { trackable.ownerGuid = matcherOwner.group(1); trackable.owner = matcherOwner.group(2); } } } catch (Exception e) { // failed to parse trackable owner name Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable owner name"); } // trackable origin try { final Matcher matcherOrigin = patternOrigin.matcher(page); while (matcherOrigin.find()) { if (matcherOrigin.groupCount() > 0) { trackable.origin = matcherOrigin.group(1); } } } catch (Exception e) { // failed to parse trackable origin Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable origin"); } // trackable spotted try { final Matcher matcherSpottedCache = patternSpottedCache.matcher(page); while (matcherSpottedCache.find()) { if (matcherSpottedCache.groupCount() > 0) { trackable.spottedGuid = matcherSpottedCache.group(1); trackable.spottedName = matcherSpottedCache.group(2); trackable.spottedType = cgTrackable.SPOTTED_CACHE; } } final Matcher matcherSpottedUser = patternSpottedUser.matcher(page); while (matcherSpottedUser.find()) { if (matcherSpottedUser.groupCount() > 0) { trackable.spottedGuid = matcherSpottedUser.group(1); trackable.spottedName = matcherSpottedUser.group(2); trackable.spottedType = cgTrackable.SPOTTED_USER; } } final Matcher matcherSpottedUnknown = patternSpottedUnknown.matcher(page); if (matcherSpottedUnknown.find()) { trackable.spottedType = cgTrackable.SPOTTED_UNKNOWN; } final Matcher matcherSpottedOwner = patternSpottedOwner.matcher(page); if (matcherSpottedOwner.find()) { trackable.spottedType = cgTrackable.SPOTTED_OWNER; } } catch (Exception e) { // failed to parse trackable last known place Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable last known place"); } // released try { final Matcher matcherReleased = patternReleased.matcher(page); while (matcherReleased.find()) { if (matcherReleased.groupCount() > 0 && matcherReleased.group(1) != null) { try { if (trackable.released == null) { trackable.released = dateTbIn1.parse(matcherReleased.group(1)); } } catch (Exception e) { // } try { if (trackable.released == null) { trackable.released = dateTbIn2.parse(matcherReleased.group(1)); } } catch (Exception e) { // } } } } catch (Exception e) { // failed to parse trackable released date Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable released date"); } // trackable distance try { final Matcher matcherDistance = patternDistance.matcher(page); while (matcherDistance.find()) { if (matcherDistance.groupCount() > 0) { trackable.distance = parseDistance(matcherDistance.group(1)); } } } catch (Exception e) { // failed to parse trackable distance Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable distance"); } // trackable goal try { final Matcher matcherGoal = patternGoal.matcher(page); while (matcherGoal.find()) { if (matcherGoal.groupCount() > 0) { trackable.goal = matcherGoal.group(1); } } } catch (Exception e) { // failed to parse trackable goal Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable goal"); } // trackable details & image try { final Matcher matcherDetailsImage = patternDetailsImage.matcher(page); while (matcherDetailsImage.find()) { if (matcherDetailsImage.groupCount() > 0) { final String image = matcherDetailsImage.group(3); final String details = matcherDetailsImage.group(4); if (image != null) { trackable.image = image; } if (details != null) { trackable.details = details; } } } } catch (Exception e) { // failed to parse trackable details & image Log.w(cgSettings.tag, "cgeoBase.parseTrackable: Failed to parse trackable details & image"); } // trackable logs try { final Matcher matcherLogs = patternLogs.matcher(page); while (matcherLogs.find()) { if (matcherLogs.groupCount() > 0) { final Pattern patternLog = Pattern.compile("[^>]*>" + "[^<]*<td[^<]*<img src=[\"|'].*\\/icons\\/([^\\.]+)\\.[a-z]{2,5}[\"|'][^>]*> (\\d+).(\\d+).(\\d+)[^<]*</td>" + "[^<]*<td>[^<]*<a href=[^>]+>([^<]+)<.a>([^<]*|[^<]*<a href=[\"|'].*guid=([^\"]*)\">([^<]*)</a>[^<]*)</td>" + "[^<]*<td>[^<]*</td>" + "[^<]*<td[^<]*<a href=[^>]+>[^<]+</a>[^<]*</td>[^<]*</tr>" + "[^<]*<tr[^>]*>[^<]*<td[^>]*>(.*?)</td>[^<]*</tr>.*" + ""); // 1 filename == type // 2 month // 3 date // 4 year // 5 user // 6 action dependent // 7 cache guid // 8 cache name // 9 text final String[] logs = matcherLogs.group(1).split("<tr class=\"Data BorderTop"); final int logsCnt = logs.length; for (int k = 1; k < logsCnt; k++) { final Matcher matcherLog = patternLog.matcher(logs[k]); if (matcherLog.find()) { final cgLog logDone = new cgLog(); String logTmp = matcherLog.group(9); logTmp = Pattern.compile("<p>").matcher(logTmp).replaceAll("\n"); logTmp = Pattern.compile("<br[^>]*>").matcher(logTmp).replaceAll("\n"); logTmp = Pattern.compile("<\\/p>").matcher(logTmp).replaceAll(""); logTmp = Pattern.compile("\r+").matcher(logTmp).replaceAll("\n"); int day = -1; try { day = Integer.parseInt(matcherLog.group(3)); } catch (Exception e) { Log.w(cgSettings.tag, "Failed to parse logs date (day): " + e.toString()); } int month = -1; try { month = Integer.parseInt(matcherLog.group(2)); month -= 1; } catch (Exception e) { Log.w(cgSettings.tag, "Failed to parse logs date (month): " + e.toString()); } int year = -1; try { year = Integer.parseInt(matcherLog.group(4)); } catch (Exception e) { Log.w(cgSettings.tag, "Failed to parse logs date (year): " + e.toString()); } long logDate; if (year > 0 && month >= 0 && day > 0) { Calendar date = Calendar.getInstance(); date.set(year, month, day, 12, 0, 0); logDate = date.getTimeInMillis(); logDate = (long) (Math.ceil(logDate / 1000)) * 1000; } else { logDate = 0; } if (logTypes.containsKey(matcherLog.group(1).toLowerCase()) == true) { logDone.type = logTypes.get(matcherLog.group(1).toLowerCase()); } else { logDone.type = logTypes.get("icon_note"); } logDone.author = Html.fromHtml(matcherLog.group(5)).toString(); logDone.date = logDate; logDone.log = logTmp; if (matcherLog.group(7) != null && matcherLog.group(8) != null) { logDone.cacheGuid = matcherLog.group(7); logDone.cacheName = matcherLog.group(8); } trackable.logs.add(logDone); } } } } } catch (Exception e) { // failed to parse logs Log.w(cgSettings.tag, "cgeoBase.parseCache: Failed to parse cache logs"); } app.saveTrackable(trackable); return trackable; } public ArrayList<Integer> parseTypes(String page) { if (page == null || page.length() == 0) { return null; } final ArrayList<Integer> types = new ArrayList<Integer>(); final Pattern typeBoxPattern = Pattern.compile( "<select name=\"ctl00\\$ContentBody\\$LogBookPanel1\\$ddLogType\" id=\"ctl00_ContentBody_LogBookPanel1_ddLogType\"[^>]*>" + "(([^<]*<option[^>]*>[^<]+</option>)+)[^<]*</select>", Pattern.CASE_INSENSITIVE); final Matcher typeBoxMatcher = typeBoxPattern.matcher(page); String typesText = null; if (typeBoxMatcher.find()) { if (typeBoxMatcher.groupCount() > 0) { typesText = typeBoxMatcher.group(1); } } if (typesText != null) { final Pattern typePattern = Pattern.compile( "<option( selected=\"selected\")? value=\"(\\d+)\">[^<]+</option>", Pattern.CASE_INSENSITIVE); final Matcher typeMatcher = typePattern.matcher(typesText); while (typeMatcher.find()) { if (typeMatcher.groupCount() > 1) { final int type = Integer.parseInt(typeMatcher.group(2)); if (type > 0) { types.add(type); } } } } return types; } public ArrayList<cgTrackableLog> parseTrackableLog(String page) { if (page == null || page.length() == 0) { return null; } final ArrayList<cgTrackableLog> trackables = new ArrayList<cgTrackableLog>(); int startPos = -1; int endPos = -1; startPos = page.indexOf("<table id=\"tblTravelBugs\""); if (startPos == -1) { Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: ID \"tblTravelBugs\" not found on page"); return null; } page = page.substring(startPos); // cut on <table endPos = page.indexOf("</table>"); if (endPos == -1) { Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: end of ID \"tblTravelBugs\" not found on page"); return null; } page = page.substring(0, endPos); // cut on </table> startPos = page.indexOf("<tbody>"); if (startPos == -1) { Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: tbody not found on page"); return null; } page = page.substring(startPos); // cut on <tbody> endPos = page.indexOf("</tbody>"); if (endPos == -1) { Log.e(cgSettings.tag, "cgeoBase.parseTrackableLog: end of tbody not found on page"); return null; } page = page.substring(0, endPos); // cut on </tbody> final Pattern trackablePattern = Pattern .compile("<tr id=\"ctl00_ContentBody_LogBookPanel1_uxTrackables_repTravelBugs_ctl[0-9]+_row\"[^>]*>" + "[^<]*<td>[^<]*<a href=\"[^\"]+\">([A-Z0-9]+)</a>[^<]*</td>[^<]*<td>([^<]+)</td>[^<]*<td>" + "[^<]*<select name=\"ctl00\\$ContentBody\\$LogBookPanel1\\$uxTrackables\\$repTravelBugs\\$ctl([0-9]+)\\$ddlAction\"[^>]*>" + "([^<]*<option value=\"([0-9]+)(_[a-z]+)?\">[^<]+</option>)+" + "[^<]*</select>[^<]*</td>[^<]*</tr>", Pattern.CASE_INSENSITIVE); final Matcher trackableMatcher = trackablePattern.matcher(page); while (trackableMatcher.find()) { if (trackableMatcher.groupCount() > 0) { final cgTrackableLog trackable = new cgTrackableLog(); if (trackableMatcher.group(1) != null) { trackable.trackCode = trackableMatcher.group(1); } else { continue; } if (trackableMatcher.group(2) != null) { trackable.name = Html.fromHtml(trackableMatcher.group(2)).toString(); } else { continue; } if (trackableMatcher.group(3) != null) { trackable.ctl = new Integer(trackableMatcher.group(3)); } else { continue; } if (trackableMatcher.group(5) != null) { trackable.id = new Integer(trackableMatcher.group(5)); } else { continue; } Log.i(cgSettings.tag, "Trackable in inventory (#" + trackable.ctl + "/" + trackable.id + "): " + trackable.trackCode + " - " + trackable.name); trackables.add(trackable); } } return trackables; } public int parseFindCount(String page) { if (page == null || page.length() == 0) { return -1; } int findCount = -1; try { final Pattern findPattern = Pattern.compile("<strong>Caches Found:<\\/strong>([^<]+)<br", Pattern.CASE_INSENSITIVE); final Matcher findMatcher = findPattern.matcher(page); if (findMatcher.find() == true) { if (findMatcher.groupCount() > 0) { String count = findMatcher.group(1); if (count != null) { count = count.trim(); if (count.length() == 0) { findCount = 0; } else { findCount = Integer.parseInt(count); } } } } } catch (Exception e) { Log.w(cgSettings.tag, "cgBase.parseFindCount: " + e.toString()); } return findCount; } public static String stripParagraphs(String text) { if (text == null) { return ""; } final Pattern patternP = Pattern.compile("(<p>|</p>|<br \\/>|<br>)", Pattern.CASE_INSENSITIVE); final Pattern patternP2 = Pattern.compile("([ ]+)", Pattern.CASE_INSENSITIVE); final Matcher matcherP = patternP.matcher(text); final Matcher matcherP2 = patternP2.matcher(text); matcherP.replaceAll(" "); matcherP2.replaceAll(" "); return text.trim(); } public static String stripTags(String text) { if (text == null) { return ""; } final Pattern patternP = Pattern.compile("(<[^>]+>)", Pattern.CASE_INSENSITIVE); final Matcher matcherP = patternP.matcher(text); matcherP.replaceAll(" "); return text.trim(); } public static String capitalizeSentence(String sentence) { if (sentence == null) { return ""; } final String[] word = sentence.split(" "); for (int i = 0; i < word.length; i++) { word[i] = capitalizeWord(word[i]); } return implode(" ", word); } public static String capitalizeWord(String word) { if (word.length() == 0) { return word; } return (word.substring(0, 1).toUpperCase() + word.substring(1).toLowerCase()); } public static Double parseDistance(String dst) { Double distance = null; final Pattern pattern = Pattern.compile("([0-9\\.,]+)[ ]*(km|mi)", Pattern.CASE_INSENSITIVE); final Matcher matcher = pattern.matcher(dst); while (matcher.find()) { if (matcher.groupCount() > 1) { if (matcher.group(2).equalsIgnoreCase("km") == true) { distance = new Double(matcher.group(1)); } else { distance = new Double(matcher.group(1)) / kmInMiles; } } } return distance; } public static double getDistance(Double lat1, Double lon1, Double lat2, Double lon2) { if (lat1 == null || lon1 == null || lat2 == null || lon2 == null) { return 0d; } lat1 *= deg2rad; lon1 *= deg2rad; lat2 *= deg2rad; lon2 *= deg2rad; final double d = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2); final double distance = erad * Math.acos(d); // distance in km if (Double.isNaN(distance) == false && distance > 0) { return distance; } else { return 0d; } } public static Double getHeading(Double lat1, Double lon1, Double lat2, Double lon2) { Double result = new Double(0); int ilat1 = (int) Math.round(0.5 + lat1 * 360000); int ilon1 = (int) Math.round(0.5 + lon1 * 360000); int ilat2 = (int) Math.round(0.5 + lat2 * 360000); int ilon2 = (int) Math.round(0.5 + lon2 * 360000); lat1 *= deg2rad; lon1 *= deg2rad; lat2 *= deg2rad; lon2 *= deg2rad; if (ilat1 == ilat2 && ilon1 == ilon2) { return new Double(result); } else if (ilat1 == ilat2) { if (ilon1 > ilon2) { result = new Double(270); } else { result = new Double(90); } } else if (ilon1 == ilon2) { if (ilat1 > ilat2) { result = new Double(180); } } else { Double c = Math.acos( Math.sin(lat2) * Math.sin(lat1) + Math.cos(lat2) * Math.cos(lat1) * Math.cos(lon2 - lon1)); Double A = Math.asin(Math.cos(lat2) * Math.sin(lon2 - lon1) / Math.sin(c)); result = new Double(A * rad2deg); if (ilat2 > ilat1 && ilon2 > ilon1) { // result don't need change } else if (ilat2 < ilat1 && ilon2 < ilon1) { result = 180f - result; } else if (ilat2 < ilat1 && ilon2 > ilon1) { result = 180f - result; } else if (ilat2 > ilat1 && ilon2 < ilon1) { result += 360f; } } return result; } public HashMap<String, Double> getRadialDistance(Double latitude, Double longitude, Double bearing, Double distance) { final Double rlat1 = latitude * deg2rad; final Double rlon1 = longitude * deg2rad; final Double rbearing = bearing * deg2rad; final Double rdistance = distance / erad; final Double rlat = Math.asin( Math.sin(rlat1) * Math.cos(rdistance) + Math.cos(rlat1) * Math.sin(rdistance) * Math.cos(rbearing)); final Double rlon = rlon1 + Math.atan2(Math.sin(rbearing) * Math.sin(rdistance) * Math.cos(rlat1), Math.cos(rdistance) - Math.sin(rlat1) * Math.sin(rlat)); HashMap<String, Double> result = new HashMap<String, Double>(); result.put("latitude", rlat * rad2deg); result.put("longitude", rlon * rad2deg); return result; } public String getHumanDistance(Float distance) { if (distance == null) { return "?"; } return getHumanDistance(new Double(distance)); } public String getHumanDistance(Double distance) { if (distance == null) { return "?"; } if (settings.units == cgSettings.unitsImperial) { distance *= kmInMiles; if (distance > 100) { return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance))) + " mi"; } else if (distance > 0.5) { return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 10.0) / 10.0)) + " mi"; } else if (distance > 0.1) { return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 100.0) / 100.0)) + " mi"; } else if (distance > 0.05) { return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance * 5280.0))) + " ft"; } else if (distance > 0.01) { return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 5280 * 10.0) / 10.0)) + " ft"; } else { return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 5280 * 100.0) / 100.0)) + " ft"; } } else { if (distance > 100) { return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance))) + " km"; } else if (distance > 10) { return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 10.0) / 10.0)) + " km"; } else if (distance > 1) { return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 100.0) / 100.0)) + " km"; } else if (distance > 0.1) { return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(distance * 1000.0))) + " m"; } else if (distance > 0.01) { return String.format(Locale.getDefault(), "%.1f", new Double(Math.round(distance * 1000.0 * 10.0) / 10.0)) + " m"; } else { return String.format(Locale.getDefault(), "%.2f", new Double(Math.round(distance * 1000.0 * 100.0) / 100.0)) + " m"; } } } public String getHumanSpeed(float speed) { double kph = speed * 3.6; String unit = "kmh"; if (this.settings.units == cgSettings.unitsImperial) { kph *= kmInMiles; unit = "mph"; } if (kph < 10) { return String.format(Locale.getDefault(), "%.1f", new Double((Math.round(kph * 10) / 10))) + " " + unit; } else { return String.format(Locale.getDefault(), "%.0f", new Double(Math.round(kph))) + " " + unit; } } public HashMap<String, Object> parseLatlon(String latlon) { final HashMap<String, Object> result = new HashMap<String, Object>(); final Pattern patternLatlon = Pattern.compile( "([NS])[^\\d]*(\\d+)[^]* (\\d+)\\.(\\d+) ([WE])[^\\d]*(\\d+)[^]* (\\d+)\\.(\\d+)", Pattern.CASE_INSENSITIVE); final Matcher matcherLatlon = patternLatlon.matcher(latlon); while (matcherLatlon.find()) { if (matcherLatlon.groupCount() > 0) { result.put("latitudeString", (String) (matcherLatlon.group(1) + " " + matcherLatlon.group(2) + " " + matcherLatlon.group(3) + "." + matcherLatlon.group(4))); result.put("longitudeString", (String) (matcherLatlon.group(5) + " " + matcherLatlon.group(6) + " " + matcherLatlon.group(7) + "." + matcherLatlon.group(8))); int latNegative = -1; int lonNegative = -1; if (matcherLatlon.group(1).equalsIgnoreCase("N")) { latNegative = 1; } if (matcherLatlon.group(5).equalsIgnoreCase("E")) { lonNegative = 1; } result.put("latitude", new Double(latNegative * (new Float(matcherLatlon.group(2)) + new Float(matcherLatlon.group(3) + "." + matcherLatlon.group(4)) / 60))); result.put("longitude", new Double(lonNegative * (new Float(matcherLatlon.group(6)) + new Float(matcherLatlon.group(7) + "." + matcherLatlon.group(8)) / 60))); } else { Log.w(cgSettings.tag, "cgBase.parseLatlon: Failed to parse coordinates."); } } return result; } public String formatCoordinate(Double coord, String latlon, boolean degrees) { String formatted = ""; if (coord == null) { return formatted; } String worldSide = ""; if (latlon.equalsIgnoreCase("lat") == true) { if (coord >= 0) { // have the blanks here at the direction to avoid one String concatenation worldSide = "N "; } else { worldSide = "S "; } } else if (latlon.equalsIgnoreCase("lon") == true) { if (coord >= 0) { worldSide = "E "; } else { worldSide = "W "; } } coord = Math.abs(coord); if (latlon.equalsIgnoreCase("lat") == true) { if (degrees == true) { formatted = worldSide + String.format(Locale.getDefault(), "%02.0f", Math.floor(coord)) + " " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60)); } else { formatted = worldSide + String.format(Locale.getDefault(), "%02.0f", Math.floor(coord)) + " " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60)); } } else { if (degrees == true) { formatted = worldSide + String.format(Locale.getDefault(), "%03.0f", Math.floor(coord)) + " " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60)); } else { formatted = worldSide + String.format(Locale.getDefault(), "%03.0f", Math.floor(coord)) + " " + String.format(Locale.getDefault(), "%06.3f", ((coord - Math.floor(coord)) * 60)); } } return formatted; } public HashMap<String, Object> parseCoordinate(String coord, String latlon) { final HashMap<String, Object> coords = new HashMap<String, Object>(); final Pattern patternA = Pattern.compile("^([NSWE])[^\\d]*(\\d+)? +(\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE); final Pattern patternB = Pattern.compile("^([NSWE])[^\\d]*(\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE); final Pattern patternC = Pattern.compile("^(-?\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE); final Pattern patternD = Pattern.compile("^([NSWE])[^\\d]*(\\d+)?$", Pattern.CASE_INSENSITIVE); final Pattern patternE = Pattern.compile("^(-?\\d+)?$", Pattern.CASE_INSENSITIVE); final Pattern patternF = Pattern.compile("^([NSWE])[^\\d]*(\\d+)$", Pattern.CASE_INSENSITIVE); final Pattern pattern0 = Pattern.compile("^(-?\\d+)([\\.|,](\\d+))?$", Pattern.CASE_INSENSITIVE); coord = coord.trim().toUpperCase(); final Matcher matcherA = patternA.matcher(coord); final Matcher matcherB = patternB.matcher(coord); final Matcher matcherC = patternC.matcher(coord); final Matcher matcherD = patternD.matcher(coord); final Matcher matcherE = patternE.matcher(coord); final Matcher matcherF = patternF.matcher(coord); final Matcher matcher0 = pattern0.matcher(coord); int latlonNegative; if (matcherA.find() == true && matcherA.groupCount() > 0) { if (matcherA.group(1).equalsIgnoreCase("N") || matcherA.group(1).equalsIgnoreCase("E")) { latlonNegative = 1; } else { latlonNegative = -1; } if (matcherA.groupCount() < 5 || matcherA.group(5) == null) { coords.put("coordinate", new Double(latlonNegative * (new Double(matcherA.group(2)) + new Double(matcherA.group(3) + ".0") / 60))); coords.put("string", matcherA.group(1) + " " + matcherA.group(2) + " " + matcherA.group(3) + ".000"); } else { coords.put("coordinate", new Double(latlonNegative * (new Double(matcherA.group(2)) + new Double(matcherA.group(3) + "." + matcherA.group(5)) / 60))); coords.put("string", matcherA.group(1) + " " + matcherA.group(2) + " " + matcherA.group(3) + "." + matcherA.group(5)); } return coords; } else if (matcherB.find() == true && matcherB.groupCount() > 0) { if (matcherB.group(1).equalsIgnoreCase("N") || matcherB.group(1).equalsIgnoreCase("E")) { latlonNegative = 1; } else { latlonNegative = -1; } if (matcherB.groupCount() < 4 || matcherB.group(4) == null) { coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2) + ".0")))); } else { coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2) + "." + matcherB.group(4))))); } } else if (matcherC.find() == true && matcherC.groupCount() > 0) { if (matcherC.groupCount() < 3 || matcherC.group(3) == null) { coords.put("coordinate", new Double(new Float(matcherC.group(1) + ".0"))); } else { coords.put("coordinate", new Double(new Float(matcherC.group(1) + "." + matcherC.group(3)))); } } else if (matcherD.find() == true && matcherD.groupCount() > 0) { if (matcherD.group(1).equalsIgnoreCase("N") || matcherD.group(1).equalsIgnoreCase("E")) { latlonNegative = 1; } else { latlonNegative = -1; } coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2))))); } else if (matcherE.find() == true && matcherE.groupCount() > 0) { coords.put("coordinate", new Double(matcherE.group(1))); } else if (matcherF.find() == true && matcherF.groupCount() > 0) { if (matcherF.group(1).equalsIgnoreCase("N") || matcherF.group(1).equalsIgnoreCase("E")) { latlonNegative = 1; } else { latlonNegative = -1; } coords.put("coordinate", new Double(latlonNegative * (new Double(matcherB.group(2))))); } else { return null; } if (matcher0.find() == true && matcher0.groupCount() > 0) { String tmpDir = null; Float tmpCoord; if (matcher0.groupCount() < 3 || matcher0.group(3) == null) { tmpCoord = new Float("0.0"); } else { tmpCoord = new Float("0." + matcher0.group(3)); } if (latlon.equalsIgnoreCase("lat")) { if (matcher0.group(1).equals("+")) { tmpDir = "N"; } if (matcher0.group(1).equals("-")) { tmpDir = "S"; } } else if (latlon.equalsIgnoreCase("lon")) { if (matcher0.group(1).equals("+")) { tmpDir = "E"; } if (matcher0.group(1).equals("-")) { tmpDir = "W"; } } coords.put("string", tmpDir + " " + matcher0.group(1) + " " + (Math.round(tmpCoord / (1 / 60) * 1000) * 1000)); return coords; } else { return new HashMap<String, Object>(); } } public Long searchByNextPage(cgSearchThread thread, Long searchId, int reason, boolean showCaptcha) { final String viewstate = app.getViewstate(searchId); final String viewstate1 = app.getViewstate1(searchId); cgCacheWrap caches = new cgCacheWrap(); String url = app.getUrl(searchId); if (url == null || url.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No url found"); return searchId; } if (viewstate == null || viewstate.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No viewstate given"); return searchId; } String host = "www.geocaching.com"; String path = "/"; final String method = "POST"; int dash = -1; if (url.indexOf("http://") > -1) { url = url.substring(7); } dash = url.indexOf("/"); if (dash > -1) { host = url.substring(0, dash); url = url.substring(dash); } else { host = url; url = ""; } dash = url.indexOf("?"); if (dash > -1) { path = url.substring(0, dash); } else { path = url; } final HashMap<String, String> params = new HashMap<String, String>(); params.put("__VIEWSTATE", viewstate); if (viewstate1 != null) { params.put("__VIEWSTATE1", viewstate1); params.put("__VIEWSTATEFIELDCOUNT", "2"); } params.put("__EVENTTARGET", "ctl00$ContentBody$pgrBottom$ctl08"); params.put("__EVENTARGUMENT", ""); String page = request(false, host, path, method, params, false, false, true).getData(); if (checkLogin(page) == false) { int loginState = login(); if (loginState == 1) { page = request(false, host, path, method, params, false, false, true).getData(); } else if (loginState == -3) { Log.i(cgSettings.tag, "Working as guest."); } else { app.setError(searchId, errorRetrieve.get(loginState)); Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: Can not log in geocaching"); return searchId; } } if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No data from server"); return searchId; } caches = parseSearch(thread, url, page, showCaptcha); if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { Log.e(cgSettings.tag, "cgeoBase.searchByNextPage: No cache parsed"); return searchId; } // save to application app.setError(searchId, caches.error); app.setViewstate(searchId, caches.viewstate); app.setViewstate1(searchId, caches.viewstate1); final ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); for (cgCache cache : caches.cacheList) { app.addGeocode(searchId, cache.geocode); cacheList.add(cache); } app.addSearch(searchId, cacheList, true, reason); return searchId; } public Long searchByGeocode(HashMap<String, String> parameters, int reason, boolean forceReload) { final cgSearch search = new cgSearch(); String geocode = parameters.get("geocode"); String guid = parameters.get("guid"); if ((geocode == null || geocode.length() == 0) && ((guid == null || guid.length() == 0))) { Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No geocode nor guid given"); return null; } if (forceReload == false && reason == 0 && (app.isOffline(geocode, guid) == true || app.isThere(geocode, guid, true, true) == true)) { if ((geocode == null || geocode.length() == 0) && guid != null && guid.length() > 0) { geocode = app.getGeocode(guid); } ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); cacheList.add(app.getCacheByGeocode(geocode, true, true, true, true, true, true)); search.addGeocode(geocode); app.addSearch(search, cacheList, false, reason); cacheList.clear(); cacheList = null; return search.getCurrentId(); } final String host = "www.geocaching.com"; final String path = "/seek/cache_details.aspx"; final String method = "GET"; final HashMap<String, String> params = new HashMap<String, String>(); if (geocode != null && geocode.length() > 0) { params.put("wp", geocode); } else if (guid != null && guid.length() > 0) { params.put("guid", guid); } params.put("decrypt", "y"); params.put("log", "y"); // download logs (more than 5 params.put("numlogs", "35"); // 35 logs String page = requestLogged(false, host, path, method, params, false, false, false); if (page == null || page.length() == 0) { if (app.isThere(geocode, guid, true, false) == true) { if ((geocode == null || geocode.length() == 0) && guid != null && guid.length() > 0) { Log.i(cgSettings.tag, "Loading old cache from cache."); geocode = app.getGeocode(guid); } final ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); cacheList.add(app.getCacheByGeocode(geocode)); search.addGeocode(geocode); search.error = null; search.errorRetrieve = 0; // reset errors from previous failed request app.addSearch(search, cacheList, false, reason); cacheList.clear(); return search.getCurrentId(); } Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No data from server"); return null; } final cgCacheWrap caches = parseCache(page, reason); if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { if (caches != null && caches.error != null && caches.error.length() > 0) { search.error = caches.error; } if (caches != null && caches.url != null && caches.url.length() > 0) { search.url = caches.url; } app.addSearch(search, null, true, reason); Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No cache parsed"); return null; } if (app == null) { Log.e(cgSettings.tag, "cgeoBase.searchByGeocode: No application found"); return null; } final ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); if (caches != null) { if (caches.error != null && caches.error.length() > 0) { search.error = caches.error; } if (caches.url != null && caches.url.length() > 0) { search.url = caches.url; } if (caches.viewstate != null && caches.viewstate.length() > 0) { search.viewstate = caches.viewstate; } if (caches.viewstate1 != null && caches.viewstate1.length() > 0) { search.viewstate1 = caches.viewstate1; } search.totalCnt = caches.totalCnt; for (cgCache cache : caches.cacheList) { search.addGeocode(cache.geocode); cacheList.add(cache); } } app.addSearch(search, cacheList, true, reason); page = null; cacheList.clear(); return search.getCurrentId(); } public Long searchByOffline(HashMap<String, Object> parameters) { if (app == null) { Log.e(cgSettings.tag, "cgeoBase.searchByOffline: No application found"); return null; } Double latitude = null; Double longitude = null; String cachetype = null; Integer list = 1; if (parameters.containsKey("latitude") == true && parameters.containsKey("longitude") == true) { latitude = (Double) parameters.get("latitude"); longitude = (Double) parameters.get("longitude"); } if (parameters.containsKey("cachetype") == true) { cachetype = (String) parameters.get("cachetype"); } if (parameters.containsKey("list") == true) { list = (Integer) parameters.get("list"); } final cgSearch search = app.getBatchOfStoredCaches(true, latitude, longitude, cachetype, list); search.totalCnt = app.getAllStoredCachesCount(true, cachetype, list); return search.getCurrentId(); } public Long searchByHistory(HashMap<String, Object> parameters) { if (app == null) { Log.e(cgSettings.tag, "cgeoBase.searchByHistory: No application found"); return null; } String cachetype = null; if (parameters.containsKey("cachetype") == true) { cachetype = (String) parameters.get("cachetype"); } final cgSearch search = app.getHistoryOfCaches(true, cachetype); search.totalCnt = app.getAllHistoricCachesCount(true, cachetype); return search.getCurrentId(); } public Long searchByCoords(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) { final cgSearch search = new cgSearch(); final String latitude = parameters.get("latitude"); final String longitude = parameters.get("longitude"); cgCacheWrap caches = new cgCacheWrap(); String cacheType = parameters.get("cachetype"); if (latitude == null || latitude.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No latitude given"); return null; } if (longitude == null || longitude.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No longitude given"); return null; } if (cacheType != null && cacheType.length() == 0) { cacheType = null; } final String host = "www.geocaching.com"; final String path = "/seek/nearest.aspx"; final String method = "GET"; final HashMap<String, String> params = new HashMap<String, String>(); if (cacheType != null && cacheIDs.containsKey(cacheType) == true) { params.put("tx", cacheIDs.get(cacheType)); } else { params.put("tx", cacheIDs.get("all")); } params.put("lat", latitude); params.put("lng", longitude); final String url = "http://" + host + path + "?" + prepareParameters(params, false, true); String page = requestLogged(false, host, path, method, params, false, false, true); if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No data from server"); return null; } caches = parseSearch(thread, url, page, showCaptcha); if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No cache parsed"); } if (app == null) { Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found"); return null; } final ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); if (caches != null) { if (caches.error != null && caches.error.length() > 0) { search.error = caches.error; } if (caches.url != null && caches.url.length() > 0) { search.url = caches.url; } if (caches.viewstate != null && caches.viewstate.length() > 0) { search.viewstate = caches.viewstate; } if (caches.viewstate1 != null && caches.viewstate1.length() > 0) { search.viewstate1 = caches.viewstate1; } search.totalCnt = caches.totalCnt; for (cgCache cache : caches.cacheList) { if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) { search.addGeocode(cache.geocode); cacheList.add(cache); } } } app.addSearch(search, cacheList, true, reason); return search.getCurrentId(); } public Long searchByKeyword(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) { final cgSearch search = new cgSearch(); final String keyword = parameters.get("keyword"); cgCacheWrap caches = new cgCacheWrap(); String cacheType = parameters.get("cachetype"); if (keyword == null || keyword.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No keyword given"); return null; } if (cacheType != null && cacheType.length() == 0) { cacheType = null; } final String host = "www.geocaching.com"; final String path = "/seek/nearest.aspx"; final String method = "GET"; final HashMap<String, String> params = new HashMap<String, String>(); if (cacheType != null && cacheIDs.containsKey(cacheType) == true) { params.put("tx", cacheIDs.get(cacheType)); } else { params.put("tx", cacheIDs.get("all")); } params.put("key", keyword); final String url = "http://" + host + path + "?" + prepareParameters(params, false, true); String page = requestLogged(false, host, path, method, params, false, false, true); if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No data from server"); return null; } caches = parseSearch(thread, url, page, showCaptcha); if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { Log.e(cgSettings.tag, "cgeoBase.searchByKeyword: No cache parsed"); } if (app == null) { Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found"); return null; } final ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); if (caches != null) { if (caches.error != null && caches.error.length() > 0) { search.error = caches.error; } if (caches.url != null && caches.url.length() > 0) { search.url = caches.url; } if (caches.viewstate != null && caches.viewstate.length() > 0) { search.viewstate = caches.viewstate; } if (caches.viewstate1 != null && caches.viewstate1.length() > 0) { search.viewstate1 = caches.viewstate1; } search.totalCnt = caches.totalCnt; for (cgCache cache : caches.cacheList) { if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) { search.addGeocode(cache.geocode); cacheList.add(cache); } } } app.addSearch(search, cacheList, true, reason); return search.getCurrentId(); } public Long searchByUsername(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) { final cgSearch search = new cgSearch(); final String userName = parameters.get("username"); cgCacheWrap caches = new cgCacheWrap(); String cacheType = parameters.get("cachetype"); if (userName == null || userName.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No user name given"); return null; } if (cacheType != null && cacheType.length() == 0) { cacheType = null; } final String host = "www.geocaching.com"; final String path = "/seek/nearest.aspx"; final String method = "GET"; final HashMap<String, String> params = new HashMap<String, String>(); if (cacheType != null && cacheIDs.containsKey(cacheType) == true) { params.put("tx", cacheIDs.get(cacheType)); } else { params.put("tx", cacheIDs.get("all")); } params.put("ul", userName); boolean my = false; if (userName.equalsIgnoreCase(settings.getLogin().get("username")) == true) { my = true; Log.i(cgSettings.tag, "cgBase.searchByUsername: Overriding users choice, downloading all caches."); } final String url = "http://" + host + path + "?" + prepareParameters(params, my, true); String page = requestLogged(false, host, path, method, params, false, my, true); if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No data from server"); return null; } caches = parseSearch(thread, url, page, showCaptcha); if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { Log.e(cgSettings.tag, "cgeoBase.searchByUsername: No cache parsed"); } if (app == null) { Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found"); return null; } final ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); if (caches != null) { if (caches.error != null && caches.error.length() > 0) { search.error = caches.error; } if (caches.url != null && caches.url.length() > 0) { search.url = caches.url; } if (caches.viewstate != null && caches.viewstate.length() > 0) { search.viewstate = caches.viewstate; } if (caches.viewstate1 != null && caches.viewstate1.length() > 0) { search.viewstate1 = caches.viewstate1; } search.totalCnt = caches.totalCnt; for (cgCache cache : caches.cacheList) { if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) { search.addGeocode(cache.geocode); cacheList.add(cache); } } } app.addSearch(search, cacheList, true, reason); return search.getCurrentId(); } public Long searchByOwner(cgSearchThread thread, HashMap<String, String> parameters, int reason, boolean showCaptcha) { final cgSearch search = new cgSearch(); final String userName = parameters.get("username"); cgCacheWrap caches = new cgCacheWrap(); String cacheType = parameters.get("cachetype"); if (userName == null || userName.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No user name given"); return null; } if (cacheType != null && cacheType.length() == 0) { cacheType = null; } final String host = "www.geocaching.com"; final String path = "/seek/nearest.aspx"; final String method = "GET"; final HashMap<String, String> params = new HashMap<String, String>(); if (cacheType != null && cacheIDs.containsKey(cacheType) == true) { params.put("tx", cacheIDs.get(cacheType)); } else { params.put("tx", cacheIDs.get("all")); } params.put("u", userName); final String url = "http://" + host + path + "?" + prepareParameters(params, false, true); String page = requestLogged(false, host, path, method, params, false, false, true); if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No data from server"); return null; } caches = parseSearch(thread, url, page, showCaptcha); if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { Log.e(cgSettings.tag, "cgeoBase.searchByOwner: No cache parsed"); } if (app == null) { Log.e(cgSettings.tag, "cgeoBase.searchByCoords: No application found"); return null; } final ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); if (caches != null) { if (caches.error != null && caches.error.length() > 0) { search.error = caches.error; } if (caches.url != null && caches.url.length() > 0) { search.url = caches.url; } if (caches.viewstate != null && caches.viewstate.length() > 0) { search.viewstate = caches.viewstate; } if (caches.viewstate1 != null && caches.viewstate1.length() > 0) { search.viewstate1 = caches.viewstate1; } search.totalCnt = caches.totalCnt; for (cgCache cache : caches.cacheList) { if (settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) { search.addGeocode(cache.geocode); cacheList.add(cache); } } } app.addSearch(search, cacheList, true, reason); return search.getCurrentId(); } public Long searchByViewport(HashMap<String, String> parameters, int reason) { final cgSearch search = new cgSearch(); final String latMin = parameters.get("latitude-min"); final String latMax = parameters.get("latitude-max"); final String lonMin = parameters.get("longitude-min"); final String lonMax = parameters.get("longitude-max"); String usertoken = null; if (parameters.get("usertoken") != null) { usertoken = parameters.get("usertoken"); } else { usertoken = ""; } cgCacheWrap caches = new cgCacheWrap(); String page = null; if (latMin == null || latMin.length() == 0 || latMax == null || latMax.length() == 0 || lonMin == null || lonMin.length() == 0 || lonMax == null || lonMax.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByViewport: Not enough parameters to recognize viewport"); return null; } final String host = "www.geocaching.com"; final String path = "/map/default.aspx/MapAction"; String params = "{\"dto\":{\"data\":{\"c\":1,\"m\":\"\",\"d\":\"" + latMax + "|" + latMin + "|" + lonMax + "|" + lonMin + "\"},\"ut\":\"" + usertoken + "\"}}"; final String url = "http://" + host + path + "?" + params; page = requestJSONgc(host, path, params); if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No data from server"); return null; } caches = parseMapJSON(url, page); if (caches == null || caches.cacheList == null || caches.cacheList.isEmpty()) { Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No cache parsed"); } if (app == null) { Log.e(cgSettings.tag, "cgeoBase.searchByViewport: No application found"); return null; } final ArrayList<cgCache> cacheList = new ArrayList<cgCache>(); if (caches != null) { if (caches.error != null && caches.error.length() > 0) { search.error = caches.error; } if (caches.url != null && caches.url.length() > 0) { search.url = caches.url; } if (caches.viewstate != null && caches.viewstate.length() > 0) { search.viewstate = caches.viewstate; } if (caches.viewstate1 != null && caches.viewstate1.length() > 0) { search.viewstate1 = caches.viewstate1; } search.totalCnt = caches.totalCnt; if (caches.cacheList != null && caches.cacheList.size() > 0) { for (cgCache cache : caches.cacheList) { if ((settings.excludeDisabled == 0 || (settings.excludeDisabled == 1 && cache.disabled == false)) && (settings.excludeMine == 0 || (settings.excludeMine == 1 && cache.own == false)) && (settings.excludeMine == 0 || (settings.excludeMine == 1 && cache.found == false)) && (settings.cacheType == null || (settings.cacheType.equals(cache.type) == true))) { search.addGeocode(cache.geocode); cacheList.add(cache); } } } } app.addSearch(search, cacheList, true, reason); return search.getCurrentId(); } public ArrayList<cgUser> getGeocachersInViewport(String username, Double latMin, Double latMax, Double lonMin, Double lonMax) { final ArrayList<cgUser> users = new ArrayList<cgUser>(); if (username == null) { return users; } if (latMin == null || latMax == null || lonMin == null || lonMax == null) { return users; } final String host = "api.go4cache.com"; final String path = "/get.php"; final String method = "POST"; final HashMap<String, String> params = new HashMap<String, String>(); params.put("u", username); params.put("ltm", String.format((Locale) null, "%.6f", latMin)); params.put("ltx", String.format((Locale) null, "%.6f", latMax)); params.put("lnm", String.format((Locale) null, "%.6f", lonMin)); params.put("lnx", String.format((Locale) null, "%.6f", lonMax)); final String data = request(false, host, path, method, params, false, false, false).getData(); if (data == null || data.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.getGeocachersInViewport: No data from server"); return null; } try { final JSONObject dataJSON = new JSONObject(data); final JSONArray usersData = dataJSON.getJSONArray("users"); if (usersData != null && usersData.length() > 0) { int count = usersData.length(); JSONObject oneUser = null; for (int i = 0; i < count; i++) { final cgUser user = new cgUser(); oneUser = usersData.getJSONObject(i); if (oneUser != null) { final String located = oneUser.getString("located"); if (located != null) { user.located = dateSqlIn.parse(located); } else { user.located = new Date(); } user.username = oneUser.getString("user"); user.latitude = oneUser.getDouble("latitude"); user.longitude = oneUser.getDouble("longitude"); user.action = oneUser.getString("action"); user.client = oneUser.getString("client"); if (user.latitude != null && user.longitude != null) { users.add(user); } } } } } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.getGeocachersInViewport: " + e.toString()); } return users; } public cgTrackable searchTrackable(HashMap<String, String> parameters) { final String geocode = parameters.get("geocode"); final String guid = parameters.get("guid"); final String id = parameters.get("id"); cgTrackable trackable = new cgTrackable(); if ((geocode == null || geocode.length() == 0) && (guid == null || guid.length() == 0) && (id == null || id.length() == 0)) { Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No geocode nor guid nor id given"); return null; } final String host = "www.geocaching.com"; final String path = "/track/details.aspx"; final String method = "GET"; final HashMap<String, String> params = new HashMap<String, String>(); if (geocode != null && geocode.length() > 0) { params.put("tracker", geocode); } else if (guid != null && guid.length() > 0) { params.put("guid", guid); } else if (id != null && id.length() > 0) { params.put("id", id); } String page = requestLogged(false, host, path, method, params, false, false, false); if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No data from server"); return trackable; } trackable = parseTrackable(page); if (trackable == null) { Log.e(cgSettings.tag, "cgeoBase.searchTrackable: No trackable parsed"); return trackable; } return trackable; } public int postLog(cgeoapplication app, String geocode, String cacheid, String viewstate, String viewstate1, int logType, int year, int month, int day, String log, ArrayList<cgTrackableLog> trackables) { if (viewstate == null || viewstate.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.postLog: No viewstate given"); return 1000; } if (logTypes2.containsKey(logType) == false) { Log.e(cgSettings.tag, "cgeoBase.postLog: Unknown logtype"); return 1000; } if (log == null || log.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.postLog: No log text given"); return 1001; } // fix log (non-Latin characters converted to HTML entities) final int logLen = log.length(); final StringBuilder logUpdated = new StringBuilder(); for (int i = 0; i < logLen; i++) { char c = log.charAt(i); if (c > 300) { logUpdated.append("&#"); logUpdated.append(Integer.toString((int) c)); logUpdated.append(";"); } else { logUpdated.append(c); } } log = logUpdated.toString(); log = log.replace("\n", "\r\n"); // windows' eol if (trackables != null) { Log.i(cgSettings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log + "; trackables: " + trackables.size()); } else { Log.i(cgSettings.tag, "Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log + "; trackables: 0"); } final String host = "www.geocaching.com"; final String path = "/seek/log.aspx?ID=" + cacheid; final String method = "POST"; final HashMap<String, String> params = new HashMap<String, String>(); params.put("__VIEWSTATE", viewstate); if (viewstate1 != null) { params.put("__VIEWSTATE1", viewstate1); params.put("__VIEWSTATEFIELDCOUNT", "2"); } params.put("__EVENTTARGET", ""); params.put("__EVENTARGUMENT", ""); params.put("__LASTFOCUS", ""); params.put("ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType)); params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", String.format("%02d", month) + "/" + String.format("%02d", day) + "/" + String.format("%04d", year)); params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month", Integer.toString(month)); params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day)); params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year", Integer.toString(year)); params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log); params.put("ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry"); params.put("ctl00$ContentBody$uxVistOtherListingGC", ""); if (trackables != null && trackables.isEmpty() == false) { // we have some trackables to proceed final StringBuilder hdnSelected = new StringBuilder(); for (cgTrackableLog tb : trackables) { final String action = Integer.toString(tb.id) + logTypesTrackableAction.get(tb.action); if (tb.action > 0) { hdnSelected.append(action); hdnSelected.append(","); } } params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnSelectedActions", hdnSelected.toString()); // selected trackables params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", ""); } String page = request(false, host, path, method, params, false, false, false).getData(); if (checkLogin(page) == false) { int loginState = login(); if (loginState == 1) { page = request(false, host, path, method, params, false, false, false).getData(); } else { Log.e(cgSettings.tag, "cgeoBase.postLog: Can not log in geocaching (error: " + loginState + ")"); return loginState; } } if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.postLog: No data from server"); return 1002; } // maintenance, archived needs to be confirmed final Pattern pattern = Pattern.compile( "<span id=\"ctl00_ContentBody_LogBookPanel1_lbConfirm\"[^>]*>([^<]*<font[^>]*>)?([^<]+)(</font>[^<]*)?</span>", Pattern.CASE_INSENSITIVE); final Matcher matcher = pattern.matcher(page); try { if (matcher.find() == true && matcher.groupCount() > 0) { final String viewstateConfirm = findViewstate(page, 0); final String viewstate1Confirm = findViewstate(page, 1); if (viewstateConfirm == null || viewstateConfirm.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.postLog: No viewstate for confirm log"); return 1000; } params.clear(); params.put("__VIEWSTATE", viewstateConfirm); if (viewstate1 != null) { params.put("__VIEWSTATE1", viewstate1Confirm); params.put("__VIEWSTATEFIELDCOUNT", "2"); } params.put("__EVENTTARGET", ""); params.put("__EVENTARGUMENT", ""); params.put("__LASTFOCUS", ""); params.put("ctl00$ContentBody$LogBookPanel1$btnConfirm", "Yes"); params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log); params.put("ctl00$ContentBody$uxVistOtherListingGC", ""); if (trackables != null && trackables.isEmpty() == false) { // we have some trackables to proceed final StringBuilder hdnSelected = new StringBuilder(); for (cgTrackableLog tb : trackables) { String ctl = null; final String action = Integer.toString(tb.id) + logTypesTrackableAction.get(tb.action); if (tb.ctl < 10) { ctl = "0" + Integer.toString(tb.ctl); } else { ctl = Integer.toString(tb.ctl); } params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$repTravelBugs$ctl" + ctl + "$ddlAction", action); if (tb.action > 0) { hdnSelected.append(action); hdnSelected.append(","); } } params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnSelectedActions", hdnSelected.toString()); // selected trackables params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", ""); } page = request(false, host, path, method, params, false, false, false).getData(); } } catch (Exception e) { Log.e(cgSettings.tag, "cgeoBase.postLog.confim: " + e.toString()); } try { final Pattern patternOk = Pattern.compile( "<h2[^>]*>[^<]*<span id=\"ctl00_ContentBody_lbHeading\"[^>]*>[^<]*</span>[^<]*</h2>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Matcher matcherOk = patternOk.matcher(page); if (matcherOk.find() == true) { Log.i(cgSettings.tag, "Log successfully posted to cache #" + cacheid); if (app != null && geocode != null) { app.saveVisitDate(geocode); } return 1; } } catch (Exception e) { Log.e(cgSettings.tag, "cgeoBase.postLog.check: " + e.toString()); } Log.e(cgSettings.tag, "cgeoBase.postLog: Failed to post log because of unknown error"); return 1000; } public int postLogTrackable(String tbid, String trackingCode, String viewstate, String viewstate1, int logType, int year, int month, int day, String log) { if (viewstate == null || viewstate.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No viewstate given"); return 1000; } if (logTypes2.containsKey(logType) == false) { Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Unknown logtype"); return 1000; } if (log == null || log.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No log text given"); return 1001; } Log.i(cgSettings.tag, "Trying to post log for trackable #" + trackingCode + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log); log = log.replace("\n", "\r\n"); // windows' eol final Calendar currentDate = Calendar.getInstance(); final String host = "www.geocaching.com"; final String path = "/track/log.aspx?wid=" + tbid; final String method = "POST"; final HashMap<String, String> params = new HashMap<String, String>(); params.put("__VIEWSTATE", viewstate); if (viewstate1 != null) { params.put("__VIEWSTATE1", viewstate1); params.put("__VIEWSTATEFIELDCOUNT", "2"); } params.put("__EVENTTARGET", ""); params.put("__EVENTARGUMENT", ""); params.put("__LASTFOCUS", ""); params.put("ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType)); params.put("ctl00$ContentBody$LogBookPanel1$tbCode", trackingCode); if (currentDate.get(Calendar.YEAR) == year && (currentDate.get(Calendar.MONTH) + 1) == month && currentDate.get(Calendar.DATE) == day) { params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", ""); } else { params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged", Integer.toString(month) + "/" + Integer.toString(day) + "/" + Integer.toString(year)); } params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day)); params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month", Integer.toString(month)); params.put("ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year", Integer.toString(year)); params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", log); params.put("ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry"); params.put("ctl00$ContentBody$uxVistOtherListingGC", ""); String page = request(false, host, path, method, params, false, false, false).getData(); if (checkLogin(page) == false) { int loginState = login(); if (loginState == 1) { page = request(false, host, path, method, params, false, false, false).getData(); } else { Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Can not log in geocaching (error: " + loginState + ")"); return loginState; } } if (page == null || page.length() == 0) { Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: No data from server"); return 1002; } try { final Pattern patternOk = Pattern.compile( "<div id=[\"|']ctl00_ContentBody_LogBookPanel1_ViewLogPanel[\"|']>", Pattern.CASE_INSENSITIVE); final Matcher matcherOk = patternOk.matcher(page); if (matcherOk.find() == true) { Log.i(cgSettings.tag, "Log successfully posted to trackable #" + trackingCode); return 1; } } catch (Exception e) { Log.e(cgSettings.tag, "cgeoBase.postLogTrackable.check: " + e.toString()); } Log.e(cgSettings.tag, "cgeoBase.postLogTrackable: Failed to post log because of unknown error"); return 1000; } final public static HostnameVerifier doNotVerify = new HostnameVerifier() { public boolean verify(String hostname, SSLSession session) { return true; } }; public static void trustAllHosts() { TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[] {}; } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } } }; try { SSLContext sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.trustAllHosts: " + e.toString()); } } public void postTweetCache(cgeoapplication app, cgSettings settings, String geocode) { final cgCache cache = app.getCacheByGeocode(geocode); String name = cache.name; if (name.length() > 84) { name = name.substring(0, 81) + "..."; } final String status = "I found " + name + " (http://coord.info/" + cache.geocode.toUpperCase() + ")! #cgeo #geocaching"; // 56 chars + cache name postTweet(app, settings, status, null, null); } public void postTweetTrackable(cgeoapplication app, cgSettings settings, String geocode) { final cgTrackable trackable = app.getTrackableByGeocode(geocode); String name = trackable.name; if (name.length() > 82) { name = name.substring(0, 79) + "..."; } final String status = "I touched " + name + " (http://coord.info/" + trackable.geocode.toUpperCase() + ")! #cgeo #geocaching"; // 58 chars + trackable name postTweet(app, settings, status, null, null); } public void postTweet(cgeoapplication app, cgSettings settings, String status, Double latitude, Double longitude) { if (app == null) { return; } if (settings == null || settings.tokenPublic == null || settings.tokenPublic.length() == 0 || settings.tokenSecret == null || settings.tokenSecret.length() == 0) { return; } try { HashMap<String, String> parameters = new HashMap<String, String>(); parameters.put("status", status); if (latitude != null && longitude != null) { parameters.put("lat", String.format("%.6f", latitude)); parameters.put("long", String.format("%.6f", longitude)); parameters.put("display_coordinates", "true"); } final String paramsDone = cgOAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, settings.tokenPublic, settings.tokenSecret); HttpURLConnection connection = null; try { final StringBuffer buffer = new StringBuffer(); final URL u = new URL("http://api.twitter.com/1/statuses/update.json"); final URLConnection uc = u.openConnection(); uc.setRequestProperty("Host", "api.twitter.com"); connection = (HttpURLConnection) uc; connection.setReadTimeout(30000); connection.setRequestMethod("POST"); HttpURLConnection.setFollowRedirects(true); connection.setDoInput(true); connection.setDoOutput(true); final OutputStream out = connection.getOutputStream(); final OutputStreamWriter wr = new OutputStreamWriter(out); wr.write(paramsDone); wr.flush(); wr.close(); Log.i(cgSettings.tag, "Twitter.com: " + connection.getResponseCode() + " " + connection.getResponseMessage()); InputStream ins; final String encoding = connection.getContentEncoding(); if (encoding != null && encoding.equalsIgnoreCase("gzip")) { ins = new GZIPInputStream(connection.getInputStream()); } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) { ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true)); } else { ins = connection.getInputStream(); } final InputStreamReader inr = new InputStreamReader(ins); final BufferedReader br = new BufferedReader(inr); readIntoBuffer(br, buffer); br.close(); ins.close(); inr.close(); connection.disconnect(); } catch (IOException e) { Log.e(cgSettings.tag, "cgBase.postTweet.IO: " + connection.getResponseCode() + ": " + connection.getResponseMessage() + " ~ " + e.toString()); final InputStream ins = connection.getErrorStream(); final StringBuffer buffer = new StringBuffer(); final InputStreamReader inr = new InputStreamReader(ins); final BufferedReader br = new BufferedReader(inr); readIntoBuffer(br, buffer); br.close(); ins.close(); inr.close(); } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.postTweet.inner: " + e.toString()); } connection.disconnect(); } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.postTweet: " + e.toString()); } } private void readIntoBuffer(BufferedReader br, StringBuffer buffer) throws IOException { int bufferSize = 1024 * 16; char[] bytes = new char[bufferSize]; int bytesRead; while ((bytesRead = br.read(bytes)) > 0) { if (bytesRead == bufferSize) { buffer.append(bytes); } else { buffer.append(bytes, 0, bytesRead); } } } /* public ArrayList<String> translate(ArrayList<String> text, String target) { if (settings.translate == false) { return text; } String[] languages = null; if (settings.languages != null) { languages = settings.languages.split(" "); } ArrayList<String> translated = new ArrayList<String>(); String language = null; if (text == null || text.isEmpty()) { return text; } // cut to 5000 characters (limitation of Google Translation API) for (String textOne : text) { int len = urlencode_rfc3986(textOne).length(); if (len > 5000) { textOne = Html.fromHtml(textOne).toString(); len = urlencode_rfc3986(textOne).length(); if (len > 5000) { int cut = 2000; if (textOne.length() > cut) { cut = 1000; } textOne = textOne.substring(0, cut) + "..."; } } } try { if (target == null) { final Locale locale = Locale.getDefault(); target = locale.getLanguage(); } final String scheme = "https://"; final String host = "www.googleapis.com"; final String path = "/language/translate/v2"; final ArrayList<String> params = new ArrayList<String>(); params.add("key=" + urlencode_rfc3986("AIzaSyAJH8x5etFHUbFifmgChlWoCVmwBFSwShQ")); params.add("target=" + urlencode_rfc3986(target)); for (String textOne : text) { params.add("q=" + urlencode_rfc3986(textOne)); } params.add("format=" + urlencode_rfc3986("html")); String page = requestJSON(scheme, host, path, "POST", implode("&", params.toArray())); if (page == null || page.length() == 0) { return text; } JSONObject json = new JSONObject(page); JSONObject jsonData = json.getJSONObject("data"); JSONArray jsonTranslations = jsonData.getJSONArray("translations"); int translationCnt = jsonTranslations.length(); for (int i = 0; i < translationCnt; i ++) { JSONObject jsonTranslation = jsonTranslations.getJSONObject(i); language = jsonTranslation.getString("detectedSourceLanguage"); boolean toTranslate = true; if (languages != null) { for (String lng : languages) { if (lng.equalsIgnoreCase(language)) { toTranslate = false; } } } if (toTranslate == false) { translated.add(text.get(i)); } else { Log.i(cgSettings.tag, "Translating #" + i + ": " + language + ">" + target); translated.add(jsonTranslation.getString("translatedText")); } } } catch (Exception e) { Log.w(cgSettings.tag, "cgBase.translate: " + e.toString()); } return translated; } */ public String getLocalIpAddress() { try { for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en .hasMoreElements();) { NetworkInterface intf = en.nextElement(); for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) { InetAddress inetAddress = enumIpAddr.nextElement(); if (!inetAddress.isLoopbackAddress()) { return inetAddress.getHostAddress().toString(); } } } } catch (SocketException e) { // nothing } return null; } public static String implode(String delim, Object[] array) { String out = ""; try { for (int i = 0; i < array.length; i++) { if (i != 0) { out += delim; } out += array[i].toString(); } } catch (Exception e) { Log.e(cgSettings.tag, "cgeoBase.implode: " + e.toString()); } return out; } public static String urlencode_rfc3986(String text) { final String encoded = URLEncoder.encode(text).replace("+", "%20").replaceAll("%7E", "~"); return encoded; } public String prepareParameters(HashMap<String, String> params, boolean my, boolean addF) { String paramsDone = null; if (my != true && settings.excludeMine > 0) { if (params == null) { params = new HashMap<String, String>(); } if (addF == true) { params.put("f", "1"); } Log.i(cgSettings.tag, "Skipping caches found or hidden by user."); } if (params != null) { Object[] keys = params.keySet().toArray(); ArrayList<String> paramsEncoded = new ArrayList<String>(); String key; String value; for (int i = 0; i < keys.length; i++) { key = (String) keys[i]; value = (String) params.get(key); if (key.charAt(0) == '^') { key = ""; } if (value == null) { value = ""; } paramsEncoded.add(key + "=" + urlencode_rfc3986(value)); } paramsDone = implode("&", paramsEncoded.toArray()); } else { paramsDone = ""; } return paramsDone; } public String requestViewstate(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my) { final cgResponse response = request(secure, host, path, method, params, xContentType, my, false); return findViewstate(response.getData(), 0); } public String requestViewstate1(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my) { final cgResponse response = request(secure, host, path, method, params, xContentType, my, false); return findViewstate(response.getData(), 1); } public String requestLogged(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my, boolean addF) { cgResponse response = request(secure, host, path, method, params, xContentType, my, addF); String data = response.getData(); if (checkLogin(data) == false) { int loginState = login(); if (loginState == 1) { response = request(secure, host, path, method, params, xContentType, my, addF); data = response.getData(); } else { Log.i(cgSettings.tag, "Working as guest."); } } return data; } public cgResponse request(boolean secure, String host, String path, String method, HashMap<String, String> params, boolean xContentType, boolean my, boolean addF) { // prepare parameters final String paramsDone = prepareParameters(params, my, addF); return request(secure, host, path, method, paramsDone, 0, xContentType); } public cgResponse request(boolean secure, String host, String path, String method, HashMap<String, String> params, int requestId, boolean xContentType, boolean my, boolean addF) { // prepare parameters final String paramsDone = prepareParameters(params, my, addF); return request(secure, host, path, method, paramsDone, requestId, xContentType); } public cgResponse request(boolean secure, String host, String path, String method, String params, int requestId, Boolean xContentType) { URL u = null; int httpCode = -1; String httpMessage = null; String httpLocation = null; if (requestId == 0) { requestId = (int) (Math.random() * 1000); } if (method == null || (method.equalsIgnoreCase("GET") == false && method.equalsIgnoreCase("POST") == false)) { method = "POST"; } else { method = method.toUpperCase(); } // https String scheme = "http://"; if (secure) { scheme = "https://"; } // prepare cookies String cookiesDone = null; if (cookies == null || cookies.isEmpty() == true) { if (cookies == null) { cookies = new HashMap<String, String>(); } final Map<String, ?> prefsAll = prefs.getAll(); final Set<String> prefsKeys = prefsAll.keySet(); for (String key : prefsKeys) { if (key.matches("cookie_.+") == true) { final String cookieKey = key.substring(7); final String cookieValue = (String) prefsAll.get(key); cookies.put(cookieKey, cookieValue); } } } if (cookies != null && !cookies.isEmpty() && cookies.keySet().size() > 0) { final Object[] keys = cookies.keySet().toArray(); final ArrayList<String> cookiesEncoded = new ArrayList<String>(); for (int i = 0; i < keys.length; i++) { String value = cookies.get(keys[i].toString()); cookiesEncoded.add(keys[i] + "=" + value); } if (cookiesEncoded.size() > 0) { cookiesDone = implode("; ", cookiesEncoded.toArray()); } } if (cookiesDone == null) { Map<String, ?> prefsValues = prefs.getAll(); if (prefsValues != null && prefsValues.size() > 0 && prefsValues.keySet().size() > 0) { final Object[] keys = prefsValues.keySet().toArray(); final ArrayList<String> cookiesEncoded = new ArrayList<String>(); final int length = keys.length; for (int i = 0; i < length; i++) { if (keys[i].toString().length() > 7 && keys[i].toString().substring(0, 7).equals("cookie_") == true) { cookiesEncoded .add(keys[i].toString().substring(7) + "=" + prefsValues.get(keys[i].toString())); } } if (cookiesEncoded.size() > 0) { cookiesDone = implode("; ", cookiesEncoded.toArray()); } } } if (cookiesDone == null) { cookiesDone = ""; } URLConnection uc = null; HttpURLConnection connection = null; Integer timeout = 30000; StringBuffer buffer = null; for (int i = 0; i < 5; i++) { if (i > 0) { Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1)); } buffer = new StringBuffer(); timeout = 30000 + (i * 10000); try { if (method.equals("GET")) { // GET u = new URL(scheme + host + path + "?" + params); uc = u.openConnection(); uc.setRequestProperty("Host", host); uc.setRequestProperty("Cookie", cookiesDone); if (xContentType == true) { uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); } if (settings.asBrowser == 1) { uc.setRequestProperty("Accept", "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); // uc.setRequestProperty("Accept-Encoding", "gzip"); // not supported via cellular network uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7"); uc.setRequestProperty("Accept-Language", "en-US"); uc.setRequestProperty("User-Agent", idBrowser); uc.setRequestProperty("Connection", "keep-alive"); uc.setRequestProperty("Keep-Alive", "300"); } connection = (HttpURLConnection) uc; connection.setReadTimeout(timeout); connection.setRequestMethod(method); HttpURLConnection.setFollowRedirects(false); connection.setDoInput(true); connection.setDoOutput(false); } else { // POST u = new URL(scheme + host + path); uc = u.openConnection(); uc.setRequestProperty("Host", host); uc.setRequestProperty("Cookie", cookiesDone); if (xContentType == true) { uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); } if (settings.asBrowser == 1) { uc.setRequestProperty("Accept", "application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); // uc.setRequestProperty("Accept-Encoding", "gzip"); // not supported via cellular network uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7"); uc.setRequestProperty("Accept-Language", "en-US"); uc.setRequestProperty("User-Agent", idBrowser); uc.setRequestProperty("Connection", "keep-alive"); uc.setRequestProperty("Keep-Alive", "300"); } connection = (HttpURLConnection) uc; connection.setReadTimeout(timeout); connection.setRequestMethod(method); HttpURLConnection.setFollowRedirects(false); connection.setDoInput(true); connection.setDoOutput(true); final OutputStream out = connection.getOutputStream(); final OutputStreamWriter wr = new OutputStreamWriter(out); wr.write(params); wr.flush(); wr.close(); } String headerName = null; final SharedPreferences.Editor prefsEditor = prefs.edit(); for (int j = 1; (headerName = uc.getHeaderFieldKey(j)) != null; j++) { if (headerName != null && headerName.equalsIgnoreCase("Set-Cookie")) { int index; String cookie = uc.getHeaderField(j); index = cookie.indexOf(";"); if (index > -1) { cookie = cookie.substring(0, cookie.indexOf(";")); } index = cookie.indexOf("="); if (index > -1 && cookie.length() > (index + 1)) { String name = cookie.substring(0, cookie.indexOf("=")); String value = cookie.substring(cookie.indexOf("=") + 1, cookie.length()); cookies.put(name, value); prefsEditor.putString("cookie_" + name, value); } } } prefsEditor.commit(); final String encoding = connection.getContentEncoding(); InputStream ins; if (encoding != null && encoding.equalsIgnoreCase("gzip")) { ins = new GZIPInputStream(connection.getInputStream()); } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) { ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true)); } else { ins = connection.getInputStream(); } final InputStreamReader inr = new InputStreamReader(ins); final BufferedReader br = new BufferedReader(inr); readIntoBuffer(br, buffer); httpCode = connection.getResponseCode(); httpMessage = connection.getResponseMessage(); httpLocation = uc.getHeaderField("Location"); final String paramsLog = params.replaceAll(passMatch, "password=***"); if (buffer != null && connection != null) { Log.i(cgSettings.tag + "|" + requestId, "[" + method + " " + (int) (params.length() / 1024) + "k | " + httpCode + " | " + (int) (buffer.length() / 1024) + "k] Downloaded " + scheme + host + path + "?" + paramsLog); } else { Log.i(cgSettings.tag + "|" + requestId, "[" + method + " | " + httpCode + "] Failed to download " + scheme + host + path + "?" + paramsLog); } connection.disconnect(); br.close(); ins.close(); inr.close(); } catch (IOException e) { Log.e(cgSettings.tag, "cgeoBase.request.IOException: " + e.toString()); } catch (Exception e) { Log.e(cgSettings.tag, "cgeoBase.request: " + e.toString()); } if (buffer != null && buffer.length() > 0) { break; } } cgResponse response = new cgResponse(); String data = null; try { if (httpCode == 302 && httpLocation != null) { final Uri newLocation = Uri.parse(httpLocation); if (newLocation.isRelative() == true) { response = request(secure, host, path, "GET", new HashMap<String, String>(), requestId, false, false, false); } else { boolean secureRedir = false; if (newLocation.getScheme().equals("https")) { secureRedir = true; } response = request(secureRedir, newLocation.getHost(), newLocation.getPath(), "GET", new HashMap<String, String>(), requestId, false, false, false); } } else { if (buffer != null && buffer.length() > 0) { data = replaceWhitespace(buffer); buffer = null; if (data != null) { response.setData(data); } else { response.setData(""); } response.setStatusCode(httpCode); response.setStatusMessage(httpMessage); response.setUrl(u.toString()); } } } catch (Exception e) { Log.e(cgSettings.tag, "cgeoBase.page: " + e.toString()); } return response; } private String replaceWhitespace(final StringBuffer buffer) { final int length = buffer.length(); final char[] bytes = new char[length]; buffer.getChars(0, length, bytes, 0); int resultSize = 0; boolean lastWasWhitespace = false; for (int i = 0; i < length; i++) { char c = bytes[i]; if (c == ' ' || c == '\n' || c == '\r' || c == '\t') { if (!lastWasWhitespace) { bytes[resultSize++] = ' '; } lastWasWhitespace = true; } else { bytes[resultSize++] = c; lastWasWhitespace = false; } } return new String(bytes, 0, resultSize); } public String requestJSONgc(String host, String path, String params) { int httpCode = -1; String httpLocation = null; // prepare cookies String cookiesDone = null; if (cookies == null || cookies.isEmpty() == true) { if (cookies == null) { cookies = new HashMap<String, String>(); } final Map<String, ?> prefsAll = prefs.getAll(); final Set<String> prefsKeys = prefsAll.keySet(); for (String key : prefsKeys) { if (key.matches("cookie_.+") == true) { final String cookieKey = key.substring(7); final String cookieValue = (String) prefsAll.get(key); cookies.put(cookieKey, cookieValue); } } } if (cookies != null) { final Object[] keys = cookies.keySet().toArray(); final ArrayList<String> cookiesEncoded = new ArrayList<String>(); for (int i = 0; i < keys.length; i++) { String value = cookies.get(keys[i].toString()); cookiesEncoded.add(keys[i] + "=" + value); } if (cookiesEncoded.size() > 0) { cookiesDone = implode("; ", cookiesEncoded.toArray()); } } if (cookiesDone == null) { Map<String, ?> prefsValues = prefs.getAll(); if (prefsValues != null && prefsValues.size() > 0) { final Object[] keys = prefsValues.keySet().toArray(); final ArrayList<String> cookiesEncoded = new ArrayList<String>(); final int length = keys.length; for (int i = 0; i < length; i++) { if (keys[i].toString().length() > 7 && keys[i].toString().substring(0, 7).equals("cookie_") == true) { cookiesEncoded .add(keys[i].toString().substring(7) + "=" + prefsValues.get(keys[i].toString())); } } if (cookiesEncoded.size() > 0) { cookiesDone = implode("; ", cookiesEncoded.toArray()); } } } if (cookiesDone == null) { cookiesDone = ""; } URLConnection uc = null; HttpURLConnection connection = null; Integer timeout = 30000; final StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 3; i++) { if (i > 0) { Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1)); } buffer.delete(0, buffer.length()); timeout = 30000 + (i * 15000); try { // POST final URL u = new URL("http://" + host + path); uc = u.openConnection(); uc.setRequestProperty("Host", host); uc.setRequestProperty("Cookie", cookiesDone); uc.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); uc.setRequestProperty("X-Requested-With", "XMLHttpRequest"); uc.setRequestProperty("Accept", "application/json, text/javascript, */*; q=0.01"); uc.setRequestProperty("Referer", host + "/" + path); if (settings.asBrowser == 1) { uc.setRequestProperty("Accept-Charset", "utf-8, iso-8859-1, utf-16, *;q=0.7"); uc.setRequestProperty("Accept-Language", "en-US"); uc.setRequestProperty("User-Agent", idBrowser); uc.setRequestProperty("Connection", "keep-alive"); uc.setRequestProperty("Keep-Alive", "300"); } connection = (HttpURLConnection) uc; connection.setReadTimeout(timeout); connection.setRequestMethod("POST"); HttpURLConnection.setFollowRedirects(false); // TODO: Fix these (FilCab) connection.setDoInput(true); connection.setDoOutput(true); final OutputStream out = connection.getOutputStream(); final OutputStreamWriter wr = new OutputStreamWriter(out); wr.write(params); wr.flush(); wr.close(); String headerName = null; final SharedPreferences.Editor prefsEditor = prefs.edit(); for (int j = 1; (headerName = uc.getHeaderFieldKey(j)) != null; j++) { if (headerName != null && headerName.equalsIgnoreCase("Set-Cookie")) { int index; String cookie = uc.getHeaderField(j); index = cookie.indexOf(";"); if (index > -1) { cookie = cookie.substring(0, cookie.indexOf(";")); } index = cookie.indexOf("="); if (index > -1 && cookie.length() > (index + 1)) { String name = cookie.substring(0, cookie.indexOf("=")); String value = cookie.substring(cookie.indexOf("=") + 1, cookie.length()); cookies.put(name, value); prefsEditor.putString("cookie_" + name, value); } } } prefsEditor.commit(); final String encoding = connection.getContentEncoding(); InputStream ins; if (encoding != null && encoding.equalsIgnoreCase("gzip")) { ins = new GZIPInputStream(connection.getInputStream()); } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) { ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true)); } else { ins = connection.getInputStream(); } final InputStreamReader inr = new InputStreamReader(ins); final BufferedReader br = new BufferedReader(inr); readIntoBuffer(br, buffer); httpCode = connection.getResponseCode(); httpLocation = uc.getHeaderField("Location"); final String paramsLog = params.replaceAll(passMatch, "password=***"); Log.i(cgSettings.tag + " | JSON", "[POST " + (int) (params.length() / 1024) + "k | " + httpCode + " | " + (int) (buffer.length() / 1024) + "k] Downloaded " + "http://" + host + path + "?" + paramsLog); connection.disconnect(); br.close(); ins.close(); inr.close(); } catch (IOException e) { Log.e(cgSettings.tag, "cgeoBase.requestJSONgc.IOException: " + e.toString()); } catch (Exception e) { Log.e(cgSettings.tag, "cgeoBase.requestJSONgc: " + e.toString()); } if (buffer != null && buffer.length() > 0) { break; } } String page = null; if (httpCode == 302 && httpLocation != null) { final Uri newLocation = Uri.parse(httpLocation); if (newLocation.isRelative() == true) { page = requestJSONgc(host, path, params); } else { page = requestJSONgc(newLocation.getHost(), newLocation.getPath(), params); } } else { page = replaceWhitespace(buffer); } if (page != null) { return page; } else { return ""; } } public String requestJSON(String host, String path, String params) { return requestJSON("http://", host, path, "GET", params); } public String requestJSON(String scheme, String host, String path, String method, String params) { int httpCode = -1; String httpLocation = null; if (method == null) { method = "GET"; } else { method = method.toUpperCase(); } boolean methodPost = false; if (method.equalsIgnoreCase("POST")) { methodPost = true; } URLConnection uc = null; HttpURLConnection connection = null; Integer timeout = 30000; final StringBuffer buffer = new StringBuffer(); for (int i = 0; i < 3; i++) { if (i > 0) { Log.w(cgSettings.tag, "Failed to download data, retrying. Attempt #" + (i + 1)); } buffer.delete(0, buffer.length()); timeout = 30000 + (i * 15000); try { try { URL u = null; if (methodPost) { u = new URL(scheme + host + path); } else { u = new URL(scheme + host + path + "?" + params); } if (u.getProtocol().toLowerCase().equals("https")) { trustAllHosts(); HttpsURLConnection https = (HttpsURLConnection) u.openConnection(); https.setHostnameVerifier(doNotVerify); uc = https; } else { uc = (HttpURLConnection) u.openConnection(); } uc.setRequestProperty("Host", host); uc.setRequestProperty("Accept", "application/json, text/javascript, */*; q=0.01"); if (methodPost) { uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); uc.setRequestProperty("Content-Length", Integer.toString(params.length())); uc.setRequestProperty("X-HTTP-Method-Override", "GET"); } else { uc.setRequestProperty("Content-Type", "application/json; charset=UTF-8"); } uc.setRequestProperty("X-Requested-With", "XMLHttpRequest"); connection = (HttpURLConnection) uc; connection.setReadTimeout(timeout); connection.setRequestMethod(method); HttpURLConnection.setFollowRedirects(false); // TODO: Fix these (FilCab) connection.setDoInput(true); if (methodPost) { connection.setDoOutput(true); final OutputStream out = connection.getOutputStream(); final OutputStreamWriter wr = new OutputStreamWriter(out); wr.write(params); wr.flush(); wr.close(); } else { connection.setDoOutput(false); } final String encoding = connection.getContentEncoding(); InputStream ins; if (encoding != null && encoding.equalsIgnoreCase("gzip")) { ins = new GZIPInputStream(connection.getInputStream()); } else if (encoding != null && encoding.equalsIgnoreCase("deflate")) { ins = new InflaterInputStream(connection.getInputStream(), new Inflater(true)); } else { ins = connection.getInputStream(); } final InputStreamReader inr = new InputStreamReader(ins); final BufferedReader br = new BufferedReader(inr); readIntoBuffer(br, buffer); httpCode = connection.getResponseCode(); final String paramsLog = params.replaceAll(passMatch, "password=***"); Log.i(cgSettings.tag + " | JSON", "[POST " + (int) (params.length() / 1024) + "k | " + httpCode + " | " + (int) (buffer.length() / 1024) + "k] Downloaded " + "http://" + host + path + "?" + paramsLog); connection.disconnect(); br.close(); ins.close(); inr.close(); } catch (IOException e) { httpCode = connection.getResponseCode(); Log.e(cgSettings.tag, "cgeoBase.requestJSON.IOException: " + httpCode + ": " + connection.getResponseMessage() + " ~ " + e.toString()); } } catch (Exception e) { Log.e(cgSettings.tag, "cgeoBase.requestJSON: " + e.toString()); } if (buffer != null && buffer.length() > 0) { break; } if (httpCode == 403) { // we're not allowed to download content, so let's move break; } } String page = null; if (httpCode == 302 && httpLocation != null) { final Uri newLocation = Uri.parse(httpLocation); if (newLocation.isRelative() == true) { page = requestJSONgc(host, path, params); } else { page = requestJSONgc(newLocation.getHost(), newLocation.getPath(), params); } } else { page = replaceWhitespace(buffer); } if (page != null) { return page; } else { return ""; } } public static String rot13(String text) { final StringBuilder result = new StringBuilder(); // plaintext flag (do not convert) boolean plaintext = false; int length = text.length(); for (int index = 0; index < length; index++) { int c = text.charAt(index); if (c == '[') { plaintext = true; } else if (c == ']') { plaintext = false; } else if (!plaintext) { int capitalized = c & 32; c &= ~capitalized; c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c) | capitalized; } result.append((char) c); } return result.toString(); } public static String md5(String text) { String hashed = ""; try { MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.md5: " + e.toString()); } return hashed; } public static String sha1(String text) { String hashed = ""; try { MessageDigest digest = MessageDigest.getInstance("SHA-1"); digest.update(text.getBytes(), 0, text.length()); hashed = new BigInteger(1, digest.digest()).toString(16); } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.sha1: " + e.toString()); } return hashed; } public static byte[] hashHmac(String text, String salt) { byte[] macBytes = {}; try { SecretKeySpec secretKeySpec = new SecretKeySpec(salt.getBytes(), "HmacSHA1"); Mac mac = Mac.getInstance("HmacSHA1"); mac.init(secretKeySpec); macBytes = mac.doFinal(text.getBytes()); } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.hashHmac: " + e.toString()); } return macBytes; } public static boolean deleteDirectory(File path) { if (path.exists()) { File[] files = path.listFiles(); for (int i = 0; i < files.length; i++) { if (files[i].isDirectory()) { deleteDirectory(files[i]); } else { files[i].delete(); } } } return (path.delete()); } public static boolean isIntentAvailable(Context context, String action) { final Intent intent = new Intent(action); return isIntentAvailable(context, intent); } public static boolean isIntentAvailable(Context context, Intent intent) { final PackageManager packageManager = context.getPackageManager(); final List<ResolveInfo> list = packageManager.queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY); return (list.size() > 0); } public void storeCache(cgeoapplication app, Activity activity, cgCache cache, String geocode, int listId, Handler handler) { try { // cache details if (cache != null) { final HashMap<String, String> params = new HashMap<String, String>(); params.put("geocode", cache.geocode); final Long searchId = searchByGeocode(params, listId, false); cache = app.getCache(searchId); } else if (geocode != null) { final HashMap<String, String> params = new HashMap<String, String>(); params.put("geocode", geocode); final Long searchId = searchByGeocode(params, listId, false); cache = app.getCache(searchId); } if (cache == null) { if (handler != null) { handler.sendMessage(new Message()); } return; } final cgHtmlImg imgGetter = new cgHtmlImg(activity, settings, cache.geocode, false, listId, true); // store images from description if (cache.description != null) { Html.fromHtml(cache.description, imgGetter, null); } // store spoilers if (cache.spoilers != null && cache.spoilers.isEmpty() == false) { for (cgSpoiler oneSpoiler : cache.spoilers) { imgGetter.getDrawable(oneSpoiler.url); } } // store map previews if (settings.storeOfflineMaps == 1 && cache.latitude != null && cache.longitude != null) { final String latlonMap = String.format((Locale) null, "%.6f", cache.latitude) + "," + String.format((Locale) null, "%.6f", cache.longitude); final Display display = ((WindowManager) activity.getSystemService(Context.WINDOW_SERVICE)) .getDefaultDisplay(); final int maxWidth = display.getWidth() - 25; final int maxHeight = display.getHeight() - 25; int edge = 0; if (maxWidth > maxHeight) { edge = maxWidth; } else { edge = maxHeight; } String type = "mystery"; if (cache.found == true) { type = cache.type + "_found"; } else if (cache.disabled == true) { type = cache.type + "_disabled"; } else { type = cache.type; } final String markerUrl = urlencode_rfc3986( "http://cgeo.carnero.cc/_markers/marker_cache_" + type + ".png"); final StringBuilder waypoints = new StringBuilder(); if (cache.waypoints != null && cache.waypoints.size() > 0) { for (cgWaypoint waypoint : cache.waypoints) { if (waypoint.latitude == null && waypoint.longitude == null) { continue; } waypoints.append("&markers=icon%3Ahttp://cgeo.carnero.cc/_markers/marker_waypoint_"); waypoints.append(waypoint.type); waypoints.append(".png%7C"); waypoints.append(String.format((Locale) null, "%.6f", waypoint.latitude)); waypoints.append(","); waypoints.append(String.format((Locale) null, "%.6f", waypoint.longitude)); } } // download map images in separate background thread for higher performance final String code = cache.geocode; final int finalEdge = edge; Thread staticMapsThread = new Thread("getting static map") { @Override public void run() { cgMapImg mapGetter = new cgMapImg(settings, code); mapGetter.getDrawable( "http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=20&size=" + finalEdge + "x" + finalEdge + "&maptype=satellite&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 1); mapGetter.getDrawable( "http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=18&size=" + finalEdge + "x" + finalEdge + "&maptype=satellite&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 2); mapGetter.getDrawable( "http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=16&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 3); mapGetter.getDrawable( "http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=14&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 4); mapGetter.getDrawable( "http://maps.google.com/maps/api/staticmap?center=" + latlonMap + "&zoom=11&size=" + finalEdge + "x" + finalEdge + "&maptype=roadmap&markers=icon%3A" + markerUrl + "%7C" + latlonMap + waypoints.toString() + "&sensor=false", 5); } }; staticMapsThread.setPriority(Thread.MIN_PRIORITY); staticMapsThread.start(); } app.markStored(cache.geocode, listId); app.removeCacheFromCache(cache.geocode); if (handler != null) { handler.sendMessage(new Message()); } } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.storeCache: " + e.toString()); } } public void dropCache(cgeoapplication app, Activity activity, cgCache cache, Handler handler) { try { app.markDropped(cache.geocode); app.removeCacheFromCache(cache.geocode); handler.sendMessage(new Message()); } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.dropCache: " + e.toString()); } } public boolean isInViewPort(int centerLat1, int centerLon1, int centerLat2, int centerLon2, int spanLat1, int spanLon1, int spanLat2, int spanLon2) { try { // expects coordinates in E6 format final int left1 = centerLat1 - (spanLat1 / 2); final int right1 = centerLat1 + (spanLat1 / 2); final int top1 = centerLon1 + (spanLon1 / 2); final int bottom1 = centerLon1 - (spanLon1 / 2); final int left2 = centerLat2 - (spanLat2 / 2); final int right2 = centerLat2 + (spanLat2 / 2); final int top2 = centerLon2 + (spanLon2 / 2); final int bottom2 = centerLon2 - (spanLon2 / 2); if (left2 <= left1) { return false; } if (right2 >= right1) { return false; } if (top2 >= top1) { return false; } if (bottom2 <= bottom1) { return false; } return true; } catch (Exception e) { Log.e(cgSettings.tag, "cgBase.isInViewPort: " + e.toString()); return false; } } public boolean isCacheInViewPort(int centerLat, int centerLon, int spanLat, int spanLon, Double cacheLat, Double cacheLon) { if (cacheLat == null || cacheLon == null) { return false; } // viewport is defined by center, span and some (10%) reserve on every side int minLat = centerLat - (spanLat / 2) - (spanLat / 10); int maxLat = centerLat + (spanLat / 2) + (spanLat / 10); int minLon = centerLon - (spanLon / 2) - (spanLon / 10); int maxLon = centerLon + (spanLon / 2) + (spanLon / 10); int cLat = (int) Math.round(cacheLat * 1e6); int cLon = (int) Math.round(cacheLon * 1e6); int mid = 0; if (maxLat < minLat) { mid = minLat; minLat = maxLat; maxLat = mid; } if (maxLon < minLon) { mid = minLon; minLon = maxLon; maxLon = mid; } boolean latOk = false; boolean lonOk = false; if (cLat >= minLat && cLat <= maxLat) { latOk = true; } if (cLon >= minLon && cLon <= maxLon) { lonOk = true; } if (latOk == true && lonOk == true) { return true; } else { return false; } } private static char[] base64map1 = new char[64]; static { int i = 0; for (char c = 'A'; c <= 'Z'; c++) { base64map1[i++] = c; } for (char c = 'a'; c <= 'z'; c++) { base64map1[i++] = c; } for (char c = '0'; c <= '9'; c++) { base64map1[i++] = c; } base64map1[i++] = '+'; base64map1[i++] = '/'; } private static byte[] base64map2 = new byte[128]; static { for (int i = 0; i < base64map2.length; i++) { base64map2[i] = -1; } for (int i = 0; i < 64; i++) { base64map2[base64map1[i]] = (byte) i; } } public static String base64Encode(byte[] in) { int iLen = in.length; int oDataLen = (iLen * 4 + 2) / 3; // output length without padding int oLen = ((iLen + 2) / 3) * 4; // output length including padding char[] out = new char[oLen]; int ip = 0; int op = 0; while (ip < iLen) { int i0 = in[ip++] & 0xff; int i1 = ip < iLen ? in[ip++] & 0xff : 0; int i2 = ip < iLen ? in[ip++] & 0xff : 0; int o0 = i0 >>> 2; int o1 = ((i0 & 3) << 4) | (i1 >>> 4); int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6); int o3 = i2 & 0x3F; out[op++] = base64map1[o0]; out[op++] = base64map1[o1]; out[op] = op < oDataLen ? base64map1[o2] : '='; op++; out[op] = op < oDataLen ? base64map1[o3] : '='; op++; } return new String(out); } public static byte[] base64Decode(String text) { char[] in = text.toCharArray(); int iLen = in.length; if (iLen % 4 != 0) { throw new IllegalArgumentException("Length of Base64 encoded input string is not a multiple of 4."); } while (iLen > 0 && in[iLen - 1] == '=') { iLen--; } int oLen = (iLen * 3) / 4; byte[] out = new byte[oLen]; int ip = 0; int op = 0; while (ip < iLen) { int i0 = in[ip++]; int i1 = in[ip++]; int i2 = ip < iLen ? in[ip++] : 'A'; int i3 = ip < iLen ? in[ip++] : 'A'; if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127) { throw new IllegalArgumentException("Illegal character in Base64 encoded data."); } int b0 = base64map2[i0]; int b1 = base64map2[i1]; int b2 = base64map2[i2]; int b3 = base64map2[i3]; if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0) { throw new IllegalArgumentException("Illegal character in Base64 encoded data."); } int o0 = (b0 << 2) | (b1 >>> 4); int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2); int o2 = ((b2 & 3) << 6) | b3; out[op++] = (byte) o0; if (op < oLen) { out[op++] = (byte) o1; } if (op < oLen) { out[op++] = (byte) o2; } } return out; } public int getIcon(boolean cache, String type, boolean own, boolean found, boolean disabled) { if (gcIcons.isEmpty()) { // default markers gcIcons.put("ape", R.drawable.marker_cache_ape); gcIcons.put("cito", R.drawable.marker_cache_cito); gcIcons.put("earth", R.drawable.marker_cache_earth); gcIcons.put("event", R.drawable.marker_cache_event); gcIcons.put("letterbox", R.drawable.marker_cache_letterbox); gcIcons.put("locationless", R.drawable.marker_cache_locationless); gcIcons.put("mega", R.drawable.marker_cache_mega); gcIcons.put("multi", R.drawable.marker_cache_multi); gcIcons.put("traditional", R.drawable.marker_cache_traditional); gcIcons.put("virtual", R.drawable.marker_cache_virtual); gcIcons.put("webcam", R.drawable.marker_cache_webcam); gcIcons.put("wherigo", R.drawable.marker_cache_wherigo); gcIcons.put("mystery", R.drawable.marker_cache_mystery); gcIcons.put("gchq", R.drawable.marker_cache_gchq); // own cache markers gcIcons.put("ape-own", R.drawable.marker_cache_ape_own); gcIcons.put("cito-own", R.drawable.marker_cache_cito_own); gcIcons.put("earth-own", R.drawable.marker_cache_earth_own); gcIcons.put("event-own", R.drawable.marker_cache_event_own); gcIcons.put("letterbox-own", R.drawable.marker_cache_letterbox_own); gcIcons.put("locationless-own", R.drawable.marker_cache_locationless_own); gcIcons.put("mega-own", R.drawable.marker_cache_mega_own); gcIcons.put("multi-own", R.drawable.marker_cache_multi_own); gcIcons.put("traditional-own", R.drawable.marker_cache_traditional_own); gcIcons.put("virtual-own", R.drawable.marker_cache_virtual_own); gcIcons.put("webcam-own", R.drawable.marker_cache_webcam_own); gcIcons.put("wherigo-own", R.drawable.marker_cache_wherigo_own); gcIcons.put("mystery-own", R.drawable.marker_cache_mystery_own); gcIcons.put("gchq-own", R.drawable.marker_cache_gchq_own); // found cache markers gcIcons.put("ape-found", R.drawable.marker_cache_ape_found); gcIcons.put("cito-found", R.drawable.marker_cache_cito_found); gcIcons.put("earth-found", R.drawable.marker_cache_earth_found); gcIcons.put("event-found", R.drawable.marker_cache_event_found); gcIcons.put("letterbox-found", R.drawable.marker_cache_letterbox_found); gcIcons.put("locationless-found", R.drawable.marker_cache_locationless_found); gcIcons.put("mega-found", R.drawable.marker_cache_mega_found); gcIcons.put("multi-found", R.drawable.marker_cache_multi_found); gcIcons.put("traditional-found", R.drawable.marker_cache_traditional_found); gcIcons.put("virtual-found", R.drawable.marker_cache_virtual_found); gcIcons.put("webcam-found", R.drawable.marker_cache_webcam_found); gcIcons.put("wherigo-found", R.drawable.marker_cache_wherigo_found); gcIcons.put("mystery-found", R.drawable.marker_cache_mystery_found); gcIcons.put("gchq-found", R.drawable.marker_cache_gchq_found); // disabled cache markers gcIcons.put("ape-disabled", R.drawable.marker_cache_ape_disabled); gcIcons.put("cito-disabled", R.drawable.marker_cache_cito_disabled); gcIcons.put("earth-disabled", R.drawable.marker_cache_earth_disabled); gcIcons.put("event-disabled", R.drawable.marker_cache_event_disabled); gcIcons.put("letterbox-disabled", R.drawable.marker_cache_letterbox_disabled); gcIcons.put("locationless-disabled", R.drawable.marker_cache_locationless_disabled); gcIcons.put("mega-disabled", R.drawable.marker_cache_mega_disabled); gcIcons.put("multi-disabled", R.drawable.marker_cache_multi_disabled); gcIcons.put("traditional-disabled", R.drawable.marker_cache_traditional_disabled); gcIcons.put("virtual-disabled", R.drawable.marker_cache_virtual_disabled); gcIcons.put("webcam-disabled", R.drawable.marker_cache_webcam_disabled); gcIcons.put("wherigo-disabled", R.drawable.marker_cache_wherigo_disabled); gcIcons.put("mystery-disabled", R.drawable.marker_cache_mystery_disabled); gcIcons.put("gchq-disabled", R.drawable.marker_cache_gchq_disabled); } if (wpIcons.isEmpty()) { wpIcons.put("waypoint", R.drawable.marker_waypoint_waypoint); wpIcons.put("flag", R.drawable.marker_waypoint_flag); wpIcons.put("pkg", R.drawable.marker_waypoint_pkg); wpIcons.put("puzzle", R.drawable.marker_waypoint_puzzle); wpIcons.put("stage", R.drawable.marker_waypoint_stage); wpIcons.put("trailhead", R.drawable.marker_waypoint_trailhead); } int icon = -1; String iconTxt = null; if (cache == true) { if (type != null && type.length() > 0) { if (own == true) { iconTxt = type + "-own"; } else if (found == true) { iconTxt = type + "-found"; } else if (disabled == true) { iconTxt = type + "-disabled"; } else { iconTxt = type; } } else { iconTxt = "traditional"; } if (gcIcons.containsKey(iconTxt) == true) { icon = gcIcons.get(iconTxt); } else { icon = gcIcons.get("traditional"); } } else { if (type != null && type.length() > 0) { iconTxt = type; } else { iconTxt = "waypoint"; } if (wpIcons.containsKey(iconTxt) == true) { icon = wpIcons.get(iconTxt); } else { icon = wpIcons.get("waypoint"); } } return icon; } public boolean isLocus(Context context) { boolean locus = false; final Intent intentTest = new Intent(Intent.ACTION_VIEW); intentTest.setData(Uri.parse("menion.points:x")); if (isIntentAvailable(context, intentTest) == true) { locus = true; } return locus; } public boolean isRmaps(Context context) { boolean rmaps = false; final Intent intent = new Intent("com.robert.maps.action.SHOW_POINTS"); if (isIntentAvailable(context, intent) == true) { rmaps = true; } return rmaps; } public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude) { // waypoint return runExternalMap(application, activity, res, warning, tracker, null, null, latitude, longitude); } public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgWaypoint waypoint) { // waypoint return runExternalMap(application, activity, res, warning, tracker, null, waypoint, null, null); } public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgCache cache) { // cache return runExternalMap(application, activity, res, warning, tracker, cache, null, null, null); } public boolean runExternalMap(int application, Activity activity, Resources res, cgWarning warning, GoogleAnalyticsTracker tracker, cgCache cache, cgWaypoint waypoint, Double latitude, Double longitude) { if (cache == null && waypoint == null && latitude == null && longitude == null) { return false; } if (application == mapAppLocus) { // locus try { final Intent intentTest = new Intent(Intent.ACTION_VIEW); intentTest.setData(Uri.parse("menion.points:x")); if (isIntentAvailable(activity, intentTest) == true) { final ArrayList<cgWaypoint> waypoints = new ArrayList<cgWaypoint>(); // get only waypoints with coordinates if (cache != null && cache.waypoints != null && cache.waypoints.isEmpty() == false) { for (cgWaypoint wp : cache.waypoints) { if (wp.latitude != null && wp.longitude != null) { waypoints.add(wp); } } } final ByteArrayOutputStream baos = new ByteArrayOutputStream(); final DataOutputStream dos = new DataOutputStream(baos); dos.writeInt(1); // not used if (cache != null) { if (waypoints == null || waypoints.isEmpty() == true) { dos.writeInt(1); // cache only } else { dos.writeInt((1 + waypoints.size())); // cache and waypoints } } else { dos.writeInt(1); // one waypoint } int icon = -1; if (cache != null) { icon = getIcon(true, cache.type, cache.own, cache.found, cache.disabled || cache.archived); } else if (waypoint != null) { icon = getIcon(false, waypoint.type, false, false, false); } else { icon = getIcon(false, "waypoint", false, false, false); } if (icon > 0) { // load icon Bitmap bitmap = BitmapFactory.decodeResource(res, icon); ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos2); byte[] image = baos2.toByteArray(); dos.writeInt(image.length); dos.write(image); } else { // no icon dos.writeInt(0); // no image } // name if (cache != null && cache.name != null && cache.name.length() > 0) { dos.writeUTF(cache.name); } else if (waypoint != null && waypoint.name != null && waypoint.name.length() > 0) { dos.writeUTF(waypoint.name); } else { dos.writeUTF(""); } // description if (cache != null && cache.geocode != null && cache.geocode.length() > 0) { dos.writeUTF(cache.geocode.toUpperCase()); } else if (waypoint != null && waypoint.lookup != null && waypoint.lookup.length() > 0) { dos.writeUTF(waypoint.lookup.toUpperCase()); } else { dos.writeUTF(""); } // additional data :: keyword, button title, package, activity, data name, data content if (cache != null && cache.geocode != null && cache.geocode.length() > 0) { dos.writeUTF("intent;c:geo;carnero.cgeo;carnero.cgeo.cgeodetail;geocode;" + cache.geocode); } else if (waypoint != null && waypoint.id != null && waypoint.id > 0) { dos.writeUTF("intent;c:geo;carnero.cgeo;carnero.cgeo.cgeowaypoint;id;" + waypoint.id); } else { dos.writeUTF(""); } if (cache != null && cache.latitude != null && cache.longitude != null) { dos.writeDouble(cache.latitude); // latitude dos.writeDouble(cache.longitude); // longitude } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) { dos.writeDouble(waypoint.latitude); // latitude dos.writeDouble(waypoint.longitude); // longitude } else { dos.writeDouble(latitude); // latitude dos.writeDouble(longitude); // longitude } // cache waypoints if (waypoints != null && waypoints.isEmpty() == false) { for (cgWaypoint wp : waypoints) { if (wp == null || wp.latitude == null || wp.longitude == null) { continue; } final int wpIcon = getIcon(false, wp.type, false, false, false); if (wpIcon > 0) { // load icon Bitmap bitmap = BitmapFactory.decodeResource(res, wpIcon); ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos2); byte[] image = baos2.toByteArray(); dos.writeInt(image.length); dos.write(image); } else { // no icon dos.writeInt(0); // no image } // name if (wp.lookup != null && wp.lookup.length() > 0) { dos.writeUTF(wp.lookup.toUpperCase()); } else { dos.writeUTF(""); } // description if (wp.name != null && wp.name.length() > 0) { dos.writeUTF(wp.name); } else { dos.writeUTF(""); } // additional data :: keyword, button title, package, activity, data name, data content if (wp.id != null && wp.id > 0) { dos.writeUTF("intent;c:geo;carnero.cgeo;carnero.cgeo.cgeowaypoint;id;" + wp.id); } else { dos.writeUTF(""); } dos.writeDouble(wp.latitude); // latitude dos.writeDouble(wp.longitude); // longitude } } final Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setData(Uri.parse("menion.points:data")); intent.putExtra("data", baos.toByteArray()); activity.startActivity(intent); sendAnal(activity, tracker, "/external/locus"); return true; } } catch (Exception e) { // nothing } } if (application == mapAppRmaps) { // rmaps try { final Intent intent = new Intent("com.robert.maps.action.SHOW_POINTS"); if (isIntentAvailable(activity, intent) == true) { final ArrayList<String> locations = new ArrayList<String>(); if (cache != null && cache.latitude != null && cache.longitude != null) { locations.add(String.format((Locale) null, "%.6f", cache.latitude) + "," + String.format((Locale) null, "%.6f", cache.longitude) + ";" + cache.geocode + ";" + cache.name); } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) { locations.add(String.format((Locale) null, "%.6f", waypoint.latitude) + "," + String.format((Locale) null, "%.6f", waypoint.longitude) + ";" + waypoint.lookup + ";" + waypoint.name); } intent.putStringArrayListExtra("locations", locations); activity.startActivity(intent); sendAnal(activity, tracker, "/external/rmaps"); return true; } } catch (Exception e) { // nothing } } if (application == mapAppAny) { // fallback try { if (cache != null && cache.latitude != null && cache.longitude != null) { activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:" + cache.latitude + "," + cache.longitude))); // INFO: q parameter works with Google Maps, but breaks cooperation with all other apps } else if (waypoint != null && waypoint.latitude != null && waypoint.longitude != null) { activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("geo:" + waypoint.latitude + "," + waypoint.longitude))); // INFO: q parameter works with Google Maps, but breaks cooperation with all other apps } sendAnal(activity, tracker, "/external/native/maps"); return true; } catch (Exception e) { // nothing } } Log.i(cgSettings.tag, "cgBase.runExternalMap: No maps application available."); if (warning != null && res != null) { warning.showToast(res.getString(R.string.err_application_no)); } return false; } public boolean runNavigation(Activity activity, Resources res, cgSettings settings, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude) { return runNavigation(activity, res, settings, warning, tracker, latitude, longitude, null, null); } public boolean runNavigation(Activity activity, Resources res, cgSettings settings, cgWarning warning, GoogleAnalyticsTracker tracker, Double latitude, Double longitude, Double latitudeNow, Double longitudeNow) { if (activity == null) { return false; } if (settings == null) { return false; } // Google Navigation if (settings.useGNavigation == 1) { try { activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("google.navigation:ll=" + latitude + "," + longitude))); sendAnal(activity, tracker, "/external/native/navigation"); return true; } catch (Exception e) { // nothing } } // Google Maps Directions try { if (latitudeNow != null && longitudeNow != null) { activity.startActivity( new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google.com/maps?f=d&saddr=" + latitudeNow + "," + longitudeNow + "&daddr=" + latitude + "," + longitude))); } else { activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://maps.google.com/maps?f=d&daddr=" + latitude + "," + longitude))); } sendAnal(activity, tracker, "/external/native/maps"); return true; } catch (Exception e) { // nothing } Log.i(cgSettings.tag, "cgBase.runNavigation: No navigation application available."); if (warning != null && res != null) { warning.showToast(res.getString(R.string.err_navigation_no)); } return false; } public String getMapUserToken(Handler noTokenHandler) { final cgResponse response = request(false, "www.geocaching.com", "/map/default.aspx", "GET", "", 0, false); final String data = response.getData(); String usertoken = null; if (data != null && data.length() > 0) { final Pattern pattern = Pattern.compile("var userToken[^=]*=[^']*'([^']+)';", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE); final Matcher matcher = pattern.matcher(data); while (matcher.find()) { if (matcher.groupCount() > 0) { usertoken = matcher.group(1); } } } if (noTokenHandler != null && (usertoken == null || usertoken.length() == 0)) { noTokenHandler.sendEmptyMessage(0); } return usertoken; } public void sendAnal(Context context, String page) { (new sendAnalThread(context, null, page)).start(); } public void sendAnal(Context context, GoogleAnalyticsTracker tracker, String page) { (new sendAnalThread(context, tracker, page)).start(); } private class sendAnalThread extends Thread { Context context = null; GoogleAnalyticsTracker tracker = null; String page = null; boolean startedHere = false; public sendAnalThread(Context contextIn, GoogleAnalyticsTracker trackerIn, String pageIn) { context = contextIn; tracker = trackerIn; page = pageIn; } @Override public void run() { try { if (page == null || page.length() == 0) { page = "/"; } if (tracker == null && context != null) { startedHere = true; tracker = GoogleAnalyticsTracker.getInstance(); tracker.start(cgSettings.analytics, context); } tracker.trackPageView(page); tracker.dispatch(); Log.i(cgSettings.tag, "Logged use of " + page); if (startedHere == true) { tracker.stop(); } } catch (Exception e) { // nothing } } } public Double getElevation(Double latitude, Double longitude) { Double elv = null; try { final String host = "maps.googleapis.com"; final String path = "/maps/api/elevation/json"; final String params = "sensor=false&locations=" + String.format((Locale) null, "%.6f", latitude) + "," + String.format((Locale) null, "%.6f", longitude); final String data = requestJSON(host, path, params); if (data == null || data.length() == 0) { return elv; } JSONObject response = new JSONObject(data); String status = response.getString("status"); if (status == null || status.equalsIgnoreCase("OK") == false) { return elv; } if (response.has("results") == true) { JSONArray results = response.getJSONArray("results"); JSONObject result = results.getJSONObject(0); elv = result.getDouble("elevation"); } } catch (Exception e) { Log.w(cgSettings.tag, "cgBase.getElevation: " + e.toString()); } return elv; } public void showProgress(Activity activity, boolean status) { if (activity == null) { return; } final ProgressBar progress = (ProgressBar) activity.findViewById(R.id.actionbar_progress); if (status == true) { progress.setVisibility(View.VISIBLE); } else { progress.setVisibility(View.GONE); } } public void goHome(Activity activity) { final Intent intent = new Intent(activity, cgeo.class); intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); activity.startActivity(intent); activity.finish(); } public void setTitle(Activity activity, String text) { if (activity == null || text == null) { return; } final TextView title = (TextView) activity.findViewById(R.id.actionbar_title); if (title != null) { title.setText(text); } } }