root/src/ftmod/ftmod_libpri/ftmod_libpri.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _ftdm_channel_set_state_force
  2. FIO_IO_UNLOAD_FUNCTION
  3. FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
  4. FIO_SPAN_GET_SIG_STATUS_FUNCTION
  5. FIO_CHANNEL_OUTGOING_CALL_FUNCTION
  6. FIO_CHANNEL_REQUEST_FUNCTION
  7. s_pri_error
  8. s_pri_message
  9. parse_debug
  10. print_debug
  11. FIO_API_FUNCTION
  12. FIO_IO_LOAD_FUNCTION
  13. FIO_SIG_LOAD_FUNCTION
  14. state_advance
  15. check_state
  16. on_info
  17. on_hangup
  18. on_answer
  19. on_proceeding
  20. on_progress
  21. on_ringing
  22. on_ring
  23. process_event
  24. check_events
  25. check_flags
  26. on_restart
  27. aoc_billing_id
  28. aoc_money_amount
  29. handle_facility_aoc_s
  30. handle_facility_aoc_d
  31. handle_facility_aoc_e
  32. on_facility
  33. on_dchan_up
  34. on_dchan_down
  35. on_anything
  36. on_io_fail
  37. ftdm_libpri_run
  38. ftdm_libpri_stop
  39. ftdm_libpri_start
  40. parse_mode
  41. parse_dialect
  42. parse_layer1
  43. parse_ton
  44. parse_opts
  45. FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION

   1 /*
   2  * Copyright (c) 2007, Anthony Minessale II
   3  * Copyright (c) 2010, Stefan Knoblich <s.knoblich@axsentis.de>
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * * Redistributions of source code must retain the above copyright
  11  * notice, this list of conditions and the following disclaimer.
  12  *
  13  * * Redistributions in binary form must reproduce the above copyright
  14  * notice, this list of conditions and the following disclaimer in the
  15  * documentation and/or other materials provided with the distribution.
  16  *
  17  * * Neither the name of the original author; nor the names of any contributors
  18  * may be used to endorse or promote products derived from this software
  19  * without specific prior written permission.
  20  *
  21  *
  22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  25  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  26  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  27  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  29  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  30  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  31  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  32  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  33  */
  34 #include "private/ftdm_core.h"
  35 #include "ftmod_libpri.h"
  36 
  37 static void _ftdm_channel_set_state_force(ftdm_channel_t *chan, const ftdm_channel_state_t state)
  38 {
  39         assert(chan);
  40         chan->state = state;
  41 }
  42 
  43 /**
  44  * \brief Unloads libpri IO module
  45  * \return Success
  46  */
  47 static FIO_IO_UNLOAD_FUNCTION(ftdm_libpri_unload)
  48 {
  49         return FTDM_SUCCESS;
  50 }
  51 
  52 /**
  53  * \brief Returns the signalling status on a channel
  54  * \param ftdmchan Channel to get status on
  55  * \param status        Pointer to set signalling status
  56  * \return Success or failure
  57  */
  58 
  59 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(isdn_get_channel_sig_status)
  60 {
  61         *status = FTDM_SIG_STATE_DOWN;
  62 
  63         ftdm_libpri_data_t *isdn_data = ftdmchan->span->signal_data;
  64         if (ftdm_test_flag(&(isdn_data->spri), LPWRAP_PRI_READY)) {
  65                 *status = FTDM_SIG_STATE_UP;
  66         }
  67         return FTDM_SUCCESS;
  68 }
  69 
  70 /**
  71  * \brief Returns the signalling status on a span
  72  * \param span Span to get status on
  73  * \param status        Pointer to set signalling status
  74  * \return Success or failure
  75  */
  76 
  77 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(isdn_get_span_sig_status)
  78 {
  79         *status = FTDM_SIG_STATE_DOWN;
  80 
  81         ftdm_libpri_data_t *isdn_data = span->signal_data;
  82         if (ftdm_test_flag(&(isdn_data->spri), LPWRAP_PRI_READY)) {
  83                 *status = FTDM_SIG_STATE_UP;
  84         }
  85         return FTDM_SUCCESS;
  86 }
  87 
  88 
  89 /**
  90  * \brief Starts a libpri channel (outgoing call)
  91  * \param ftdmchan Channel to initiate call on
  92  * \return Success or failure
  93  */
  94 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(isdn_outgoing_call)
  95 {
  96         ftdm_status_t status = FTDM_SUCCESS;
  97         ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
  98         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
  99         return status;
 100 }
 101 
 102 /**
 103  * \brief Requests an libpri channel on a span (outgoing call)
 104  * \param span Span where to get a channel (unused)
 105  * \param chan_id Specific channel to get (0 for any) (unused)
 106  * \param direction Call direction (unused)
 107  * \param caller_data Caller information (unused)
 108  * \param ftdmchan Channel to initialise (unused)
 109  * \return Failure
 110  */
 111 static FIO_CHANNEL_REQUEST_FUNCTION(isdn_channel_request)
 112 {
 113         return FTDM_FAIL;
 114 }
 115 
 116 #ifdef WIN32
 117 /**
 118  * \brief Logs a libpri error
 119  * \param s Error string
 120  */
 121 static void s_pri_error(char *s)
 122 #else
 123 /**
 124  * \brief Logs a libpri error
 125  * \param pri libpri structure (unused)
 126  * \param s Error string
 127  */
 128 static void s_pri_error(struct pri *pri, char *s)
 129 #endif
 130 {
 131         ftdm_log(FTDM_LOG_ERROR, "%s", s);
 132 }
 133 
 134 #ifdef WIN32
 135 /**
 136  * \brief Logs a libpri message
 137  * \param s Message string
 138  */
 139 static void s_pri_message(char *s)
 140 #else
 141 /**
 142  * \brief Logs a libpri message
 143  * \param pri libpri structure (unused)
 144  * \param s Message string
 145  */
 146 static void s_pri_message(struct pri *pri, char *s)
 147 #endif
 148 {
 149         ftdm_log(FTDM_LOG_DEBUG, "%s", s);
 150 }
 151 
 152 #define PRI_DEBUG_Q921_ALL      (PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_STATE)
 153 #define PRI_DEBUG_Q931_ALL      (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE | PRI_DEBUG_Q931_ANOMALY)
 154 
 155 static const struct ftdm_libpri_debug {
 156         const char *name;
 157         const int   flags;
 158 } ftdm_libpri_debug[] = {
 159         /* NOTE: order is important for print_debug() */
 160         { "q921_all",     PRI_DEBUG_Q921_ALL   },
 161         { "q921_raw",     PRI_DEBUG_Q921_RAW   },
 162         { "q921_dump",    PRI_DEBUG_Q921_DUMP  },
 163         { "q921_state",   PRI_DEBUG_Q921_STATE },
 164 
 165         { "q931_all",     PRI_DEBUG_Q931_ALL     },
 166         { "q931_dump",    PRI_DEBUG_Q931_DUMP    },
 167         { "q931_state",   PRI_DEBUG_Q931_STATE   },
 168         { "q931_anomaly", PRI_DEBUG_Q931_ANOMALY },
 169 
 170         { "config",       PRI_DEBUG_CONFIG },
 171         { "apdu",         PRI_DEBUG_APDU   },
 172         { "aoc",          PRI_DEBUG_AOC    }
 173 };
 174 
 175 /**
 176  * \brief Parses a debug string to flags
 177  * \param in Debug string to parse for
 178  * \return Flags or -1 if nothing matched
 179  */
 180 static int parse_debug(const char *in, uint32_t *flags)
 181 {
 182         int res = -1;
 183         int i;
 184 
 185         if (!in || !flags)
 186                 return -1;
 187 
 188         if (!strcmp(in, "all")) {
 189                 *flags = PRI_DEBUG_ALL;
 190                 return 0;
 191         }
 192         if (strstr(in, "none")) {
 193                 *flags = 0;
 194                 return 0;
 195         }
 196 
 197         for (i = 0; i < ftdm_array_len(ftdm_libpri_debug); i++) {
 198                 if (strstr(in, ftdm_libpri_debug[i].name)) {
 199                         *flags |= ftdm_libpri_debug[i].flags;
 200                         res = 0;
 201                 }
 202         }
 203         return res;
 204 }
 205 
 206 static int print_debug(uint32_t flags, char *tmp, const int size)
 207 {
 208         int offset = 0;
 209         int res = 0;
 210         int i;
 211 
 212         if ((flags & PRI_DEBUG_ALL) == PRI_DEBUG_ALL) {
 213                 strcat(tmp, "all");
 214                 return 0;
 215         }
 216         else if (!flags) {
 217                 strcat(tmp, "none");
 218                 return 0;
 219         }
 220 
 221         for (i = 0; i < ftdm_array_len(ftdm_libpri_debug); i++) {
 222                 if ((flags & ftdm_libpri_debug[i].flags) == ftdm_libpri_debug[i].flags) {
 223                         res = snprintf(&tmp[offset], size - offset, "%s,", ftdm_libpri_debug[i].name);
 224                         if (res <= 0 || res == (size - offset))
 225                                 goto out;
 226                         offset += res;
 227                         flags  &= ~ftdm_libpri_debug[i].flags;  /* remove detected flags to make *_all work correctly */
 228                 }
 229         }
 230 
 231 out:
 232         tmp[offset - 1] = '\0';
 233         return 0;
 234 }
 235 
 236 static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span);
 237 static ftdm_io_interface_t ftdm_libpri_interface;
 238 
 239 static const char *ftdm_libpri_usage =
 240         "Usage:\n"
 241         "libpri kill <span>\n"
 242         "libpri debug <span> [all|none|flag,...flagN]\n"
 243         "\n"
 244         "Possible debug flags:\n"
 245         "\tq921_raw     - Q.921 Raw messages\n"
 246         "\tq921_dump    - Q.921 Decoded messages\n"
 247         "\tq921_state   - Q.921 State machine changes\n"
 248         "\tq921_all     - Enable all Q.921 debug options\n"
 249         "\n"
 250         "\tq931_dump    - Q.931 Messages\n"
 251         "\tq931_state   - Q.931 State machine changes\n"
 252         "\tq931_anomaly - Q.931 Anomalies\n"
 253         "\tq931_all     - Enable all Q.931 debug options\n"
 254         "\n"
 255         "\tapdu         - Application protocol data unit\n"
 256         "\taoc          - Advice of Charge messages\n"
 257         "\tconfig       - Configuration\n"
 258         "\n"
 259         "\tnone         - Disable debugging\n"
 260         "\tall          - Enable all debug options\n";
 261 
 262 /**
 263  * \brief API function to kill or debug a libpri span
 264  * \param stream API stream handler
 265  * \param data String containing argurments
 266  * \return Flags
 267  */
 268 static FIO_API_FUNCTION(ftdm_libpri_api)
 269 {
 270         char *mycmd = NULL, *argv[10] = { 0 };
 271         int argc = 0;
 272 
 273         if (data) {
 274                 mycmd = ftdm_strdup(data);
 275                 argc = ftdm_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
 276         }
 277 
 278         if (argc == 1) {
 279                 if (!strcasecmp(argv[0], "help") || !strcasecmp(argv[0], "usage")) {
 280                         stream->write_function(stream, ftdm_libpri_usage);
 281                         goto done;
 282                 }
 283         }
 284 
 285         if (argc == 2) {
 286                 if (!strcasecmp(argv[0], "kill")) {
 287                         int span_id = atoi(argv[1]);
 288                         ftdm_span_t *span = NULL;
 289 
 290                         if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS || ftdm_span_find(span_id, &span) == FTDM_SUCCESS) {
 291                                 ftdm_libpri_data_t *isdn_data = span->signal_data;
 292 
 293                                 if (span->start != ftdm_libpri_start) {
 294                                         stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
 295                                         goto done;
 296                                 }
 297 
 298                                 ftdm_clear_flag(&(isdn_data->spri), LPWRAP_PRI_READY);
 299                                 stream->write_function(stream, "%s: +OK killed.\n", __FILE__);
 300                                 goto done;
 301                         } else {
 302                                 stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
 303                                 goto done;
 304                         }
 305                 }
 306         }
 307 
 308         if (argc >= 2) {
 309                 if (!strcasecmp(argv[0], "debug")) {
 310                         ftdm_span_t *span = NULL;
 311 
 312                         if (ftdm_span_find_by_name(argv[1], &span) == FTDM_SUCCESS) {
 313                                 ftdm_libpri_data_t *isdn_data = span->signal_data;
 314                                 uint32_t flags = 0;
 315 
 316                                 if (span->start != ftdm_libpri_start) {
 317                                         stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
 318                                         goto done;
 319                                 }
 320 
 321                                 if (argc == 2) {
 322                                         char tmp[100] = { 0 };
 323                                         print_debug(pri_get_debug(isdn_data->spri.pri), tmp, sizeof(tmp));
 324                                         stream->write_function(stream, "%s: +OK current debug flags: '%s'\n", __FILE__, tmp);
 325                                         goto done;
 326                                 }
 327 
 328                                 if (parse_debug(argv[2], &flags) == -1) {
 329                                         stream->write_function(stream, "%s: -ERR invalid debug flags given\n", __FILE__);
 330                                         goto done;
 331                                 }
 332 
 333                                 pri_set_debug(isdn_data->spri.pri, flags);
 334                                 stream->write_function(stream, "%s: +OK debug %s.\n", __FILE__, (flags) ? "enabled" : "disabled");
 335                                 goto done;
 336                         } else {
 337                                 stream->write_function(stream, "%s: -ERR invalid span.\n", __FILE__);
 338                                 goto done;
 339                         }
 340                 }
 341 
 342         }
 343         stream->write_function(stream, "%s: -ERR invalid command.\n", __FILE__);
 344 
 345 done:
 346         ftdm_safe_free(mycmd);
 347 
 348         return FTDM_SUCCESS;
 349 }
 350 
 351 
 352 /**
 353  * \brief Loads libpri IO module
 354  * \param fio FreeTDM IO interface
 355  * \return Success
 356  */
 357 static FIO_IO_LOAD_FUNCTION(ftdm_libpri_io_init)
 358 {
 359         assert(fio != NULL);
 360 
 361         memset(&ftdm_libpri_interface, 0, sizeof(ftdm_libpri_interface));
 362         ftdm_libpri_interface.name = "libpri";
 363         ftdm_libpri_interface.api  = &ftdm_libpri_api;
 364 
 365         *fio = &ftdm_libpri_interface;
 366 
 367         return FTDM_SUCCESS;
 368 }
 369 
 370 /**
 371  * \brief Loads libpri signaling module
 372  * \param fio FreeTDM IO interface
 373  * \return Success
 374  */
 375 static FIO_SIG_LOAD_FUNCTION(ftdm_libpri_init)
 376 {
 377         pri_set_error(s_pri_error);
 378         pri_set_message(s_pri_message);
 379         return FTDM_SUCCESS;
 380 }
 381 
 382 /**
 383  * \brief libpri state map
 384  */
 385 static ftdm_state_map_t isdn_state_map = {
 386         {
 387                 {
 388                         ZSD_OUTBOUND,
 389                         ZSM_UNACCEPTABLE,
 390                         {FTDM_ANY_STATE},
 391                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
 392                 },
 393                 {
 394                         ZSD_OUTBOUND,
 395                         ZSM_UNACCEPTABLE,
 396                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
 397                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
 398                 },
 399                 {
 400                         ZSD_OUTBOUND,
 401                         ZSM_UNACCEPTABLE,
 402                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 403                         {FTDM_CHANNEL_STATE_DIALING, FTDM_END}
 404                 },
 405                 {
 406                         ZSD_OUTBOUND,
 407                         ZSM_UNACCEPTABLE,
 408                         {FTDM_CHANNEL_STATE_DIALING, FTDM_END},
 409                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
 410                          FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_PROGRESS,
 411                          FTDM_CHANNEL_STATE_UP, FTDM_END}
 412                 },
 413                 {
 414                         ZSD_OUTBOUND,
 415                         ZSM_UNACCEPTABLE,
 416                         {FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
 417                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
 418                          FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
 419                 },
 420                 {
 421                         ZSD_OUTBOUND,
 422                         ZSM_UNACCEPTABLE,
 423                         {FTDM_CHANNEL_STATE_RINGING, FTDM_END},
 424                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
 425                          FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END},
 426                 },
 427                 {
 428                         ZSD_OUTBOUND,
 429                         ZSM_UNACCEPTABLE,
 430                         {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
 431                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP,
 432                          FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
 433                 },
 434                 {
 435                         ZSD_OUTBOUND,
 436                         ZSM_UNACCEPTABLE,
 437                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
 438                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_UP, FTDM_END}
 439                 },
 440                 {
 441                         ZSD_OUTBOUND,
 442                         ZSM_UNACCEPTABLE,
 443                         {FTDM_CHANNEL_STATE_UP, FTDM_END},
 444                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
 445                 },
 446                 {
 447                         ZSD_OUTBOUND,
 448                         ZSM_UNACCEPTABLE,
 449                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 450                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_END}
 451                 },
 452                 {
 453                         ZSD_OUTBOUND,
 454                         ZSM_UNACCEPTABLE,
 455                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 456                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 457                 },
 458                 {
 459                         ZSD_OUTBOUND,
 460                         ZSM_UNACCEPTABLE,
 461                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 462                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 463                 },
 464 
 465                 /****************************************/
 466                 {
 467                         ZSD_INBOUND,
 468                         ZSM_UNACCEPTABLE,
 469                         {FTDM_ANY_STATE},
 470                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END}
 471                 },
 472                 {
 473                         ZSD_INBOUND,
 474                         ZSM_UNACCEPTABLE,
 475                         {FTDM_CHANNEL_STATE_RESTART, FTDM_END},
 476                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END}
 477                 },
 478                 {
 479                         ZSD_INBOUND,
 480                         ZSM_UNACCEPTABLE,
 481                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 482                         {FTDM_CHANNEL_STATE_DIALTONE, FTDM_CHANNEL_STATE_RING, FTDM_END}
 483                 },
 484                 {
 485                         ZSD_INBOUND,
 486                         ZSM_UNACCEPTABLE,
 487                         {FTDM_CHANNEL_STATE_DIALTONE, FTDM_END},
 488                         {FTDM_CHANNEL_STATE_RING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END}
 489                 },
 490                 {
 491                         ZSD_INBOUND,
 492                         ZSM_UNACCEPTABLE,
 493                         {FTDM_CHANNEL_STATE_RING, FTDM_END},
 494                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROCEED, FTDM_CHANNEL_STATE_RINGING, FTDM_END}
 495                 },
 496                 {
 497                         ZSD_INBOUND,
 498                         ZSM_UNACCEPTABLE,
 499                         {FTDM_CHANNEL_STATE_PROCEED, FTDM_END},
 500                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_RINGING, FTDM_CHANNEL_STATE_PROGRESS,
 501                          FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
 502                 },
 503                 {
 504                         ZSD_INBOUND,
 505                         ZSM_UNACCEPTABLE,
 506                         {FTDM_CHANNEL_STATE_RINGING, FTDM_END},
 507                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS, FTDM_CHANNEL_STATE_PROGRESS_MEDIA,
 508                          FTDM_CHANNEL_STATE_UP, FTDM_END}
 509                 },
 510                 {
 511                         ZSD_INBOUND,
 512                         ZSM_UNACCEPTABLE,
 513                         {FTDM_CHANNEL_STATE_PROGRESS, FTDM_END},
 514                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_CHANNEL_STATE_UP, FTDM_END}
 515                 },
 516                 {
 517                         ZSD_INBOUND,
 518                         ZSM_UNACCEPTABLE,
 519                         {FTDM_CHANNEL_STATE_PROGRESS_MEDIA, FTDM_END},
 520                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_UP, FTDM_END}
 521                 },
 522                 {
 523                         ZSD_INBOUND,
 524                         ZSM_UNACCEPTABLE,
 525                         {FTDM_CHANNEL_STATE_UP, FTDM_END},
 526                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 527                 },
 528                 {
 529                         ZSD_INBOUND,
 530                         ZSM_UNACCEPTABLE,
 531                         {FTDM_CHANNEL_STATE_TERMINATING, FTDM_END},
 532                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 533                 },
 534                 {
 535                         ZSD_INBOUND,
 536                         ZSM_UNACCEPTABLE,
 537                         {FTDM_CHANNEL_STATE_HANGUP, FTDM_END},
 538                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 539                 },
 540                 {
 541                         ZSD_INBOUND,
 542                         ZSM_UNACCEPTABLE,
 543                         {FTDM_CHANNEL_STATE_HANGUP_COMPLETE, FTDM_END},
 544                         {FTDM_CHANNEL_STATE_DOWN, FTDM_END},
 545                 },
 546         }
 547 };
 548 
 549 /**
 550  * \brief Handler for channel state change
 551  * \param ftdmchan Channel to handle
 552  * \note This function MUST be called with the channel locked
 553  */
 554 static ftdm_status_t state_advance(ftdm_channel_t *chan)
 555 {
 556         ftdm_libpri_data_t *isdn_data = chan->span->signal_data;
 557         q931_call *call = (q931_call *)chan->call_data;
 558         ftdm_status_t status;
 559         ftdm_sigmsg_t sig;
 560 
 561         ftdm_log(FTDM_LOG_DEBUG, "-- %d:%d STATE [%s]\n",
 562                         ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan), ftdm_channel_get_state_str(chan));
 563 
 564         memset(&sig, 0, sizeof(sig));
 565         sig.chan_id = ftdm_channel_get_id(chan);
 566         sig.span_id = ftdm_channel_get_span_id(chan);
 567         sig.channel = chan;
 568         
 569         ftdm_channel_complete_state(chan);
 570 
 571         switch (ftdm_channel_get_state(chan)) {
 572         case FTDM_CHANNEL_STATE_DOWN:
 573                 {
 574                         ftdm_channel_t *chtmp = chan;
 575                         chan->call_data = NULL;
 576 
 577                         if (ftdm_channel_close(&chtmp) != FTDM_SUCCESS) {
 578                                 ftdm_log(FTDM_LOG_WARNING, "-- Failed to close channel %d:%d\n",
 579                                         ftdm_channel_get_span_id(chan),
 580                                         ftdm_channel_get_id(chan));
 581                         } else {
 582                                 ftdm_log(FTDM_LOG_DEBUG, "-- Closed channel %d:%d\n",
 583                                         ftdm_channel_get_span_id(chan),
 584                                         ftdm_channel_get_id(chan));
 585                         }
 586                 }
 587                 break;
 588 
 589         case FTDM_CHANNEL_STATE_PROGRESS:
 590                 {
 591                         if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
 592                                 sig.event_id = FTDM_SIGEVENT_PROGRESS;
 593                                 if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
 594                                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
 595                                 }
 596                         } else if (call) {
 597                                 pri_progress(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
 598                         } else {
 599                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
 600                         }
 601                 }
 602                 break;
 603 
 604         case FTDM_CHANNEL_STATE_RINGING:
 605                 {
 606                         if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
 607                                 sig.event_id = FTDM_SIGEVENT_RINGING;
 608                                 if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
 609                                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
 610                                 }
 611                         } else if (call) {
 612 //                              pri_progress(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 1);
 613                                 pri_acknowledge(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 1);
 614                         } else {
 615                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
 616                         }
 617                 }
 618                 break;
 619 
 620         case FTDM_CHANNEL_STATE_PROGRESS_MEDIA:
 621                 {
 622                         if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
 623                                 sig.event_id = FTDM_SIGEVENT_PROGRESS_MEDIA;
 624                                 if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
 625                                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
 626                                 }
 627                         } else if (call) {
 628                                 /* make sure channel is open in this state (outbound handled in on_proceeding()) */
 629                                 if (!ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
 630                                         ftdm_channel_open_chan(chan);
 631                                 }
 632                                 pri_progress(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 1);
 633                         } else {
 634                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
 635                         }
 636                 }
 637                 break;
 638 
 639         case FTDM_CHANNEL_STATE_PROCEED:
 640                 {
 641                         if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
 642                                 /* PROCEED from other end, notify user */
 643                                 sig.event_id = FTDM_SIGEVENT_PROCEED;
 644                                 if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
 645                                         ftdm_log(FTDM_LOG_ERROR, "Failed to send PROCEED sigevent on Channel %d:%d\n",
 646                                                 ftdm_channel_get_span_id(chan),
 647                                                 ftdm_channel_get_id(chan));
 648                                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
 649                                 }
 650                         } else if (call) {
 651                                 pri_proceeding(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
 652                         } else {
 653                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
 654                         }
 655                 }
 656                 break;
 657 
 658         case FTDM_CHANNEL_STATE_RING:
 659                 {
 660                         /*
 661                          * This needs more auditing for BRI PTMP:
 662                          * does pri_acknowledge() steal the call from other devices? (yes, it does)
 663                          */
 664                         if (!ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
 665                                 if (call) {
 666                                         pri_proceeding(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
 667 //                                      pri_acknowledge(isdn_data->spri.pri, call, ftdm_channel_get_id(chan), 0);
 668                                         sig.event_id = FTDM_SIGEVENT_START;
 669                                         if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
 670                                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
 671                                         }
 672                                 } else {
 673                                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
 674                                 }
 675                         }
 676                 }
 677                 break;
 678 
 679         case FTDM_CHANNEL_STATE_RESTART:
 680                 {
 681                         chan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_UNSPECIFIED;
 682                         sig.event_id = FTDM_SIGEVENT_RESTART;
 683                         status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig);
 684                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
 685                 }
 686                 break;
 687 
 688         case FTDM_CHANNEL_STATE_UP:
 689                 {
 690                         if (ftdm_test_flag(chan, FTDM_CHANNEL_OUTBOUND)) {
 691                                 sig.event_id = FTDM_SIGEVENT_UP;
 692                                 if ((status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig) != FTDM_SUCCESS)) {
 693                                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
 694                                 }
 695                         } else if (call) {
 696                                 /* make sure channel is open in this state (outbound handled in on_answer()) */
 697                                 if (!ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
 698                                         ftdm_channel_open_chan(chan);
 699                                 }
 700                                 pri_answer(isdn_data->spri.pri, call, 0, 1);
 701                         } else {
 702                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
 703                         }
 704                 }
 705                 break;
 706 
 707         case FTDM_CHANNEL_STATE_DIALING:
 708                 if (isdn_data) {
 709                         ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
 710                         struct pri_sr *sr;
 711                         int ton;
 712 
 713                         if (!(call = pri_new_call(isdn_data->spri.pri))) {
 714                                 ftdm_log(FTDM_LOG_ERROR, "Failed to create new call on channel %d:%d\n",
 715                                         ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
 716                                 /* TODO: set hangup cause? */
 717                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
 718                                 return FTDM_SUCCESS;
 719                         }
 720 
 721                         ton = caller_data->dnis.type;
 722                         switch (ton) {
 723                         case FTDM_TON_NATIONAL:
 724                                 ton = PRI_NATIONAL_ISDN;
 725                                 break;
 726                         case FTDM_TON_INTERNATIONAL:
 727                                 ton = PRI_INTERNATIONAL_ISDN;
 728                                 break;
 729                         case FTDM_TON_SUBSCRIBER_NUMBER:
 730                                 ton = PRI_LOCAL_ISDN;
 731                                 break;
 732                         default:
 733                                 ton = isdn_data->ton;
 734                         }
 735 
 736                         chan->call_data = call;
 737 
 738                         sr = pri_sr_new();
 739                         if (!sr) {
 740                                 ftdm_log(FTDM_LOG_ERROR, "Failed to create new setup request on channel %d:%d\n",
 741                                         ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
 742                                 /* TODO: handle error properly */
 743                         }
 744                         assert(sr);
 745 
 746                         pri_sr_set_channel(sr, ftdm_channel_get_id(chan), 0, 0);
 747                         pri_sr_set_bearer(sr, PRI_TRANS_CAP_SPEECH, isdn_data->layer1);
 748 
 749                         pri_sr_set_called(sr, caller_data->dnis.digits, ton, 1);
 750                         pri_sr_set_caller(sr, caller_data->cid_num.digits,
 751                                         ((isdn_data->opts & FTMOD_LIBPRI_OPT_OMIT_DISPLAY_IE) ? NULL : caller_data->cid_name),
 752                                         ton,
 753                                         ((caller_data->pres != 1) ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_PROHIB_USER_NUMBER_NOT_SCREENED));
 754 
 755                         if (!(isdn_data->opts & FTMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE)) {
 756                                 pri_sr_set_redirecting(sr, caller_data->cid_num.digits, ton,
 757                                         PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, PRI_REDIR_UNCONDITIONAL);
 758                         }
 759 #ifdef HAVE_LIBPRI_AOC
 760                         if (isdn_data->opts & FTMOD_LIBPRI_OPT_FACILITY_AOC) {
 761                                 /* request AOC on call */
 762                                 pri_sr_set_aoc_charging_request(sr, (PRI_AOC_REQUEST_S | PRI_AOC_REQUEST_E | PRI_AOC_REQUEST_D));
 763                                 ftdm_log(FTDM_LOG_DEBUG, "Requesting AOC-S/D/E on call\n");
 764                         }
 765 #endif
 766                         if (pri_setup(isdn_data->spri.pri, call, sr)) {
 767                                 caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
 768                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP);
 769                         }
 770 
 771                         pri_sr_free(sr);
 772                 }
 773                 break;
 774 
 775         case FTDM_CHANNEL_STATE_HANGUP:
 776                 {
 777                         if (call) {
 778                                 ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
 779 
 780                                 pri_hangup(isdn_data->spri.pri, call, caller_data->hangup_cause);
 781 //                              pri_destroycall(isdn_data->spri.pri, call);
 782 
 783                                 chan->call_data = NULL;
 784                         }
 785                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_HANGUP_COMPLETE);
 786                 }
 787                 break;
 788 
 789         case FTDM_CHANNEL_STATE_HANGUP_COMPLETE:
 790                 {
 791                         if (call) {
 792                                 pri_destroycall(isdn_data->spri.pri, call);
 793                                 chan->call_data = NULL;
 794                         }
 795                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_DOWN);
 796                 }
 797                 break;
 798 
 799         case FTDM_CHANNEL_STATE_TERMINATING:
 800                 {
 801                         sig.event_id = FTDM_SIGEVENT_STOP;
 802                         status = ftdm_span_send_signal(ftdm_channel_get_span(chan), &sig);
 803                         /* user moves us to HANGUP and from there we go to DOWN */
 804                 }
 805         default:
 806                 break;
 807         }
 808         return FTDM_SUCCESS;
 809 }
 810 
 811 /**
 812  * \brief Checks current state on a span
 813  * \param span Span to check status on
 814  */
 815 static __inline__ void check_state(ftdm_span_t *span)
 816 {
 817         if (ftdm_test_flag(span, FTDM_SPAN_STATE_CHANGE)) {
 818                 uint32_t j;
 819 
 820                 ftdm_clear_flag_locked(span, FTDM_SPAN_STATE_CHANGE);
 821 
 822                 for (j = 1; j <= ftdm_span_get_chan_count(span); j++) {
 823                         ftdm_channel_t *chan = ftdm_span_get_channel(span, j);
 824                         ftdm_channel_lock(chan);
 825                         ftdm_channel_advance_states(chan);
 826                         ftdm_channel_unlock(chan);
 827                 }
 828         }
 829 }
 830 
 831 /**
 832  * \brief Handler for libpri information event (incoming call?)
 833  * \param spri Pri wrapper structure (libpri, span, dchan)
 834  * \param event_type Event type (unused)
 835  * \param pevent Event
 836  * \return 0
 837  */
 838 static int on_info(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
 839 {
 840         ftdm_log(FTDM_LOG_DEBUG, "number is: %s\n", pevent->ring.callednum);
 841 
 842         if (strlen(pevent->ring.callednum) > 3) {
 843                 ftdm_log(FTDM_LOG_DEBUG, "final number is: %s\n", pevent->ring.callednum);
 844                 pri_answer(spri->pri, pevent->ring.call, 0, 1);
 845         }
 846         return 0;
 847 }
 848 
 849 /**
 850  * \brief Handler for libpri hangup event
 851  * \param spri Pri wrapper structure (libpri, span, dchan)
 852  * \param event_type Event type (unused)
 853  * \param pevent Event
 854  * \return 0
 855  */
 856 static int on_hangup(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
 857 {
 858         ftdm_span_t *span = spri->span;
 859         ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->hangup.channel);
 860         q931_call *call = NULL;
 861 
 862         if (!chan) {
 863                 ftdm_log(FTDM_LOG_CRIT, "-- Hangup on channel %d:%d %s but it's not in use?\n", ftdm_span_get_id(spri->span), pevent->hangup.channel);
 864                 return 0;
 865         }
 866 
 867         ftdm_channel_lock(chan);
 868 
 869         if (ftdm_channel_get_state(chan) >= FTDM_CHANNEL_STATE_TERMINATING) {
 870                 ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Ignoring remote hangup in state %s\n", ftdm_channel_get_state_str(chan));
 871                 goto done;
 872         }
 873 
 874         if (!chan->call_data) {
 875                 ftdm_log_chan(chan, FTDM_LOG_DEBUG, "Ignoring remote hangup in state %s with no call data\n", ftdm_channel_get_state_str(chan));
 876                 goto done;
 877         }
 878 
 879         call = (q931_call *)chan->call_data;
 880 
 881         ftdm_log(FTDM_LOG_DEBUG, "-- Hangup on channel %d:%d\n", ftdm_span_get_id(spri->span), pevent->hangup.channel);
 882 
 883         pri_release(spri->pri, call, 0);
 884         pri_destroycall(spri->pri, call);
 885 
 886         chan->caller_data.hangup_cause = pevent->hangup.cause;
 887         chan->call_data = NULL;
 888         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_TERMINATING);
 889 
 890 done:
 891         ftdm_channel_unlock(chan);
 892         return 0;
 893 }
 894 
 895 /**
 896  * \brief Handler for libpri answer event
 897  * \param spri Pri wrapper structure (libpri, span, dchan)
 898  * \param event_type Event type (unused)
 899  * \param pevent Event
 900  * \return 0
 901  */
 902 static int on_answer(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
 903 {
 904         ftdm_span_t *span = spri->span;
 905         ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->answer.channel);
 906 
 907         if (chan) {
 908                 if (!ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
 909                         ftdm_log(FTDM_LOG_DEBUG, "-- Call answered, opening B-Channel %d:%d\n",
 910                                 ftdm_channel_get_span_id(chan),
 911                                 ftdm_channel_get_id(chan));
 912 
 913                         if (ftdm_channel_open_chan(chan) != FTDM_SUCCESS) {
 914                                 ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
 915 
 916                                 ftdm_log(FTDM_LOG_ERROR, "-- Error opening channel %d:%d\n",
 917                                         ftdm_channel_get_span_id(chan),
 918                                         ftdm_channel_get_id(chan));
 919 
 920                                 caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
 921                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_TERMINATING);
 922                                 goto out;
 923                         }
 924                 }
 925                 ftdm_log(FTDM_LOG_DEBUG, "-- Answer on channel %d:%d\n", ftdm_span_get_id(span), pevent->answer.channel);
 926                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_UP);
 927         } else {
 928                 ftdm_log(FTDM_LOG_DEBUG, "-- Answer on channel %d:%d but it's not in the span?\n",
 929                         ftdm_span_get_id(span), pevent->answer.channel);
 930         }
 931 out:
 932         return 0;
 933 }
 934 
 935 /**
 936  * \brief Handler for libpri proceeding event
 937  * \param spri Pri wrapper structure (libpri, span, dchan)
 938  * \param event_type Event type (unused)
 939  * \param pevent Event
 940  * \return 0
 941  */
 942 static int on_proceeding(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
 943 {
 944         ftdm_span_t *span = spri->span;
 945         ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->proceeding.channel);
 946 
 947         if (chan) {
 948                 /* Open channel if inband information is available */
 949                 if ((pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) && !ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
 950                         ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, opening B-Channel %d:%d\n",
 951                                 ftdm_channel_get_span_id(chan),
 952                                 ftdm_channel_get_id(chan));
 953 
 954                         if (ftdm_channel_open_chan(chan) != FTDM_SUCCESS) {
 955                                 ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
 956 
 957                                 ftdm_log(FTDM_LOG_ERROR, "-- Error opening channel %d:%d\n",
 958                                         ftdm_channel_get_span_id(chan),
 959                                         ftdm_channel_get_id(chan));
 960 
 961                                 caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
 962                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_TERMINATING);
 963                                 goto out;
 964                         }
 965                 }
 966                 ftdm_log(FTDM_LOG_DEBUG, "-- Proceeding on channel %d:%d\n", ftdm_span_get_id(span), pevent->proceeding.channel);
 967                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_PROCEED);
 968         } else {
 969                 ftdm_log(FTDM_LOG_DEBUG, "-- Proceeding on channel %d:%d but it's not in the span?\n",
 970                                                 ftdm_span_get_id(span), pevent->proceeding.channel);
 971         }
 972 out:
 973         return 0;
 974 }
 975 
 976 /**
 977  * \brief Handler for libpri progress event
 978  * \param spri Pri wrapper structure (libpri, span, dchan)
 979  * \param event_type Event type (unused)
 980  * \param pevent Event
 981  * \return 0
 982  * \note also uses pri_event->proceeding
 983  */
 984 static int on_progress(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
 985 {
 986         ftdm_span_t *span = spri->span;
 987         ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->proceeding.channel);
 988 
 989         if (chan) {
 990                 /* Open channel if inband information is available */
 991                 if ((pevent->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) && !ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
 992                         ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, opening B-Channel %d:%d\n",
 993                                 ftdm_channel_get_span_id(chan),
 994                                 ftdm_channel_get_id(chan));
 995 
 996                         if (ftdm_channel_open_chan(chan) != FTDM_SUCCESS) {
 997                                 ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
 998 
 999                                 ftdm_log(FTDM_LOG_ERROR, "-- Error opening channel %d:%d\n",
1000                                         ftdm_channel_get_span_id(chan),
1001                                         ftdm_channel_get_id(chan));
1002 
1003                                 caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
1004                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_TERMINATING);
1005                                 goto out;
1006                         }
1007                         ftdm_log(FTDM_LOG_DEBUG, "-- Progress on channel %d:%d with media\n", ftdm_span_get_id(span), pevent->proceeding.channel);
1008                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_PROGRESS_MEDIA);
1009                 } else {
1010                         ftdm_log(FTDM_LOG_DEBUG, "-- Progress on channel %d:%d\n", ftdm_span_get_id(span), pevent->proceeding.channel);
1011                         ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_PROGRESS);
1012                 }
1013         } else {
1014                 ftdm_log(FTDM_LOG_DEBUG, "-- Progress on channel %d:%d but it's not in the span?\n",
1015                                                 ftdm_span_get_id(span), pevent->proceeding.channel);
1016         }
1017 out:
1018         return 0;
1019 }
1020 
1021 /**
1022  * \brief Handler for libpri ringing event
1023  * \param spri Pri wrapper structure (libpri, span, dchan)
1024  * \param event_type Event type (unused)
1025  * \param pevent Event
1026  * \return 0
1027  */
1028 static int on_ringing(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
1029 {
1030         ftdm_span_t *span = spri->span;
1031         ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->ringing.channel);
1032 
1033         if (chan) {
1034                 ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d\n", ftdm_span_get_id(span), pevent->ringing.channel);
1035 
1036                 /* we may get on_ringing even when we're already in FTDM_CHANNEL_STATE_PROGRESS_MEDIA */
1037 //              if (ftdm_channel_get_state(chan) == FTDM_CHANNEL_STATE_PROGRESS_MEDIA) {
1038 //                      /* dont try to move to STATE_PROGRESS to avoid annoying veto warning */
1039 //                      return 0;
1040 //              }
1041 
1042                 /* Open channel if inband information is available */
1043                 if ((pevent->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) && !ftdm_test_flag(chan, FTDM_CHANNEL_OPEN)) {
1044                         ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, opening B-Channel %d:%d\n",
1045                                 ftdm_channel_get_span_id(chan),
1046                                 ftdm_channel_get_id(chan));
1047 
1048                         if (ftdm_channel_open_chan(chan) != FTDM_SUCCESS) {
1049                                 ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
1050 
1051                                 ftdm_log(FTDM_LOG_ERROR, "-- Error opening channel %d:%d\n",
1052                                         ftdm_channel_get_span_id(chan),
1053                                         ftdm_channel_get_id(chan));
1054 
1055                                 caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
1056                                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_TERMINATING);
1057                                 goto out;
1058                         }
1059                 }
1060 //              ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_PROGRESS);
1061                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RINGING);
1062         } else {
1063                 ftdm_log(FTDM_LOG_DEBUG, "-- Ringing on channel %d:%d but it's not in the span?\n",
1064                         ftdm_span_get_id(span), pevent->ringing.channel);
1065         }
1066 out:
1067         return 0;
1068 }
1069 
1070 /**
1071  * \brief Handler for libpri ring event
1072  * \param spri Pri wrapper structure (libpri, span, dchan)
1073  * \param event_type Event type (unused)
1074  * \param pevent Event
1075  * \return 0 on success
1076  */
1077 static int on_ring(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
1078 {
1079         ftdm_span_t *span = spri->span;
1080         ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->ring.channel);
1081         ftdm_caller_data_t *caller_data = NULL;
1082         int ret = 0;
1083 
1084         if (!chan) {
1085                 ftdm_log(FTDM_LOG_ERROR, "-- Unable to get channel %d:%d\n", ftdm_span_get_id(span), pevent->ring.channel);
1086                 return ret;
1087         }
1088 
1089         ftdm_channel_lock(chan);
1090 
1091         if (chan->call_data) {
1092                 /* we could drop the incoming call, but most likely the pointer is just a ghost of the past, 
1093                  * this check is just to detect potentially unreleased pointers */
1094                 ftdm_log_chan(chan, FTDM_LOG_ERROR, "channel already has call %p!\n", chan->call_data);
1095                 chan->call_data = NULL;
1096         }
1097 
1098         if (ftdm_channel_get_state(chan) != FTDM_CHANNEL_STATE_DOWN || ftdm_test_flag(chan, FTDM_CHANNEL_INUSE)) {
1099                 ftdm_log(FTDM_LOG_WARNING, "-- Duplicate Ring on channel %d:%d (ignored)\n", ftdm_span_get_id(span), pevent->ring.channel);
1100                 goto done;
1101         }
1102 
1103         if ((pevent->ring.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
1104                 /* Open channel if inband information is available */
1105                 ftdm_log(FTDM_LOG_DEBUG, "-- In-band information available, opening B-Channel %d:%d\n",
1106                         ftdm_channel_get_span_id(chan),
1107                         ftdm_channel_get_id(chan));
1108 
1109                 if (!ftdm_test_flag(chan, FTDM_CHANNEL_OPEN) && ftdm_channel_open_chan(chan) != FTDM_SUCCESS) {
1110 //                      ftdm_caller_data_t *caller_data = ftdm_channel_get_caller_data(chan);
1111 
1112                         ftdm_log(FTDM_LOG_WARNING, "-- Error opening channel %d:%d (ignored)\n",
1113                                 ftdm_channel_get_span_id(chan),
1114                                 ftdm_channel_get_id(chan));
1115 
1116 //                      caller_data->hangup_cause = FTDM_CAUSE_DESTINATION_OUT_OF_ORDER;
1117 //                      ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_TERMINATING);
1118 //                      goto done;
1119                 }
1120         } else {
1121                 /* Reserve channel, don't open it yet */
1122                 if (ftdm_channel_use(chan) != FTDM_SUCCESS) {
1123                         ftdm_log(FTDM_LOG_WARNING, "-- Error reserving channel %d:%d (ignored)\n",
1124                                 ftdm_span_get_id(span), pevent->ring.channel);
1125                         goto done;
1126                 }
1127         }
1128 
1129         ftdm_log(FTDM_LOG_NOTICE, "-- Ring on channel %d:%d (from %s to %s)\n", ftdm_span_get_id(span), pevent->ring.channel,
1130                                           pevent->ring.callingnum, pevent->ring.callednum);
1131 
1132         caller_data = ftdm_channel_get_caller_data(chan);
1133 
1134         memset(caller_data, 0, sizeof(*caller_data));
1135 
1136         ftdm_set_string(caller_data->cid_num.digits, (char *)pevent->ring.callingnum);
1137         ftdm_set_string(caller_data->ani.digits, (char *)pevent->ring.callingani);
1138         ftdm_set_string(caller_data->dnis.digits, (char *)pevent->ring.callednum);
1139         ftdm_set_string(caller_data->rdnis.digits, (char *)pevent->ring.redirectingnum);
1140 
1141         if (!ftdm_strlen_zero((char *)pevent->ring.callingname)) {
1142                 ftdm_set_string(caller_data->cid_name, (char *)pevent->ring.callingname);
1143         } else {
1144                 ftdm_set_string(caller_data->cid_name, (char *)pevent->ring.callingnum);
1145         }
1146 
1147         if (pevent->ring.ani2 >= 0) {
1148                 snprintf(caller_data->aniII, 5, "%.2d", pevent->ring.ani2);
1149         }
1150 
1151         // scary to trust this pointer, you'd think they would give you a copy of the call data so you own it......
1152         /* hurr, this is valid as along as nobody releases the call */
1153         chan->call_data = pevent->ring.call;
1154 
1155         ftdm_set_state(chan, FTDM_CHANNEL_STATE_RING);
1156 
1157 done:
1158         ftdm_channel_unlock(chan);
1159         return ret;
1160 }
1161 
1162 /**
1163  * \brief Processes freetdm event
1164  * \param span Span on which the event was fired
1165  * \param event Event to be treated
1166  * \return Success or failure
1167  */
1168 static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
1169 {
1170         ftdm_alarm_flag_t alarmbits;
1171 
1172         ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d][%d:%d] STATE [%s]\n",
1173                         ftdm_oob_event2str(event->enum_id),
1174                         event->enum_id,
1175                         ftdm_channel_get_span_id(event->channel),
1176                         ftdm_channel_get_id(event->channel),
1177                         ftdm_channel_get_state_str(event->channel));
1178 
1179         switch (event->enum_id) {
1180         case FTDM_OOB_ALARM_TRAP:
1181                 {
1182                         if (ftdm_channel_get_state(event->channel) != FTDM_CHANNEL_STATE_DOWN) {
1183                                 if (ftdm_channel_get_type(event->channel) == FTDM_CHAN_TYPE_B) {
1184                                         ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_RESTART);
1185                                 }
1186                         }
1187 
1188                         ftdm_set_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
1189 
1190                         ftdm_channel_get_alarms(event->channel, &alarmbits);
1191                         ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) has alarms! [%s]\n",
1192                                         ftdm_channel_get_span_id(event->channel), ftdm_channel_get_id(event->channel),
1193                                         ftdm_channel_get_ph_span_id(event->channel), ftdm_channel_get_ph_id(event->channel),
1194                                         ftdm_channel_get_last_error(event->channel));
1195                 }
1196                 break;
1197         case FTDM_OOB_ALARM_CLEAR:
1198                 {
1199                         ftdm_log(FTDM_LOG_WARNING, "channel %d:%d (%d:%d) alarms Cleared!\n",
1200                                         ftdm_channel_get_span_id(event->channel), ftdm_channel_get_id(event->channel),
1201                                         ftdm_channel_get_ph_span_id(event->channel), ftdm_channel_get_ph_id(event->channel));
1202 
1203                         ftdm_clear_flag(event->channel, FTDM_CHANNEL_SUSPENDED);
1204                         ftdm_channel_get_alarms(event->channel, &alarmbits);
1205                 }
1206                 break;
1207         }
1208         return FTDM_SUCCESS;
1209 }
1210 
1211 /**
1212  * \brief Checks for events on a span
1213  * \param span Span to check for events
1214  */
1215 static __inline__ void check_events(ftdm_span_t *span)
1216 {
1217         ftdm_status_t status;
1218 
1219         status = ftdm_span_poll_event(span, 5, NULL);
1220 
1221         switch (status) {
1222         case FTDM_SUCCESS:
1223                 {
1224                         ftdm_event_t *event;
1225 
1226                         while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
1227                                 if (event->enum_id == FTDM_OOB_NOOP) {
1228                                         continue;
1229                                 }
1230                                 if (process_event(span, event) != FTDM_SUCCESS) {
1231                                         break;
1232                                 }
1233                         }
1234                 }
1235                 break;
1236 
1237         case FTDM_FAIL:
1238                 ftdm_log(FTDM_LOG_DEBUG, "Event Failure! %d\n", ftdm_running());
1239                 ftdm_sleep(2000);
1240                 break;
1241 
1242         default:
1243                 break;
1244         }
1245 }
1246 
1247 /**
1248  * \brief Checks flags on a pri span
1249  * \param spri Pri wrapper structure (libpri, span, dchan)
1250  * \return 0 on success, -1 on error
1251  */
1252 static int check_flags(lpwrap_pri_t *spri)
1253 {
1254         ftdm_span_t *span = spri->span;
1255 
1256         if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
1257                 return -1;
1258         }
1259 
1260         check_state(span);
1261         check_events(span);
1262         return 0;
1263 }
1264 
1265 /**
1266  * \brief Handler for libpri restart event
1267  * \param spri Pri wrapper structure (libpri, span, dchan)
1268  * \param event_type Event type (unused)
1269  * \param pevent Event
1270  * \return 0
1271  */
1272 static int on_restart(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
1273 {
1274         ftdm_span_t *span = spri->span;
1275         ftdm_channel_t *chan = ftdm_span_get_channel(span, pevent->restart.channel);
1276 
1277         ftdm_log(FTDM_LOG_NOTICE, "-- Restarting %d:%d\n", ftdm_span_get_id(span), pevent->restart.channel);
1278         _ftdm_channel_set_state_force(spri->dchan, FTDM_CHANNEL_STATE_UP);
1279 
1280         if (!chan) {
1281                 return 0;
1282         }
1283 
1284         if (pevent->restart.channel < 1) {
1285                 ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
1286         } else {
1287                 ftdm_set_state_locked(chan, FTDM_CHANNEL_STATE_RESTART);
1288         }
1289         return 0;
1290 }
1291 
1292 /*
1293  * FACILITY Advice-On-Charge handler
1294  */
1295 #ifdef HAVE_LIBPRI_AOC
1296 static const char *aoc_billing_id(const int id)
1297 {
1298         switch (id) {
1299         case PRI_AOC_E_BILLING_ID_NOT_AVAILABLE:
1300                 return "not available";
1301         case PRI_AOC_E_BILLING_ID_NORMAL:
1302                 return "normal";
1303         case PRI_AOC_E_BILLING_ID_REVERSE:
1304                 return "reverse";
1305         case PRI_AOC_E_BILLING_ID_CREDIT_CARD:
1306                 return "credit card";
1307         case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_UNCONDITIONAL:
1308                 return "call forwarding unconditional";
1309         case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_BUSY:
1310                 return "call forwarding busy";
1311         case PRI_AOC_E_BILLING_ID_CALL_FORWARDING_NO_REPLY:
1312                 return "call forwarding no reply";
1313         case PRI_AOC_E_BILLING_ID_CALL_DEFLECTION:
1314                 return "call deflection";
1315         case PRI_AOC_E_BILLING_ID_CALL_TRANSFER:
1316                 return "call transfer";
1317         default:
1318                 return "unknown\n";
1319         }
1320 }
1321 
1322 static float aoc_money_amount(const struct pri_aoc_amount *amount)
1323 {
1324         switch (amount->multiplier) {
1325         case PRI_AOC_MULTIPLIER_THOUSANDTH:
1326                 return amount->cost * 0.001f;
1327         case PRI_AOC_MULTIPLIER_HUNDREDTH:
1328                 return amount->cost * 0.01f;
1329         case PRI_AOC_MULTIPLIER_TENTH:
1330                 return amount->cost * 0.1f;
1331         case PRI_AOC_MULTIPLIER_TEN:
1332                 return amount->cost * 10.0f;
1333         case PRI_AOC_MULTIPLIER_HUNDRED:
1334                 return amount->cost * 100.0f;
1335         case PRI_AOC_MULTIPLIER_THOUSAND:
1336                 return amount->cost * 1000.0f;
1337         default:
1338                 return amount->cost;
1339         }
1340 }
1341 
1342 static int handle_facility_aoc_s(const struct pri_subcmd_aoc_s *aoc_s)
1343 {
1344         /* Left as an excercise to the reader */
1345         return 0;
1346 }
1347 
1348 static int handle_facility_aoc_d(const struct pri_subcmd_aoc_d *aoc_d)
1349 {
1350         /* Left as an excercise to the reader */
1351         return 0;
1352 }
1353 
1354 static int handle_facility_aoc_e(const struct pri_subcmd_aoc_e *aoc_e)
1355 {
1356         char tmp[1024] = { 0 };
1357         int x = 0, offset = 0;
1358 
1359         switch (aoc_e->charge) {
1360         case PRI_AOC_DE_CHARGE_FREE:
1361                 strcat(tmp, "\tcharge-type: none\n");
1362                 offset = strlen(tmp);
1363                 break;
1364 
1365         case PRI_AOC_DE_CHARGE_CURRENCY:
1366                 sprintf(tmp, "\tcharge-type: money\n\tcharge-amount: %.2f\n\tcharge-currency: %s\n",
1367                                 aoc_money_amount(&aoc_e->recorded.money.amount),
1368                                 aoc_e->recorded.money.currency);
1369                 offset = strlen(tmp);
1370                 break;
1371 
1372         case PRI_AOC_DE_CHARGE_UNITS:
1373                 strcat(tmp, "\tcharge-type: units\n");
1374                 offset = strlen(tmp);
1375 
1376                 for (x = 0; x < aoc_e->recorded.unit.num_items; x++) {
1377                         sprintf(&tmp[offset], "\tcharge-amount: %ld (type: %d)\n",
1378                                         aoc_e->recorded.unit.item[x].number,
1379                                         aoc_e->recorded.unit.item[x].type);
1380                         offset += strlen(&tmp[offset]);
1381                 }
1382                 break;
1383 
1384         default:
1385                 strcat(tmp, "\tcharge-type: not available\n");
1386                 offset = strlen(tmp);
1387         }
1388 
1389         sprintf(&tmp[offset], "\tbilling-id: %s\n", aoc_billing_id(aoc_e->billing_id));
1390         offset += strlen(&tmp[offset]);
1391 
1392         strcat(&tmp[offset], "\tassociation-type: ");
1393         offset += strlen(&tmp[offset]);
1394 
1395         switch (aoc_e->associated.charging_type) {
1396         case PRI_AOC_E_CHARGING_ASSOCIATION_NOT_AVAILABLE:
1397                 strcat(&tmp[offset], "not available\n");
1398                 break;
1399         case PRI_AOC_E_CHARGING_ASSOCIATION_NUMBER:
1400                 sprintf(&tmp[offset], "number\n\tassociation-number: %s\n", aoc_e->associated.charge.number.str);
1401                 break;
1402         case PRI_AOC_E_CHARGING_ASSOCIATION_ID:
1403                 sprintf(&tmp[offset], "id\n\tassociation-id: %d\n", aoc_e->associated.charge.id);
1404                 break;
1405         default:
1406                 strcat(&tmp[offset], "unknown\n");
1407         }
1408 
1409         ftdm_log(FTDM_LOG_INFO, "AOC-E:\n%s", tmp);
1410         return 0;
1411 }
1412 
1413 /**
1414  * \brief Handler for libpri facility events
1415  * \param spri Pri wrapper structure (libpri, span, dchan)
1416  * \param event_type Event type (unused)
1417  * \param pevent Event
1418  * \return 0
1419  */
1420 static int on_facility(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
1421 {
1422         struct pri_event_facility *pfac = &pevent->facility;
1423         int i = 0;
1424 
1425         if (!pevent)
1426                 return 0;
1427 
1428         ftdm_log(FTDM_LOG_DEBUG, "Got a FACILITY event on span %d:%d\n", ftdm_span_get_id(spri->span), pfac->channel);
1429 
1430         if (!pfac->subcmds || pfac->subcmds->counter_subcmd <= 0)
1431                 return 0;
1432 
1433         for (i = 0; i < pfac->subcmds->counter_subcmd; i++) {
1434                 struct pri_subcommand *sub = &pfac->subcmds->subcmd[i];
1435                 int res = -1;
1436 
1437                 switch (sub->cmd) {
1438                 case PRI_SUBCMD_AOC_S:  /* AOC-S: Start of call */
1439                         res = handle_facility_aoc_s(&sub->u.aoc_s);
1440                         break;
1441                 case PRI_SUBCMD_AOC_D:  /* AOC-D: During call */
1442                         res = handle_facility_aoc_d(&sub->u.aoc_d);
1443                         break;
1444                 case PRI_SUBCMD_AOC_E:  /* AOC-E: End of call */
1445                         res = handle_facility_aoc_e(&sub->u.aoc_e);
1446                         break;
1447                 case PRI_SUBCMD_AOC_CHARGING_REQ:
1448                         ftdm_log(FTDM_LOG_NOTICE, "AOC Charging Request received\n");
1449                         break;
1450                 case PRI_SUBCMD_AOC_CHARGING_REQ_RSP:
1451                         ftdm_log(FTDM_LOG_NOTICE, "AOC Charging Request Response received [aoc_s data: %s, req: %x, resp: %x]\n",
1452                                         sub->u.aoc_request_response.valid_aoc_s ? "yes" : "no",
1453                                         sub->u.aoc_request_response.charging_request,
1454                                         sub->u.aoc_request_response.charging_response);
1455                         break;
1456                 default:
1457                         ftdm_log(FTDM_LOG_DEBUG, "FACILITY subcommand %d is not implemented, ignoring\n", sub->cmd);
1458                 }
1459 
1460                 ftdm_log(FTDM_LOG_DEBUG, "FACILITY subcommand %d handler returned %d\n", sub->cmd, res);
1461         }
1462 
1463         ftdm_log(FTDM_LOG_DEBUG, "Caught Event on span %d %u (%s)\n", ftdm_span_get_id(spri->span), event_type, lpwrap_pri_event_str(event_type));
1464         return 0;
1465 }
1466 #endif
1467 
1468 /**
1469  * \brief Handler for libpri dchan up event
1470  * \param spri Pri wrapper structure (libpri, span, dchan)
1471  * \param event_type Event type (unused)
1472  * \param pevent Event
1473  * \return 0
1474  */
1475 static int on_dchan_up(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
1476 {
1477         if (!ftdm_test_flag(spri, LPWRAP_PRI_READY)) {
1478                 ftdm_signaling_status_t status = FTDM_SIG_STATE_UP;
1479                 ftdm_span_t *span = spri->span;
1480                 ftdm_sigmsg_t sig;
1481                 int i;
1482 
1483                 ftdm_log(FTDM_LOG_INFO, "Span %d D-Channel UP!\n", ftdm_span_get_id(span));
1484                 ftdm_set_flag(spri, LPWRAP_PRI_READY);
1485                 ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
1486 
1487                 ftdm_log(FTDM_LOG_NOTICE, "%d:Signaling link status changed to %s\n", ftdm_span_get_id(span), ftdm_signaling_status2str(status));
1488 
1489                 for (i = 1; i <= ftdm_span_get_chan_count(span); i++) {
1490                         ftdm_channel_t *chan = ftdm_span_get_channel(span, i);
1491 
1492                         memset(&sig, 0, sizeof(sig));
1493                         sig.span_id = ftdm_channel_get_span_id(chan);
1494                         sig.chan_id = ftdm_channel_get_id(chan);
1495                         sig.channel = chan;
1496                         sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
1497                         sig.ev_data.sigstatus.status = status;
1498                         ftdm_span_send_signal(span, &sig);
1499                 }
1500         }
1501         return 0;
1502 }
1503 
1504 /**
1505  * \brief Handler for libpri dchan down event
1506  * \param spri Pri wrapper structure (libpri, span, dchan)
1507  * \param event_type Event type (unused)
1508  * \param pevent Event
1509  * \return 0
1510  */
1511 static int on_dchan_down(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
1512 {
1513         if (ftdm_test_flag(spri, LPWRAP_PRI_READY)) {
1514                 ftdm_signaling_status_t status = FTDM_SIG_STATE_DOWN;
1515                 ftdm_span_t *span = spri->span;
1516                 ftdm_sigmsg_t sig;
1517                 int i;
1518 
1519                 ftdm_log(FTDM_LOG_INFO, "Span %d D-Channel DOWN!\n", ftdm_span_get_id(span));
1520                 ftdm_clear_flag(spri, LPWRAP_PRI_READY);
1521                 ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
1522 
1523                 ftdm_log(FTDM_LOG_NOTICE, "%d:Signaling link status changed to %s\n", ftdm_span_get_id(span), ftdm_signaling_status2str(status));
1524 
1525                 for (i = 1; i <= ftdm_span_get_chan_count(span); i++) {
1526                         ftdm_channel_t *chan = ftdm_span_get_channel(span, i);
1527 
1528                         memset(&sig, 0, sizeof(sig));
1529                         sig.span_id = ftdm_channel_get_span_id(chan);
1530                         sig.chan_id = ftdm_channel_get_id(chan);
1531                         sig.channel = chan;
1532                         sig.event_id = FTDM_SIGEVENT_SIGSTATUS_CHANGED;
1533                         sig.ev_data.sigstatus.status = status;
1534 
1535                         ftdm_span_send_signal(span, &sig);
1536                 }
1537         }
1538 
1539         return 0;
1540 }
1541 
1542 /**
1543  * \brief Handler for any libpri event
1544  * \param spri Pri wrapper structure (libpri, span, dchan)
1545  * \param event_type Event type (unused)
1546  * \param pevent Event
1547  * \return 0
1548  */
1549 static int on_anything(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
1550 {
1551         ftdm_log(FTDM_LOG_DEBUG, "-- Caught Event span %d %u (%s)\n", ftdm_span_get_id(spri->span), event_type, lpwrap_pri_event_str(event_type));
1552         return 0;
1553 }
1554 
1555 /**
1556  * \brief Handler for libpri io fail event
1557  * \param spri Pri wrapper structure (libpri, span, dchan)
1558  * \param event_type Event type (unused)
1559  * \param pevent Event
1560  * \return 0
1561  */
1562 static int on_io_fail(lpwrap_pri_t *spri, lpwrap_pri_event_t event_type, pri_event *pevent)
1563 {
1564         ftdm_log(FTDM_LOG_DEBUG, "-- Caught Event span %d %u (%s)\n", ftdm_span_get_id(spri->span), event_type, lpwrap_pri_event_str(event_type));
1565         return 0;
1566 }
1567 
1568 /**
1569  * \brief Main thread function for libpri span (monitor)
1570  * \param me Current thread
1571  * \param obj Span to run in this thread
1572  *
1573  * \todo  Move all init stuff outside of loop or into ftdm_libpri_configure_span()
1574  */
1575 static void *ftdm_libpri_run(ftdm_thread_t *me, void *obj)
1576 {
1577         ftdm_span_t *span = (ftdm_span_t *) obj;
1578         ftdm_libpri_data_t *isdn_data = span->signal_data;
1579         int down = 0;
1580         int got_d = 0;
1581         int res = 0;
1582 
1583         ftdm_set_flag(span, FTDM_SPAN_IN_THREAD);
1584 
1585         while (ftdm_running() && !ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
1586                 if (!got_d) {
1587                         int i, x;
1588 
1589                         for (i = 1, x = 0; i <= ftdm_span_get_chan_count(span); i++) {
1590                                 ftdm_channel_t *chan = ftdm_span_get_channel(span, i);
1591 
1592                                 if (ftdm_channel_get_type(chan) == FTDM_CHAN_TYPE_DQ921) {
1593                                         if (ftdm_channel_open(ftdm_span_get_id(span), i, &isdn_data->dchan) == FTDM_SUCCESS) {
1594                                                 ftdm_log(FTDM_LOG_DEBUG, "opening D-Channel #%d %d:%d\n", x,
1595                                                         ftdm_channel_get_span_id(isdn_data->dchan), ftdm_channel_get_id(isdn_data->dchan));
1596                                                 got_d = 1;
1597                                                 x++;
1598                                                 break;
1599                                         } else {
1600                                             ftdm_log(FTDM_LOG_ERROR, "failed to open D-Channel #%d %d:%d\n", x,
1601                                                 ftdm_channel_get_span_id(chan), ftdm_channel_get_id(chan));
1602                                         }
1603                                 }
1604                         }
1605                 }
1606                 if (!got_d || !isdn_data->dchan) {
1607                         ftdm_log(FTDM_LOG_ERROR, "Failed to get a D-Channel in span %d\n", ftdm_span_get_id(span));
1608                         break;
1609                 }
1610 
1611                 /* Initialize libpri trunk */
1612                 switch (ftdm_span_get_trunk_type(span)) {
1613                 case FTDM_TRUNK_E1:
1614                 case FTDM_TRUNK_T1:
1615                 case FTDM_TRUNK_J1:
1616                         res = lpwrap_init_pri(&isdn_data->spri, span, isdn_data->dchan,
1617                                         isdn_data->dialect, isdn_data->mode, isdn_data->debug_mask);
1618                         break;
1619                 case FTDM_TRUNK_BRI:
1620                         res = lpwrap_init_bri(&isdn_data->spri, span, isdn_data->dchan,
1621                                         isdn_data->dialect, isdn_data->mode, 1, isdn_data->debug_mask);
1622 #ifndef HAVE_LIBPRI_BRI
1623                         goto out;
1624 #endif
1625                         break;
1626                 case FTDM_TRUNK_BRI_PTMP:
1627                         res = lpwrap_init_bri(&isdn_data->spri, span, isdn_data->dchan,
1628                                         isdn_data->dialect, isdn_data->mode, 0, isdn_data->debug_mask);
1629 #ifndef HAVE_LIBPRI_BRI
1630                         goto out;
1631 #endif
1632                         break;
1633                 default:
1634                         snprintf(span->last_error, sizeof(span->last_error), "Invalid trunk type");
1635                         goto out;
1636                 }
1637 
1638 #ifdef HAVE_LIBPRI_AOC
1639                 /*
1640                  * Only enable facility on trunk if really required,
1641                  * this may help avoid problems on troublesome lines.
1642                  */
1643                 if (isdn_data->opts & FTMOD_LIBPRI_OPT_FACILITY_AOC) {
1644                         pri_facility_enable(isdn_data->spri.pri);
1645                 }
1646 #endif
1647 
1648                 if (res == 0) {
1649                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANY, on_anything);
1650                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RING, on_ring);
1651                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RINGING, on_ringing);
1652                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROCEEDING, on_proceeding);
1653                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_PROGRESS, on_progress);
1654                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_ANSWER, on_answer);
1655                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_UP, on_dchan_up);
1656                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_DCHAN_DOWN, on_dchan_down);
1657                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP_REQ, on_hangup);
1658                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_HANGUP, on_hangup);
1659                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_INFO_RECEIVED, on_info);
1660                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_RESTART, on_restart);
1661                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_IO_FAIL, on_io_fail);
1662 #ifdef HAVE_LIBPRI_AOC
1663                         LPWRAP_MAP_PRI_EVENT(isdn_data->spri, LPWRAP_PRI_EVENT_FACILITY, on_facility);
1664 #endif
1665                         if (down) {
1666                                 ftdm_log(FTDM_LOG_INFO, "PRI back up on span %d\n", ftdm_span_get_id(span));
1667                                 ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
1668                                 down = 0;
1669                         }
1670 
1671                         isdn_data->spri.on_loop = check_flags;
1672 
1673                         lpwrap_run_pri(&isdn_data->spri);
1674                 } else {
1675                         ftdm_log(FTDM_LOG_CRIT, "PRI init failed!\n");
1676                         snprintf(span->last_error, sizeof(span->last_error), "PRI init failed!");
1677                         break;
1678                 }
1679 
1680                 if (!ftdm_running() || ftdm_test_flag(span, FTDM_SPAN_STOP_THREAD)) {
1681                         break;
1682                 }
1683 
1684                 ftdm_log(FTDM_LOG_CRIT, "PRI down on span %d\n", ftdm_span_get_id(span));
1685                 if (isdn_data->spri.dchan) {
1686                         _ftdm_channel_set_state_force(isdn_data->spri.dchan, FTDM_CHANNEL_STATE_DOWN);
1687                 }
1688 
1689                 if (!down) {
1690                         ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
1691                         check_state(span);
1692                 }
1693 
1694                 check_state(span);
1695                 check_events(span);
1696 
1697                 down = 1;
1698                 ftdm_sleep(5000);
1699         }
1700 out:
1701         ftdm_log(FTDM_LOG_DEBUG, "PRI thread ended on span %d\n", ftdm_span_get_id(span));
1702 
1703         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
1704         ftdm_clear_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
1705 
1706         return NULL;
1707 }
1708 
1709 /**
1710  * \brief Stops a libpri span
1711  * \param span Span to halt
1712  * \return Success
1713  *
1714  * Sets a stop flag and waits for the thread to end
1715  */
1716 static ftdm_status_t ftdm_libpri_stop(ftdm_span_t *span)
1717 {
1718         ftdm_libpri_data_t *isdn_data = span->signal_data;
1719 
1720         if (!ftdm_test_flag(isdn_data, FTMOD_LIBPRI_RUNNING)) {
1721                 return FTDM_FAIL;
1722         }
1723 
1724         ftdm_set_state_all(span, FTDM_CHANNEL_STATE_RESTART);
1725 
1726         check_state(span);
1727 
1728         ftdm_set_flag(span, FTDM_SPAN_STOP_THREAD);
1729 
1730         while (ftdm_test_flag(span, FTDM_SPAN_IN_THREAD)) {
1731                 ftdm_sleep(100);
1732         }
1733 
1734         check_state(span);
1735 
1736         return FTDM_SUCCESS;
1737 }
1738 
1739 /**
1740  * \brief Starts a libpri span
1741  * \param span Span to halt
1742  * \return Success or failure
1743  *
1744  * Launches a thread to monitor the span
1745  */
1746 static ftdm_status_t ftdm_libpri_start(ftdm_span_t *span)
1747 {
1748         ftdm_libpri_data_t *isdn_data = span->signal_data;
1749 
1750         if (ftdm_test_flag(isdn_data, FTMOD_LIBPRI_RUNNING)) {
1751                 return FTDM_FAIL;
1752         }
1753 
1754         ftdm_clear_flag(span, FTDM_SPAN_STOP_THREAD);
1755         ftdm_clear_flag(span, FTDM_SPAN_IN_THREAD);
1756 
1757         ftdm_set_flag(isdn_data, FTMOD_LIBPRI_RUNNING);
1758 
1759         return ftdm_thread_create_detached(ftdm_libpri_run, span);
1760 }
1761 
1762 /**
1763  * \brief Converts a node string to node value
1764  * \param node Node string to convert
1765  * \return -1 on failure, node value on success
1766  */
1767 static int parse_mode(const char *mode)
1768 {
1769         if (!strcasecmp(mode, "cpe") || !strcasecmp(mode, "user"))
1770                 return PRI_CPE;
1771         if (!strcasecmp(mode, "network") || !strcasecmp(mode, "net"))
1772                 return PRI_NETWORK;
1773 
1774         return -1;
1775 }
1776 
1777 /**
1778  * \brief Converts a switch string to switch value
1779  * \param swtype Swtype string to convert
1780  * \return Switch value
1781  */
1782 static int parse_dialect(const char *dialect)
1783 {
1784         if (!strcasecmp(dialect, "ni1"))
1785                 return PRI_SWITCH_NI1;
1786         if (!strcasecmp(dialect, "ni2"))
1787                 return PRI_SWITCH_NI2;
1788         if (!strcasecmp(dialect, "dms100"))
1789                 return PRI_SWITCH_DMS100;
1790         if (!strcasecmp(dialect, "lucent5e") || !strcasecmp(dialect, "5ess"))
1791                 return PRI_SWITCH_LUCENT5E;
1792         if (!strcasecmp(dialect, "att4ess") || !strcasecmp(dialect, "4ess"))
1793                 return PRI_SWITCH_ATT4ESS;
1794         if (!strcasecmp(dialect, "euroisdn") || !strcasecmp(dialect, "q931"))
1795                 return PRI_SWITCH_EUROISDN_E1;
1796         if (!strcasecmp(dialect, "gr303eoc"))
1797                 return PRI_SWITCH_GR303_EOC;
1798         if (!strcasecmp(dialect, "gr303tmc"))
1799                 return PRI_SWITCH_GR303_TMC;
1800 
1801         return PRI_SWITCH_DMS100;
1802 }
1803 
1804 /**
1805  * \brief Converts a L1 string to L1 value
1806  * \param l1 L1 string to convert
1807  * \return L1 value
1808  */
1809 static int parse_layer1(const char *val)
1810 {
1811         if (!strcasecmp(val, "alaw"))
1812                 return PRI_LAYER_1_ALAW;
1813 
1814         return PRI_LAYER_1_ULAW;
1815 }
1816 
1817 /**
1818  * \brief Converts a DP string to DP value
1819  * \param dp DP string to convert
1820  * \return DP value
1821  */
1822 static int parse_ton(const char *ton)
1823 {
1824         if (!strcasecmp(ton, "international"))
1825                 return PRI_INTERNATIONAL_ISDN;
1826         if (!strcasecmp(ton, "national"))
1827                 return PRI_NATIONAL_ISDN;
1828         if (!strcasecmp(ton, "local"))
1829                 return PRI_LOCAL_ISDN;
1830         if (!strcasecmp(ton, "private"))
1831                 return PRI_PRIVATE;
1832         if (!strcasecmp(ton, "unknown"))
1833                 return PRI_UNKNOWN;
1834 
1835         return PRI_UNKNOWN;
1836 }
1837 
1838 /**
1839  * \brief Parses an option string to flags
1840  * \param in String to parse for configuration options
1841  * \return Flags
1842  */
1843 static uint32_t parse_opts(const char *in)
1844 {
1845         uint32_t flags = 0;
1846 
1847         if (!in) {
1848                 return 0;
1849         }
1850 
1851         if (strstr(in, "suggest_channel")) {
1852                 flags |= FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL;
1853         }
1854         if (strstr(in, "omit_display")) {
1855                 flags |= FTMOD_LIBPRI_OPT_OMIT_DISPLAY_IE;
1856         }
1857         if (strstr(in, "omit_redirecting_number")) {
1858                 flags |= FTMOD_LIBPRI_OPT_OMIT_REDIRECTING_NUMBER_IE;
1859         }
1860         if (strstr(in, "aoc")) {
1861                 flags |= FTMOD_LIBPRI_OPT_FACILITY_AOC;
1862         }
1863         return flags;
1864 }
1865 
1866 /**
1867  * \brief Initialises a libpri span from configuration variables
1868  * \param span Span to configure
1869  * \param sig_cb Callback function for event signals
1870  * \param ftdm_parameters List of configuration variables
1871  * \return Success or failure
1872  */
1873 static FIO_CONFIGURE_SPAN_SIGNALING_FUNCTION(ftdm_libpri_configure_span)
1874 {
1875         ftdm_libpri_data_t *isdn_data = NULL;
1876         //ftdm_channel_t *dchan = NULL;
1877         uint32_t bchan_count = 0;
1878         uint32_t dchan_count = 0;
1879         uint32_t i;
1880 
1881         if (ftdm_span_get_trunk_type(span) >= FTDM_TRUNK_NONE) {
1882                 ftdm_log(FTDM_LOG_WARNING, "Invalid trunk type '%s' defaulting to T1.\n", ftdm_span_get_trunk_type_str(span));
1883                 ftdm_span_set_trunk_type(span, FTDM_TRUNK_T1);
1884         }
1885 
1886         for (i = 1; i <= ftdm_span_get_chan_count(span); i++) {
1887                 ftdm_channel_t *chan = ftdm_span_get_channel(span, i);
1888 
1889                 switch (ftdm_channel_get_type(chan)) {
1890                 case FTDM_CHAN_TYPE_DQ921:
1891                         if (dchan_count > 1) {
1892                                 ftdm_log(FTDM_LOG_ERROR, "Span has more than 2 D-Channels!\n");
1893                                 snprintf(span->last_error, sizeof(span->last_error), "Span has more than 2 D-Channels!");
1894                                 return FTDM_FAIL;
1895                         } else {
1896 #if 0
1897                                 if (ftdm_channel_open(ftdm_span_get_id(span), i, &dchan) == FTDM_SUCCESS) {
1898                                         ftdm_log(FTDM_LOG_DEBUG, "opening D-Channel %d:%d\n", ftdm_channel_get_span_id(dchan), ftdm_channel_get_id(dchan));
1899                                         _ftdm_channel_set_state_force(dchan, FTDM_CHANNEL_STATE_UP);
1900                                 } else {
1901                                         ftdm_log(FTDM_LOG_ERROR, "Failed to open D-Channel %d:%d\n", ftdm_channel_get_span_id(chan), ftdm_channel_getid(chan));
1902                                         snprintf(span->last_error, sizeof(span->last_error), "Failed to open D-Channel %d:%d\n", ftdm_channel_get_span_id(chan), ftdm_channel_getid(chan));
1903                                         return FTDM_FAIL;
1904                                 }
1905 #endif
1906                                 dchan_count++;
1907                         }
1908                         break;
1909 
1910                 case FTDM_CHAN_TYPE_B:
1911                         bchan_count++;
1912                         break;
1913                 default:                /* Ignore other channel types */
1914                         break;
1915                 }
1916         }
1917         if (!dchan_count) {
1918                 ftdm_log(FTDM_LOG_ERROR, "Span has no D-Channel!\n");
1919                 snprintf(span->last_error, sizeof(span->last_error), "Span has no D-Channel!");
1920                 return FTDM_FAIL;
1921         }
1922         if (!bchan_count) {
1923                 ftdm_log(FTDM_LOG_ERROR, "Span has no B-Channels!\n");
1924                 snprintf(span->last_error, sizeof(span->last_error), "Span has no B-Channels!");
1925                 return FTDM_FAIL;
1926         }
1927 
1928         isdn_data = ftdm_malloc(sizeof(*isdn_data));
1929         assert(isdn_data != NULL);
1930         memset(isdn_data, 0, sizeof(*isdn_data));
1931 
1932         switch (ftdm_span_get_trunk_type(span)) {
1933         case FTDM_TRUNK_BRI:
1934         case FTDM_TRUNK_BRI_PTMP:
1935 #ifndef HAVE_LIBPRI_BRI
1936                 ftdm_log(FTDM_LOG_ERROR, "Unsupported trunk type: '%s', libpri too old\n", ftdm_span_get_trunk_type_str(span));
1937                 snprintf(span->last_error, sizeof(span->last_error), "Unsupported trunk type [%s], libpri too old", ftdm_span_get_trunk_type_str(span));
1938                 return FTDM_FAIL;
1939 #endif
1940         case FTDM_TRUNK_E1:
1941                 ftdm_log(FTDM_LOG_NOTICE, "Setting default Layer 1 to ALAW since this is an E1/BRI/BRI PTMP trunk\n");
1942                 isdn_data->layer1 = PRI_LAYER_1_ALAW;
1943                 break;
1944         case FTDM_TRUNK_T1:
1945         case FTDM_TRUNK_J1:
1946                 ftdm_log(FTDM_LOG_NOTICE, "Setting default Layer 1 to ULAW since this is a T1/J1 trunk\n");
1947                 isdn_data->layer1 = PRI_LAYER_1_ULAW;
1948                 break;
1949         default:
1950                 ftdm_log(FTDM_LOG_ERROR, "Invalid trunk type: '%s'\n", ftdm_span_get_trunk_type_str(span));
1951                 snprintf(span->last_error, sizeof(span->last_error), "Invalid trunk type [%s]", ftdm_span_get_trunk_type_str(span));
1952                 return FTDM_FAIL;
1953         }
1954 
1955         for (i = 0; ftdm_parameters[i].var; i++) {
1956                 const char *var = ftdm_parameters[i].var;
1957                 const char *val = ftdm_parameters[i].val;
1958 
1959                 if (ftdm_strlen_zero(var)) {
1960                         ftdm_log(FTDM_LOG_WARNING, "Skipping parameter with no name\n");
1961                         continue;
1962                 }
1963 
1964                 if (ftdm_strlen_zero(val)) {
1965                         ftdm_log(FTDM_LOG_ERROR, "Parameter '%s' has no value\n", var);
1966                         snprintf(span->last_error, sizeof(span->last_error), "Parameter [%s] has no value", var);
1967                         return FTDM_FAIL;
1968                 }
1969 
1970                 if (!strcasecmp(var, "node") || !strcasecmp(var, "mode")) {
1971                         if ((isdn_data->mode = parse_mode(val)) == -1) {
1972                                 ftdm_log(FTDM_LOG_ERROR, "Unknown node type '%s', defaulting to CPE mode\n", val);
1973                                 isdn_data->mode = PRI_CPE;
1974                         }
1975                 }
1976                 else if (!strcasecmp(var, "switch") || !strcasecmp(var, "dialect")) {
1977                         isdn_data->dialect = parse_dialect(val);
1978                 }
1979                 else if (!strcasecmp(var, "opts")) {
1980                         isdn_data->opts = parse_opts(val);
1981                 }
1982                 else if (!strcasecmp(var, "dp") || !strcasecmp(var, "ton")) {
1983                         isdn_data->ton = parse_ton(val);
1984                 }
1985                 else if (!strcasecmp(var, "l1") || !strcasecmp(var, "layer1")) {
1986                         isdn_data->layer1 = parse_layer1(val);
1987                 }
1988                 else if (!strcasecmp(var, "debug")) {
1989                         if (parse_debug(val, &isdn_data->debug_mask) == -1) {
1990                                 ftdm_log(FTDM_LOG_ERROR, "Invalid debug flag, ignoring parameter\n");
1991                                 isdn_data->debug_mask = 0;
1992                         }
1993                 }
1994                 else {
1995                         ftdm_log(FTDM_LOG_ERROR, "Unknown parameter '%s', aborting configuration\n", var);
1996                         snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
1997                         return FTDM_FAIL;
1998                 }
1999         }
2000 
2001         span->start = ftdm_libpri_start;
2002         span->stop  = ftdm_libpri_stop;
2003         span->signal_cb = sig_cb;
2004 
2005         span->signal_data = isdn_data;
2006         span->signal_type = FTDM_SIGTYPE_ISDN;
2007         span->outgoing_call = isdn_outgoing_call;
2008 
2009         span->state_map = &isdn_state_map;
2010         span->state_processor = state_advance;
2011 
2012         span->get_channel_sig_status = isdn_get_channel_sig_status;
2013         span->get_span_sig_status = isdn_get_span_sig_status;
2014 
2015         /* move calls to PROCEED state when they hit dialplan (ROUTING state in FreeSWITCH) */
2016         ftdm_set_flag(span, FTDM_SPAN_USE_PROCEED_STATE);
2017 
2018         if ((isdn_data->opts & FTMOD_LIBPRI_OPT_SUGGEST_CHANNEL)) {
2019                 span->channel_request = isdn_channel_request;
2020                 ftdm_set_flag(span, FTDM_SPAN_SUGGEST_CHAN_ID);
2021         }
2022 
2023         return FTDM_SUCCESS;
2024 }
2025 
2026 /**
2027  * \brief FreeTDM libpri signaling and IO module definition
2028  */
2029 ftdm_module_t ftdm_module = {
2030         "libpri",
2031         ftdm_libpri_io_init,
2032         ftdm_libpri_unload,
2033         ftdm_libpri_init,
2034         NULL,
2035         NULL,
2036         ftdm_libpri_configure_span
2037 };
2038 
2039 /* For Emacs:
2040  * Local Variables:
2041  * mode:c
2042  * indent-tabs-mode:t
2043  * tab-width:4
2044  * c-basic-offset:4
2045  * End:
2046  * For VIM:
2047  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
2048  */

/* [<][>][^][v][top][bottom][index][help] */