summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@yahoo.com>2011-11-15 00:29:40 +0100
committerJoel Klinghed <the_jk@yahoo.com>2011-11-15 00:29:40 +0100
commit29ef95680bcbb6cacefbd9f26cb04ab2ed12e1ca (patch)
treef3a0cd1081e01e38e79a23e57c6b945539d81c5b /src/main.c
parent4e199c3693d85c0917f264d9e01ceab20b368fc2 (diff)
Connect/Disconnect support.
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c410
1 files changed, 363 insertions, 47 deletions
diff --git a/src/main.c b/src/main.c
index 525aa38..1197054 100644
--- a/src/main.c
+++ b/src/main.c
@@ -39,6 +39,30 @@ static void torrent_update(torrent_t* torrent,
typedef struct
{
GAsyncQueue* queue;
+
+ gboolean connected;
+ GtkListStore* liststore;
+ GtkWidget* top;
+ GtkWidget* connectmenuitem, * disconnectmenuitem;
+
+ GtkWidget* connectdlg;
+ GtkWidget* connectdlg_url;
+ GtkWidget* connectdlg_user;
+ GtkWidget* connectdlg_pwd;
+
+ GtkWidget* statusbar;
+ guint status_contextid;
+
+ GKeyFile* config;
+ gchar* configfile;
+ guint config_timer;
+ guint config_try;
+} master_t;
+
+typedef struct
+{
+ GAsyncQueue* queue;
+ master_t* master;
} worker_data_t;
typedef enum
@@ -48,11 +72,13 @@ typedef enum
MSG_DISCONNECT, /* main -> worker */
MSG_QUIT, /* main -> worker */
MSG_ERROR, /* worker -> main */
+ MSG_STATUS, /* worker -> main */
} msg_type_t;
typedef struct
{
msg_type_t type;
+ master_t* master;
} msg_t;
typedef struct
@@ -78,6 +104,12 @@ typedef struct
typedef struct
{
msg_t base;
+ gchar* msg;
+} msg_status_t;
+
+typedef struct
+{
+ msg_t base;
} msg_quit_t;
typedef struct
@@ -91,10 +123,18 @@ static msg_t* msg_connect(const gchar* url, const gchar* username,
const gchar* password);
static msg_t* msg_connectresult(gboolean success, const gchar* errfmt, ...);
static msg_t* msg_error(const gchar* format, ...);
+static msg_t* msg_status(const gchar* format, ...);
static msg_t* msg_disconnect(void);
static msg_t* msg_quit(void);
+static void do_connect(GtkMenuItem* menuitem, gpointer data);
+static void do_disconnect(GtkMenuItem* menuitem, gpointer data);
+
static gpointer worker_main(gpointer data);
+static gboolean incoming_msg(gpointer data);
+static gboolean sync_config(gpointer data);
+static void save_config(master_t* master);
+static void status(master_t* master, const char* format, ...);
int main(int argc, char** argv)
{
@@ -102,20 +142,22 @@ int main(int argc, char** argv)
GtkBuilder* builder;
GError* error = NULL;
guint ret;
- GtkWidget* top;
GtkWidget* listview;
- GtkListStore* liststore;
- GtkTreeIter iter;
GtkCellRenderer* cell;
GtkTreeViewColumn* column;
GThread* worker;
worker_data_t worker_data;
+ master_t master;
+
+ memset(&master, 0, sizeof(master));
g_thread_init(NULL);
gtk_init(&argc, &argv);
worker_data.queue = g_async_queue_new();
+ master.queue = worker_data.queue;
+ worker_data.master = &master;
worker = g_thread_create(worker_main, &worker_data, TRUE, NULL);
if (worker == NULL)
{
@@ -141,14 +183,26 @@ int main(int argc, char** argv)
return EXIT_FAILURE;
}
- top = GTK_WIDGET(gtk_builder_get_object(builder, "main"));
+ master.top = GTK_WIDGET(gtk_builder_get_object(builder, "main"));
- g_signal_connect(top, "delete-event", G_CALLBACK(gtk_main_quit), NULL);
+ g_signal_connect(master.top, "delete-event",
+ G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(gtk_builder_get_object(builder, "quitmenuitem"),
"activate", G_CALLBACK(gtk_main_quit), NULL);
+ master.connectmenuitem = GTK_WIDGET(gtk_builder_get_object(builder, "connectmenuitem"));
+ master.disconnectmenuitem = GTK_WIDGET(gtk_builder_get_object(builder, "disconnectmenuitem"));
+ g_signal_connect(master.connectmenuitem,
+ "activate", G_CALLBACK(do_connect), &master);
+ g_signal_connect(master.disconnectmenuitem,
+ "activate", G_CALLBACK(do_disconnect), &master);
+
+ gtk_widget_set_sensitive(master.connectmenuitem, TRUE);
+ gtk_widget_set_sensitive(master.disconnectmenuitem, FALSE);
+
listview = GTK_WIDGET(gtk_builder_get_object(builder, "treeview"));
- liststore = GTK_LIST_STORE(gtk_builder_get_object(builder, "liststore"));
+ master.liststore = GTK_LIST_STORE(gtk_builder_get_object(builder,
+ "liststore"));
cell = custom_cell_renderer_state_new();
column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "statecolumn"));
@@ -175,54 +229,287 @@ int main(int argc, char** argv)
gtk_tree_view_column_pack_start(column, cell, TRUE);
gtk_tree_view_column_add_attribute(column, cell, "left", COLUMN_LEFT);
+ master.statusbar = GTK_WIDGET(gtk_builder_get_object(builder, "statusbar"));
+ master.status_contextid = gtk_statusbar_get_context_id(GTK_STATUSBAR(master.statusbar), "main");
+
+ master.config = g_key_file_new();
+ master.configfile = g_build_filename(g_get_user_config_dir(),
+ "viewtorrent.ini", NULL);
+ g_key_file_load_from_file(master.config, master.configfile,
+ G_KEY_FILE_KEEP_COMMENTS |
+ G_KEY_FILE_KEEP_TRANSLATIONS,
+ NULL);
+
+ gtk_widget_show_all(master.top);
+
+ master.connectdlg = GTK_WIDGET(gtk_builder_get_object(builder, "connectdlg"));
+ master.connectdlg_url = GTK_WIDGET(gtk_builder_get_object(builder, "connectdlg_url"));
+ master.connectdlg_user = GTK_WIDGET(gtk_builder_get_object(builder, "connectdlg_user"));
+ master.connectdlg_pwd = GTK_WIDGET(gtk_builder_get_object(builder, "connectdlg_pwd"));
+
+ if (g_key_file_get_boolean(master.config, "connect", "auto", NULL))
{
- torrent_t torrent;
- torrent.state = STATE_DEAD;
- torrent.title = "The.Tree.of.Life.2011.720p.BluRay.x264.DTS-HDxT";
- torrent.seeded = 3.0;
- torrent.downloaded = 100.0;
- torrent.up = 0.0;
- torrent.down = 0.0;
- torrent.left = -1;
+ gchar* url = g_key_file_get_string(master.config, "connect", "url",
+ NULL);
+ gchar* user = g_key_file_get_string(master.config,
+ "connect", "username",
+ NULL);
+ gchar* pass = NULL;
+ if (url != NULL && user != NULL)
+ {
+ GtkWidget* dlg, * label, * pwd;
+ gchar* format, * text;
+ dlg = GTK_WIDGET(gtk_builder_get_object(builder, "pwddlg"));
+ label = GTK_WIDGET(gtk_builder_get_object(builder, "pwddlg_label"));
+ pwd = GTK_WIDGET(gtk_builder_get_object(builder, "pwddlg_pwd"));
+
+ format = g_strdup(gtk_label_get_text(GTK_LABEL(label)));
+ text = g_strdup_printf(format, url);
+ g_free(format);
+ gtk_label_set_text(GTK_LABEL(label), text);
+ g_free(text);
- gtk_list_store_append(liststore, &iter);
- torrent_update(&torrent, liststore, &iter);
+ switch (gtk_dialog_run(GTK_DIALOG(dlg)))
+ {
+ case GTK_RESPONSE_OK:
+ pass = g_strdup(gtk_entry_get_text(GTK_ENTRY(pwd)));
+ break;
+ case GTK_RESPONSE_CANCEL:
+ default:
+ g_free(url);
+ url = NULL;
+ }
+ gtk_widget_hide(dlg);
+ }
+ if (url != NULL)
+ {
+ g_async_queue_push(worker_data.queue, msg_connect(url, user, pass));
+ status(&master, "Autoconnecting to %s...", url);
+ }
+ g_free(url);
+ g_free(user);
+ g_free(pass);
}
+
+ gtk_main();
+
+ if (master.config_timer > 0)
{
- torrent_t torrent;
- torrent.state = STATE_ACTIVE;
- torrent.title = "Burn.Notice.S05E14.720p.HDTV.x264-AVS.mkv";
- torrent.seeded = 2.79;
- torrent.downloaded = 100.0;
- torrent.up = 72.5;
- torrent.down = 0.0;
- torrent.left = -1;
+ g_source_remove(master.config_timer);
+ master.config_timer = 0;
+ sync_config(&master);
+ }
- gtk_list_store_append(liststore, &iter);
- torrent_update(&torrent, liststore, &iter);
+ g_async_queue_push(worker_data.queue, msg_quit());
+ g_async_queue_unref(worker_data.queue);
+
+ g_thread_join(worker);
+
+ g_key_file_free(master.config);
+ g_free(master.configfile);
+
+ return EXIT_SUCCESS;
+}
+
+gboolean sync_config(gpointer _data)
+{
+ master_t* master = (master_t*)_data;
+ gsize length;
+ gchar *data = g_key_file_to_data(master->config, &length, NULL);
+ GError* err = NULL;
+ if (!g_file_set_contents(master->configfile, data, length, &err))
+ {
+ g_free(data);
+ status(master, "Error writing configfile: %s", err->message);
+ g_error_free(err);
+ master->config_try++;
+ if (master->config_try == 2)
+ {
+ /* Wait longer */
+ master->config_timer = g_timeout_add_seconds(5 * 60,
+ sync_config, master);
+ return FALSE;
+ }
+ if (master->config_try == 10)
+ {
+ /* Just give up */
+ return FALSE;
+ }
+ /* Try again */
+ return TRUE;
}
+ g_free(data);
+ master->config_timer = 0;
+ master->config_try = 0;
+ return FALSE;
+}
+
+gboolean incoming_msg(gpointer data)
+{
+ msg_t* msg = data;
+ switch (msg->type)
{
- torrent_t torrent;
- torrent.state = STATE_ACTIVE;
- torrent.title = "CSI.S12E07.720p.HDTV.X264-DIMENSION.mkv";
- torrent.seeded = 1.5;
- torrent.downloaded = 73.45;
- torrent.up = 37.3;
- torrent.down = 994.8;
- torrent.left = 24340;
+ case MSG_CONNECTRESULT:
+ {
+ msg_connectresult_t* m = (msg_connectresult_t*)msg;
+ if (m->success)
+ {
+ msg->master->connected = TRUE;
+ gtk_widget_set_sensitive(msg->master->connectmenuitem, FALSE);
+ gtk_widget_set_sensitive(msg->master->disconnectmenuitem, TRUE);
- gtk_list_store_append(liststore, &iter);
- torrent_update(&torrent, liststore, &iter);
+ g_key_file_set_boolean(msg->master->config, "connect",
+ "auto", TRUE);
+ save_config(msg->master);
+
+ status(master, "Connected.");
+ }
+ else
+ {
+ GtkWidget* dlg;
+ msg->master->connected = FALSE;
+ gtk_widget_set_sensitive(msg->master->connectmenuitem, TRUE);
+ gtk_widget_set_sensitive(msg->master->disconnectmenuitem, FALSE);
+ gtk_list_store_clear(msg->master->liststore);
+
+ dlg = gtk_message_dialog_new(GTK_WINDOW(msg->master->top),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Failed to connect: %s",
+ m->errmsg);
+ gtk_dialog_run(GTK_DIALOG(dlg));
+ gtk_widget_destroy(dlg);
+ }
+ break;
}
+ case MSG_ERROR:
+ {
+ msg_error_t* m = (msg_error_t*)msg;
+ GtkWidget* dlg;
+ dlg = gtk_message_dialog_new(GTK_WINDOW(msg->master->top),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CLOSE,
+ "Fatal error: %s",
+ m->msg);
+ gtk_dialog_run(GTK_DIALOG(dlg));
+ gtk_widget_destroy(dlg);
+ gtk_main_quit();
+ break;
+ }
+ case MSG_STATUS:
+ {
+ msg_status_t* m = (msg_status_t*)msg;
+ status(msg->master, m->msg);
+ break;
+ }
+ case MSG_CONNECT:
+ case MSG_DISCONNECT:
+ case MSG_QUIT:
+ g_assert(FALSE);
+ }
+ msg_free(msg);
+ return FALSE;
+}
- gtk_widget_show_all(top);
+void do_connect(GtkMenuItem* menuitem, gpointer data)
+{
+ master_t* master = data;
+ gchar* url, * user, * pass = NULL;
+ if (master->connected)
+ {
+ return;
+ }
- gtk_main();
+ url = g_key_file_get_string(master->config, "connect", "url", NULL);
+ user = g_key_file_get_string(master->config, "connect", "username", NULL);
- g_async_queue_push(worker_data.queue, msg_quit());
- g_async_queue_unref(worker_data.queue);
+ gtk_entry_set_text(GTK_ENTRY(master->connectdlg_url), url ? url : "");
+ gtk_entry_set_text(GTK_ENTRY(master->connectdlg_user),user ? user : "");
+ gtk_entry_set_text(GTK_ENTRY(master->connectdlg_pwd), "");
- return EXIT_SUCCESS;
+ switch (gtk_dialog_run(GTK_DIALOG(master->connectdlg)))
+ {
+ case GTK_RESPONSE_OK:
+ g_free(url);
+ g_free(user);
+ url = g_strdup(gtk_entry_get_text(GTK_ENTRY(master->connectdlg_url)));
+ user = g_strdup(gtk_entry_get_text(GTK_ENTRY(master->connectdlg_user)));
+ pass = g_strdup(gtk_entry_get_text(GTK_ENTRY(master->connectdlg_pwd)));
+ break;
+ case GTK_RESPONSE_CANCEL:
+ default:
+ g_free(url);
+ g_free(user);
+ url = NULL;
+ }
+ gtk_widget_hide(master->connectdlg);
+
+ if (url == NULL)
+ {
+ return FALSE;
+ }
+
+ if (strlen(user) == 0 && strlen(pass) == 0)
+ {
+ g_free(user);
+ g_free(pass);
+ user = NULL;
+ pass = NULL;
+ }
+
+ gtk_widget_set_sensitive(master->connectmenuitem, FALSE);
+ status(master, "Connecting to %s...", url);
+ g_key_file_set_string(master->config, "connect", "url", url);
+ if (user != NULL)
+ {
+ g_key_file_set_string(master->config, "connect", "username", user);
+ }
+ else
+ {
+ g_key_file_remove_key(master->config, "connect", "username", NULL);
+ }
+ g_key_file_remove_key(master->config, "connect", "auto", NULL);
+ save_config(master);
+ g_async_queue_push(master->queue, msg_connect(url, user, pass));
+ g_free(url);
+ g_free(user);
+ g_free(pass);
+}
+
+void do_disconnect(GtkMenuItem* menuitem, gpointer data)
+{
+ master_t* master = data;
+ if (!master->connected)
+ {
+ return;
+ }
+ gtk_widget_set_sensitive(master->disconnectmenuitem, FALSE);
+ status(master, "Disconnecting...");
+ g_async_queue_push(master->queue, msg_disconnect());
+}
+
+void save_config(master_t* master)
+{
+ if (master->config_timer == 0)
+ {
+ master->config_timer = g_timeout_add_seconds(5, sync_config, master);
+ }
+}
+
+void status(master_t* master, const char* format, ...)
+{
+ gchar* tmp;
+ va_list args;
+ gtk_statusbar_pop(GTK_STATUSBAR(master->statusbar),
+ master->status_contextid);
+ va_start(args, format);
+ tmp = g_strdup_vprintf(format, args);
+ va_end(args);
+ gtk_statusbar_push(GTK_STATUSBAR(master->statusbar),
+ master->status_contextid, tmp);
+ g_free(tmp);
}
void torrent_update(torrent_t* torrent, GtkListStore* store, GtkTreeIter* iter)
@@ -241,6 +528,8 @@ void torrent_update(torrent_t* torrent, GtkListStore* store, GtkTreeIter* iter)
-1);
}
+static void worker_respond(worker_data_t* data, msg_t* msg);
+
gpointer worker_main(gpointer _data)
{
worker_data_t* data = _data;
@@ -257,9 +546,9 @@ gpointer worker_main(gpointer _data)
NULL, 0, &client);
if (env.fault_occurred)
{
- g_async_queue_push(data->queue,
- msg_error("Unable to create XMLRPC-C client (%d): %s",
- env.fault_code, env.fault_string));
+ worker_respond(data,
+ msg_error("Unable to create XMLRPC-C client (%d): %s",
+ env.fault_code, env.fault_string));
quit = TRUE;
}
@@ -292,7 +581,7 @@ gpointer worker_main(gpointer _data)
xmlrpc_server_info_free(server);
msg_free(msg);
server = NULL;
- g_async_queue_push(data->queue,
+ worker_respond(data,
msg_connectresult(FALSE,
"Unable to get client version (%d): %s",
env.fault_code, env.fault_string));
@@ -306,7 +595,7 @@ gpointer worker_main(gpointer _data)
xmlrpc_server_info_free(server);
msg_free(msg);
server = NULL;
- g_async_queue_push(data->queue,
+ worker_respond(data,
msg_connectresult(FALSE,
"Unable to get client version (%d): %s",
env.fault_code, env.fault_string));
@@ -314,7 +603,8 @@ gpointer worker_main(gpointer _data)
}
printf("result: %s\n", tmp);
xmlrpc_DECREF(result);
- g_async_queue_push(data->queue, msg_connectresult(TRUE, NULL));
+ worker_respond(data,
+ msg_connectresult(TRUE, NULL));
msg_free(msg);
break;
}
@@ -322,12 +612,15 @@ gpointer worker_main(gpointer _data)
{
xmlrpc_server_info_free(server);
server = NULL;
+ worker_respond(data, msg_status("Disconnected."));
break;
}
case MSG_QUIT:
+ quit = TRUE;
break;
case MSG_CONNECTRESULT:
case MSG_ERROR:
+ case MSG_STATUS:
g_assert(FALSE);
break;
}
@@ -343,6 +636,12 @@ gpointer worker_main(gpointer _data)
return NULL;
}
+void worker_respond(worker_data_t* data, msg_t* msg)
+{
+ msg->master = data->master;
+ g_main_context_invoke(NULL, incoming_msg, msg);
+}
+
void msg_free(msg_t* msg)
{
switch (msg->type)
@@ -367,6 +666,12 @@ void msg_free(msg_t* msg)
g_free(m->msg);
break;
}
+ case MSG_STATUS:
+ {
+ msg_status_t* m = (msg_status_t*)msg;
+ g_free(m->msg);
+ break;
+ }
case MSG_DISCONNECT:
case MSG_QUIT:
break;
@@ -415,6 +720,17 @@ msg_t* msg_error(const gchar* format, ...)
return &msg->base;
}
+msg_t* msg_status(const gchar* format, ...)
+{
+ msg_status_t* msg = g_new0(msg_status_t, 1);
+ va_list args;
+ msg->base.type = MSG_STATUS;
+ va_start(args, format);
+ msg->msg = g_strdup_vprintf(format, args);
+ va_end(args);
+ return &msg->base;
+}
+
msg_t* msg_disconnect(void)
{
msg_disconnect_t* msg = g_new0(msg_disconnect_t, 1);