diff options
| author | Joel Klinghed <the_jk@yahoo.com> | 2011-11-15 00:29:40 +0100 |
|---|---|---|
| committer | Joel Klinghed <the_jk@yahoo.com> | 2011-11-15 00:29:40 +0100 |
| commit | 29ef95680bcbb6cacefbd9f26cb04ab2ed12e1ca (patch) | |
| tree | f3a0cd1081e01e38e79a23e57c6b945539d81c5b /src | |
| parent | 4e199c3693d85c0917f264d9e01ceab20b368fc2 (diff) | |
Connect/Disconnect support.
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.c | 410 |
1 files changed, 363 insertions, 47 deletions
@@ -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); |
