]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
work in progress
authorAnthony Minessale <anthony.minessale@gmail.com>
Sat, 20 Dec 2008 05:24:51 +0000 (05:24 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Sat, 20 Dec 2008 05:24:51 +0000 (05:24 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@10892 d0543943-73ff-0310-b7d9-9358b9ac24b2

libs/esl/Makefile
libs/esl/fs_cli.c
libs/esl/src/esl.c
libs/esl/src/esl_config.c [new file with mode: 0644]
libs/esl/src/include/esl.h
libs/esl/src/include/esl_config.h [new file with mode: 0644]

index e094058d55452eaafb72936d808bdf3714656204..ea4d9e2877666bb0857c4a5797a80958ddf989ce 100644 (file)
@@ -4,7 +4,7 @@ LIBEDIT_DIR=../../libs/libedit
 CFLAGS=$(INCS) -g -ggdb -I$(LIBEDIT_DIR)/src/
 MYLIB=libesl.a
 
-OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o
+OBJS=src/esl.o src/esl_event.o src/esl_threadmutex.o src/esl_config.o
 
 all: $(MYLIB) fs_cli
 
index aeddc58b1fe3c0d468dfbfc48905efaaf46b2f38..bf2ba11348ed63294fad717f377948a6ca8f031d 100644 (file)
@@ -61,14 +61,18 @@ static void *msg_thread_run(esl_thread_t *me, void *obj)
                        esl_mutex_unlock(global_mutex);
                        goto done;
                }
-
-
                if (activity && FD_ISSET(handle->sock, &rfds)) {
-                       esl_recv(handle);
+                       if (esl_recv(handle)) {
+                               running = thread_running = 0;
+                               esl_mutex_unlock(global_mutex);
+                               esl_log(ESL_LOG_WARNING, "Disconnected.\n");
+                               goto done;
+                       }
+
                        if (handle->last_event) {
                                const char *type = esl_event_get_header(handle->last_event, "content-type");
                                if (!strcasecmp(type, "log/data")) {
-                                       int level;
+                                       int level = 0;
                                        if (strstr(handle->last_event->body, "[CONSOLE]")) {
                                                level = 0;
                                        } else if (strstr(handle->last_event->body, "[ALERT]")) {
@@ -88,6 +92,10 @@ static void *msg_thread_run(esl_thread_t *me, void *obj)
                                        }
 
                                        printf("%s%s%s", COLORS[level], handle->last_event->body, ESL_SEQ_DEFAULT_COLOR);
+                               } else if (0 && !strcasecmp(type, "text/disconnect-notice")) {
+                                       running = thread_running = 0;
+                               } else {
+                                       printf("INCOMING DATA [%s]\n%s", type, handle->last_event->body);
                                }
                        }
 
@@ -106,28 +114,29 @@ static void *msg_thread_run(esl_thread_t *me, void *obj)
 
 static int process_command(esl_handle_t *handle, const char *cmd) 
 {
-       if (!strcasecmp(cmd, "exit")) {
+       if (
+               !strcasecmp(cmd, "exit") ||
+               !strcasecmp(cmd, "quit") ||
+               !strcasecmp(cmd, "bye")
+               ) {
                return -1;
        }
 
-       if (!strncasecmp(cmd, "loglevel", 8)) {
-               const char *level = cmd + 8;
-               
-               while(*level == ' ') level++;
-               if (!esl_strlen_zero(level)) {
-                       char cb[128] = "";
-                       
-                       snprintf(cb, sizeof(cb), "log %s\n\n", level);
-                       esl_mutex_lock(global_mutex);
-                       esl_send_recv(handle, cb);                      
-                       printf("%s\n", handle->last_reply);
-                       esl_mutex_unlock(global_mutex);
-               }
-
+       if (
+               !strncasecmp(cmd, "event", 5) || 
+               !strncasecmp(cmd, "noevent", 7) ||
+               !strncasecmp(cmd, "nixevent", 8) ||
+               !strncasecmp(cmd, "log", 3) || 
+               !strncasecmp(cmd, "nolog", 5) || 
+               !strncasecmp(cmd, "filter", 6)
+               ) {
+               esl_mutex_lock(global_mutex);
+               esl_send_recv(handle, cmd);                     
+               printf("%s\n", handle->last_reply);
+               esl_mutex_unlock(global_mutex);
                goto end;
        }
-
-
+       
        printf("Unknown command [%s]\n", cmd);
 
  end:
@@ -136,17 +145,35 @@ static int process_command(esl_handle_t *handle, const char *cmd)
 
 }
 
-int main(void)
+typedef struct {
+       char host[128];
+       char pass[128];
+       esl_port_t port;
+} cli_profile_t;
+
+static cli_profile_t profiles[128] = { 0 };
+static int pcount;
+
+int main(int argc, char *argv[])
 {
        esl_handle_t handle = {0};
        int count;
        const char *line;
        char cmd_str[1024] = "";
        char hfile[512] = "/tmp/fs_cli_history";
+       char cfile[512] = "/tmp/fs_cli_config";
        char *home = getenv("HOME");
-
+       esl_config_t cfg;
+       cli_profile_t *profile = &profiles[0];
+       
+       strncpy(profiles[0].host, "localhost", sizeof(profiles[0].host));
+       strncpy(profiles[0].pass, "ClueCon", sizeof(profiles[0].pass));
+       profiles[0].port = 8021;
+       pcount = 1;
+       
        if (home) {
                snprintf(hfile, sizeof(hfile), "%s/.fs_cli_history", home);
+               snprintf(cfile, sizeof(cfile), "%s/.fs_cli_config", home);
        }
        
        esl_mutex_create(&global_mutex);
@@ -155,15 +182,27 @@ int main(void)
        gethostname(hostname, sizeof(hostname));
 
        handle.debug = 0;
-       
 
-       // um ya add some command line parsing for host port and pass 
+       
+       if (esl_config_open_file(&cfg, cfile)) {
+               char *var, *val;
+               while (esl_config_next_pair(&cfg, &var, &val)) {
+                       
+               }
+               esl_config_close_file(&cfg);
+       }
 
-       if (esl_connect(&handle, "localhost", 8021, "ClueCon")) {
+       
+       if (esl_connect(&handle, profile->host, profile->port, profile->pass)) {
                printf("Error Connecting [%s]\n", handle.err);
-               goto done;
+               return -1;
        }
-       
+
+
+       if (handle.debug) {
+               esl_global_set_default_logger(7);
+       }
+               
        esl_thread_create_detached(msg_thread_run, &handle);
        
        el = el_init(__FILE__, stdout, stdout, stdout);
index 703955cac78ebc77af3f183a60ded0bae001fcce..60e7ad66c23954b92c93431b7b5c76a5cd7b6521 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <esl.h>
+#include <sys/signal.h>
 
 #ifndef HAVE_GETHOSTBYNAME_R
 extern int gethostbyname_r (const char *__name,
@@ -43,6 +44,230 @@ extern int gethostbyname_r (const char *__name,
 
 
 
+/* 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_;
+
+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_;
+
+int esl_tolower(int c)
+{
+       if ((unsigned int)c > 255)
+               return(c);
+       if (c < -1)
+               return EOF;
+       return((_esl_tolower_tab_ + 1)[c]);
+}
+
+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;
+}
+
+
+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[1024];
+       va_list ap;
+
+       if (level < 0 || level > 7) {
+               level = 7;
+       }
+       if (level > esl_log_level) {
+               return;
+       }
+       
+       fp = cut_path(file);
+
+       va_start(ap, fmt);
+
+       vsnprintf(data, sizeof(data), fmt, ap);
+
+
+       fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], file, line, func, data);
+
+       va_end(ap);
+
+}
+
+esl_logger_t esl_log = null_logger;
+
+void esl_global_set_logger(esl_logger_t logger)
+{
+       if (logger) {
+               esl_log = logger;
+       } else {
+               esl_log = null_logger;
+       }
+}
+
+void esl_global_set_default_logger(int level)
+{
+       if (level < 0 || level > 7) {
+               level = 7;
+       }
+
+       esl_log = default_logger;
+       esl_log_level = level;
+}
+
 size_t esl_url_encode(const char *url, char *buf, size_t len)
 {
        const char *p;
@@ -138,10 +363,12 @@ esl_status_t esl_connect(esl_handle_t *handle, const char *host, esl_port_t port
        rval = connect(handle->sock, (struct sockaddr *) &handle->sockaddr, sizeof(handle->sockaddr));
        
        if (rval) {
-               strerror_r(handle->errno, handle->err, sizeof(handle->err));
+               snprintf(handle->err, sizeof(handle->err), "Socket Connection Error");
                goto fail;
        }
-       
+
+       handle->connected = 1;
+
        if (esl_recv(handle)) {
                snprintf(handle->err, sizeof(handle->err), "Connection Error");
                goto fail;
@@ -171,8 +398,6 @@ esl_status_t esl_connect(esl_handle_t *handle, const char *host, esl_port_t port
                goto fail;
        }
        
-       handle->connected = 1;
-
        return ESL_SUCCESS;
 
  fail:
@@ -184,7 +409,9 @@ esl_status_t esl_connect(esl_handle_t *handle, const char *host, esl_port_t port
 esl_status_t esl_disconnect(esl_handle_t *handle)
 {
        esl_event_safe_destroy(&handle->last_event);
-       
+       esl_event_safe_destroy(&handle->last_ievent);
+       esl_event_safe_destroy(&handle->info_event);
+
        if (handle->sock != ESL_SOCK_INVALID) {
                close(handle->sock);
                handle->sock = ESL_SOCK_INVALID;
@@ -207,20 +434,29 @@ esl_status_t esl_recv(esl_handle_t *handle)
        char *col;
        char *cl;
        ssize_t len;
-
+       int zc = 0;
+       
        esl_event_safe_destroy(&handle->last_event);
        memset(handle->header_buf, 0, sizeof(handle->header_buf));
 
        c = handle->header_buf;
        beg = c;
 
-       for(;;) {
+       while(handle->connected) {
                rrval = recv(handle->sock, c, 1, 0);
 
-               if (rrval < 0) {
+               if (rrval == 0) {
+
+                       if (++zc >= 100) {
+                               esl_disconnect(handle);
+                               return ESL_FAIL;
+                       }
+               } else if (rrval < 0) {
                        strerror_r(handle->errno, handle->err, sizeof(handle->err));
                        goto fail;
-               } else if (rrval > 0) {
+               } else {
+                       zc = 0;
+                       
                        if (*c == '\n') {
                                if (++crc == 2) {
                                        break;
@@ -243,7 +479,7 @@ esl_status_t esl_recv(esl_handle_t *handle)
                                
                                if (hname && hval) {
                                        if (handle->debug > 1) {
-                                               printf("RECV HEADER [%s] = [%s]\n", hname, hval);
+                                               esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval);
                                        }
                                        esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval);
                                }
@@ -289,17 +525,84 @@ esl_status_t esl_recv(esl_handle_t *handle)
        handle->last_event = revent;
        
        if (handle->last_event) {
-               const char *reply = esl_event_get_header(handle->last_event, "reply-text");
-               if (!esl_strlen_zero(reply)) {
-                       strncpy(handle->last_reply, reply, sizeof(handle->last_reply));
+               const char *hval = esl_event_get_header(handle->last_event, "reply-text");
+
+               if (!esl_strlen_zero(hval)) {
+                       strncpy(handle->last_reply, hval, sizeof(handle->last_reply));
                }
+
+               hval = esl_event_get_header(handle->last_event, "content-type");
+
+               if (!esl_strlen_zero(hval) && !strcasecmp(hval, "text/event-plain") && handle->last_event->body) {
+                       const char *en;
+                       esl_event_types_t et = ESL_EVENT_COMMAND;
+                       char *body = strdup(handle->last_event->body);
+                       char *beg;
+                       char *hname, *hval;
+                       char *col;
+                       char *cl;
+                       ssize_t len;
+                       char *c;
+                       
+                       esl_event_safe_destroy(&handle->last_ievent);
+
+                       if ((en = esl_stristr("event-name:", body))) {
+                               en++;
+                               while(*en == ' ') en++;
+                               if (en) {
+                                       esl_name_event(en, &et);
+                               }
+                       }
+                       
+                       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);
+
+                                       if (handle->debug > 1) {
+                                               esl_log(ESL_LOG_DEBUG, "RECV INNER HEADER [%s] = [%s]\n", hname, hval);
+                                       }
+                                       esl_event_add_header_string(handle->last_ievent, ESL_STACK_BOTTOM, hname, hval);
+                               }
+                               
+                               beg = c + 1;
+                       }
+
+                       free(body);
+
+                       if (handle->debug) {
+                               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 (handle->debug) {
                char *foo;
                esl_event_serialize(handle->last_event, &foo, ESL_FALSE);
-               printf("RECV MESSAGE\n%s\n", foo);
+               esl_log(ESL_LOG_DEBUG, "RECV MESSAGE\n%s\n", foo);
                free(foo);
        }
 
@@ -314,11 +617,17 @@ esl_status_t esl_recv(esl_handle_t *handle)
 
 esl_status_t esl_send(esl_handle_t *handle, const char *cmd)
 {
+       const char *e = cmd + strlen(cmd) -1;
+       
        if (handle->debug) {
-               printf("SEND\n%s\n", cmd);
+               esl_log(ESL_LOG_DEBUG, "SEND\n%s\n", cmd);
        }
        
        send(handle->sock, cmd, strlen(cmd), 0);
+
+       if (!(*e == '\n' && *(e-1) == '\n')) {
+               send(handle->sock, "\n\n", 2, 0);
+       }
 }
 
 
diff --git a/libs/esl/src/esl_config.c b/libs/esl/src/esl_config.c
new file mode 100644 (file)
index 0000000..05702ff
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * 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"
+
+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 {
+               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;
+
+                       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;
+       }
+}
+
+void esl_config_close_file(esl_config_t *cfg)
+{
+
+       if (cfg->file) {
+               fclose(cfg->file);
+       }
+
+       memset(cfg, 0, sizeof(*cfg));
+}
+
+
+
+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;
+
+}
+
+int esl_config_get_cas_bits(char *strvalue, unsigned char *outbits)
+{
+       char cas_bits[5];
+       unsigned char bit = 0x8;
+       char *double_colon = strchr(strvalue, ':');
+       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);
+       int x = 0;
+       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:
+ */
index 4b71364b87feef45573144ab87d0083572aa32c7..412c4c322c72abc7b42fb5751f00470255f137cc 100644 (file)
@@ -34,6 +34,9 @@
 #ifndef _ESL_H_
 #define _ESL_H_
 
+#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;
 
@@ -204,6 +207,8 @@ typedef struct {
        char header_buf[4196];
        char last_reply[1024];
        esl_event_t *last_event;
+       esl_event_t *last_ievent;
+       esl_event_t *info_event;
        int debug;
        int connected;
 } esl_handle_t;
@@ -213,12 +218,44 @@ typedef enum {
        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, ...);
+
+extern esl_logger_t esl_log;
+
+void esl_global_set_logger(esl_logger_t logger);
+void esl_global_set_default_logger(int level);
 
 #include "esl_event.h"
 #include "esl_threadmutex.h"
+#include "esl_config.h"
 
 size_t esl_url_encode(const char *url, char *buf, size_t len);
 char *esl_url_decode(char *s);
+int esl_toupper(int c);
+int esl_tolower(int c);
+
 
 esl_status_t esl_connect(esl_handle_t *handle, const char *host, esl_port_t port, const char *password);
 esl_status_t esl_disconnect(esl_handle_t *handle);
@@ -226,7 +263,6 @@ esl_status_t esl_send(esl_handle_t *handle, const char *cmd);
 esl_status_t esl_recv(esl_handle_t *handle);
 esl_status_t esl_send_recv(esl_handle_t *handle, const char *cmd);
 
-
 #endif
 
 
diff --git a/libs/esl/src/include/esl_config.h b/libs/esl/src/include/esl_config.h
new file mode 100644 (file)
index 0000000..934db15
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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
+ * 
+ * <pre>
+ *
+ * EXAMPLE 
+ * 
+ * [category1]
+ * var1 => val1
+ * var2 => val2
+ * \# lines that begin with \# are comments
+ * \#var3 => val3
+ * </pre>
+ * @{
+ */
+
+#ifndef ESL_CONFIG_H
+#define ESL_CONFIG_H
+
+#include "esl.h"
+#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
+
+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
+*/
+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
+*/
+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
+*/
+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
+*/
+int esl_config_get_cas_bits(char *strvalue, unsigned char *outbits);
+
+
+/** @} */
+#endif
+/* 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:
+ */