]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add ozmod_libpri and framework for per module api commands like FS has, mikej probabl...
authorAnthony Minessale <anthony.minessale@gmail.com>
Sat, 7 Feb 2009 23:14:25 +0000 (23:14 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Sat, 7 Feb 2009 23:14:25 +0000 (23:14 +0000)
git-svn-id: http://svn.openzap.org/svn/openzap/trunk@653 a93c3328-9c30-0410-af19-c9cd2b2d52af

libs/openzap/Makefile.am
libs/openzap/mod_openzap/mod_openzap.c
libs/openzap/src/include/openzap.h
libs/openzap/src/include/zap_types.h
libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c [new file with mode: 0644]
libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h [new file with mode: 0644]
libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c [new file with mode: 0644]
libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h [new file with mode: 0644]
libs/openzap/src/zap_io.c

index dba1a1e1879058bc7ae0a34f802cb2da7c8f96d0..5a4d4774d8f482d29bb056729c4c4209651fce9a 100644 (file)
@@ -130,7 +130,7 @@ install-data-local:
        @[ -f "$(DESTDIR)$(PREFIX)/conf/openzap.conf" ] || ( cp conf/*.conf $(DESTDIR)$(PREFIX)/conf)
        @echo OpenZAP Installed
 
-mod_LTLIBRARIES = ozmod_zt.la ozmod_skel.la ozmod_wanpipe.la ozmod_isdn.la ozmod_analog.la ozmod_analog_em.la ozmod_ss7_boost.la #ozmod_libpri.la
+mod_LTLIBRARIES = ozmod_zt.la ozmod_skel.la ozmod_wanpipe.la ozmod_isdn.la ozmod_analog.la ozmod_analog_em.la ozmod_ss7_boost.la ozmod_libpri.la
 ozmod_zt_la_SOURCES = $(SRC)/ozmod/ozmod_zt/ozmod_zt.c
 ozmod_zt_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
 ozmod_zt_la_LDFLAGS = -module
@@ -193,8 +193,8 @@ ozmod_ss7_boost_la_LDFLAGS = -module
 ozmod_ss7_boost_la_LIBADD = $(MYLIB)
 
 if LIBPRI
-#ozmod_libpri_la_SOURCES = $(SRC)/ozmod/ozmod_libpri/ozmod_libpri.c
-#ozmod_libpri_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
-#ozmod_libpri_la_LDFLAGS = -module -lpri
-#ozmod_libpri_la_LIBADD = $(MYLIB)
+ozmod_libpri_la_SOURCES = $(SRC)/ozmod/ozmod_libpri/ozmod_libpri.c $(SRC)/ozmod/ozmod_libpri/lpwrap_pri.c
+ozmod_libpri_la_CFLAGS = $(AM_CFLAGS) $(MY_CFLAGS)
+ozmod_libpri_la_LDFLAGS = -module -lpri
+ozmod_libpri_la_LIBADD = $(MYLIB)
 endif
index 5ecaa981439652063598eae451e1e111832a555f..6b941616ed8851c116ae820a7461d486693b3dc1 100644 (file)
@@ -545,6 +545,7 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
        int total_to;
        int chunk, do_break = 0;
 
+
        channel = switch_core_session_get_channel(session);
        assert(channel != NULL);
        
@@ -634,11 +635,9 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch
                        }
                }
        }
-
        return SWITCH_STATUS_SUCCESS;
 
  fail:
-       
        switch_clear_flag_locked(tech_pvt, TFLAG_IO);
        return SWITCH_STATUS_GENERR;
        
@@ -1926,6 +1925,101 @@ static switch_status_t load_config(void)
                }
        }
 
+
+
+       if ((spans = switch_xml_child(cfg, "libpri_spans"))) {
+               for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
+                       char *id = (char *) switch_xml_attr(myspan, "id");
+                       char *name = (char *) switch_xml_attr(myspan, "name");
+                       zap_status_t zstatus = ZAP_FAIL;
+                       const char *context = "default";
+                       const char *dialplan = "XML";
+                       
+                       const char *o_node = "cpe";
+                       const char *o_switch = "dms100";
+                       const char *o_dp = "unknown";
+                       const char *o_l1 = "ulaw";
+                       const char *o_debug = NULL;
+
+                       
+                       uint32_t span_id = 0;
+                       zap_span_t *span = NULL;
+                       uint32_t opts = 0;
+                       
+                       for (param = switch_xml_child(myspan, "param"); param; param = param->next) {
+                               char *var = (char *) switch_xml_attr_soft(param, "name");
+                               char *val = (char *) switch_xml_attr_soft(param, "value");
+
+                               if (!strcasecmp(var, "node")) {
+                                       o_node = val;
+                               } else if (!strcasecmp(var, "switch")) {
+                                       o_switch = val;
+                               } else if (!strcasecmp(var, "dp")) {
+                                       o_dp = val;
+                               } else if (!strcasecmp(var, "l1")) {
+                                       o_l1 = val;
+                               } else if (!strcasecmp(var, "debug")) {
+                                       o_debug = val;
+                               } else if (!strcasecmp(var, "context")) {
+                                       context = val;
+                               } else if (!strcasecmp(var, "suggest-channel") && switch_true(val)) {
+                                       opts |= 1;
+                               } else if (!strcasecmp(var, "dialplan")) {
+                                       dialplan = val;
+                               }
+                       }
+       
+                       if (!id && !name) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "span missing required param 'id'\n");
+                               continue;
+                       }
+                       
+                       if (name) {
+                               zstatus = zap_span_find_by_name(name, &span);
+                       } else {
+                               if (switch_is_number(id)) {
+                                       span_id = atoi(id);
+                                       zstatus = zap_span_find(span_id, &span);
+                               }
+
+                               if (zstatus != ZAP_SUCCESS) {
+                                       zstatus = zap_span_find_by_name(id, &span);
+                               }
+                       }
+
+                       if (zstatus != ZAP_SUCCESS) {
+                               zap_log(ZAP_LOG_ERROR, "Error finding OpenZAP span id:%s name:%s\n", switch_str_nil(id), switch_str_nil(name));
+                               continue;
+                       }
+
+                       if (!span_id) {
+                               span_id = span->span_id;
+                       }
+                       
+                       
+                       if (zap_configure_span("libpri", span, on_clear_channel_signal, 
+                                                                  "node", o_node,
+                                                                  "switch", o_switch,
+                                                                  "dp", o_dp,
+                                                                  "l1", o_l1,
+                                                                  "debug", o_debug,
+                                                                  "opts", opts,
+                                                                  TAG_END) != ZAP_SUCCESS) {
+                               zap_log(ZAP_LOG_ERROR, "Error starting OpenZAP span %d node: %s switch: %s dp: %s l1: %s debug: %s error: %s\n", 
+                                               span_id, switch_str_nil(o_node), switch_str_nil(o_switch), switch_str_nil(o_dp), switch_str_nil(o_l1), switch_str_nil(o_debug),
+                                               span->last_error);
+                               continue;
+                       }
+
+                       SPAN_CONFIG[span->span_id].span = span;
+                       switch_copy_string(SPAN_CONFIG[span->span_id].context, context, sizeof(SPAN_CONFIG[span->span_id].context));
+                       switch_copy_string(SPAN_CONFIG[span->span_id].dialplan, dialplan, sizeof(SPAN_CONFIG[span->span_id].dialplan));
+                       switch_copy_string(SPAN_CONFIG[span->span_id].type, "isdn", sizeof(SPAN_CONFIG[span->span_id].type));
+
+                       zap_span_start(span);
+               }
+       }
+
        if ((spans = switch_xml_child(cfg, "boost_spans"))) {
                for (myspan = switch_xml_child(spans, "span"); myspan; myspan = myspan->next) {
                        char *id = (char *) switch_xml_attr(myspan, "id");
@@ -2292,7 +2386,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_openzap_load)
 SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_openzap_shutdown)
 {
        zap_global_destroy();
-       return SWITCH_STATUS_NOUNLOAD;
+
+       // this breaks pika but they are MIA so *shrug*
+       //return SWITCH_STATUS_NOUNLOAD;
+       return SWITCH_STATUS_SUCCESS;
 }
 
 /* For Emacs:
index e0974326ca8d110de2e750b4fe6f0c32754a8247..2b078e603ed78e0e16d5a532e69d5e0fc9c8506d 100644 (file)
@@ -287,6 +287,31 @@ typedef enum {
 #define zap_socket_close(it) if (it > -1) { close(it); it = -1;}
 
 
+struct zap_stream_handle {
+       zap_stream_handle_write_function_t write_function;
+       zap_stream_handle_raw_write_function_t raw_write_function;
+       void *data;
+       void *end;
+       zap_size_t data_size;
+       zap_size_t data_len;
+       zap_size_t alloc_len;
+       zap_size_t alloc_chunk;
+};
+
+zap_status_t zap_console_stream_raw_write(zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen);
+zap_status_t zap_console_stream_write(zap_stream_handle_t *handle, const char *fmt, ...);
+
+#define ZAP_CMD_CHUNK_LEN 1024
+#define ZAP_STANDARD_STREAM(s) memset(&s, 0, sizeof(s)); s.data = malloc(ZAP_CMD_CHUNK_LEN); \
+       switch_assert(s.data);                                                                                          \
+       memset(s.data, 0, SWITCH_CMD_CHUNK_LEN);                                                        \
+       s.end = s.data;                                                                                                         \
+       s.data_size = ZAP_CMD_CHUNK_LEN;                                                                        \
+       s.write_function = zap_console_stream_write;                                            \
+       s.raw_write_function = zap_console_stream_raw_write;                            \
+       s.alloc_len = ZAP_CMD_CHUNK_LEN;                                                                        \
+       s.alloc_chunk = ZAP_CMD_CHUNK_LEN
+
 struct zap_event {
        zap_event_type_t e_type;
        uint32_t enum_id;
@@ -444,6 +469,7 @@ struct zap_channel {
        uint8_t fsk_buf[80];
        uint32_t ring_count;
        void *mod_data;
+       void *call_data;
        struct zap_caller_data caller_data;
        struct zap_span *span;
        struct zap_io_interface *zio;
@@ -511,6 +537,7 @@ struct zap_io_interface {
        zio_write_t write;
        zio_span_poll_event_t poll_event;
        zio_span_next_event_t next_event;
+       zio_api_t api;
 };
 
 
index 28fd127fbf32f22d6369a7e501b8b86c285663e0..0aca99908022c40ed5d3b01d403121f54df57b8c 100644 (file)
@@ -397,6 +397,10 @@ typedef struct zap_sigmsg zap_sigmsg_t;
 typedef struct zap_span zap_span_t;
 typedef struct zap_caller_data zap_caller_data_t;
 typedef struct zap_io_interface zap_io_interface_t;
+typedef struct zap_stream_handle zap_stream_handle_t;
+
+typedef zap_status_t (*zap_stream_handle_write_function_t) (zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen);
+typedef zap_status_t (*zap_stream_handle_raw_write_function_t) (zap_stream_handle_t *handle, const char *fmt, ...);
 
 #define ZIO_CHANNEL_REQUEST_ARGS (zap_span_t *span, uint32_t chan_id, zap_direction_t direction, zap_caller_data_t *caller_data, zap_channel_t **zchan)
 #define ZIO_CHANNEL_OUTGOING_CALL_ARGS (zap_channel_t *zchan)
@@ -421,6 +425,7 @@ typedef struct zap_io_interface zap_io_interface_t;
 #define ZIO_SIG_LOAD_ARGS (void)
 #define ZIO_SIG_CONFIGURE_ARGS (zap_span_t *span, zio_signal_cb_t sig_cb, va_list ap)
 #define ZIO_SIG_UNLOAD_ARGS (void)
+#define ZIO_API_ARGS (zap_stream_handle_t *stream, const char *data)
 
 typedef zap_status_t (*zio_channel_request_t) ZIO_CHANNEL_REQUEST_ARGS ;
 typedef zap_status_t (*zio_channel_outgoing_call_t) ZIO_CHANNEL_OUTGOING_CALL_ARGS ;
@@ -445,6 +450,8 @@ typedef zap_status_t (*zio_sig_load_t) ZIO_SIG_LOAD_ARGS ;
 typedef zap_status_t (*zio_sig_configure_t) ZIO_SIG_CONFIGURE_ARGS ;
 typedef zap_status_t (*zio_io_unload_t) ZIO_IO_UNLOAD_ARGS ;
 typedef zap_status_t (*zio_sig_unload_t) ZIO_SIG_UNLOAD_ARGS ;
+typedef zap_status_t (*zio_api_t) ZIO_API_ARGS ;
+
 
 #define ZIO_CHANNEL_REQUEST_FUNCTION(name) zap_status_t name ZIO_CHANNEL_REQUEST_ARGS
 #define ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(name) zap_status_t name ZIO_CHANNEL_OUTGOING_CALL_ARGS
@@ -469,9 +476,12 @@ typedef zap_status_t (*zio_sig_unload_t) ZIO_SIG_UNLOAD_ARGS ;
 #define ZIO_SIG_CONFIGURE_FUNCTION(name) zap_status_t name ZIO_SIG_CONFIGURE_ARGS
 #define ZIO_IO_UNLOAD_FUNCTION(name) zap_status_t name ZIO_IO_UNLOAD_ARGS
 #define ZIO_SIG_UNLOAD_FUNCTION(name) zap_status_t name ZIO_SIG_UNLOAD_ARGS
+#define ZIP_API_FUNCTION(name) zap_status_t name ZIO_API_ARGS
 
 #include "zap_dso.h"
 
+
+
 typedef struct {
        char name[256];
        zio_io_load_t io_load;
diff --git a/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c b/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.c
new file mode 100644 (file)
index 0000000..3b227c3
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2009, 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 "openzap.h"
+#include "lpwrap_pri.h"
+#ifndef HAVE_GETTIMEOFDAY
+
+#ifdef WIN32
+#include <mmsystem.h>
+
+static __inline int gettimeofday(struct timeval *tp, void *nothing)
+{
+#ifdef WITHOUT_MM_LIB
+       SYSTEMTIME st;
+       time_t tt;
+       struct tm tmtm;
+       /* mktime converts local to UTC */
+       GetLocalTime (&st);
+       tmtm.tm_sec = st.wSecond;
+       tmtm.tm_min = st.wMinute;
+       tmtm.tm_hour = st.wHour;
+       tmtm.tm_mday = st.wDay;
+       tmtm.tm_mon = st.wMonth - 1;
+       tmtm.tm_year = st.wYear - 1900;  tmtm.tm_isdst = -1;
+       tt = mktime (&tmtm);
+       tp->tv_sec = tt;
+       tp->tv_usec = st.wMilliseconds * 1000;
+#else
+       /**
+        ** The earlier time calculations using GetLocalTime
+        ** had a time resolution of 10ms.The timeGetTime, part
+        ** of multimedia apis offer a better time resolution
+        ** of 1ms.Need to link against winmm.lib for this
+        **/
+       unsigned long Ticks = 0;
+       unsigned long Sec =0;
+       unsigned long Usec = 0;
+       Ticks = timeGetTime();
+
+       Sec = Ticks/1000;
+       Usec = (Ticks - (Sec*1000))*1000;
+       tp->tv_sec = Sec;
+       tp->tv_usec = Usec;
+#endif /* WITHOUT_MM_LIB */
+       (void)nothing;
+       return 0;
+}
+#endif /* WIN32 */
+#endif /* HAVE_GETTIMEOFDAY */
+
+static struct lpwrap_pri_event_list LPWRAP_PRI_EVENT_LIST[] = {
+       {0, LPWRAP_PRI_EVENT_ANY, "ANY"},
+       {1, LPWRAP_PRI_EVENT_DCHAN_UP, "DCHAN_UP"},
+       {2, LPWRAP_PRI_EVENT_DCHAN_DOWN, "DCHAN_DOWN"},
+       {3, LPWRAP_PRI_EVENT_RESTART, "RESTART"},
+       {4, LPWRAP_PRI_EVENT_CONFIG_ERR, "CONFIG_ERR"},
+       {5, LPWRAP_PRI_EVENT_RING, "RING"},
+       {6, LPWRAP_PRI_EVENT_HANGUP, "HANGUP"},
+       {7, LPWRAP_PRI_EVENT_RINGING, "RINGING"},
+       {8, LPWRAP_PRI_EVENT_ANSWER, "ANSWER"},
+       {9, LPWRAP_PRI_EVENT_HANGUP_ACK, "HANGUP_ACK"},
+       {10, LPWRAP_PRI_EVENT_RESTART_ACK, "RESTART_ACK"},
+       {11, LPWRAP_PRI_EVENT_FACNAME, "FACNAME"},
+       {12, LPWRAP_PRI_EVENT_INFO_RECEIVED, "INFO_RECEIVED"},
+       {13, LPWRAP_PRI_EVENT_PROCEEDING, "PROCEEDING"},
+       {14, LPWRAP_PRI_EVENT_SETUP_ACK, "SETUP_ACK"},
+       {15, LPWRAP_PRI_EVENT_HANGUP_REQ, "HANGUP_REQ"},
+       {16, LPWRAP_PRI_EVENT_NOTIFY, "NOTIFY"},
+       {17, LPWRAP_PRI_EVENT_PROGRESS, "PROGRESS"},
+       {18, LPWRAP_PRI_EVENT_KEYPAD_DIGIT, "KEYPAD_DIGIT"}
+};
+
+#define LINE "--------------------------------------------------------------------------------"
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id)
+{ 
+       return LPWRAP_PRI_EVENT_LIST[event_id].name;
+}
+
+static int __pri_lpwrap_read(struct pri *pri, void *buf, int buflen)
+{
+       struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+       zap_size_t len = buflen;
+       int res;
+
+       if (zap_channel_read(spri->zdchan, buf, &len) != ZAP_SUCCESS) {
+               printf("D-READ FAIL! [%s]\n", spri->zdchan->last_error);
+               return 0;
+       }
+       res = (int)len;
+       memset(&((unsigned char*)buf)[res],0,2);
+       res+=2;
+
+       //print_bits(buf, res-2, bb, sizeof(bb), 1, 0);
+       //zap_log(ZAP_LOG_DEBUG, "READ %d\n%s\n%s\n\n", res-2, LINE, bb);
+
+       return res;
+}
+
+static int __pri_lpwrap_write(struct pri *pri, void *buf, int buflen)
+{
+       struct lpwrap_pri *spri = (struct lpwrap_pri *) pri_get_userdata(pri);
+       zap_size_t len = buflen -2;
+
+       if (zap_channel_write(spri->zdchan, buf, buflen, &len) != ZAP_SUCCESS) {
+               printf("D-WRITE FAIL! [%s]\n", spri->zdchan->last_error);
+        return 0;
+       }
+       
+       //print_bits(buf, (int)buflen-2, bb, sizeof(bb), 1, 0);
+       //zap_log(ZAP_LOG_DEBUG, "WRITE %d\n%s\n%s\n\n", (int)buflen-2, LINE, bb);
+
+       return (int) buflen;
+}
+
+int lpwrap_init_pri(struct lpwrap_pri *spri, int span, zap_channel_t *dchan, int swtype, int node, int debug)
+{
+       int ret = -1;
+
+       memset(spri, 0, sizeof(struct lpwrap_pri));
+       
+       spri->zdchan = dchan;
+
+       if ((spri->pri = pri_new_cb(spri->zdchan->sockfd, node, swtype, __pri_lpwrap_read, __pri_lpwrap_write, spri))){
+               spri->span = span;
+               pri_set_debug(spri->pri, debug);
+               ret = 0;
+       } else {
+               fprintf(stderr, "Unable to create PRI\n");
+       }
+
+       return ret;
+}
+
+
+int lpwrap_one_loop(struct lpwrap_pri *spri)
+{
+       fd_set rfds, efds;
+       struct timeval now = {0,0}, *next;
+       pri_event *event;
+    int sel;
+       
+       if (spri->on_loop) {
+               spri->on_loop(spri);
+       }
+
+       FD_ZERO(&rfds);
+       FD_ZERO(&efds);
+
+#ifdef _MSC_VER
+       //Windows macro for FD_SET includes a warning C4127: conditional expression is constant
+#pragma warning(push)
+#pragma warning(disable:4127)
+#endif
+
+       FD_SET(pri_fd(spri->pri), &rfds);
+       FD_SET(pri_fd(spri->pri), &efds);
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+       now.tv_sec = 0;
+       now.tv_usec = 100000;
+
+       sel = select(pri_fd(spri->pri) + 1, &rfds, NULL, &efds, &now);
+
+       event = NULL;
+
+       if (!sel) {
+               if ((next = pri_schedule_next(spri->pri))) {
+                       gettimeofday(&now, NULL);
+                       if (now.tv_sec >= next->tv_sec && (now.tv_usec >= next->tv_usec || next->tv_usec <= 100000)) {
+                               //zap_log(ZAP_LOG_DEBUG, "Check event\n");
+                               event = pri_schedule_run(spri->pri);
+                       }
+               }
+       } else if (sel > 0) {
+               event = pri_check_event(spri->pri);
+       }
+
+       if (event) {
+               event_handler handler;
+               /* 0 is catchall event handler */
+               if ((handler = spri->eventmap[event->e] ? spri->eventmap[event->e] : spri->eventmap[0] ? spri->eventmap[0] : NULL)) {
+                       handler(spri, event->e, event);
+               } else {
+                       zap_log(ZAP_LOG_CRIT, "No event handler found for event %d.\n", event->e);
+               }
+       }
+
+       return sel;
+}
+
+int lpwrap_run_pri(struct lpwrap_pri *spri)
+{
+       int ret = 0;
+
+       for (;;){
+               ret=lpwrap_one_loop(spri);
+               if (ret < 0){
+
+#ifndef WIN32 //This needs to be adressed fror WIN32 still
+                       if (errno == EINTR){
+                               /* Igonore an interrupted system call */
+                               continue;
+                       }
+#endif 
+                       printf("Error = %i\n",ret);
+                       perror("Lpwrap Run Pri: ");
+                       break;          
+               }
+       }
+
+       return ret;
+
+}
+
+/* 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/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h b/libs/openzap/src/ozmod/ozmod_libpri/lpwrap_pri.h
new file mode 100644 (file)
index 0000000..9333e3a
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2009, 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 _LPWRAP_PRI_H
+#define _LPWRAP_PRI_H
+#include <libpri.h>
+#include <openzap.h>
+
+
+#define LPWRAP_MAX_CHAN_PER_SPAN 32
+
+typedef enum {
+       LPWRAP_PRI_EVENT_ANY = 0,
+       LPWRAP_PRI_EVENT_DCHAN_UP = PRI_EVENT_DCHAN_UP,
+       LPWRAP_PRI_EVENT_DCHAN_DOWN = PRI_EVENT_DCHAN_DOWN,
+       LPWRAP_PRI_EVENT_RESTART = PRI_EVENT_RESTART,
+       LPWRAP_PRI_EVENT_CONFIG_ERR = PRI_EVENT_CONFIG_ERR,
+       LPWRAP_PRI_EVENT_RING = PRI_EVENT_RING,
+       LPWRAP_PRI_EVENT_HANGUP = PRI_EVENT_HANGUP,
+       LPWRAP_PRI_EVENT_RINGING = PRI_EVENT_RINGING,
+       LPWRAP_PRI_EVENT_ANSWER = PRI_EVENT_ANSWER,
+       LPWRAP_PRI_EVENT_HANGUP_ACK = PRI_EVENT_HANGUP_ACK,
+       LPWRAP_PRI_EVENT_RESTART_ACK = PRI_EVENT_RESTART_ACK,
+       LPWRAP_PRI_EVENT_FACNAME = PRI_EVENT_FACNAME,
+       LPWRAP_PRI_EVENT_INFO_RECEIVED = PRI_EVENT_INFO_RECEIVED,
+       LPWRAP_PRI_EVENT_PROCEEDING = PRI_EVENT_PROCEEDING,
+       LPWRAP_PRI_EVENT_SETUP_ACK = PRI_EVENT_SETUP_ACK,
+       LPWRAP_PRI_EVENT_HANGUP_REQ = PRI_EVENT_HANGUP_REQ,
+       LPWRAP_PRI_EVENT_NOTIFY = PRI_EVENT_NOTIFY,
+       LPWRAP_PRI_EVENT_PROGRESS = PRI_EVENT_PROGRESS,
+       LPWRAP_PRI_EVENT_KEYPAD_DIGIT = PRI_EVENT_KEYPAD_DIGIT
+} lpwrap_pri_event_t;
+
+typedef enum {
+       LPWRAP_PRI_NETWORK = PRI_NETWORK,
+       LPWRAP_PRI_CPE = PRI_CPE
+} lpwrap_pri_node_t;
+
+typedef enum {
+       LPWRAP_PRI_SWITCH_UNKNOWN = PRI_SWITCH_UNKNOWN,
+       LPWRAP_PRI_SWITCH_NI2 = PRI_SWITCH_NI2,                 
+       LPWRAP_PRI_SWITCH_DMS100 = PRI_SWITCH_DMS100,
+       LPWRAP_PRI_SWITCH_LUCENT5E = PRI_SWITCH_LUCENT5E,
+       LPWRAP_PRI_SWITCH_ATT4ESS = PRI_SWITCH_ATT4ESS,
+       LPWRAP_PRI_SWITCH_EUROISDN_E1 = PRI_SWITCH_EUROISDN_E1,
+       LPWRAP_PRI_SWITCH_EUROISDN_T1 = PRI_SWITCH_EUROISDN_T1,
+       LPWRAP_PRI_SWITCH_NI1 = PRI_SWITCH_NI1,
+       LPWRAP_PRI_SWITCH_GR303_EOC = PRI_SWITCH_GR303_EOC,
+       LPWRAP_PRI_SWITCH_GR303_TMC = PRI_SWITCH_GR303_TMC,
+       LPWRAP_PRI_SWITCH_QSIG = PRI_SWITCH_QSIG
+} lpwrap_pri_switch_t;
+
+typedef enum {
+       LPWRAP_PRI_READY = (1 << 0)
+} lpwrap_pri_flag_t;
+
+struct lpwrap_pri;
+typedef int (*event_handler)(struct lpwrap_pri *, lpwrap_pri_event_t, pri_event *);
+typedef int (*loop_handler)(struct lpwrap_pri *);
+#define MAX_EVENT 18
+
+struct lpwrap_pri {
+       struct pri *pri;
+       int span;
+       int dchan;
+       unsigned int flags;
+       void *private_info;
+       event_handler eventmap[MAX_EVENT+1];
+       loop_handler on_loop;
+       zap_channel_t *zdchan;
+};
+
+typedef struct lpwrap_pri lpwrap_pri_t;
+
+struct lpwrap_pri_event_list {
+       int event_id;
+       int pri_event;
+       const char *name;
+};
+
+
+
+#define LPWRAP_MAP_PRI_EVENT(spri, event, func) spri.eventmap[event] = func;
+
+const char *lpwrap_pri_event_str(lpwrap_pri_event_t event_id);
+int lpwrap_one_loop(struct lpwrap_pri *spri);
+int lpwrap_init_pri(struct lpwrap_pri *spri, int span, zap_channel_t *dchan, int swtype, int node, int debug);
+int lpwrap_run_pri(struct lpwrap_pri *spri);
+
+#endif
diff --git a/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c b/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.c
new file mode 100644 (file)
index 0000000..d80960d
--- /dev/null
@@ -0,0 +1,805 @@
+/*
+ * 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 "openzap.h"
+#include "ozmod_libpri.h"
+
+static ZIO_IO_UNLOAD_FUNCTION(zap_libpri_unload)
+{
+       return ZAP_SUCCESS;
+}
+
+static ZIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
+{
+       zap_status_t status = ZAP_SUCCESS;
+       zap_set_flag(zchan, ZAP_CHANNEL_OUTBOUND);
+       zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DIALING);
+       return status;
+}
+
+static ZIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
+{
+       return ZAP_FAIL;
+
+}
+
+#ifdef WIN32
+static void s_pri_error(char *s)
+#else
+static void s_pri_error(struct pri *pri, char *s)
+#endif
+{
+
+       zap_log(ZAP_LOG_ERROR, "%s", s);
+
+}
+
+#ifdef WIN32
+static void s_pri_message(char *s)
+{
+       zap_log(ZAP_LOG_DEBUG, "%s", s);
+}
+#else
+static void s_pri_message(struct pri *pri, char *s)
+{
+       zap_log(ZAP_LOG_DEBUG, "%s", s);
+}
+#endif
+
+static ZIO_SIG_LOAD_FUNCTION(zap_libpri_init)
+{
+       pri_set_error(s_pri_error);
+       pri_set_message(s_pri_message);
+
+       return ZAP_SUCCESS;
+}
+
+
+static zap_state_map_t isdn_state_map = {
+       {
+               {
+                       ZSD_OUTBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_ANY_STATE},
+                       {ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+               },
+               {
+                       ZSD_OUTBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+                       {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+               },
+               {
+                       ZSD_OUTBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+                       {ZAP_CHANNEL_STATE_DIALING, ZAP_END}
+               },
+               {
+                       ZSD_OUTBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_DIALING, ZAP_END},
+                       {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_UP, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+               },
+               {
+                       ZSD_OUTBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_PROGRESS, ZAP_END},
+                       {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_UP, ZAP_END}
+               },
+               {
+                       ZSD_OUTBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+                       {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+               },
+               {
+                       ZSD_OUTBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+                       {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+               },
+               {
+                       ZSD_OUTBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_UP, ZAP_END},
+                       {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+               },
+
+               /****************************************/
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_ANY_STATE},
+                       {ZAP_CHANNEL_STATE_RESTART, ZAP_END}
+               },
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_RESTART, ZAP_END},
+                       {ZAP_CHANNEL_STATE_DOWN, ZAP_END}
+               },
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+                       {ZAP_CHANNEL_STATE_DIALTONE, ZAP_CHANNEL_STATE_RING, ZAP_END}
+               },
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_DIALTONE, ZAP_END},
+                       {ZAP_CHANNEL_STATE_RING, ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END}
+               },
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_RING, ZAP_END},
+                       {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_CHANNEL_STATE_UP, ZAP_END}
+               },
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+                       {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+               },
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_HANGUP_COMPLETE, ZAP_END},
+                       {ZAP_CHANNEL_STATE_DOWN, ZAP_END},
+               },
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_PROGRESS, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, ZAP_END},
+                       {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_CHANNEL_STATE_PROGRESS_MEDIA, 
+                        ZAP_CHANNEL_STATE_CANCEL, ZAP_CHANNEL_STATE_UP, ZAP_END},
+               },
+               {
+                       ZSD_INBOUND,
+                       ZSM_UNACCEPTABLE,
+                       {ZAP_CHANNEL_STATE_UP, ZAP_END},
+                       {ZAP_CHANNEL_STATE_HANGUP, ZAP_CHANNEL_STATE_TERMINATING, ZAP_END},
+               },
+               
+
+       }
+};
+
+
+
+
+
+static __inline__ void state_advance(zap_channel_t *zchan)
+{
+       //Q931mes_Generic *gen = (Q931mes_Generic *) zchan->caller_data.raw_data;
+       zap_libpri_data_t *isdn_data = zchan->span->signal_data;
+       zap_status_t status;
+       zap_sigmsg_t sig;
+       q931_call *call = (q931_call *) zchan->call_data;
+       
+       
+       zap_log(ZAP_LOG_DEBUG, "%d:%d STATE [%s]\n", 
+                       zchan->span_id, zchan->chan_id, zap_channel_state2str(zchan->state));
+
+
+       if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND) && !call) {
+               zap_log(ZAP_LOG_WARNING, "NO CALL!!!!\n");
+       }
+
+       
+       memset(&sig, 0, sizeof(sig));
+       sig.chan_id = zchan->chan_id;
+       sig.span_id = zchan->span_id;
+       sig.channel = zchan;
+
+
+       switch (zchan->state) {
+       case ZAP_CHANNEL_STATE_DOWN:
+               {
+                       zchan->call_data = NULL;
+                       zap_channel_done(zchan);                        
+               }
+               break;
+       case ZAP_CHANNEL_STATE_PROGRESS:
+               {
+                       if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+                               sig.event_id = ZAP_SIGEVENT_PROGRESS;
+                               if ((status = isdn_data->sig_cb(&sig) != ZAP_SUCCESS)) {
+                                       zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+                               }
+                       } else if (call) {
+                               pri_progress(isdn_data->spri.pri, call, zchan->chan_id, 0);
+                       } else {
+                               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+                       }
+               }
+               break;
+       case ZAP_CHANNEL_STATE_PROGRESS_MEDIA:
+               {
+                       if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+                               sig.event_id = ZAP_SIGEVENT_PROGRESS_MEDIA;
+                               if ((status = isdn_data->sig_cb(&sig) != ZAP_SUCCESS)) {
+                                       zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+                               }
+                       } else if (call) {
+                               pri_proceeding(isdn_data->spri.pri, call, zchan->chan_id, 0);
+                       } else {
+                               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+                       }
+               }
+               break;
+       case ZAP_CHANNEL_STATE_RING:
+               {
+                       if (!zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+                               if (call) {
+                                       pri_acknowledge(isdn_data->spri.pri, call, zchan->chan_id, 0);
+                                       sig.event_id = ZAP_SIGEVENT_START;
+                                       if ((status = isdn_data->sig_cb(&sig) != ZAP_SUCCESS)) {
+                                               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+                                       }
+                               } else {
+                                       zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+                               }
+                       }
+               }
+               break;
+       case ZAP_CHANNEL_STATE_RESTART:
+               {
+                       zchan->caller_data.hangup_cause = ZAP_CAUSE_NORMAL_UNSPECIFIED;
+                       sig.event_id = ZAP_SIGEVENT_RESTART;
+                       status = isdn_data->sig_cb(&sig);
+                       zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+               }
+               break;
+       case ZAP_CHANNEL_STATE_UP:
+               {
+                       if (zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+                               sig.event_id = ZAP_SIGEVENT_UP;
+                               if ((status = isdn_data->sig_cb(&sig) != ZAP_SUCCESS)) {
+                                       zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+                               }
+                       } else if (call) {
+                               pri_answer(isdn_data->spri.pri, call, 0, 1);
+                       } else {
+                               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+                       }
+               }
+               break;
+       case ZAP_CHANNEL_STATE_DIALING:
+               if (isdn_data) {
+                       struct pri_sr *sr;
+                       
+                       if (!(call = pri_new_call(isdn_data->spri.pri))) {
+                               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+                               return;
+                       }
+
+                       zchan->call_data = call;
+                       sr = pri_sr_new();
+                       assert(sr);
+                       pri_sr_set_channel(sr, zchan->chan_id, 0, 0);
+                       pri_sr_set_bearer(sr, 0, isdn_data->l1);
+                       pri_sr_set_called(sr, zchan->caller_data.ani.digits, isdn_data->dp, 1);
+                       pri_sr_set_caller(sr, zchan->caller_data.cid_num.digits, zchan->caller_data.cid_name, isdn_data->dp, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN);
+                       pri_sr_set_redirecting(sr, zchan->caller_data.cid_num.digits, isdn_data->dp, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, PRI_REDIR_UNCONDITIONAL);
+                       
+                       if (pri_setup(isdn_data->spri.pri, call, sr)) {
+                               zchan->caller_data.hangup_cause = ZAP_CAUSE_DESTINATION_OUT_OF_ORDER;                           
+                               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_HANGUP);
+                       }
+
+                       pri_sr_free(sr);
+               }
+
+               break;
+       case ZAP_CHANNEL_STATE_HANGUP:
+               {
+                       if (call && !zap_test_flag(zchan, ZAP_CHANNEL_OUTBOUND)) {
+                               pri_hangup(isdn_data->spri.pri, call, zchan->caller_data.hangup_cause);
+                               pri_destroycall(isdn_data->spri.pri, call);
+                               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+                       } else {
+                               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+                       }
+               }
+               break;
+       case ZAP_CHANNEL_STATE_HANGUP_COMPLETE:
+               break;
+       case ZAP_CHANNEL_STATE_TERMINATING:
+               {
+                       sig.event_id = ZAP_SIGEVENT_STOP;
+                       status = isdn_data->sig_cb(&sig);
+                       zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_DOWN);
+
+               }
+       default:
+               break;
+       }
+
+
+
+       return;
+}
+
+static __inline__ void check_state(zap_span_t *span)
+{
+    if (zap_test_flag(span, ZAP_SPAN_STATE_CHANGE)) {
+        uint32_t j;
+        zap_clear_flag_locked(span, ZAP_SPAN_STATE_CHANGE);
+        for(j = 1; j <= span->chan_count; j++) {
+            if (zap_test_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE)) {
+                               zap_mutex_lock(span->channels[j]->mutex);
+                zap_clear_flag((span->channels[j]), ZAP_CHANNEL_STATE_CHANGE);
+                state_advance(span->channels[j]);
+                zap_channel_complete_state(span->channels[j]);
+                               zap_mutex_unlock(span->channels[j]->mutex);
+            }
+        }
+    }
+}
+
+
+
+static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+
+       zap_log(ZAP_LOG_DEBUG, "number is: %s\n", pevent->ring.callednum);
+       if (strlen(pevent->ring.callednum) > 3) {
+               zap_log(ZAP_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum);
+               pri_answer(spri->pri, pevent->ring.call, 0, 1);
+       }
+       return 0;
+}
+
+static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+       zap_span_t *span = spri->private_info;
+       zap_channel_t *zchan = NULL;
+       q931_call *call = NULL;
+       zchan = span->channels[pevent->hangup.channel];
+       
+       if (zchan) {
+               call = (q931_call *) zchan->call_data;
+               zap_log(ZAP_LOG_DEBUG, "-- Hangup on channel %d:%d\n", spri->span, pevent->hangup.channel);
+               zchan->caller_data.hangup_cause = pevent->hangup.cause;
+               pri_destroycall(spri->pri, call);
+               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_TERMINATING);
+       } else {
+               zap_log(ZAP_LOG_DEBUG, "-- Hangup on channel %d:%d %s but it's not in use?\n", spri->span,
+                               pevent->hangup.channel, zchan->chan_id);
+       }
+
+       return 0;
+}
+
+static int on_answer(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+       zap_span_t *span = spri->private_info;
+       zap_channel_t *zchan = NULL;
+
+       zchan = span->channels[pevent->answer.channel];
+       
+       if (zchan) {
+               zap_log(ZAP_LOG_DEBUG, "-- Answer on channel %d:%d\n", spri->span, pevent->answer.channel);
+               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_UP);
+       } else {
+               zap_log(ZAP_LOG_DEBUG, "-- Answer on channel %d:%d %s but it's not in use?\n", spri->span, pevent->answer.channel, zchan->chan_id);
+                               
+       }
+
+       return 0;
+}
+
+
+static int on_proceed(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+       zap_span_t *span = spri->private_info;
+       zap_channel_t *zchan = NULL;
+       
+       zchan = span->channels[pevent->proceeding.channel];
+       
+       if (zchan) {
+               zap_log(ZAP_LOG_DEBUG, "-- Proceeding on channel %d:%d\n", spri->span, pevent->proceeding.channel);
+               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS_MEDIA);
+       } else {
+               zap_log(ZAP_LOG_DEBUG, "-- Proceeding on channel %d:%d %s but it's not in use?\n", spri->span,
+                                                 pevent->proceeding.channel, zchan->chan_id);
+       }
+
+       return 0;
+}
+
+
+static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+       zap_span_t *span = spri->private_info;
+       zap_channel_t *zchan = NULL;
+
+       zchan = span->channels[pevent->ringing.channel];
+       
+       if (zchan) {
+               zap_log(ZAP_LOG_DEBUG, "-- Ringing on channel %d:%d\n", spri->span, pevent->ringing.channel);
+               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_PROGRESS);
+       } else {
+               zap_log(ZAP_LOG_DEBUG, "-- Ringing on channel %d:%d %s but it's not in use?\n", spri->span,
+                                                 pevent->ringing.channel, zchan->chan_id);
+       }
+
+       return 0;
+}
+
+
+static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
+{
+       zap_span_t *span = spri->private_info;
+       zap_channel_t *zchan = NULL;
+       int ret = 0;
+
+       //switch_mutex_lock(globals.channel_mutex);
+       
+       zchan = span->channels[pevent->ring.channel];
+       if (!zchan || zchan->state != ZAP_CHANNEL_STATE_DOWN || zap_test_flag(zchan, ZAP_CHANNEL_INUSE)) {
+               zap_log(ZAP_LOG_WARNING, "--Duplicate Ring on channel %d:%d (ignored)\n", spri->span, pevent->ring.channel);
+               ret = 0;
+               goto done;
+       }
+
+       if (zap_channel_open_chan(zchan) != ZAP_SUCCESS) {
+               zap_log(ZAP_LOG_WARNING, "--Failure opening channel %d:%d (ignored)\n", spri->span, pevent->ring.channel);
+               ret = 0;
+               goto done;
+       }
+       
+
+       zap_log(ZAP_LOG_NOTICE, "-- Ring on channel %d:%d (from %s to %s)\n", spri->span, pevent->ring.channel,
+                                         pevent->ring.callingnum, pevent->ring.callednum);
+       
+       memset(&zchan->caller_data, 0, sizeof(zchan->caller_data));
+       
+       zap_set_string(zchan->caller_data.cid_num.digits, (char *)pevent->ring.callingnum);
+       zap_set_string(zchan->caller_data.cid_name, (char *)pevent->ring.callingnum);
+       zap_set_string(zchan->caller_data.ani.digits, (char *)pevent->ring.callingani);
+       zap_set_string(zchan->caller_data.dnis.digits, (char *)pevent->ring.callednum);
+       
+       if (pevent->ring.ani2 >= 0) {
+               snprintf(zchan->caller_data.aniII, 5, "%.2d", pevent->ring.ani2);
+       }
+       
+       // scary to trust this pointer, you'd think they would give you a copy of the call data so you own it......
+       zchan->call_data = pevent->ring.call;
+       
+       zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RING);
+       
+ done:
+       //switch_mutex_unlock(globals.channel_mutex);
+
+       return ret;
+}
+
+static int check_flags(lpwrap_pri_t *spri)
+{
+       zap_span_t *span = spri->private_info;
+
+       check_state(span);
+
+       return 0;
+}
+
+static int on_restart(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+       zap_span_t *span = spri->private_info;
+       zap_channel_t *zchan;
+
+       zap_log(ZAP_LOG_NOTICE, "-- Restarting %d:%d\n", spri->span, pevent->restart.channel);
+
+       zchan = span->channels[pevent->restart.channel];
+
+       if (!zchan) {
+               return 0;
+       }
+
+       if (pevent->restart.channel < 1) {
+               zap_set_state_all(zchan->span, ZAP_CHANNEL_STATE_RESTART);
+       } else {
+               zap_set_state_locked(zchan, ZAP_CHANNEL_STATE_RESTART);
+       }
+
+       return 0;
+}
+
+static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+       
+       if (!zap_test_flag(spri, LPWRAP_PRI_READY)) {
+               zap_log(ZAP_LOG_INFO, "Span %d D-Chan UP!\n", spri->span);
+               zap_set_flag(spri, LPWRAP_PRI_READY);
+       }
+
+       return 0;
+}
+
+static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+
+       if (zap_test_flag(spri, LPWRAP_PRI_READY)) {
+               zap_log(ZAP_LOG_INFO, "Span %d D-Chan DOWN!\n", spri->span);
+               zap_clear_flag(spri, LPWRAP_PRI_READY);
+       }
+
+       return 0;
+}
+
+static int on_anything(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event * pevent)
+{
+
+       zap_log(ZAP_LOG_DEBUG, "Caught Event span %d %u (%s)\n", spri->span, event_type, lpwrap_pri_event_str(event_type));
+       return 0;
+}
+
+
+
+static void *zap_libpri_run(zap_thread_t *me, void *obj)
+{
+       zap_span_t *span = (zap_span_t *) obj;
+       zap_libpri_data_t *isdn_data = span->signal_data;
+
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RING, on_ring);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RINGING, on_ringing);
+       //LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_SETUP_ACK, on_proceed);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROCEEDING, on_proceed);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANSWER, on_answer);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_UP, on_dchan_up);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_DOWN, on_dchan_down);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_REQ, on_hangup);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP, on_hangup);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_INFO_RECEIVED, on_info);
+       LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART, on_restart);
+
+       isdn_data->spri.on_loop = check_flags;
+       isdn_data->spri.private_info = span;
+       
+       lpwrap_run_pri(&isdn_data->spri);
+
+       
+       return NULL;
+}
+
+static zap_status_t zap_libpri_start(zap_span_t *span)
+{
+       zap_status_t ret;
+
+       zap_libpri_data_t *isdn_data = span->signal_data;
+       zap_set_flag(isdn_data, OZMOD_LIBPRI_RUNNING);
+
+       ret = zap_thread_create_detached(zap_libpri_run, span);
+       if (ret != ZAP_SUCCESS) {
+               return ret;
+       }
+
+       return ret;
+}
+
+
+
+static int str2node(char *node)
+{
+       if (!strcasecmp(node, "cpe"))
+               return PRI_CPE;
+       if (!strcasecmp(node, "network"))
+               return PRI_NETWORK;
+       return PRI_CPE;
+}
+
+static int str2switch(char *swtype)
+{
+       if (!strcasecmp(swtype, "ni1"))
+               return PRI_SWITCH_NI1;
+       if (!strcasecmp(swtype, "ni2"))
+               return PRI_SWITCH_NI2;
+       if (!strcasecmp(swtype, "dms100"))
+               return PRI_SWITCH_DMS100;
+       if (!strcasecmp(swtype, "lucent5e"))
+               return PRI_SWITCH_LUCENT5E;
+       if (!strcasecmp(swtype, "att4ess"))
+               return PRI_SWITCH_ATT4ESS;
+       if (!strcasecmp(swtype, "euroisdn"))
+               return PRI_SWITCH_EUROISDN_E1;
+       if (!strcasecmp(swtype, "gr303eoc"))
+               return PRI_SWITCH_GR303_EOC;
+       if (!strcasecmp(swtype, "gr303tmc"))
+               return PRI_SWITCH_GR303_TMC;
+       return PRI_SWITCH_DMS100;
+}
+
+
+static int str2l1(char *l1)
+{
+       if (!strcasecmp(l1, "alaw"))
+               return PRI_LAYER_1_ALAW;
+       
+       return PRI_LAYER_1_ULAW;
+}
+
+static int str2dp(char *dp)
+{
+       if (!strcasecmp(dp, "international"))
+               return PRI_INTERNATIONAL_ISDN;
+       if (!strcasecmp(dp, "national"))
+               return PRI_NATIONAL_ISDN;
+       if (!strcasecmp(dp, "local"))
+               return PRI_LOCAL_ISDN;
+       if (!strcasecmp(dp, "private"))
+               return PRI_PRIVATE;
+       if (!strcasecmp(dp, "unknown"))
+               return PRI_UNKNOWN;
+
+       return PRI_UNKNOWN;
+}
+
+
+
+static ZIO_SIG_CONFIGURE_FUNCTION(zap_libpri_configure_span)
+{
+       uint32_t i, x = 0;
+       zap_channel_t *dchans[2] = {0};
+       zap_libpri_data_t *isdn_data;
+       char *var, *val;
+       int32_t opts = 0;
+       
+       if (span->trunk_type >= ZAP_TRUNK_NONE) {
+               zap_log(ZAP_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", zap_trunk_type2str(span->trunk_type));
+               span->trunk_type = ZAP_TRUNK_T1;
+       }
+       
+       for(i = 1; i <= span->chan_count; i++) {
+               if (span->channels[i]->type == ZAP_CHAN_TYPE_DQ921) {
+                       if (x > 1) {
+                               snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
+                               return ZAP_FAIL;
+                       } else {
+                               if (zap_channel_open(span->span_id, i, &dchans[x]) == ZAP_SUCCESS) {
+                                       zap_log(ZAP_LOG_DEBUG, "opening d-channel #%d %d:%d\n", x, dchans[x]->span_id, dchans[x]->chan_id);
+                                       dchans[x]->state = ZAP_CHANNEL_STATE_UP;
+                                       x++;
+                               }
+                       }
+               }
+       }
+       
+       if (!x) {
+               snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channels!");
+               return ZAP_FAIL;
+       }
+
+       isdn_data = malloc(sizeof(*isdn_data));
+       assert(isdn_data != NULL);
+       memset(isdn_data, 0, sizeof(*isdn_data));
+       
+       while((var = va_arg(ap, char *))) {
+               if (!strcasecmp(var, "node")) {
+                       if (!(val = va_arg(ap, char *))) {
+                               break;
+                       }
+                       isdn_data->node = str2node(val);
+               } else if (!strcasecmp(var, "switch")) {
+                       if (!(val = va_arg(ap, char *))) {
+                               break;
+                       }
+                       isdn_data->pswitch = str2switch(val);
+               } else if (!strcasecmp(var, "opts")) {
+                       opts = va_arg(ap, uint32_t);
+                       if  (opts >= OZMOD_LIBPRI_OPT_MAX) {
+                               return ZAP_FAIL;
+                       }
+                       isdn_data->opts = opts;
+               } else if (!strcasecmp(var, "dp")) {
+                       if (!(val = va_arg(ap, char *))) {
+                               break;
+                       }
+                       isdn_data->dp = str2dp(val);
+               } else if (!strcasecmp(var, "l1")) {
+                       if (!(val = va_arg(ap, char *))) {
+                               break;
+                       }
+                       isdn_data->l1 = str2l1(val);
+               } else if (!strcasecmp(var, "debug")) {
+                       if (!(val = va_arg(ap, char *))) {
+                               break;
+                       }
+                       isdn_data->debug = atoi(val);
+               } else {
+                       snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
+                       return ZAP_FAIL;
+               }
+       }
+       
+
+       span->start = zap_libpri_start;
+       isdn_data->sig_cb = sig_cb;
+       isdn_data->dchans[0] = dchans[0];
+       isdn_data->dchans[1] = dchans[1];
+       isdn_data->dchan = isdn_data->dchans[0];
+       
+       
+       // force debug rm me later
+       isdn_data->debug = PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE;
+       
+       
+       if (lpwrap_init_pri(&isdn_data->spri,
+                                               span->span_id,  // span
+                                               isdn_data->dchan, // dchan
+                                               isdn_data->pswitch,
+                                               isdn_data->node,
+                                               isdn_data->debug) < 0) {
+               snprintf(span->last_error, sizeof(span->last_error), "PRI init FAIL!");
+               return ZAP_FAIL;
+       }
+
+       span->signal_data = isdn_data;
+       span->signal_type = ZAP_SIGTYPE_ISDN;
+       span->outgoing_call = isdn_outgoing_call;
+
+       if ((opts & OZMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) {
+               span->channel_request = isdn_channel_request;
+               span->suggest_chan_id = 1;
+       }
+
+       span->state_map = &isdn_state_map;
+
+       return ZAP_SUCCESS;
+}
+
+zap_module_t zap_module = { 
+       "libpri",
+       NULL,
+       zap_libpri_unload,
+       zap_libpri_init,
+       zap_libpri_configure_span,
+       NULL
+};
+
+
+
+/* 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/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h b/libs/openzap/src/ozmod/ozmod_libpri/ozmod_libpri.h
new file mode 100644 (file)
index 0000000..64a0c05
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2009, 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 OZMOD_LIBPRI_H
+#define OZMOD_LIBPRI_H
+#include "openzap.h"
+#include "lpwrap_pri.h"
+
+typedef enum {
+       OZMOD_LIBPRI_OPT_NONE = 0,
+       OZMOD_LIBPRI_OPT_SUGGEST_CHANNEL = (1 << 0),
+
+       OZMOD_LIBPRI_OPT_MAX = (2 << 0)
+} zap_isdn_opts_t;
+
+typedef enum {
+       OZMOD_LIBPRI_RUNNING = (1 << 0)
+} zap_isdn_flag_t;
+
+
+struct zap_libpri_data {
+       zap_channel_t *dchan;
+       zap_channel_t *dchans[2];
+       struct zap_sigmsg sigmsg;
+       zio_signal_cb_t sig_cb;
+       uint32_t flags;
+       int32_t mode;
+       zap_isdn_opts_t opts;
+
+       int node;
+       int pswitch;
+       char *dialplan;
+       unsigned int l1;
+       unsigned int dp;
+
+       int debug;
+
+       lpwrap_pri_t spri;
+};
+
+typedef struct zap_libpri_data zap_libpri_data_t;
+
+
+/* b-channel private data */
+struct zap_isdn_bchan_data
+{
+       int32_t digit_timeout;
+};
+
+typedef struct zap_isdn_bchan_data zap_isdn_bchan_data_t;
+
+
+#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:
+ */
+
index 9dbfa9efd94add2e5f95f5b4b7f929d62c9d9b33..50198709d5d5d7195466dc9fdd8afb646940c546 100644 (file)
@@ -31,6 +31,7 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#define _GNU_SOURCE
 #ifndef WIN32
 #endif
 #include "openzap.h"
@@ -2767,6 +2768,87 @@ void print_bits(uint8_t *b, int bl, char *buf, int blen, zap_endian_t e, uint8_t
 
 }
 
+
+
+zap_status_t zap_console_stream_raw_write(zap_stream_handle_t *handle, uint8_t *data, zap_size_t datalen)
+{
+       zap_size_t need = handle->data_len + datalen;
+       
+       if (need >= handle->data_size) {
+               void *new_data;
+               need += handle->alloc_chunk;
+
+               if (!(new_data = realloc(handle->data, need))) {
+                       return ZAP_MEMERR;
+               }
+
+               handle->data = new_data;
+               handle->data_size = need;
+       }
+
+       memcpy((uint8_t *) (handle->data) + handle->data_len, data, datalen);
+       handle->data_len += datalen;
+       handle->end = (uint8_t *) (handle->data) + handle->data_len;
+       *(uint8_t *)handle->end = '\0';
+
+       return ZAP_SUCCESS;
+}
+
+zap_status_t zap_console_stream_write(zap_stream_handle_t *handle, const char *fmt, ...)
+{
+       va_list ap;
+       char *buf = handle->data;
+       char *end = handle->end;
+       int ret = 0;
+       char *data = NULL;
+
+       if (handle->data_len >= handle->data_size) {
+               return ZAP_FAIL;
+       }
+
+       va_start(ap, fmt);
+       ret = vasprintf(&data, fmt, ap);
+       va_end(ap);
+
+       if (data) {
+               zap_size_t remaining = handle->data_size - handle->data_len;
+               zap_size_t need = strlen(data) + 1;
+
+               if ((remaining < need) && handle->alloc_len) {
+                       zap_size_t new_len;
+                       void *new_data;
+
+                       new_len = handle->data_size + need + handle->alloc_chunk;
+                       if ((new_data = realloc(handle->data, new_len))) {
+                               handle->data_size = handle->alloc_len = new_len;
+                               handle->data = new_data;
+                               buf = handle->data;
+                               remaining = handle->data_size - handle->data_len;
+                               handle->end = (uint8_t *) (handle->data) + handle->data_len;
+                               end = handle->end;
+                       } else {
+                               zap_log(ZAP_LOG_CRIT, "Memory Error!\n");
+                               free(data);
+                               return ZAP_FAIL;
+                       }
+               }
+
+               if (remaining < need) {
+                       ret = -1;
+               } else {
+                       ret = 0;
+                       snprintf(end, remaining, "%s", data);
+                       handle->data_len = strlen(buf);
+                       handle->end = (uint8_t *) (handle->data) + handle->data_len;
+               }
+               free(data);
+       }
+
+       return ret ? ZAP_FAIL : ZAP_SUCCESS;
+}
+
+
+
 /* For Emacs:
  * Local Variables:
  * mode:c