aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorrel00p <rel00p@gmx.net>2013-12-08 20:18:11 +0100
committerBananeweizen <bananeweizen@gmx.de>2013-12-16 08:07:40 +0100
commit02d30d2b7694fa15bfc19cb723c9b6e5c9cf7f89 (patch)
tree088bf0ea6701f1dc6540190a72f12e3b2e58ec9e /main
parent709a5120f1606e011ddc74fccdc1909cc6540592 (diff)
downloadcgeo-02d30d2b7694fa15bfc19cb723c9b6e5c9cf7f89.zip
cgeo-02d30d2b7694fa15bfc19cb723c9b6e5c9cf7f89.tar.gz
cgeo-02d30d2b7694fa15bfc19cb723c9b6e5c9cf7f89.tar.bz2
extremcaching connector initial version
Diffstat (limited to 'main')
-rw-r--r--main/res/values-de/strings.xml3
-rw-r--r--main/res/values/ecicons.xml11
-rw-r--r--main/res/values/preference_keys.xml5
-rw-r--r--main/res/values/strings.xml6
-rw-r--r--main/res/xml/preferences.xml47
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java2
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECApi.java172
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECConnector.java183
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECConstants.java19
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECGPXParser.java10
-rw-r--r--main/src/cgeo/geocaching/connector/ec/ECLogin.java184
-rw-r--r--main/src/cgeo/geocaching/enumerations/StatusCode.java1
-rw-r--r--main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java123
-rw-r--r--main/src/cgeo/geocaching/settings/Settings.java25
-rw-r--r--main/src/cgeo/geocaching/settings/SettingsActivity.java7
-rw-r--r--main/src/cgeo/geocaching/ui/CacheDetailsCreator.java21
16 files changed, 813 insertions, 6 deletions
diff --git a/main/res/values-de/strings.xml b/main/res/values-de/strings.xml
index f4a361f..dbd7184 100644
--- a/main/res/values-de/strings.xml
+++ b/main/res/values-de/strings.xml
@@ -124,6 +124,7 @@
<string name="err_start">Kommunikation nicht gestartet</string>
<string name="err_parse">Parsing der Anmeldung gescheitert</string>
<string name="err_server">Verbindung zu Geocaching.com konnte nicht hergestellt werden (Server oder Verbindung inaktiv?)</string>
+ <string name="err_server_ec">Verbindung zu Extremcaching.com konnte nicht hergestellt werden (Server oder Verbindung inaktiv?)</string>
<string name="err_login">Keine Anmeldedaten gespeichert.</string>
<string name="err_login_failed">Login fehlgeschlagen.</string>
<string name="err_login_failed_toast">c:geo konnte sich nicht einloggen und arbeitet im Offline-Modus. Bitte die Login-Daten in den Einstellungen überprüfen oder eine Internetverbindung herstellen.</string>
@@ -343,7 +344,9 @@
<string name="settings_category_logging_other">Andere Log-Optionen</string>
<string name="settings_goto_url_button">mehr …</string>
<string name="settings_title_gc">Geocaching.com</string>
+ <string name="settings_title_ec">Extremcaching.com</string>
<string name="settings_activate_gc">Aktivieren</string>
+ <string name="settings_activate_ec">Aktivieren</string>
<string name="settings_gc_legal_note">Mit Benutzung der Dienste von geocaching.com werden die Groundspeak-Nutzungsbedingungen (englisch) akzeptiert.</string>
<string name="settings_info_facebook_login_title">Facebook-Login</string>
<string name="settings_info_facebook_login">c:geo kann sich zwar nicht per Facebook bei Geocaching.com einloggen, aber es gibt eine einfache Abhilfe …</string>
diff --git a/main/res/values/ecicons.xml b/main/res/values/ecicons.xml
new file mode 100644
index 0000000..234db5f
--- /dev/null
+++ b/main/res/values/ecicons.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string-array name="ECIcons">
+ <item>@string/settings_ec_icons_other</item>
+ <item>@string/settings_ec_icons_oc</item>
+ </string-array>
+ <string-array name="ECIconsValues">
+ <item>1</item>
+ <item>2</item>
+ </string-array>
+</resources> \ No newline at end of file
diff --git a/main/res/values/preference_keys.xml b/main/res/values/preference_keys.xml
index 975cff9..41f289e 100644
--- a/main/res/values/preference_keys.xml
+++ b/main/res/values/preference_keys.xml
@@ -18,6 +18,9 @@
<string name="pref_password">password</string>
<string name="pref_connectorOCActive">connectorOCActive</string>
<string name="pref_connectorOCPLActive">connectorOCPLActive</string>
+ <string name="pref_ecusername">ecusername</string>
+ <string name="pref_ecpassword">ecpassword</string>
+ <string name="pref_connectorECActive">connectorECActive</string>
<string name="pref_pass_vote">pass-vote</string>
<string name="pref_twitter">twitter</string>
<string name="pref_webDeviceName">webDeviceName</string>
@@ -123,9 +126,11 @@
<string name="pref_fakekey_gc_website">fakekey_gc_website</string>
<string name="pref_fakekey_ocde_website">fakekey_ocde_website</string>
<string name="pref_fakekey_ocpl_website">fakekey_ocpl_website</string>
+ <string name="pref_fakekey_ec_website">fakekey_ec_website</string>
<string name="pref_fakekey_gcvote_website">fakekey_gcvote_website</string>
<string name="pref_fakekey_sendtocgeo_website">fakekey_sendtocgeo_website</string>
<string name="pref_twitter_cache_message">twitter_cache_message</string>
<string name="pref_twitter_trackable_message">twitter_trackable_message</string>
+ <string name="pref_ec_icons">ec_icons</string>
</resources> \ No newline at end of file
diff --git a/main/res/values/strings.xml b/main/res/values/strings.xml
index da7699a..75537e3 100644
--- a/main/res/values/strings.xml
+++ b/main/res/values/strings.xml
@@ -148,6 +148,7 @@
<string name="err_start">Communication not started</string>
<string name="err_parse">Failed Login page parsing</string>
<string name="err_server">Unable to contact Geocaching.com. The website may be down or your internet connection not working.</string>
+ <string name="err_server_ec">Unable to contact Extremcaching.com. The website may be down or your internet connection not working.</string>
<string name="err_login">No Login information stored</string>
<string name="err_login_failed">c:geo can\'t log in.</string>
<string name="err_login_failed_toast">c:geo can\'t log in. c:geo works offline with Stored caches. Check Login settings or enable your internet connection.</string>
@@ -391,7 +392,9 @@
<string name="settings_goto_url_button">more …</string>
<string name="settings_title_gc">Geocaching.com</string>
+ <string name="settings_title_ec">Extremcaching.com</string>
<string name="settings_activate_gc">Activate</string>
+ <string name="settings_activate_ec">Activate</string>
<string name="settings_gc_legal_note">With using the service of geocaching.com, you accept the Groundspeak Terms of Use.</string>
<string name="settings_info_facebook_login_title">Facebook Login</string>
<string name="settings_info_facebook_login">You can\'t make c:geo login to geocaching.com with your Facebook account. But there is a simple workaround …</string>
@@ -523,6 +526,9 @@
<string name="settings_information">Information</string>
<string name="settings_twitter_cache_message">Message for found cache</string>
<string name="settings_twitter_trackable_message">Message for found trackable</string>
+ <string name="init_ec_icons">Map Icons</string>
+ <string name="settings_ec_icons_other">Other</string>
+ <string name="settings_ec_icons_oc">OC</string>
<!-- map sources -->
<string name="map_source_google_map">Google: Map</string>
diff --git a/main/res/xml/preferences.xml b/main/res/xml/preferences.xml
index 74a6f6e..8c72ae0 100644
--- a/main/res/xml/preferences.xml
+++ b/main/res/xml/preferences.xml
@@ -114,6 +114,53 @@
android:title="@string/settings_open_website" />
</PreferenceCategory>
</PreferenceScreen>
+
+ <PreferenceScreen android:title="@string/settings_title_ec" >
+ <PreferenceCategory android:title="@string/settings_settings" >
+ <CheckBoxPreference
+ android:defaultValue="false"
+ android:key="@string/pref_connectorECActive"
+ android:title="@string/settings_activate_ec" />
+
+ <EditTextPreference
+ android:dependency="@string/pref_connectorECActive"
+ android:dialogTitle="@string/init_username"
+ android:hint="@string/init_username"
+ android:imeOptions="actionDone"
+ android:key="@string/pref_ecusername"
+ android:singleLine="true"
+ android:title="@string/init_username" />
+
+ <cgeo.geocaching.settings.EditPasswordPreference
+ android:dependency="@string/pref_connectorECActive"
+ android:dialogTitle="@string/init_password"
+ android:hint="@string/init_password"
+ android:imeOptions="actionDone"
+ android:inputType="textPassword"
+ android:key="@string/pref_ecpassword"
+ android:singleLine="true"
+ android:title="@string/init_password" />
+ <cgeo.geocaching.settings.CheckECCredentialsPreference
+ android:dependency="@string/pref_connectorECActive"
+ android:title="@string/init_login" />
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/settings_title_appearance" >
+ <ListPreference
+ android:dependency="@string/pref_connectorECActive"
+ android:defaultValue="1"
+ android:dialogTitle="@string/init_ec_icons"
+ android:key="@string/pref_ec_icons"
+ android:title="@string/init_ec_icons"
+ android:entries="@array/ECIcons"
+ android:entryValues="@array/ECIconsValues" />
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/settings_information" >
+ <Preference
+ android:key="@string/pref_fakekey_ec_website"
+ android:title="@string/settings_open_website" />
+ </PreferenceCategory>
+ </PreferenceScreen>
+
<PreferenceScreen android:title="@string/init_gcvote" >
<PreferenceCategory android:title="@string/settings_settings" >
<cgeo.geocaching.settings.EditPasswordPreference
diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
index 28974eb..5c5d9db 100644
--- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java
+++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java
@@ -8,6 +8,7 @@ import cgeo.geocaching.connector.capability.ILogin;
import cgeo.geocaching.connector.capability.ISearchByCenter;
import cgeo.geocaching.connector.capability.ISearchByKeyword;
import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.connector.ec.ECConnector;
import cgeo.geocaching.connector.gc.GCConnector;
import cgeo.geocaching.connector.oc.OCApiConnector;
import cgeo.geocaching.connector.oc.OCApiConnector.ApiSupport;
@@ -30,6 +31,7 @@ public final class ConnectorFactory {
private static final UnknownConnector UNKNOWN_CONNECTOR = new UnknownConnector();
private static final IConnector[] CONNECTORS = new IConnector[] {
GCConnector.getInstance(),
+ ECConnector.getInstance(),
new OCApiLiveConnector("opencaching.de", "www.opencaching.de", "OC", "CC BY-NC-ND, alle Logeinträge © jeweiliger Autor",
R.string.oc_de_okapi_consumer_key, R.string.oc_de_okapi_consumer_secret,
R.string.pref_connectorOCActive, R.string.pref_ocde_tokenpublic, R.string.pref_ocde_tokensecret, ApiSupport.current),
diff --git a/main/src/cgeo/geocaching/connector/ec/ECApi.java b/main/src/cgeo/geocaching/connector/ec/ECApi.java
new file mode 100644
index 0000000..8c1a428
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECApi.java
@@ -0,0 +1,172 @@
+package cgeo.geocaching.connector.ec;
+
+import cgeo.geocaching.DataStore;
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.enumerations.CacheType;
+import cgeo.geocaching.enumerations.LoadFlags.SaveFlag;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.list.StoredList;
+import cgeo.geocaching.network.Network;
+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.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+
+public class ECApi {
+
+ private static final String API_URL = "http://extremcaching.com/exports/api.php";
+
+ public static String cleanCode(String geocode) {
+ return geocode.replace("EC", "");
+ }
+
+ public static Geocache searchByGeoCode(final String geocode) {
+ final Parameters params = new Parameters("id", cleanCode(geocode));
+ params.add("cgeo", "1");
+ final HttpResponse response = apiRequest("http://extremcaching.com/exports/gpx.php", params);
+
+ final Collection<Geocache> caches = importCachesFromGPXResponse(response);
+ if (CollectionUtils.isNotEmpty(caches)) {
+ return caches.iterator().next();
+ }
+ return null;
+ }
+
+ public static Collection<Geocache> searchByBBox(final Viewport viewport) {
+
+ if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) {
+ return Collections.emptyList();
+ }
+
+ final Parameters params = new Parameters("fnc", "bbox");
+ params.add("lat1", String.valueOf(viewport.getLatitudeMin()));
+ params.add("lat2", String.valueOf(viewport.getLatitudeMax()));
+ params.add("lon1", String.valueOf(viewport.getLongitudeMin()));
+ params.add("lon2", String.valueOf(viewport.getLongitudeMax()));
+ final HttpResponse response = apiRequest(params);
+
+ return importCachesFromJSON(response);
+ }
+
+
+ public static Collection<Geocache> searchByCenter(final Geopoint center) {
+
+ final Parameters params = new Parameters("fnc", "center");
+ params.add("distance", "20");
+ params.add("lat", String.valueOf(center.getLatitude()));
+ params.add("lon", String.valueOf(center.getLongitude()));
+ final HttpResponse response = apiRequest(params);
+
+ return importCachesFromJSON(response);
+ }
+
+
+ private static HttpResponse apiRequest(final Parameters params) {
+ return apiRequest(API_URL, params, false);
+ }
+
+ private static HttpResponse apiRequest(final String uri, final Parameters params) {
+ return apiRequest(uri, params, false);
+ }
+
+ private static HttpResponse apiRequest(final String uri, final Parameters params, final boolean isRetry) {
+ final HttpResponse response = Network.getRequest(uri, params);
+
+ if (response == null) {
+ return null;
+ }
+ if (!isRetry && response.getStatusLine().getStatusCode() == 403) {
+ apiRequest(uri, params, true);
+ }
+ if (response.getStatusLine().getStatusCode() != 200) {
+ return null;
+ }
+ return response;
+ }
+
+ private static Collection<Geocache> importCachesFromGPXResponse(final HttpResponse response) {
+ if (response == null) {
+ return Collections.emptyList();
+ }
+ Collection<Geocache> caches;
+ try {
+ caches = new ECGPXParser(StoredList.TEMPORARY_LIST_ID).parse(response.getEntity().getContent(), null);
+ } catch (Exception e) {
+ Log.e("Error importing gpx from extremcaching.com", e);
+ return Collections.emptyList();
+ }
+ return caches;
+ }
+
+ private static List<Geocache> importCachesFromJSON(final HttpResponse response) {
+
+ if (response != null) {
+ try {
+ final String data = Network.getResponseDataAlways(response);
+ if (data == null || StringUtils.isBlank(data) || StringUtils.equals(data, "[]")) {
+ return Collections.emptyList();
+ }
+ final JSONArray json = new JSONArray(data);
+ final List<Geocache> caches = new ArrayList<Geocache>(json.length());
+ for (int i = 0; i < json.length(); i++) {
+ final Geocache cache = parseCache(json.getJSONObject(i));
+ caches.add(cache);
+ }
+ return caches;
+ } catch (final JSONException e) {
+ Log.w("JSONResult", e);
+ }
+ }
+
+ return Collections.emptyList();
+
+ }
+
+ private static Geocache parseCache(final JSONObject response) {
+ final Geocache cache = new Geocache();
+ cache.setReliableLatLon(true);
+ try {
+ cache.setGeocode("EC" + response.getString("cache_id"));
+ cache.setName(response.getString("title"));
+ cache.setCoords(new Geopoint(response.getString("lat"), response.getString("lon")));
+ cache.setType(getCacheType(response.getString("type")));
+ cache.setDifficulty((float) response.getDouble("difficulty"));
+ cache.setTerrain((float) response.getDouble("terrain"));
+ cache.setFound(response.getInt("found") == 1 ? true : false);
+
+ DataStore.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE));
+ } catch (final JSONException e) {
+ Log.e("ECApi.parseCache", e);
+ }
+ return cache;
+ }
+
+ private static CacheType getCacheType(final String cacheType) {
+ if (cacheType.equalsIgnoreCase("Tradi")) {
+ return CacheType.TRADITIONAL;
+ }
+ if (cacheType.equalsIgnoreCase("Multi")) {
+ return CacheType.MULTI;
+ }
+ if (cacheType.equalsIgnoreCase("Event")) {
+ return CacheType.EVENT;
+ }
+ if (cacheType.equalsIgnoreCase("Mystery")) {
+ return CacheType.MYSTERY;
+ }
+ return CacheType.UNKNOWN;
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECConnector.java b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
new file mode 100644
index 0000000..3b6376a
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECConnector.java
@@ -0,0 +1,183 @@
+package cgeo.geocaching.connector.ec;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.Geocache;
+import cgeo.geocaching.ICache;
+import cgeo.geocaching.R;
+import cgeo.geocaching.SearchResult;
+import cgeo.geocaching.connector.AbstractConnector;
+import cgeo.geocaching.connector.capability.ILogin;
+import cgeo.geocaching.connector.capability.ISearchByCenter;
+import cgeo.geocaching.connector.capability.ISearchByGeocode;
+import cgeo.geocaching.connector.capability.ISearchByViewPort;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.geopoint.Geopoint;
+import cgeo.geocaching.geopoint.Viewport;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.settings.SettingsActivity;
+import cgeo.geocaching.utils.CancellableHandler;
+
+import org.apache.commons.lang3.StringUtils;
+
+import android.content.Context;
+import android.os.Handler;
+
+import java.util.Collection;
+import java.util.regex.Pattern;
+
+public class ECConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort, ILogin {
+
+ private static final String CACHE_URL = "http://extremcaching.com/index.php/output-2/";
+
+ /**
+ * Pattern for EC codes
+ */
+ private final static Pattern PATTERN_EC_CODE = Pattern.compile("EC[0-9]+", Pattern.CASE_INSENSITIVE);
+
+
+ private ECConnector() {
+ // singleton
+ }
+
+ /**
+ * initialization on demand holder pattern
+ */
+ private static class Holder {
+ private static final ECConnector INSTANCE = new ECConnector();
+ }
+
+ public static ECConnector getInstance() {
+ return Holder.INSTANCE;
+ }
+
+ @Override
+ public boolean canHandle(String geocode) {
+ if (geocode == null) {
+ return false;
+ }
+ return ECConnector.PATTERN_EC_CODE.matcher(geocode).matches();
+ }
+
+ @Override
+ public String getCacheUrl(Geocache cache) {
+ return CACHE_URL + cache.getGeocode().replace("EC", "");
+ }
+
+ @Override
+ public String getName() {
+ return "extremcaching.com";
+ }
+
+ @Override
+ public String getHost() {
+ return "extremcaching.com";
+ }
+
+ @Override
+ public SearchResult searchByGeocode(final String geocode, final String guid, final CancellableHandler handler) {
+
+ CancellableHandler.sendLoadProgressDetail(handler, R.string.cache_dialog_loading_details_status_loadpage);
+
+ final Geocache cache = ECApi.searchByGeoCode(geocode);
+ if (cache == null) {
+ return null;
+ }
+ final SearchResult searchResult = new SearchResult(cache);
+
+ return searchResult;
+ }
+
+ @Override
+ public SearchResult searchByViewport(Viewport viewport, String[] tokens) {
+ final Collection<Geocache> caches = ECApi.searchByBBox(viewport);
+ if (caches == null) {
+ return null;
+ }
+ final SearchResult searchResult = new SearchResult(caches);
+ return searchResult.filterSearchResults(false, false, Settings.getCacheType());
+ }
+
+ @Override
+ public SearchResult searchByCenter(Geopoint center) {
+ final Collection<Geocache> caches = ECApi.searchByCenter(center);
+ if (caches == null) {
+ return null;
+ }
+ final SearchResult searchResult = new SearchResult(caches);
+ return searchResult.filterSearchResults(false, false, Settings.getCacheType());
+ }
+
+ @Override
+ public boolean isOwner(final ICache cache) {
+ //return StringUtils.equalsIgnoreCase(cache.getOwnerUserId(), Settings.getUsername());
+ return false;
+ }
+
+ @Override
+ protected String getCacheUrlPrefix() {
+ return CACHE_URL;
+ }
+
+ @Override
+ public boolean isActivated() {
+ return Settings.isECConnectorActive();
+ }
+
+ @Override
+ public boolean login(Handler handler, Context fromActivity) {
+ // login
+ final StatusCode status = ECLogin.login();
+
+ if (status == StatusCode.NO_ERROR) {
+ CgeoApplication.getInstance().checkLogin = false;
+ }
+
+ if (CgeoApplication.getInstance().showLoginToast && handler != null) {
+ handler.sendMessage(handler.obtainMessage(0, status));
+ CgeoApplication.getInstance().showLoginToast = false;
+
+ // invoke settings activity to insert login details
+ if (status == StatusCode.NO_LOGIN_INFO_STORED && fromActivity != null) {
+ SettingsActivity.jumpToServicesPage(fromActivity);
+ }
+ }
+ return status == StatusCode.NO_ERROR;
+ }
+
+ @Override
+ public String getUserName() {
+ return ECLogin.getActualUserName();
+ }
+
+ @Override
+ public int getCachesFound() {
+ return ECLogin.getActualCachesFound();
+ }
+
+ @Override
+ public String getLoginStatusString() {
+ return ECLogin.getActualStatus();
+ }
+
+ @Override
+ public boolean isLoggedIn() {
+ return ECLogin.isActualLoginStatus();
+ }
+
+ @Override
+ public int getCacheMapMarkerId(boolean disabled) {
+ final String icons = Settings.getECIconSet();
+ if (StringUtils.equals(icons, "1")) {
+ if (disabled) {
+ return R.drawable.marker_disabled_other;
+ }
+ return R.drawable.marker_other;
+ }
+
+ if (disabled) {
+ return R.drawable.marker_disabled_oc;
+ }
+ return R.drawable.marker_oc;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECConstants.java b/main/src/cgeo/geocaching/connector/ec/ECConstants.java
new file mode 100644
index 0000000..9b7353b
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECConstants.java
@@ -0,0 +1,19 @@
+package cgeo.geocaching.connector.ec;
+
+import java.util.regex.Pattern;
+
+/**
+ * For further information about patterns have a look at
+ * http://download.oracle.com/javase/1.4.2/docs/api/java/util/regex/Pattern.html
+ */
+public final class ECConstants {
+
+ public static final Pattern PATTERN_LOGIN_NAME = Pattern.compile("\"mod_login_greetingfrontpage-teaser\">Hallo, ([^<]+)</span>");
+ public static final Pattern PATTERN_LOGIN_SECURITY = Pattern.compile("<input type=\"hidden\" name=\"return\" value=\"(.*)\" />[^<]*<input type=\"hidden\" name=\"(.*)\" value=\"1\" />");
+ public static final Pattern PATTERN_CACHES_FOUND = Pattern.compile("Gefundene Caches::</label><div class=\"cb_field\"><div id=\"cbfv_71\">([0-9]+)</div>");
+
+ private ECConstants() {
+ // this class shall not have instances
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECGPXParser.java b/main/src/cgeo/geocaching/connector/ec/ECGPXParser.java
new file mode 100644
index 0000000..f2ffb5e
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECGPXParser.java
@@ -0,0 +1,10 @@
+package cgeo.geocaching.connector.ec;
+
+import cgeo.geocaching.files.GPX10Parser;
+
+public class ECGPXParser extends GPX10Parser {
+
+ public ECGPXParser(int listIdIn) {
+ super(listIdIn);
+ }
+}
diff --git a/main/src/cgeo/geocaching/connector/ec/ECLogin.java b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
new file mode 100644
index 0000000..8eaa8ee
--- /dev/null
+++ b/main/src/cgeo/geocaching/connector/ec/ECLogin.java
@@ -0,0 +1,184 @@
+package cgeo.geocaching.connector.ec;
+
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.R;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.network.Cookies;
+import cgeo.geocaching.network.Network;
+import cgeo.geocaching.network.Parameters;
+import cgeo.geocaching.settings.Settings;
+import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.TextUtils;
+
+import ch.boye.httpclientandroidlib.HttpResponse;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.Nullable;
+
+import java.util.regex.Matcher;
+
+public abstract class ECLogin {
+
+ // false = not logged in
+ private static boolean actualLoginStatus = false;
+ private static String actualUserName = StringUtils.EMPTY;
+ private static int actualCachesFound = -1;
+ private static String actualStatus = StringUtils.EMPTY;
+
+
+ public static StatusCode login() {
+ return login(true);
+ }
+
+ private static StatusCode login(boolean retry) {
+ final ImmutablePair<String, String> login = Settings.getECLogin();
+
+ if (StringUtils.isEmpty(login.left) || StringUtils.isEmpty(login.right)) {
+ clearLoginInfo();
+ Log.e("ECLogin.login: No login information stored");
+ return StatusCode.NO_LOGIN_INFO_STORED;
+ }
+
+ ECLogin.setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_working));
+ //HttpResponse loginResponse = Network.getRequest("http://extremcaching.com/component/users/?view=login");
+ HttpResponse loginResponse = Network.getRequest("https://extremcaching.com/community/profil1");
+ String loginData = Network.getResponseData(loginResponse);
+
+ if (StringUtils.isBlank(loginData)) {
+ Log.e("ECLogin.login: Failed to retrieve login page (1st)");
+ return StatusCode.CONNECTION_FAILED_EC; // no login page
+ }
+
+ if (ECLogin.getLoginStatus(loginData)) {
+ Log.i("Already logged in Extremcaching.com as " + login.left);
+ return StatusCode.NO_ERROR; // logged in
+ }
+
+ //Cookies.clearCookies();
+ //Settings.setCookieStore(null);
+
+ final Parameters params = new Parameters(
+ "username", login.left,
+ "password", login.right,
+ "remember", "yes");
+
+ Matcher m = ECConstants.PATTERN_LOGIN_SECURITY.matcher(loginData);
+ if (m.find() && m.groupCount() == 2) {
+ params.add("return", m.group(1));
+ params.add(m.group(2), "1");
+ } else {
+ Log.e("ECLogin.login security tokens in login form not found");
+ return StatusCode.COMMUNICATION_ERROR;
+ }
+
+ loginResponse = Network.postRequest("http://extremcaching.com/component/users/?task=user.login", params);
+ loginData = Network.getResponseData(loginResponse);
+
+ if (StringUtils.isBlank(loginData)) {
+ Log.e("ECLogin.login: Failed to retrieve login page (2nd)");
+ return StatusCode.COMMUNICATION_ERROR; // no login page
+ }
+ assert loginData != null; // Caught above
+
+ if (ECLogin.getLoginStatus(loginData)) {
+ Log.i("Successfully logged in Extremcaching.com as " + login.left);
+
+ Settings.setCookieStore(Cookies.dumpCookieStore());
+
+ return StatusCode.NO_ERROR; // logged in
+ }
+
+ if (loginData.contains("Benutzername und Passwort falsch")) {
+ Log.i("Failed to log in Extremcaching.com as " + login.left + " because of wrong username/password");
+ return StatusCode.WRONG_LOGIN_DATA; // wrong login
+ }
+
+ Log.i("Failed to log in Extremcaching.com as " + login.left + " for some unknown reason");
+ if (retry) {
+ return login(false);
+ }
+
+ return StatusCode.UNKNOWN_ERROR; // can't login
+ }
+
+ private static void resetLoginStatus() {
+ Cookies.clearCookies();
+ Settings.setCookieStore(null);
+
+ setActualLoginStatus(false);
+ }
+
+ private static void clearLoginInfo() {
+ resetLoginStatus();
+
+ setActualCachesFound(-1);
+ setActualStatus(CgeoApplication.getInstance().getString(R.string.err_login));
+ }
+
+ static void setActualCachesFound(final int found) {
+ actualCachesFound = found;
+ }
+
+ public static String getActualStatus() {
+ return actualStatus;
+ }
+
+ private static void setActualStatus(final String status) {
+ actualStatus = status;
+ }
+
+ public static boolean isActualLoginStatus() {
+ return actualLoginStatus;
+ }
+
+ private static void setActualLoginStatus(boolean loginStatus) {
+ actualLoginStatus = loginStatus;
+ }
+
+ public static String getActualUserName() {
+ return actualUserName;
+ }
+
+ private static void setActualUserName(String userName) {
+ actualUserName = userName;
+ }
+
+ public static int getActualCachesFound() {
+ return actualCachesFound;
+ }
+
+ /**
+ * Check if the user has been logged in when he retrieved the data.
+ *
+ * @param page
+ * @return <code>true</code> if user is logged in, <code>false</code> otherwise
+ */
+ public static boolean getLoginStatus(@Nullable final String page) {
+ if (StringUtils.isBlank(page)) {
+ Log.e("ECLogin.getLoginStatus: No page given");
+ return false;
+ }
+ assert page != null;
+
+ setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_ok));
+
+ // on every page except login page
+ setActualLoginStatus(TextUtils.matches(page, ECConstants.PATTERN_LOGIN_NAME));
+ if (isActualLoginStatus()) {
+ setActualUserName(TextUtils.getMatch(page, ECConstants.PATTERN_LOGIN_NAME, true, "???"));
+ int cachesCount = 0;
+ try {
+ cachesCount = Integer.parseInt(TextUtils.getMatch(page, ECConstants.PATTERN_CACHES_FOUND, true, "0"));
+ } catch (final NumberFormatException e) {
+ Log.e("ECLogin.getLoginStatus: bad cache count", e);
+ }
+ setActualCachesFound(cachesCount);
+ return true;
+ }
+
+ setActualStatus(CgeoApplication.getInstance().getString(R.string.init_login_popup_failed));
+ return false;
+ }
+
+}
diff --git a/main/src/cgeo/geocaching/enumerations/StatusCode.java b/main/src/cgeo/geocaching/enumerations/StatusCode.java
index 102b9e9..8c1db47 100644
--- a/main/src/cgeo/geocaching/enumerations/StatusCode.java
+++ b/main/src/cgeo/geocaching/enumerations/StatusCode.java
@@ -11,6 +11,7 @@ public enum StatusCode {
LOG_SAVED(R.string.info_log_saved),
LOGIN_PARSE_ERROR(R.string.err_parse),
CONNECTION_FAILED(R.string.err_server),
+ CONNECTION_FAILED_EC(R.string.err_server_ec),
NO_LOGIN_INFO_STORED(R.string.err_login),
UNKNOWN_ERROR(R.string.err_unknown),
COMMUNICATION_ERROR(R.string.err_comm),
diff --git a/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java b/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java
new file mode 100644
index 0000000..fabd5a5
--- /dev/null
+++ b/main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java
@@ -0,0 +1,123 @@
+package cgeo.geocaching.settings;
+
+import cgeo.geocaching.R;
+import cgeo.geocaching.activity.ActivityMixin;
+import cgeo.geocaching.connector.ec.ECLogin;
+import cgeo.geocaching.enumerations.StatusCode;
+import cgeo.geocaching.network.Cookies;
+import cgeo.geocaching.utils.Log;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+
+import android.annotation.SuppressLint;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.os.Message;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class CheckECCredentialsPreference extends Preference {
+
+ public CheckECCredentialsPreference(Context context) {
+ super(context);
+ }
+
+ public CheckECCredentialsPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public CheckECCredentialsPreference(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected View onCreateView(ViewGroup parent) {
+ setOnPreferenceClickListener(EC_LOGIN_CHECK);
+ return super.onCreateView(parent);
+ }
+
+ private final ECLoginCheck EC_LOGIN_CHECK = new ECLoginCheck();
+
+ private class ECLoginCheck implements OnPreferenceClickListener {
+ private Resources res;
+ private SettingsActivity activity;
+
+ private ProgressDialog loginDialog;
+ @SuppressLint("HandlerLeak")
+ private Handler logInHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ try {
+ if (loginDialog != null && loginDialog.isShowing()) {
+ loginDialog.dismiss();
+ }
+
+ if (msg.obj == null || (msg.obj instanceof Drawable)) {
+ ActivityMixin.helpDialog(activity,
+ res.getString(R.string.init_login_popup),
+ res.getString(R.string.init_login_popup_ok),
+ (Drawable) msg.obj);
+ } else {
+ ActivityMixin.helpDialog(activity,
+ res.getString(R.string.init_login_popup),
+ res.getString(R.string.init_login_popup_failed_reason)
+ + " "
+ + ((StatusCode) msg.obj).getErrorString(res)
+ + ".");
+ }
+ } catch (Exception e) {
+ ActivityMixin.showToast(activity, R.string.err_login_failed);
+ Log.e("SettingsActivity.logInHandler", e);
+ } finally {
+ if (loginDialog != null && loginDialog.isShowing()) {
+ loginDialog.dismiss();
+ }
+ // enable/disable basic member preferences
+ //activity.initBasicMemberPreferences();
+ }
+ }
+ };
+
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
+ this.activity = (SettingsActivity) CheckECCredentialsPreference.this.getContext();
+ this.res = activity.getResources();
+
+ ImmutablePair<String, String> credentials = Settings.getECLogin();
+
+ // check credentials for validity
+ if (StringUtils.isBlank(credentials.getLeft())
+ || StringUtils.isBlank(credentials.getRight())) {
+ ActivityMixin.showToast(activity, R.string.err_missing_auth);
+ return false;
+ }
+
+ loginDialog = ProgressDialog.show(activity,
+ res.getString(R.string.init_login_popup),
+ res.getString(R.string.init_login_popup_working), true);
+ loginDialog.setCancelable(false);
+ Cookies.clearCookies();
+
+ (new Thread() {
+ @Override
+ public void run() {
+ final StatusCode loginResult = ECLogin.login();
+ Object payload = loginResult;
+ if (loginResult == StatusCode.NO_ERROR) {
+ //Login.detectGcCustomDate();
+ payload = null;// Login.downloadAvatarAndGetMemberStatus();
+ }
+ logInHandler.obtainMessage(0, payload).sendToTarget();
+ }
+ }).start();
+
+ return false; // no shared preference has to be changed
+ }
+ }
+}
diff --git a/main/src/cgeo/geocaching/settings/Settings.java b/main/src/cgeo/geocaching/settings/Settings.java
index 146182a..b179e55 100644
--- a/main/src/cgeo/geocaching/settings/Settings.java
+++ b/main/src/cgeo/geocaching/settings/Settings.java
@@ -286,6 +286,23 @@ public class Settings {
return new ImmutablePair<String, String>(username, password);
}
+ /**
+ * Get login and password information.
+ *
+ * @return a pair either with (login, password) or (empty, empty) if no valid information is stored
+ */
+ public static ImmutablePair<String, String> getECLogin() {
+
+ final String username = getString(R.string.pref_ecusername, null);
+ final String password = getString(R.string.pref_ecpassword, null);
+
+ if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
+ return new ImmutablePair<String, String>(StringUtils.EMPTY, StringUtils.EMPTY);
+ }
+
+ return new ImmutablePair<String, String>(username, password);
+ }
+
public static String getUsername() {
return getString(R.string.pref_username, null);
}
@@ -294,6 +311,10 @@ public class Settings {
return getBoolean(R.string.pref_connectorGCActive, true);
}
+ public static boolean isECConnectorActive() {
+ return getBoolean(R.string.pref_connectorECActive, true);
+ }
+
public static boolean isPremiumMember() {
// Basic Member, Premium Member, ???
return GCConstants.MEMBER_STATUS_PM.equalsIgnoreCase(Settings.getMemberStatus());
@@ -982,4 +1003,8 @@ public class Settings {
return getBoolean(R.string.pref_fieldNoteExportOnlyNew, false);
}
+ public static String getECIconSet() {
+ return getString(R.string.pref_ec_icons, "1");
+ }
+
}
diff --git a/main/src/cgeo/geocaching/settings/SettingsActivity.java b/main/src/cgeo/geocaching/settings/SettingsActivity.java
index 403b11d..c25e796 100644
--- a/main/src/cgeo/geocaching/settings/SettingsActivity.java
+++ b/main/src/cgeo/geocaching/settings/SettingsActivity.java
@@ -128,7 +128,8 @@ public class SettingsActivity extends PreferenceActivity {
R.string.pref_gpxExportDir, R.string.pref_gpxImportDir,
R.string.pref_mapDirectory, R.string.pref_defaultNavigationTool,
R.string.pref_defaultNavigationTool2, R.string.pref_webDeviceName,
- R.string.pref_fakekey_preference_backup_info, R.string.pref_twitter_cache_message, R.string.pref_twitter_trackable_message }) {
+ R.string.pref_fakekey_preference_backup_info, R.string.pref_twitter_cache_message, R.string.pref_twitter_trackable_message,
+ R.string.pref_ecusername, R.string.pref_ecpassword, R.string.pref_ec_icons }) {
bindSummaryToStringValue(k);
}
getPreference(R.string.pref_units).setDefaultValue(Settings.getImperialUnitsDefault());
@@ -149,9 +150,11 @@ public class SettingsActivity extends PreferenceActivity {
getPreference(R.string.pref_connectorOCActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER);
getPreference(R.string.pref_connectorOCPLActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER);
getPreference(R.string.pref_connectorGCActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER);
+ getPreference(R.string.pref_connectorECActive).setOnPreferenceChangeListener(VALUE_CHANGE_LISTENER);
setWebsite(R.string.pref_fakekey_gc_website, GCConnector.getInstance().getHost());
setWebsite(R.string.pref_fakekey_ocde_website, "opencaching.de");
setWebsite(R.string.pref_fakekey_ocpl_website, "opencaching.pl");
+ setWebsite(R.string.pref_fakekey_ec_website, "extremcaching.com");
setWebsite(R.string.pref_fakekey_gcvote_website, "gcvote.com");
setWebsite(R.string.pref_fakekey_sendtocgeo_website, "send2.cgeo.org");
}
@@ -495,7 +498,7 @@ public class SettingsActivity extends PreferenceActivity {
}
Settings.setMapSource(mapSource);
preference.setSummary(mapSource.getName());
- } else if (isPreference(preference, R.string.pref_connectorOCActive) || isPreference(preference, R.string.pref_connectorOCPLActive) || isPreference(preference, R.string.pref_connectorGCActive)) {
+ } else if (isPreference(preference, R.string.pref_connectorOCActive) || isPreference(preference, R.string.pref_connectorOCPLActive) || isPreference(preference, R.string.pref_connectorGCActive) || isPreference(preference, R.string.pref_connectorECActive)) {
// // reset log-in status if connector activation was changed
CgeoApplication.getInstance().checkLogin = true;
} else if (preference instanceof ListPreference) {
diff --git a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
index f1cee05..dad87f0 100644
--- a/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
+++ b/main/src/cgeo/geocaching/ui/CacheDetailsCreator.java
@@ -4,6 +4,7 @@ import cgeo.geocaching.CgeoApplication;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
+import cgeo.geocaching.connector.ec.ECConnector;
import cgeo.geocaching.geopoint.Geopoint;
import cgeo.geocaching.geopoint.Units;
@@ -53,14 +54,18 @@ public final class CacheDetailsCreator {
}
public RelativeLayout addStars(final int nameId, final float value) {
+ return addStars(nameId, value, 5);
+ }
+
+ public RelativeLayout addStars(final int nameId, final float value, final int max) {
final RelativeLayout layout = (RelativeLayout) activity.getLayoutInflater().inflate(R.layout.cache_information_item, null);
final TextView nameView = (TextView) layout.findViewById(R.id.name);
lastValueView = (TextView) layout.findViewById(R.id.value);
final LinearLayout layoutStars = (LinearLayout) layout.findViewById(R.id.stars);
nameView.setText(activity.getResources().getString(nameId));
- lastValueView.setText(String.format("%.1f", value) + ' ' + activity.getResources().getString(R.string.cache_rating_of) + " 5");
- createStarImages(layoutStars, value);
+ lastValueView.setText(String.format("%.1f", value) + ' ' + activity.getResources().getString(R.string.cache_rating_of) + " " + String.format("%d", max));
+ createStarImages(layoutStars, value, max);
layoutStars.setVisibility(View.VISIBLE);
parentView.addView(layout);
@@ -68,9 +73,13 @@ public final class CacheDetailsCreator {
}
private void createStarImages(final ViewGroup starsContainer, final float value) {
+ createStarImages(starsContainer, value, 5);
+ }
+
+ private void createStarImages(final ViewGroup starsContainer, final float value, final int max) {
final LayoutInflater inflater = LayoutInflater.from(activity);
- for (int i = 0; i < 5; i++) {
+ for (int i = 0; i < max; i++) {
ImageView star = (ImageView) inflater.inflate(R.layout.star_image, null);
if (value - i >= 0.75) {
star.setImageResource(R.drawable.star_on);
@@ -130,7 +139,11 @@ public final class CacheDetailsCreator {
public void addTerrain(Geocache cache) {
if (cache.getTerrain() > 0) {
- addStars(R.string.cache_terrain, cache.getTerrain());
+ if (ECConnector.getInstance().canHandle(cache.getGeocode())) {
+ addStars(R.string.cache_terrain, cache.getTerrain(), 7);
+ } else {
+ addStars(R.string.cache_terrain, cache.getTerrain());
+ }
}
}