summaryrefslogtreecommitdiff
path: root/src/sms_config.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sms_config.c')
-rw-r--r--src/sms_config.c361
1 files changed, 361 insertions, 0 deletions
diff --git a/src/sms_config.c b/src/sms_config.c
new file mode 100644
index 0000000..79271a3
--- /dev/null
+++ b/src/sms_config.c
@@ -0,0 +1,361 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <termios.h>
+#include <linux/limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "global.h"
+
+#if HAVE_LIBYAML
+#include <yaml.h>
+#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_open(struct config_info *config, 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_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_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("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)) {
+ Global.core.device = strdup(value);
+ } else if (!strcmp("msg-store-read", key)) {
+ Global.core.msg_store_read = strdup(value);
+ } else if (!strcmp("msg-store-send", key)) {
+ Global.core.msg_store_send = strdup(value);
+ } else if (!strcmp("msg-store-new", key)) {
+ Global.core.msg_store_new = strdup(value);
+ } else if (!strcmp("pb-store", key)) {
+ Global.core.pb_store = strdup(value);
+ } else if (!strcmp("editor", key)) {
+ Global.core.editor = strdup(value);
+ } else if (!strcmp("edit-file", key)) {
+ 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)) {
+ Global.smtp.server = strdup(value);
+ } else if (!strcmp("port", key)) {
+ Global.smtp.port = atoi(value);
+ } else if (!strcmp("user", key)) {
+ Global.smtp.user = strdup(value);
+ } else if (!strcmp("passwd", key)) {
+ Global.smtp.passwd = strdup(value);
+ } else if (!strcmp("encryption", key)) {
+ 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)) {
+ 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)) {
+ Global.user.name = strdup(value);
+ } else if (!strcmp("email", key)) {
+ 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;
+ }
+}
+
+#define SMS_CONFIG_FILE ".smsconfig"
+static int _sms_config_load(void)
+{
+ int err;
+ struct config_info config;
+ struct stat sbuf;
+
+ err = stat(SMS_CONFIG_FILE, &sbuf);
+ if (err < 0) {
+ if (errno == ENOENT) {
+ log_notice("sms config file missing");
+ return 0;
+ }
+
+ return -1;
+ }
+
+ err = config_open(&config, SMS_CONFIG_FILE);
+ 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;
+}
+
+int sms_config_load(void)
+{
+ int err;
+ char *cp;
+ char prev[PATH_MAX];
+ char *home;
+
+ 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();
+
+ chdir(prev);
+
+ return err;
+}
+#else
+int sms_config_load(void)
+{
+ return 0;
+}
+#endif