diff options
Diffstat (limited to 'main')
| -rw-r--r-- | main/res/values-de/strings.xml | 3 | ||||
| -rw-r--r-- | main/res/values/ecicons.xml | 11 | ||||
| -rw-r--r-- | main/res/values/preference_keys.xml | 5 | ||||
| -rw-r--r-- | main/res/values/strings.xml | 6 | ||||
| -rw-r--r-- | main/res/xml/preferences.xml | 47 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/ConnectorFactory.java | 2 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/ec/ECApi.java | 172 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/ec/ECConnector.java | 183 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/ec/ECConstants.java | 19 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/ec/ECGPXParser.java | 10 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/connector/ec/ECLogin.java | 184 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/enumerations/StatusCode.java | 1 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/settings/CheckECCredentialsPreference.java | 123 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/settings/Settings.java | 25 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/settings/SettingsActivity.java | 7 | ||||
| -rw-r--r-- | main/src/cgeo/geocaching/ui/CacheDetailsCreator.java | 21 |
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()); + } } } |
