aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/connector
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/connector')
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java16
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java40
-rw-r--r--main/src/cgeo/geocaching/connector/UserAction.java10
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECApi.java1
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECConnector.java2
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECLogin.java1
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java31
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLogin.java13
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCMap.java2
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCParser.java59
-rw-r--r--main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java113
-rw-r--r--main/src/cgeo/geocaching/connector/gc/SearchHandler.java126
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiClient.java41
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OXGPXParser.java4
-rw-r--r--main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java1
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java4
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java27
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java8
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java4
-rw-r--r--main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java17
20 files changed, 297 insertions, 223 deletions
diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java
index 53a3bcb..ca05439 100644
--- a/main/src/cgeo/geocaching/connector/AbstractConnector.java
+++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java
@@ -16,10 +16,10 @@ import cgeo.geocaching.connector.capability.ISearchByViewPort;
import cgeo.geocaching.enumerations.CacheType;
import cgeo.geocaching.enumerations.LogType;
import cgeo.geocaching.geopoint.Geopoint;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
import java.util.ArrayList;
import java.util.Collection;
@@ -255,21 +255,21 @@ public abstract class AbstractConnector implements IConnector {
List<UserAction> actions = getDefaultUserActions();
if (this instanceof ISearchByOwner) {
- actions.add(new UserAction(R.string.user_menu_view_hidden, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_view_hidden, new Action1<Context>() {
@Override
- public void run(Context context) {
+ public void call(Context context) {
CacheListActivity.startActivityOwner(context.activity, context.userName);
}
}));
}
if (this instanceof ISearchByFinder) {
- actions.add(new UserAction(R.string.user_menu_view_found, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_view_found, new Action1<UserAction.Context>() {
@Override
- public void run(Context context) {
- CacheListActivity.startActivityUserName(context.activity, context.userName);
+ public void call(Context context) {
+ CacheListActivity.startActivityFinder(context.activity, context.userName);
}
}));
}
@@ -283,10 +283,10 @@ public abstract class AbstractConnector implements IConnector {
public List<UserAction> getDefaultUserActions() {
final ArrayList<UserAction> actions = new ArrayList<UserAction>();
if (ContactsAddon.isAvailable()) {
- actions.add(new UserAction(R.string.user_menu_open_contact, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_open_contact, new Action1<UserAction.Context>() {
@Override
- public void run(Context context) {
+ public void call(Context context) {
ContactsAddon.openContactCard(context.activity, context.userName);
}
}));
diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
index 0081951..68e3142 100644
--- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java
+++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
@@ -27,6 +27,10 @@ import cgeo.geocaching.geopoint.Viewport;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.Observable;
+import rx.concurrency.Schedulers;
+import rx.util.functions.Func1;
+import rx.util.functions.Func2;
import java.util.ArrayList;
import java.util.Arrays;
@@ -176,14 +180,30 @@ public final class ConnectorFactory {
}
/** @see ISearchByViewPort#searchByViewport */
- public static SearchResult searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens) {
- final SearchResult result = new SearchResult();
- for (final ISearchByViewPort connector : searchByViewPortConns) {
- if (connector.isActive()) {
- result.addSearchResult(connector.searchByViewport(viewport, tokens));
+ public static Observable<SearchResult> searchByViewport(final @NonNull Viewport viewport, final MapTokens tokens) {
+ return Observable.from(searchByViewPortConns).filter(new Func1<ISearchByViewPort, Boolean>() {
+ @Override
+ public Boolean call(final ISearchByViewPort connector) {
+ return connector.isActive();
}
- }
- return result;
+ }).parallel(new Func1<Observable<ISearchByViewPort>, Observable<SearchResult>>() {
+ @Override
+ public Observable<SearchResult> call(final Observable<ISearchByViewPort> connector) {
+ return connector.map(new Func1<ISearchByViewPort, SearchResult>() {
+ @Override
+ public SearchResult call(final ISearchByViewPort connector) {
+ return connector.searchByViewport(viewport, tokens);
+ }
+ });
+ }
+ }, Schedulers.threadPoolForIO()).reduce(new SearchResult(), new Func2<SearchResult, SearchResult, SearchResult>() {
+
+ @Override
+ public SearchResult call(final SearchResult result, final SearchResult searchResult) {
+ result.addSearchResult(searchResult);
+ return result;
+ }
+ });
}
public static String getGeocodeFromURL(final String url) {
@@ -200,6 +220,12 @@ public final class ConnectorFactory {
return TRACKABLE_CONNECTORS;
}
+ /**
+ * Get the geocode of a trackable from a URL.
+ *
+ * @param url
+ * @return {@code null} if the URL cannot be decoded
+ */
public static String getTrackableFromURL(final String url) {
if (url == null) {
return null;
diff --git a/main/src/cgeo/geocaching/connector/UserAction.java b/main/src/cgeo/geocaching/connector/UserAction.java
index d0c97bb..da03a95 100644
--- a/main/src/cgeo/geocaching/connector/UserAction.java
+++ b/main/src/cgeo/geocaching/connector/UserAction.java
@@ -1,8 +1,7 @@
package cgeo.geocaching.connector;
-import cgeo.geocaching.utils.RunnableWithArgument;
-
import org.eclipse.jdt.annotation.NonNull;
+import rx.util.functions.Action1;
import android.app.Activity;
@@ -19,14 +18,15 @@ public class UserAction {
}
public final int displayResourceId;
- private final @NonNull RunnableWithArgument<Context> runnable;
+ private final @NonNull
+ Action1<Context> runnable;
- public UserAction(int displayResourceId, final @NonNull RunnableWithArgument<UserAction.Context> runnable) {
+ public UserAction(int displayResourceId, final @NonNull Action1<Context> runnable) {
this.displayResourceId = displayResourceId;
this.runnable = runnable;
}
public void run(Context context) {
- runnable.run(context);
+ runnable.call(context);
}
}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECApi.java b/main/src/cgeo/geocaching/connector/ec/ECApi.java
index 03fce4d..9d786ea 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECApi.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECApi.java
@@ -17,7 +17,6 @@ import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.FastDateFormat;
diff --git a/main/src/cgeo/geocaching/connector/ec/ECConnector.java b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
index 6da076b..71716fe 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECConnector.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
@@ -140,7 +140,7 @@ public class ECConnector extends AbstractConnector implements ISearchByGeocode,
// invoke settings activity to insert login details
if (status == StatusCode.NO_LOGIN_INFO_STORED && fromActivity != null) {
- SettingsActivity.jumpToServicesPage(fromActivity);
+ SettingsActivity.openForScreen(R.string.preference_screen_ec, fromActivity);
}
}
return status == StatusCode.NO_ERROR;
diff --git a/main/src/cgeo/geocaching/connector/ec/ECLogin.java b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
index 52bd423..012bdc9 100644
--- a/main/src/cgeo/geocaching/connector/ec/ECLogin.java
+++ b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
@@ -10,7 +10,6 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.Nullable;
diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
index e946748..a62b1f6 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java
@@ -27,12 +27,12 @@ import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.settings.SettingsActivity;
import cgeo.geocaching.utils.CancellableHandler;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.RunnableWithArgument;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import rx.util.functions.Action1;
import android.content.Context;
import android.content.Intent;
@@ -91,7 +91,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
public boolean supportsPersonalNote() {
- return Settings.isPremiumMember();
+ return Settings.isGCPremiumMember();
}
@Override
@@ -285,7 +285,22 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
@Override
protected String getCacheUrlPrefix() {
- return CACHE_URL_SHORT;
+ return null; // UNUSED
+ }
+
+ @Override
+ public String getGeocodeFromUrl(String url) {
+ // coord.info URLs
+ String code = StringUtils.substringAfterLast(url, "coord.info/");
+ if (code != null && canHandle(code)) {
+ return code;
+ }
+ // expanded geocaching.com URLs
+ code = StringUtils.substringBetween(url, "/geocache/", "_");
+ if (code != null && canHandle(code)) {
+ return code;
+ }
+ return null;
}
@Override
@@ -316,7 +331,7 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
// invoke settings activity to insert login details
if (status == StatusCode.NO_LOGIN_INFO_STORED && fromActivity != null) {
- SettingsActivity.jumpToServicesPage(fromActivity);
+ SettingsActivity.openForScreen(R.string.preference_screen_gc, fromActivity);
}
}
return status == StatusCode.NO_ERROR;
@@ -379,17 +394,17 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode,
public @NonNull
List<UserAction> getUserActions() {
List<UserAction> actions = super.getUserActions();
- actions.add(new UserAction(R.string.user_menu_open_browser, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_open_browser, new Action1<UserAction.Context>() {
@Override
- public void run(cgeo.geocaching.connector.UserAction.Context context) {
+ public void call(cgeo.geocaching.connector.UserAction.Context context) {
context.activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/profile/?u=" + Network.encode(context.userName))));
}
}));
- actions.add(new UserAction(R.string.user_menu_send_message, new RunnableWithArgument<UserAction.Context>() {
+ actions.add(new UserAction(R.string.user_menu_send_message, new Action1<UserAction.Context>() {
@Override
- public void run(cgeo.geocaching.connector.UserAction.Context context) {
+ public void call(cgeo.geocaching.connector.UserAction.Context context) {
context.activity.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.geocaching.com/email/?u=" + Network.encode(context.userName))));
}
}));
diff --git a/main/src/cgeo/geocaching/connector/gc/GCLogin.java b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
index a7cf6cf..92d488d 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCLogin.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCLogin.java
@@ -14,7 +14,6 @@ import cgeo.geocaching.utils.MatcherWrapper;
import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -97,7 +96,7 @@ public class GCLogin extends AbstractLogin {
}
if (getLoginStatus(loginData)) {
- Log.i("Already logged in Geocaching.com as " + username + " (" + Settings.getMemberStatus() + ')');
+ Log.i("Already logged in Geocaching.com as " + username + " (" + Settings.getGCMemberStatus() + ')');
if (switchToEnglish(loginData) && retry) {
return login(false);
}
@@ -132,7 +131,7 @@ public class GCLogin extends AbstractLogin {
assert loginData != null; // Caught above
if (getLoginStatus(loginData)) {
- Log.i("Successfully logged in Geocaching.com as " + username + " (" + Settings.getMemberStatus() + ')');
+ Log.i("Successfully logged in Geocaching.com as " + username + " (" + Settings.getGCMemberStatus() + ')');
if (switchToEnglish(loginData) && retry) {
return login(false);
@@ -204,9 +203,9 @@ public class GCLogin extends AbstractLogin {
Log.e("getLoginStatus: bad cache count", e);
}
setActualCachesFound(cachesCount);
- Settings.setMemberStatus(TextUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+ Settings.setGCMemberStatus(TextUtils.getMatch(page, GCConstants.PATTERN_MEMBER_STATUS, true, null));
if ( page.contains(GCConstants.MEMBER_STATUS_RENEW) ) {
- Settings.setMemberStatus(GCConstants.MEMBER_STATUS_PM);
+ Settings.setGCMemberStatus(GCConstants.MEMBER_STATUS_PM);
}
return true;
}
@@ -259,9 +258,9 @@ public class GCLogin extends AbstractLogin {
final String responseData = StringUtils.defaultString(Network.getResponseData(Network.getRequest("http://www.geocaching.com/my/")));
final String profile = TextUtils.replaceWhitespace(responseData);
- Settings.setMemberStatus(TextUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
+ Settings.setGCMemberStatus(TextUtils.getMatch(profile, GCConstants.PATTERN_MEMBER_STATUS, true, null));
if (profile.contains(GCConstants.MEMBER_STATUS_RENEW)) {
- Settings.setMemberStatus(GCConstants.MEMBER_STATUS_PM);
+ Settings.setGCMemberStatus(GCConstants.MEMBER_STATUS_PM);
}
setActualCachesFound(Integer.parseInt(TextUtils.getMatch(profile, GCConstants.PATTERN_CACHES_FOUND, true, "-1").replaceAll("[,.]", "")));
diff --git a/main/src/cgeo/geocaching/connector/gc/GCMap.java b/main/src/cgeo/geocaching/connector/gc/GCMap.java
index 6c94150..2782b64 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCMap.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCMap.java
@@ -368,7 +368,7 @@ public class GCMap {
}
}
- if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY) && Settings.isPremiumMember()) {
+ if (strategy.flags.contains(StrategyFlag.SEARCH_NEARBY) && Settings.isGCPremiumMember()) {
final Geopoint center = viewport.getCenter();
if ((lastSearchViewport == null) || !lastSearchViewport.contains(center)) {
//FIXME We don't have a RecaptchaReceiver!?
diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java
index 62ccb14..f60764d 100644
--- a/main/src/cgeo/geocaching/connector/gc/GCParser.java
+++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java
@@ -36,7 +36,6 @@ import cgeo.geocaching.utils.SynchronizedDateFormat;
import cgeo.geocaching.utils.TextUtils;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringEscapeUtils;
@@ -68,7 +67,7 @@ public abstract class GCParser {
private final static SynchronizedDateFormat dateTbIn1 = new SynchronizedDateFormat("EEEEE, dd MMMMM yyyy", Locale.ENGLISH); // Saturday, 28 March 2009
private final static SynchronizedDateFormat dateTbIn2 = new SynchronizedDateFormat("EEEEE, MMMMM dd, yyyy", Locale.ENGLISH); // Saturday, March 28, 2009
- private static SearchResult parseSearch(final String url, final String pageContent, final boolean showCaptcha, RecaptchaReceiver thread) {
+ private static SearchResult parseSearch(final String url, final String pageContent, final boolean showCaptcha, final RecaptchaReceiver recaptchaReceiver) {
if (StringUtils.isBlank(pageContent)) {
Log.e("GCParser.parseSearch: No page given");
return null;
@@ -86,12 +85,12 @@ public abstract class GCParser {
final String recaptchaJsParam = TextUtils.getMatch(page, GCConstants.PATTERN_SEARCH_RECAPTCHA, false, null);
if (recaptchaJsParam != null) {
- thread.setKey(recaptchaJsParam.trim());
+ recaptchaReceiver.setKey(recaptchaJsParam.trim());
- thread.fetchChallenge();
+ recaptchaReceiver.fetchChallenge();
}
- if (thread != null && StringUtils.isNotBlank(thread.getChallenge())) {
- thread.notifyNeed();
+ if (recaptchaReceiver != null && StringUtils.isNotBlank(recaptchaReceiver.getChallenge())) {
+ recaptchaReceiver.notifyNeed();
}
}
@@ -277,12 +276,12 @@ public abstract class GCParser {
}
String recaptchaText = null;
- if (thread != null && StringUtils.isNotBlank(thread.getChallenge())) {
- thread.waitForUser();
- recaptchaText = thread.getText();
+ if (recaptchaReceiver != null && StringUtils.isNotBlank(recaptchaReceiver.getChallenge())) {
+ recaptchaReceiver.waitForUser();
+ recaptchaText = recaptchaReceiver.getText();
}
- if (!cids.isEmpty() && (Settings.isPremiumMember() || showCaptcha) && ((thread == null || StringUtils.isBlank(thread.getChallenge())) || StringUtils.isNotBlank(recaptchaText))) {
+ if (!cids.isEmpty() && (Settings.isGCPremiumMember() || showCaptcha) && ((recaptchaReceiver == null || StringUtils.isBlank(recaptchaReceiver.getChallenge())) || StringUtils.isNotBlank(recaptchaText))) {
Log.i("Trying to get .loc for " + cids.size() + " caches");
try {
@@ -303,8 +302,8 @@ public abstract class GCParser {
params.put("CID", cid);
}
- if (thread != null && StringUtils.isNotBlank(thread.getChallenge()) && StringUtils.isNotBlank(recaptchaText)) {
- params.put("recaptcha_challenge_field", thread.getChallenge());
+ if (StringUtils.isNotBlank(recaptchaText) && recaptchaReceiver != null) {
+ params.put("recaptcha_challenge_field", recaptchaReceiver.getChallenge());
params.put("recaptcha_response_field", recaptchaText);
}
params.put("ctl00$ContentBody$uxDownloadLoc", "Download Waypoints");
@@ -347,6 +346,9 @@ public abstract class GCParser {
// attention: parseCacheFromText already stores implicitly through searchResult.addCache
if (searchResult != null && !searchResult.getGeocodes().isEmpty()) {
final Geocache cache = searchResult.getFirstCacheFromResult(LoadFlags.LOAD_CACHE_OR_DB);
+ if (cache == null) {
+ return null;
+ }
getExtraOnlineInfo(cache, page, handler);
// too late: it is already stored through parseCacheFromText
cache.setDetailedUpdatedNow();
@@ -741,7 +743,7 @@ public abstract class GCParser {
cache.parseWaypointsFromNote();
// logs
- cache.setLogs(loadLogsFromDetails(page, cache, false, true));
+ cache.setLogs(getLogsFromDetails(page, false));
// last check for necessary cache conditions
if (StringUtils.isBlank(cache.getGeocode())) {
@@ -1380,8 +1382,7 @@ public abstract class GCParser {
}
private static boolean changeFavorite(final Geocache cache, final boolean add) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
@@ -1400,6 +1401,11 @@ public abstract class GCParser {
return false;
}
+ private static String getUserToken(final Geocache cache) {
+ final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
+ return TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ }
+
/**
* Removes the cache from the favorites.
*
@@ -1613,19 +1619,20 @@ public abstract class GCParser {
}
/**
- * Load logs from a cache details page.
+ * Extract 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
+ * return friends logs only (will require a network request)
+ * @return a list of log entries or <code>null</code> if the logs could not be retrieved
+ *
*/
- private static List<LogEntry> loadLogsFromDetails(final String page, final Geocache cache, final boolean friends, final boolean getDataFromPage) {
+ @Nullable
+ private static List<LogEntry> getLogsFromDetails(final String page, final boolean friends) {
String rawResponse;
- if (!getDataFromPage) {
+ if (friends) {
final MatcherWrapper userTokenMatcher = new MatcherWrapper(GCConstants.PATTERN_USERTOKEN, page);
if (!userTokenMatcher.find()) {
Log.e("GCParser.loadLogsFromDetails: unable to extract userToken");
@@ -1712,7 +1719,7 @@ public abstract class GCParser {
final JSONArray images = entry.getJSONArray("Images");
for (int i = 0; i < images.length(); i++) {
final JSONObject image = images.getJSONObject(i);
- final String url = "http://img.geocaching.com/cache/log/large/" + image.getString("FileName");
+ final String url = "http://imgcdn.geocaching.com/cache/log/large/" + image.getString("FileName");
final String title = TextUtils.removeControlCharacters(image.getString("Name"));
final Image logImage = new Image(url, title);
logDone.addLogImage(logImage);
@@ -1825,7 +1832,7 @@ public abstract class GCParser {
if (Settings.isFriendLogsWanted()) {
CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_logs);
final List<LogEntry> allLogs = cache.getLogs();
- final List<LogEntry> friendLogs = loadLogsFromDetails(page, cache, true, false);
+ final List<LogEntry> friendLogs = getLogsFromDetails(page, true);
if (friendLogs != null) {
for (final LogEntry log : friendLogs) {
if (allLogs.contains(log)) {
@@ -1860,8 +1867,7 @@ public abstract class GCParser {
}
public static boolean editModifiedCoordinates(Geocache cache, Geopoint wpt) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
@@ -1896,8 +1902,7 @@ public abstract class GCParser {
}
public static boolean uploadPersonalNote(Geocache cache) {
- final String page = requestHtmlPage(cache.getGeocode(), null, "n", "0");
- final String userToken = TextUtils.getMatch(page, GCConstants.PATTERN_USERTOKEN, "");
+ final String userToken = getUserToken(cache);
if (StringUtils.isEmpty(userToken)) {
return false;
}
diff --git a/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java b/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java
new file mode 100644
index 0000000..0a34928
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/gc/RecaptchaHandler.java
@@ -0,0 +1,113 @@
+package cgeo.geocaching.connector.gc;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.loaders.RecaptchaReceiver;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.io.IOUtils;
+import rx.Observable;
+import rx.android.observables.AndroidObservable;
+import rx.concurrency.Schedulers;
+import rx.util.functions.Action1;
+import rx.util.functions.Func0;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.os.Handler;
+import android.os.Message;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+
+import java.io.InputStream;
+
+public class RecaptchaHandler extends Handler {
+ final public static int SHOW_CAPTCHA = 1;
+
+ final private Activity activity;
+ final private RecaptchaReceiver recaptchaReceiver;
+
+ public RecaptchaHandler(final Activity activity, final RecaptchaReceiver recaptchaReceiver) {
+ this.activity = activity;
+ this.recaptchaReceiver = recaptchaReceiver;
+ }
+
+ private void loadChallenge(final ImageView imageView, final View reloadButton) {
+ getCaptcha().subscribe(new Action1<Bitmap>() {
+ @Override
+ public void call(final Bitmap bitmap) {
+ imageView.setImageBitmap(bitmap);
+ }
+ }, new Action1<Throwable>() {
+ @Override
+ public void call(final Throwable throwable) {
+ // Do nothing
+ }
+ });
+ reloadButton.setEnabled(true);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == SHOW_CAPTCHA) {
+ final AlertDialog.Builder dlg = new AlertDialog.Builder(activity);
+ final View view = activity.getLayoutInflater().inflate(R.layout.recaptcha_dialog, null);
+
+ final ImageView imageView = (ImageView) view.findViewById(R.id.image);
+
+ final ImageButton reloadButton = (ImageButton) view.findViewById(R.id.button_recaptcha_refresh);
+ reloadButton.setEnabled(false);
+ reloadButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ recaptchaReceiver.fetchChallenge();
+ loadChallenge(imageView, reloadButton);
+ }
+ });
+
+ loadChallenge(imageView, reloadButton);
+
+ dlg.setTitle(activity.getString(R.string.caches_recaptcha_title));
+ dlg.setView(view);
+ dlg.setNeutralButton(activity.getString(R.string.caches_recaptcha_continue), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ final String text = ((EditText) view.findViewById(R.id.text)).getText().toString();
+ recaptchaReceiver.setText(text);
+ dialog.cancel();
+ }
+ });
+
+ dlg.create().show();
+ }
+ }
+
+ private Observable<Bitmap> getCaptcha() {
+ return AndroidObservable.fromActivity(activity,
+ Observable.defer(new Func0<Observable<? extends Bitmap>>() {
+ @Override
+ public Observable<? extends Bitmap> call() {
+ final String url = "http://www.google.com/recaptcha/api/image?c=" + recaptchaReceiver.getChallenge();
+ final InputStream is = Network.getResponseStream(Network.getRequest(url));
+ if (is != null) {
+ try {
+ final Bitmap img = BitmapFactory.decodeStream(is);
+ return Observable.from(img);
+ } catch (final Exception e) {
+ Log.e("RecaptchaHandler.getCaptcha", e);
+ return Observable.error(e);
+ } finally {
+ IOUtils.closeQuietly(is);
+ }
+ }
+ return Observable.empty();
+ }
+ }).subscribeOn(Schedulers.threadPoolForIO()));
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/gc/SearchHandler.java b/main/src/cgeo/geocaching/connector/gc/SearchHandler.java
deleted file mode 100644
index 795ed2f..0000000
--- a/main/src/cgeo/geocaching/connector/gc/SearchHandler.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package cgeo.geocaching.connector.gc;
-
-import cgeo.geocaching.R;
-import cgeo.geocaching.loaders.RecaptchaReceiver;
-import cgeo.geocaching.utils.Log;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.Handler;
-import android.os.Message;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.EditText;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-public class SearchHandler extends Handler {
- private Activity activity = null;
- private Resources res = null;
- private RecaptchaReceiver recaptchaThread = null;
- private ImageView imageView = null;
- private Bitmap img = null;
-
- private Handler imgHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- try {
- if (img != null && imageView != null) {
- imageView.setImageBitmap(img);
- }
- } catch (Exception e) {
- Log.e("Error setting reCAPTCHA image", e);
- }
- }
- };
-
- public SearchHandler(Activity activityIn, Resources resIn, RecaptchaReceiver recaptchaThreadIn) {
- activity = activityIn;
- res = resIn;
- recaptchaThread = recaptchaThreadIn;
- }
-
- @Override
- public void handleMessage(Message msg) {
- try {
- if (msg.what == 1) {
- final AlertDialog.Builder dlg = new AlertDialog.Builder(activity);
- final LayoutInflater inflater = activity.getLayoutInflater();
- final View view = inflater.inflate(R.layout.recaptcha_dialog, null);
-
- imageView = (ImageView) view.findViewById(R.id.image);
-
- ImageButton reloadButton = (ImageButton) view.findViewById(R.id.button_recaptcha_refresh);
- reloadButton.setOnClickListener(new View.OnClickListener() {
-
- @Override
- public void onClick(View v) {
- recaptchaThread.fetchChallenge();
- try {
- (new GetCaptchaThread(new URL("http://www.google.com/recaptcha/api/image?c=" + recaptchaThread.getChallenge()))).start();
- } catch (MalformedURLException e) {
- Log.e("Bad reCAPTCHA image url", e);
- }
- }
- });
-
- (new GetCaptchaThread(new URL("http://www.google.com/recaptcha/api/image?c=" + recaptchaThread.getChallenge()))).start();
-
- dlg.setTitle(res.getString(R.string.caches_recaptcha_title));
- dlg.setView(view);
- dlg.setNeutralButton(res.getString(R.string.caches_recaptcha_continue), new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- final String text = ((EditText) view.findViewById(R.id.text)).getText().toString();
-
- recaptchaThread.setText(text);
-
- dialog.cancel();
- }
- });
-
- dlg.create().show();
- }
- } catch (MalformedURLException e) {
- Log.e("Error in reCAPTCHA handler", e);
- }
- }
-
- private class GetCaptchaThread extends Thread {
- private URL uri = null;
-
- public GetCaptchaThread(URL uriIn) {
- uri = uriIn;
- }
-
- @Override
- public void run() {
- try {
- Log.d("Getting reCAPTCHA image from: " + uri.toString());
- HttpURLConnection connection = (HttpURLConnection) uri.openConnection();
- connection.setDoInput(true);
- connection.connect();
-
- InputStream is = connection.getInputStream();
-
- img = BitmapFactory.decodeStream(is);
-
- is.close();
-
- imgHandler.sendEmptyMessage(0);
- } catch (IOException e) {
- Log.e("Failed to download reCAPTCHA image", e);
- }
- }
- }
-}
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
index 2175935..c33a90e 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
@@ -75,7 +75,8 @@ final class OkapiClient {
private static final String CACHE_STATUS_ARCHIVED = "Archived";
private static final String CACHE_STATUS_DISABLED = "Temporarily unavailable";
private static final String CACHE_IS_FOUND = "is_found";
- private static final String CACHE_SIZE = "size";
+ private static final String CACHE_SIZE_DEPRECATED = "size";
+ private static final String CACHE_SIZE2 = "size2";
private static final String CACHE_VOTES = "rating_votes";
private static final String CACHE_NOTFOUNDS = "notfounds";
private static final String CACHE_FOUNDS = "founds";
@@ -112,7 +113,7 @@ final class OkapiClient {
// the several realms of possible fields for cache retrieval:
// Core: for livemap requests (L3 - only with level 3 auth)
// Additional: additional fields for full cache (L3 - only for level 3 auth, current - only for connectors with current api)
- private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|date_hidden";
+ private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|size2|date_hidden";
private static final String SERVICE_CACHE_CORE_L3_FIELDS = "is_found";
private static final String SERVICE_CACHE_ADDITIONAL_FIELDS = "owner|founds|notfounds|rating|rating_votes|recommendations|description|hint|images|latest_logs|alt_wpts|attrnames|req_passwd";
private static final String SERVICE_CACHE_ADDITIONAL_CURRENT_FIELDS = "gc_code|attribution_note|attr_acodes";
@@ -152,19 +153,14 @@ final class OkapiClient {
}
public static List<Geocache> getCachesByOwner(final String username, final OCApiConnector connector) {
- final Parameters params = new Parameters("search_method", METHOD_SEARCH_ALL);
- final Map<String, String> valueMap = new LinkedHashMap<String, String>();
- final @Nullable
- String uuid = getUserUUID(connector, username);
- if (StringUtils.isEmpty(uuid)) {
- return Collections.emptyList();
- }
- valueMap.put("owner_uuid", uuid);
-
- return requestCaches(connector, params, valueMap);
+ return getCachesByUser(username, connector, "owner_uuid");
}
public static List<Geocache> getCachesByFinder(final String username, final OCApiConnector connector) {
+ return getCachesByUser(username, connector, "found_by");
+ }
+
+ private static List<Geocache> getCachesByUser(final String username, final OCApiConnector connector, final String userRequestParam) {
final Parameters params = new Parameters("search_method", METHOD_SEARCH_ALL);
final Map<String, String> valueMap = new LinkedHashMap<String, String>();
final @Nullable
@@ -172,7 +168,7 @@ final class OkapiClient {
if (StringUtils.isEmpty(uuid)) {
return Collections.emptyList();
}
- valueMap.put("found_by", uuid);
+ valueMap.put(userRequestParam, uuid);
return requestCaches(connector, params, valueMap);
}
@@ -567,12 +563,25 @@ final class OkapiClient {
}
private static CacheSize getCacheSize(final JSONObject response) {
- if (response.isNull(CACHE_SIZE)) {
+ if (response.isNull(CACHE_SIZE2)) {
+ return getCacheSizeDeprecated(response);
+ }
+ try {
+ final String size = response.getString(CACHE_SIZE2);
+ return CacheSize.getById(size);
+ } catch (JSONException e) {
+ Log.e("OkapiClient.getCacheSize", e);
+ return getCacheSizeDeprecated(response);
+ }
+ }
+
+ private static CacheSize getCacheSizeDeprecated(final JSONObject response) {
+ if (response.isNull(CACHE_SIZE_DEPRECATED)) {
return CacheSize.NOT_CHOSEN;
}
double size = 0;
try {
- size = response.getDouble(CACHE_SIZE);
+ size = response.getDouble(CACHE_SIZE_DEPRECATED);
} catch (final JSONException e) {
Log.e("OkapiClient.getCacheSize", e);
}
@@ -586,7 +595,7 @@ final class OkapiClient {
case 4:
return CacheSize.LARGE;
case 5:
- return CacheSize.LARGE;
+ return CacheSize.VERY_LARGE;
default:
break;
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
index f72b698..5f11a11 100644
--- a/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
+++ b/main/src/cgeo/geocaching/connector/ox/OXGPXParser.java
@@ -28,10 +28,10 @@ public class OXGPXParser extends GPX10Parser {
/**
* The short description of OX caches contains "title by owner, type(T/D/Awesomeness)". That is a lot of
* duplication.
- *
+ *
* @param cache
*/
private static void removeTitleFromShortDescription(final @NonNull Geocache cache) {
- cache.setShortDescription(StringUtils.substringAfterLast(cache.getShortDescription(), ","));
+ cache.setShortDescription(StringUtils.trim(StringUtils.substringAfterLast(cache.getShortDescription(), ",")));
}
}
diff --git a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
index 2defc52..0137af4 100644
--- a/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
+++ b/main/src/cgeo/geocaching/connector/ox/OpenCachingApi.java
@@ -11,7 +11,6 @@ import cgeo.geocaching.utils.CryptUtils;
import cgeo.geocaching.utils.Log;
import ch.boye.httpclientandroidlib.HttpResponse;
-
import org.apache.commons.collections4.CollectionUtils;
import org.eclipse.jdt.annotation.NonNull;
diff --git a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
index 69efddc..fb554b9 100644
--- a/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/AbstractTrackableConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.connector.AbstractConnector;
import cgeo.geocaching.connector.UserAction;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
@@ -15,7 +16,8 @@ public abstract class AbstractTrackableConnector implements TrackableConnector {
}
@Override
- public String getTrackableCodeFromUrl(@NonNull String url) {
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
return null;
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
index 8387076..03052f9 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyConnector.java
@@ -4,6 +4,10 @@ import cgeo.geocaching.Trackable;
import cgeo.geocaching.network.Network;
import cgeo.geocaching.utils.Log;
+import org.apache.commons.lang3.StringUtils;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+
import java.util.regex.Pattern;
public class GeokretyConnector extends AbstractTrackableConnector {
@@ -29,7 +33,7 @@ public class GeokretyConnector extends AbstractTrackableConnector {
return GeokretyParser.parse(page);
}
- private static int getId(String geocode) {
+ protected static int getId(String geocode) {
try {
final String hex = geocode.substring(2);
return Integer.parseInt(hex, 16);
@@ -39,4 +43,25 @@ public class GeokretyConnector extends AbstractTrackableConnector {
return -1;
}
+ @Override
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
+ // http://geokrety.org/konkret.php?id=38545
+ String id = StringUtils.substringAfterLast(url, "konkret.php?id=");
+ if (StringUtils.isNumeric(id)) {
+ return geocode(Integer.parseInt(id));
+ }
+ return null;
+ }
+
+ /**
+ * Get geocode from geokrety id
+ *
+ * @param id
+ * @return
+ */
+ public static String geocode(final int id) {
+ return String.format("GK%04X", id);
+ }
+
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
index ee8c8c0..0e64abd 100644
--- a/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
+++ b/main/src/cgeo/geocaching/connector/trackable/GeokretyParser.java
@@ -37,8 +37,8 @@ public class GeokretyParser {
public void start(Attributes attributes) {
try {
final String kretyId = attributes.getValue("id");
- if (StringUtils.isNotBlank(kretyId)) {
- trackable.setGeocode(geocode(Integer.parseInt(kretyId)));
+ if (StringUtils.isNumeric(kretyId)) {
+ trackable.setGeocode(GeokretyConnector.geocode(Integer.parseInt(kretyId)));
}
final String distance = attributes.getValue("dist");
if (StringUtils.isNotBlank(distance)) {
@@ -88,8 +88,4 @@ public class GeokretyParser {
}
return null;
}
-
- protected static String geocode(final int id) {
- return String.format("GK%04X", id);
- }
}
diff --git a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
index 0990d96..6071b5f 100644
--- a/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/TrackableConnector.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.Trackable;
import cgeo.geocaching.connector.UserAction;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
@@ -21,7 +22,8 @@ public interface TrackableConnector {
public Trackable searchTrackable(String geocode, String guid, String id);
- public String getTrackableCodeFromUrl(final @NonNull String url);
+ public @Nullable
+ String getTrackableCodeFromUrl(final @NonNull String url);
public @NonNull
List<UserAction> getUserActions();
diff --git a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
index dad285c..77848d7 100644
--- a/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
+++ b/main/src/cgeo/geocaching/connector/trackable/TravelBugConnector.java
@@ -7,6 +7,7 @@ import cgeo.geocaching.connector.gc.GCParser;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import java.util.List;
import java.util.regex.Pattern;
@@ -20,7 +21,7 @@ public class TravelBugConnector extends AbstractTrackableConnector {
@Override
public boolean canHandleTrackable(String geocode) {
- return TravelBugConnector.PATTERN_TB_CODE.matcher(geocode).matches();
+ return TravelBugConnector.PATTERN_TB_CODE.matcher(geocode).matches() && !StringUtils.startsWithIgnoreCase(geocode, "GC");
}
@Override
@@ -54,8 +55,18 @@ public class TravelBugConnector extends AbstractTrackableConnector {
}
@Override
- public String getTrackableCodeFromUrl(@NonNull String url) {
- return StringUtils.substringAfterLast(url, "?tracker=");
+ public @Nullable
+ String getTrackableCodeFromUrl(@NonNull String url) {
+ // coord.info URLs
+ String code = StringUtils.substringAfterLast(url, "coord.info/");
+ if (code != null && canHandleTrackable(code)) {
+ return code;
+ }
+ code = StringUtils.substringAfterLast(url, "?tracker=");
+ if (code != null && canHandleTrackable(code)) {
+ return code;
+ }
+ return null;
}
@Override