From 3593ead589b5c8857c60246b7bec574459b5b661 Mon Sep 17 00:00:00 2001 From: Eric Kok Date: Thu, 27 Jun 2013 15:34:02 +0200 Subject: [PATCH] Finalized adding of torrents via http, file or magnet; also multiple http links at once via ADD_MULTIPLE. --- .../preferences/PreferencesXirvikServer.java | 2 +- .../transdroid/preferences/ImportExport.java | 2 +- .../GoogleWebSearchBarcodeResolver.java | 2 +- .../org/transdroid/service/UpdateService.java | 2 +- core/res/layout-w900dp/activity_rssfeeds.xml | 4 +- core/res/layout/activity_rssitems.xml | 2 +- core/res/layout/fragment_rssitems.xml | 5 +- core/res/layout/list_item_rssitem.xml | 6 +- core/res/menu/fragment_rssfeeds.xml | 6 + core/res/values/strings.xml | 5 + core/res/xml/pref_websearch.xml | 6 + .../GoogleWebSearchBarcodeResolver.java | 2 +- .../app/settings/ApplicationSettings.java | 50 ++-- .../app/settings/SettingsPersistence.java | 2 +- .../core/app/settings/WebsearchSetting.java | 8 +- .../transdroid/core/gui/TorrentsActivity.java | 140 +++++++-- .../core/gui/rss/RssfeedLoader.java | 2 +- .../transdroid/core/gui/rss/RssfeedView.java | 3 +- .../core/gui/rss/RssfeedsActivity.java | 77 +++-- .../core/gui/rss/RssfeedsFragment.java | 7 +- .../transdroid/core/gui/rss/RssitemView.java | 5 +- .../core/gui/rss/RssitemsActivity.java | 4 +- .../core/gui/rss/RssitemsFragment.java | 49 +++- .../settings/WebsearchSettingsActivity.java | 1 + .../transdroid/core/rssparser/Channel.java | 1 + .../transdroid/core/rssparser/HttpHelper.java | 6 +- .../org/transdroid/core/rssparser/Item.java | 3 +- full/AndroidManifest.xml | 112 ++++++- .../daemon/BitComet/BitCometAdapter.java | 10 +- .../daemon/Bitflu/BitfluAdapter.java | 2 +- .../daemon/BuffaloNas/BuffaloNasAdapter.java | 2 +- .../DLinkRouterBT/DLinkRouterBTAdapter.java | 2 +- .../daemon/Deluge/DelugeAdapter.java | 6 +- .../daemon/Ktorrent/KtorrentAdapter.java | 6 +- .../Qbittorrent/QbittorrentAdapter.java | 2 +- .../daemon/Synology/SynologyAdapter.java | 2 +- .../daemon/Tfb4rt/Tfb4rtAdapter.java | 4 +- .../Transmission/TransmissionAdapter.java | 12 +- .../daemon/Utorrent/UtorrentAdapter.java | 6 +- .../transdroid/daemon/util/HttpHelper.java | 273 ++++++++++-------- lite/AndroidManifest.xml | 103 ++++++- 41 files changed, 678 insertions(+), 266 deletions(-) diff --git a/android/src/com/xirvik/transdroid/preferences/PreferencesXirvikServer.java b/android/src/com/xirvik/transdroid/preferences/PreferencesXirvikServer.java index 0abd68a2..84e8f001 100644 --- a/android/src/com/xirvik/transdroid/preferences/PreferencesXirvikServer.java +++ b/android/src/com/xirvik/transdroid/preferences/PreferencesXirvikServer.java @@ -230,7 +230,7 @@ public class PreferencesXirvikServer extends PreferenceActivity { String url = "https://" + serverValue + ":443/browsers_addons/transdroid_autoconf.txt"; HttpResponse request = httpclient.execute(new HttpGet(url)); InputStream stream = request.getEntity().getContent(); - String folderVal = HttpHelper.ConvertStreamToString(stream).trim(); + String folderVal = HttpHelper.convertStreamToString(stream).trim(); if (folderVal.startsWith(" @@ -19,7 +19,7 @@ android:id="@+id/rssitems_list" android:layout_width="0dip" android:layout_height="match_parent" - android:layout_weight="1" + android:layout_weight="3" class="org.transdroid.core.gui.rss.RssitemsFragment_" tools:layout="@layout/fragment_rssitems" /> diff --git a/core/res/layout/activity_rssitems.xml b/core/res/layout/activity_rssitems.xml index 465a7a34..e86818dd 100644 --- a/core/res/layout/activity_rssitems.xml +++ b/core/res/layout/activity_rssitems.xml @@ -6,7 +6,7 @@ tools:context=".RssItemsActivity" > + android:text="@string/rss_noselection" + android:textIsSelectable="false" /> \ No newline at end of file diff --git a/core/res/layout/list_item_rssitem.xml b/core/res/layout/list_item_rssitem.xml index eca6a3e4..c1297c62 100644 --- a/core/res/layout/list_item_rssitem.xml +++ b/core/res/layout/list_item_rssitem.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/core/res/menu/fragment_rssfeeds.xml b/core/res/menu/fragment_rssfeeds.xml index 94b4cfbf..8975f24b 100644 --- a/core/res/menu/fragment_rssfeeds.xml +++ b/core/res/menu/fragment_rssfeeds.xml @@ -1,5 +1,11 @@ + + diff --git a/core/res/values/strings.xml b/core/res/values/strings.xml index cc6bfbea..7703fa51 100644 --- a/core/res/values/strings.xml +++ b/core/res/values/strings.xml @@ -121,7 +121,10 @@ RSS feeds You have not defined any RSS feeds yet to monitor. Torrent-specific RSS feeds keep you up to date with new releases and you are notified of new items. + Select an RSS feed to view the new items The RSS feed is not available or it contains no items + Sorry, please wait until the RSS feed is loaded + Sorry, this RSS feed could not be loaded at this time %1$d item selected %1$d items selected @@ -140,6 +143,8 @@ Optional personal name Direct search URL %s will be replaced by the search query + Cookies + Optional; use the key1=value1;key2=value2 format Feed URL Requires authentication Opens links in the webbrowser for user login diff --git a/core/res/xml/pref_websearch.xml b/core/res/xml/pref_websearch.xml index f2efdec1..0c760030 100644 --- a/core/res/xml/pref_websearch.xml +++ b/core/res/xml/pref_websearch.xml @@ -13,4 +13,10 @@ android:summary="@string/pref_searchurl_info" android:inputType="textUri" /> + + \ No newline at end of file diff --git a/core/src/org/transdroid/core/app/search/GoogleWebSearchBarcodeResolver.java b/core/src/org/transdroid/core/app/search/GoogleWebSearchBarcodeResolver.java index d681deba..93ad08c0 100644 --- a/core/src/org/transdroid/core/app/search/GoogleWebSearchBarcodeResolver.java +++ b/core/src/org/transdroid/core/app/search/GoogleWebSearchBarcodeResolver.java @@ -44,7 +44,7 @@ public class GoogleWebSearchBarcodeResolver { HttpGet httpget = new HttpGet(callUrl); HttpResponse response = httpclient.execute(httpget); InputStream instream = response.getEntity().getContent(); - String result = HttpHelper.ConvertStreamToString(instream); + String result = HttpHelper.convertStreamToString(instream); JSONArray results = new JSONObject(result).getJSONObject("responseData").getJSONArray("results"); // We will combine and filter multiple results, if there are any diff --git a/core/src/org/transdroid/core/app/settings/ApplicationSettings.java b/core/src/org/transdroid/core/app/settings/ApplicationSettings.java index 24297afb..b019572d 100644 --- a/core/src/org/transdroid/core/app/settings/ApplicationSettings.java +++ b/core/src/org/transdroid/core/app/settings/ApplicationSettings.java @@ -65,18 +65,28 @@ public class ApplicationSettings { Daemon type = Daemon.fromCode(prefs.getString("server_type_" + order, null)); boolean ssl = prefs.getBoolean("server_sslenabled_" + order, false); String defaultPort = Integer.toString(Daemon.getDefaultPortNumber(type, ssl)); - return new ServerSetting(order, prefs.getString("server_name_" + order, null), type, prefs.getString( - "server_address_" + order, null), prefs.getString("server_localaddress_" + order, null), - prefs.getString("server_localnetwork_" + order, null), Integer.parseInt(prefs.getString("server_port_" - + order, defaultPort)), ssl, prefs.getBoolean("server_ssltrustall_" + order, false), - prefs.getString("server_ssltrustkey_" + order, null), prefs.getString("server_folder_" + order, null), - prefs.getBoolean("server_useauth_" + order, true), prefs.getString("server_user_" + order, null), - prefs.getString("server_pass_" + order, null), prefs.getString("server_extrapass_" + order, null), - OS.fromCode(prefs.getString("server_os_" + order, "type_linux")), prefs.getString("server_downloaddir_" - + order, null), prefs.getString("server_ftpurl_" + order, null), prefs.getString( - "server_ftppass_" + order, null), Integer.parseInt(prefs.getString("server_timeout_" + order, - "8")), prefs.getBoolean("server_alarmfinished_" + order, true), prefs.getBoolean( - "server_alarmnew_" + order, false), false); + return new ServerSetting(order, + prefs.getString("server_name_" + order, null), type, + prefs.getString("server_address_" + order, null), + prefs.getString("server_localaddress_" + order, null), + prefs.getString("server_localnetwork_" + order, null), + Integer.parseInt(prefs.getString("server_port_" + order, defaultPort)), + ssl, + prefs.getBoolean("server_ssltrustall_" + order, false), + prefs.getString("server_ssltrustkey_" + order, null), + prefs.getString("server_folder_" + order, null), + prefs.getBoolean("server_useauth_" + order, true), + prefs.getString("server_user_" + order, null), + prefs.getString("server_pass_" + order, null), + prefs.getString("server_extrapass_" + order, null), + OS.fromCode(prefs.getString("server_os_" + order, "type_linux")), + prefs.getString("server_downloaddir_" + order, null), + prefs.getString("server_ftpurl_" + order, null), + prefs.getString("server_ftppass_" + order, null), + Integer.parseInt(prefs.getString("server_timeout_" + order, "8")), + prefs.getBoolean("server_alarmfinished_" + order, true), + prefs.getBoolean("server_alarmnew_" + order, false), + false); // @formatter:on } @@ -219,8 +229,10 @@ public class ApplicationSettings { */ public WebsearchSetting getWebsearchSetting(int order) { // @formatter:off - return new WebsearchSetting(order, prefs.getString("websearch_name_" + order, null), prefs.getString( - "websearch_baseurl_" + order, null)); + return new WebsearchSetting(order, + prefs.getString("websearch_name_" + order, null), + prefs.getString("websearch_baseurl_" + order, null), + prefs.getString("websearch_cookies_" + order, null)); // @formatter:on } @@ -239,11 +251,13 @@ public class ApplicationSettings { for (int i = order; i < max; i++) { edit.putString("websearch_name_" + i, prefs.getString("websearch_name_" + (i + 1), null)); edit.putString("websearch_baseurl_" + i, prefs.getString("websearch_baseurl_" + (i + 1), null)); + edit.putString("websearch_cookies_" + i, prefs.getString("websearch_cookies_" + (i + 1), null)); } // Remove the last settings, of which we are now sure are no longer required edit.remove("websearch_name_" + max); edit.remove("websearch_baseurl_" + max); + edit.remove("websearch_cookies_" + max); edit.commit(); } @@ -279,9 +293,11 @@ public class ApplicationSettings { public RssfeedSetting getRssfeedSetting(int order) { // @formatter:off long lastViewed = prefs.getLong("rssfeed_lastviewed_" + order, -1); - return new RssfeedSetting(order, prefs.getString("rssfeed_name_" + order, null), prefs.getString("rssfeed_url_" - + order, null), prefs.getBoolean("rssfeed_reqauth_" + order, false), lastViewed == -1L ? null - : new Date(lastViewed)); + return new RssfeedSetting(order, + prefs.getString("rssfeed_name_" + order, null), + prefs.getString("rssfeed_url_" + order, null), + prefs.getBoolean("rssfeed_reqauth_" + order, false), + lastViewed == -1L ? null: new Date(lastViewed)); // @formatter:on } diff --git a/core/src/org/transdroid/core/app/settings/SettingsPersistence.java b/core/src/org/transdroid/core/app/settings/SettingsPersistence.java index f860cf09..620b67d8 100644 --- a/core/src/org/transdroid/core/app/settings/SettingsPersistence.java +++ b/core/src/org/transdroid/core/app/settings/SettingsPersistence.java @@ -49,7 +49,7 @@ public class SettingsPersistence { Editor editor = prefs.edit(); // Read the settings file - String raw = HttpHelper.ConvertStreamToString(new FileInputStream(settingsFile)); + String raw = HttpHelper.convertStreamToString(new FileInputStream(settingsFile)); JSONObject json = new JSONObject(raw); // Import servers diff --git a/core/src/org/transdroid/core/app/settings/WebsearchSetting.java b/core/src/org/transdroid/core/app/settings/WebsearchSetting.java index 76923215..8c6c673f 100644 --- a/core/src/org/transdroid/core/app/settings/WebsearchSetting.java +++ b/core/src/org/transdroid/core/app/settings/WebsearchSetting.java @@ -17,11 +17,13 @@ public class WebsearchSetting implements SimpleListItem { private final int order; private final String name; private final String baseUrl; + private final String cookies; - public WebsearchSetting(int order, String name, String baseUrl) { + public WebsearchSetting(int order, String name, String baseUrl, String cookies) { this.order = order; this.name = name; this.baseUrl = baseUrl; + this.cookies = cookies; } public int getOrder() { @@ -43,6 +45,10 @@ public class WebsearchSetting implements SimpleListItem { return baseUrl; } + public String getCookies() { + return cookies; + } + public String getKey() { return KEY_PREFIX + getOrder(); } diff --git a/core/src/org/transdroid/core/gui/TorrentsActivity.java b/core/src/org/transdroid/core/gui/TorrentsActivity.java index c0019529..91afe10a 100644 --- a/core/src/org/transdroid/core/gui/TorrentsActivity.java +++ b/core/src/org/transdroid/core/gui/TorrentsActivity.java @@ -1,11 +1,14 @@ package org.transdroid.core.gui; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.Background; @@ -19,17 +22,33 @@ import org.androidannotations.annotations.OptionsMenu; import org.androidannotations.annotations.SystemService; import org.androidannotations.annotations.UiThread; import org.androidannotations.annotations.ViewById; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.cookie.BasicClientCookie; import org.transdroid.core.R; -import org.transdroid.core.app.settings.*; +import org.transdroid.core.app.settings.ApplicationSettings; +import org.transdroid.core.app.settings.ServerSetting; +import org.transdroid.core.app.settings.SystemSettings_; +import org.transdroid.core.app.settings.WebsearchSetting; import org.transdroid.core.gui.lists.LocalTorrent; import org.transdroid.core.gui.lists.SimpleListItem; -import org.transdroid.core.gui.log.*; -import org.transdroid.core.gui.navigation.*; -import org.transdroid.core.gui.rss.*; +import org.transdroid.core.gui.log.Log; +import org.transdroid.core.gui.log.Log_; +import org.transdroid.core.gui.navigation.FilterListAdapter; +import org.transdroid.core.gui.navigation.FilterListAdapter_; +import org.transdroid.core.gui.navigation.FilterListDropDownAdapter; +import org.transdroid.core.gui.navigation.FilterListDropDownAdapter_; +import org.transdroid.core.gui.navigation.Label; +import org.transdroid.core.gui.navigation.NavigationFilter; +import org.transdroid.core.gui.navigation.NavigationHelper; +import org.transdroid.core.gui.navigation.StatusType; +import org.transdroid.core.gui.rss.RssfeedsActivity_; import org.transdroid.core.gui.search.BarcodeHelper; import org.transdroid.core.gui.search.FilePickerHelper; import org.transdroid.core.gui.search.UrlEntryDialog; -import org.transdroid.core.gui.settings.*; +import org.transdroid.core.gui.settings.MainSettingsActivity_; import org.transdroid.daemon.Daemon; import org.transdroid.daemon.IDaemonAdapter; import org.transdroid.daemon.Priority; @@ -62,6 +81,7 @@ import org.transdroid.daemon.task.SetTrackersTask; import org.transdroid.daemon.task.StartTask; import org.transdroid.daemon.task.StopTask; import org.transdroid.daemon.util.DLog; +import org.transdroid.daemon.util.HttpHelper; import android.annotation.TargetApi; import android.app.SearchManager; @@ -185,6 +205,7 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi // Handle any start up intents if (firstStart && getIntent() != null) { + currentConnection = lastUsed.createServerAdapter(); handleStartIntent(); } @@ -399,11 +420,32 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi // Adding a torrent from http or https URL if (dataUri.getScheme().equals("http") || dataUri.getScheme().equals("https")) { - String title = data.substring(data.lastIndexOf("/")); - if (intent.hasExtra("TORRENT_TITLE")) { - title = intent.getStringExtra("TORRENT_TITLE"); + + // Check if the target URL is also defined as a web search in the user's settings + List websearches = applicationSettings.getWebsearchSettings(); + WebsearchSetting match = null; + for (WebsearchSetting setting : websearches) { + Uri uri = Uri.parse(setting.getBaseUrl()); + if (uri.getHost() != null && uri.getHost().equals(dataUri.getHost())) { + match = setting; + break; + } + } + + // If the URL is also a web search and it defines cookies, use the cookies by downloading the targeted + // torrent file (while supplies the cookies to the HTTP request) instead of sending the URL directly to the + // torrent client + if (match != null && match.getCookies() != null) { + addTorrentFromWeb(data, match); + } else { + // Normally send the URL to the torrent client; the title we show is just the 'file name' + // TODO: Make a better effort in determining the title (check query string, clean special chars) + String title = data.substring(data.lastIndexOf("/") + 1); + if (intent.hasExtra("TORRENT_TITLE")) { + title = intent.getStringExtra("TORRENT_TITLE"); + } + addTorrentByUrl(data, title); } - addTorrentByUrl(data, title); return; } @@ -413,9 +455,9 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi return; } - // Adding a local .torrent file + // Adding a local .torrent file; the title we show is just the file name if (dataUri.getScheme().equals("file")) { - String title = data.substring(data.lastIndexOf("/")); + String title = data.substring(data.lastIndexOf("/") + 1); addTorrentByFile(data, title); return; } @@ -638,13 +680,61 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi private void addTorrentFromDownloads(Uri contentUri) { - InputStream input = null; try { - // Open the content uri as input stream - input = getContentResolver().openInputStream(contentUri); + // Open the content uri as input stream and this via a local temporary file + addTorrentFromStream(getContentResolver().openInputStream(contentUri)); + } catch (SecurityException e) { + // No longer access to this file + Log.e(this, "No access given to " + contentUri.toString() + ": " + e.toString()); + Crouton.showText(this, R.string.error_torrentfile, NavigationHelper.CROUTON_ERROR_STYLE); + } catch (FileNotFoundException e) { + Log.e(this, contentUri.toString() + " does not exist: " + e.toString()); + Crouton.showText(this, R.string.error_torrentfile, NavigationHelper.CROUTON_ERROR_STYLE); + } + } + + @Background + protected void addTorrentFromWeb(String url, WebsearchSetting websearchSetting) { + + try { + // Cookies are taken from the websearchSetting that we already matched against this target URL + DefaultHttpClient httpclient = HttpHelper.createStandardHttpClient(false, null, null, true, null, 10000, + null, -1); + Map cookies = HttpHelper.parseCookiePairs(websearchSetting.getCookies()); + String domain = Uri.parse(url).getHost(); + for (Entry pair : cookies.entrySet()) { + BasicClientCookie cookie = new BasicClientCookie(pair.getKey(), pair.getValue()); + cookie.setPath("/"); + cookie.setDomain(domain); + httpclient.getCookieStore().addCookie(cookie); + } + // Download the torrent at the specified URL (which will first be written to a temporary file) + // If we get an HTTP 401, 403 or 404 response, show an error to the user + HttpResponse response = httpclient.execute(new HttpGet(url)); + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED + || response.getStatusLine().getStatusCode() == HttpStatus.SC_FORBIDDEN + || response.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_FOUND) { + Log.e(this, "Can't retrieve web torrent " + url + ": Unexpected HTTP response status code " + + response.getStatusLine().toString()); + Crouton.showText(this, R.string.error_401, NavigationHelper.CROUTON_ERROR_STYLE); + return; + } + InputStream input = response.getEntity().getContent(); + addTorrentFromStream(input); + } catch (Exception e) { + Log.e(this, "Can't retrieve web torrent " + url + ": " + e.toString()); + Crouton.showText(this, R.string.error_torrentfile, NavigationHelper.CROUTON_ERROR_STYLE); + } + } + + @Background + protected void addTorrentFromStream(InputStream input) { + + File tempFile = new File("/not/yet/set"); + try { // Write a temporary file with the torrent contents - File tempFile = File.createTempFile("transdroid_", ".torrent", getCacheDir()); + tempFile = File.createTempFile("transdroid_", ".torrent", getCacheDir()); FileOutputStream output = new FileOutputStream(tempFile); try { final byte[] buffer = new byte[1024]; @@ -657,17 +747,15 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi } finally { output.close(); } - } catch (SecurityException e) { - // No longer access to this file - Crouton.showText(this, R.string.error_torrentfile, NavigationHelper.CROUTON_ERROR_STYLE); - } catch (IOException e1) { - // Can't write temporary file + } catch (IOException e) { + Log.e(this, "Can't write input stream to " + tempFile.toString() + ": " + e.toString()); Crouton.showText(this, R.string.error_torrentfile, NavigationHelper.CROUTON_ERROR_STYLE); } finally { try { if (input != null) input.close(); } catch (IOException e) { + Log.e(this, "Error closing the input stream " + tempFile.toString() + ": " + e.toString()); Crouton.showText(this, R.string.error_torrentfile, NavigationHelper.CROUTON_ERROR_STYLE); } } @@ -725,7 +813,7 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi @Override public void removeTorrent(Torrent torrent, boolean withData) { DaemonTaskResult result = RemoveTask.create(currentConnection, torrent, withData).execute(); - if (result instanceof DaemonTaskResult) { + if (result instanceof DaemonTaskSuccessResult) { onTaskSucceeded( (DaemonTaskSuccessResult) result, getString(withData ? R.string.result_removed_with_data : R.string.result_removed, torrent.getName())); @@ -799,16 +887,16 @@ public class TorrentsActivity extends SherlockFragmentActivity implements OnNavi @UiThread protected void onTorrentsRetrieved(List torrents, List labels) { - + // Report the newly retrieved list of torrents to the torrents fragment fragmentTorrents.updateIsLoading(false); fragmentTorrents.updateTorrents(new ArrayList(torrents)); - + // Update the details fragment if the currently shown torrent is in the newly retrieved list if (fragmentDetails != null) { fragmentDetails.perhapsUpdateTorrent(torrents); } - + // Update local list of labels in the navigation List