/* -*- Mode: C ; c-basic-offset: 4 -*- */ /* Copyright (C) 2007,2008 Nedko Arnaudov This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #if defined(HAVE_CONFIG_H) #include "config.h" #endif #include #include #include #include #include #include #include #include #include "controller_internal.h" #include "dbus.h" /* XPath expression used for engine options selection */ #define XPATH_ENGINE_OPTIONS_EXPRESSION "/jack/engine/option" /* XPath expression used for drivers selection */ #define XPATH_DRIVERS_EXPRESSION "/jack/drivers/driver" /* XPath expression used for driver options selection */ #define XPATH_DRIVER_OPTIONS_EXPRESSION "/jack/drivers/driver[@name = '%s']/option" bool jack_controller_settings_init() { /* * this initialize the library and check potential ABI mismatches * between the version it was compiled for and the actual shared * library used. */ LIBXML_TEST_VERSION; return true; } void jack_controller_settings_uninit() { } #define writer ((xmlTextWriterPtr)context) bool jack_controller_settings_write_option( void *context, const char *name, const char *content, void *dbus_call_context_ptr) { if (xmlTextWriterStartElement(writer, BAD_CAST "option") == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); return false; } if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST name) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed."); return false; } if (xmlTextWriterWriteString(writer, BAD_CAST content) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteString() failed."); return false; } if (xmlTextWriterEndElement(writer) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed."); return false; } return true; } #undef writer bool jack_controller_settings_write_engine( struct jack_controller * controller_ptr, xmlTextWriterPtr writer, void *dbus_call_context_ptr) { /* jack_info("engine settings begin"); */ /* if (xmlTextWriterWriteComment(writer, BAD_CAST "engine parameters") == -1) */ /* { */ /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */ /* return false; */ /* } */ if (xmlTextWriterStartElement(writer, BAD_CAST "engine") == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); return false; } if (!jack_controller_settings_save_engine_options(writer, controller_ptr, dbus_call_context_ptr)) { return false; } if (xmlTextWriterEndElement(writer) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed."); return false; } /* jack_info("engine settings end"); */ return true; } bool jack_controller_settings_write_driver( struct jack_controller * controller_ptr, xmlTextWriterPtr writer, jackctl_driver driver, void *dbus_call_context_ptr) { /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */ /* { */ /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */ /* return false; */ /* } */ if (xmlTextWriterStartElement(writer, BAD_CAST "driver") == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); return false; } if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_driver_get_name(driver)) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed."); return false; } if (!jack_controller_settings_save_driver_options(writer, driver, dbus_call_context_ptr)) { return false; } if (xmlTextWriterEndElement(writer) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed."); return false; } return true; } bool jack_controller_settings_write_drivers( struct jack_controller * controller_ptr, xmlTextWriterPtr writer, void *dbus_call_context_ptr) { const JSList * node_ptr; jackctl_driver driver; if (xmlTextWriterStartElement(writer, BAD_CAST "drivers") == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); return false; } node_ptr = jackctl_server_get_drivers_list(controller_ptr->server); while (node_ptr != NULL) { driver = (jackctl_driver)node_ptr->data; if (!jack_controller_settings_write_driver( controller_ptr, writer, driver, dbus_call_context_ptr)) { return false; } node_ptr = jack_slist_next(node_ptr); } if (xmlTextWriterEndElement(writer) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed."); return false; } return true; } bool jack_controller_settings_write_internal( struct jack_controller * controller_ptr, xmlTextWriterPtr writer, jackctl_internal internal, void *dbus_call_context_ptr) { /* if (xmlTextWriterWriteComment(writer, BAD_CAST "driver parameters") == -1) */ /* { */ /* jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); */ /* return false; */ /* } */ if (xmlTextWriterStartElement(writer, BAD_CAST "internal") == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); return false; } if (xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST jackctl_internal_get_name(driver)) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteAttribute() failed."); return false; } if (!jack_controller_settings_save_internal_options(writer, internal, dbus_call_context_ptr)) { return false; } if (xmlTextWriterEndElement(writer) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed."); return false; } return true; } bool jack_controller_settings_write_internals( struct jack_controller * controller_ptr, xmlTextWriterPtr writer, void *dbus_call_context_ptr) { const JSList * node_ptr; jackctl_driver internal; if (xmlTextWriterStartElement(writer, BAD_CAST "internals") == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); return false; } node_ptr = jackctl_server_get_internals_list(controller_ptr->server); while (node_ptr != NULL) { internal = (jackctl_internal)node_ptr->data; if (!jack_controller_settings_write_internal( controller_ptr, writer, internal, dbus_call_context_ptr)) { return false; } node_ptr = jack_slist_next(node_ptr); } if (xmlTextWriterEndElement(writer) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndElement() failed."); return false; } return true; } bool jack_controller_settings_save( struct jack_controller * controller_ptr, void *dbus_call_context_ptr) { xmlTextWriterPtr writer; char *filename; size_t conf_len; bool ret; time_t timestamp; char timestamp_str[28]; time(×tamp); timestamp_str[0] = ' '; ctime_r(×tamp, timestamp_str + 1); timestamp_str[25] = ' '; ret = false; conf_len = strlen(JACKDBUS_CONF); filename = malloc(g_jackdbus_dir_len + conf_len + 1); if (filename == NULL) { jack_error("Out of memory."); goto fail; } memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len); memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len); filename[g_jackdbus_dir_len + conf_len] = 0; jack_info("saving settings to \"%s\"", filename); writer = xmlNewTextWriterFilename(filename, 0); if (writer == NULL) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "Error creating the xml writer."); goto fail_free_filename; } if (xmlTextWriterSetIndent(writer, 1) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterSetIndent() failed."); goto fail_free_writter; } if (xmlTextWriterStartDocument(writer, NULL, NULL, NULL) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartDocument() failed."); goto fail_free_writter; } if (xmlTextWriterWriteComment(writer, BAD_CAST "\n" JACK_CONF_HEADER_TEXT) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); goto fail_free_writter; } if (xmlTextWriterWriteComment(writer, BAD_CAST timestamp_str) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterWriteComment() failed."); goto fail_free_writter; } if (xmlTextWriterStartElement(writer, BAD_CAST "jack") == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); goto fail_free_writter; } if (!jack_controller_settings_write_engine(controller_ptr, writer, dbus_call_context_ptr)) { goto fail_free_writter; } if (!jack_controller_settings_write_drivers(controller_ptr, writer, dbus_call_context_ptr)) { goto fail_free_writter; } if (!jack_controller_settings_write_internals(controller_ptr, writer, dbus_call_context_ptr)) { goto fail_free_writter; } if (xmlTextWriterEndElement(writer) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterStartElement() failed."); goto fail_free_writter; } if (xmlTextWriterEndDocument(writer) == -1) { jack_dbus_error(dbus_call_context_ptr, JACK_DBUS_ERROR_GENERIC, "xmlTextWriterEndDocument() failed."); goto fail_free_writter; } ret = true; fail_free_writter: xmlFreeTextWriter(writer); fail_free_filename: free(filename); fail: return ret; } void jack_controller_settings_read_engine( struct jack_controller * controller_ptr, xmlXPathContextPtr xpath_ctx_ptr) { xmlXPathObjectPtr xpath_obj_ptr; xmlBufferPtr content_buffer_ptr; int i; const char *option_name; const char *option_value; /* Evaluate xpath expression */ xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_ENGINE_OPTIONS_EXPRESSION, xpath_ctx_ptr); if (xpath_obj_ptr == NULL) { jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_ENGINE_OPTIONS_EXPRESSION); goto exit; } if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0) { jack_error("XPath \"%s\" evaluation returned no data", XPATH_ENGINE_OPTIONS_EXPRESSION); goto free_xpath_obj; } content_buffer_ptr = xmlBufferCreate(); if (content_buffer_ptr == NULL) { jack_error("xmlBufferCreate() failed."); goto free_xpath_obj; } for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++) { //jack_info("engine option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i); if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1) { jack_error("xmlNodeBufGetContent() failed."); goto next_option; } option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"); option_value = (const char *)xmlBufferContent(content_buffer_ptr); jack_controller_settings_set_engine_option(controller_ptr, option_name, option_value); next_option: xmlBufferEmpty(content_buffer_ptr); } //free_buffer: xmlBufferFree(content_buffer_ptr); free_xpath_obj: xmlXPathFreeObject(xpath_obj_ptr); exit: return; } void jack_controller_settings_read_driver( struct jack_controller * controller_ptr, xmlXPathContextPtr xpath_ctx_ptr, jackctl_driver driver) { char *xpath; size_t xpath_len; xmlXPathObjectPtr xpath_obj_ptr; xmlBufferPtr content_buffer_ptr; int i; const char *option_name; const char *option_value; const char *driver_name; driver_name = jackctl_driver_get_name(driver); jack_info("reading options for driver \"%s\"", driver_name); xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name); xpath = malloc(xpath_len); if (xpath == NULL) { jack_error("Out of memory."); goto exit; } snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, driver_name); //jack_info("xpath = \"%s\"", xpath); /* Evaluate xpath expression */ xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr); if (xpath_obj_ptr == NULL) { jack_error("Unable to evaluate XPath expression \"%s\"", xpath); goto free_xpath; } if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0) { //jack_info("XPath \"%s\" evaluation returned no data", xpath); goto free_xpath_obj; } content_buffer_ptr = xmlBufferCreate(); if (content_buffer_ptr == NULL) { jack_error("xmlBufferCreate() failed."); goto free_xpath_obj; } for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++) { //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i); if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1) { jack_error("xmlNodeBufGetContent() failed."); goto next_option; } option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"); option_value = (const char *)xmlBufferContent(content_buffer_ptr); jack_controller_settings_set_driver_option(driver, option_name, option_value); next_option: xmlBufferEmpty(content_buffer_ptr); } //free_buffer: xmlBufferFree(content_buffer_ptr); free_xpath_obj: xmlXPathFreeObject(xpath_obj_ptr); free_xpath: free(xpath); exit: return; } void jack_controller_settings_read_internal( struct jack_controller * controller_ptr, xmlXPathContextPtr xpath_ctx_ptr, jackctl_internal internal) { char *xpath; size_t xpath_len; xmlXPathObjectPtr xpath_obj_ptr; xmlBufferPtr content_buffer_ptr; int i; const char *option_name; const char *option_value; const char *internal_name; internal_name = jackctl_internal_get_name(internal); jack_info("reading options for internal \"%s\"", internal_name); xpath_len = snprintf(NULL, 0, XPATH_DRIVER_OPTIONS_EXPRESSION, internal_name); xpath = malloc(xpath_len); if (xpath == NULL) { jack_error("Out of memory."); goto exit; } snprintf(xpath, xpath_len, XPATH_DRIVER_OPTIONS_EXPRESSION, internal_name); //jack_info("xpath = \"%s\"", xpath); /* Evaluate xpath expression */ xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)xpath, xpath_ctx_ptr); if (xpath_obj_ptr == NULL) { jack_error("Unable to evaluate XPath expression \"%s\"", xpath); goto free_xpath; } if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0) { //jack_info("XPath \"%s\" evaluation returned no data", xpath); goto free_xpath_obj; } content_buffer_ptr = xmlBufferCreate(); if (content_buffer_ptr == NULL) { jack_error("xmlBufferCreate() failed."); goto free_xpath_obj; } for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++) { //jack_info("driver option \"%s\" at index %d", xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"), i); if (xmlNodeBufGetContent(content_buffer_ptr, xpath_obj_ptr->nodesetval->nodeTab[i]) == -1) { jack_error("xmlNodeBufGetContent() failed."); goto next_option; } option_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"); option_value = (const char *)xmlBufferContent(content_buffer_ptr); jack_controller_settings_set_internal_option(internal, option_name, option_value); next_option: xmlBufferEmpty(content_buffer_ptr); } //free_buffer: xmlBufferFree(content_buffer_ptr); free_xpath_obj: xmlXPathFreeObject(xpath_obj_ptr); free_xpath: free(xpath); exit: return; } void jack_controller_settings_read_drivers( struct jack_controller * controller_ptr, xmlXPathContextPtr xpath_ctx_ptr) { xmlXPathObjectPtr xpath_obj_ptr; int i; const char *driver_name; jackctl_driver driver; /* Evaluate xpath expression */ xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr); if (xpath_obj_ptr == NULL) { jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION); goto exit; } if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0) { jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION); goto free_xpath_obj; } for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++) { driver_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"); driver = jack_controller_find_driver(controller_ptr->server, driver_name); if (driver == NULL) { jack_error("ignoring settings for unknown driver \"%s\"", driver_name); } else { jack_info("setting for driver \"%s\" found", driver_name); jack_controller_settings_read_driver(controller_ptr, xpath_ctx_ptr, driver); } } free_xpath_obj: xmlXPathFreeObject(xpath_obj_ptr); exit: return; } void jack_controller_settings_read_internals( struct jack_controller * controller_ptr, xmlXPathContextPtr xpath_ctx_ptr) { xmlXPathObjectPtr xpath_obj_ptr; int i; const char *internal_name; jackctl_internal internal; /* Evaluate xpath expression */ xpath_obj_ptr = xmlXPathEvalExpression((const xmlChar *)XPATH_DRIVERS_EXPRESSION, xpath_ctx_ptr); if (xpath_obj_ptr == NULL) { jack_error("Unable to evaluate XPath expression \"%s\"", XPATH_DRIVERS_EXPRESSION); goto exit; } if (xpath_obj_ptr->nodesetval == NULL || xpath_obj_ptr->nodesetval->nodeNr == 0) { jack_error("XPath \"%s\" evaluation returned no data", XPATH_DRIVERS_EXPRESSION); goto free_xpath_obj; } for (i = 0 ; i < xpath_obj_ptr->nodesetval->nodeNr ; i++) { internal_name = (const char *)xmlGetProp(xpath_obj_ptr->nodesetval->nodeTab[i], BAD_CAST "name"); driver = jack_controller_find_internal(controller_ptr->server, driver_name); if (driver == NULL) { jack_error("ignoring settings for unknown internal \"%s\"", internal_name); } else { jack_info("setting for internal \"%s\" found", internal_name); jack_controller_settings_read_internal(controller_ptr, xpath_ctx_ptr, driver); } } free_xpath_obj: xmlXPathFreeObject(xpath_obj_ptr); exit: return; } void jack_controller_settings_load( struct jack_controller * controller_ptr) { char *filename; size_t conf_len; xmlDocPtr doc_ptr; xmlXPathContextPtr xpath_ctx_ptr; conf_len = strlen(JACKDBUS_CONF); filename = malloc(g_jackdbus_dir_len + conf_len + 1); if (filename == NULL) { jack_error("Out of memory."); goto exit; } memcpy(filename, g_jackdbus_dir, g_jackdbus_dir_len); memcpy(filename + g_jackdbus_dir_len, JACKDBUS_CONF, conf_len); filename[g_jackdbus_dir_len + conf_len] = 0; jack_info("loading settings from \"%s\"", filename); doc_ptr = xmlParseFile(filename); if (doc_ptr == NULL) { jack_error("Failed to parse \"%s\"", filename); goto free_filename; } /* Create xpath evaluation context */ xpath_ctx_ptr = xmlXPathNewContext(doc_ptr); if (xpath_ctx_ptr == NULL) { jack_error("Unable to create new XPath context"); goto free_doc; } jack_controller_settings_read_engine(controller_ptr, xpath_ctx_ptr); jack_controller_settings_read_drivers(controller_ptr, xpath_ctx_ptr); jack_controller_settings_read_internals(controller_ptr, xpath_ctx_ptr); xmlXPathFreeContext(xpath_ctx_ptr); free_doc: xmlFreeDoc(doc_ptr); free_filename: free(filename); exit: return; } void jack_controller_settings_save_auto( struct jack_controller * controller_ptr) { jack_controller_settings_save(controller_ptr, NULL); }