#include "commands.h" #include "music.h" #include "servers.h" #include "server_communication.h" #include #include GQuark commands_quark() { return g_quark_from_static_string("commands"); } static void list_local(GString *string, gchar *dirname, GError **error) { struct directory *directory = music_find_dir(dirname); if(directory == NULL) { *error = g_error_new(commands_quark(), 0, "error: couldn't find directory %s\n", dirname); return; } for(GSList *node = directory->sub; node; node = g_slist_next(node)) { struct directory *d = node->data; gchar *name = g_path_get_basename(d->path); g_string_append_printf(string, "%s\n", name); g_free(name); } for(GSList *node = directory->files; node; node = g_slist_next(node)) { struct file *f = node->data; g_string_append_printf(string, "%s\n", f->name); } } static void list_remote(GString *string, gchar *remotename, gchar *dirname, GError **error) { struct server *server = NULL; for(GSList *node = servers; node; node = g_slist_next(node)) { struct server *temp = node->data; if(g_strcasecmp(temp->name, remotename) == 0) { server = temp; break; } } if(server == NULL) { *error = g_error_new(commands_quark(), 0, "couldn't find remote host %s", remotename); return; } gchar **data = server_list(server, dirname, error); if(data == NULL) { return; } g_debug("got %d results from %s", g_strv_length(data), remotename); for(gint i = 0; i < g_strv_length(data); i++) { if(strlen(data[i]) == 0) { break; } g_string_append_printf(string, "%s:%s\n", server->host, data[i]); } g_strfreev(data); } static void commands_list(GSocketConnection *connection, const gchar *cmd, GError **error) { gboolean remote = g_strncasecmp(cmd, "listr", 5) == 0 ? TRUE : FALSE; gchar **data = g_strsplit(cmd, " ", remote == TRUE ? 3 : 2); if(remote == TRUE && data[1] == NULL) { *error = g_error_new(commands_quark(), 0, "syntax: list[r host] [directory]"); g_strfreev(data); return; } gchar *dirname, *remotename; if(remote == TRUE) { remotename = g_strdup(data[1]); dirname = g_strdup(data[2]); } else { dirname = g_strdup(data[1]); } g_strfreev(data); if(dirname == NULL) { dirname = "/"; } GString *string = g_string_new(NULL); if(remote == TRUE) { list_remote(string, remotename, dirname, error); } else { list_local(string, dirname, error); } if(*error != NULL) { g_string_free(string, TRUE); return; } GOutputStream *os = g_io_stream_get_output_stream((GIOStream*)connection); g_output_stream_write_all(os, string->str, string->len, NULL, NULL, error); g_string_free(string, TRUE); } static void commands_find(GSocketConnection *connection, const gchar *cmd, GError **error) { gchar **data = g_strsplit(cmd, " ", 3); if(g_strv_length(data) != 3) { *error = g_error_new(commands_quark(), 0, "syntax: find[l|r remotename] artist|title|album search"); return; } gboolean remote = g_strncasecmp(data[0], "findl", 5) == 0 ? FALSE : TRUE; gboolean local = g_strncasecmp(data[0], "findr", 5) == 0 ? FALSE : TRUE; GString *string = g_string_new(NULL); if(local == TRUE) { GSList *list = NULL; if(g_ascii_strcasecmp(data[1], "artist") == 0) { list = music_find_artist(data[2]); } else if(g_ascii_strcasecmp(data[1] , "title") == 0) { list = music_find_title(data[2]); } else if(g_ascii_strcasecmp(data[1], "album") == 0) { list = music_find_album(data[2]); } else { *error = g_error_new(commands_quark(), 0, "unknown search method %s", data[1]); return; } for(GSList *node = list; node; node = g_slist_next(node)) { struct file *f = node->data; gchar *relpath = g_build_filename(f->parent->path + strlen(music_root->path), f->name, NULL); g_string_append_printf(string, "%s\n", relpath); g_free(relpath); } g_slist_free(list); } if(remote == TRUE) { for(GSList *node = servers; node; node = g_slist_next(node)) { struct server *server = node->data; g_debug("fetching data from server %s", server->host); gchar **temp = server_find(server, data[1], data[2], error); if(temp == NULL) { g_warning((*error)->message); g_error_free(*error); *error = NULL; continue; } for(gint i = 0; i < g_strv_length(temp); i++) { if(strlen(temp[i]) == 0) { break; } g_string_append_printf(string, "%s:%s\n", server->host, temp[i]); } g_strfreev(temp); } } GOutputStream *os = g_io_stream_get_output_stream((GIOStream*)connection); if(g_output_stream_write_all(os, string->str, string->len, NULL, NULL, error) == FALSE) { return; } g_string_free(string, TRUE); } static void commands_ping(GSocketConnection *connection, const gchar *cmd, GError **error) { GSocket *socket = g_socket_connection_get_socket(connection); g_socket_send(socket, "pong\n", 5, NULL, error); } static void commands_exit(GSocketConnection *connection, const gchar *cmd, GError **error) { GSocket *socket = g_socket_connection_get_socket(connection); g_socket_close(socket, NULL); } static void commands_get(GSocketConnection *connection, const gchar *cmd, GError **error) { gchar **data = g_strsplit(cmd, " ", 5); if(g_strv_length(data) != 5) { g_strfreev(data); *error = g_error_new(commands_quark(), 0, "syntax: get TYPE LOCALFILE REMOTENAME REMOTEFILE"); return; } struct server *server = NULL; for(GSList *node = servers; node; node = g_slist_next(node)) { struct server *temp = node->data; if(g_strcasecmp(temp->name, data[3]) == 0) { server = temp; break; } } gchar *localfile = g_uri_unescape_string(data[2], NULL); gchar *remotefile = g_uri_unescape_string(data[4], NULL); server_get(server, data[1], localfile, remotefile, error); g_free(localfile); g_free(remotefile); g_strfreev(data); } void commands_handle(GSocketConnection *connection, const gchar *cmd, GError **error) { g_debug(cmd); if(g_strncasecmp(cmd, "ping", 4) == 0) { commands_ping(connection, cmd, error); } else if(g_strncasecmp(cmd, "list", 4) == 0) { commands_list(connection, cmd, error); } else if(g_strncasecmp(cmd, "find", 4) == 0) { commands_find(connection, cmd, error); } else if(g_strncasecmp(cmd, "exit", 4) == 0) { commands_exit(connection, cmd, error); } else if(G_IS_UNIX_CONNECTION(connection) && g_strncasecmp(cmd, "get", 3) == 0) { commands_get(connection, cmd, error); } else { g_debug("unknown command"); *error = g_error_new(commands_quark(), 0, "unknown command %s", cmd); } }