#include "commands.h" #include "music.h" #include "transcode.h" #include "decoder.h" #include "encoder.h" #include #include #include static void send_404(GSocketConnection *connection) { GError *error = NULL; GString *string = g_string_new(NULL); g_string_append(string, "HTTP/1.1 404 Not Found\r\n"); g_string_append(string, "\r\n"); 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) { g_warning(error->message); g_error_free(error); } } static void commands_list(GSocketConnection *connection, const gchar *cmd) { GError *error = NULL; gchar **data = g_strsplit(cmd, " ", 2); for(gint i = 0; data[i]; i++) { g_debug("\tdata[%d] = %s", i, data[i]); } g_assert(data[0] != NULL && data[1] != NULL); gchar *dirname = g_strdup(data[1]); g_strfreev(data); struct directory *directory = music_find_dir(dirname); if(directory == NULL) { g_warning("couldn't find directory %s", dirname); send_404(connection); return; } GString *list_string = g_string_new(NULL); 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(list_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(list_string, "%s\n", f->name); } GString *string = g_string_new(NULL); g_string_append(string, "HTTP/1.1 200 OK\r\n"); g_string_append(string, "content-type: text/plain\r\n"); g_string_append_printf(string, "content-length: %lu\r\n", list_string->len); g_string_append(string, "\r\n"); g_string_append(string, list_string->str); g_string_free(list_string, TRUE); 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) { g_warning(error->message); g_error_free(error); } g_string_free(string, TRUE); } static void commands_get_raw(GSocketConnection *connection, const gchar *cmd) { GError *error = NULL; gchar **data = g_strsplit(cmd, " ", 2); g_assert(data[0] != NULL && data[1] != NULL); gchar *path = g_strdup(data[1]); g_strfreev(data); struct file *f = music_find_file(path); if(f == NULL) { g_warning("couldn't find %s", path); send_404(connection); goto commands_get_raw_free_path; } GOutputStream *os = g_io_stream_get_output_stream((GIOStream*)connection); gchar *full_path = music_get_full_path(path); GFile *file = g_file_new_for_path(full_path); g_free(full_path); GFileInputStream *is = g_file_read(file, NULL, &error); if(is == NULL) { g_warning(error->message); g_error_free(error); goto commands_get_raw_file_unref; } GFileInfo *fi = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, NULL, &error); if(fi == NULL) { g_warning(error->message); g_error_free(error); goto commands_get_raw_file_unref; } goffset filesize = g_file_info_get_size(fi); g_object_unref(fi); GString *string = g_string_new(NULL); g_string_append(string, "HTTP/1.1 200 OK\r\n"); g_string_append(string, "content-type: application/octet-stream\r\n"); g_string_append_printf(string, "content-length: %lu\r\n", filesize); g_string_append(string, "\r\n"); if(g_output_stream_write_all(os, string->str, string->len, NULL, NULL, &error) == FALSE) { g_warning(error->message); g_error_free(error); g_string_free(string, TRUE); goto commands_get_raw_file_unref; } g_string_free(string, TRUE); gssize size = g_output_stream_splice(os, (GInputStream*)is, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE || G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, &error); if(size == -1) { g_warning(error->message); } else { g_debug("wrote %lu bytes of file data", size); } commands_get_raw_file_unref: g_object_unref(is); g_object_unref(file); commands_get_raw_free_path: g_free(path); } static void commands_get_mp3(GSocketConnection *connection, const gchar *cmd) { GError *error = NULL; gchar **data = g_strsplit(cmd, " ", 2); g_assert(data[0] != NULL && data[1] != NULL); gchar *path = g_strdup(data[1]); g_strfreev(data); struct file *f = music_find_file(path); if(f == NULL) { g_warning("couldn't find %s", path); send_404(connection); goto commands_get_mp3_free_path; } GOutputStream *os = g_io_stream_get_output_stream((GIOStream*)connection); gchar *full_path = music_get_full_path(path); GFile *file = g_file_new_for_path(full_path); g_free(full_path); GFileInputStream *is = g_file_read(file, NULL, &error); if(is == NULL) { g_warning(error->message); g_error_free(error); goto commands_get_mp3_file_unref; } GString *string = g_string_new(NULL); g_string_append(string, "HTTP/1.1 200 OK\r\n"); g_string_append(string, "content-type: application/octet-stream\r\n"); g_string_append(string, "\r\n"); if(g_output_stream_write_all(os, string->str, string->len, NULL, NULL, &error) == FALSE) { g_warning(error->message); g_error_free(error); g_string_free(string, TRUE); goto commands_get_mp3_file_unref; } g_string_free(string, TRUE); extern const struct decoder_plugin decoder_mpg123_decoder; extern const struct encoder_plugin encoder_lame_encoder; transcode((GInputStream*)is, &decoder_mpg123_decoder, os, &encoder_lame_encoder); commands_get_mp3_file_unref: g_object_unref(is); g_object_unref(file); commands_get_mp3_free_path: g_free(path); } void commands_handle(GSocketConnection *connection, const gchar *cmd) { g_debug("handling command string %s", cmd); if(g_ascii_strncasecmp(cmd, "/list", 5) == 0) { commands_list(connection, cmd); } else if(g_ascii_strncasecmp(cmd, "/get_raw", 8) == 0) { commands_get_raw(connection, cmd); } else if(g_ascii_strncasecmp(cmd, "/get_mp3", 8) == 0) { commands_get_mp3(connection, cmd); } else { g_warning("no command handlers found"); } }