aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/connector
diff options
context:
space:
mode:
authorBananeweizen <bananeweizen@gmx.de>2012-04-18 20:23:18 +0200
committerBananeweizen <bananeweizen@gmx.de>2012-04-18 20:23:18 +0200
commit45e1a0dc358e4a02b2394ae5c140692931eed8e7 (patch)
treeefbc3dfdc569f3ca915587f1788dcdd7da2f1d84 /main/src/cgeo/geocaching/connector
parentfd79c341e2890516494ead8559b108c225549aa8 (diff)
downloadcgeo-45e1a0dc358e4a02b2394ae5c140692931eed8e7.zip
cgeo-45e1a0dc358e4a02b2394ae5c140692931eed8e7.tar.gz
cgeo-45e1a0dc358e4a02b2394ae5c140692931eed8e7.tar.bz2
refactoring: rest in peace, cgBase
Diffstat (limited to 'main/src/cgeo/geocaching/connector')
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCBase.java3
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java5
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java1634
-rw-r--r--main/src/cgeo/geocaching/connector/gc/Login.java39
4 files changed, 1661 insertions, 20 deletions
diff --git a/main/src/cgeo/geocaching/connector/gc/GCBase.java b/main/src/cgeo/geocaching/connector/gc/GCBase.java
index e038573..2f22c52 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCBase.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCBase.java
@@ -2,7 +2,6 @@ package cgeo.geocaching.connector.gc;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.cgCache;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.enumerations.CacheSize;
@@ -185,7 +184,7 @@ public class GCBase {
if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY)) {
Geopoint center = viewport.getCenter();
if ((lastSearchViewport == null) || !lastSearchViewport.contains(center)) {
- SearchResult search = cgBase.searchByCoords(null, center, Settings.getCacheType(), false);
+ SearchResult search = GCParser.searchByCoords(null, center, Settings.getCacheType(), false);
if (search != null && !search.isEmpty()) {
final Set<String> geocodes = search.getGeocodes();
if (Settings.isPremiumMember()) {
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index f539d58..a431359 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -3,7 +3,6 @@ package cgeo.geocaching.connector.gc;
import cgeo.geocaching.R;
import cgeo.geocaching.SearchResult;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
import cgeo.geocaching.cgCache;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.connector.AbstractConnector;
@@ -101,7 +100,7 @@ public class GCConnector extends AbstractConnector {
params.put("log", "y");
params.put("numlogs", String.valueOf(GCConstants.NUMBER_OF_LOGS));
- cgBase.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage);
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage);
final String page = Login.getRequestLogged("http://www.geocaching.com/seek/cache_details.aspx", params);
@@ -124,7 +123,7 @@ public class GCConnector extends AbstractConnector {
return search;
}
- final SearchResult searchResult = cgBase.parseCache(page, handler);
+ final SearchResult searchResult = GCParser.parseCache(page, handler);
if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) {
Log.e("cgeoBase.searchByGeocode: No cache parsed");
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
new file mode 100644
index 0000000..b6d8f26
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -0,0 +1,1634 @@
+package cgeo.geocaching.connector.gc;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.SearchResult;
+import cgeo.geocaching.Settings;
+import cgeo.geocaching.cgCache;
+import cgeo.geocaching.cgImage;
+import cgeo.geocaching.cgLog;
+import cgeo.geocaching.cgSearchThread;
+import cgeo.geocaching.cgTrackable;
+import cgeo.geocaching.cgTrackableLog;
+import cgeo.geocaching.cgWaypoint;
+import cgeo.geocaching.cgeoapplication;
+import cgeo.geocaching.enumerations.CacheSize;
+import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.enumerations.LoadFlags;
+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.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.net.Uri;
+import android.text.Html;
+import android.text.Spannable;
+import android.text.Spanned;
+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 abstract class GCParser {
+ 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
+
+ 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<String> cids = new ArrayList<String>();
+ final List<String> guids = new ArrayList<String>();
+ 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("<div id=\"ctl00_ContentBody_ResultsPanel\"");
+ if (startPos == -1) {
+ Log.e("cgeoBase.parseSearch: ID \"ctl00_ContentBody_dlResults\" not found on page");
+ return null;
+ }
+
+ page = page.substring(startPos); // cut on <table
+
+ 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 <table> and </table>
+
+ final String[] rows = page.split("<tr class=");
+ final int rows_count = rows.length;
+
+ for (int z = 1; z < rows_count; z++) {
+ final cgCache cache = new cgCache();
+ String row = rows[z];
+
+ // check for cache type presence
+ if (!row.contains("images/wpttypes")) {
+ continue;
+ }
+
+ try {
+ final Matcher matcherGuidAndDisabled = GCConstants.PATTERN_SEARCH_GUIDANDDISABLED.matcher(row);
+
+ while (matcherGuidAndDisabled.find()) {
+ if (matcherGuidAndDisabled.groupCount() > 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());
+ }
+
+ // favorite 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<cgCache> 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)
+ CancellableHandler.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) {
+ CancellableHandler.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("<li>This cache is temporarily unavailable."));
+
+ cache.setArchived(page.contains("<li>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("<div class=\"CacheInformationTable\"");
+ if (pos == -1) {
+ Log.e("cgeoBase.parseCache: class \"CacheInformationTable\" not found on page");
+ return null;
+ }
+
+ tableInside = tableInside.substring(0, pos);
+
+ if (StringUtils.isNotBlank(tableInside)) {
+ // cache terrain
+ String result = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_TERRAIN, true, null);
+ if (result != null) {
+ cache.setTerrain(Float.parseFloat(StringUtils.replaceChars(result, '_', '.')));
+ }
+
+ // cache difficulty
+ result = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_DIFFICULTY, true, null);
+ if (result != null) {
+ cache.setDifficulty(Float.parseFloat(StringUtils.replaceChars(result, '_', '.')));
+ }
+
+ // owner
+ cache.setOwner(Html.fromHtml(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_OWNER, true, cache.getOwner())).toString());
+
+ // hidden
+ try {
+ String hiddenString = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDEN, true, null);
+ if (StringUtils.isNotBlank(hiddenString)) {
+ cache.setHidden(Login.parseGcCustomDate(hiddenString));
+ }
+ if (cache.getHiddenDate() == null) {
+ // event date
+ hiddenString = BaseUtils.getMatch(tableInside, GCConstants.PATTERN_HIDDENEVENT, true, null);
+ if (StringUtils.isNotBlank(hiddenString)) {
+ cache.setHidden(Login.parseGcCustomDate(hiddenString));
+ }
+ }
+ } catch (ParseException e) {
+ // failed to parse cache hidden date
+ Log.w("cgeoBase.parseCache: Failed to parse cache hidden (event) date");
+ }
+
+ // favourite
+ cache.setFavoritePoints(Integer.parseInt(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_FAVORITECOUNT, true, "0")));
+
+ // cache size
+ cache.setSize(CacheSize.getById(BaseUtils.getMatch(tableInside, GCConstants.PATTERN_SIZE, true, CacheSize.NOT_CHOSEN.id).toLowerCase()));
+ }
+
+ // cache found
+ cache.setFound(BaseUtils.matches(page, GCConstants.PATTERN_FOUND) || BaseUtils.matches(page, GCConstants.PATTERN_FOUND_ALTERNATIVE));
+
+ // cache type
+ cache.setType(CacheType.getByPattern(BaseUtils.getMatch(page, GCConstants.PATTERN_TYPE, true, cache.getType().id)));
+
+ // on watchlist
+ cache.setOnWatchlist(BaseUtils.matches(page, GCConstants.PATTERN_WATCHLIST));
+
+ // latitude and longitude. Can only be retrieved if user is logged in
+ cache.setLatlon(BaseUtils.getMatch(page, GCConstants.PATTERN_LATLON, true, cache.getLatlon()));
+ if (StringUtils.isNotEmpty(cache.getLatlon())) {
+ try {
+ cache.setCoords(new Geopoint(cache.getLatlon()));
+ cache.setReliableLatLon(true);
+ } catch (Geopoint.GeopointException e) {
+ Log.w("cgeoBase.parseCache: Failed to parse cache coordinates: " + e.toString());
+ }
+ }
+
+ // cache location
+ cache.setLocation(BaseUtils.getMatch(page, GCConstants.PATTERN_LOCATION, true, cache.getLocation()));
+
+ // cache hint
+ String result = BaseUtils.getMatch(page, GCConstants.PATTERN_HINT, false, null);
+ if (result != null) {
+ // replace linebreak and paragraph tags
+ String hint = GCConstants.PATTERN_LINEBREAK.matcher(result).replaceAll("\n");
+ if (hint != null) {
+ cache.setHint(StringUtils.replace(hint, "</p>", "").trim());
+ }
+ }
+
+ cache.checkFields();
+
+ // cache personal note
+ cache.setPersonalNote(BaseUtils.getMatch(page, GCConstants.PATTERN_PERSONALNOTE, true, cache.getPersonalNote()));
+
+ // cache short description
+ cache.setShortdesc(BaseUtils.getMatch(page, GCConstants.PATTERN_SHORTDESC, true, cache.getShortdesc()));
+
+ // cache description
+ cache.setDescription(BaseUtils.getMatch(page, GCConstants.PATTERN_DESC, true, ""));
+
+ // cache attributes
+ try {
+ final String attributesPre = BaseUtils.getMatch(page, GCConstants.PATTERN_ATTRIBUTES, true, null);
+ if (null != attributesPre) {
+ final Matcher matcherAttributesInside = GCConstants.PATTERN_ATTRIBUTESINSIDE.matcher(attributesPre);
+
+ while (matcherAttributesInside.find()) {
+ if (matcherAttributesInside.groupCount() > 1 && !matcherAttributesInside.group(2).equalsIgnoreCase("blank")) {
+ // 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('-', '_').toLowerCase();
+ }
+ }
+ cache.addAttribute(attribute);
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache attributes
+ Log.w("cgeoBase.parseCache: Failed to parse cache attributes");
+ }
+
+ // cache spoilers
+ try {
+ final String spoilers = BaseUtils.getMatch(page, GCConstants.PATTERN_SPOILERS, false, null);
+ if (null != spoilers) {
+ if (CancellableHandler.isCancelled(handler)) {
+ return null;
+ }
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_spoilers);
+
+ final Matcher matcherSpoilersInside = GCConstants.PATTERN_SPOILERSINSIDE.matcher(spoilers);
+
+ while (matcherSpoilersInside.find()) {
+ // the original spoiler URL (include .../display/... contains a low-resolution image
+ // if we shorten the URL we get the original-resolution image
+ String url = matcherSpoilersInside.group(1).replace("/display", "");
+
+ String title = null;
+ if (matcherSpoilersInside.group(2) != null) {
+ title = matcherSpoilersInside.group(2);
+ }
+ String description = null;
+ if (matcherSpoilersInside.group(3) != null) {
+ description = matcherSpoilersInside.group(3);
+ }
+ final cgImage spoiler = new cgImage(url, title, description);
+
+ if (cache.getSpoilers() == null) {
+ cache.setSpoilers(new ArrayList<cgImage>());
+ }
+ cache.getSpoilers().add(spoiler);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache spoilers
+ Log.w("cgeoBase.parseCache: Failed to parse cache spoilers");
+ }
+
+ // cache inventory
+ try {
+ cache.setInventoryItems(0);
+
+ final Matcher matcherInventory = GCConstants.PATTERN_INVENTORY.matcher(page);
+ if (matcherInventory.find()) {
+ if (cache.getInventory() == null) {
+ cache.setInventory(new ArrayList<cgTrackable>());
+ }
+
+ if (matcherInventory.groupCount() > 1) {
+ final String inventoryPre = matcherInventory.group(2);
+
+ if (StringUtils.isNotBlank(inventoryPre)) {
+ final Matcher matcherInventoryInside = GCConstants.PATTERN_INVENTORYINSIDE.matcher(inventoryPre);
+
+ while (matcherInventoryInside.find()) {
+ if (matcherInventoryInside.groupCount() > 0) {
+ final cgTrackable inventoryItem = new cgTrackable();
+ inventoryItem.setGuid(matcherInventoryInside.group(1));
+ inventoryItem.setName(matcherInventoryInside.group(2));
+
+ cache.getInventory().add(inventoryItem);
+ cache.setInventoryItems(cache.getInventoryItems() + 1);
+ }
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse cache inventory
+ Log.w("cgeoBase.parseCache: Failed to parse cache inventory (2)");
+ }
+
+ // cache logs counts
+ try
+ {
+ final String countlogs = BaseUtils.getMatch(page, GCConstants.PATTERN_COUNTLOGS, true, null);
+ if (null != countlogs) {
+ final Matcher matcherLog = GCConstants.PATTERN_COUNTLOG.matcher(countlogs);
+
+ while (matcherLog.find())
+ {
+ String typeStr = matcherLog.group(1);
+ String countStr = matcherLog.group(2).replaceAll("[.,]", "");
+
+ if (StringUtils.isNotBlank(typeStr)
+ && LogType.LOG_UNKNOWN != LogType.getByIconName(typeStr)
+ && StringUtils.isNotBlank(countStr)) {
+ cache.getLogCounts().put(LogType.getByIconName(typeStr), Integer.parseInt(countStr));
+ }
+ }
+ }
+ } catch (Exception e)
+ {
+ // failed to parse logs
+ Log.w("cgeoBase.parseCache: Failed to parse cache log count");
+ }
+
+ // add waypoint for original coordinates in case of user-modified listing-coordinates
+ try {
+ final String originalCoords = BaseUtils.getMatch(page, GCConstants.PATTERN_LATLON_ORIG, false, null);
+
+ if (null != originalCoords) {
+ final cgWaypoint waypoint = new cgWaypoint(cgeoapplication.getInstance().getString(R.string.cache_coordinates_original), WaypointType.WAYPOINT, false);
+ waypoint.setCoords(new Geopoint(originalCoords));
+ cache.addWaypoint(waypoint, false);
+ cache.setUserModifiedCoords(true);
+ }
+ } catch (Geopoint.GeopointException e) {
+ }
+
+ // waypoints
+ int wpBegin = 0;
+ int wpEnd = 0;
+
+ wpBegin = page.indexOf("<table class=\"Table\" id=\"ctl00_ContentBody_Waypoints\">");
+ if (wpBegin != -1) { // parse waypoints
+ if (CancellableHandler.isCancelled(handler)) {
+ return null;
+ }
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_waypoints);
+
+ String wpList = page.substring(wpBegin);
+
+ wpEnd = wpList.indexOf("</p>");
+ if (wpEnd > -1 && wpEnd <= wpList.length()) {
+ wpList = wpList.substring(0, wpEnd);
+ }
+
+ if (!wpList.contains("No additional waypoints to display.")) {
+ 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++) {
+ wp = wpItems[j].split("<td");
+
+ // waypoint name
+ // res is null during the unit tests
+ final String name = BaseUtils.getMatch(wp[6], GCConstants.PATTERN_WPNAME, true, 1, cgeoapplication.getInstance().getString(R.string.waypoint), true);
+
+ // waypoint type
+ final String resulttype = BaseUtils.getMatch(wp[3], GCConstants.PATTERN_WPTYPE, null);
+
+ final cgWaypoint waypoint = new cgWaypoint(name, WaypointType.findById(resulttype), false);
+
+ // waypoint prefix
+ waypoint.setPrefix(BaseUtils.getMatch(wp[4], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, true, 2, waypoint.getPrefix(), false));
+
+ // waypoint lookup
+ waypoint.setLookup(BaseUtils.getMatch(wp[5], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, true, 2, waypoint.getLookup(), false));
+
+ // waypoint latitude and logitude
+ String latlon = Html.fromHtml(BaseUtils.getMatch(wp[7], GCConstants.PATTERN_WPPREFIXORLOOKUPORLATLON, false, 2, "", false)).toString().trim();
+ if (!StringUtils.startsWith(latlon, "???")) {
+ waypoint.setLatlon(latlon);
+ waypoint.setCoords(new Geopoint(latlon));
+ }
+
+ j++;
+ if (wpItems.length > j) {
+ wp = wpItems[j].split("<td");
+ }
+
+ // waypoint note
+ waypoint.setNote(BaseUtils.getMatch(wp[3], GCConstants.PATTERN_WPNOTE, waypoint.getNote()));
+
+ cache.addWaypoint(waypoint, false);
+ }
+ }
+ }
+
+ cache.parseWaypointsFromNote();
+
+ // logs
+ cache.setLogs(loadLogsFromDetails(page, cache, false, true));
+
+ // last check for necessary cache conditions
+ if (StringUtils.isBlank(cache.getGeocode())) {
+ searchResult.setError(StatusCode.UNKNOWN_ERROR);
+ return searchResult;
+ }
+
+ searchResult.addCache(cache);
+ return searchResult;
+ }
+
+ public static SearchResult searchByNextPage(cgSearchThread thread, final SearchResult search, boolean showCaptcha) {
+ if (search == null) {
+ return search;
+ }
+ final String[] viewstates = search.getViewstates();
+
+ final String url = search.getUrl();
+
+ if (StringUtils.isBlank(url)) {
+ Log.e("cgeoBase.searchByNextPage: No url found");
+ return search;
+ }
+
+ if (Login.isEmpty(viewstates)) {
+ Log.e("cgeoBase.searchByNextPage: No viewstate given");
+ return search;
+ }
+
+ // As in the original code, remove the query string
+ final String uri = Uri.parse(url).buildUpon().query(null).build().toString();
+
+ final Parameters params = new Parameters(
+ "__EVENTTARGET", "ctl00$ContentBody$pgrBottom$ctl08",
+ "__EVENTARGUMENT", "");
+ Login.putViewstates(params, viewstates);
+
+ String page = Network.getResponseData(Network.postRequest(uri, params));
+ if (!Login.getLoginStatus(page)) {
+ final StatusCode loginState = Login.login();
+ if (loginState == StatusCode.NO_ERROR) {
+ page = Network.getResponseData(Network.postRequest(uri, params));
+ } else if (loginState == StatusCode.NO_LOGIN_INFO_STORED) {
+ Log.i("Working as guest.");
+ } else {
+ search.setError(loginState);
+ Log.e("cgeoBase.searchByNextPage: Can not log in geocaching");
+ return search;
+ }
+ }
+
+ if (StringUtils.isBlank(page)) {
+ Log.e("cgeoBase.searchByNextPage: No data from server");
+ return search;
+ }
+
+ final SearchResult searchResult = parseSearch(thread, url, page, showCaptcha);
+ if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) {
+ Log.e("cgeoBase.searchByNextPage: No cache parsed");
+ return search;
+ }
+
+ // save to application
+ search.setError(searchResult.getError());
+ search.setViewstates(searchResult.viewstates);
+ for (String geocode : searchResult.getGeocodes()) {
+ search.addGeocode(geocode);
+ }
+ return search;
+ }
+
+ /**
+ * Possibly hide caches found or hidden by user. This mutates its params argument when possible.
+ *
+ * @param params
+ * the parameters to mutate, or null to create a new Parameters if needed
+ * @param my
+ * @param addF
+ * @return the original params if not null, maybe augmented with f=1, or a new Parameters with f=1 or null otherwise
+ */
+ public static Parameters addFToParams(final Parameters params, final boolean my, final boolean addF) {
+ if (!my && Settings.isExcludeMyCaches() && addF) {
+ if (params == null) {
+ return new Parameters("f", "1");
+ }
+ params.put("f", "1");
+ Log.i("Skipping caches found or hidden by user.");
+ }
+
+ return params;
+ }
+
+ /**
+ * @param thread
+ * thread to run the captcha if needed
+ * @param cacheType
+ * @param listId
+ * @param showCaptcha
+ * @param params
+ * the parameters to add to the request URI
+ * @return
+ */
+ private static SearchResult searchByAny(final cgSearchThread thread, final CacheType cacheType, final boolean my, final boolean showCaptcha, final Parameters params) {
+ insertCacheType(params, cacheType);
+
+ final String uri = "http://www.geocaching.com/seek/nearest.aspx";
+ final String fullUri = uri + "?" + addFToParams(params, false, true);
+ final String page = Login.getRequestLogged(uri, addFToParams(params, my, true));
+
+ if (StringUtils.isBlank(page)) {
+ Log.e("cgeoBase.searchByAny: No data from server");
+ return null;
+ }
+
+ final SearchResult searchResult = parseSearch(thread, fullUri, page, showCaptcha);
+ if (searchResult == null || CollectionUtils.isEmpty(searchResult.getGeocodes())) {
+ Log.e("cgeoBase.searchByAny: No cache parsed");
+ return searchResult;
+ }
+
+ final SearchResult search = searchResult.filterSearchResults(Settings.isExcludeDisabledCaches(), false, cacheType);
+
+ Login.getLoginStatus(page);
+
+ return search;
+ }
+
+ public static SearchResult searchByCoords(final cgSearchThread thread, final Geopoint coords, final CacheType cacheType, final boolean showCaptcha) {
+ final Parameters params = new Parameters("lat", Double.toString(coords.getLatitude()), "lng", Double.toString(coords.getLongitude()));
+ return searchByAny(thread, cacheType, false, showCaptcha, params);
+ }
+
+ public static SearchResult searchByKeyword(final cgSearchThread thread, final String keyword, final CacheType cacheType, final boolean showCaptcha) {
+ if (StringUtils.isBlank(keyword)) {
+ Log.e("cgeoBase.searchByKeyword: No keyword given");
+ return null;
+ }
+
+ final Parameters params = new Parameters("key", keyword);
+ return searchByAny(thread, cacheType, false, showCaptcha, params);
+ }
+
+ public static SearchResult searchByUsername(final cgSearchThread thread, final String userName, final CacheType cacheType, final boolean showCaptcha) {
+ if (StringUtils.isBlank(userName)) {
+ Log.e("cgeoBase.searchByUsername: No user name given");
+ return null;
+ }
+
+ final Parameters params = new Parameters("ul", userName);
+
+ boolean my = false;
+ if (userName.equalsIgnoreCase(Settings.getLogin().left)) {
+ my = true;
+ Log.i("cgBase.searchByUsername: Overriding users choice, downloading all caches.");
+ }
+
+ return searchByAny(thread, cacheType, my, showCaptcha, params);
+ }
+
+ public static SearchResult searchByOwner(final cgSearchThread thread, final String userName, final CacheType cacheType, final boolean showCaptcha) {
+ if (StringUtils.isBlank(userName)) {
+ Log.e("cgeoBase.searchByOwner: No user name given");
+ return null;
+ }
+
+ final Parameters params = new Parameters("u", userName);
+ return searchByAny(thread, cacheType, false, showCaptcha, params);
+ }
+
+ public static cgTrackable searchTrackable(final String geocode, final String guid, final String id) {
+ if (StringUtils.isBlank(geocode) && StringUtils.isBlank(guid) && StringUtils.isBlank(id)) {
+ Log.w("cgeoBase.searchTrackable: No geocode nor guid nor id given");
+ return null;
+ }
+
+ cgTrackable trackable = new cgTrackable();
+
+ final Parameters params = new Parameters();
+ if (StringUtils.isNotBlank(geocode)) {
+ params.put("tracker", geocode);
+ trackable.setGeocode(geocode);
+ } else if (StringUtils.isNotBlank(guid)) {
+ params.put("guid", guid);
+ } else if (StringUtils.isNotBlank(id)) {
+ params.put("id", id);
+ }
+
+ final String page = Login.getRequestLogged("http://www.geocaching.com/track/details.aspx", params);
+
+ if (StringUtils.isBlank(page)) {
+ Log.e("cgeoBase.searchTrackable: No data from server");
+ return trackable;
+ }
+
+ trackable = parseTrackable(page, cgeoapplication.getInstance(), geocode);
+ if (trackable == null) {
+ Log.e("cgeoBase.searchTrackable: No trackable parsed");
+ return null;
+ }
+
+ return trackable;
+ }
+
+ public static StatusCode postLog(final String geocode, final String cacheid, final String[] viewstates,
+ final LogType logType, final int year, final int month, final int day,
+ final String log, final List<cgTrackableLog> trackables) {
+ if (Login.isEmpty(viewstates)) {
+ Log.e("cgeoBase.postLog: No viewstate given");
+ return StatusCode.LOG_POST_ERROR;
+ }
+
+ if (StringUtils.isBlank(log)) {
+ Log.e("cgeoBase.postLog: No log text given");
+ return StatusCode.NO_LOG_TEXT;
+ }
+
+ // 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(c));
+ logUpdated.append(';');
+ } else {
+ logUpdated.append(c);
+ }
+ }
+
+ final String logInfo = logUpdated.toString().replace("\n", "\r\n").trim(); // windows' eol and remove leading and trailing whitespaces
+
+ if (trackables != null) {
+ Log.i("Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: " + trackables.size());
+ } else {
+ Log.i("Trying to post log for cache #" + cacheid + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + logInfo + "; trackables: 0");
+ }
+
+ final Parameters params = new Parameters(
+ "__EVENTTARGET", "",
+ "__EVENTARGUMENT", "",
+ "__LASTFOCUS", "",
+ "ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType.id),
+ "ctl00$ContentBody$LogBookPanel1$DateTimeLogged", String.format("%02d", month) + "/" + String.format("%02d", day) + "/" + String.format("%04d", year),
+ "ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month", Integer.toString(month),
+ "ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Day", Integer.toString(day),
+ "ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year", Integer.toString(year),
+ "ctl00$ContentBody$LogBookPanel1$uxLogInfo", logInfo,
+ "ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry",
+ "ctl00$ContentBody$uxVistOtherListingGC", "");
+ Login.putViewstates(params, viewstates);
+ if (trackables != null && !trackables.isEmpty()) { // we have some trackables to proceed
+ final StringBuilder hdnSelected = new StringBuilder();
+
+ for (final cgTrackableLog tb : trackables) {
+ if (tb.action != LogTypeTrackable.DO_NOTHING) {
+ hdnSelected.append(Integer.toString(tb.id));
+ hdnSelected.append(tb.action.action);
+ hdnSelected.append(',');
+ }
+ }
+
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnSelectedActions", hdnSelected.toString(), // selected trackables
+ "ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", "");
+ }
+
+ final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/seek/log.aspx").encodedQuery("ID=" + cacheid).build().toString();
+ String page = Network.getResponseData(Network.postRequest(uri, params));
+ if (!Login.getLoginStatus(page)) {
+ final StatusCode loginState = Login.login();
+ if (loginState == StatusCode.NO_ERROR) {
+ page = Network.getResponseData(Network.postRequest(uri, params));
+ } else {
+ Log.e("cgeoBase.postLog: Can not log in geocaching (error: " + loginState + ")");
+ return loginState;
+ }
+ }
+
+ if (StringUtils.isBlank(page)) {
+ Log.e("cgeoBase.postLog: No data from server");
+ return StatusCode.NO_DATA_FROM_SERVER;
+ }
+
+ // maintenance, archived needs to be confirmed
+
+ final Matcher matcher = GCConstants.PATTERN_MAINTENANCE.matcher(page);
+
+ try {
+ if (matcher.find() && matcher.groupCount() > 0) {
+ final String[] viewstatesConfirm = Login.getViewstates(page);
+
+ if (Login.isEmpty(viewstatesConfirm)) {
+ Log.e("cgeoBase.postLog: No viewstate for confirm log");
+ return StatusCode.LOG_POST_ERROR;
+ }
+
+ params.clear();
+ Login.putViewstates(params, viewstatesConfirm);
+ params.put("__EVENTTARGET", "");
+ params.put("__EVENTARGUMENT", "");
+ params.put("__LASTFOCUS", "");
+ params.put("ctl00$ContentBody$LogBookPanel1$btnConfirm", "Yes");
+ params.put("ctl00$ContentBody$LogBookPanel1$uxLogInfo", logInfo);
+ params.put("ctl00$ContentBody$uxVistOtherListingGC", "");
+ if (trackables != null && !trackables.isEmpty()) { // 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) + tb.action.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 != LogTypeTrackable.DO_NOTHING) {
+ hdnSelected.append(action);
+ hdnSelected.append(',');
+ }
+ }
+
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnSelectedActions", hdnSelected.toString()); // selected trackables
+ params.put("ctl00$ContentBody$LogBookPanel1$uxTrackables$hdnCurrentFilter", "");
+ }
+
+ page = Network.getResponseData(Network.postRequest(uri, params));
+ }
+ } catch (Exception e) {
+ Log.e("cgeoBase.postLog.confim: " + e.toString());
+ }
+
+ try {
+
+ final Matcher matcherOk = GCConstants.PATTERN_OK1.matcher(page);
+ if (matcherOk.find()) {
+ Log.i("Log successfully posted to cache #" + cacheid);
+
+ if (geocode != null) {
+ cgeoapplication.getInstance().saveVisitDate(geocode);
+ }
+
+ Login.getLoginStatus(page);
+ // the log-successful-page contains still the old value
+ if (Login.getActualCachesFound() >= 0) {
+ Login.setActualCachesFound(Login.getActualCachesFound() + 1);
+ }
+ return StatusCode.NO_ERROR;
+ }
+ } catch (Exception e) {
+ Log.e("cgeoBase.postLog.check: " + e.toString());
+ }
+
+ Log.e("cgeoBase.postLog: Failed to post log because of unknown error");
+ return StatusCode.LOG_POST_ERROR;
+ }
+
+ public static StatusCode postLogTrackable(final String tbid, final String trackingCode, final String[] viewstates,
+ final LogType logType, final int year, final int month, final int day, final String log) {
+ if (Login.isEmpty(viewstates)) {
+ Log.e("cgeoBase.postLogTrackable: No viewstate given");
+ return StatusCode.LOG_POST_ERROR;
+ }
+
+ if (StringUtils.isBlank(log)) {
+ Log.e("cgeoBase.postLogTrackable: No log text given");
+ return StatusCode.NO_LOG_TEXT;
+ }
+
+ Log.i("Trying to post log for trackable #" + trackingCode + " - action: " + logType + "; date: " + year + "." + month + "." + day + ", log: " + log);
+
+ final String logInfo = log.replace("\n", "\r\n"); // windows' eol
+
+ final Calendar currentDate = Calendar.getInstance();
+ final Parameters params = new Parameters(
+ "__EVENTTARGET", "",
+ "__EVENTARGUMENT", "",
+ "__LASTFOCUS", "",
+ "ctl00$ContentBody$LogBookPanel1$ddLogType", Integer.toString(logType.id),
+ "ctl00$ContentBody$LogBookPanel1$tbCode", trackingCode);
+ Login.putViewstates(params, viewstates);
+ 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),
+ "ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Month", Integer.toString(month),
+ "ctl00$ContentBody$LogBookPanel1$DateTimeLogged$Year", Integer.toString(year),
+ "ctl00$ContentBody$LogBookPanel1$uxLogInfo", logInfo,
+ "ctl00$ContentBody$LogBookPanel1$LogButton", "Submit Log Entry",
+ "ctl00$ContentBody$uxVistOtherListingGC", "");
+
+ final String uri = new Uri.Builder().scheme("http").authority("www.geocaching.com").path("/track/log.aspx").encodedQuery("wid=" + tbid).build().toString();
+ String page = Network.getResponseData(Network.postRequest(uri, params));
+ if (!Login.getLoginStatus(page)) {
+ final StatusCode loginState = Login.login();
+ if (loginState == StatusCode.NO_ERROR) {
+ page = Network.getResponseData(Network.postRequest(uri, params));
+ } else {
+ Log.e("cgeoBase.postLogTrackable: Can not log in geocaching (error: " + loginState + ")");
+ return loginState;
+ }
+ }
+
+ if (StringUtils.isBlank(page)) {
+ Log.e("cgeoBase.postLogTrackable: No data from server");
+ return StatusCode.NO_DATA_FROM_SERVER;
+ }
+
+ try {
+
+ final Matcher matcherOk = GCConstants.PATTERN_OK2.matcher(page);
+ if (matcherOk.find()) {
+ Log.i("Log successfully posted to trackable #" + trackingCode);
+ return StatusCode.NO_ERROR;
+ }
+ } catch (Exception e) {
+ Log.e("cgeoBase.postLogTrackable.check: " + e.toString());
+ }
+
+ Log.e("cgeoBase.postLogTrackable: Failed to post log because of unknown error");
+ return StatusCode.LOG_POST_ERROR;
+ }
+
+ /**
+ * Adds the cache to the watchlist of the user.
+ *
+ * @param cache
+ * the cache to add
+ * @return -1: error occured
+ */
+ public static int addToWatchlist(final cgCache cache) {
+ final String uri = "http://www.geocaching.com/my/watchlist.aspx?w=" + cache.getCacheId();
+ String page = Login.postRequestLogged(uri);
+
+ if (StringUtils.isBlank(page)) {
+ Log.e("cgBase.addToWatchlist: No data from server");
+ return -1; // error
+ }
+
+ boolean guidOnPage = cache.isGuidContainedInPage(page);
+ if (guidOnPage) {
+ Log.i("cgBase.addToWatchlist: cache is on watchlist");
+ cache.setOnWatchlist(true);
+ } else {
+ Log.e("cgBase.addToWatchlist: cache is not on watchlist");
+ }
+ return guidOnPage ? 1 : -1; // on watchlist (=added) / else: error
+ }
+
+ /**
+ * Removes the cache from the watchlist
+ *
+ * @param cache
+ * the cache to remove
+ * @return -1: error occured
+ */
+ public static int removeFromWatchlist(final cgCache cache) {
+ final String uri = "http://www.geocaching.com/my/watchlist.aspx?ds=1&action=rem&id=" + cache.getCacheId();
+ String page = Login.postRequestLogged(uri);
+
+ if (StringUtils.isBlank(page)) {
+ Log.e("cgBase.removeFromWatchlist: No data from server");
+ return -1; // error
+ }
+
+ // removing cache from list needs approval by hitting "Yes" button
+ final Parameters params = new Parameters(
+ "__EVENTTARGET", "",
+ "__EVENTARGUMENT", "",
+ "ctl00$ContentBody$btnYes", "Yes");
+ Login.transferViewstates(page, params);
+
+ page = Network.getResponseData(Network.postRequest(uri, params));
+ boolean guidOnPage = cache.isGuidContainedInPage(page);
+ if (!guidOnPage) {
+ Log.i("cgBase.removeFromWatchlist: cache removed from watchlist");
+ cache.setOnWatchlist(false);
+ } else {
+ Log.e("cgBase.removeFromWatchlist: cache not removed from watchlist");
+ }
+ return guidOnPage ? -1 : 0; // on watchlist (=error) / not on watchlist
+ }
+
+ /**
+ * Parse a trackable HTML description into a cgTrackable object
+ *
+ * @param page
+ * the HTML page to parse, already processed through {@link BaseUtils#replaceWhitespace}
+ * @param app
+ * if not null, the application to use to save the trackable
+ * @return the parsed trackable, or null if none could be parsed
+ */
+ public static cgTrackable parseTrackable(final String page, final cgeoapplication app, final String possibleTrackingcode) {
+ if (StringUtils.isBlank(page)) {
+ Log.e("cgeoBase.parseTrackable: No page given");
+ return null;
+ }
+
+ final cgTrackable trackable = new cgTrackable();
+
+ // trackable geocode
+ trackable.setGeocode(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GEOCODE, true, trackable.getGeocode()).toUpperCase());
+
+ // trackable id
+ trackable.setGuid(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GUID, true, trackable.getGuid()));
+
+ // trackable icon
+ trackable.setIconUrl(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ICON, true, trackable.getIconUrl()));
+
+ // trackable name
+ trackable.setName(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_NAME, true, trackable.getName()));
+
+ // trackable type
+ if (StringUtils.isNotBlank(trackable.getName())) {
+ trackable.setType(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_TYPE, true, trackable.getType()));
+ }
+
+ // trackable owner name
+ try {
+ final Matcher matcherOwner = GCConstants.PATTERN_TRACKABLE_OWNER.matcher(page);
+ if (matcherOwner.find() && matcherOwner.groupCount() > 0) {
+ trackable.setOwnerGuid(matcherOwner.group(1));
+ trackable.setOwner(matcherOwner.group(2).trim());
+ }
+ } catch (Exception e) {
+ // failed to parse trackable owner name
+ Log.w("cgeoBase.parseTrackable: Failed to parse trackable owner name");
+ }
+
+ // trackable origin
+ trackable.setOrigin(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_ORIGIN, true, trackable.getOrigin()));
+
+ // trackable spotted
+ try {
+ final Matcher matcherSpottedCache = GCConstants.PATTERN_TRACKABLE_SPOTTEDCACHE.matcher(page);
+ if (matcherSpottedCache.find() && matcherSpottedCache.groupCount() > 0) {
+ trackable.setSpottedGuid(matcherSpottedCache.group(1));
+ trackable.setSpottedName(matcherSpottedCache.group(2).trim());
+ trackable.setSpottedType(cgTrackable.SPOTTED_CACHE);
+ }
+
+ final Matcher matcherSpottedUser = GCConstants.PATTERN_TRACKABLE_SPOTTEDUSER.matcher(page);
+ if (matcherSpottedUser.find() && matcherSpottedUser.groupCount() > 0) {
+ trackable.setSpottedGuid(matcherSpottedUser.group(1));
+ trackable.setSpottedName(matcherSpottedUser.group(2).trim());
+ trackable.setSpottedType(cgTrackable.SPOTTED_USER);
+ }
+
+ if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDUNKNOWN)) {
+ trackable.setSpottedType(cgTrackable.SPOTTED_UNKNOWN);
+ }
+
+ if (BaseUtils.matches(page, GCConstants.PATTERN_TRACKABLE_SPOTTEDOWNER)) {
+ trackable.setSpottedType(cgTrackable.SPOTTED_OWNER);
+ }
+ } catch (Exception e) {
+ // failed to parse trackable last known place
+ Log.w("cgeoBase.parseTrackable: Failed to parse trackable last known place");
+ }
+
+ // released date - can be missing on the page
+ try {
+ String releaseString = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_RELEASES, false, null);
+ if (releaseString != null) {
+ trackable.setReleased(dateTbIn1.parse(releaseString));
+ if (trackable.getReleased() == null) {
+ trackable.setReleased(dateTbIn2.parse(releaseString));
+ }
+ }
+ } catch (ParseException e1) {
+ trackable.setReleased(null);
+ }
+
+ // trackable distance
+ try {
+ final String distance = BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_DISTANCE, false, null);
+ if (null != distance) {
+ trackable.setDistance(DistanceParser.parseDistance(distance, Settings.isUseMetricUnits()));
+ }
+ } catch (NumberFormatException e) {
+ throw e;
+ }
+
+ // trackable goal
+ trackable.setGoal(BaseUtils.getMatch(page, GCConstants.PATTERN_TRACKABLE_GOAL, true, trackable.getGoal()));
+
+ // trackable details & image
+ try {
+ final Matcher matcherDetailsImage = GCConstants.PATTERN_TRACKABLE_DETAILSIMAGE.matcher(page);
+ if (matcherDetailsImage.find() && matcherDetailsImage.groupCount() > 0) {
+ final String image = StringUtils.trim(matcherDetailsImage.group(3));
+ final String details = StringUtils.trim(matcherDetailsImage.group(4));
+
+ if (StringUtils.isNotEmpty(image)) {
+ trackable.setImage(image);
+ }
+ if (StringUtils.isNotEmpty(details) && !StringUtils.equals(details, "No additional details available.")) {
+ trackable.setDetails(details);
+ }
+ }
+ } catch (Exception e) {
+ // failed to parse trackable details & image
+ Log.w("cgeoBase.parseTrackable: Failed to parse trackable details & image");
+ }
+
+ // trackable logs
+ try
+ {
+ final Matcher matcherLogs = GCConstants.PATTERN_TRACKABLE_LOG.matcher(page);
+ /*
+ * 1. Type (img)
+ * 2. Date
+ * 3. Author
+ * 4. Cache-GUID
+ * 5. <ignored> (strike-through property for ancien caches)
+ * 6. Cache-name
+ * 7. Logtext
+ */
+ while (matcherLogs.find())
+ {
+ final cgLog logDone = new cgLog();
+
+ logDone.type = LogType.getByIconName(matcherLogs.group(1));
+ logDone.author = Html.fromHtml(matcherLogs.group(3)).toString().trim();
+
+ try
+ {
+ logDone.date = Login.parseGcCustomDate(matcherLogs.group(2)).getTime();
+ } catch (ParseException e) {
+ }
+
+ logDone.log = matcherLogs.group(7).trim();
+
+ if (matcherLogs.group(4) != null && matcherLogs.group(6) != null)
+ {
+ logDone.cacheGuid = matcherLogs.group(4);
+ logDone.cacheName = matcherLogs.group(6);
+ }
+
+ // Apply the pattern for images in a trackable log entry against each full log (group(0))
+ final Matcher matcherLogImages = GCConstants.PATTERN_TRACKABLE_LOG_IMAGES.matcher(matcherLogs.group(0));
+ /*
+ * 1. Image URL
+ * 2. Image title
+ */
+ while (matcherLogImages.find())
+ {
+ final cgImage logImage = new cgImage(matcherLogImages.group(1), matcherLogImages.group(2));
+ if (logDone.logImages == null) {
+ logDone.logImages = new ArrayList<cgImage>();
+ }
+ logDone.logImages.add(logImage);
+ }
+
+ trackable.getLogs().add(logDone);
+ }
+ } catch (Exception e) {
+ // failed to parse logs
+ Log.w("cgeoBase.parseCache: Failed to parse cache logs" + e.toString());
+ }
+
+ // trackingcode
+ if (!StringUtils.equalsIgnoreCase(trackable.getGeocode(), possibleTrackingcode)) {
+ trackable.setTrackingcode(possibleTrackingcode);
+ }
+
+ if (app != null) {
+ app.saveTrackable(trackable);
+ }
+
+ return trackable;
+ }
+
+ /**
+ * Load logs from a cache details page.
+ *
+ * @param page
+ * the text of the details page
+ * @param cache
+ * the cache object to put the logs in
+ * @param friends
+ * retrieve friend logs
+ */
+ private static List<cgLog> loadLogsFromDetails(final String page, final cgCache cache, final boolean friends, final boolean getDataFromPage) {
+ String rawResponse = null;
+
+ if (!getDataFromPage) {
+ final Matcher userTokenMatcher = GCConstants.PATTERN_USERTOKEN2.matcher(page);
+ if (!userTokenMatcher.find()) {
+ Log.e("cgBase.loadLogsFromDetails: unable to extract userToken");
+ return null;
+ }
+
+ final String userToken = userTokenMatcher.group(1);
+ final Parameters params = new Parameters(
+ "tkn", userToken,
+ "idx", "1",
+ "num", String.valueOf(GCConstants.NUMBER_OF_LOGS),
+ "decrypt", "true",
+ // "sp", Boolean.toString(personal), // personal logs
+ "sf", Boolean.toString(friends));
+
+ final HttpResponse response = Network.getRequest("http://www.geocaching.com/seek/geocache.logbook", params);
+ if (response == null) {
+ Log.e("cgBase.loadLogsFromDetails: cannot log logs, response is null");
+ return null;
+ }
+ final int statusCode = response.getStatusLine().getStatusCode();
+ if (statusCode != 200) {
+ Log.e("cgBase.loadLogsFromDetails: error " + statusCode + " when requesting log information");
+ return null;
+ }
+ rawResponse = Network.getResponseData(response);
+ if (rawResponse == null) {
+ Log.e("cgBase.loadLogsFromDetails: unable to read whole response");
+ return null;
+ }
+ } else {
+ // extract embedded JSON data from page
+ rawResponse = BaseUtils.getMatch(page, GCConstants.PATTERN_LOGBOOK, "");
+ }
+
+ List<cgLog> logs = new ArrayList<cgLog>();
+
+ try {
+ final JSONObject resp = new JSONObject(rawResponse);
+ if (!resp.getString("status").equals("success")) {
+ Log.e("cgBase.loadLogsFromDetails: status is " + resp.getString("status"));
+ return null;
+ }
+
+ final JSONArray data = resp.getJSONArray("data");
+
+ for (int index = 0; index < data.length(); index++) {
+ final JSONObject entry = data.getJSONObject(index);
+ final cgLog logDone = new cgLog();
+ logDone.friend = friends;
+
+ // FIXME: use the "LogType" field instead of the "LogTypeImage" one.
+ final String logIconNameExt = entry.optString("LogTypeImage", ".gif");
+ final String logIconName = logIconNameExt.substring(0, logIconNameExt.length() - 4);
+ logDone.type = LogType.getByIconName(logIconName);
+
+ try {
+ logDone.date = Login.parseGcCustomDate(entry.getString("Visited")).getTime();
+ } catch (ParseException e) {
+ Log.e("cgBase.loadLogsFromDetails: failed to parse log date.");
+ }
+
+ logDone.author = entry.getString("UserName");
+ logDone.found = entry.getInt("GeocacheFindCount");
+ logDone.log = entry.getString("LogText");
+
+ final JSONArray images = entry.getJSONArray("Images");
+ for (int i = 0; i < images.length(); i++) {
+ final JSONObject image = images.getJSONObject(i);
+ String url = "http://img.geocaching.com/cache/log/" + image.getString("FileName");
+ String title = image.getString("Name");
+ final cgImage logImage = new cgImage(url, title);
+ if (logDone.logImages == null) {
+ logDone.logImages = new ArrayList<cgImage>();
+ }
+ logDone.logImages.add(logImage);
+ }
+
+ logs.add(logDone);
+ }
+ } catch (JSONException e) {
+ // failed to parse logs
+ Log.w("cgBase.loadLogsFromDetails: Failed to parse cache logs", e);
+ }
+
+ return logs;
+ }
+
+ public static List<LogType> parseTypes(String page) {
+ if (StringUtils.isEmpty(page)) {
+ return null;
+ }
+
+ final List<LogType> types = new ArrayList<LogType>();
+
+ final Matcher typeBoxMatcher = GCConstants.PATTERN_TYPEBOX.matcher(page);
+ String typesText = null;
+ if (typeBoxMatcher.find()) {
+ if (typeBoxMatcher.groupCount() > 0) {
+ typesText = typeBoxMatcher.group(1);
+ }
+ }
+
+ if (typesText != null) {
+
+ final Matcher typeMatcher = GCConstants.PATTERN_TYPE2.matcher(typesText);
+ while (typeMatcher.find()) {
+ if (typeMatcher.groupCount() > 1) {
+ final int type = Integer.parseInt(typeMatcher.group(2));
+
+ if (type > 0) {
+ types.add(LogType.getById(type));
+ }
+ }
+ }
+ }
+
+ return types;
+ }
+
+ public static List<cgTrackableLog> parseTrackableLog(final String page) {
+ if (StringUtils.isEmpty(page)) {
+ return null;
+ }
+
+ final List<cgTrackableLog> trackables = new ArrayList<cgTrackableLog>();
+
+ String table = StringUtils.substringBetween(page, "<table id=\"tblTravelBugs\"", "</table>");
+
+ // if no trackables are currently in the account, the table is not available, so return an empty list instead of null
+ if (StringUtils.isBlank(table)) {
+ return trackables;
+ }
+
+ table = StringUtils.substringBetween(table, "<tbody>", "</tbody>");
+ if (StringUtils.isBlank(table)) {
+ Log.e("cgeoBase.parseTrackableLog: tbody not found on page");
+ return null;
+ }
+
+ final Matcher trackableMatcher = GCConstants.PATTERN_TRACKABLE.matcher(page);
+ while (trackableMatcher.find()) {
+ if (trackableMatcher.groupCount() > 0) {
+ final cgTrackableLog trackableLog = new cgTrackableLog();
+
+ if (trackableMatcher.group(1) != null) {
+ trackableLog.trackCode = trackableMatcher.group(1);
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(2) != null) {
+ trackableLog.name = Html.fromHtml(trackableMatcher.group(2)).toString();
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(3) != null) {
+ trackableLog.ctl = Integer.valueOf(trackableMatcher.group(3));
+ } else {
+ continue;
+ }
+ if (trackableMatcher.group(5) != null) {
+ trackableLog.id = Integer.valueOf(trackableMatcher.group(5));
+ } else {
+ continue;
+ }
+
+ Log.i("Trackable in inventory (#" + trackableLog.ctl + "/" + trackableLog.id + "): " + trackableLog.trackCode + " - " + trackableLog.name);
+
+ trackables.add(trackableLog);
+ }
+ }
+
+ return trackables;
+ }
+
+ /**
+ * Insert the right cache type restriction in parameters
+ *
+ * @param params
+ * the parameters to insert the restriction into
+ * @param cacheType
+ * the type of cache, or null to include everything
+ */
+ static private void insertCacheType(final Parameters params, final CacheType cacheType) {
+ params.put("tx", cacheType.guid);
+ }
+
+ private static void getExtraOnlineInfo(final cgCache cache, final String page, final CancellableHandler handler) {
+ if (CancellableHandler.isCancelled(handler)) {
+ return;
+ }
+
+ //cache.setLogs(loadLogsFromDetails(page, cache, false));
+ if (Settings.isFriendLogsWanted()) {
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs);
+ List<cgLog> allLogs = cache.getLogs();
+ List<cgLog> friendLogs = loadLogsFromDetails(page, cache, true, false);
+ if (friendLogs != null) {
+ for (cgLog log : friendLogs) {
+ if (allLogs.contains(log)) {
+ allLogs.get(allLogs.indexOf(log)).friend = true;
+ } else {
+ allLogs.add(log);
+ }
+ }
+ }
+ }
+
+ if (Settings.isElevationWanted()) {
+ if (CancellableHandler.isCancelled(handler)) {
+ return;
+ }
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_elevation);
+ if (cache.getCoords() != null) {
+ cache.setElevation(cache.getCoords().getElevation());
+ }
+ }
+
+ if (Settings.isRatingWanted()) {
+ if (CancellableHandler.isCancelled(handler)) {
+ return;
+ }
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_gcvote);
+ final GCVoteRating rating = GCVote.getRating(cache.getGuid(), cache.getGeocode());
+ if (rating != null) {
+ cache.setRating(rating.getRating());
+ cache.setVotes(rating.getVotes());
+ cache.setMyVote(rating.getMyVote());
+ }
+ }
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/gc/Login.java b/main/src/cgeo/geocaching/connector/gc/Login.java
index 4605bc9..1e614df 100644
--- a/main/src/cgeo/geocaching/connector/gc/Login.java
+++ b/main/src/cgeo/geocaching/connector/gc/Login.java
@@ -2,7 +2,7 @@ package cgeo.geocaching.connector.gc;
import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
-import cgeo.geocaching.cgBase;
+import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.enumerations.StatusCode;
import cgeo.geocaching.network.Cookies;
import cgeo.geocaching.network.HtmlImage;
@@ -63,15 +63,12 @@ public abstract class Login {
final ImmutablePair<String, String> login = Settings.getLogin();
if (login == null || StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) {
- Login.setActualStatus(cgBase.res.getString(R.string.err_login));
+ Login.setActualStatus(cgeoapplication.getInstance().getString(R.string.err_login));
Log.e("cgeoBase.login: No login information stored");
return StatusCode.NO_LOGIN_INFO_STORED;
}
- // res is null during the unit tests
- if (cgBase.res != null) {
- Login.setActualStatus(cgBase.res.getString(R.string.init_login_popup_working));
- }
+ Login.setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_working));
HttpResponse loginResponse = Network.getRequest("https://www.geocaching.com/login/default.aspx");
String loginData = Network.getResponseData(loginResponse);
if (loginResponse != null && loginResponse.getStatusLine().getStatusCode() == 503 && BaseUtils.matches(loginData, GCConstants.PATTERN_MAINTENANCE)) {
@@ -100,7 +97,7 @@ public abstract class Login {
"ctl00$ContentBody$cbRememberMe", "on",
"ctl00$ContentBody$btnSignIn", "Login");
final String[] viewstates = Login.getViewstates(loginData);
- if (cgBase.isEmpty(viewstates)) {
+ if (isEmpty(viewstates)) {
Log.e("cgeoBase.login: Failed to find viewstates");
return StatusCode.LOGIN_PARSE_ERROR; // no viewstates
}
@@ -189,10 +186,7 @@ public abstract class Login {
return false;
}
- // res is null during the unit tests
- if (cgBase.res != null) {
- setActualStatus(cgBase.res.getString(R.string.init_login_popup_ok));
- }
+ setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_ok));
// on every page except login page
setActualLoginStatus(BaseUtils.matches(page, GCConstants.PATTERN_LOGIN_NAME));
@@ -210,10 +204,7 @@ public abstract class Login {
return true;
}
- // res is null during the unit tests
- if (cgBase.res != null) {
- setActualStatus(cgBase.res.getString(R.string.init_login_popup_failed));
- }
+ setActualStatus(cgeoapplication.getInstance().getString(R.string.init_login_popup_failed));
return false;
}
@@ -307,6 +298,24 @@ public abstract class Login {
}
/**
+ * 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;
+ }
+
+ /**
* read all viewstates from page
*
* @return String[] with all view states