diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/torrent.c | 19 | ||||
-rw-r--r-- | src/torrent.h | 1 | ||||
-rw-r--r-- | src/trg-main-window.c | 46 | ||||
-rw-r--r-- | src/trg-main-window.h | 3 | ||||
-rw-r--r-- | src/trg-model.c | 6 | ||||
-rw-r--r-- | src/trg-model.h | 2 | ||||
-rw-r--r-- | src/trg-state-selector.c | 127 | ||||
-rw-r--r-- | src/trg-state-selector.h | 10 | ||||
-rw-r--r-- | src/trg-torrent-model.c | 19 | ||||
-rw-r--r-- | src/trg-torrent-model.h | 6 | ||||
-rw-r--r-- | src/util.c | 17 | ||||
-rw-r--r-- | src/util.h | 3 |
12 files changed, 236 insertions, 23 deletions
diff --git a/src/torrent.c b/src/torrent.c index def9cbc..f45cc31 100644 --- a/src/torrent.c +++ b/src/torrent.c @@ -23,6 +23,7 @@ #include "torrent.h" #include "protocol-constants.h" +#include "util.h" JsonArray *torrent_get_peers(JsonObject * t) { @@ -208,6 +209,24 @@ gchar *torrent_get_status_string(gint64 value) } } +gboolean torrent_has_tracker(JsonObject *t, GRegex *rx, gchar *search) +{ + JsonArray *trackers = torrent_get_trackers(t); + int i; + + for (i = 0; i < json_array_get_length(trackers); i++) { + JsonObject *tracker = json_array_get_object_element(trackers, i); + const gchar *trackerAnnounce = tracker_get_announce(tracker); + gchar *trackerAnnounceHost = trg_uri_host_extract(rx, trackerAnnounce); + int cmpResult = g_strcmp0(trackerAnnounceHost, search); + g_free(trackerAnnounceHost); + if (cmpResult == 0) + return TRUE; + } + + return FALSE; +} + gint64 tracker_get_id(JsonObject * t) { return json_object_get_int_member(t, FIELD_ID); diff --git a/src/torrent.h b/src/torrent.h index 16102e4..226cd4e 100644 --- a/src/torrent.h +++ b/src/torrent.h @@ -68,6 +68,7 @@ gboolean torrent_get_download_limited(JsonObject * t); gdouble torrent_get_seed_ratio_limit(JsonObject * t); gint64 torrent_get_seed_ratio_mode(JsonObject * t); gint64 torrent_get_peer_limit(JsonObject * t); +gboolean torrent_has_tracker(JsonObject *t, GRegex *rx, gchar *search); JsonArray *get_torrents(JsonObject * response); diff --git a/src/trg-main-window.c b/src/trg-main-window.c index ed25791..1b67687 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -40,6 +40,7 @@ #include "util.h" #include "requests.h" #include "session-get.h" +#include "torrent.h" #include "protocol-constants.h" #include "trg-main-window.h" @@ -72,13 +73,13 @@ static void torrent_event_notification(TrgTorrentModel * model, gchar * icon, gchar * desc, gint tmout, gchar * prefKey, GtkTreeIter * iter, - gpointer * data); + gpointer data); static void on_torrent_completed(TrgTorrentModel * model, - GtkTreeIter * iter, gpointer * data); + GtkTreeIter * iter, gpointer data); static void on_torrent_added(TrgTorrentModel * model, GtkTreeIter * iter, - gpointer * data); + gpointer data); static gboolean delete_event(GtkWidget * w, GdkEvent * event, - gpointer * data); + gpointer data); static void destroy_window(GtkWidget * w, gpointer data); static void torrent_tv_onRowActivated(GtkTreeView * treeview, GtkTreePath * path, @@ -268,7 +269,7 @@ static gboolean update_selected_torrent_notebook(TrgMainWindow * win, static void torrent_event_notification(TrgTorrentModel * model, gchar * icon, gchar * desc, gint tmout, gchar * prefKey, - GtkTreeIter * iter, gpointer * data) + GtkTreeIter * iter, gpointer data) { TrgMainWindowPrivate *priv; gchar *name; @@ -305,24 +306,30 @@ static void torrent_event_notification(TrgTorrentModel * model, } static void on_torrent_completed(TrgTorrentModel * model, - GtkTreeIter * iter, gpointer * data) + GtkTreeIter * iter, gpointer data) { torrent_event_notification(model, GTK_STOCK_APPLY, - "This torrent has completed.", 8000, + "This torrent has completed.", TORRENT_COMPLETE_NOTIFY_TMOUT, TRG_GCONF_KEY_COMPLETE_NOTIFY, iter, data); } +static void on_torrent_addremove(TrgTorrentModel *model, gpointer data) +{ + TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data); + trg_state_selector_update_trackers(priv->stateSelector, priv->client->torrents, priv->client->updateSerial); +} + static void on_torrent_added(TrgTorrentModel * model, - GtkTreeIter * iter, gpointer * data) + GtkTreeIter * iter, gpointer data) { torrent_event_notification(model, GTK_STOCK_ADD, - "This torrent has been added.", 3000, + "This torrent has been added.", TORRENT_ADD_NOTIFY_TMOUT, TRG_GCONF_KEY_ADD_NOTIFY, iter, data); } static gboolean delete_event(GtkWidget * w, GdkEvent * event G_GNUC_UNUSED, - gpointer * data G_GNUC_UNUSED) + gpointer data G_GNUC_UNUSED) { TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(w); int width, height; @@ -1043,9 +1050,20 @@ trg_torrent_tree_view_visible_func(GtkTreeModel * model, TORRENT_COLUMN_FLAGS, &flags, TORRENT_COLUMN_NAME, &name, -1); - if (criteria != 0 && !(flags & criteria)) { - visible = FALSE; - } else if (name != NULL) { + if (criteria != 0) { + if (criteria & FILTER_FLAG_TRACKER) { + gchar *text = trg_state_selector_get_selected_text(priv->stateSelector); + JsonObject *json = NULL; + gtk_tree_model_get(model, iter, TORRENT_COLUMN_JSON, &json, -1); + + if (!torrent_has_tracker(json, trg_state_selector_get_url_host_regex(priv->stateSelector), text)) + visible = FALSE; + } else if (!(flags & criteria)) { + visible = FALSE; + } + } + + if (visible && name != NULL) { const gchar *filterText = gtk_entry_get_text(GTK_ENTRY(priv->filterEntry)); if (strlen(filterText) > 0) { @@ -1762,6 +1780,8 @@ static GObject *trg_main_window_constructor(GType type, G_CALLBACK(on_torrent_completed), self); g_signal_connect(priv->torrentModel, "torrent-added", G_CALLBACK(on_torrent_added), self); + g_signal_connect(priv->torrentModel, "torrent-addremove", + G_CALLBACK(on_torrent_addremove), self); priv->filteredTorrentModel = gtk_tree_model_filter_new(GTK_TREE_MODEL(priv->torrentModel), diff --git a/src/trg-main-window.h b/src/trg-main-window.h index fd413c6..cdba421 100644 --- a/src/trg-main-window.h +++ b/src/trg-main-window.h @@ -57,6 +57,9 @@ typedef struct { #define TORRENT_GET_MODE_INTERACTION 1 #define TORRENT_GET_MODE_UPDATE 2 +#define TORRENT_COMPLETE_NOTIFY_TMOUT 8000 +#define TORRENT_ADD_NOTIFY_TMOUT 3000 + GType trg_main_window_get_type(void); gboolean trg_add_from_filename(TrgMainWindow * win, gchar * fileName); void on_session_set(JsonObject * response, int status, gpointer data); diff --git a/src/trg-model.c b/src/trg-model.c index e41c4b3..5796507 100644 --- a/src/trg-model.c +++ b/src/trg-model.c @@ -43,12 +43,13 @@ trg_model_remove_removed_foreachfunc(GtkTreeModel * model, return FALSE; } -void +guint trg_model_remove_removed(GtkListStore * model, gint serial_column, gint64 currentSerial) { struct trg_model_remove_removed_foreachfunc_args args; GList *li; + guint removed = 0; args.toRemove = NULL; args.currentSerial = currentSerial; @@ -60,9 +61,12 @@ trg_model_remove_removed(GtkListStore * model, gint serial_column, li = g_list_previous(li)) { gtk_list_store_remove(model, (GtkTreeIter *) li->data); gtk_tree_iter_free((GtkTreeIter *) li->data); + removed++; } g_list_free(args.toRemove); } + + return removed; } struct find_existing_item_foreach_args { diff --git a/src/trg-model.h b/src/trg-model.h index b20cbe4..987cfca 100644 --- a/src/trg-model.h +++ b/src/trg-model.h @@ -22,7 +22,7 @@ #include <gtk/gtk.h> -void trg_model_remove_removed(GtkListStore * model, gint serial_column, +guint trg_model_remove_removed(GtkListStore * model, gint serial_column, gint64 currentSerial); gboolean diff --git a/src/trg-state-selector.c b/src/trg-state-selector.c index 1ae4247..f20a407 100644 --- a/src/trg-state-selector.c +++ b/src/trg-state-selector.c @@ -18,11 +18,13 @@ */ #include <glib-object.h> +#include <json-glib/json-glib.h> #include <glib/gi18n.h> #include <gtk/gtk.h> #include "torrent.h" #include "trg-state-selector.h" +#include "util.h" enum { SELECTOR_STATE_CHANGED, @@ -38,8 +40,16 @@ typedef struct _TrgStateSelectorPrivate TrgStateSelectorPrivate; struct _TrgStateSelectorPrivate { guint flag; + GHashTable *trackers; + GRegex *urlHostRegex; }; +GRegex *trg_state_selector_get_url_host_regex(TrgStateSelector *s) +{ + TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); + return priv->urlHostRegex; +} + guint32 trg_state_selector_get_flag(TrgStateSelector * s) { TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); @@ -85,6 +95,104 @@ static void state_selection_changed(GtkTreeSelection * selection, signals[SELECTOR_STATE_CHANGED], 0, priv->flag); } +static GtkTreeRowReference *quick_tree_ref_new(GtkTreeModel *model, GtkTreeIter *iter) +{ + GtkTreePath *path = gtk_tree_model_get_path(model, iter); + GtkTreeRowReference *rr = gtk_tree_row_reference_new(model, path); + gtk_tree_path_free(path); + return rr; +} + +struct cruft_remove_args { + GHashTable *table; + gint64 serial; +}; + +static gboolean trg_state_selector_remove_cruft(gpointer key, gpointer value, gpointer data) +{ + struct cruft_remove_args *args = (struct cruft_remove_args*)data; + GtkTreeRowReference *rr = (GtkTreeRowReference*)value; + GtkTreeModel *model = gtk_tree_row_reference_get_model(rr); + GtkTreePath *path = gtk_tree_row_reference_get_path(rr); + gboolean remove; + + GtkTreeIter iter; + gint64 currentSerial; + + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, STATE_SELECTOR_SERIAL, ¤tSerial, -1); + + remove = (args->serial != currentSerial); + + gtk_tree_path_free(path); + + return remove; +} + +gchar *trg_state_selector_get_selected_text(TrgStateSelector *s) +{ + GtkTreeSelection *sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(s)); + GtkTreeModel *model; + GtkTreeIter iter; + gchar *name = NULL; + + if (gtk_tree_selection_get_selected(sel, &model, &iter)) + gtk_tree_model_get(model, &iter, STATE_SELECTOR_NAME, &name, -1); + + return name; +} + +void trg_state_selector_update_trackers(TrgStateSelector *s, JsonArray *torrents, gint64 serial) +{ + TrgStateSelectorPrivate *priv = TRG_STATE_SELECTOR_GET_PRIVATE(s); + GtkTreeModel *model; + GtkTreeIter iter; + int i, j; + struct cruft_remove_args cruft; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(s)); + + for (i = 0; i < json_array_get_length(torrents); i++) { + JsonObject *t = json_array_get_object_element(torrents, i); + JsonArray *trackers = torrent_get_trackers(t); + + for (j = 0; j < json_array_get_length(trackers); j++) { + JsonObject *tracker = json_array_get_object_element(trackers, j); + const gchar *announceUrl = tracker_get_announce(tracker); + gchar *announceHost = trg_uri_host_extract(priv->urlHostRegex, announceUrl); + gpointer result; + + if (!announceHost) + continue; + + result = g_hash_table_lookup(priv->trackers, announceHost); + + if (result) + { + GtkTreeRowReference *rr = (GtkTreeRowReference*)result; + GtkTreePath *path = gtk_tree_row_reference_get_path(rr); + gtk_tree_model_get_iter(model, &iter, path); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + STATE_SELECTOR_SERIAL, serial, -1); + gtk_tree_path_free(path); + } else { + gtk_list_store_append(GTK_LIST_STORE(model), &iter); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + STATE_SELECTOR_ICON, GTK_STOCK_NETWORK, + STATE_SELECTOR_NAME, announceHost, + STATE_SELECTOR_SERIAL, serial, + STATE_SELECTOR_BIT, FILTER_FLAG_TRACKER, -1); + g_hash_table_insert(priv->trackers, announceHost, quick_tree_ref_new(model, &iter)); + } + } + } + + cruft.serial = serial; + cruft.table = priv->trackers; + + g_hash_table_foreach_remove(priv->trackers, trg_state_selector_remove_cruft, &cruft); +} + static void trg_state_selector_add_state(GtkListStore * model, GtkTreeIter * iter, gchar * icon, gchar * name, guint32 flag) @@ -96,6 +204,18 @@ static void trg_state_selector_add_state(GtkListStore * model, STATE_SELECTOR_BIT, flag, -1); } +static void remove_row_ref_and_free(GtkTreeRowReference *rr) +{ + GtkTreeModel *model = gtk_tree_row_reference_get_model(rr); + GtkTreePath *path = gtk_tree_row_reference_get_path(rr); + GtkTreeIter iter; + + gtk_tree_model_get_iter(model, &iter, path); + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + gtk_tree_path_free(path); + gtk_tree_row_reference_free(rr); +} + static void trg_state_selector_init(TrgStateSelector * self) { TrgStateSelectorPrivate *priv; @@ -108,6 +228,9 @@ static void trg_state_selector_init(TrgStateSelector * self) priv = TRG_STATE_SELECTOR_GET_PRIVATE(self); priv->flag = 0; + priv->urlHostRegex = trg_uri_host_regex_new(); + priv->trackers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)remove_row_ref_and_free); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(self), FALSE); column = gtk_tree_view_column_new(); @@ -126,7 +249,7 @@ static void trg_state_selector_init(TrgStateSelector * self) store = gtk_list_store_new(STATE_SELECTOR_COLUMNS, G_TYPE_STRING, - G_TYPE_STRING, G_TYPE_UINT); + G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INT64); trg_state_selector_add_state(store, &iter, GTK_STOCK_ABOUT, _("All"), 0); @@ -145,6 +268,8 @@ static void trg_state_selector_init(TrgStateSelector * self) _("Seeding"), TORRENT_FLAG_SEEDING); trg_state_selector_add_state(store, &iter, GTK_STOCK_DIALOG_WARNING, _("Error"), TORRENT_FLAG_ERROR); + trg_state_selector_add_state(store, &iter, NULL, + NULL, 0); gtk_tree_view_set_model(GTK_TREE_VIEW(self), GTK_TREE_MODEL(store)); gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(self), TRUE); diff --git a/src/trg-state-selector.h b/src/trg-state-selector.h index 944647a..d09d76a 100644 --- a/src/trg-state-selector.h +++ b/src/trg-state-selector.h @@ -22,11 +22,13 @@ #define TRG_STATE_LIST_H_ #include <glib-object.h> +#include <json-glib/json-glib.h> enum { STATE_SELECTOR_ICON, STATE_SELECTOR_NAME, STATE_SELECTOR_BIT, + STATE_SELECTOR_SERIAL, STATE_SELECTOR_COLUMNS }; @@ -49,15 +51,17 @@ G_BEGIN_DECLS typedef struct { GtkTreeViewClass parent_class; - /* SIGNALS */ - void (*torrent_state_changed) (TrgStateSelector * selector, - guint flag, gpointer data); + guint flag, gpointer data); + } TrgStateSelectorClass; GType trg_state_selector_get_type(void); TrgStateSelector *trg_state_selector_new(void); G_END_DECLS guint32 trg_state_selector_get_flag(TrgStateSelector * s); +void trg_state_selector_update_trackers(TrgStateSelector *s, JsonArray *torrents, gint64 serial); +gchar *trg_state_selector_get_selected_text(TrgStateSelector *s); +GRegex *trg_state_selector_get_url_host_regex(TrgStateSelector *s); #endif /* TRG_STATE_LIST_H_ */ diff --git a/src/trg-torrent-model.c b/src/trg-torrent-model.c index c201fa2..7fa82ae 100644 --- a/src/trg-torrent-model.c +++ b/src/trg-torrent-model.c @@ -33,6 +33,7 @@ enum { TMODEL_TORRENT_COMPLETED, TMODEL_TORRENT_ADDED, + TMODEL_TORRENT_ADDREMOVE, TMODEL_SIGNAL_COUNT }; @@ -69,6 +70,16 @@ static void trg_torrent_model_class_init(TrgTorrentModelClass * klass) torrent_added), NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER); + + signals[TMODEL_TORRENT_ADDREMOVE] = + g_signal_new("torrent-addremove", + G_TYPE_FROM_CLASS(object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(TrgTorrentModelClass, + torrent_removed), NULL, + NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + } static void trg_torrent_model_count_peers(TrgTorrentModel * model, @@ -272,6 +283,7 @@ void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc, { int i; JsonArray *newTorrents; + gboolean added = FALSE; newTorrents = get_torrents(get_arguments(response)); stats->count = json_array_get_length(newTorrents); @@ -287,8 +299,10 @@ void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc, TORRENT_COLUMN_ID, torrent_get_id(t), &iter) == FALSE) { + added = TRUE; gtk_list_store_append(GTK_LIST_STORE(model), &iter); update_torrent_iter(tc->updateSerial, model, &iter, t, stats); + if (!first) g_signal_emit(model, signals[TMODEL_TORRENT_ADDED], 0, &iter); @@ -304,7 +318,8 @@ void trg_torrent_model_update(TrgTorrentModel * model, trg_client * tc, tc->torrents = newTorrents; - trg_model_remove_removed(GTK_LIST_STORE(model), + if (trg_model_remove_removed(GTK_LIST_STORE(model), TORRENT_COLUMN_UPDATESERIAL, - tc->updateSerial); + tc->updateSerial) > 0 || added) + g_signal_emit(model, signals[TMODEL_TORRENT_ADDREMOVE], 0); } diff --git a/src/trg-torrent-model.h b/src/trg-torrent-model.h index cc8c695..ee064d2 100644 --- a/src/trg-torrent-model.h +++ b/src/trg-torrent-model.h @@ -45,11 +45,13 @@ G_BEGIN_DECLS typedef struct { GtkListStoreClass parent_class; void (*torrent_completed) (TrgTorrentModel * model, - GtkTreeIter * iter, JsonObject * t, + GtkTreeIter * iter, gpointer data); void (*torrent_added) (TrgTorrentModel * model, - GtkTreeIter * iter, JsonObject * t, + GtkTreeIter * iter, gpointer data); + + void (*torrent_removed) (TrgTorrentModel *model, gpointer data); } TrgTorrentModelClass; typedef struct { @@ -34,6 +34,23 @@ #include "util.h" #include "dispatch.h" +GRegex *trg_uri_host_regex_new(void) +{ + return g_regex_new("^[^:/?#]+:?//([^/?#]*)", 0, 0, NULL); +} + +gchar *trg_uri_host_extract(GRegex *rx, const gchar *uri) +{ + GMatchInfo *mi = NULL; + gchar *host = NULL; + g_regex_match (rx, uri, 0, &mi); + if (mi) { + host = g_match_info_fetch(mi, 1); + g_match_info_free (mi); + } + return host; +} + void trg_error_dialog(GtkWindow * parent, int status, JsonObject * response) { @@ -36,6 +36,9 @@ #define MEGABYTE_FACTOR ( 1024.0 * 1024.0 ) #define GIGABYTE_FACTOR ( 1024.0 * 1024.0 * 1024.0 ) +GRegex *trg_uri_host_regex_new(void); +gchar *trg_uri_host_extract(GRegex *rx, const gchar *uri); + char *tr_strltime_long(char *buf, gint64 seconds, size_t buflen); char *tr_strltime_short(char *buf, gint64 seconds, size_t buflen); char *tr_strpercent(char *buf, double x, size_t buflen); |