// $codepro.audit.disable logExceptions package cgeo.geocaching; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.gc.GCConnector; import cgeo.geocaching.connector.gc.GCConstants; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.RemoveFlag; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; 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.network.HtmlImage; import cgeo.geocaching.network.Login; import cgeo.geocaching.network.Network; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.ui.DirectionImage; import cgeo.geocaching.utils.BaseUtils; import cgeo.geocaching.utils.CancellableHandler; import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpResponse; 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.pm.ResolveInfo; import android.content.res.Resources; 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 java.net.URLDecoder; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.regex.Matcher; public class cgBase { 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; private static Context context; public static Resources res; public static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186; private cgBase() { //initialize(app); throw new UnsupportedOperationException(); // static class, not to be instantiated } /** * Called from AbstractActivity.onCreate() and AbstractListActivity.onCreate() * * @param app */ public static void initialize(final cgeoapplication app) { context = app.getBaseContext(); res = app.getBaseContext().getResources(); try { final PackageManager manager = app.getPackageManager(); final PackageInfo info = manager.getPackageInfo(app.getPackageName(), 0); version = info.versionName; } catch (PackageManager.NameNotFoundException e) { Log.e("unable to get version information", e); version = null; } } public static void sendLoadProgressDetail(final Handler handler, final int str) { if (null != handler) { handler.obtainMessage(UPDATE_LOAD_PROGRESS_DETAIL, cgeoapplication.getInstance().getString(str)).sendToTarget(); } } /** * 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; } private static SearchResult parseSearch(final cgSearchThread thread, final String url, final String pageContent, final boolean showCaptcha) { if (StringUtils.isBlank(pageContent)) { Log.e("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 SearchResult searchResult = new SearchResult(); searchResult.setUrl(url); searchResult.viewstates = Login.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 = Network.getResponseData(Network.getRequest("http://www.google.com/recaptcha/api/challenge", params)); if (StringUtils.isNotBlank(recaptchaJs)) { recaptchaChallenge = BaseUtils.getMatch(recaptchaJs, GCConstants.PATTERN_SEARCH_RECAPTCHACHALLENGE, true, 1, null, 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 searchResult; } int startPos = page.indexOf("
'); int endPos = page.indexOf("ctl00_ContentBody_UnitTxt"); if (startPos == -1 || endPos == -1) { Log.e("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("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("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); } } searchResult.addCache(cache); } // total caches found try { String result = BaseUtils.getMatch(page, GCConstants.PATTERN_SEARCH_TOTALCOUNT, false, 1, null, true); if (null != result) { searchResult.setTotal(Integer.parseInt(result)); } } catch (NumberFormatException e) { Log.w("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 && (Settings.isPremiumMember() || showCaptcha) && (recaptchaChallenge == null || StringUtils.isNotBlank(recaptchaText))) { Log.i("Trying to get .loc for " + cids.size() + " caches"); try { // get coordinates for parsed caches final Parameters params = new Parameters( "__EVENTTARGET", "", "__EVENTARGUMENT", ""); if (ArrayUtils.isNotEmpty(searchResult.viewstates)) { params.put("__VIEWSTATE", searchResult.viewstates[0]); if (searchResult.viewstates.length > 1) { for (int i = 1; i < searchResult.viewstates.length; i++) { params.put("__VIEWSTATE" + i, searchResult.viewstates[i]); } params.put("__VIEWSTATEFIELDCOUNT", String.valueOf(searchResult.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 = Network.getResponseData(Network.postRequest("http://www.geocaching.com/seek/nearest.aspx", params), false); 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("User has not agreed to the license agreement. Can\'t download .loc file."); searchResult.setError(StatusCode.UNAPPROVED_LICENSE); return searchResult; } } LocParser.parseLoc(searchResult, coordinates); } catch (Exception e) { Log.e("cgBase.parseSearch.CIDs: " + e.toString()); } } // get direction images if (Settings.getLoadDirImg()) { final Set caches = searchResult.getCachesFromSearchResult(LoadFlags.LOAD_CACHE_OR_DB); for (cgCache cache : caches) { if (cache.getCoords() == null && StringUtils.isNotEmpty(cache.getDirectionImg())) { DirectionImage.getDrawable(cache.getGeocode(), cache.getDirectionImg()); } } } return searchResult; } public static SearchResult parseCache(final String page, final CancellableHandler handler) { final SearchResult searchResult = parseCacheFromText(page, handler); if (searchResult != null && !searchResult.getGeocodes().isEmpty()) { final cgCache cache = searchResult.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB); getExtraOnlineInfo(cache, page, handler); cache.setUpdated(System.currentTimeMillis()); cache.setDetailedUpdate(cache.getUpdated()); cache.setDetailed(true); if (CancellableHandler.isCancelled(handler)) { return null; } // update progress message so user knows we're still working. Otherwise it will remain on whatever was set // in getExtraOnlineInfo (which could be logs, gcvote, or elevation) sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_render); // save full detailed caches cgeoapplication.getInstance().saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB)); } return searchResult; } static SearchResult parseCacheFromText(final String page, final CancellableHandler handler) { sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_details); if (StringUtils.isBlank(page)) { Log.e("cgeoBase.parseCache: No page given"); return null; } final SearchResult searchResult = new SearchResult(); if (page.contains("Cache is Unpublished") || page.contains("you cannot view this cache listing until it has been published")) { searchResult.setError(StatusCode.UNPUBLISHED_CACHE); return searchResult; } if (page.contains("Sorry, the owner of this listing has made it viewable to Premium Members only.")) { searchResult.setError(StatusCode.PREMIUM_ONLY); return searchResult; } if (page.contains("has chosen to make this cache listing visible to Premium Members only.")) { searchResult.setError(StatusCode.PREMIUM_ONLY); return searchResult; } final String cacheName = Html.fromHtml(BaseUtils.getMatch(page, GCConstants.PATTERN_NAME, true, "")).toString(); if ("An Error Has Occurred".equalsIgnoreCase(cacheName)) { searchResult.setError(StatusCode.UNKNOWN_ERROR); return searchResult; } 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 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(cacheName); // 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("cgeoBase.parseCache: ID \"cacheDetails\" not found on page"); return null; } tableInside = tableInside.substring(pos); pos = tableInside.indexOf("