// $codepro.audit.disable logExceptions package cgeo.geocaching; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.GCConnector; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.LogTypeTrackable; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.files.LocParser; import cgeo.geocaching.gcvote.GCVote; import cgeo.geocaching.gcvote.GCVoteRating; import cgeo.geocaching.geopoint.DistanceParser; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter.Format; import cgeo.geocaching.geopoint.IConversion; import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.HtmlImage; import cgeo.geocaching.twitter.Twitter; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.CancellableHandler; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.cookie.Cookie; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.BasicCookieStore; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.cookie.BasicClientCookie; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.CoreConnectionPNames; import org.apache.http.params.CoreProtocolPNames; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HTTP; import org.apache.http.util.EntityUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.res.Resources; import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.Handler; import android.os.Message; import android.text.Html; import android.text.Spannable; import android.text.Spanned; import android.text.format.DateUtils; import android.text.style.StrikethroughSpan; import android.util.Log; import android.view.LayoutInflater; import android.widget.EditText; import android.widget.ImageView; import android.widget.LinearLayout; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketException; import java.net.URLDecoder; import java.net.URLEncoder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.regex.Matcher; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLSession; public class cgBase { private static final String passMatch = "(?<=[\\?&])[Pp]ass(w(or)?d)?=[^&#$]+"; public final static Map waypointTypes = new HashMap(); private final static Map gcCustomDateFormats; static { final String[] formats = new String[] { "MM/dd/yyyy", "yyyy-MM-dd", "yyyy/MM/dd", "dd/MMM/yyyy", "MMM/dd/yyyy", "dd MMM yy", "dd/MM/yyyy" }; Map map = new HashMap(); for (String format : formats) { map.put(format, new SimpleDateFormat(format, Locale.ENGLISH)); } gcCustomDateFormats = Collections.unmodifiableMap(map); } private final static SimpleDateFormat dateTbIn1 = new SimpleDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009 private final static SimpleDateFormat dateTbIn2 = new SimpleDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009 public static String version = null; /** * FIXME: browser id should become part of settings (where it can be created more easily depending on the current * settings) */ private static 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"; private static Context context; private static Resources res; final private static Map gcIcons = new HashMap(); private static final int NB_DOWNLOAD_RETRIES = 4; public static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186; private cgBase() { //initialize(app); throw new UnsupportedOperationException(); // static class, not to be instantiated } public static void initialize(final cgeoapplication app) { context = app.getBaseContext(); res = app.getBaseContext().getResources(); // waypoint types for (WaypointType wt : WaypointType.values()) { if (wt != WaypointType.OWN) { waypointTypes.put(wt, res.getString(wt.stringId)); } } try { final PackageManager manager = app.getPackageManager(); final PackageInfo info = manager.getPackageInfo(app.getPackageName(), 0); version = info.versionName; } catch (PackageManager.NameNotFoundException e) { Log.e(Settings.tag, "unable to get version information", e); version = null; } if (Settings.isBrowser()) { final long rndBrowser = Math.round(Math.random() * 6); switch ((int) rndBrowser) { case 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"; break; case 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)"; break; case 2: idBrowser = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3"; break; case 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"; break; case 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"; break; case 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"; break; case 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"; break; default: 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"; break; } } } public static String hidePassword(final String message) { return message.replaceAll(passMatch, "password=***"); } public static void sendLoadProgressDetail(final Handler handler, final int str) { if (null != handler) { handler.obtainMessage(UPDATE_LOAD_PROGRESS_DETAIL, cgeoapplication.getInstance().getString(str)).sendToTarget(); } } /** * read all viewstates from page * * @return String[] with all view states */ public static String[] getViewstates(String page) { // Get the number of viewstates. // If there is only one viewstate, __VIEWSTATEFIELDCOUNT is not present if (page == null) { // no network access return null; } int count = 1; final Matcher matcherViewstateCount = GCConstants.PATTERN_VIEWSTATEFIELDCOUNT.matcher(page); if (matcherViewstateCount.find()) { count = Integer.parseInt(matcherViewstateCount.group(1)); } String[] viewstates = new String[count]; // Get the viewstates int no; final Matcher matcherViewstates = GCConstants.PATTERN_VIEWSTATES.matcher(page); while (matcherViewstates.find()) { String sno = matcherViewstates.group(1); // number of viewstate if ("".equals(sno)) { no = 0; } else { no = Integer.parseInt(sno); } viewstates[no] = matcherViewstates.group(2); } if (viewstates.length != 1 || viewstates[0] != null) { return viewstates; } // no viewstates were present return null; } /** * put viewstates into request parameters */ private static void putViewstates(final Parameters params, final String[] viewstates) { if (ArrayUtils.isEmpty(viewstates)) { return; } params.put("__VIEWSTATE", viewstates[0]); if (viewstates.length > 1) { for (int i = 1; i < viewstates.length; i++) { params.put("__VIEWSTATE" + i, viewstates[i]); } params.put("__VIEWSTATEFIELDCOUNT", viewstates.length + ""); } } /** * transfers the viewstates variables from a page (response) to parameters * (next request) */ public static void transferViewstates(final String page, final Parameters params) { putViewstates(params, getViewstates(page)); } /** * checks if an Array of Strings is empty or not. Empty means: * - Array is null * - or all elements are null or empty strings */ public static boolean isEmpty(String[] a) { if (a == null) { return true; } for (String s : a) { if (StringUtils.isNotEmpty(s)) { return false; } } return true; } public static StatusCode login() { final ImmutablePair login = Settings.getLogin(); if (login == null || StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) { Log.e(Settings.tag, "cgeoBase.login: No login information stored"); return StatusCode.NO_LOGIN_INFO_STORED; } HttpResponse loginResponse = request("https://www.geocaching.com/login/default.aspx", null, false, false, false); String loginData = getResponseData(loginResponse); if (loginResponse != null && loginResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(loginData, GCConstants.PATTERN_MAINTENANCE)) { return StatusCode.MAINTENANCE; } if (StringUtils.isBlank(loginData)) { Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (1st)"); return StatusCode.CONNECTION_FAILED; // no loginpage } if (checkLogin(loginData)) { Log.i(Settings.tag, "Already logged in Geocaching.com as " + login.left); switchToEnglish(loginData); return StatusCode.NO_ERROR; // logged in } clearCookies(); Settings.setCookieStore(null); final Parameters params = new Parameters( "__EVENTTARGET", "", "__EVENTARGUMENT", "", "ctl00$ContentBody$tbUsername", login.left, "ctl00$ContentBody$tbPassword", login.right, "ctl00$ContentBody$cbRememberMe", "on", "ctl00$ContentBody$btnSignIn", "Login"); final String[] viewstates = getViewstates(loginData); if (isEmpty(viewstates)) { Log.e(Settings.tag, "cgeoBase.login: Failed to find viewstates"); return StatusCode.LOGIN_PARSE_ERROR; // no viewstates } putViewstates(params, viewstates); loginResponse = postRequest("https://www.geocaching.com/login/default.aspx", params); loginData = getResponseData(loginResponse); if (StringUtils.isNotBlank(loginData)) { if (checkLogin(loginData)) { Log.i(Settings.tag, "Successfully logged in Geocaching.com as " + login.left); switchToEnglish(loginData); Settings.setCookieStore(dumpCookieStore()); return StatusCode.NO_ERROR; // logged in } else { if (loginData.contains("Your username/password combination does not match.")) { Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " because of wrong username/password"); return StatusCode.WRONG_LOGIN_DATA; // wrong login } else { Log.i(Settings.tag, "Failed to log in Geocaching.com as " + login.left + " for some unknown reason"); return StatusCode.UNKNOWN_ERROR; // can't login } } } else { Log.e(Settings.tag, "cgeoBase.login: Failed to retrieve login page (2nd)"); // FIXME: should it be CONNECTION_FAILED to match the first attempt? return StatusCode.COMMUNICATION_ERROR; // no login page } } public static StatusCode logout() { HttpResponse logoutResponse = request("https://www.geocaching.com/login/default.aspx?RESET=Y&redir=http%3a%2f%2fwww.geocaching.com%2fdefault.aspx%3f", null, false, false, false); String logoutData = getResponseData(logoutResponse); if (logoutResponse != null && logoutResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(logoutData, GCConstants.PATTERN_MAINTENANCE)) { return StatusCode.MAINTENANCE; } clearCookies(); Settings.setCookieStore(null); return StatusCode.NO_ERROR; } /** * Check if the user has been logged in when he retrieved the data. * * @param page * @return true = User has been logged in, false else */ private static boolean checkLogin(String page) { if (StringUtils.isBlank(page)) { Log.e(Settings.tag, "cgeoBase.checkLogin: No page given"); return false; } // on every page if (BaseUtils.matches(page, GCConstants.PATTERN_LOGGEDIN2)) { return true; } // after login if (BaseUtils.matches(page, GCConstants.PATTERN_LOGGEDIN)) { return true; } return false; } public static void switchToEnglish(String previousPage) { final String ENGLISH = "English▼"; if (previousPage != null && previousPage.indexOf(ENGLISH) >= 0) { Log.i(Settings.tag, "Geocaching.com language already set to English"); } else { final String page = getResponseData(request("http://www.geocaching.com/default.aspx", null, false)); if (page == null) { Log.e(Settings.tag, "Failed to read viewstates to set geocaching.com language"); } final Parameters params = new Parameters( "__EVENTTARGET", "ctl00$uxLocaleList$uxLocaleList$ctl00$uxLocaleItem", // switch to english "__EVENTARGUMENT", ""); transferViewstates(page, params); final HttpResponse response = postRequest("http://www.geocaching.com/default.aspx", params); if (!isSuccess(response)) { Log.e(Settings.tag, "Failed to set geocaching.com language to English"); } } } private static ParseResult parseSearch(final cgSearchThread thread, final String url, final String pageContent, final boolean showCaptcha) { if (StringUtils.isBlank(pageContent)) { Log.e(Settings.tag, "cgeoBase.parseSearch: No page given"); return null; } final List cids = new ArrayList(); final List guids = new ArrayList(); String recaptchaChallenge = null; String recaptchaText = null; String page = pageContent; final ParseResult parseResult = new ParseResult(); parseResult.url = url; parseResult.viewstates = getViewstates(page); // recaptcha if (showCaptcha) { String recaptchaJsParam = BaseUtils.getMatch(page, GCConstants.PATTERN_SEARCH_RECAPTCHA, false, null); if (recaptchaJsParam != null) { final Parameters params = new Parameters("k", recaptchaJsParam.trim()); final String recaptchaJs = cgBase.getResponseData(request("http://www.google.com/recaptcha/api/challenge", params, true)); if (StringUtils.isNotBlank(recaptchaJs)) { recaptchaChallenge = BaseUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, recaptchaChallenge, true); } } if (thread != null && StringUtils.isNotBlank(recaptchaChallenge)) { thread.setChallenge(recaptchaChallenge); thread.notifyNeed(); } } if (!page.contains("SearchResultsTable")) { // there are no results. aborting here avoids a wrong error log in the next parsing step return parseResult; } int startPos = page.indexOf("
"); int endPos = page.indexOf("ctl00_ContentBody_UnitTxt"); if (startPos == -1 || endPos == -1) { Log.e(Settings.tag, "cgeoBase.parseSearch: ID \"ctl00_ContentBody_UnitTxt\" not found on page"); return null; } page = page.substring(startPos + 1, endPos - startPos + 1); // cut between and
final String[] rows = page.split(" 0) { guids.add(matcherGuidAndDisabled.group(1)); cache.setGuid(matcherGuidAndDisabled.group(1)); if (matcherGuidAndDisabled.group(4) != null) { cache.setName(Html.fromHtml(matcherGuidAndDisabled.group(4).trim()).toString()); } if (matcherGuidAndDisabled.group(6) != null) { cache.setLocation(Html.fromHtml(matcherGuidAndDisabled.group(6).trim()).toString()); } final String attr = matcherGuidAndDisabled.group(2); if (attr != null) { cache.setDisabled(attr.contains("Strike")); cache.setArchived(attr.contains("OldWarning")); } } } } catch (Exception e) { // failed to parse GUID and/or Disabled Log.w(Settings.tag, "cgeoBase.parseSearch: Failed to parse GUID and/or Disabled data"); } if (Settings.isExcludeDisabledCaches() && (cache.isDisabled() || cache.isArchived())) { // skip disabled and archived caches continue; } String inventoryPre = null; cache.setGeocode(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_GEOCODE, true, 1, cache.getGeocode(), true).toUpperCase()); // cache type cache.setType(CacheType.getByPattern(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_TYPE, true, 1, null, true))); // cache direction - image if (Settings.getLoadDirImg()) { cache.setDirectionImg(URLDecoder.decode(BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_DIRECTION, true, 1, cache.getDirectionImg(), true))); } // cache inventory final Matcher matcherTbs = GCConstants.PATTERN_SEARCH_TRACKABLES.matcher(row); while (matcherTbs.find()) { if (matcherTbs.groupCount() > 0) { cache.setInventoryItems(Integer.parseInt(matcherTbs.group(1))); inventoryPre = matcherTbs.group(2); } } if (StringUtils.isNotBlank(inventoryPre)) { final Matcher matcherTbsInside = GCConstants.PATTERN_SEARCH_TRACKABLESINSIDE.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.getInventoryItems() <= 0) { cache.setInventoryItems(1); } } } } } // premium cache cache.setPremiumMembersOnly(row.contains("/images/small_profile.gif")); // found it cache.setFound(row.contains("/images/icons/icon_smile")); // own it cache.setOwn(row.contains("/images/silk/star.png")); // id String result = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_ID, null); if (null != result) { cache.setCacheId(result); cids.add(cache.getCacheId()); } // favourite count try { result = BaseUtils.getMatch(row, GCConstants.PATTERN_SEARCH_FAVORITE, false, 1, null, true); if (null != result) { cache.setFavoritePoints(Integer.parseInt(result)); } } catch (NumberFormatException e) { Log.w(Settings.tag, "cgeoBase.parseSearch: Failed to parse favourite count"); } if (cache.getNameSp() == null) { cache.setNameSp((new Spannable.Factory()).newSpannable(cache.getName())); if (cache.isDisabled() || cache.isArchived()) { // strike cache.getNameSp().setSpan(new StrikethroughSpan(), 0, cache.getNameSp().toString().length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } } parseResult.cacheList.add(cache); } // total caches found try { String result = BaseUtils.getMatch(page, GCConstants.PATTERN_SEARCH_TOTALCOUNT, false, 1, null, true); if (null != result) { parseResult.totalCnt = Integer.parseInt(result); } } catch (NumberFormatException e) { Log.w(Settings.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 || StringUtils.isNotBlank(recaptchaText))) { Log.i(Settings.tag, "Trying to get .loc for " + cids.size() + " caches"); try { // get coordinates for parsed caches final Parameters params = new Parameters( "__EVENTTARGET", "", "__EVENTARGUMENT", ""); if (ArrayUtils.isNotEmpty(parseResult.viewstates)) { params.put("__VIEWSTATE", parseResult.viewstates[0]); if (parseResult.viewstates.length > 1) { for (int i = 1; i < parseResult.viewstates.length; i++) { params.put("__VIEWSTATE" + i, parseResult.viewstates[i]); } params.put("__VIEWSTATEFIELDCOUNT", "" + parseResult.viewstates.length); } } for (String cid : cids) { params.put("CID", cid); } if (recaptchaChallenge != null && StringUtils.isNotBlank(recaptchaText)) { params.put("recaptcha_challenge_field", recaptchaChallenge); params.put("recaptcha_response_field", recaptchaText); } params.put("ctl00$ContentBody$uxDownloadLoc", "Download Waypoints"); final String coordinates = getResponseData(postRequest("http://www.geocaching.com/seek/nearest.aspx", params)); if (StringUtils.isNotBlank(coordinates)) { if (coordinates.contains("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")) { Log.i(Settings.tag, "User has not agreed to the license agreement. Can\'t download .loc file."); parseResult.error = StatusCode.UNAPPROVED_LICENSE; return parseResult; } } LocParser.parseLoc(parseResult, coordinates); } catch (Exception e) { Log.e(Settings.tag, "cgBase.parseSearch.CIDs: " + e.toString()); } } // get direction images if (Settings.getLoadDirImg()) { for (cgCache oneCache : parseResult.cacheList) { if (oneCache.getCoords() == null && StringUtils.isNotEmpty(oneCache.getDirectionImg())) { cgDirectionImg.getDrawable(oneCache.getGeocode(), oneCache.getDirectionImg()); } } } if (Settings.isRatingWanted()) { // get ratings if (guids.size() > 0) { Log.i(Settings.tag, "Trying to get ratings for " + cids.size() + " caches"); try { final Map ratings = GCVote.getRating(guids, null); if (MapUtils.isNotEmpty(ratings)) { // save found cache coordinates for (cgCache cache : parseResult.cacheList) { if (ratings.containsKey(cache.getGuid())) { GCVoteRating rating = ratings.get(cache.getGuid()); cache.setRating(rating.getRating()); cache.setVotes(rating.getVotes()); cache.setMyVote(rating.getMyVote()); } } } } catch (Exception e) { Log.e(Settings.tag, "cgBase.parseSearch.GCvote: " + e.toString()); } } } return parseResult; } public static ParseResult parseMapJSON(final String uri, final String data) { if (StringUtils.isEmpty(data)) { Log.e(Settings.tag, "cgeoBase.parseMapJSON: No page given"); return null; } final ParseResult parseResult = new ParseResult(); parseResult.url = uri; try { final JSONObject yoDawg = new JSONObject(data); final String json = yoDawg.getString("d"); if (StringUtils.isBlank(json)) { Log.e(Settings.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"); // unused, meaning not clearn boolean li = extra.getBoolean("li"); // expected meaning pm=premium member boolean pm = extra.getBoolean("pm"); if (Settings.isPremiumMember() && !pm) { parseResult.error = StatusCode.NOT_LOGGED_IN; } 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.setDetailed(false); // coords could be reliable but we only can detect that for premium members cacheToAdd.setReliableLatLon(pm); cacheToAdd.setGeocode(oneCache.getString("gc")); cacheToAdd.setCoords(new Geopoint(oneCache.getDouble("lat"), oneCache.getDouble("lon"))); cacheToAdd.setName(oneCache.getString("nn")); cacheToAdd.setFound(oneCache.getBoolean("f")); cacheToAdd.setOwn(oneCache.getBoolean("o")); cacheToAdd.setDisabled(!oneCache.getBoolean("ia")); int ctid = oneCache.getInt("ctid"); if (ctid == 2) { cacheToAdd.setType(CacheType.TRADITIONAL); } else if (ctid == 3) { cacheToAdd.setType(CacheType.MULTI); } else if (ctid == 4) { cacheToAdd.setType(CacheType.VIRTUAL); } else if (ctid == 5) { cacheToAdd.setType(CacheType.LETTERBOX); } else if (ctid == 6) { cacheToAdd.setType(CacheType.EVENT); } else if (ctid == 8) { cacheToAdd.setType(CacheType.MYSTERY); } else if (ctid == 11) { cacheToAdd.setType(CacheType.WEBCAM); } else if (ctid == 13) { cacheToAdd.setType(CacheType.CITO); } else if (ctid == 137) { cacheToAdd.setType(CacheType.EARTH); } else if (ctid == 453) { cacheToAdd.setType(CacheType.MEGA_EVENT); } else if (ctid == 1858) { cacheToAdd.setType(CacheType.WHERIGO); } else if (ctid == 3653) { cacheToAdd.setType(CacheType.LOSTANDFOUND); } else { cacheToAdd.setType(CacheType.UNKNOWN); } parseResult.cacheList.add(cacheToAdd); } } } else { Log.w(Settings.tag, "There are no caches in viewport"); } parseResult.totalCnt = parseResult.cacheList.size(); } } catch (Exception e) { Log.e(Settings.tag, "cgBase.parseMapJSON", e); } return parseResult; } public static ParseResult parseCache(final String page, final int listId, final CancellableHandler handler) { final ParseResult parseResult = parseCacheFromText(page, listId, handler); if (parseResult != null && !parseResult.cacheList.isEmpty()) { final cgCache cache = parseResult.cacheList.get(0); getExtraOnlineInfo(cache, page, handler); cache.setUpdated(System.currentTimeMillis()); cache.setDetailedUpdate(cache.getUpdated()); cache.setDetailed(true); } if (CancellableHandler.isCancelled(handler)) { return null; } return parseResult; } static ParseResult parseCacheFromText(final String page, final int listId, final CancellableHandler handler) { sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_details); if (StringUtils.isBlank(page)) { Log.e(Settings.tag, "cgeoBase.parseCache: No page given"); return null; } final ParseResult parseResult = new ParseResult(); if (page.contains("Cache is Unpublished")) { parseResult.error = StatusCode.UNPUBLISHED_CACHE; return parseResult; } if (page.contains("Sorry, the owner of this listing has made it viewable to Premium Members only.")) { parseResult.error = StatusCode.PREMIUM_ONLY; return parseResult; } if (page.contains("has chosen to make this cache listing visible to Premium Members only.")) { parseResult.error = StatusCode.PREMIUM_ONLY; return parseResult; } final cgCache cache = new cgCache(); cache.setDisabled(page.contains("
  • This cache is temporarily unavailable.")); cache.setArchived(page.contains("
  • This cache has been archived,")); cache.setPremiumMembersOnly(BaseUtils.matches(page, GCConstants.PATTERN_PREMIUMMEMBERS)); cache.setFavorite(BaseUtils.matches(page, GCConstants.PATTERN_FAVORITE)); cache.setListId(listId); // cache geocode cache.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_GEOCODE, true, cache.getGeocode())); // cache id cache.setCacheId(BaseUtils.getMatch(page, GCConstants.PATTERN_CACHEID, true, cache.getCacheId())); // cache guid cache.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_GUID, true, cache.getGuid())); // name cache.setName(Html.fromHtml(BaseUtils.getMatch(page, GCConstants.PATTERN_NAME, true, cache.getName())).toString()); // owner real name cache.setOwnerReal(URLDecoder.decode(BaseUtils.getMatch(page, GCConstants.PATTERN_OWNERREAL, true, cache.getOwnerReal()))); final String username = Settings.getUsername(); if (cache.getOwnerReal() != null && username != null && cache.getOwnerReal().equalsIgnoreCase(username)) { cache.setOwn(true); } String tableInside = page; int pos = tableInside.indexOf("id=\"cacheDetails\""); if (pos == -1) { Log.e(Settings.tag, "cgeoBase.parseCache: ID \"cacheDetails\" not found on page"); return null; } tableInside = tableInside.substring(pos); pos = tableInside.indexOf("