From: Leon de Rooij Date: Fri, 24 Apr 2009 13:53:07 +0000 (+0200) Subject: freeswitch plugin: Copied all esl libs in libesl and modified Makefile X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=43715831860b2c1939268c5597bf1f813d3e1fa9 freeswitch plugin: Copied all esl libs in libesl and modified Makefile --- diff --git a/src/esl.h b/src/esl.h deleted file mode 100644 index ecca1908..00000000 --- a/src/esl.h +++ /dev/null @@ -1,372 +0,0 @@ -/* - * Copyright (c) 2007, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _ESL_H_ -#define _ESL_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* defined(__cplusplus) */ - -#define esl_copy_string(_x, _y, _z) strncpy(_x, _y, _z - 1) -#define esl_set_string(_x, _y) esl_copy_string(_x, _y, sizeof(_x)) - -typedef struct esl_event_header esl_event_header_t; -typedef struct esl_event esl_event_t; - - -typedef enum { - ESL_EVENT_TYPE_PLAIN, - ESL_EVENT_TYPE_XML -} esl_event_type_t; - -#ifdef WIN32 -#define ESL_SEQ_FWHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY -#define ESL_SEQ_FRED FOREGROUND_RED | FOREGROUND_INTENSITY -#define ESL_SEQ_FMAGEN FOREGROUND_BLUE | FOREGROUND_RED -#define ESL_SEQ_FCYAN FOREGROUND_GREEN | FOREGROUND_BLUE -#define ESL_SEQ_FGREEN FOREGROUND_GREEN -#define ESL_SEQ_FYELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY -#define ESL_SEQ_DEFAULT_COLOR ESL_SEQ_FWHITE -#else -#define ESL_SEQ_ESC "\033[" -/* Ansi Control character suffixes */ -#define ESL_SEQ_HOME_CHAR 'H' -#define ESL_SEQ_HOME_CHAR_STR "H" -#define ESL_SEQ_CLEARLINE_CHAR '1' -#define ESL_SEQ_CLEARLINE_CHAR_STR "1" -#define ESL_SEQ_CLEARLINEEND_CHAR "K" -#define ESL_SEQ_CLEARSCR_CHAR0 '2' -#define ESL_SEQ_CLEARSCR_CHAR1 'J' -#define ESL_SEQ_CLEARSCR_CHAR "2J" -#define ESL_SEQ_DEFAULT_COLOR ESL_SEQ_ESC ESL_SEQ_END_COLOR /* Reset to Default fg/bg color */ -#define ESL_SEQ_AND_COLOR ";" /* To add multiple color definitions */ -#define ESL_SEQ_END_COLOR "m" /* To end color definitions */ -/* Foreground colors values */ -#define ESL_SEQ_F_BLACK "30" -#define ESL_SEQ_F_RED "31" -#define ESL_SEQ_F_GREEN "32" -#define ESL_SEQ_F_YELLOW "33" -#define ESL_SEQ_F_BLUE "34" -#define ESL_SEQ_F_MAGEN "35" -#define ESL_SEQ_F_CYAN "36" -#define ESL_SEQ_F_WHITE "37" -/* Background colors values */ -#define ESL_SEQ_B_BLACK "40" -#define ESL_SEQ_B_RED "41" -#define ESL_SEQ_B_GREEN "42" -#define ESL_SEQ_B_YELLOW "43" -#define ESL_SEQ_B_BLUE "44" -#define ESL_SEQ_B_MAGEN "45" -#define ESL_SEQ_B_CYAN "46" -#define ESL_SEQ_B_WHITE "47" -/* Preset escape sequences - Change foreground colors only */ -#define ESL_SEQ_FBLACK ESL_SEQ_ESC ESL_SEQ_F_BLACK ESL_SEQ_END_COLOR -#define ESL_SEQ_FRED ESL_SEQ_ESC ESL_SEQ_F_RED ESL_SEQ_END_COLOR -#define ESL_SEQ_FGREEN ESL_SEQ_ESC ESL_SEQ_F_GREEN ESL_SEQ_END_COLOR -#define ESL_SEQ_FYELLOW ESL_SEQ_ESC ESL_SEQ_F_YELLOW ESL_SEQ_END_COLOR -#define ESL_SEQ_FBLUE ESL_SEQ_ESC ESL_SEQ_F_BLUE ESL_SEQ_END_COLOR -#define ESL_SEQ_FMAGEN ESL_SEQ_ESC ESL_SEQ_F_MAGEN ESL_SEQ_END_COLOR -#define ESL_SEQ_FCYAN ESL_SEQ_ESC ESL_SEQ_F_CYAN ESL_SEQ_END_COLOR -#define ESL_SEQ_FWHITE ESL_SEQ_ESC ESL_SEQ_F_WHITE ESL_SEQ_END_COLOR -#define ESL_SEQ_BBLACK ESL_SEQ_ESC ESL_SEQ_B_BLACK ESL_SEQ_END_COLOR -#define ESL_SEQ_BRED ESL_SEQ_ESC ESL_SEQ_B_RED ESL_SEQ_END_COLOR -#define ESL_SEQ_BGREEN ESL_SEQ_ESC ESL_SEQ_B_GREEN ESL_SEQ_END_COLOR -#define ESL_SEQ_BYELLOW ESL_SEQ_ESC ESL_SEQ_B_YELLOW ESL_SEQ_END_COLOR -#define ESL_SEQ_BBLUE ESL_SEQ_ESC ESL_SEQ_B_BLUE ESL_SEQ_END_COLOR -#define ESL_SEQ_BMAGEN ESL_SEQ_ESC ESL_SEQ_B_MAGEN ESL_SEQ_END_COLOR -#define ESL_SEQ_BCYAN ESL_SEQ_ESC ESL_SEQ_B_CYAN ESL_SEQ_END_COLOR -#define ESL_SEQ_BWHITE ESL_SEQ_ESC ESL_SEQ_B_WHITE ESL_SEQ_END_COLOR -/* Preset escape sequences */ -#define ESL_SEQ_HOME ESL_SEQ_ESC ESL_SEQ_HOME_CHAR_STR -#define ESL_SEQ_CLEARLINE ESL_SEQ_ESC ESL_SEQ_CLEARLINE_CHAR_STR -#define ESL_SEQ_CLEARLINEEND ESL_SEQ_ESC ESL_SEQ_CLEARLINEEND_CHAR -#define ESL_SEQ_CLEARSCR ESL_SEQ_ESC ESL_SEQ_CLEARSCR_CHAR ESL_SEQ_HOME -#endif - -#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__NetBSD__) -#define _XOPEN_SOURCE 600 -#endif - -#ifndef HAVE_STRINGS_H -#define HAVE_STRINGS_H 1 -#endif -#ifndef HAVE_SYS_SOCKET_H -#define HAVE_SYS_SOCKET_H 1 -#endif - -#ifndef __WINDOWS__ -#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) -#define __WINDOWS__ -#endif -#endif - -#ifdef _MSC_VER -#ifndef __inline__ -#define __inline__ __inline -#endif -#if (_MSC_VER >= 1400) /* VC8+ */ -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE -#endif -#ifndef _CRT_NONSTDC_NO_DEPRECATE -#define _CRT_NONSTDC_NO_DEPRECATE -#endif -#endif -#ifndef strcasecmp -#define strcasecmp(s1, s2) _stricmp(s1, s2) -#endif -#ifndef strncasecmp -#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) -#endif -#ifndef snprintf -#define snprintf _snprintf -#endif -#ifndef S_IRUSR -#define S_IRUSR _S_IREAD -#endif -#ifndef S_IWUSR -#define S_IWUSR _S_IWRITE -#endif -#undef HAVE_STRINGS_H -#undef HAVE_SYS_SOCKET_H -#endif - -#include -#ifndef WIN32 -#include -#endif - -#include -#include -#include -#include -#ifndef WIN32 -#include -#include -#include -#include -#endif - -#ifdef HAVE_STRINGS_H -#include -#endif -#include - -#if (_MSC_VER >= 1400) // VC8+ -#define esl_assert(expr) assert(expr);__analysis_assume( expr ) -#endif - -#ifndef esl_assert -#define esl_assert(_x) assert(_x) -#endif - -#define esl_safe_free(_x) if (_x) free(_x); _x = NULL -#define esl_strlen_zero(s) (!s || *(s) == '\0') -#define esl_strlen_zero_buf(s) (*(s) == '\0') - -#ifdef WIN32 -#include -#include -typedef SOCKET esl_socket_t; -typedef unsigned __int64 uint64_t; -typedef unsigned __int32 uint32_t; -typedef unsigned __int16 uint16_t; -typedef unsigned __int8 uint8_t; -typedef __int64 int64_t; -typedef __int32 int32_t; -typedef __int16 int16_t; -typedef __int8 int8_t; -typedef intptr_t esl_ssize_t; -typedef int esl_filehandle_t; -#define ESL_SOCK_INVALID INVALID_SOCKET -#define strerror_r(num, buf, size) strerror_s(buf, size, num) -#if defined(ESL_DECLARE_STATIC) -#define ESL_DECLARE(type) type __stdcall -#define ESL_DECLARE_NONSTD(type) type __cdecl -#define ESL_DECLARE_DATA -#elif defined(ESL_EXPORTS) -#define ESL_DECLARE(type) __declspec(dllexport) type __stdcall -#define ESL_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl -#define ESL_DECLARE_DATA __declspec(dllexport) -#else -#define ESL_DECLARE(type) __declspec(dllimport) type __stdcall -#define ESL_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl -#define ESL_DECLARE_DATA __declspec(dllimport) -#endif -#else -#define ESL_DECLARE(type) type -#define ESL_DECLARE_NONSTD(type) type -#define ESL_DECLARE_DATA -#include -#include -#include -#include -#include -#include -#include -#define ESL_SOCK_INVALID -1 -typedef int esl_socket_t; -typedef ssize_t esl_ssize_t; -typedef int esl_filehandle_t; -#endif - -typedef int16_t esl_port_t; - -typedef enum { - ESL_SUCCESS, - ESL_FAIL, - ESL_BREAK, - ESL_DISCONNECTED -} esl_status_t; - -#include - -typedef struct { - struct sockaddr_in sockaddr; - struct hostent hostent; - char hostbuf[256]; - esl_socket_t sock; - char err[256]; - int errnum; - char header_buf[4196]; - char last_reply[1024]; - char last_sr_reply[1024]; - esl_event_t *last_event; - esl_event_t *last_sr_event; - esl_event_t *race_event; - esl_event_t *last_ievent; - esl_event_t *info_event; - int connected; - struct sockaddr_in addr; - esl_mutex_t *mutex; - int async_execute; - int event_lock; -} esl_handle_t; - -typedef enum { - ESL_TRUE = 1, - ESL_FALSE = 0 -} esl_bool_t; - -#ifndef __FUNCTION__ -#define __FUNCTION__ (const char *)__func__ -#endif - -#define ESL_PRE __FILE__, __FUNCTION__, __LINE__ -#define ESL_LOG_LEVEL_DEBUG 7 -#define ESL_LOG_LEVEL_INFO 6 -#define ESL_LOG_LEVEL_NOTICE 5 -#define ESL_LOG_LEVEL_WARNING 4 -#define ESL_LOG_LEVEL_ERROR 3 -#define ESL_LOG_LEVEL_CRIT 2 -#define ESL_LOG_LEVEL_ALERT 1 -#define ESL_LOG_LEVEL_EMERG 0 - -#define ESL_LOG_DEBUG ESL_PRE, ESL_LOG_LEVEL_DEBUG -#define ESL_LOG_INFO ESL_PRE, ESL_LOG_LEVEL_INFO -#define ESL_LOG_NOTICE ESL_PRE, ESL_LOG_LEVEL_NOTICE -#define ESL_LOG_WARNING ESL_PRE, ESL_LOG_LEVEL_WARNING -#define ESL_LOG_ERROR ESL_PRE, ESL_LOG_LEVEL_ERROR -#define ESL_LOG_CRIT ESL_PRE, ESL_LOG_LEVEL_CRIT -#define ESL_LOG_ALERT ESL_PRE, ESL_LOG_LEVEL_ALERT -#define ESL_LOG_EMERG ESL_PRE, ESL_LOG_LEVEL_EMERG -typedef void (*esl_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...); - - -ESL_DECLARE(int) esl_vasprintf(char **ret, const char *fmt, va_list ap); - -ESL_DECLARE_DATA extern esl_logger_t esl_log; - -ESL_DECLARE(void) esl_global_set_logger(esl_logger_t logger); -ESL_DECLARE(void) esl_global_set_default_logger(int level); - -#include "esl_event.h" -#include "esl_threadmutex.h" -#include "esl_config.h" - -ESL_DECLARE(size_t) esl_url_encode(const char *url, char *buf, size_t len); -ESL_DECLARE(char *)esl_url_decode(char *s); -ESL_DECLARE(const char *)esl_stristr(const char *instr, const char *str); -ESL_DECLARE(int) esl_toupper(int c); -ESL_DECLARE(int) esl_tolower(int c); -ESL_DECLARE(int) esl_snprintf(char *buffer, size_t count, const char *fmt, ...); - - -typedef void (*esl_listen_callback_t)(esl_socket_t server_sock, esl_socket_t client_sock, struct sockaddr_in *addr); - -ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t socket, struct sockaddr_in *addr); -ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback); -ESL_DECLARE(esl_status_t) esl_execute(esl_handle_t *handle, const char *app, const char *arg, const char *uuid); -ESL_DECLARE(esl_status_t) esl_sendevent(esl_handle_t *handle, esl_event_t *event); - -ESL_DECLARE(esl_status_t) esl_connect(esl_handle_t *handle, const char *host, esl_port_t port, const char *password); -ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle); -ESL_DECLARE(esl_status_t) esl_send(esl_handle_t *handle, const char *cmd); -ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event); -ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, int check_q, esl_event_t **save_event); -ESL_DECLARE(esl_status_t) esl_send_recv(esl_handle_t *handle, const char *cmd); -ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value); -ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etype, const char *value); - -#define esl_recv(_h) esl_recv_event(_h, 0, NULL) -#define esl_recv_timed(_h, _ms) esl_recv_event_timed(_h, _ms, 0, NULL) - -static __inline__ int esl_safe_strcasecmp(const char *s1, const char *s2) -{ - if (!(s1 && s2)) { - return 1; - } - - return strcasecmp(s1, s2); -} - -#ifdef __cplusplus -} -#endif /* defined(__cplusplus) */ - - -#endif /* defined(_ESL_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: - */ diff --git a/src/esl_config.h b/src/esl_config.h deleted file mode 100644 index 6763cdb7..00000000 --- a/src/esl_config.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright (c) 2007, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @defgroup config Config File Parser - * @ingroup config - * This module implements a basic interface and file format parser - * - *
- *
- * EXAMPLE 
- * 
- * [category1]
- * var1 => val1
- * var2 => val2
- * \# lines that begin with \# are comments
- * \#var3 => val3
- * 
- * @{ - */ - -#ifndef ESL_CONFIG_H -#define ESL_CONFIG_H - -#include "esl.h" - -#ifdef __cplusplus -extern "C" { -#endif /* defined(__cplusplus) */ - - -#define ESL_URL_SEPARATOR "://" - - -#ifdef WIN32 -#define ESL_PATH_SEPARATOR "\\" -#ifndef ESL_CONFIG_DIR -#define ESL_CONFIG_DIR "c:\\openesl" -#endif -#define esl_is_file_path(file) (*(file +1) == ':' || *file == '/' || strstr(file, SWITCH_URL_SEPARATOR)) -#else -#define ESL_PATH_SEPARATOR "/" -#ifndef ESL_CONFIG_DIR -#define ESL_CONFIG_DIR "/etc/openesl" -#endif -#define esl_is_file_path(file) ((*file == '/') || strstr(file, SWITCH_URL_SEPARATOR)) -#endif - -/*! - \brief Evaluate the truthfullness of a string expression - \param expr a string expression - \return true or false -*/ -#define esl_true(expr)\ -(expr && ( !strcasecmp(expr, "yes") ||\ -!strcasecmp(expr, "on") ||\ -!strcasecmp(expr, "true") ||\ -!strcasecmp(expr, "enabled") ||\ -!strcasecmp(expr, "active") ||\ -!strcasecmp(expr, "allow") ||\ -atoi(expr))) ? 1 : 0 - -/*! - \brief Evaluate the falsefullness of a string expression - \param expr a string expression - \return true or false -*/ -#define esl_false(expr)\ -(expr && ( !strcasecmp(expr, "no") ||\ -!strcasecmp(expr, "off") ||\ -!strcasecmp(expr, "false") ||\ -!strcasecmp(expr, "disabled") ||\ -!strcasecmp(expr, "inactive") ||\ -!strcasecmp(expr, "disallow") ||\ -!atoi(expr))) ? 1 : 0 - -typedef struct esl_config esl_config_t; - -/*! \brief A simple file handle representing an open configuration file **/ -struct esl_config { - /*! FILE stream buffer to the opened file */ - FILE *file; - /*! path to the file */ - char path[512]; - /*! current category */ - char category[256]; - /*! current section */ - char section[256]; - /*! buffer of current line being read */ - char buf[1024]; - /*! current line number in file */ - int lineno; - /*! current category number in file */ - int catno; - /*! current section number in file */ - int sectno; - - int lockto; -}; - -/*! - \brief Open a configuration file - \param cfg (esl_config_t *) config handle to use - \param file_path path to the file - \return 1 (true) on success 0 (false) on failure -*/ -ESL_DECLARE(int) esl_config_open_file(esl_config_t * cfg, const char *file_path); - -/*! - \brief Close a previously opened configuration file - \param cfg (esl_config_t *) config handle to use -*/ -ESL_DECLARE(void) esl_config_close_file(esl_config_t * cfg); - -/*! - \brief Retrieve next name/value pair from configuration file - \param cfg (esl_config_t *) config handle to use - \param var pointer to aim at the new variable name - \param val pointer to aim at the new value -*/ -ESL_DECLARE(int) esl_config_next_pair(esl_config_t * cfg, char **var, char **val); - -/*! - \brief Retrieve the CAS bits from a configuration string value - \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx) - \param outbits pointer to aim at the CAS bits -*/ -ESL_DECLARE(int) esl_config_get_cas_bits(char *strvalue, unsigned char *outbits); - - -/** @} */ - -#ifdef __cplusplus -} -#endif /* defined(__cplusplus) */ - -#endif /* defined(ESL_CONFIG_H) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: - */ diff --git a/src/esl_event.h b/src/esl_event.h deleted file mode 100644 index d9e7a3e4..00000000 --- a/src/esl_event.h +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (c) 2007, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef ESL_EVENT_H -#define ESL_EVENT_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif /* defined(__cplusplus) */ - -typedef enum { - ESL_STACK_BOTTOM, - ESL_STACK_TOP -} esl_stack_t; - -typedef enum { - ESL_EVENT_CUSTOM, - ESL_EVENT_CLONE, - ESL_EVENT_CHANNEL_CREATE, - ESL_EVENT_CHANNEL_DESTROY, - ESL_EVENT_CHANNEL_STATE, - ESL_EVENT_CHANNEL_ANSWER, - ESL_EVENT_CHANNEL_HANGUP, - ESL_EVENT_CHANNEL_EXECUTE, - ESL_EVENT_CHANNEL_EXECUTE_COMPLETE, - ESL_EVENT_CHANNEL_BRIDGE, - ESL_EVENT_CHANNEL_UNBRIDGE, - ESL_EVENT_CHANNEL_PROGRESS, - ESL_EVENT_CHANNEL_PROGRESS_MEDIA, - ESL_EVENT_CHANNEL_OUTGOING, - ESL_EVENT_CHANNEL_PARK, - ESL_EVENT_CHANNEL_UNPARK, - ESL_EVENT_CHANNEL_APPLICATION, - ESL_EVENT_CHANNEL_ORIGINATE, - ESL_EVENT_CHANNEL_UUID, - ESL_EVENT_API, - ESL_EVENT_LOG, - ESL_EVENT_INBOUND_CHAN, - ESL_EVENT_OUTBOUND_CHAN, - ESL_EVENT_STARTUP, - ESL_EVENT_SHUTDOWN, - ESL_EVENT_PUBLISH, - ESL_EVENT_UNPUBLISH, - ESL_EVENT_TALK, - ESL_EVENT_NOTALK, - ESL_EVENT_SESSION_CRASH, - ESL_EVENT_MODULE_LOAD, - ESL_EVENT_MODULE_UNLOAD, - ESL_EVENT_DTMF, - ESL_EVENT_MESSAGE, - ESL_EVENT_PRESENCE_IN, - ESL_EVENT_NOTIFY_IN, - ESL_EVENT_PRESENCE_OUT, - ESL_EVENT_PRESENCE_PROBE, - ESL_EVENT_MESSAGE_WAITING, - ESL_EVENT_MESSAGE_QUERY, - ESL_EVENT_ROSTER, - ESL_EVENT_CODEC, - ESL_EVENT_BACKGROUND_JOB, - ESL_EVENT_DETECTED_SPEECH, - ESL_EVENT_DETECTED_TONE, - ESL_EVENT_PRIVATE_COMMAND, - ESL_EVENT_HEARTBEAT, - ESL_EVENT_TRAP, - ESL_EVENT_ADD_SCHEDULE, - ESL_EVENT_DEL_SCHEDULE, - ESL_EVENT_EXE_SCHEDULE, - ESL_EVENT_RE_SCHEDULE, - ESL_EVENT_RELOADXML, - ESL_EVENT_NOTIFY, - ESL_EVENT_SEND_MESSAGE, - ESL_EVENT_RECV_MESSAGE, - ESL_EVENT_REQUEST_PARAMS, - ESL_EVENT_CHANNEL_DATA, - ESL_EVENT_GENERAL, - ESL_EVENT_COMMAND, - ESL_EVENT_SESSION_HEARTBEAT, - ESL_EVENT_CLIENT_DISCONNECTED, - ESL_EVENT_SERVER_DISCONNECTED, - ESL_EVENT_ALL -} esl_event_types_t; - -typedef enum { - ESL_PRIORITY_NORMAL, - ESL_PRIORITY_LOW, - ESL_PRIORITY_HIGH -} esl_priority_t; - -/*! \brief An event Header */ - struct esl_event_header { - /*! the header name */ - char *name; - /*! the header value */ - char *value; - /*! hash of the header name */ - unsigned long hash; - struct esl_event_header *next; -}; - - -/*! \brief Representation of an event */ -struct esl_event { - /*! the event id (descriptor) */ - esl_event_types_t event_id; - /*! the priority of the event */ - esl_priority_t priority; - /*! the owner of the event */ - char *owner; - /*! the subclass of the event */ - char *subclass_name; - /*! the event headers */ - esl_event_header_t *headers; - /*! the event headers tail pointer */ - esl_event_header_t *last_header; - /*! the body of the event */ - char *body; - /*! user data from the subclass provider */ - void *bind_user_data; - /*! user data from the event sender */ - void *event_user_data; - /*! unique key */ - unsigned long key; - struct esl_event *next; -}; - - - -#define ESL_EVENT_SUBCLASS_ANY NULL - -/*! - \brief Create an event - \param event a NULL pointer on which to create the event - \param event_id the event id enumeration of the desired event - \param subclass_name the subclass name for custom event (only valid when event_id is ESL_EVENT_CUSTOM) - \return ESL_STATUS_SUCCESS on success -*/ -ESL_DECLARE(esl_status_t) esl_event_create_subclass(esl_event_t **event, esl_event_types_t event_id, const char *subclass_name); - -/*! - \brief Set the priority of an event - \param event the event to set the priority on - \param priority the event priority - \return ESL_STATUS_SUCCESS -*/ -ESL_DECLARE(esl_status_t) esl_event_set_priority(esl_event_t *event, esl_priority_t priority); - -/*! - \brief Retrieve a header value from an event - \param event the event to read the header from - \param header_name the name of the header to read - \return the value of the requested header -*/ -ESL_DECLARE(char *)esl_event_get_header(esl_event_t *event, const char *header_name); - -/*! - \brief Retrieve the body value from an event - \param event the event to read the body from - \return the value of the body or NULL -*/ -ESL_DECLARE(char *)esl_event_get_body(esl_event_t *event); - -/*! - \brief Add a header to an event - \param event the event to add the header to - \param stack the stack sense (stack it on the top or on the bottom) - \param header_name the name of the header to add - \param fmt the value of the header (varargs see standard sprintf family) - \return ESL_STATUS_SUCCESS if the header was added -*/ -ESL_DECLARE(esl_status_t) esl_event_add_header(esl_event_t *event, esl_stack_t stack, - const char *header_name, const char *fmt, ...); //PRINTF_FUNCTION(4, 5); - -/*! - \brief Add a string header to an event - \param event the event to add the header to - \param stack the stack sense (stack it on the top or on the bottom) - \param header_name the name of the header to add - \param data the value of the header - \return ESL_STATUS_SUCCESS if the header was added -*/ -ESL_DECLARE(esl_status_t) esl_event_add_header_string(esl_event_t *event, esl_stack_t stack, const char *header_name, const char *data); - -ESL_DECLARE(esl_status_t) esl_event_del_header(esl_event_t *event, const char *header_name); - -/*! - \brief Destroy an event - \param event pointer to the pointer to event to destroy -*/ -ESL_DECLARE(void) esl_event_destroy(esl_event_t **event); -#define esl_event_safe_destroy(_event) if (_event) esl_event_destroy(_event) - -/*! - \brief Duplicate an event - \param event a NULL pointer on which to duplicate the event - \param todup an event to duplicate - \return ESL_STATUS_SUCCESS if the event was duplicated -*/ -ESL_DECLARE(esl_status_t) esl_event_dup(esl_event_t **event, esl_event_t *todup); - -/*! - \brief Render the name of an event id enumeration - \param event the event id to render the name of - \return the rendered name -*/ -ESL_DECLARE(const char *)esl_event_name(esl_event_types_t event); - -/*! - \brief return the event id that matches a given event name - \param name the name of the event - \param type the event id to return - \return ESL_STATUS_SUCCESS if there was a match -*/ -ESL_DECLARE(esl_status_t) esl_name_event(const char *name, esl_event_types_t *type); - -/*! - \brief Render a string representation of an event sutable for printing or network transport - \param event the event to render - \param str a string pointer to point at the allocated data - \param encode url encode the headers - \return ESL_STATUS_SUCCESS if the operation was successful - \note you must free the resulting string when you are finished with it -*/ -ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, esl_bool_t encode); - -/*! - \brief Add a body to an event - \param event the event to add to body to - \param fmt optional body of the event (varargs see standard sprintf family) - \return ESL_STATUS_SUCCESS if the body was added to the event - \note the body parameter can be shadowed by the esl_event_reserve_subclass_detailed function -*/ -ESL_DECLARE(esl_status_t) esl_event_add_body(esl_event_t *event, const char *fmt, ...); - -/*! - \brief Create a new event assuming it will not be custom event and therefore hiding the unused parameters - \param event a NULL pointer on which to create the event - \param id the event id enumeration of the desired event - \return ESL_STATUS_SUCCESS on success -*/ -#define esl_event_create(event, id) esl_event_create_subclass(event, id, ESL_EVENT_SUBCLASS_ANY) - -ESL_DECLARE(const char *)esl_priority_name(esl_priority_t priority); - -///\} - -#ifdef __cplusplus -} -#endif /* defined(__cplusplus) */ - -#endif /* defined(ESL_EVENT_H) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4: - */ diff --git a/src/esl_oop.h b/src/esl_oop.h deleted file mode 100644 index 840b0ef9..00000000 --- a/src/esl_oop.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2007, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * * Neither the name of the original author; nor the names of any contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _ESL_OOP_H_ -#define _ESL_OOP_H_ -#include -#ifdef __cplusplus -extern "C" { -#endif - -#define this_check(x) do { if (!this) { esl_log(ESL_LOG_ERROR, "object is not initalized\n"); return x;}} while(0) -#define this_check_void() do { if (!this) { esl_log(ESL_LOG_ERROR, "object is not initalized\n"); return;}} while(0) - - -class ESLevent { - private: - esl_event_header_t *hp; - public: - esl_event_t *event; - char *serialized_string; - int mine; - - ESLevent(const char *type, const char *subclass_name = NULL); - ESLevent(esl_event_t *wrap_me, int free_me = 0); - ESLevent(ESLevent *me); - virtual ~ESLevent(); - const char *serialize(const char *format = NULL); - bool setPriority(esl_priority_t priority = ESL_PRIORITY_NORMAL); - const char *getHeader(const char *header_name); - char *getBody(void); - const char *getType(void); - bool addBody(const char *value); - bool addHeader(const char *header_name, const char *value); - bool delHeader(const char *header_name); - const char *firstHeader(void); - const char *nextHeader(void); -}; - - - -class ESLconnection { - private: - esl_handle_t handle; - ESLevent *last_event_obj; - public: - ESLconnection(const char *host, const char *port, const char *password); - ESLconnection(int socket); - virtual ~ESLconnection(); - int connected(); - ESLevent *getInfo(); - int send(const char *cmd); - ESLevent *sendRecv(const char *cmd); - ESLevent *api(const char *cmd, const char *arg = NULL); - ESLevent *bgapi(const char *cmd, const char *arg = NULL); - int sendEvent(ESLevent *send_me); - ESLevent *recvEvent(); - ESLevent *recvEventTimed(int ms); - ESLevent *filter(const char *header, const char *value); - int events(const char *etype, const char *value); - int execute(const char *app, const char *arg = NULL, const char *uuid = NULL); - int executeAsync(const char *app, const char *arg = NULL, const char *uuid = NULL); - int setAsyncExecute(const char *val); - int setEventLock(const char *val); - int disconnect(void); -}; - -void eslSetLogLevel(int level); - - - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/esl_threadmutex.h b/src/esl_threadmutex.h deleted file mode 100644 index e8373ef0..00000000 --- a/src/esl_threadmutex.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Cross Platform Thread/Mutex abstraction - * Copyright(C) 2007 Michael Jerris - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so. - * - * This work is provided under this license on an "as is" basis, without warranty of any kind, - * either expressed or implied, including, without limitation, warranties that the covered code - * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire - * risk as to the quality and performance of the covered code is with you. Should any covered - * code prove defective in any respect, you (not the initial developer or any other contributor) - * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty - * constitutes an essential part of this license. No use of any covered code is authorized hereunder - * except under this disclaimer. - * - */ - - -#ifndef _ESL_THREADMUTEX_H -#define _ESL_THREADMUTEX_H - -#include "esl.h" - -#ifdef __cplusplus -extern "C" { -#endif /* defined(__cplusplus) */ - -typedef struct esl_mutex esl_mutex_t; -typedef struct esl_thread esl_thread_t; -typedef void *(*esl_thread_function_t) (esl_thread_t *, void *); - -ESL_DECLARE(esl_status_t) esl_thread_create_detached(esl_thread_function_t func, void *data); -esl_status_t esl_thread_create_detached_ex(esl_thread_function_t func, void *data, size_t stack_size); -void esl_thread_override_default_stacksize(size_t size); -ESL_DECLARE(esl_status_t) esl_mutex_create(esl_mutex_t **mutex); -ESL_DECLARE(esl_status_t) esl_mutex_destroy(esl_mutex_t **mutex); -ESL_DECLARE(esl_status_t) esl_mutex_lock(esl_mutex_t *mutex); -ESL_DECLARE(esl_status_t) esl_mutex_trylock(esl_mutex_t *mutex); -ESL_DECLARE(esl_status_t) esl_mutex_unlock(esl_mutex_t *mutex); - -#ifdef __cplusplus -} -#endif /* defined(__cplusplus) */ - -#endif /* defined(_ESL_THREADMUTEX_H) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: - */ diff --git a/src/libesl/esl.c b/src/libesl/esl.c new file mode 100644 index 00000000..2d2600a3 --- /dev/null +++ b/src/libesl/esl.c @@ -0,0 +1,1078 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#ifndef WIN32 +#define closesocket(x) close(x) +#endif + + +/* Written by Marc Espie, public domain */ +#define ESL_CTYPE_NUM_CHARS 256 + +const short _esl_C_toupper_[1 + ESL_CTYPE_NUM_CHARS] = { + EOF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G', + 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', + 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const short *_esl_toupper_tab_ = _esl_C_toupper_; + +ESL_DECLARE(int) esl_toupper(int c) +{ + if ((unsigned int)c > 255) + return(c); + if (c < -1) + return EOF; + return((_esl_toupper_tab_ + 1)[c]); +} + +const short _esl_C_tolower_[1 + ESL_CTYPE_NUM_CHARS] = { + EOF, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', + 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', + 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const short *_esl_tolower_tab_ = _esl_C_tolower_; + +ESL_DECLARE(int) esl_tolower(int c) +{ + if ((unsigned int)c > 255) + return(c); + if (c < -1) + return EOF; + return((_esl_tolower_tab_ + 1)[c]); +} + +ESL_DECLARE(const char *)esl_stristr(const char *instr, const char *str) +{ +/* +** Rev History: 16/07/97 Greg Thayer Optimized +** 07/04/95 Bob Stout ANSI-fy +** 02/03/94 Fred Cole Original +** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback +** +** Hereby donated to public domain. +*/ + const char *pptr, *sptr, *start; + + if (!str || !instr) + return NULL; + + for (start = str; *start; start++) { + /* find start of pattern in string */ + for (; ((*start) && (esl_toupper(*start) != esl_toupper(*instr))); start++); + + if (!*start) + return NULL; + + pptr = instr; + sptr = start; + + while (esl_toupper(*sptr) == esl_toupper(*pptr)) { + sptr++; + pptr++; + + /* if end of pattern then pattern was found */ + if (!*pptr) + return (start); + + if (!*sptr) + return NULL; + } + } + return NULL; +} + +#ifdef WIN32 +#ifndef vsnprintf +#define vsnprintf _vsnprintf +#endif +#endif + + +int vasprintf(char **ret, const char *format, va_list ap); + +ESL_DECLARE(int) esl_vasprintf(char **ret, const char *fmt, va_list ap) +{ +#if !defined(WIN32) && !defined(__sun) + return vasprintf(ret, fmt, ap); +#else + char *buf; + int len; + size_t buflen; + va_list ap2; + char *tmp = NULL; + +#ifdef _MSC_VER +#if _MSC_VER >= 1500 + /* hack for incorrect assumption in msvc header files for code analysis */ + __analysis_assume(tmp); +#endif + ap2 = ap; +#else + va_copy(ap2, ap); +#endif + + len = vsnprintf(tmp, 0, fmt, ap2); + + if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) { + len = vsnprintf(buf, buflen, fmt, ap); + *ret = buf; + } else { + *ret = NULL; + len = -1; + } + + va_end(ap2); + return len; +#endif +} + + + + +ESL_DECLARE(int) esl_snprintf(char *buffer, size_t count, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vsnprintf(buffer, count-1, fmt, ap); + if (ret < 0) + buffer[count-1] = '\0'; + va_end(ap); + return ret; +} + +static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + if (file && func && line && level && fmt) { + return; + } + return; +} + + +static const char *LEVEL_NAMES[] = { + "EMERG", + "ALERT", + "CRIT", + "ERROR", + "WARNING", + "NOTICE", + "INFO", + "DEBUG", + NULL +}; + +static int esl_log_level = 7; + +static const char *cut_path(const char *in) +{ + const char *p, *ret = in; + char delims[] = "/\\"; + char *i; + + for (i = delims; *i; i++) { + p = in; + while ((p = strchr(p, *i)) != 0) { + ret = ++p; + } + } + return ret; +} + + +static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) +{ + const char *fp; + char *data; + va_list ap; + int ret; + + if (level < 0 || level > 7) { + level = 7; + } + if (level > esl_log_level) { + return; + } + + fp = cut_path(file); + + va_start(ap, fmt); + + ret = esl_vasprintf(&data, fmt, ap); + + if (ret != -1) { + fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data); + free(data); + } + + va_end(ap); + +} + +esl_logger_t esl_log = null_logger; + +ESL_DECLARE(void) esl_global_set_logger(esl_logger_t logger) +{ + if (logger) { + esl_log = logger; + } else { + esl_log = null_logger; + } +} + +ESL_DECLARE(void) esl_global_set_default_logger(int level) +{ + if (level < 0 || level > 7) { + level = 7; + } + + esl_log = default_logger; + esl_log_level = level; +} + +ESL_DECLARE(size_t) esl_url_encode(const char *url, char *buf, size_t len) +{ + const char *p; + size_t x = 0; + const char urlunsafe[] = "\r\n \"#%&+:;<=>?@[\\]^`{|}"; + const char hex[] = "0123456789ABCDEF"; + + if (!buf) { + return 0; + } + + if (!url) { + return 0; + } + + len--; + + for (p = url; *p; p++) { + if (x >= len) { + break; + } + if (*p < ' ' || *p > '~' || strchr(urlunsafe, *p)) { + if ((x + 3) >= len) { + break; + } + buf[x++] = '%'; + buf[x++] = hex[*p >> 4]; + buf[x++] = hex[*p & 0x0f]; + } else { + buf[x++] = *p; + } + } + buf[x] = '\0'; + + return x; +} + +ESL_DECLARE(char *)esl_url_decode(char *s) +{ + char *o; + unsigned int tmp; + + for (o = s; *s; s++, o++) { + if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { + *o = (char) tmp; + s += 2; + } else { + *o = *s; + } + } + *o = '\0'; + return s; +} + +static void sock_setup(esl_handle_t *handle) +{ +#ifdef WIN32 + BOOL bOptVal = TRUE; + int bOptLen = sizeof(BOOL); + setsockopt(handle->sock, IPPROTO_TCP, TCP_NODELAY, (const char *)&bOptVal, bOptLen); +#else + int x = 1; + setsockopt(handle->sock, IPPROTO_TCP, TCP_NODELAY, &x, sizeof(x)); +#endif +} + +ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t socket, struct sockaddr_in *addr) +{ + handle->sock = socket; + if (addr) { + handle->addr = *addr; + } + + if (handle->sock == ESL_SOCK_INVALID) { + return ESL_FAIL; + } + + + if (!handle->mutex) { + esl_mutex_create(&handle->mutex); + } + + handle->connected = 1; + + sock_setup(handle); + + esl_send_recv(handle, "connect\n\n"); + + + if (handle->last_sr_event) { + handle->info_event = handle->last_sr_event; + handle->last_sr_event = NULL; + return ESL_SUCCESS; + } + + handle->connected = 0; + + return ESL_FAIL; +} + +ESL_DECLARE(esl_status_t) esl_sendevent(esl_handle_t *handle, esl_event_t *event) +{ + char *txt; + char event_buf[256] = ""; + + if (!handle->connected || !event) { + return ESL_FAIL; + } + + esl_event_serialize(event, &txt, ESL_FALSE); + + esl_log(ESL_LOG_DEBUG, "SEND EVENT\n%s\n", txt); + + snprintf(event_buf, sizeof(event_buf), "sendevent %s\n", esl_event_name(event->event_id)); + + send(handle->sock, event_buf, strlen(event_buf), 0); + send(handle->sock, txt, strlen(txt), 0); + send(handle->sock, "\n\n", 2, 0); + + free(txt); + + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_execute(esl_handle_t *handle, const char *app, const char *arg, const char *uuid) +{ + char cmd_buf[128] = "sendmsg"; + char app_buf[512] = ""; + char arg_buf[512] = ""; + const char *el_buf = "event-lock: true\n"; + const char *bl_buf = "async: true\n"; + char send_buf[1292] = ""; + + if (!handle->connected) { + return ESL_FAIL; + } + + if (uuid) { + snprintf(cmd_buf, sizeof(cmd_buf), "sendmsg %s", uuid); + } + + if (app) { + snprintf(app_buf, sizeof(app_buf), "execute-app-name: %s\n", app); + } + + if (arg) { + snprintf(arg_buf, sizeof(arg_buf), "execute-app-arg: %s\n", arg); + } + + snprintf(send_buf, sizeof(send_buf), "%s\ncall-command: execute\n%s%s%s%s\n", + cmd_buf, app_buf, arg_buf, handle->event_lock ? el_buf : "", handle->async_execute ? bl_buf : ""); + + return esl_send_recv(handle, send_buf); +} + + +ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value) +{ + char send_buf[1024] = ""; + + if (!handle->connected) { + return ESL_FAIL; + } + + snprintf(send_buf, sizeof(send_buf), "filter %s %s\n\n", header, value); + + return esl_send_recv(handle, send_buf); +} + + +ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etype, const char *value) +{ + char send_buf[1024] = ""; + const char *type = "plain"; + + if (!handle->connected) { + return ESL_FAIL; + } + + if (etype == ESL_EVENT_TYPE_XML) { + type = "xml"; + } + + snprintf(send_buf, sizeof(send_buf), "event %s %s\n\n", type, value); + + return esl_send_recv(handle, send_buf); +} + +static int esl_socket_reuseaddr(esl_socket_t socket) +{ +#ifdef WIN32 + BOOL reuse_addr = TRUE; + return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse_addr, sizeof(reuse_addr)); +#else + int reuse_addr = 1; + return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); +#endif +} + +ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback) +{ + esl_socket_t server_sock = ESL_SOCK_INVALID; + struct sockaddr_in addr; + esl_status_t status = ESL_SUCCESS; + + if ((server_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + return ESL_FAIL; + } + + esl_socket_reuseaddr(server_sock); + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(INADDR_ANY); + addr.sin_port = htons(port); + + if (bind(server_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { + status = ESL_FAIL; + goto end; + } + + if (listen(server_sock, 10000) < 0) { + status = ESL_FAIL; + goto end; + } + + for (;;) { + int client_sock; + struct sockaddr_in echoClntAddr; +#ifdef WIN32 + int clntLen; +#else + unsigned int clntLen; +#endif + + clntLen = sizeof(echoClntAddr); + + if ((client_sock = accept(server_sock, (struct sockaddr *) &echoClntAddr, &clntLen)) == ESL_SOCK_INVALID) { + status = ESL_FAIL; + goto end; + } + + callback(server_sock, client_sock, &echoClntAddr); + } + + end: + + if (server_sock != ESL_SOCK_INVALID) { + closesocket(server_sock); + server_sock = ESL_SOCK_INVALID; + } + + return status; + +} + +ESL_DECLARE(esl_status_t) esl_connect(esl_handle_t *handle, const char *host, esl_port_t port, const char *password) +{ + + struct hostent *result; + char sendbuf[256]; + int rval = 0; + const char *hval; +#ifdef WIN32 + WORD wVersionRequested = MAKEWORD(2, 0); + WSADATA wsaData; + int err = WSAStartup(wVersionRequested, &wsaData); + if (err != 0) { + snprintf(handle->err, sizeof(handle->err), "WSAStartup Error"); + return ESL_FAIL; + } + +#endif + + if (!handle->mutex) { + esl_mutex_create(&handle->mutex); + } + + handle->sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (handle->sock == ESL_SOCK_INVALID) { + snprintf(handle->err, sizeof(handle->err), "Socket Error"); + return ESL_FAIL; + } + + memset(&handle->sockaddr, 0, sizeof(handle->sockaddr)); + handle->sockaddr.sin_family = AF_INET; + handle->sockaddr.sin_port = htons(port); + + memset(&handle->hostent, 0, sizeof(handle->hostent)); + + if ((result = gethostbyname(host))) { + handle->hostent = *result; + } else { + rval = -1; + } + + if (rval) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + goto fail; + } + + memcpy(&handle->sockaddr.sin_addr, result->h_addr_list[0], result->h_length); + + rval = connect(handle->sock, (struct sockaddr *) &handle->sockaddr, sizeof(handle->sockaddr)); + + if (rval) { + snprintf(handle->err, sizeof(handle->err), "Socket Connection Error"); + goto fail; + } + + sock_setup(handle); + + handle->connected = 1; + + if (esl_recv(handle)) { + snprintf(handle->err, sizeof(handle->err), "Connection Error"); + goto fail; + } + + hval = esl_event_get_header(handle->last_event, "content-type"); + + if (esl_safe_strcasecmp(hval, "auth/request")) { + snprintf(handle->err, sizeof(handle->err), "Connection Error"); + goto fail; + } + + snprintf(sendbuf, sizeof(sendbuf), "auth %s\n\n", password); + esl_send(handle, sendbuf); + + + if (esl_recv(handle)) { + snprintf(handle->err, sizeof(handle->err), "Authentication Error"); + goto fail; + } + + + hval = esl_event_get_header(handle->last_event, "reply-text"); + + if (esl_safe_strcasecmp(hval, "+OK accepted")) { + snprintf(handle->err, sizeof(handle->err), "Authentication Error"); + goto fail; + } + + return ESL_SUCCESS; + + fail: + + esl_disconnect(handle); + + return ESL_FAIL; +} + +ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle) +{ + esl_mutex_t *mutex = handle->mutex; + esl_status_t status = ESL_FAIL; + + if (mutex) { + esl_mutex_lock(mutex); + } + + esl_event_safe_destroy(&handle->race_event); + esl_event_safe_destroy(&handle->last_event); + esl_event_safe_destroy(&handle->last_sr_event); + esl_event_safe_destroy(&handle->last_ievent); + esl_event_safe_destroy(&handle->info_event); + + if (handle->sock != ESL_SOCK_INVALID) { + closesocket(handle->sock); + handle->sock = ESL_SOCK_INVALID; + status = ESL_SUCCESS; + } + + handle->connected = 0; + + if (mutex) { + esl_mutex_unlock(mutex); + esl_mutex_destroy(&mutex); + } + + + return status; +} + +ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, int check_q, esl_event_t **save_event) +{ + fd_set rfds, efds; + struct timeval tv = { 0 }; + int max, activity; + esl_status_t status = ESL_SUCCESS; + + if (check_q) { + esl_mutex_lock(handle->mutex); + if (handle->race_event) { + esl_mutex_unlock(handle->mutex); + return esl_recv_event(handle, check_q, save_event); + } + esl_mutex_unlock(handle->mutex); + } + + if (!handle || !handle->connected || handle->sock == -1) { + return ESL_FAIL; + } + + tv.tv_usec = ms * 1000; + + + FD_ZERO(&rfds); + FD_ZERO(&efds); + +#ifdef WIN32 +#pragma warning( push ) +#pragma warning( disable : 4127 ) + FD_SET(handle->sock, &rfds); + FD_SET(handle->sock, &efds); +#pragma warning( pop ) +#else + FD_SET(handle->sock, &rfds); + FD_SET(handle->sock, &efds); +#endif + + max = handle->sock + 1; + + if ((activity = select(max, &rfds, NULL, &efds, &tv)) < 0) { + return ESL_FAIL; + } + + if (esl_mutex_trylock(handle->mutex) != ESL_SUCCESS) { + return ESL_BREAK; + } + + if (activity && FD_ISSET(handle->sock, &rfds)) { + if (esl_recv_event(handle, check_q, save_event)) { + status = ESL_FAIL; + } + } else { + status = ESL_BREAK; + } + + if (handle->mutex) esl_mutex_unlock(handle->mutex); + + return status; + +} + + +ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event) +{ + char *c; + esl_ssize_t rrval; + int crc = 0; + esl_event_t *revent = NULL, *qevent = NULL; + char *beg; + char *hname, *hval; + char *col; + char *cl; + esl_ssize_t len; + int zc = 0; + + if (!handle->connected) { + return ESL_FAIL; + } + + esl_mutex_lock(handle->mutex); + + if (check_q && handle->race_event) { + qevent = handle->race_event; + handle->race_event = handle->race_event->next; + qevent->next = NULL; + + if (save_event) { + *save_event = qevent; + qevent = NULL; + } else { + handle->last_event = qevent; + } + + esl_mutex_unlock(handle->mutex); + return ESL_SUCCESS; + } + + esl_event_safe_destroy(&handle->last_event); + memset(handle->header_buf, 0, sizeof(handle->header_buf)); + + c = handle->header_buf; + beg = c; + + while(handle->connected) { + rrval = recv(handle->sock, c, 1, 0); + if (rrval == 0) { + if (++zc >= 100) { + esl_disconnect(handle); + esl_mutex_unlock(handle->mutex); + return ESL_DISCONNECTED; + } + } else if (rrval < 0) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + goto fail; + } else { + zc = 0; + + if (*c == '\n') { + if (++crc == 2) { + break; + } + + if (!revent) { + esl_event_create(&revent, ESL_EVENT_COMMAND); + } + + hname = beg; + hval = col = NULL; + + if (hname && (col = strchr(hname, ':'))) { + hval = col + 1; + *col = '\0'; + while(*hval == ' ') hval++; + } + + *c = '\0'; + + if (hname && hval) { + esl_url_decode(hval); + esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval); + esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); + } + + beg = c+1; + + + } else { + crc = 0; + } + + c++; + } + } + + if (!revent) { + goto fail; + } + + if ((cl = esl_event_get_header(revent, "content-length"))) { + char *body; + esl_ssize_t sofar = 0; + + len = atol(cl); + body = malloc(len+1); + esl_assert(body); + *(body + len) = '\0'; + + do { + esl_ssize_t r; + if ((r = recv(handle->sock, body + sofar, len - sofar, 0)) < 0) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + goto fail; + } + sofar += r; + } while (sofar < len); + + revent->body = body; + } + + if (save_event) { + *save_event = revent; + revent = NULL; + } else { + handle->last_event = revent; + } + + if (revent) { + hval = esl_event_get_header(revent, "reply-text"); + + if (!esl_strlen_zero(hval)) { + strncpy(handle->last_reply, hval, sizeof(handle->last_reply)); + } + + hval = esl_event_get_header(revent, "content-type"); + + if (!esl_safe_strcasecmp(hval, "text/disconnect-notice") && revent->body) { + goto fail; + } + + if (!esl_safe_strcasecmp(hval, "text/event-plain") && revent->body) { + esl_event_types_t et = ESL_EVENT_COMMAND; + char *body = strdup(revent->body); + + esl_event_safe_destroy(&handle->last_ievent); + + esl_event_create(&handle->last_ievent, et); + + beg = body; + + while(beg) { + if (!(c = strchr(beg, '\n'))) { + break; + } + + hname = beg; + hval = col = NULL; + + if (hname && (col = strchr(hname, ':'))) { + hval = col + 1; + *col = '\0'; + while(*hval == ' ') hval++; + } + + *c = '\0'; + + if (hname && hval) { + esl_url_decode(hval); + esl_log(ESL_LOG_DEBUG, "RECV INNER HEADER [%s] = [%s]\n", hname, hval); + if (!strcasecmp(hname, "event-name")) { + esl_event_del_header(handle->last_ievent, "event-name"); + } + esl_event_add_header_string(handle->last_ievent, ESL_STACK_BOTTOM, hname, hval); + esl_name_event(hval, &handle->last_ievent->event_id); + } + + beg = c + 1; + + if (*beg == '\n') { + beg++; + break; + } + } + + if ((cl = esl_event_get_header(handle->last_ievent, "content-length"))) { + handle->last_ievent->body = strdup(beg); + } + + free(body); + + if (esl_log_level >= 7) { + char *foo; + esl_event_serialize(handle->last_ievent, &foo, ESL_FALSE); + esl_log(ESL_LOG_DEBUG, "RECV EVENT\n%s\n", foo); + free(foo); + } + } + + if (esl_log_level >= 7) { + char *foo; + esl_event_serialize(revent, &foo, ESL_FALSE); + esl_log(ESL_LOG_DEBUG, "RECV MESSAGE\n%s\n", foo); + free(foo); + } + } + + esl_mutex_unlock(handle->mutex); + + return ESL_SUCCESS; + + fail: + + esl_disconnect(handle); + return ESL_FAIL; + +} + +ESL_DECLARE(esl_status_t) esl_send(esl_handle_t *handle, const char *cmd) +{ + const char *e = cmd + strlen(cmd) -1; + + if (!handle->connected) { + return ESL_FAIL; + } + + esl_log(ESL_LOG_DEBUG, "SEND\n%s\n", cmd); + + if (send(handle->sock, cmd, strlen(cmd), 0) != (int)strlen(cmd)) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + return ESL_FAIL; + } + + if (!(*e == '\n' && *(e-1) == '\n')) { + if (send(handle->sock, "\n\n", 2, 0) != 2) { + strerror_r(handle->errnum, handle->err, sizeof(handle->err)); + return ESL_FAIL; + } + } + + return ESL_SUCCESS; + +} + + +ESL_DECLARE(esl_status_t) esl_send_recv(esl_handle_t *handle, const char *cmd) +{ + const char *hval; + esl_status_t status; + + if (!handle->connected) { + return ESL_FAIL; + } + + + esl_mutex_lock(handle->mutex); + + esl_event_safe_destroy(&handle->last_event); + esl_event_safe_destroy(&handle->last_sr_event); + + *handle->last_sr_reply = '\0'; + + if ((status = esl_send(handle, cmd))) { + esl_mutex_unlock(handle->mutex); + return status; + } + + recv: + + status = esl_recv_event(handle, 0, &handle->last_sr_event); + + if (handle->last_sr_event) { + char *ct = esl_event_get_header(handle->last_sr_event,"content-type"); + + if (strcasecmp(ct, "api/response") && strcasecmp(ct, "command/reply")) { + esl_event_t *ep; + + for(ep = handle->race_event; ep && ep->next; ep = ep->next); + + if (ep) { + ep->next = handle->last_sr_event; + } else { + handle->race_event = handle->last_sr_event; + } + + handle->last_sr_event = NULL; + + esl_mutex_unlock(handle->mutex); + esl_mutex_lock(handle->mutex); + goto recv; + } + + if (handle->last_sr_event) { + hval = esl_event_get_header(handle->last_sr_event, "reply-text"); + + if (!esl_strlen_zero(hval)) { + strncpy(handle->last_sr_reply, hval, sizeof(handle->last_sr_reply)); + } + } + } + + esl_mutex_unlock(handle->mutex); + + return status; +} + + + + diff --git a/src/libesl/esl.h b/src/libesl/esl.h new file mode 100644 index 00000000..db86abb7 --- /dev/null +++ b/src/libesl/esl.h @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ESL_H_ +#define _ESL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + +#define esl_copy_string(_x, _y, _z) strncpy(_x, _y, _z - 1) +#define esl_set_string(_x, _y) esl_copy_string(_x, _y, sizeof(_x)) + +typedef struct esl_event_header esl_event_header_t; +typedef struct esl_event esl_event_t; + + +typedef enum { + ESL_EVENT_TYPE_PLAIN, + ESL_EVENT_TYPE_XML +} esl_event_type_t; + +#ifdef WIN32 +#define ESL_SEQ_FWHITE FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY +#define ESL_SEQ_FRED FOREGROUND_RED | FOREGROUND_INTENSITY +#define ESL_SEQ_FMAGEN FOREGROUND_BLUE | FOREGROUND_RED +#define ESL_SEQ_FCYAN FOREGROUND_GREEN | FOREGROUND_BLUE +#define ESL_SEQ_FGREEN FOREGROUND_GREEN +#define ESL_SEQ_FYELLOW FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY +#define ESL_SEQ_DEFAULT_COLOR ESL_SEQ_FWHITE +#else +#define ESL_SEQ_ESC "\033[" +/* Ansi Control character suffixes */ +#define ESL_SEQ_HOME_CHAR 'H' +#define ESL_SEQ_HOME_CHAR_STR "H" +#define ESL_SEQ_CLEARLINE_CHAR '1' +#define ESL_SEQ_CLEARLINE_CHAR_STR "1" +#define ESL_SEQ_CLEARLINEEND_CHAR "K" +#define ESL_SEQ_CLEARSCR_CHAR0 '2' +#define ESL_SEQ_CLEARSCR_CHAR1 'J' +#define ESL_SEQ_CLEARSCR_CHAR "2J" +#define ESL_SEQ_DEFAULT_COLOR ESL_SEQ_ESC ESL_SEQ_END_COLOR /* Reset to Default fg/bg color */ +#define ESL_SEQ_AND_COLOR ";" /* To add multiple color definitions */ +#define ESL_SEQ_END_COLOR "m" /* To end color definitions */ +/* Foreground colors values */ +#define ESL_SEQ_F_BLACK "30" +#define ESL_SEQ_F_RED "31" +#define ESL_SEQ_F_GREEN "32" +#define ESL_SEQ_F_YELLOW "33" +#define ESL_SEQ_F_BLUE "34" +#define ESL_SEQ_F_MAGEN "35" +#define ESL_SEQ_F_CYAN "36" +#define ESL_SEQ_F_WHITE "37" +/* Background colors values */ +#define ESL_SEQ_B_BLACK "40" +#define ESL_SEQ_B_RED "41" +#define ESL_SEQ_B_GREEN "42" +#define ESL_SEQ_B_YELLOW "43" +#define ESL_SEQ_B_BLUE "44" +#define ESL_SEQ_B_MAGEN "45" +#define ESL_SEQ_B_CYAN "46" +#define ESL_SEQ_B_WHITE "47" +/* Preset escape sequences - Change foreground colors only */ +#define ESL_SEQ_FBLACK ESL_SEQ_ESC ESL_SEQ_F_BLACK ESL_SEQ_END_COLOR +#define ESL_SEQ_FRED ESL_SEQ_ESC ESL_SEQ_F_RED ESL_SEQ_END_COLOR +#define ESL_SEQ_FGREEN ESL_SEQ_ESC ESL_SEQ_F_GREEN ESL_SEQ_END_COLOR +#define ESL_SEQ_FYELLOW ESL_SEQ_ESC ESL_SEQ_F_YELLOW ESL_SEQ_END_COLOR +#define ESL_SEQ_FBLUE ESL_SEQ_ESC ESL_SEQ_F_BLUE ESL_SEQ_END_COLOR +#define ESL_SEQ_FMAGEN ESL_SEQ_ESC ESL_SEQ_F_MAGEN ESL_SEQ_END_COLOR +#define ESL_SEQ_FCYAN ESL_SEQ_ESC ESL_SEQ_F_CYAN ESL_SEQ_END_COLOR +#define ESL_SEQ_FWHITE ESL_SEQ_ESC ESL_SEQ_F_WHITE ESL_SEQ_END_COLOR +#define ESL_SEQ_BBLACK ESL_SEQ_ESC ESL_SEQ_B_BLACK ESL_SEQ_END_COLOR +#define ESL_SEQ_BRED ESL_SEQ_ESC ESL_SEQ_B_RED ESL_SEQ_END_COLOR +#define ESL_SEQ_BGREEN ESL_SEQ_ESC ESL_SEQ_B_GREEN ESL_SEQ_END_COLOR +#define ESL_SEQ_BYELLOW ESL_SEQ_ESC ESL_SEQ_B_YELLOW ESL_SEQ_END_COLOR +#define ESL_SEQ_BBLUE ESL_SEQ_ESC ESL_SEQ_B_BLUE ESL_SEQ_END_COLOR +#define ESL_SEQ_BMAGEN ESL_SEQ_ESC ESL_SEQ_B_MAGEN ESL_SEQ_END_COLOR +#define ESL_SEQ_BCYAN ESL_SEQ_ESC ESL_SEQ_B_CYAN ESL_SEQ_END_COLOR +#define ESL_SEQ_BWHITE ESL_SEQ_ESC ESL_SEQ_B_WHITE ESL_SEQ_END_COLOR +/* Preset escape sequences */ +#define ESL_SEQ_HOME ESL_SEQ_ESC ESL_SEQ_HOME_CHAR_STR +#define ESL_SEQ_CLEARLINE ESL_SEQ_ESC ESL_SEQ_CLEARLINE_CHAR_STR +#define ESL_SEQ_CLEARLINEEND ESL_SEQ_ESC ESL_SEQ_CLEARLINEEND_CHAR +#define ESL_SEQ_CLEARSCR ESL_SEQ_ESC ESL_SEQ_CLEARSCR_CHAR ESL_SEQ_HOME +#endif + +#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__NetBSD__) +#define _XOPEN_SOURCE 600 +#endif + +#ifndef HAVE_STRINGS_H +#define HAVE_STRINGS_H 1 +#endif +#ifndef HAVE_SYS_SOCKET_H +#define HAVE_SYS_SOCKET_H 1 +#endif + +#ifndef __WINDOWS__ +#if defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32) +#define __WINDOWS__ +#endif +#endif + +#ifdef _MSC_VER +#ifndef __inline__ +#define __inline__ __inline +#endif +#if (_MSC_VER >= 1400) /* VC8+ */ +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE +#endif +#ifndef _CRT_NONSTDC_NO_DEPRECATE +#define _CRT_NONSTDC_NO_DEPRECATE +#endif +#endif +#ifndef strcasecmp +#define strcasecmp(s1, s2) _stricmp(s1, s2) +#endif +#ifndef strncasecmp +#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) +#endif +#ifndef snprintf +#define snprintf _snprintf +#endif +#ifndef S_IRUSR +#define S_IRUSR _S_IREAD +#endif +#ifndef S_IWUSR +#define S_IWUSR _S_IWRITE +#endif +#undef HAVE_STRINGS_H +#undef HAVE_SYS_SOCKET_H +#endif + +#include +#ifndef WIN32 +#include +#endif + +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#endif + +#ifdef HAVE_STRINGS_H +#include +#endif +#include + +#if (_MSC_VER >= 1400) // VC8+ +#define esl_assert(expr) assert(expr);__analysis_assume( expr ) +#endif + +#ifndef esl_assert +#define esl_assert(_x) assert(_x) +#endif + +#define esl_safe_free(_x) if (_x) free(_x); _x = NULL +#define esl_strlen_zero(s) (!s || *(s) == '\0') +#define esl_strlen_zero_buf(s) (*(s) == '\0') + +#ifdef WIN32 +#include +#include +typedef SOCKET esl_socket_t; +typedef unsigned __int64 uint64_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int16 uint16_t; +typedef unsigned __int8 uint8_t; +typedef __int64 int64_t; +typedef __int32 int32_t; +typedef __int16 int16_t; +typedef __int8 int8_t; +typedef intptr_t esl_ssize_t; +typedef int esl_filehandle_t; +#define ESL_SOCK_INVALID INVALID_SOCKET +#define strerror_r(num, buf, size) strerror_s(buf, size, num) +#if defined(ESL_DECLARE_STATIC) +#define ESL_DECLARE(type) type __stdcall +#define ESL_DECLARE_NONSTD(type) type __cdecl +#define ESL_DECLARE_DATA +#elif defined(ESL_EXPORTS) +#define ESL_DECLARE(type) __declspec(dllexport) type __stdcall +#define ESL_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl +#define ESL_DECLARE_DATA __declspec(dllexport) +#else +#define ESL_DECLARE(type) __declspec(dllimport) type __stdcall +#define ESL_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl +#define ESL_DECLARE_DATA __declspec(dllimport) +#endif +#else +#define ESL_DECLARE(type) type +#define ESL_DECLARE_NONSTD(type) type +#define ESL_DECLARE_DATA +#include +#include +#include +#include +#include +#include +#include +#define ESL_SOCK_INVALID -1 +typedef int esl_socket_t; +typedef ssize_t esl_ssize_t; +typedef int esl_filehandle_t; +#endif + +typedef int16_t esl_port_t; + +typedef enum { + ESL_SUCCESS, + ESL_FAIL, + ESL_BREAK, + ESL_DISCONNECTED +} esl_status_t; + +#include + +typedef struct { + struct sockaddr_in sockaddr; + struct hostent hostent; + char hostbuf[256]; + esl_socket_t sock; + char err[256]; + int errnum; + char header_buf[4196]; + char last_reply[1024]; + char last_sr_reply[1024]; + esl_event_t *last_event; + esl_event_t *last_sr_event; + esl_event_t *race_event; + esl_event_t *last_ievent; + esl_event_t *info_event; + int connected; + struct sockaddr_in addr; + esl_mutex_t *mutex; + int async_execute; + int event_lock; +} esl_handle_t; + +typedef enum { + ESL_TRUE = 1, + ESL_FALSE = 0 +} esl_bool_t; + +#ifndef __FUNCTION__ +#define __FUNCTION__ (const char *)__func__ +#endif + +#define ESL_PRE __FILE__, __FUNCTION__, __LINE__ +#define ESL_LOG_LEVEL_DEBUG 7 +#define ESL_LOG_LEVEL_INFO 6 +#define ESL_LOG_LEVEL_NOTICE 5 +#define ESL_LOG_LEVEL_WARNING 4 +#define ESL_LOG_LEVEL_ERROR 3 +#define ESL_LOG_LEVEL_CRIT 2 +#define ESL_LOG_LEVEL_ALERT 1 +#define ESL_LOG_LEVEL_EMERG 0 + +#define ESL_LOG_DEBUG ESL_PRE, ESL_LOG_LEVEL_DEBUG +#define ESL_LOG_INFO ESL_PRE, ESL_LOG_LEVEL_INFO +#define ESL_LOG_NOTICE ESL_PRE, ESL_LOG_LEVEL_NOTICE +#define ESL_LOG_WARNING ESL_PRE, ESL_LOG_LEVEL_WARNING +#define ESL_LOG_ERROR ESL_PRE, ESL_LOG_LEVEL_ERROR +#define ESL_LOG_CRIT ESL_PRE, ESL_LOG_LEVEL_CRIT +#define ESL_LOG_ALERT ESL_PRE, ESL_LOG_LEVEL_ALERT +#define ESL_LOG_EMERG ESL_PRE, ESL_LOG_LEVEL_EMERG +typedef void (*esl_logger_t)(const char *file, const char *func, int line, int level, const char *fmt, ...); + + +ESL_DECLARE(int) esl_vasprintf(char **ret, const char *fmt, va_list ap); + +ESL_DECLARE_DATA extern esl_logger_t esl_log; + +ESL_DECLARE(void) esl_global_set_logger(esl_logger_t logger); +ESL_DECLARE(void) esl_global_set_default_logger(int level); + +#include "esl_event.h" +#include "esl_threadmutex.h" +#include "esl_config.h" + +ESL_DECLARE(size_t) esl_url_encode(const char *url, char *buf, size_t len); +ESL_DECLARE(char *)esl_url_decode(char *s); +ESL_DECLARE(const char *)esl_stristr(const char *instr, const char *str); +ESL_DECLARE(int) esl_toupper(int c); +ESL_DECLARE(int) esl_tolower(int c); +ESL_DECLARE(int) esl_snprintf(char *buffer, size_t count, const char *fmt, ...); + + +typedef void (*esl_listen_callback_t)(esl_socket_t server_sock, esl_socket_t client_sock, struct sockaddr_in *addr); + +ESL_DECLARE(esl_status_t) esl_attach_handle(esl_handle_t *handle, esl_socket_t socket, struct sockaddr_in *addr); +ESL_DECLARE(esl_status_t) esl_listen(const char *host, esl_port_t port, esl_listen_callback_t callback); +ESL_DECLARE(esl_status_t) esl_execute(esl_handle_t *handle, const char *app, const char *arg, const char *uuid); +ESL_DECLARE(esl_status_t) esl_sendevent(esl_handle_t *handle, esl_event_t *event); + +ESL_DECLARE(esl_status_t) esl_connect(esl_handle_t *handle, const char *host, esl_port_t port, const char *password); +ESL_DECLARE(esl_status_t) esl_disconnect(esl_handle_t *handle); +ESL_DECLARE(esl_status_t) esl_send(esl_handle_t *handle, const char *cmd); +ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event); +ESL_DECLARE(esl_status_t) esl_recv_event_timed(esl_handle_t *handle, uint32_t ms, int check_q, esl_event_t **save_event); +ESL_DECLARE(esl_status_t) esl_send_recv(esl_handle_t *handle, const char *cmd); +ESL_DECLARE(esl_status_t) esl_filter(esl_handle_t *handle, const char *header, const char *value); +ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etype, const char *value); + +#define esl_recv(_h) esl_recv_event(_h, 0, NULL) +#define esl_recv_timed(_h, _ms) esl_recv_event_timed(_h, _ms, 0, NULL) + +static __inline__ int esl_safe_strcasecmp(const char *s1, const char *s2) +{ + if (!(s1 && s2)) { + return 1; + } + + return strcasecmp(s1, s2); +} + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + + +#endif /* defined(_ESL_H_) */ + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */ diff --git a/src/libesl/esl_config.c b/src/libesl/esl_config.c new file mode 100644 index 00000000..b781d83e --- /dev/null +++ b/src/libesl/esl_config.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "esl.h" +#include "esl_config.h" + +ESL_DECLARE(int) esl_config_open_file(esl_config_t *cfg, const char *file_path) +{ + FILE *f; + const char *path = NULL; + char path_buf[1024]; + + if (file_path[0] == '/') { + path = file_path; + } else { + esl_snprintf(path_buf, sizeof(path_buf), "%s%s%s", ESL_CONFIG_DIR, ESL_PATH_SEPARATOR, file_path); + path = path_buf; + } + + if (!path) { + return 0; + } + + memset(cfg, 0, sizeof(*cfg)); + cfg->lockto = -1; + esl_log(ESL_LOG_DEBUG, "Configuration file is %s.\n", path); + f = fopen(path, "r"); + + if (!f) { + if (file_path[0] != '/') { + int last = -1; + char *var, *val; + + esl_snprintf(path_buf, sizeof(path_buf), "%s%sopenesl.conf", ESL_CONFIG_DIR, ESL_PATH_SEPARATOR); + path = path_buf; + + if ((f = fopen(path, "r")) == 0) { + return 0; + } + + cfg->file = f; + esl_set_string(cfg->path, path); + + while (esl_config_next_pair(cfg, &var, &val)) { + if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) { + cfg->lockto = cfg->sectno; + return 1; + } + } + + esl_config_close_file(cfg); + memset(cfg, 0, sizeof(*cfg)); + return 0; + } + + return 0; + } else { + cfg->file = f; + esl_set_string(cfg->path, path); + return 1; + } +} + +ESL_DECLARE(void) esl_config_close_file(esl_config_t *cfg) +{ + + if (cfg->file) { + fclose(cfg->file); + } + + memset(cfg, 0, sizeof(*cfg)); +} + + + +ESL_DECLARE(int) esl_config_next_pair(esl_config_t *cfg, char **var, char **val) +{ + int ret = 0; + char *p, *end; + + *var = *val = NULL; + + if (!cfg->path) { + return 0; + } + + for (;;) { + cfg->lineno++; + + if (!fgets(cfg->buf, sizeof(cfg->buf), cfg->file)) { + ret = 0; + break; + } + *var = cfg->buf; + + if (**var == '[' && (end = strchr(*var, ']')) != 0) { + *end = '\0'; + (*var)++; + if (**var == '+') { + (*var)++; + esl_copy_string(cfg->section, *var, sizeof(cfg->section)); + cfg->sectno++; + + if (cfg->lockto > -1 && cfg->sectno != cfg->lockto) { + break; + } + cfg->catno = 0; + cfg->lineno = 0; + *var = (char *) ""; + *val = (char *) ""; + return 1; + } else { + esl_copy_string(cfg->category, *var, sizeof(cfg->category)); + cfg->catno++; + } + continue; + } + + + + if (**var == '#' || **var == ';' || **var == '\n' || **var == '\r') { + continue; + } + + if (!strncmp(*var, "__END__", 7)) { + break; + } + + + if ((end = strchr(*var, ';')) && *(end+1) == *end) { + *end = '\0'; + end--; + } else if ((end = strchr(*var, '\n')) != 0) { + if (*(end - 1) == '\r') { + end--; + } + *end = '\0'; + } + + p = *var; + while ((*p == ' ' || *p == '\t') && p != end) { + *p = '\0'; + p++; + } + *var = p; + + + if ((*val = strchr(*var, '=')) == 0) { + ret = -1; + /* log_printf(0, server.log, "Invalid syntax on %s: line %d\n", cfg->path, cfg->lineno); */ + continue; + } else { + p = *val - 1; + *(*val) = '\0'; + (*val)++; + if (*(*val) == '>') { + *(*val) = '\0'; + (*val)++; + } + + while ((*p == ' ' || *p == '\t') && p != *var) { + *p = '\0'; + p--; + } + + p = *val; + while ((*p == ' ' || *p == '\t') && p != end) { + *p = '\0'; + p++; + } + *val = p; + ret = 1; + break; + } + } + + + return ret; + +} + +ESL_DECLARE(int) esl_config_get_cas_bits(char *strvalue, unsigned char *outbits) +{ + char cas_bits[5]; + unsigned char bit = 0x8; + char *double_colon = strchr(strvalue, ':'); + int x = 0; + + if (!double_colon) { + esl_log(ESL_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon); + return -1; + } + + double_colon++; + *outbits = 0; + cas_bits[4] = 0; + + if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) { + esl_log(ESL_LOG_ERROR, "Invalid CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon); + return -1; + } + + esl_log(ESL_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits); + + for (; cas_bits[x]; x++) { + if ('1' == cas_bits[x]) { + *outbits |= bit; + } else if ('0' != cas_bits[x]) { + esl_log(ESL_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n"); + return -1; + } + bit >>= 1; + } + return 0; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */ diff --git a/src/libesl/esl_config.h b/src/libesl/esl_config.h new file mode 100644 index 00000000..6763cdb7 --- /dev/null +++ b/src/libesl/esl_config.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @defgroup config Config File Parser + * @ingroup config + * This module implements a basic interface and file format parser + * + *
+ *
+ * EXAMPLE 
+ * 
+ * [category1]
+ * var1 => val1
+ * var2 => val2
+ * \# lines that begin with \# are comments
+ * \#var3 => val3
+ * 
+ * @{ + */ + +#ifndef ESL_CONFIG_H +#define ESL_CONFIG_H + +#include "esl.h" + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + + +#define ESL_URL_SEPARATOR "://" + + +#ifdef WIN32 +#define ESL_PATH_SEPARATOR "\\" +#ifndef ESL_CONFIG_DIR +#define ESL_CONFIG_DIR "c:\\openesl" +#endif +#define esl_is_file_path(file) (*(file +1) == ':' || *file == '/' || strstr(file, SWITCH_URL_SEPARATOR)) +#else +#define ESL_PATH_SEPARATOR "/" +#ifndef ESL_CONFIG_DIR +#define ESL_CONFIG_DIR "/etc/openesl" +#endif +#define esl_is_file_path(file) ((*file == '/') || strstr(file, SWITCH_URL_SEPARATOR)) +#endif + +/*! + \brief Evaluate the truthfullness of a string expression + \param expr a string expression + \return true or false +*/ +#define esl_true(expr)\ +(expr && ( !strcasecmp(expr, "yes") ||\ +!strcasecmp(expr, "on") ||\ +!strcasecmp(expr, "true") ||\ +!strcasecmp(expr, "enabled") ||\ +!strcasecmp(expr, "active") ||\ +!strcasecmp(expr, "allow") ||\ +atoi(expr))) ? 1 : 0 + +/*! + \brief Evaluate the falsefullness of a string expression + \param expr a string expression + \return true or false +*/ +#define esl_false(expr)\ +(expr && ( !strcasecmp(expr, "no") ||\ +!strcasecmp(expr, "off") ||\ +!strcasecmp(expr, "false") ||\ +!strcasecmp(expr, "disabled") ||\ +!strcasecmp(expr, "inactive") ||\ +!strcasecmp(expr, "disallow") ||\ +!atoi(expr))) ? 1 : 0 + +typedef struct esl_config esl_config_t; + +/*! \brief A simple file handle representing an open configuration file **/ +struct esl_config { + /*! FILE stream buffer to the opened file */ + FILE *file; + /*! path to the file */ + char path[512]; + /*! current category */ + char category[256]; + /*! current section */ + char section[256]; + /*! buffer of current line being read */ + char buf[1024]; + /*! current line number in file */ + int lineno; + /*! current category number in file */ + int catno; + /*! current section number in file */ + int sectno; + + int lockto; +}; + +/*! + \brief Open a configuration file + \param cfg (esl_config_t *) config handle to use + \param file_path path to the file + \return 1 (true) on success 0 (false) on failure +*/ +ESL_DECLARE(int) esl_config_open_file(esl_config_t * cfg, const char *file_path); + +/*! + \brief Close a previously opened configuration file + \param cfg (esl_config_t *) config handle to use +*/ +ESL_DECLARE(void) esl_config_close_file(esl_config_t * cfg); + +/*! + \brief Retrieve next name/value pair from configuration file + \param cfg (esl_config_t *) config handle to use + \param var pointer to aim at the new variable name + \param val pointer to aim at the new value +*/ +ESL_DECLARE(int) esl_config_next_pair(esl_config_t * cfg, char **var, char **val); + +/*! + \brief Retrieve the CAS bits from a configuration string value + \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx) + \param outbits pointer to aim at the CAS bits +*/ +ESL_DECLARE(int) esl_config_get_cas_bits(char *strvalue, unsigned char *outbits); + + +/** @} */ + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif /* defined(ESL_CONFIG_H) */ + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */ diff --git a/src/libesl/esl_event.c b/src/libesl/esl_event.c new file mode 100644 index 00000000..65bcb341 --- /dev/null +++ b/src/libesl/esl_event.c @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include +#include + +static char *my_dup(const char *s) +{ + size_t len = strlen(s) + 1; + void *new = malloc(len); + esl_assert(new); + + return (char *) memcpy(new, s, len); +} + +#ifndef ALLOC +#define ALLOC(size) malloc(size) +#endif +#ifndef DUP +#define DUP(str) my_dup(str) +#endif +#ifndef FREE +#define FREE(ptr) esl_safe_free(ptr) +#endif + +/* make sure this is synced with the esl_event_types_t enum in esl_types.h + also never put any new ones before EVENT_ALL +*/ +static const char *EVENT_NAMES[] = { + "CUSTOM", + "CLONE", + "CHANNEL_CREATE", + "CHANNEL_DESTROY", + "CHANNEL_STATE", + "CHANNEL_ANSWER", + "CHANNEL_HANGUP", + "CHANNEL_EXECUTE", + "CHANNEL_EXECUTE_COMPLETE", + "CHANNEL_BRIDGE", + "CHANNEL_UNBRIDGE", + "CHANNEL_PROGRESS", + "CHANNEL_PROGRESS_MEDIA", + "CHANNEL_OUTGOING", + "CHANNEL_PARK", + "CHANNEL_UNPARK", + "CHANNEL_APPLICATION", + "CHANNEL_ORIGINATE", + "CHANNEL_UUID", + "API", + "LOG", + "INBOUND_CHAN", + "OUTBOUND_CHAN", + "STARTUP", + "SHUTDOWN", + "PUBLISH", + "UNPUBLISH", + "TALK", + "NOTALK", + "SESSION_CRASH", + "MODULE_LOAD", + "MODULE_UNLOAD", + "DTMF", + "MESSAGE", + "PRESENCE_IN", + "NOTIFY_IN", + "PRESENCE_OUT", + "PRESENCE_PROBE", + "MESSAGE_WAITING", + "MESSAGE_QUERY", + "ROSTER", + "CODEC", + "BACKGROUND_JOB", + "DETECTED_SPEECH", + "DETECTED_TONE", + "PRIVATE_COMMAND", + "HEARTBEAT", + "TRAP", + "ADD_SCHEDULE", + "DEL_SCHEDULE", + "EXE_SCHEDULE", + "RE_SCHEDULE", + "RELOADXML", + "NOTIFY", + "SEND_MESSAGE", + "RECV_MESSAGE", + "REQUEST_PARAMS", + "CHANNEL_DATA", + "GENERAL", + "COMMAND", + "SESSION_HEARTBEAT", + "CLIENT_DISCONNECTED", + "SERVER_DISCONNECTED", + "SEND_INFO", + "RECV_INFO", + "ALL" +}; + +ESL_DECLARE(const char *)esl_event_name(esl_event_types_t event) +{ + return EVENT_NAMES[event]; +} + +ESL_DECLARE(esl_status_t) esl_name_event(const char *name, esl_event_types_t *type) +{ + esl_event_types_t x; + + for (x = 0; x <= ESL_EVENT_ALL; x++) { + if ((strlen(name) > 13 && !strcasecmp(name + 13, EVENT_NAMES[x])) || !strcasecmp(name, EVENT_NAMES[x])) { + *type = x; + return ESL_SUCCESS; + } + } + + return ESL_FAIL; +} + + +ESL_DECLARE(esl_status_t) esl_event_create_subclass(esl_event_t **event, esl_event_types_t event_id, const char *subclass_name) +{ + *event = NULL; + + if ((event_id != ESL_EVENT_CLONE && event_id != ESL_EVENT_CUSTOM) && subclass_name) { + return ESL_FAIL; + } + + *event = ALLOC(sizeof(esl_event_t)); + esl_assert(*event); + + + memset(*event, 0, sizeof(esl_event_t)); + + if (event_id != ESL_EVENT_CLONE) { + (*event)->event_id = event_id; + esl_event_add_header_string(*event, ESL_STACK_BOTTOM, "Event-Name", esl_event_name((*event)->event_id)); + } + + if (subclass_name) { + (*event)->subclass_name = DUP(subclass_name); + esl_event_add_header_string(*event, ESL_STACK_BOTTOM, "Event-Subclass", subclass_name); + } + + return ESL_SUCCESS; +} + + +ESL_DECLARE(const char *)esl_priority_name(esl_priority_t priority) +{ + switch (priority) { /*lol */ + case ESL_PRIORITY_NORMAL: + return "NORMAL"; + case ESL_PRIORITY_LOW: + return "LOW"; + case ESL_PRIORITY_HIGH: + return "HIGH"; + default: + return "INVALID"; + } +} + +ESL_DECLARE(esl_status_t) esl_event_set_priority(esl_event_t *event, esl_priority_t priority) +{ + event->priority = priority; + esl_event_add_header_string(event, ESL_STACK_TOP, "priority", esl_priority_name(priority)); + return ESL_SUCCESS; +} + +#define ESL_HASH_KEY_STRING -1 + +static unsigned int esl_ci_hashfunc_default(const char *char_key, esl_ssize_t *klen) + +{ + unsigned int hash = 0; + const unsigned char *key = (const unsigned char *)char_key; + const unsigned char *p; + esl_ssize_t i; + + if (*klen == ESL_HASH_KEY_STRING) { + for (p = key; *p; p++) { + hash = hash * 33 + tolower(*p); + } + *klen = p - key; + } + else { + for (p = key, i = *klen; i; i--, p++) { + hash = hash * 33 + tolower(*p); + } + } + + return hash; +} + + +ESL_DECLARE(char *)esl_event_get_header(esl_event_t *event, const char *header_name) +{ + esl_event_header_t *hp; + esl_ssize_t hlen = -1; + unsigned long hash = 0; + + esl_assert(event); + + if (!header_name) return NULL; + + hash = esl_ci_hashfunc_default(header_name, &hlen); + + for (hp = event->headers; hp; hp = hp->next) { + if ((!hp->hash || hash == hp->hash) && !strcasecmp(hp->name, header_name) ) { + return hp->value; + } + } + return NULL; +} + +ESL_DECLARE(char *)esl_event_get_body(esl_event_t *event) +{ + return (event ? event->body : NULL); +} + +ESL_DECLARE(esl_status_t) esl_event_del_header(esl_event_t *event, const char *header_name) +{ + esl_event_header_t *hp, *lp = NULL, *tp; + esl_status_t status = ESL_FAIL; + int x = 0; + esl_ssize_t hlen = -1; + unsigned long hash = 0; + + tp = event->headers; + while (tp) { + hp = tp; + tp = tp->next; + + x++; + esl_assert(x < 1000); + hash = esl_ci_hashfunc_default(header_name, &hlen); + + if (hp->name && (!hp->hash || hash == hp->hash) && !strcasecmp(header_name, hp->name)) { + if (lp) { + lp->next = hp->next; + } else { + event->headers = hp->next; + } + if (hp == event->last_header || !hp->next) { + event->last_header = lp; + } + FREE(hp->name); + FREE(hp->value); + memset(hp, 0, sizeof(*hp)); + FREE(hp); + + status = ESL_SUCCESS; + } else { + lp = hp; + } + } + + return status; +} + +static esl_status_t esl_event_base_add_header(esl_event_t *event, esl_stack_t stack, const char *header_name, char *data) +{ + esl_event_header_t *header; + esl_ssize_t hlen = -1; + + header = ALLOC(sizeof(*header)); + esl_assert(header); + + memset(header, 0, sizeof(*header)); + + header->name = DUP(header_name); + header->value = data; + header->hash = esl_ci_hashfunc_default(header->name, &hlen); + + if (stack == ESL_STACK_TOP) { + header->next = event->headers; + event->headers = header; + if (!event->last_header) { + event->last_header = header; + } + } else { + if (event->last_header) { + event->last_header->next = header; + } else { + event->headers = header; + header->next = NULL; + } + event->last_header = header; + } + + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_event_add_header(esl_event_t *event, esl_stack_t stack, const char *header_name, const char *fmt, ...) +{ + int ret = 0; + char *data; + va_list ap; + + va_start(ap, fmt); + ret = esl_vasprintf(&data, fmt, ap); + va_end(ap); + + if (ret == -1) { + return ESL_FAIL; + } + + return esl_event_base_add_header(event, stack, header_name, data); +} + +ESL_DECLARE(esl_status_t) esl_event_add_header_string(esl_event_t *event, esl_stack_t stack, const char *header_name, const char *data) +{ + if (data) { + return esl_event_base_add_header(event, stack, header_name, DUP(data)); + } + return ESL_FAIL; +} + +ESL_DECLARE(esl_status_t) esl_event_add_body(esl_event_t *event, const char *fmt, ...) +{ + int ret = 0; + char *data; + + va_list ap; + if (fmt) { + va_start(ap, fmt); + ret = esl_vasprintf(&data, fmt, ap); + va_end(ap); + + if (ret == -1) { + return ESL_FAIL; + } else { + esl_safe_free(event->body); + event->body = data; + return ESL_SUCCESS; + } + } else { + return ESL_FAIL; + } +} + +ESL_DECLARE(void) esl_event_destroy(esl_event_t **event) +{ + esl_event_t *ep = *event, *this_event; + esl_event_header_t *hp, *this_header; + + for (ep = *event ; ep ;) { + this_event = ep; + ep = ep->next; + + for (hp = this_event->headers; hp;) { + this_header = hp; + hp = hp->next; + FREE(this_header->name); + FREE(this_header->value); + memset(this_header, 0, sizeof(*this_header)); + FREE(this_header); + } + FREE(this_event->body); + FREE(this_event->subclass_name); + memset(this_event, 0, sizeof(*this_event)); + FREE(this_event); + } + *event = NULL; +} + + + +ESL_DECLARE(esl_status_t) esl_event_dup(esl_event_t **event, esl_event_t *todup) +{ + esl_event_header_t *hp; + + if (esl_event_create_subclass(event, ESL_EVENT_CLONE, todup->subclass_name) != ESL_SUCCESS) { + return ESL_FAIL; + } + + (*event)->event_id = todup->event_id; + + (*event)->event_user_data = todup->event_user_data; + (*event)->bind_user_data = todup->bind_user_data; + + for (hp = todup->headers; hp; hp = hp->next) { + esl_event_add_header_string(*event, ESL_STACK_BOTTOM, hp->name, hp->value); + } + + if (todup->body) { + (*event)->body = DUP(todup->body); + } + + (*event)->key = todup->key; + + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, esl_bool_t encode) +{ + size_t len = 0; + esl_event_header_t *hp; + size_t llen = 0, dlen = 0, blocksize = 512, encode_len = 1536, new_len = 0; + char *buf; + char *encode_buf = NULL; /* used for url encoding of variables to make sure unsafe things stay out of the serialized copy */ + + *str = NULL; + + dlen = blocksize * 2; + + if (!(buf = malloc(dlen))) { + return ESL_FAIL; + } + + /* go ahead and give ourselves some space to work with, should save a few reallocs */ + if (!(encode_buf = malloc(encode_len))) { + esl_safe_free(buf); + return ESL_FAIL; + } + + /* esl_log_printf(ESL_CHANNEL_LOG, ESL_LOG_INFO, "hit serialized!.\n"); */ + for (hp = event->headers; hp; hp = hp->next) { + /* + * grab enough memory to store 3x the string (url encode takes one char and turns it into %XX) + * so we could end up with a string that is 3 times the originals length, unlikely but rather + * be safe than destroy the string, also add one for the null. And try to be smart about using + * the memory, allocate and only reallocate if we need more. This avoids an alloc, free CPU + * destroying loop. + */ + + + new_len = (strlen(hp->value) * 3) + 1; + + if (encode_len < new_len) { + char *tmp; + /* esl_log_printf(ESL_CHANNEL_LOG, ESL_LOG_INFO, "Allocing %d was %d.\n", ((strlen(hp->value) * 3) + 1), encode_len); */ + /* we can use realloc for initial alloc as well, if encode_buf is zero it treats it as a malloc */ + + /* keep track of the size of our allocation */ + encode_len = new_len; + + if (!(tmp = realloc(encode_buf, encode_len))) { + /* oh boy, ram's gone, give back what little we grabbed and bail */ + esl_safe_free(buf); + esl_safe_free(encode_buf); + return ESL_FAIL; + } + + encode_buf = tmp; + } + + /* handle any bad things in the string like newlines : etc that screw up the serialized format */ + if (encode) { + esl_url_encode(hp->value, encode_buf, encode_len); + } else { + esl_snprintf(encode_buf, encode_len, "%s", hp->value); + } + + llen = strlen(hp->name) + strlen(encode_buf) + 8; + + if ((len + llen) > dlen) { + char *m; + dlen += (blocksize + (len + llen)); + if ((m = realloc(buf, dlen))) { + buf = m; + } else { + /* we seem to be out of memory trying to resize the serialize string, give back what we already have and give up */ + esl_safe_free(buf); + esl_safe_free(encode_buf); + return ESL_FAIL; + } + } + + snprintf(buf + len, dlen - len, "%s: %s\n", hp->name, *encode_buf == '\0' ? "_undef_" : encode_buf); + len = strlen(buf); + } + + /* we are done with the memory we used for encoding, give it back */ + esl_safe_free(encode_buf); + + if (event->body) { + int blen = (int) strlen(event->body); + llen = blen; + + if (blen) { + llen += 25; + } else { + llen += 5; + } + + if ((len + llen) > dlen) { + char *m; + dlen += (blocksize + (len + llen)); + if ((m = realloc(buf, dlen))) { + buf = m; + } else { + esl_safe_free(buf); + return ESL_FAIL; + } + } + + if (blen) { + snprintf(buf + len, dlen - len, "\n%s", event->body); + } else { + snprintf(buf + len, dlen - len, "\n"); + } + } else { + snprintf(buf + len, dlen - len, "\n"); + } + + + *str = buf; + + return ESL_SUCCESS; +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/libesl/esl_event.h b/src/libesl/esl_event.h new file mode 100644 index 00000000..cfc93104 --- /dev/null +++ b/src/libesl/esl_event.h @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ESL_EVENT_H +#define ESL_EVENT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + +typedef enum { + ESL_STACK_BOTTOM, + ESL_STACK_TOP +} esl_stack_t; + +typedef enum { + ESL_EVENT_CUSTOM, + ESL_EVENT_CLONE, + ESL_EVENT_CHANNEL_CREATE, + ESL_EVENT_CHANNEL_DESTROY, + ESL_EVENT_CHANNEL_STATE, + ESL_EVENT_CHANNEL_ANSWER, + ESL_EVENT_CHANNEL_HANGUP, + ESL_EVENT_CHANNEL_EXECUTE, + ESL_EVENT_CHANNEL_EXECUTE_COMPLETE, + ESL_EVENT_CHANNEL_BRIDGE, + ESL_EVENT_CHANNEL_UNBRIDGE, + ESL_EVENT_CHANNEL_PROGRESS, + ESL_EVENT_CHANNEL_PROGRESS_MEDIA, + ESL_EVENT_CHANNEL_OUTGOING, + ESL_EVENT_CHANNEL_PARK, + ESL_EVENT_CHANNEL_UNPARK, + ESL_EVENT_CHANNEL_APPLICATION, + ESL_EVENT_CHANNEL_ORIGINATE, + ESL_EVENT_CHANNEL_UUID, + ESL_EVENT_API, + ESL_EVENT_LOG, + ESL_EVENT_INBOUND_CHAN, + ESL_EVENT_OUTBOUND_CHAN, + ESL_EVENT_STARTUP, + ESL_EVENT_SHUTDOWN, + ESL_EVENT_PUBLISH, + ESL_EVENT_UNPUBLISH, + ESL_EVENT_TALK, + ESL_EVENT_NOTALK, + ESL_EVENT_SESSION_CRASH, + ESL_EVENT_MODULE_LOAD, + ESL_EVENT_MODULE_UNLOAD, + ESL_EVENT_DTMF, + ESL_EVENT_MESSAGE, + ESL_EVENT_PRESENCE_IN, + ESL_EVENT_NOTIFY_IN, + ESL_EVENT_PRESENCE_OUT, + ESL_EVENT_PRESENCE_PROBE, + ESL_EVENT_MESSAGE_WAITING, + ESL_EVENT_MESSAGE_QUERY, + ESL_EVENT_ROSTER, + ESL_EVENT_CODEC, + ESL_EVENT_BACKGROUND_JOB, + ESL_EVENT_DETECTED_SPEECH, + ESL_EVENT_DETECTED_TONE, + ESL_EVENT_PRIVATE_COMMAND, + ESL_EVENT_HEARTBEAT, + ESL_EVENT_TRAP, + ESL_EVENT_ADD_SCHEDULE, + ESL_EVENT_DEL_SCHEDULE, + ESL_EVENT_EXE_SCHEDULE, + ESL_EVENT_RE_SCHEDULE, + ESL_EVENT_RELOADXML, + ESL_EVENT_NOTIFY, + ESL_EVENT_SEND_MESSAGE, + ESL_EVENT_RECV_MESSAGE, + ESL_EVENT_REQUEST_PARAMS, + ESL_EVENT_CHANNEL_DATA, + ESL_EVENT_GENERAL, + ESL_EVENT_COMMAND, + ESL_EVENT_SESSION_HEARTBEAT, + ESL_EVENT_CLIENT_DISCONNECTED, + ESL_EVENT_SERVER_DISCONNECTED, + ESL_EVENT_SEND_INFO, + ESL_EVENT_RECV_INFO, + ESL_EVENT_ALL +} esl_event_types_t; + +typedef enum { + ESL_PRIORITY_NORMAL, + ESL_PRIORITY_LOW, + ESL_PRIORITY_HIGH +} esl_priority_t; + +/*! \brief An event Header */ + struct esl_event_header { + /*! the header name */ + char *name; + /*! the header value */ + char *value; + /*! hash of the header name */ + unsigned long hash; + struct esl_event_header *next; +}; + + +/*! \brief Representation of an event */ +struct esl_event { + /*! the event id (descriptor) */ + esl_event_types_t event_id; + /*! the priority of the event */ + esl_priority_t priority; + /*! the owner of the event */ + char *owner; + /*! the subclass of the event */ + char *subclass_name; + /*! the event headers */ + esl_event_header_t *headers; + /*! the event headers tail pointer */ + esl_event_header_t *last_header; + /*! the body of the event */ + char *body; + /*! user data from the subclass provider */ + void *bind_user_data; + /*! user data from the event sender */ + void *event_user_data; + /*! unique key */ + unsigned long key; + struct esl_event *next; +}; + + + +#define ESL_EVENT_SUBCLASS_ANY NULL + +/*! + \brief Create an event + \param event a NULL pointer on which to create the event + \param event_id the event id enumeration of the desired event + \param subclass_name the subclass name for custom event (only valid when event_id is ESL_EVENT_CUSTOM) + \return ESL_STATUS_SUCCESS on success +*/ +ESL_DECLARE(esl_status_t) esl_event_create_subclass(esl_event_t **event, esl_event_types_t event_id, const char *subclass_name); + +/*! + \brief Set the priority of an event + \param event the event to set the priority on + \param priority the event priority + \return ESL_STATUS_SUCCESS +*/ +ESL_DECLARE(esl_status_t) esl_event_set_priority(esl_event_t *event, esl_priority_t priority); + +/*! + \brief Retrieve a header value from an event + \param event the event to read the header from + \param header_name the name of the header to read + \return the value of the requested header +*/ +ESL_DECLARE(char *)esl_event_get_header(esl_event_t *event, const char *header_name); + +/*! + \brief Retrieve the body value from an event + \param event the event to read the body from + \return the value of the body or NULL +*/ +ESL_DECLARE(char *)esl_event_get_body(esl_event_t *event); + +/*! + \brief Add a header to an event + \param event the event to add the header to + \param stack the stack sense (stack it on the top or on the bottom) + \param header_name the name of the header to add + \param fmt the value of the header (varargs see standard sprintf family) + \return ESL_STATUS_SUCCESS if the header was added +*/ +ESL_DECLARE(esl_status_t) esl_event_add_header(esl_event_t *event, esl_stack_t stack, + const char *header_name, const char *fmt, ...); //PRINTF_FUNCTION(4, 5); + +/*! + \brief Add a string header to an event + \param event the event to add the header to + \param stack the stack sense (stack it on the top or on the bottom) + \param header_name the name of the header to add + \param data the value of the header + \return ESL_STATUS_SUCCESS if the header was added +*/ +ESL_DECLARE(esl_status_t) esl_event_add_header_string(esl_event_t *event, esl_stack_t stack, const char *header_name, const char *data); + +ESL_DECLARE(esl_status_t) esl_event_del_header(esl_event_t *event, const char *header_name); + +/*! + \brief Destroy an event + \param event pointer to the pointer to event to destroy +*/ +ESL_DECLARE(void) esl_event_destroy(esl_event_t **event); +#define esl_event_safe_destroy(_event) if (_event) esl_event_destroy(_event) + +/*! + \brief Duplicate an event + \param event a NULL pointer on which to duplicate the event + \param todup an event to duplicate + \return ESL_STATUS_SUCCESS if the event was duplicated +*/ +ESL_DECLARE(esl_status_t) esl_event_dup(esl_event_t **event, esl_event_t *todup); + +/*! + \brief Render the name of an event id enumeration + \param event the event id to render the name of + \return the rendered name +*/ +ESL_DECLARE(const char *)esl_event_name(esl_event_types_t event); + +/*! + \brief return the event id that matches a given event name + \param name the name of the event + \param type the event id to return + \return ESL_STATUS_SUCCESS if there was a match +*/ +ESL_DECLARE(esl_status_t) esl_name_event(const char *name, esl_event_types_t *type); + +/*! + \brief Render a string representation of an event sutable for printing or network transport + \param event the event to render + \param str a string pointer to point at the allocated data + \param encode url encode the headers + \return ESL_STATUS_SUCCESS if the operation was successful + \note you must free the resulting string when you are finished with it +*/ +ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, esl_bool_t encode); + +/*! + \brief Add a body to an event + \param event the event to add to body to + \param fmt optional body of the event (varargs see standard sprintf family) + \return ESL_STATUS_SUCCESS if the body was added to the event + \note the body parameter can be shadowed by the esl_event_reserve_subclass_detailed function +*/ +ESL_DECLARE(esl_status_t) esl_event_add_body(esl_event_t *event, const char *fmt, ...); + +/*! + \brief Create a new event assuming it will not be custom event and therefore hiding the unused parameters + \param event a NULL pointer on which to create the event + \param id the event id enumeration of the desired event + \return ESL_STATUS_SUCCESS on success +*/ +#define esl_event_create(event, id) esl_event_create_subclass(event, id, ESL_EVENT_SUBCLASS_ANY) + +ESL_DECLARE(const char *)esl_priority_name(esl_priority_t priority); + +///\} + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif /* defined(ESL_EVENT_H) */ + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/libesl/esl_oop.cpp b/src/libesl/esl_oop.cpp new file mode 100644 index 00000000..e7168938 --- /dev/null +++ b/src/libesl/esl_oop.cpp @@ -0,0 +1,427 @@ +#include +#include + +#define connection_construct_common() memset(&handle, 0, sizeof(handle)); last_event_obj = NULL +#define event_construct_common() event = NULL; serialized_string = NULL; mine = 0; hp = NULL + +void eslSetLogLevel(int level) +{ + esl_global_set_default_logger(level); +} + +ESLconnection::ESLconnection(const char *host, const char *port, const char *password) +{ + connection_construct_common(); + int x_port = atoi(port); + + esl_connect(&handle, host, x_port, password); +} + + +ESLconnection::ESLconnection(int socket) +{ + connection_construct_common(); + memset(&handle, 0, sizeof(handle)); + esl_attach_handle(&handle, (esl_socket_t)socket, NULL); +} + +ESLconnection::~ESLconnection() +{ + if (handle.connected) { + esl_disconnect(&handle); + } + +} + +int ESLconnection::disconnect() +{ + if (handle.connected) { + return esl_disconnect(&handle); + } + + return 0; +} + +int ESLconnection::connected() +{ + return handle.connected; +} + +int ESLconnection::send(const char *cmd) +{ + return esl_send(&handle, cmd); +} + +ESLevent *ESLconnection::sendRecv(const char *cmd) +{ + if (esl_send_recv(&handle, cmd) == ESL_SUCCESS) { + esl_event_t *event; + esl_event_dup(&event, handle.last_sr_event); + return new ESLevent(event, 1); + } + + return NULL; +} + +ESLevent *ESLconnection::api(const char *cmd, const char *arg) +{ + size_t len; + char *cmd_buf; + + if (!cmd) { + return NULL; + } + + len = strlen(cmd) + (arg ? strlen(arg) : 0) + 10; + + cmd_buf = (char *) malloc(len + 1); + assert(cmd_buf); + + snprintf(cmd_buf, len, "api %s %s", cmd, arg ? arg : ""); + *(cmd_buf + (len)) = '\0'; + + + if (esl_send_recv(&handle, cmd_buf) == ESL_SUCCESS) { + esl_event_t *event; + esl_event_dup(&event, handle.last_sr_event); + return new ESLevent(event, 1); + } + + free(cmd_buf); + + return NULL; +} + +ESLevent *ESLconnection::bgapi(const char *cmd, const char *arg) +{ + size_t len; + char *cmd_buf; + + if (!cmd) { + return NULL; + } + + len = strlen(cmd) + (arg ? strlen(arg) : 0) + 10; + + cmd_buf = (char *) malloc(len + 1); + assert(cmd_buf); + + snprintf(cmd_buf, len, "bgapi %s %s", cmd, arg ? arg : ""); + *(cmd_buf + (len)) = '\0'; + + if (esl_send_recv(&handle, cmd_buf) == ESL_SUCCESS) { + esl_event_t *event; + esl_event_dup(&event, handle.last_sr_event); + return new ESLevent(event, 1); + } + + free(cmd_buf); + + return NULL; +} + +ESLevent *ESLconnection::getInfo() +{ + if (handle.connected && handle.info_event) { + esl_event_t *event; + esl_event_dup(&event, handle.info_event); + return new ESLevent(event, 1); + } + + return NULL; +} + +int ESLconnection::setAsyncExecute(const char *val) +{ + if (val) { + handle.async_execute = esl_true(val); + } + return handle.async_execute; +} + +int ESLconnection::setEventLock(const char *val) +{ + if (val) { + handle.event_lock = esl_true(val); + } + return handle.event_lock; +} + +int ESLconnection::execute(const char *app, const char *arg, const char *uuid) +{ + return esl_execute(&handle, app, arg, uuid); +} + + +int ESLconnection::executeAsync(const char *app, const char *arg, const char *uuid) +{ + int async = handle.async_execute; + int r; + + handle.async_execute = 1; + r = esl_execute(&handle, app, arg, uuid); + handle.async_execute = async; + + return r; +} + +int ESLconnection::sendEvent(ESLevent *send_me) +{ + return esl_sendevent(&handle, send_me->event); +} + +ESLevent *ESLconnection::recvEvent() +{ + if (last_event_obj) { + delete last_event_obj; + } + + if (esl_recv_event(&handle, 1, NULL) == ESL_SUCCESS) { + esl_event_t *e = handle.last_ievent ? handle.last_ievent : handle.last_event; + if (e) { + esl_event_t *event; + esl_event_dup(&event, e); + last_event_obj = new ESLevent(event, 1); + return last_event_obj; + } + } + + last_event_obj = new ESLevent("server_disconnected"); + + return last_event_obj; +} + +ESLevent *ESLconnection::recvEventTimed(int ms) +{ + if (last_event_obj) { + delete last_event_obj; + last_event_obj = NULL; + } + + if (esl_recv_event_timed(&handle, ms, 1, NULL) == ESL_SUCCESS) { + esl_event_t *e = handle.last_ievent ? handle.last_ievent : handle.last_event; + if (e) { + esl_event_t *event; + esl_event_dup(&event, e); + last_event_obj = new ESLevent(event, 1); + return last_event_obj; + } + } + + return NULL; +} + +ESLevent *ESLconnection::filter(const char *header, const char *value) +{ + esl_status_t status = esl_filter(&handle, header, value); + + if (status == ESL_SUCCESS && handle.last_sr_event) { + esl_event_t *event; + esl_event_dup(&event, handle.last_sr_event); + return new ESLevent(event, 1); + } + + return NULL; + +} + +int ESLconnection::events(const char *etype, const char *value) +{ + esl_event_type_t type_id = ESL_EVENT_TYPE_PLAIN; + + if (!strcmp(etype, "xml")) { + type_id = ESL_EVENT_TYPE_XML; + } + + return esl_events(&handle, type_id, value); +} + +// ESLevent +/////////////////////////////////////////////////////////////////////// + +ESLevent::ESLevent(const char *type, const char *subclass_name) +{ + esl_event_types_t event_id; + + event_construct_common(); + + if (esl_name_event(type, &event_id) != ESL_SUCCESS) { + event_id = ESL_EVENT_MESSAGE; + } + + if (!esl_strlen_zero(subclass_name) && event_id != ESL_EVENT_CUSTOM) { + esl_log(ESL_LOG_WARNING, "Changing event type to custom because you specified a subclass name!\n"); + event_id = ESL_EVENT_CUSTOM; + } + + if (esl_event_create_subclass(&event, event_id, subclass_name) != ESL_SUCCESS) { + esl_log(ESL_LOG_ERROR, "Failed to create event!\n"); + event = NULL; + } + + serialized_string = NULL; + mine = 1; +} + +ESLevent::ESLevent(esl_event_t *wrap_me, int free_me) +{ + event_construct_common(); + event = wrap_me; + mine = free_me; + serialized_string = NULL; +} + + +ESLevent::ESLevent(ESLevent *me) +{ + /* workaround for silly php thing */ + event = me->event; + mine = me->mine; + serialized_string = NULL; + me->event = NULL; + me->mine = 0; + esl_safe_free(me->serialized_string); +} + +ESLevent::~ESLevent() +{ + + if (serialized_string) { + free(serialized_string); + } + + if (event && mine) { + esl_event_destroy(&event); + } +} + +const char *ESLevent::nextHeader(void) +{ + const char *name = NULL; + + if (hp) { + name = hp->name; + hp = hp->next; + } + + return name; +} + +const char *ESLevent::firstHeader(void) +{ + if (event) { + hp = event->headers; + } + + return nextHeader(); +} + +const char *ESLevent::serialize(const char *format) +{ + this_check(""); + + esl_safe_free(serialized_string); + + if (!event) { + return ""; + } + + if (esl_event_serialize(event, &serialized_string, ESL_TRUE) == ESL_SUCCESS) { + return serialized_string; + } + + return ""; + +} + +bool ESLevent::setPriority(esl_priority_t priority) +{ + this_check(false); + + if (event) { + esl_event_set_priority(event, priority); + return true; + } else { + esl_log(ESL_LOG_ERROR, "Trying to setPriority an event that does not exist!\n"); + } + return false; +} + +const char *ESLevent::getHeader(const char *header_name) +{ + this_check(""); + + if (event) { + return esl_event_get_header(event, header_name); + } else { + esl_log(ESL_LOG_ERROR, "Trying to getHeader an event that does not exist!\n"); + } + return NULL; +} + +bool ESLevent::addHeader(const char *header_name, const char *value) +{ + this_check(false); + + if (event) { + return esl_event_add_header_string(event, ESL_STACK_BOTTOM, header_name, value) == ESL_SUCCESS ? true : false; + } else { + esl_log(ESL_LOG_ERROR, "Trying to addHeader an event that does not exist!\n"); + } + + return false; +} + +bool ESLevent::delHeader(const char *header_name) +{ + this_check(false); + + if (event) { + return esl_event_del_header(event, header_name) == ESL_SUCCESS ? true : false; + } else { + esl_log(ESL_LOG_ERROR, "Trying to delHeader an event that does not exist!\n"); + } + + return false; +} + + +bool ESLevent::addBody(const char *value) +{ + this_check(false); + + if (event) { + return esl_event_add_body(event, "%s", value) == ESL_SUCCESS ? true : false; + } else { + esl_log(ESL_LOG_ERROR, "Trying to addBody an event that does not exist!\n"); + } + + return false; +} + +char *ESLevent::getBody(void) +{ + + this_check((char *)""); + + if (event) { + return esl_event_get_body(event); + } else { + esl_log(ESL_LOG_ERROR, "Trying to getBody an event that does not exist!\n"); + } + + return NULL; +} + +const char *ESLevent::getType(void) +{ + this_check(""); + + if (event) { + return esl_event_name(event->event_id); + } else { + esl_log(ESL_LOG_ERROR, "Trying to getType an event that does not exist!\n"); + } + + return (char *) "invalid"; +} diff --git a/src/libesl/esl_oop.h b/src/libesl/esl_oop.h new file mode 100644 index 00000000..840b0ef9 --- /dev/null +++ b/src/libesl/esl_oop.h @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2007, Anthony Minessale II + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name of the original author; nor the names of any contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ESL_OOP_H_ +#define _ESL_OOP_H_ +#include +#ifdef __cplusplus +extern "C" { +#endif + +#define this_check(x) do { if (!this) { esl_log(ESL_LOG_ERROR, "object is not initalized\n"); return x;}} while(0) +#define this_check_void() do { if (!this) { esl_log(ESL_LOG_ERROR, "object is not initalized\n"); return;}} while(0) + + +class ESLevent { + private: + esl_event_header_t *hp; + public: + esl_event_t *event; + char *serialized_string; + int mine; + + ESLevent(const char *type, const char *subclass_name = NULL); + ESLevent(esl_event_t *wrap_me, int free_me = 0); + ESLevent(ESLevent *me); + virtual ~ESLevent(); + const char *serialize(const char *format = NULL); + bool setPriority(esl_priority_t priority = ESL_PRIORITY_NORMAL); + const char *getHeader(const char *header_name); + char *getBody(void); + const char *getType(void); + bool addBody(const char *value); + bool addHeader(const char *header_name, const char *value); + bool delHeader(const char *header_name); + const char *firstHeader(void); + const char *nextHeader(void); +}; + + + +class ESLconnection { + private: + esl_handle_t handle; + ESLevent *last_event_obj; + public: + ESLconnection(const char *host, const char *port, const char *password); + ESLconnection(int socket); + virtual ~ESLconnection(); + int connected(); + ESLevent *getInfo(); + int send(const char *cmd); + ESLevent *sendRecv(const char *cmd); + ESLevent *api(const char *cmd, const char *arg = NULL); + ESLevent *bgapi(const char *cmd, const char *arg = NULL); + int sendEvent(ESLevent *send_me); + ESLevent *recvEvent(); + ESLevent *recvEventTimed(int ms); + ESLevent *filter(const char *header, const char *value); + int events(const char *etype, const char *value); + int execute(const char *app, const char *arg = NULL, const char *uuid = NULL); + int executeAsync(const char *app, const char *arg = NULL, const char *uuid = NULL); + int setAsyncExecute(const char *val); + int setEventLock(const char *val); + int disconnect(void); +}; + +void eslSetLogLevel(int level); + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/libesl/esl_threadmutex.c b/src/libesl/esl_threadmutex.c new file mode 100644 index 00000000..2aed18ad --- /dev/null +++ b/src/libesl/esl_threadmutex.c @@ -0,0 +1,237 @@ +/* + * Cross Platform Thread/Mutex abstraction + * Copyright(C) 2007 Michael Jerris + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so. + * + * This work is provided under this license on an "as is" basis, without warranty of any kind, + * either expressed or implied, including, without limitation, warranties that the covered code + * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire + * risk as to the quality and performance of the covered code is with you. Should any covered + * code prove defective in any respect, you (not the initial developer or any other contributor) + * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty + * constitutes an essential part of this license. No use of any covered code is authorized hereunder + * except under this disclaimer. + * + */ + +#ifdef WIN32 +/* required for TryEnterCriticalSection definition. Must be defined before windows.h include */ +#define _WIN32_WINNT 0x0400 +#endif + +#include "esl.h" +#include "esl_threadmutex.h" + +#ifdef WIN32 +#include + +#define ESL_THREAD_CALLING_CONVENTION __stdcall + +struct esl_mutex { + CRITICAL_SECTION mutex; +}; + +#else + +#include + +#define ESL_THREAD_CALLING_CONVENTION + +struct esl_mutex { + pthread_mutex_t mutex; +}; + +#endif + +struct esl_thread { +#ifdef WIN32 + void *handle; +#else + pthread_t handle; +#endif + void *private_data; + esl_thread_function_t function; + size_t stack_size; +#ifndef WIN32 + pthread_attr_t attribute; +#endif +}; + +size_t thread_default_stacksize = 0; + +void esl_thread_override_default_stacksize(size_t size) +{ + thread_default_stacksize = size; +} + +static void * ESL_THREAD_CALLING_CONVENTION thread_launch(void *args) +{ + void *exit_val; + esl_thread_t *thread = (esl_thread_t *)args; + exit_val = thread->function(thread, thread->private_data); +#ifndef WIN32 + pthread_attr_destroy(&thread->attribute); +#endif + free(thread); + + return exit_val; +} + +ESL_DECLARE(esl_status_t) esl_thread_create_detached(esl_thread_function_t func, void *data) +{ + return esl_thread_create_detached_ex(func, data, thread_default_stacksize); +} + +esl_status_t esl_thread_create_detached_ex(esl_thread_function_t func, void *data, size_t stack_size) +{ + esl_thread_t *thread = NULL; + esl_status_t status = ESL_FAIL; + + if (!func || !(thread = (esl_thread_t *)malloc(sizeof(esl_thread_t)))) { + goto done; + } + + thread->private_data = data; + thread->function = func; + thread->stack_size = stack_size; + +#if defined(WIN32) + thread->handle = (void *)_beginthreadex(NULL, (unsigned)thread->stack_size, (unsigned int (__stdcall *)(void *))thread_launch, thread, 0, NULL); + if (!thread->handle) { + goto fail; + } + CloseHandle(thread->handle); + + status = ESL_SUCCESS; + goto done; +#else + + if (pthread_attr_init(&thread->attribute) != 0) goto fail; + + if (pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) goto failpthread; + + if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) goto failpthread; + + if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) goto failpthread; + + status = ESL_SUCCESS; + goto done; + failpthread: + pthread_attr_destroy(&thread->attribute); +#endif + + fail: + if (thread) { + free(thread); + } + done: + return status; +} + + +ESL_DECLARE(esl_status_t) esl_mutex_create(esl_mutex_t **mutex) +{ + esl_status_t status = ESL_FAIL; +#ifndef WIN32 + pthread_mutexattr_t attr; +#endif + esl_mutex_t *check = NULL; + + check = (esl_mutex_t *)malloc(sizeof(**mutex)); + if (!check) + goto done; +#ifdef WIN32 + InitializeCriticalSection(&check->mutex); +#else + if (pthread_mutexattr_init(&attr)) + goto done; + + if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) + goto fail; + + if (pthread_mutex_init(&check->mutex, &attr)) + goto fail; + + goto success; + + fail: + pthread_mutexattr_destroy(&attr); + goto done; + + success: +#endif + *mutex = check; + status = ESL_SUCCESS; + + done: + return status; +} + +ESL_DECLARE(esl_status_t) esl_mutex_destroy(esl_mutex_t **mutex) +{ + esl_mutex_t *mp = *mutex; + *mutex = NULL; + if (!mp) { + return ESL_FAIL; + } +#ifdef WIN32 + DeleteCriticalSection(&mp->mutex); +#else + if (pthread_mutex_destroy(&mp->mutex)) + return ESL_FAIL; +#endif + free(mp); + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_mutex_lock(esl_mutex_t *mutex) +{ +#ifdef WIN32 + EnterCriticalSection(&mutex->mutex); +#else + if (pthread_mutex_lock(&mutex->mutex)) + return ESL_FAIL; +#endif + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_mutex_trylock(esl_mutex_t *mutex) +{ +#ifdef WIN32 + if (!TryEnterCriticalSection(&mutex->mutex)) + return ESL_FAIL; +#else + if (pthread_mutex_trylock(&mutex->mutex)) + return ESL_FAIL; +#endif + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_mutex_unlock(esl_mutex_t *mutex) +{ +#ifdef WIN32 + LeaveCriticalSection(&mutex->mutex); +#else + if (pthread_mutex_unlock(&mutex->mutex)) + return ESL_FAIL; +#endif + return ESL_SUCCESS; +} + + + + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */ diff --git a/src/libesl/esl_threadmutex.h b/src/libesl/esl_threadmutex.h new file mode 100644 index 00000000..e8373ef0 --- /dev/null +++ b/src/libesl/esl_threadmutex.h @@ -0,0 +1,58 @@ +/* + * Cross Platform Thread/Mutex abstraction + * Copyright(C) 2007 Michael Jerris + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so. + * + * This work is provided under this license on an "as is" basis, without warranty of any kind, + * either expressed or implied, including, without limitation, warranties that the covered code + * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire + * risk as to the quality and performance of the covered code is with you. Should any covered + * code prove defective in any respect, you (not the initial developer or any other contributor) + * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty + * constitutes an essential part of this license. No use of any covered code is authorized hereunder + * except under this disclaimer. + * + */ + + +#ifndef _ESL_THREADMUTEX_H +#define _ESL_THREADMUTEX_H + +#include "esl.h" + +#ifdef __cplusplus +extern "C" { +#endif /* defined(__cplusplus) */ + +typedef struct esl_mutex esl_mutex_t; +typedef struct esl_thread esl_thread_t; +typedef void *(*esl_thread_function_t) (esl_thread_t *, void *); + +ESL_DECLARE(esl_status_t) esl_thread_create_detached(esl_thread_function_t func, void *data); +esl_status_t esl_thread_create_detached_ex(esl_thread_function_t func, void *data, size_t stack_size); +void esl_thread_override_default_stacksize(size_t size); +ESL_DECLARE(esl_status_t) esl_mutex_create(esl_mutex_t **mutex); +ESL_DECLARE(esl_status_t) esl_mutex_destroy(esl_mutex_t **mutex); +ESL_DECLARE(esl_status_t) esl_mutex_lock(esl_mutex_t *mutex); +ESL_DECLARE(esl_status_t) esl_mutex_trylock(esl_mutex_t *mutex); +ESL_DECLARE(esl_status_t) esl_mutex_unlock(esl_mutex_t *mutex); + +#ifdef __cplusplus +} +#endif /* defined(__cplusplus) */ + +#endif /* defined(_ESL_THREADMUTEX_H) */ + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: + */