+struct fs_command_s;
+typedef struct fs_command_s fs_command_t;
+struct fs_command_s
+{
+ char *line; // "sofia status profile res-public"
+ char *instance; // "profile-sofia-res-public"
+ char *buffer; // <output from esl command as a char*>
+ size_t buffer_size; // sizeof(*buffer)
+ size_t buffer_fill; // 0 or 1
+ fs_match_t *matches;
+ fs_command_t *next;
+};
+
+static fs_command_t *fs_commands_g = NULL;
+
+static char *fs_host = NULL;
+static char *fs_port = NULL;
+static char *fs_pass = NULL;
+
+static esl_handle_t esl_handle = {{0}};
+// static int thread_running = 0; // for when subscribing to esl events
+
+/*
+ * Private functions
+ */
+
+static int fs_config_add_string (const char *name, char **dest, oconfig_item_t *ci)
+{
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("freeswitch plugin: '%s' needs exactly one string argument.", name);
+ return (-1);
+ }
+
+ sfree (*dest);
+ *dest = strdup (ci->values[0].value.string);
+ if (*dest == NULL)
+ return (-1);
+
+ return (0);
+} /* int fs_config_add_string */
+
+static void fs_match_free (fs_match_t *fm)
+{
+ if (fm == NULL)
+ return;
+
+ sfree (fm->regex);
+ sfree (fm->type);
+ sfree (fm->instance);
+ match_destroy (fm->match);
+ fs_match_free (fm->next);
+ sfree (fm);
+} /* void fs_match_free */
+
+static int fs_config_add_match_dstype (int *dstype_ret, oconfig_item_t *ci)
+{
+ int dstype;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("freeswitch plugin: 'DSType' needs exactly one string argument.");
+ return (-1);
+ }
+
+ if (strncasecmp ("Gauge", ci->values[0].value.string, strlen ("Gauge")) == 0)
+ {
+ dstype = UTILS_MATCH_DS_TYPE_GAUGE;
+ if (strcasecmp ("GaugeAverage", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_GAUGE_AVERAGE;
+ else if (strcasecmp ("GaugeMin", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_GAUGE_MIN;
+ else if (strcasecmp ("GaugeMax", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_GAUGE_MAX;
+ else if (strcasecmp ("GaugeLast", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_GAUGE_LAST;
+ else
+ dstype = 0;
+ }
+ else if (strncasecmp ("Counter", ci->values[0].value.string, strlen ("Counter")) == 0)
+ {
+ dstype = UTILS_MATCH_DS_TYPE_COUNTER;
+ if (strcasecmp ("CounterSet", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_COUNTER_SET;
+ else if (strcasecmp ("CounterAdd", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_COUNTER_ADD;
+ else if (strcasecmp ("CounterInc", ci->values[0].value.string) == 0)
+ dstype |= UTILS_MATCH_CF_COUNTER_INC;
+ else
+ dstype = 0;
+ }
+ else
+ {
+ dstype = 0;
+ }
+
+ if (dstype == 0)
+ {
+ WARNING ("freeswitch plugin: `%s' is not a valid argument to `DSType'.",
+ ci->values[0].value.string);
+ return (-1);
+ }
+
+ *dstype_ret = dstype;
+ return (0);
+} /* int fs_config_add_match_dstype */
+
+static int fs_config_add_match (fs_command_t *fs_command, oconfig_item_t *ci)
+{
+ fs_match_t *fs_match;
+ int status;
+ int i;
+
+ if (ci->values_num != 0)
+ {
+ WARNING ("freeswitch plugin: Ignoring arguments for the 'Match' block.");
+ }
+
+ fs_match = (fs_match_t *) malloc (sizeof (*fs_match));
+ if (fs_match == NULL)
+ {
+ ERROR ("freeswitch plugin: malloc failed.");
+ return (-1);
+ }
+ memset (fs_match, 0, sizeof (*fs_match));
+
+ status = 0;
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Regex", child->key) == 0)
+ status = fs_config_add_string ("Regex", &fs_match->regex, child);
+ else if (strcasecmp ("DSType", child->key) == 0)
+ status = fs_config_add_match_dstype (&fs_match->dstype, child);
+ else if (strcasecmp ("Type", child->key) == 0)
+ status = fs_config_add_string ("Type", &fs_match->type, child);
+ else if (strcasecmp ("Instance", child->key) == 0)
+ status = fs_config_add_string ("Instance", &fs_match->instance, child);
+ else
+ {
+ WARNING ("freeswitch plugin: Option `%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ } /* for (i = 0; i < ci->children_num; i++) */
+
+ while (status == 0)
+ {
+ if (fs_match->regex == NULL)
+ {
+ WARNING ("freeswitch plugin: `Regex' missing in `Match' block.");
+ status = -1;
+ }
+
+ if (fs_match->type == NULL)
+ {
+ WARNING ("freeswitch plugin: `Type' missing in `Match' block.");
+ status = -1;
+ }
+
+ if (fs_match->dstype == 0)
+ {
+ WARNING ("freeswitch plugin: `DSType' missing in `Match' block.");
+ status = -1;
+ }
+
+ break;
+ } /* while (status == 0) */
+
+ if (status != 0)
+ return (status);
+
+ fs_match->match = match_create_simple (fs_match->regex, fs_match->dstype);
+ if (fs_match->match == NULL)
+ {
+ ERROR ("freeswitch plugin: tail_match_add_match_simple failed.");
+ fs_match_free (fs_match);
+ return (-1);
+ }
+ else
+ {
+ fs_match_t *prev;
+
+ prev = fs_command->matches;
+ while ((prev != NULL) && (prev->next != NULL))
+ prev = prev->next;
+
+ if (prev == NULL)
+ fs_command->matches = fs_match;
+ else
+ prev->next = fs_match;
+ }
+
+ return (0);
+} /* int fs_config_add_match */
+
+static int fs_config_add_command (oconfig_item_t *ci)
+{
+ fs_command_t *command;
+ int status;
+ int i;
+
+ if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
+ {
+ WARNING ("freeswitch plugin: 'Command' blocks need exactly one string argument.");
+ return (-1);
+ }
+
+ command = (fs_command_t *) malloc (sizeof (*command));
+ if (command == NULL)
+ {
+ ERROR ("freeswitch plugin: malloc failed.");
+ return (-1);
+ }
+ memset (command, 0, sizeof (*command));
+ command->line = NULL;
+
+ command->instance = strdup (ci->values[0].value.string);
+ if (command->instance == NULL)
+ {
+ ERROR ("freeswitch plugin: strdup failed.");
+ sfree (command);
+ return (-1);
+ }
+
+ /* Process all children */
+ status = 0;
+ for (i = 0; i < ci->children_num; i++)
+ {
+ oconfig_item_t *child = ci->children + i;
+
+ if (strcasecmp ("Match", child->key) == 0)
+ fs_config_add_match (command, child);
+ else
+ {
+ WARNING ("freeswitch plugin: Option '%s' not allowed here.", child->key);
+ status = -1;
+ }
+
+ if (status != 0)
+ break;
+ }
+
+ /* Add the new command to the linked list */
+ if (fs_commands_g == NULL)
+ fs_commands_g = command;
+ else
+ {
+ fs_command_t *prev;
+
+ prev = fs_commands_g;
+ while ((prev != NULL) && (prev->next != NULL))
+ prev = prev->next;
+ prev->next = command;
+ }
+
+ return (0);
+} /* int fs_config_add_command */
+
+static int fs_complex_config (oconfig_item_t *ci)