#include #include #include #include #include #include #include #include #include #include "global.h" #if HAVE_LIBYAML #include #endif #include "atcmd.h" #include "utils.h" #include "log.h" #if HAVE_LIBYAML struct config_info { yaml_parser_t parser; char *filename; FILE *file; yaml_event_t event; int map_level; char *section; char *key; char *value; int complete; }; static int boolean_value(const char *str) { return !strcmp(str, "true") ? true : false; } static int config_close(struct config_info *config) { yaml_parser_delete(&config->parser); fclose(config->file); free(config->filename); free(config->section); free(config->key); free(config->value); return 0; } static int config_open(struct config_info *config, const char *filename) { int err; memset(config, 0, sizeof(*config)); config->filename = strdup(filename); if (!config->filename) { log_error("out of memory"); } config->file = fopen(config->filename, "r"); if (!config->file) { log_error("open config %s: %m", config->filename); return -1; } err = yaml_parser_initialize(&config->parser); if (!err) { log_error("yaml_parser_initialize"); fclose(config->file); return -1; } yaml_parser_set_input_file(&config->parser, config->file); config->complete = false; return 0; } static int config_next_event(struct config_info *config) { int err; err = yaml_parser_parse(&config->parser, &config->event); if (!err) { log_error("yaml parse error"); return -1; } return 0; } static void config_delete_event(struct config_info *config) { yaml_event_delete(&config->event); } static int config_set_core_value(const char *key, const char *value) { log_debug("try setting core.%s to %s", key, value); if (!strcmp("verbose", key)) { Global.core.verbose = boolean_value(value); } else if (!strcmp("interactive", key)) { Global.core.interactive = boolean_value(value); } else if (!strcmp("sms-init", key)) { Global.core.sms_init = boolean_value(value); } else if (!strcmp("baud-rate", key)) { Global.core.baud_rate = atoi(value); Global.core.baud_rate = value_to_baud(Global.core.baud_rate); } else if (!strcmp("read-timeout", key)) { Global.core.read_timeout = atoi(value); } else if (!strcmp("device", key)) { free(Global.core.device); Global.core.device = strdup(value); } else if (!strcmp("msg-store-read", key)) { free(Global.core.msg_store_read); Global.core.msg_store_read = strdup(value); } else if (!strcmp("msg-store-send", key)) { free(Global.core.msg_store_send); Global.core.msg_store_send = strdup(value); } else if (!strcmp("msg-store-new", key)) { free(Global.core.msg_store_new); Global.core.msg_store_new = strdup(value); } else if (!strcmp("pb-store", key)) { free(Global.core.pb_store); Global.core.pb_store = strdup(value); } else if (!strcmp("editor", key)) { free(Global.core.editor); Global.core.editor = strdup(value); } else if (!strcmp("edit-file", key)) { free(Global.core.edit_file); Global.core.edit_file = strdup(value); } return 0; } static int config_set_smtp_value(const char *key, const char *value) { log_debug("try setting smtp.%s to '%s'", key, value); if (!strcmp("server", key)) { free(Global.smtp.server); Global.smtp.server = strdup(value); } else if (!strcmp("port", key)) { Global.smtp.port = atoi(value); } else if (!strcmp("user", key)) { free(Global.smtp.user); Global.smtp.user = strdup(value); } else if (!strcmp("passwd", key)) { free(Global.smtp.passwd); Global.smtp.passwd = strdup(value); } else if (!strcmp("encryption", key)) { free(Global.smtp.encryption); Global.smtp.encryption = strdup(value); } return 0; } static int config_set_send_email_value(const char *key, const char *value) { log_debug("try setting send-email.%s to %s", key, value); if (!strcmp("domain", key)) { free(Global.send_email.domain); Global.send_email.domain = strdup(value); } return 0; } static int config_set_user_value(const char *key, const char *value) { log_debug("try setting user.%s to %s", key, value); if (!strcmp("name", key)) { free(Global.user.name); Global.user.name = strdup(value); } else if (!strcmp("email", key)) { free(Global.user.email); Global.user.email = strdup(value); } return 0; } static int config_handle_event(struct config_info *config) { switch (config->event.type) { case YAML_STREAM_START_EVENT: return 0; case YAML_STREAM_END_EVENT: return 0; case YAML_DOCUMENT_START_EVENT: return 0; case YAML_DOCUMENT_END_EVENT: config->complete = true; return 0; case YAML_SCALAR_EVENT: if (config->map_level == 1) { config->section = strdup((char *) config->event.data.scalar.value); if (!config->section) { log_error("out of memory"); return -1; } log_debug("section: %s", config->section); return 0; } else if (config->map_level != 2) { log_debug("bad map level: %d", config->map_level); return -1; } if (!config->key) { config->key = strdup((char *) config->event.data.scalar.value); if (!config->key) { log_error("out of memory"); return -1; } return 0; } else if (!config->value) { config->value = strdup((char *) config->event.data.scalar.value); if (!config->value) { log_error("out of memory"); return -1; } } if (config->key && config->value) { if (!strcmp(config->section, "core")) { config_set_core_value(config->key, config->value); } else if (!strcmp(config->section, "smtp")) { config_set_smtp_value(config->key, config->value); } else if (!strcmp(config->section, "send-email")) { config_set_send_email_value(config->key, config->value); } else if (!strcmp(config->section, "user")) { config_set_user_value(config->key, config->value); } free(config->key); config->key = NULL; free(config->value); config->value = NULL; } return 0; case YAML_MAPPING_START_EVENT: config->map_level++; return 0; case YAML_MAPPING_END_EVENT: free(config->section); config->section = NULL; free(config->key); config->key = NULL; free(config->value); config->value = NULL; config->map_level--; return 0; default: log_error("event type: %d", config->event.type); return -1; } } static int _sms_config_load(const char *filename) { int err; struct config_info config; struct stat sbuf; err = stat(filename, &sbuf); if (err < 0) { if (errno == ENOENT) { log_debug("sms config file missing"); return 0; } return -1; } err = config_open(&config, filename); if (err < 0) { log_error("open config failed"); return -1; } while (1) { err = config_next_event(&config); if (err < 0) { log_error("handle event failed"); break; } err = config_handle_event(&config); if (err < 0) { log_error("handle event failed"); config_delete_event(&config); break; } config_delete_event(&config); if (config.complete) { break; } } int complete = config.complete; err = config_close(&config); if (err < 0) { log_error("close config failed"); return -1; } if (!complete) { log_error("config load did not complete"); return -1; } log_debug("config loaded"); return 0; } #define SMS_CONFIG_FILE ".smsconfig" int sms_config_load(void) { int err; char *cp; char prev[PATH_MAX]; char *home; char *config; config = getenv("SMS_CONFIG"); if (config) { return _sms_config_load(config); } home = getenv("HOME"); if (!home) { log_error("HOME is not set"); return -1; } cp = getcwd(prev, sizeof(prev)); if (!cp) { log_error("getcwd %m"); return -1; } chdir(home); err = _sms_config_load(SMS_CONFIG_FILE); chdir(prev); return err; } #else int sms_config_load(void) { return 0; } #endif