Advertisement
alcmagalhaes

openr2-asterisk-1.4.42-p1.patch

Jun 30th, 2011
326
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Diff 70.34 KB | None | 0 0
  1. Index: build_tools/menuselect-deps.in
  2. ===================================================================
  3. --- build_tools/menuselect-deps.in  2010-12-17 19:40:56.000000000 -0200
  4. +++ build_tools/menuselect-deps.in  2011-06-30 14:38:51.000000000 -0300
  5. @@ -26,6 +26,7 @@
  6.  PGSQL=@PBX_PGSQL@
  7.  POPT=@PBX_POPT@
  8.  PRI=@PBX_PRI@
  9. +OPENR2=@PBX_OPENR2@
  10.  RADIUS=@PBX_RADIUS@
  11.  SPEEX=@PBX_SPEEX@
  12.  SPEEXDSP=@PBX_SPEEXDSP@
  13. ===================================================================
  14. Index: channels/chan_dahdi.c
  15. ===================================================================
  16. --- asterisk-1.4.42/channels/chan_dahdi.c   2011-04-11 12:27:52.000000000 -0300
  17. +++ asterisk-1.4.42-alt/channels/chan_dahdi.c   2011-06-30 16:32:10.000000000 -0300
  18. @@ -43,6 +43,7 @@
  19.     <depend>tonezone</depend>
  20.     <depend>res_features</depend>
  21.     <use>pri</use>
  22. +   <use>openr2</use>
  23.   ***/
  24.  
  25.  #include "asterisk.h"
  26. @@ -71,6 +72,10 @@
  27.  #include <libpri.h>
  28.  #endif
  29.  
  30. +#ifdef HAVE_OPENR2
  31. +#include <openr2.h>
  32. +#endif
  33. +
  34.  #include "asterisk/lock.h"
  35.  #include "asterisk/channel.h"
  36.  #include "asterisk/config.h"
  37. @@ -170,6 +175,10 @@
  38.  #ifdef HAVE_PRI
  39.                 " w/PRI"
  40.  #endif
  41. +
  42. +#ifdef HAVE_OPENR2
  43. +          " w/OPENR2"
  44. +#endif
  45.  ;
  46.  
  47.  #define SIG_EM     DAHDI_SIG_EM
  48. @@ -188,6 +197,7 @@
  49.  #define SIG_FXOGS  DAHDI_SIG_FXOGS
  50.  #define SIG_FXOKS  DAHDI_SIG_FXOKS
  51.  #define SIG_PRI        DAHDI_SIG_CLEAR
  52. +#define SIG_MFCR2  DAHDI_SIG_CAS
  53.  #define    SIG_SF      DAHDI_SIG_SF
  54.  #define SIG_SFWINK     (0x0100000 | DAHDI_SIG_SF)
  55.  #define SIG_SF_FEATD   (0x0200000 | DAHDI_SIG_SF)
  56. @@ -316,6 +326,45 @@
  57.   */
  58.  static int ringt_base = DEFAULT_RINGT;
  59.  
  60. +#ifdef HAVE_OPENR2
  61. +
  62. +struct dahdi_mfcr2 {
  63. +   pthread_t master;              /*!< Thread of master */
  64. +   openr2_context_t *protocol_context;    /*!< OpenR2 context handle */
  65. +   struct dahdi_pvt *pvts[MAX_CHANNELS];     /*!< Member channel pvt structs */
  66. +   int numchans;                          /*!< Number of channels in this R2 block */
  67. +};
  68. +
  69. +static struct dahdi_mfcr2 r2links[NUM_SPANS];
  70. +static openr2_variant_t mfcr2_cur_variant = OR2_VAR_UNKNOWN;
  71. +static int mfcr2_cur_mfback_timeout = -1;
  72. +static int mfcr2_cur_metering_pulse_timeout = -1;
  73. +static int mfcr2_cur_max_ani = 10;
  74. +static int mfcr2_cur_max_dnis = 4;
  75. +static int mfcr2_cur_get_ani_first = -1;
  76. +static int mfcr2_cur_skip_category = -1;
  77. +static int mfcr2_cur_context_index = 0;
  78. +static int mfcr2_cur_call_files = 0;
  79. +static int mfcr2_cur_allow_collect_calls = 0;
  80. +static int mfcr2_cur_accept_on_offer = 1;
  81. +static int mfcr2_cur_charge_calls = 1;
  82. +static int mfcr2_cur_forced_release = 0;
  83. +static int mfcr2_cur_double_answer = 0;
  84. +static int mfcr2_cur_immediate_accept = -1;
  85. +/* starting with openr2 interface 3 we have DTMF support */
  86. +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
  87. +static int mfcr2_cur_dtmf_dialing = -1;
  88. +static int mfcr2_cur_dtmf_detection = -1;
  89. +static int mfcr2_cur_dtmf_time_on = OR2_DEFAULT_DTMF_ON;
  90. +static int mfcr2_cur_dtmf_time_off = OR2_DEFAULT_DTMF_OFF;
  91. +#endif
  92. +static char mfcr2_cur_logdir[OR2_MAX_PATH];
  93. +static char mfcr2_cur_r2proto_file[OR2_MAX_PATH];
  94. +static openr2_log_level_t mfcr2_cur_loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING;
  95. +static openr2_calling_party_category_t mfcr2_cur_category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
  96. +
  97. +#endif /* HAVE_OPENR2 */
  98. +
  99.  #ifdef HAVE_PRI
  100.  
  101.  #define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8) | (p->pri->mastertrunkgroup ? 0x10000 : 0))
  102. @@ -927,6 +976,24 @@
  103.     /*! \brief Logical span number within trunk group */
  104.     int logicalspan;
  105.  #endif
  106. +
  107. +#ifdef HAVE_OPENR2
  108. +   int mfcr2call;
  109. +   int mfcr2block;
  110. +   struct dahdi_mfcr2 *mfcr2;
  111. +   openr2_chan_t *r2chan;
  112. +   openr2_calling_party_category_t mfcr2_recvd_category;
  113. +   openr2_calling_party_category_t mfcr2_category;
  114. +   int mfcr2_accept_on_offer;
  115. +   int mfcr2_charge_calls;
  116. +   int mfcr2_allow_collect_calls;
  117. +   int mfcr2_forced_release;
  118. +   int mfcr2_dnis_index;
  119. +   int mfcr2_ani_index;
  120. +   int mfcr2_dnis_matched;
  121. +   int mfcr2_call_accepted;
  122. +#endif
  123. +
  124.     /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
  125.     int polarity;
  126.     /*! \brief DSP feature flags: DSP_FEATURE_xxx */
  127. @@ -1248,6 +1315,512 @@
  128.  #endif    
  129.  }
  130.  
  131. +static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int index, int law, int transfercapability);
  132. +#ifdef HAVE_OPENR2
  133. +static void init_mfcr2_globals(void)
  134. +{
  135. +   int r;
  136. +   mfcr2_cur_context_index = 0;
  137. +   mfcr2_cur_variant = OR2_VAR_UNKNOWN;
  138. +   mfcr2_cur_mfback_timeout = -1;
  139. +   mfcr2_cur_metering_pulse_timeout = -1;
  140. +   mfcr2_cur_max_ani = 10;
  141. +   mfcr2_cur_max_dnis = 4;
  142. +   mfcr2_cur_get_ani_first = -1;
  143. +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
  144. +   mfcr2_cur_dtmf_dialing = -1;
  145. +   mfcr2_cur_dtmf_detection = -1;
  146. +   mfcr2_cur_dtmf_time_on = OR2_DEFAULT_DTMF_ON;
  147. +   mfcr2_cur_dtmf_time_off = OR2_DEFAULT_DTMF_OFF;
  148. +#endif
  149. +   mfcr2_cur_skip_category = -1;
  150. +   mfcr2_cur_call_files = 0;
  151. +   mfcr2_cur_allow_collect_calls = 0;
  152. +   mfcr2_cur_forced_release = 0;
  153. +   mfcr2_cur_double_answer = 0;
  154. +   mfcr2_cur_immediate_accept = -1;
  155. +   mfcr2_cur_loglevel = OR2_LOG_ERROR | OR2_LOG_WARNING;
  156. +   mfcr2_cur_category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
  157. +   memset(mfcr2_cur_logdir, 0, sizeof(mfcr2_cur_logdir));
  158. +   memset(mfcr2_cur_r2proto_file, 0, sizeof(mfcr2_cur_r2proto_file));
  159. +   memset(r2links, 0, sizeof(r2links));
  160. +   for (r = 0; r < NUM_SPANS; r++) {
  161. +       r2links[r].master = AST_PTHREADT_NULL;
  162. +   }
  163. +}
  164. +
  165. +static int dahdi_r2_answer(struct dahdi_pvt *p)
  166. +{
  167. +   int res = 0;
  168. +   /* openr2 1.1.0 and older does not even define OR2_LIB_INTERFACE
  169. +    * and does not has support for openr2_chan_answer_call_with_mode
  170. +    *  */
  171. +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 1
  172. +   const char *double_answer = pbx_builtin_getvar_helper(p->owner, "MFCR2_DOUBLE_ANSWER");
  173. +   int wants_double_answer = ast_true(double_answer) ? 1 : 0;
  174. +   if (!double_answer) {
  175. +       /* this still can result in double answer if the channel context
  176. +        * was configured that way */
  177. +       res = openr2_chan_answer_call(p->r2chan);
  178. +   } else if (wants_double_answer) {
  179. +       res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_DOUBLE);
  180. +   } else {
  181. +       res = openr2_chan_answer_call_with_mode(p->r2chan, OR2_ANSWER_SIMPLE);
  182. +   }
  183. +#else
  184. +   res = openr2_chan_answer_call(p->r2chan);
  185. +#endif
  186. +   return res;
  187. +}
  188. +
  189. +static openr2_calling_party_category_t dahdi_r2_get_channel_category(struct ast_channel *c)
  190. +{
  191. +   openr2_calling_party_category_t cat;
  192. +   const char *catstr = pbx_builtin_getvar_helper(c, "MFCR2_CATEGORY");
  193. +   struct dahdi_pvt *p = c->tech_pvt;
  194. +   if (ast_strlen_zero(catstr)) {
  195. +       ast_log(LOG_DEBUG, "no MFC/R2 category specified for chan %s, using default %s\n",
  196. +               c->name, openr2_proto_get_category_string(p->mfcr2_category));
  197. +       return p->mfcr2_category;
  198. +   }
  199. +   if ((cat = openr2_proto_get_category(catstr)) == OR2_CALLING_PARTY_CATEGORY_UNKNOWN) {
  200. +       ast_log(LOG_WARNING, "Invalid category specified '%s' for chan %s, using default %s\n",
  201. +               catstr, c->name, openr2_proto_get_category_string(p->mfcr2_category));
  202. +       return p->mfcr2_category;
  203. +   }
  204. +   ast_log(LOG_DEBUG, "Using category %s\n", catstr);
  205. +   return cat;
  206. +}
  207. +
  208. +static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
  209. +{
  210. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  211. +   ast_mutex_lock(&p->lock);
  212. +   if (p->mfcr2call) {
  213. +       ast_mutex_unlock(&p->lock);
  214. +       /* TODO: This can happen when some other thread just finished zt_request requesting this very same
  215. +       interface but has not yet seized the line (zt_call), and the far end wins and seize the line,
  216. +       can we avoid this somehow?, at this point when zt_call send the seize, it is likely that since
  217. +       the other end will see our seize as a forced release and drop the call, we will see an invalid
  218. +       pattern that will be seen and treated as protocol error. */
  219. +       ast_log(LOG_ERROR, "Collision of calls on chan %d detected!.\n", openr2_chan_get_number(r2chan));
  220. +       return;
  221. +   }
  222. +   p->mfcr2call = 1;
  223. +   /* better safe than sorry ... */
  224. +   p->cid_name[0] = 0;
  225. +   p->cid_num[0] = 0;
  226. +   p->rdnis[0] = 0;
  227. +   p->exten[0] = 0;
  228. +   p->mfcr2_ani_index = 0;
  229. +   p->mfcr2_dnis_index = 0;
  230. +   p->mfcr2_dnis_matched = 0;
  231. +   p->mfcr2_call_accepted = 0;
  232. +   ast_mutex_unlock(&p->lock);
  233. +   ast_verbose("New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
  234. +}
  235. +
  236. +static void handle_alarms(struct dahdi_pvt *p, int alarms);
  237. +static int get_alarms(struct dahdi_pvt *p);
  238. +static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
  239. +{
  240. +   int res;
  241. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  242. +   ast_mutex_lock(&p->lock);
  243. +   p->inalarm = alarm ? 1 : 0;
  244. +   if (p->inalarm) {
  245. +       res = get_alarms(p);
  246. +       /* unknown_alarm may be set here */
  247. +       handle_alarms(p, res);
  248. +   } else {
  249. +       if (!p->unknown_alarm) {
  250. +           ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
  251. +           manager_event(EVENT_FLAG_SYSTEM, "AlarmClear", "Channel: %d\r\n", p->channel);
  252. +       } else {
  253. +           p->unknown_alarm = 0;
  254. +       }
  255. +   }
  256. +   ast_mutex_unlock(&p->lock);
  257. +   ast_log(LOG_WARNING, "Zap alarm on chan %d.\n", openr2_chan_get_number(r2chan));
  258. +}
  259. +
  260. +static void dahdi_r2_on_os_error(openr2_chan_t *r2chan, int errorcode)
  261. +{
  262. +   ast_log(LOG_ERROR, "OS error on chan %d: %s\n", openr2_chan_get_number(r2chan), strerror(errorcode));
  263. +}
  264. +
  265. +static void dahdi_r2_on_protocol_error(openr2_chan_t *r2chan, openr2_protocol_error_t reason)
  266. +{
  267. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  268. +   ast_log(LOG_ERROR, "MFC/R2 protocol error on chan %d: %s\n", openr2_chan_get_number(r2chan), openr2_proto_get_error(reason));
  269. +   if (p->owner) {
  270. +       p->owner->hangupcause = AST_CAUSE_PROTOCOL_ERROR;
  271. +       p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
  272. +   }
  273. +   ast_mutex_lock(&p->lock);
  274. +   p->mfcr2call = 0;
  275. +   ast_mutex_unlock(&p->lock);
  276. +}
  277. +
  278. +static void dahdi_r2_disconnect_call(struct dahdi_pvt *p, openr2_call_disconnect_cause_t cause)
  279. +{
  280. +   if (openr2_chan_disconnect_call(p->r2chan, cause)) {
  281. +       ast_log(LOG_NOTICE, "Bad! failed to disconnect call on channel %d with reason %s, hope for the best!\n",
  282. +               p->channel, openr2_proto_get_disconnect_string(cause));
  283. +       /* force the chan to idle and release the call flag now since we will not see a clean on_call_end */
  284. +       openr2_chan_set_idle(p->r2chan);
  285. +       ast_mutex_lock(&p->lock);
  286. +       p->mfcr2call = 0;
  287. +       ast_mutex_unlock(&p->lock);
  288. +   }
  289. +}
  290. +
  291. +static void dahdi_r2_on_call_offered(openr2_chan_t *r2chan, const char *ani, const char *dnis, openr2_calling_party_category_t category)
  292. +{
  293. +   struct dahdi_pvt *p;
  294. +   struct ast_channel *c;
  295. +   ast_verbose("MFC/R2 call offered on chan %d. ANI = %s, DNIS = %s, Category = %s\n",
  296. +           openr2_chan_get_number(r2chan), ani ? ani : "(restricted)", dnis, openr2_proto_get_category_string(category));
  297. +   p = openr2_chan_get_client_data(r2chan);
  298. +   if (!p->mfcr2_allow_collect_calls && category == OR2_CALLING_PARTY_CATEGORY_COLLECT_CALL) {
  299. +       ast_log(LOG_NOTICE, "Rejecting MFC/R2 collect call on chan %d\n", p->channel);
  300. +       dahdi_r2_disconnect_call(p, OR2_CAUSE_COLLECT_CALL_REJECTED);
  301. +       return;
  302. +   }
  303. +   ast_mutex_lock(&p->lock);
  304. +   p->mfcr2_recvd_category = category;
  305. +   /* if we're not supposed to use CID, clear whatever we have */
  306. +   if (!p->use_callerid) {
  307. +       ast_log(LOG_DEBUG, "No CID allowed in configuration, CID is being cleared!\n");
  308. +       p->cid_num[0] = 0;
  309. +   p->cid_name[0] = 0;
  310. +   }
  311. +   /* if we're supposed to answer immediately, clear DNIS and set 's' exten */
  312. +   if (p->immediate || !openr2_context_get_max_dnis(openr2_chan_get_context(r2chan))) {
  313. +       ast_log(LOG_DEBUG, "Setting exten => s because of immediate or 0 DNIS configured\n");
  314. +       p->exten[0] = 's';
  315. +       p->exten[1] = 0;
  316. +   }
  317. +   ast_mutex_unlock(&p->lock);
  318. +   if (!ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
  319. +       ast_log(LOG_NOTICE, "MFC/R2 call on channel %d requested non-existent extension '%s' in context '%s'. Rejecting call.\n",
  320. +               p->channel, p->exten, p->context);
  321. +       dahdi_r2_disconnect_call(p, OR2_CAUSE_UNALLOCATED_NUMBER);
  322. +   } else {
  323. +       /* if the user does not want to accept on offer, then we should launch the PBX thread now */
  324. +       if (!p->mfcr2_accept_on_offer) {
  325. +           c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, 0);
  326. +           if (!c) {
  327. +               ast_log(LOG_ERROR, "Unable to create PBX channel on chan %d\n", p->channel);
  328. +               dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
  329. +           }
  330. +           /* Don't disable reading since we still need to generate MF tone to accept
  331. +              the call or reject it and detect the tone off condition of the other end */
  332. +       } else if (p->mfcr2_charge_calls) {
  333. +           ast_log(LOG_DEBUG, "Accepting MFC/R2 call on offer with charge on chan %d\n", p->channel);
  334. +           openr2_chan_accept_call(r2chan, OR2_CALL_WITH_CHARGE);
  335. +       } else {
  336. +           ast_log(LOG_DEBUG, "Accepting MFC/R2 call on offer with no charge on chan %d\n", p->channel);
  337. +           openr2_chan_accept_call(r2chan, OR2_CALL_NO_CHARGE);
  338. +       }  
  339. +   }  
  340. +}
  341. +
  342. +static void dahdi_r2_on_call_end(openr2_chan_t *r2chan)
  343. +{
  344. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  345. +   ast_verbose("MFC/R2 call end on chan %d\n", p->channel);
  346. +   ast_mutex_lock(&p->lock);
  347. +   p->mfcr2call = 0;
  348. +   ast_mutex_unlock(&p->lock);
  349. +}
  350. +
  351. +static void dahdi_enable_ec(struct dahdi_pvt *p);
  352. +static void dahdi_r2_on_call_accepted(openr2_chan_t *r2chan, openr2_call_mode_t mode)
  353. +{
  354. +   struct dahdi_pvt *p = NULL;
  355. +   struct ast_channel *c = NULL;
  356. +   p = openr2_chan_get_client_data(r2chan);
  357. +   dahdi_enable_ec(p);
  358. +   p->mfcr2_call_accepted = 1;
  359. +   if (OR2_DIR_BACKWARD == openr2_chan_get_direction(r2chan)) {
  360. +       ast_verbose("MFC/R2 call has been accepted on backward channel %d\n", openr2_chan_get_number(r2chan));
  361. +       /* if accept on offer is not set, it means at this point the PBX thread is already
  362. +          launched and therefore this callback is being executed in the PBX thread rather than
  363. +          the monitor thread, don't launch any other thread, just disable the R2 reading and
  364. +          answer the call */
  365. +       if (!p->mfcr2_accept_on_offer) {
  366. +           openr2_chan_disable_read(r2chan);
  367. +           ast_verbose("Answering MFC/R2 call after accepting it on chan %d\n", openr2_chan_get_number(r2chan));
  368. +           dahdi_r2_answer(p);
  369. +           return;
  370. +       }
  371. +       c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, DAHDI_LAW_ALAW, 0);
  372. +       if (c) {
  373. +           /* chan_dahdi will take care of reading from now on, tell the library to forget about it */
  374. +           openr2_chan_disable_read(r2chan);
  375. +       } else {
  376. +           ast_log(LOG_ERROR, "Unable to create PBX channel on chan %d\n", p->channel);
  377. +           dahdi_r2_disconnect_call(p, OR2_CAUSE_OUT_OF_ORDER);
  378. +           return;
  379. +       }
  380. +   } else {
  381. +       ast_verbose("Call accepted on forward channel %d\n", p->channel);
  382. +       p->subs[SUB_REAL].needringing = 1;
  383. +       p->dialing = 0;
  384. +       /* chan_dahdi will take care of reading from now on, tell the library to forget about it */
  385. +       openr2_chan_disable_read(r2chan);
  386. +   }  
  387. +}
  388. +
  389. +static void dahdi_r2_on_call_answered(openr2_chan_t *r2chan)
  390. +{
  391. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  392. +   ast_verbose("MFC/R2 call has been answered on chan %d\n", openr2_chan_get_number(r2chan));
  393. +   p->subs[SUB_REAL].needanswer = 1;
  394. +}
  395. +
  396. +static void dahdi_r2_on_call_read(openr2_chan_t *r2chan, const unsigned char *buf, int buflen)
  397. +{
  398. +   /*ast_log(LOG_DEBUG, "Read data from dahdi channel %d\n", openr2_chan_get_number(r2chan));*/
  399. +}
  400. +
  401. +/*static int dahdi_r2_cause_to_ast_cause(openr2_call_disconnect_cause_t cause)
  402. +{
  403. +   switch (cause) {
  404. +   case OR2_CAUSE_BUSY_NUMBER:
  405. +       return AST_CAUSE_BUSY;
  406. +   case OR2_CAUSE_NETWORK_CONGESTION:
  407. +       return AST_CAUSE_CONGESTION;
  408. +   case OR2_CAUSE_OUT_OF_ORDER:
  409. +       return AST_CAUSE_DESTINATION_OUT_OF_ORDER;
  410. +   case OR2_CAUSE_UNALLOCATED_NUMBER:
  411. +       return AST_CAUSE_UNREGISTERED;
  412. +   case OR2_CAUSE_NO_ANSWER:
  413. +       return AST_CAUSE_NO_ANSWER;
  414. +   case OR2_CAUSE_NORMAL_CLEARING:
  415. +       return AST_CAUSE_NORMAL_CLEARING;
  416. +   case OR2_CAUSE_UNSPECIFIED:
  417. +   default:
  418. +       return AST_CAUSE_NOTDEFINED;
  419. +   }  
  420. +}*/
  421. +
  422. +static void dahdi_r2_on_call_disconnect(openr2_chan_t *r2chan, openr2_call_disconnect_cause_t cause)
  423. +{
  424. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  425. +   ast_verbose("MFC/R2 call disconnected on chan %d\n", openr2_chan_get_number(r2chan));
  426. +   ast_mutex_lock(&p->lock);
  427. +   if (p->owner) {
  428. +       /* when we have an owner we don't call openr2_chan_disconnect_call here, that will
  429. +          be done in zt_hangup */
  430. +       if (p->owner->_state == AST_STATE_UP) {
  431. +           p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
  432. +           ast_mutex_unlock(&p->lock);
  433. +       } else if (openr2_chan_get_direction(r2chan) == OR2_DIR_FORWARD) {
  434. +           /* being the forward side we must report what happened to the call to whoever requested it */
  435. +           switch (cause) {
  436. +           case OR2_CAUSE_BUSY_NUMBER:
  437. +               p->owner->hangupcause = AST_CAUSE_BUSY;
  438. +               p->subs[SUB_REAL].needbusy = 1;
  439. +               break;
  440. +           case OR2_CAUSE_NUMBER_CHANGED:
  441. +               p->owner->hangupcause = AST_CAUSE_NUMBER_CHANGED;
  442. +               p->subs[SUB_REAL].needcongestion = 1;
  443. +               break;
  444. +           case OR2_CAUSE_NETWORK_CONGESTION:
  445. +               p->owner->hangupcause = AST_CAUSE_NETWORK_OUT_OF_ORDER;
  446. +               p->subs[SUB_REAL].needcongestion = 1;
  447. +               break;
  448. +           case OR2_CAUSE_OUT_OF_ORDER:
  449. +               p->owner->hangupcause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
  450. +               p->subs[SUB_REAL].needcongestion = 1;
  451. +               break;
  452. +           case OR2_CAUSE_UNALLOCATED_NUMBER:
  453. +               p->owner->hangupcause = AST_CAUSE_UNALLOCATED;
  454. +               p->subs[SUB_REAL].needcongestion = 1;
  455. +               break;
  456. +           case OR2_CAUSE_NO_ANSWER:
  457. +               p->owner->hangupcause = AST_CAUSE_NO_ANSWER;
  458. +               p->subs[SUB_REAL].needcongestion = 1;
  459. +               break;
  460. +           case OR2_CAUSE_UNSPECIFIED:
  461. +               p->owner->hangupcause = AST_CAUSE_NOTDEFINED;
  462. +               p->subs[SUB_REAL].needcongestion = 1;
  463. +               break;
  464. +           case OR2_CAUSE_NORMAL_CLEARING:
  465. +               p->owner->hangupcause = AST_CAUSE_NORMAL_CLEARING;
  466. +               p->subs[SUB_REAL].needcongestion = 1;
  467. +               break;
  468. +           default:
  469. +               ast_log(LOG_WARNING, "Unhandled cause %d\n", cause);
  470. +           }
  471. +           p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
  472. +           ast_mutex_unlock(&p->lock);
  473. +       } else {
  474. +           ast_mutex_unlock(&p->lock);
  475. +           /* being the backward side and not UP yet, we only need to request hangup */
  476. +           /* TODO: what about doing this same thing when were AST_STATE_UP? */
  477. +           ast_queue_hangup(p->owner);
  478. +       }  
  479. +   } else {
  480. +       ast_mutex_unlock(&p->lock);
  481. +       /* no owner, therefore we can't use zt_hangup to disconnect, do it right now */
  482. +       dahdi_r2_disconnect_call(p, OR2_CAUSE_NORMAL_CLEARING);
  483. +   }
  484. +}
  485. +
  486. +static void dahdi_r2_write_log(openr2_log_level_t level, char *logmessage)
  487. +{
  488. +   switch (level) {
  489. +   case OR2_LOG_NOTICE:
  490. +       ast_verbose("%s", logmessage);
  491. +       break;
  492. +   case OR2_LOG_WARNING:
  493. +       ast_log(LOG_WARNING, "%s", logmessage);
  494. +       break;
  495. +   case OR2_LOG_ERROR:
  496. +       ast_log(LOG_ERROR, "%s", logmessage);
  497. +       break;
  498. +   case OR2_LOG_STACK_TRACE:
  499. +   case OR2_LOG_MF_TRACE:
  500. +   case OR2_LOG_CAS_TRACE:
  501. +   case OR2_LOG_DEBUG:
  502. +   case OR2_LOG_EX_DEBUG:
  503. +       ast_log(LOG_DEBUG, "%s", logmessage);
  504. +       break;
  505. +   default:
  506. +       ast_log(LOG_WARNING, "We should handle logging level %d here.\n", level);
  507. +       ast_log(LOG_NOTICE, "%s", logmessage);
  508. +       break;
  509. +   }
  510. +}
  511. +
  512. +#define DAHDI_R2_REMOTE_BLOCK (1 << 0)
  513. +#define DAHDI_R2_LOCAL_BLOCK (1 << 1)
  514. +static void dahdi_r2_on_line_blocked(openr2_chan_t *r2chan)
  515. +{
  516. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  517. +   ast_log(LOG_NOTICE, "Far end blocked on chan %d\n", p->channel);
  518. +   ast_mutex_lock(&p->lock);
  519. +   p->mfcr2block |= DAHDI_R2_REMOTE_BLOCK;
  520. +   ast_mutex_unlock(&p->lock);
  521. +}
  522. +
  523. +static void dahdi_r2_on_line_idle(openr2_chan_t *r2chan)
  524. +{
  525. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  526. +   ast_log(LOG_NOTICE, "Far end unblocked on chan %d\n", openr2_chan_get_number(r2chan));
  527. +   ast_mutex_lock(&p->lock);
  528. +   p->mfcr2block &= ~DAHDI_R2_REMOTE_BLOCK;
  529. +   ast_mutex_unlock(&p->lock);
  530. +}
  531. +
  532. +static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
  533. +   __attribute__((format (printf, 3, 0)));
  534. +static void dahdi_r2_on_context_log(openr2_context_t *r2context, openr2_log_level_t level, const char *fmt, va_list ap)
  535. +{
  536. +   char logmsg[256];
  537. +   char completemsg[sizeof(logmsg)+50];
  538. +   vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
  539. +   snprintf(completemsg, sizeof(completemsg), "Context - %s", logmsg);
  540. +   dahdi_r2_write_log(level, completemsg);
  541. +}
  542. +
  543. +static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
  544. +   __attribute__((format (printf, 3, 0)));
  545. +static void dahdi_r2_on_chan_log(openr2_chan_t *r2chan, openr2_log_level_t level, const char *fmt, va_list ap)
  546. +{
  547. +   char logmsg[256];
  548. +   char completemsg[sizeof(logmsg)+50];
  549. +   vsnprintf(logmsg, sizeof(logmsg), fmt, ap);
  550. +   snprintf(completemsg, sizeof(completemsg), "Chan %d - %s", openr2_chan_get_number(r2chan), logmsg);
  551. +   dahdi_r2_write_log(level, completemsg);
  552. +}
  553. +
  554. +static int dahdi_r2_on_dnis_digit_received(openr2_chan_t *r2chan, char digit)
  555. +{
  556. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  557. +   /* if 'immediate' is set, let's stop requesting DNIS */
  558. +   if (p->immediate) {
  559. +       return 0;
  560. +   }
  561. +   p->exten[p->mfcr2_dnis_index] = digit;
  562. +   p->rdnis[p->mfcr2_dnis_index] = digit;
  563. +   p->mfcr2_dnis_index++;
  564. +   p->exten[p->mfcr2_dnis_index] = 0;
  565. +   p->rdnis[p->mfcr2_dnis_index] = 0;
  566. +   /*
  567. +   ast_log(LOG_DEBUG, "Got digit %c in dahdi, dnis so far: %s\n", digit, p->exten);
  568. +   int ret;
  569. +   ret = ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num);
  570. +   ast_log(LOG_DEBUG, "ast_exists_extension(%s, %s, 1, %s) = %d\n", p->context, p->exten, p->cid_num, ret);
  571. +   ret = ast_matchmore_extension(NULL, p->context, p->exten, 1, p->cid_num);
  572. +   ast_log(LOG_DEBUG, "ast_matchmore_extension(%s, %s, 1, %s) = %d\n", p->context, p->exten, p->cid_num, ret);
  573. +   */
  574. +   /* if the DNIS is a match and cannot match more, stop requesting DNIS */
  575. +   if ((p->mfcr2_dnis_matched ||
  576. +       (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num) && (p->mfcr2_dnis_matched = 1))) &&
  577. +       !ast_matchmore_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
  578. +       return 0;
  579. +   }
  580. +   /* otherwise keep going */
  581. +   return 1;
  582. +}
  583. +
  584. +static void dahdi_r2_on_ani_digit_received(openr2_chan_t *r2chan, char digit)
  585. +{
  586. +   struct dahdi_pvt *p = openr2_chan_get_client_data(r2chan);
  587. +   p->cid_num[p->mfcr2_ani_index] = digit;
  588. +   p->cid_name[p->mfcr2_ani_index] = digit;
  589. +   p->mfcr2_ani_index++;
  590. +   p->cid_num[p->mfcr2_ani_index] = 0;
  591. +   p->cid_name[p->mfcr2_ani_index] = 0;
  592. +}
  593. +
  594. +static void dahdi_r2_on_billing_pulse_received(openr2_chan_t *r2chan)
  595. +{
  596. +   ast_log(LOG_NOTICE, "MFC/R2 billing pulse received on channel %d\n", openr2_chan_get_number(r2chan));
  597. +}
  598. +
  599. +static openr2_event_interface_t dahdi_r2_event_iface = {
  600. +   .on_call_init = dahdi_r2_on_call_init,
  601. +   .on_call_offered = dahdi_r2_on_call_offered,
  602. +   .on_call_accepted = dahdi_r2_on_call_accepted,
  603. +   .on_call_answered = dahdi_r2_on_call_answered,
  604. +   .on_call_disconnect = dahdi_r2_on_call_disconnect,
  605. +   .on_call_end = dahdi_r2_on_call_end,
  606. +   .on_call_read = dahdi_r2_on_call_read,
  607. +   .on_hardware_alarm = dahdi_r2_on_hardware_alarm,
  608. +   .on_os_error = dahdi_r2_on_os_error,
  609. +   .on_protocol_error = dahdi_r2_on_protocol_error,
  610. +   .on_line_blocked = dahdi_r2_on_line_blocked,
  611. +   .on_line_idle = dahdi_r2_on_line_idle,
  612. +   /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
  613. +   .on_context_log = (openr2_handle_context_logging_func)dahdi_r2_on_context_log,
  614. +   .on_dnis_digit_received = dahdi_r2_on_dnis_digit_received,
  615. +   .on_ani_digit_received = dahdi_r2_on_ani_digit_received,
  616. +   /* so far we do nothing with billing pulses, just log it */
  617. +   .on_billing_pulse_received = dahdi_r2_on_billing_pulse_received
  618. +};
  619. +
  620. +static inline int16_t dahdi_r2_alaw_to_linear(uint8_t sample)
  621. +{
  622. +   return AST_ALAW(sample);
  623. +}
  624. +
  625. +static inline uint8_t dahdi_r2_linear_to_alaw(int sample)
  626. +{
  627. +   return AST_LIN2A(sample);
  628. +}
  629. +
  630. +static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
  631. +   dahdi_r2_alaw_to_linear,
  632. +   dahdi_r2_linear_to_alaw
  633. +};
  634. +
  635. +#endif /* HAVE_OPENR2 */
  636. +
  637.  static int restore_gains(struct dahdi_pvt *p);
  638.  
  639.  static void swap_subs(struct dahdi_pvt *p, int a, int b)
  640. @@ -1637,6 +2210,8 @@
  641.         return "FXO Kewlstart";
  642.     case SIG_PRI:
  643.         return "ISDN PRI";
  644. +   case SIG_MFCR2:
  645. +       return "MFC/R2";
  646.     case SIG_SF:
  647.         return "SF (Tone) Immediate";
  648.     case SIG_SFWINK:
  649. @@ -2486,6 +3061,7 @@
  650.         ast_setstate(ast, AST_STATE_UP);
  651.         break;     
  652.     case SIG_PRI:
  653. +   case SIG_MFCR2:
  654.         /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
  655.         p->dialdest[0] = '\0';
  656.         p->dialing = 1;
  657. @@ -2495,6 +3071,37 @@
  658.         ast_mutex_unlock(&p->lock);
  659.         return -1;
  660.     }
  661. +
  662. +#ifdef HAVE_OPENR2
  663. +   if (p->mfcr2) {
  664. +       int strip = p->stripmsd;
  665. +       int callres = 0;
  666. +       c = strchr(dest, '/');
  667. +       if (c) {
  668. +           c++;
  669. +       } else {
  670. +           c = dest;
  671. +       }
  672. +       if (!p->hidecallerid) {
  673. +           l = ast->cid.cid_num;
  674. +       } else {
  675. +           l = NULL;
  676. +       }
  677. +       if (strlen(c) < strip) {
  678. +           ast_log(LOG_WARNING, "Destiny number '%s' is shorter than stripmsd(%d)? hum, you should fix that. Assuming stripmsd = 0\n", c, strip);
  679. +           strip = 0;
  680. +       }
  681. +       p->dialing = 1;
  682. +       callres = openr2_chan_make_call(p->r2chan, l, (c + strip), dahdi_r2_get_channel_category(ast));
  683. +       if (-1 == callres) {
  684. +           ast_mutex_unlock(&p->lock);
  685. +           ast_log(LOG_ERROR, "unable to make new MFC/R2 call!\n");
  686. +           return -1;
  687. +       }
  688. +       ast_setstate(ast, AST_STATE_DIALING);
  689. +   }
  690. +#endif /* HAVE_OPENR2 */
  691. +
  692.  #ifdef HAVE_PRI
  693.     if (p->pri) {
  694.         struct pri_sr *sr;
  695. @@ -2907,6 +3514,166 @@
  696.     return 0;
  697.  }
  698.  #endif
  699. +
  700. +#ifdef HAVE_OPENR2
  701. +static char *dahdi_accept_r2_call_app = "DAHDIAcceptR2Call";
  702. +static char *zap_accept_r2_call_app = "ZapAcceptR2Call";
  703. +
  704. +static char *dahdi_accept_r2_call_synopsis = "Accept an R2 call if its not already accepted (you still need to answer it)";
  705. +static char *zap_accept_r2_call_synopsis = "Accept an R2 call if its not already accepted (you still need to answer it)";
  706. +
  707. +static char *dahdi_accept_r2_call_descrip =
  708. +"  DAHDIAcceptR2Call(): This application will accept the current MFC/R2 call\n"
  709. +"  You can specify yes or no as argument to accept with or without charge.\n";
  710. +
  711. +static char *zap_accept_r2_call_descrip =
  712. +"  ZapAcceptR2Call(): This application will accept the current MFC/R2 call\n"
  713. +"  You can specify yes or no as argument to accept with or without charge.\n";
  714. +
  715. +static int dahdi_accept_r2_call_exec(struct ast_channel *chan, void *data)
  716. +{
  717. +   /* data is whether to accept with charge or no charge */
  718. +   openr2_call_mode_t accept_mode;
  719. +   int res, timeout, maxloops;
  720. +   struct ast_frame *f;
  721. +   struct dahdi_pvt *p;
  722. +   char *parse;
  723. +   AST_DECLARE_APP_ARGS(args,
  724. +           AST_APP_ARG(charge);
  725. +   );
  726. +
  727. +   if (ast_strlen_zero(data)) {
  728. +       ast_log(LOG_DEBUG, "No data sent to application!\n");
  729. +       return -1;
  730. +   }
  731. +
  732. +   if (chan->tech != &dahdi_tech) {
  733. +       ast_log(LOG_DEBUG, "Only DAHDI technology accepted!\n");
  734. +       return -1;
  735. +   }
  736. +
  737. +   p = (struct dahdi_pvt *)chan->tech_pvt;
  738. +   if (!p) {
  739. +       ast_log(LOG_DEBUG, "Unable to find technology private!\n");
  740. +       return -1;
  741. +   }
  742. +
  743. +   parse = ast_strdupa(data);
  744. +   AST_STANDARD_APP_ARGS(args, parse);
  745. +
  746. +   if (ast_strlen_zero(args.charge)) {
  747. +       ast_log(LOG_WARNING, "DAHDIAcceptR2Call requires 'yes' or 'no' for the charge parameter\n");
  748. +       return -1;
  749. +   }
  750. +
  751. +   ast_mutex_lock(&p->lock);
  752. +   if (!p->mfcr2 || !p->mfcr2call) {
  753. +       ast_mutex_unlock(&p->lock);
  754. +       ast_log(LOG_DEBUG, "Channel %s does not seems to be an R2 active channel!\n", chan->name);
  755. +       return -1;
  756. +   }
  757. +
  758. +   if (p->mfcr2_call_accepted) {
  759. +       ast_mutex_unlock(&p->lock);
  760. +       ast_log(LOG_DEBUG, "MFC/R2 call already accepted on channel %s!\n", chan->name);
  761. +       return 0;
  762. +   }
  763. +   accept_mode = ast_true(args.charge) ? OR2_CALL_WITH_CHARGE : OR2_CALL_NO_CHARGE;
  764. +   if (openr2_chan_accept_call(p->r2chan, accept_mode)) {
  765. +       ast_mutex_unlock(&p->lock);
  766. +       ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
  767. +       return -1;
  768. +   }
  769. +   ast_mutex_unlock(&p->lock);
  770. +
  771. +   res = 0;
  772. +   timeout = 100;
  773. +   maxloops = 50; /* wait up to 5 seconds */
  774. +   /* we need to read() until the call is accepted */
  775. +   while (maxloops > 0) {
  776. +       maxloops--;
  777. +       if (ast_check_hangup(chan)) {
  778. +           break;
  779. +       }
  780. +       res = ast_waitfor(chan, timeout);
  781. +       if (res < 0) {
  782. +           ast_log(LOG_DEBUG, "ast_waitfor failed on channel %s, going out ...\n", chan->name);
  783. +           res = -1;
  784. +           break;
  785. +       }
  786. +       if (res == 0) {
  787. +           continue;
  788. +       }
  789. +       f = ast_read(chan);
  790. +       if (!f) {
  791. +           ast_log(LOG_DEBUG, "No frame read on channel %s, going out ...\n", chan->name);
  792. +           res = -1;
  793. +           break;
  794. +       }
  795. +       if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP) {
  796. +           ast_log(LOG_DEBUG, "Got HANGUP frame on channel %s, going out ...\n", chan->name);
  797. +           ast_frfree(f);
  798. +           res = -1;
  799. +           break;
  800. +       }
  801. +       ast_frfree(f);
  802. +       ast_mutex_lock(&p->lock);
  803. +       if (p->mfcr2_call_accepted) {
  804. +           ast_mutex_unlock(&p->lock);
  805. +           ast_log(LOG_DEBUG, "Accepted MFC/R2 call!\n");
  806. +           break;
  807. +       }
  808. +       ast_mutex_unlock(&p->lock);
  809. +   }
  810. +   if (res == -1) {
  811. +       ast_log(LOG_WARNING, "Failed to accept MFC/R2 call!\n");
  812. +   }
  813. +   return res;
  814. +}
  815. +
  816. +static int zap_accept_r2_call_exec(struct ast_channel *chan, void *data)
  817. +{
  818. +   return dahdi_accept_r2_call_exec(chan, data);
  819. +}
  820. +
  821. +static openr2_call_disconnect_cause_t dahdi_ast_cause_to_r2_cause(int cause)
  822. +{
  823. +   openr2_call_disconnect_cause_t r2cause = OR2_CAUSE_NORMAL_CLEARING;
  824. +   switch (cause) {
  825. +   case AST_CAUSE_USER_BUSY:
  826. +   case AST_CAUSE_CALL_REJECTED:
  827. +   case AST_CAUSE_INTERWORKING: /* I don't know wtf is this but is used sometimes when ekiga rejects a call */
  828. +       r2cause = OR2_CAUSE_BUSY_NUMBER;
  829. +       break;
  830. +
  831. +   case AST_CAUSE_NORMAL_CIRCUIT_CONGESTION:
  832. +   case AST_CAUSE_SWITCH_CONGESTION:
  833. +       r2cause = OR2_CAUSE_NETWORK_CONGESTION;
  834. +       break;
  835. +
  836. +   case AST_CAUSE_UNALLOCATED:
  837. +       r2cause = OR2_CAUSE_UNALLOCATED_NUMBER;
  838. +       break;
  839. +
  840. +   case AST_CAUSE_NETWORK_OUT_OF_ORDER:
  841. +   case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
  842. +       r2cause = OR2_CAUSE_OUT_OF_ORDER;
  843. +       break;
  844. +
  845. +   case AST_CAUSE_NO_ANSWER:
  846. +   case AST_CAUSE_NO_USER_RESPONSE:
  847. +       r2cause = OR2_CAUSE_NO_ANSWER;
  848. +       break;
  849. +
  850. +   default:
  851. +       r2cause = OR2_CAUSE_NORMAL_CLEARING;
  852. +       break;
  853. +   }
  854. +   ast_log(LOG_DEBUG, "dahdi_ast_cause_to_r2_cause returned %d/%s for ast cause %d\n",
  855. +           r2cause, openr2_proto_get_disconnect_string(r2cause), cause);
  856. +   return r2cause;
  857. +}
  858. +#endif
  859.  
  860.  static int dahdi_hangup(struct ast_channel *ast)
  861.  {
  862. @@ -3129,6 +3896,27 @@
  863.         if (res < 0)
  864.             ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
  865.         /* Perform low level hangup if no owner left */
  866. +
  867. +#ifdef HAVE_OPENR2
  868. +       if (p->mfcr2 && p->mfcr2call && openr2_chan_get_direction(p->r2chan) != OR2_DIR_STOPPED) {
  869. +           ast_log(LOG_DEBUG, "disconnecting MFC/R2 call on chan %d\n", p->channel);
  870. +           ast_log(LOG_DEBUG, "ast->hangupcause is %d\n", ast->hangupcause);
  871. +           if (openr2_chan_get_direction(p->r2chan) == OR2_DIR_BACKWARD && p->mfcr2_forced_release) {
  872. +               dahdi_r2_disconnect_call(p, OR2_CAUSE_FORCED_RELEASE);
  873. +           } else {
  874. +               const char *r2causestr = pbx_builtin_getvar_helper(ast,"MFCR2_CAUSE");
  875. +               int r2cause_user = r2causestr ? atoi(r2causestr) : 0;
  876. +               openr2_call_disconnect_cause_t r2cause = r2cause_user
  877. +                                      ? dahdi_ast_cause_to_r2_cause(r2cause_user)
  878. +                                      : dahdi_ast_cause_to_r2_cause(ast->hangupcause);
  879. +               dahdi_r2_disconnect_call(p, r2cause);
  880. +           }
  881. +       } else if (p->mfcr2call) {
  882. +           ast_log(LOG_DEBUG, "Clearing call request on channel %d\n", p->channel);
  883. +           p->mfcr2call = 0;
  884. +       }
  885. +#endif
  886. +
  887.  #if defined(HAVE_PRI)
  888.         if (p->pri) {
  889.  #ifdef SUPPORT_USERUSER
  890. @@ -3181,7 +3969,7 @@
  891.         {
  892.             p->owner = NULL;
  893.         }
  894. -       if (p->sig && (p->sig != SIG_PRI))
  895. +       if (p->sig && (p->sig != SIG_PRI) && (p->sig != SIG_MFCR2))
  896.             res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
  897.         if (res < 0) {
  898.             ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
  899. @@ -3364,6 +4152,26 @@
  900.         }
  901.         break;
  902.  #endif
  903. +
  904. +#ifdef HAVE_OPENR2
  905. +   case SIG_MFCR2:
  906. +       if (!p->mfcr2_accept_on_offer) {
  907. +           /* the call was not accepted on offer, so it must be accepted now before answering,
  908. +              the answer will be executed when the callback on_call_accepted is executed */
  909. +           if (p->mfcr2_charge_calls) {
  910. +               ast_log(LOG_DEBUG, "Accepting MFC/R2 call before answering with charge on chan %d\n", p->channel);
  911. +               openr2_chan_accept_call(p->r2chan, OR2_CALL_WITH_CHARGE);
  912. +           } else {
  913. +               ast_log(LOG_DEBUG, "Accepting MFC/R2 call before answering with no charge on chan %d\n", p->channel);
  914. +               openr2_chan_accept_call(p->r2chan, OR2_CALL_NO_CHARGE);
  915. +           }
  916. +       } else {
  917. +           ast_log(LOG_DEBUG, "Answering MFC/R2 call on chan %d\n", p->channel);
  918. +           res = dahdi_r2_answer(p);
  919. +       }
  920. +       break;
  921. +#endif
  922. +
  923.     case 0:
  924.         ast_mutex_unlock(&p->lock);
  925.         return 0;
  926. @@ -4133,8 +4941,6 @@
  927.  
  928.  static void *ss_thread(void *data);
  929.  
  930. -static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
  931. -
  932.  /*!
  933.   * \internal
  934.   * \brief Attempt to transfer 3-way call.
  935. @@ -4482,13 +5288,29 @@
  936.             break;
  937.  #endif
  938.         case DAHDI_EVENT_BITSCHANGED:
  939. +#ifdef HAVE_OPENR2
  940. +           if (p->sig != SIG_MFCR2) {
  941. +               ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
  942. +           } else {
  943. +               ast_log(LOG_DEBUG, "bits changed in chan %d\n", p->channel);
  944. +               openr2_chan_handle_cas(p->r2chan);
  945. +           }
  946. +#else
  947.             ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
  948. +#endif
  949.         case DAHDI_EVENT_PULSE_START:
  950.             /* Stop tone if there's a pulse start and the PBX isn't started */
  951.             if (!ast->pbx)
  952.                 tone_zone_play_tone(p->subs[index].dfd, -1);
  953.             break; 
  954.         case DAHDI_EVENT_DIALCOMPLETE:
  955. +#ifdef HAVE_OPENR2
  956. +           if ((p->sig & SIG_MFCR2) && p->r2chan && ast->_state != AST_STATE_UP) {
  957. +               /* we don't need to do anything for this event for R2 signaling
  958. +                  if the call is being setup */
  959. +               break;
  960. +           }
  961. +#endif
  962.             if (p->inalarm) break;
  963.             if ((p->radio || (p->oprmode < 0))) break;
  964.             if (ioctl(p->subs[index].dfd,DAHDI_DIALING,&x) == -1) {
  965. @@ -4572,6 +5394,12 @@
  966.                 break;
  967.             }
  968.  #endif
  969. +
  970. +#ifdef HAVE_OPENR2
  971. +           if (p->sig == SIG_MFCR2)
  972. +               break;
  973. +#endif
  974. +
  975.         case DAHDI_EVENT_ONHOOK:
  976.             if (p->radio) {
  977.                 p->subs[index].f.frametype = AST_FRAME_CONTROL;
  978. @@ -5500,6 +6328,12 @@
  979.     else if (p->ringt > 0)
  980.         p->ringt--;
  981.  
  982. +#ifdef HAVE_OPENR2
  983. +   if (p->mfcr2) {
  984. +       openr2_chan_process_event(p->r2chan);
  985. +   }  
  986. +#endif
  987. +  
  988.     if (p->subs[index].needringing) {
  989.         /* Send ringing frame if requested */
  990.         p->subs[index].needringing = 0;
  991. @@ -5544,7 +6378,25 @@
  992.         ast_mutex_unlock(&p->lock);
  993.         return &p->subs[index].f;
  994.     }  
  995. -  
  996. +
  997. +#ifdef HAVE_OPENR2
  998. +   if (p->mfcr2 && openr2_chan_get_read_enabled(p->r2chan)) {
  999. +       /* openr2 took care of reading and handling any event
  1000. +         (needanswer, needbusy etc), if we continue we will read()
  1001. +         twice, lets just return a null frame. This should only
  1002. +         happen when openr2 is dialing out */
  1003. +       p->subs[index].f.frametype = AST_FRAME_NULL;
  1004. +       p->subs[index].f.subclass = 0;
  1005. +       p->subs[index].f.samples = 0;
  1006. +       p->subs[index].f.mallocd = 0;
  1007. +       p->subs[index].f.offset = 0;
  1008. +       p->subs[index].f.data = NULL;
  1009. +       p->subs[index].f.datalen= 0;
  1010. +       ast_mutex_unlock(&p->lock);
  1011. +       return &p->subs[index].f;
  1012. +   }
  1013. +#endif
  1014. +
  1015.     if (p->subs[index].needflash) {
  1016.         /* Send answer frame if requested */
  1017.         p->subs[index].needflash = 0;
  1018. @@ -5862,8 +6714,15 @@
  1019.     int func = DAHDI_FLASH;
  1020.     ast_mutex_lock(&p->lock);
  1021.     index = dahdi_get_index(chan, p, 0);
  1022. -   if (option_debug)
  1023. -       ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);
  1024. +   ast_log(LOG_DEBUG, "Requested indication %d on channel %s\n", condition, chan->name);
  1025. +#ifdef HAVE_OPENR2
  1026. +   if (p->mfcr2 && !p->mfcr2_call_accepted) {
  1027. +       ast_mutex_unlock(&p->lock);
  1028. +       /* if this an R2 call and the call is not yet accepted we don't want the
  1029. +          tone indications to mess up with the MF tones */
  1030. +       return 0;
  1031. +   }
  1032. +#endif
  1033.     if (index == SUB_REAL) {
  1034.         switch (condition) {
  1035.         case AST_CONTROL_BUSY:
  1036. @@ -6255,6 +7114,13 @@
  1037.     /* Configure the new channel jb */
  1038.     ast_jb_configure(tmp, &global_jbconf);
  1039.     if (startpbx) {
  1040. +
  1041. +#ifdef HAVE_OPENR2
  1042. +       if (i->mfcr2call) {
  1043. +           pbx_builtin_setvar_helper(tmp, "MFCR2_CATEGORY", openr2_proto_get_category_string(i->mfcr2_recvd_category));
  1044. +       }
  1045. +#endif
  1046. +
  1047.         if (ast_pbx_start(tmp)) {
  1048.             ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
  1049.             ast_hangup(tmp);
  1050. @@ -7818,7 +8684,7 @@
  1051.         count = 0;
  1052.         i = iflist;
  1053.         while (i) {
  1054. -           if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
  1055. +           if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio) && !(i->sig & SIG_MFCR2)) {
  1056.                 if (!i->owner && !i->subs[SUB_REAL].owner) {
  1057.                     /* This needs to be watched, as it lacks an owner */
  1058.                     pfds[count].fd = i->subs[SUB_REAL].dfd;
  1059. @@ -8007,6 +8873,17 @@
  1060.     return 0;
  1061.  }
  1062.  
  1063. +#ifdef HAVE_OPENR2
  1064. +static struct dahdi_mfcr2 *mfcr2_get_context(int id)
  1065. +{
  1066. +   if ((id < 0) || (id >= (sizeof(r2links)/sizeof(r2links[0])))) {
  1067. +       ast_log(LOG_ERROR, "No more R2 links available!.\n");
  1068. +       return NULL;
  1069. +   }
  1070. +   return &r2links[id];
  1071. +}
  1072. +#endif
  1073. +
  1074.  #ifdef HAVE_PRI
  1075.  static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
  1076.  {
  1077. @@ -8358,6 +9235,92 @@
  1078.                 tmp->prioffset = 0;
  1079.             }
  1080.  #endif
  1081. +
  1082. +#ifdef HAVE_OPENR2
  1083. +           if (chan_sig == SIG_MFCR2 && reloading != 1) {
  1084. +               char logdir[OR2_MAX_PATH];
  1085. +               struct dahdi_mfcr2 *dahdi_r2;
  1086. +               int threshold = 0;
  1087. +               int snres = 0;
  1088. +               dahdi_r2 = mfcr2_get_context(mfcr2_cur_context_index);
  1089. +               if (!dahdi_r2) {
  1090. +                   ast_log(LOG_WARNING, "Cannot get another R2 DAHDI context!\n");
  1091. +               } else if (!dahdi_r2->protocol_context){
  1092. +                   char tmplogdir[] = "/tmp";
  1093. +                   dahdi_r2->protocol_context = openr2_context_new(NULL, &dahdi_r2_event_iface,
  1094. +                           &dahdi_r2_transcode_iface, mfcr2_cur_variant, mfcr2_cur_max_ani, mfcr2_cur_max_dnis);
  1095. +                   if (!dahdi_r2->protocol_context) {
  1096. +                       ast_log(LOG_ERROR, "Cannot create OpenR2 protocol context.\n");
  1097. +                       destroy_dahdi_pvt(&tmp);
  1098. +                       return NULL;
  1099. +                   }
  1100. +                   openr2_context_set_log_level(dahdi_r2->protocol_context, mfcr2_cur_loglevel);
  1101. +                   openr2_context_set_ani_first(dahdi_r2->protocol_context, mfcr2_cur_get_ani_first);
  1102. +                   openr2_context_set_skip_category_request(dahdi_r2->protocol_context, mfcr2_cur_skip_category);
  1103. +                   openr2_context_set_mf_threshold(dahdi_r2->protocol_context, threshold);
  1104. +                   openr2_context_set_mf_back_timeout(dahdi_r2->protocol_context, mfcr2_cur_mfback_timeout);
  1105. +                   openr2_context_set_metering_pulse_timeout(dahdi_r2->protocol_context, mfcr2_cur_metering_pulse_timeout);
  1106. +                   openr2_context_set_double_answer(dahdi_r2->protocol_context, mfcr2_cur_double_answer);
  1107. +                   openr2_context_set_immediate_accept(dahdi_r2->protocol_context, mfcr2_cur_immediate_accept);
  1108. +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
  1109. +                   openr2_context_set_dtmf_dialing(dahdi_r2->protocol_context, mfcr2_cur_dtmf_dialing, mfcr2_cur_dtmf_time_on, mfcr2_cur_dtmf_time_off);
  1110. +                   openr2_context_set_dtmf_detection(dahdi_r2->protocol_context, mfcr2_cur_dtmf_detection);
  1111. +#endif
  1112. +                   if (ast_strlen_zero(mfcr2_cur_logdir)) {
  1113. +                       if (openr2_context_set_log_directory(dahdi_r2->protocol_context, tmplogdir)) {
  1114. +                           ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
  1115. +                       }
  1116. +                   } else {
  1117. +                       snres = snprintf(logdir, sizeof(logdir), "%s/%s/%s", ast_config_AST_LOG_DIR, "mfcr2", mfcr2_cur_logdir);
  1118. +                       if (snres >= sizeof(logdir)) {
  1119. +                           ast_log(LOG_ERROR, "MFC/R2 logging directory truncated, using %s\n", tmplogdir);
  1120. +                           if (openr2_context_set_log_directory(dahdi_r2->protocol_context, logdir)) {
  1121. +                               ast_log(LOG_ERROR, "Failed setting default MFC/R2 log directory %s\n", tmplogdir);
  1122. +                           }
  1123. +                       } else {
  1124. +                           if (openr2_context_set_log_directory(dahdi_r2->protocol_context, logdir)) {
  1125. +                               ast_log(LOG_ERROR, "Failed setting MFC/R2 log directory %s\n", logdir);
  1126. +                           }
  1127. +                       }  
  1128. +                   }
  1129. +                   if (!ast_strlen_zero(mfcr2_cur_r2proto_file)) {
  1130. +                       if (openr2_context_configure_from_advanced_file(dahdi_r2->protocol_context, mfcr2_cur_r2proto_file)) {
  1131. +                           ast_log(LOG_ERROR, "Failed to configure r2context from advanced configuration file %s\n", mfcr2_cur_r2proto_file);
  1132. +                       }
  1133. +                   }
  1134. +               }
  1135. +               if (dahdi_r2) {
  1136. +                   /* TODO: should we check numchans overflow, or is it already done by DAHDI? */
  1137. +                   dahdi_r2->pvts[dahdi_r2->numchans++] = tmp;
  1138. +                   tmp->r2chan = openr2_chan_new_from_fd(dahdi_r2->protocol_context,
  1139. +                           tmp->subs[SUB_REAL].dfd, NULL, NULL);
  1140. +                   if (!tmp->r2chan) {
  1141. +                       openr2_liberr_t err = openr2_context_get_last_error(dahdi_r2->protocol_context);
  1142. +                       ast_log(LOG_ERROR, "Cannot create OpenR2 channel: %s\n", openr2_context_error_string(err));
  1143. +                       destroy_dahdi_pvt(&tmp);
  1144. +                       return NULL;
  1145. +                   }
  1146. +                   openr2_chan_set_client_data(tmp->r2chan, tmp);
  1147. +                   /* cast seems to be needed to get rid of the annoying warning regarding format attribute */
  1148. +                   openr2_chan_set_logging_func(tmp->r2chan, (openr2_logging_func_t)dahdi_r2_on_chan_log);
  1149. +                   openr2_chan_set_log_level(tmp->r2chan, mfcr2_cur_loglevel);
  1150. +                   if (mfcr2_cur_call_files) {
  1151. +                       openr2_chan_enable_call_files(tmp->r2chan);
  1152. +                   }
  1153. +                   tmp->mfcr2_category = mfcr2_cur_category;
  1154. +                   tmp->mfcr2 = dahdi_r2;
  1155. +                   tmp->mfcr2call = 0;
  1156. +                   tmp->mfcr2block = DAHDI_R2_REMOTE_BLOCK | DAHDI_R2_LOCAL_BLOCK;
  1157. +                   tmp->mfcr2_accept_on_offer = mfcr2_cur_accept_on_offer;
  1158. +                   tmp->mfcr2_charge_calls = mfcr2_cur_charge_calls;
  1159. +                   tmp->mfcr2_ani_index = 0;
  1160. +                   tmp->mfcr2_dnis_index = 0;
  1161. +                   tmp->mfcr2_allow_collect_calls = mfcr2_cur_allow_collect_calls;
  1162. +                   tmp->mfcr2_forced_release = mfcr2_cur_forced_release;
  1163. +               }
  1164. +           }
  1165. +#endif
  1166. +
  1167.         } else {
  1168.             chan_sig = tmp->sig;
  1169.             if (tmp->subs[SUB_REAL].dfd > -1) {
  1170. @@ -8555,7 +9518,7 @@
  1171.                 ast_dsp_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
  1172.             update_conf(tmp);
  1173.             if (!here) {
  1174. -               if (chan_sig != SIG_PRI)
  1175. +               if ((chan_sig != SIG_PRI) && (chan_sig != SIG_MFCR2))
  1176.                     /* Hang it up to be sure it's good */
  1177.                     dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
  1178.             }
  1179. @@ -8769,6 +9732,17 @@
  1180.             return sig_pri_available(p);
  1181.         }
  1182.  #endif
  1183. +
  1184. +#ifdef HAVE_OPENR2
  1185. +       /* Trust MFC/R2 */
  1186. +       if (p->mfcr2) {
  1187. +           if (p->mfcr2call || p->mfcr2block)
  1188. +               return 0;
  1189. +           else
  1190. +               return 1;
  1191. +       }
  1192. +#endif
  1193. +
  1194.         if (!(p->radio || (p->oprmode < 0)))
  1195.         {
  1196.             if (!p->sig || (p->sig == SIG_FXSLS))
  1197. @@ -9076,7 +10050,26 @@
  1198.                     p->pri = pri;
  1199.                 }
  1200.             }
  1201. -#endif        
  1202. +#endif
  1203. +
  1204. +#ifdef HAVE_OPENR2
  1205. +           if (p->mfcr2) {
  1206. +               ast_mutex_lock(&p->lock);
  1207. +               if (p->mfcr2call) {
  1208. +                   ast_mutex_unlock(&p->lock);
  1209. +                   ast_log(LOG_NOTICE, "Yay!, someone just beat us in the race for channel %d.\n", p->channel);
  1210. +                   goto next;
  1211. +               }
  1212. +               if (p->mfcr2block) {
  1213. +                   ast_mutex_unlock(&p->lock);
  1214. +                   ast_log(LOG_NOTICE, "Yay!, channel %d just got blocked (%d).\n", p->channel, p->mfcr2block);
  1215. +                   goto next;
  1216. +               }
  1217. +               p->mfcr2call = 1;
  1218. +               ast_mutex_unlock(&p->lock);
  1219. +           }
  1220. +#endif
  1221. +
  1222.             if (p->channel == CHAN_PSEUDO) {
  1223.                 p = chandup(p);
  1224.                 if (!p) {
  1225. @@ -9179,6 +10172,94 @@
  1226.     return tmp;
  1227.  }
  1228.  
  1229. +#ifdef HAVE_OPENR2
  1230. +static void *mfcr2_monitor(void *data)
  1231. +{
  1232. +   struct dahdi_pvt *p;
  1233. +   struct dahdi_mfcr2 *mfcr2 = data;
  1234. +   /* we should be using pthread_key_create
  1235. +      and allocate pollers dynamically.
  1236. +      I think do_monitor() could be leaking, since it
  1237. +      could be cancelled at any time and is not
  1238. +      using thread keys, why?, */
  1239. +   struct pollfd pollers[mfcr2->numchans];
  1240. +   int maxsleep = 20;
  1241. +   int res = 0;
  1242. +   int i = 0;
  1243. +   int pollsize = 0;
  1244. +   int oldstate = 0;
  1245. +   int was_idle = 0;
  1246. +   int quit_loop = 0;
  1247. +   /* now that we're ready to get calls, unblock our side and
  1248. +      get current line state */
  1249. +   for (i = 0; i < mfcr2->numchans; i++) {
  1250. +       p = mfcr2->pvts[i];
  1251. +       pollers[i].fd = mfcr2->pvts[i]->subs[SUB_REAL].dfd;
  1252. +       if (openr2_chan_set_idle(p->r2chan)) {
  1253. +           ast_log(LOG_ERROR, "Failed to set channel %d in IDLE\n", p->channel);
  1254. +       } else {
  1255. +           ast_mutex_lock(&p->lock);
  1256. +           mfcr2->pvts[i]->mfcr2block &= ~DAHDI_R2_LOCAL_BLOCK;
  1257. +           mfcr2->pvts[i]->mfcr2call = 0;
  1258. +           ast_mutex_unlock(&p->lock);
  1259. +       }
  1260. +       openr2_chan_handle_cas(mfcr2->pvts[i]->r2chan);
  1261. +   }
  1262. +   while(1) {
  1263. +       /* we trust here that the mfcr2 channel list will not ever change once
  1264. +          the module is loaded */
  1265. +       pollsize = 0;
  1266. +       for (i = 0; i < mfcr2->numchans; i++) {
  1267. +           pollers[i].events = 0;
  1268. +           pollers[i].revents = 0;
  1269. +           if (mfcr2->pvts[i]->owner) {
  1270. +               continue;
  1271. +           }
  1272. +           if (!mfcr2->pvts[i]->r2chan) {
  1273. +               ast_log(LOG_DEBUG, "Wow, no r2chan on channel %d\n", mfcr2->pvts[i]->channel);
  1274. +               quit_loop = 1;
  1275. +               break;
  1276. +           }
  1277. +           openr2_chan_enable_read(mfcr2->pvts[i]->r2chan);
  1278. +           pollers[i].events = POLLIN | POLLPRI;
  1279. +           pollsize++;
  1280. +       }
  1281. +       if (quit_loop) {
  1282. +           break;
  1283. +       }
  1284. +
  1285. +       if (pollsize == 0) {
  1286. +           if (!was_idle) {
  1287. +               ast_log(LOG_NOTICE, "Monitor thread going idle since everybody has an owner\n");
  1288. +               was_idle = 1;
  1289. +           }
  1290. +           poll(NULL, 0, maxsleep);
  1291. +           continue;
  1292. +       }
  1293. +       was_idle = 0;
  1294. +
  1295. +       /* probably poll() is a valid cancel point, lets just be on the safe side
  1296. +          by calling pthread_testcancel */
  1297. +       pthread_testcancel();
  1298. +       res = poll(pollers, mfcr2->numchans, maxsleep);
  1299. +       pthread_testcancel();
  1300. +       if ((res < 0) && (errno != EINTR)) {
  1301. +           ast_log(LOG_ERROR, "going out, poll failed: %s\n", strerror(errno));
  1302. +           break;
  1303. +       }
  1304. +       /* do we want to allow to cancel while processing events? */
  1305. +       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &oldstate);
  1306. +       for (i = 0; i < mfcr2->numchans; i++) {
  1307. +           if ((pollers[i].revents & POLLPRI) || (pollers[i].revents & POLLIN)) {
  1308. +               openr2_chan_process_event(mfcr2->pvts[i]->r2chan);
  1309. +           }
  1310. +       }
  1311. +       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldstate);
  1312. +   }
  1313. +   ast_log(LOG_NOTICE, "Quitting MFC/R2 monitor thread\n");
  1314. +   return 0;
  1315. +}
  1316. +#endif
  1317.  
  1318.  #if defined(HAVE_PRI)
  1319.  static struct dahdi_pvt *pri_find_crv(struct dahdi_pri *pri, int crv)
  1320. @@ -11530,6 +12611,341 @@
  1321.  
  1322.  #endif /* HAVE_PRI */
  1323.  
  1324. +#ifdef HAVE_OPENR2
  1325. +
  1326. +static int handle_mfcr2_version(int fd, int argc, char *argv[])
  1327. +{
  1328. +   ast_cli(fd, "OpenR2 version: %s, revision: %s\n", openr2_get_version(), openr2_get_revision());
  1329. +   return RESULT_SUCCESS;
  1330. +}
  1331. +
  1332. +static int handle_mfcr2_show_variants(int fd, int argc, char *argv[])
  1333. +{
  1334. +#define FORMAT "%4s %40s\n"
  1335. +   int numvariants = 0;
  1336. +   int i;
  1337. +   const openr2_variant_entry_t *variants;
  1338. +   if (!(variants = openr2_proto_get_variant_list(&numvariants))) {
  1339. +       ast_cli(fd, "Failed to get list of variants.\n");
  1340. +       return RESULT_FAILURE;
  1341. +   }
  1342. +   ast_cli(fd, FORMAT, "Variant Code", "Country");
  1343. +   for (i = 0; i < numvariants; i++) {
  1344. +       ast_cli(fd, FORMAT, variants[i].name, variants[i].country);
  1345. +   }
  1346. +   return RESULT_SUCCESS;
  1347. +#undef FORMAT
  1348. +} 
  1349. +
  1350. +static int handle_mfcr2_show_channels(int fd, int argc, char *argv[])
  1351. +{
  1352. +#define FORMAT "%4s %-7.7s %-7.7s %-8.8s %-9.9s %-16.16s %-8.8s %-8.8s\n"
  1353. +   int filtertype = 0;
  1354. +   int targetnum = 0;
  1355. +   char channo[5];
  1356. +   char anino[5];
  1357. +   char dnisno[5];
  1358. +   struct dahdi_pvt *p;
  1359. +   openr2_context_t *r2context;
  1360. +   openr2_variant_t r2variant;
  1361. +   if (!((argc == 3) || (argc == 5))) {
  1362. +       return RESULT_SHOWUSAGE;
  1363. +   }
  1364. +   if (argc == 5) {
  1365. +       if (!strcasecmp(argv[3], "group")) {
  1366. +           targetnum = atoi(argv[4]);
  1367. +           if ((targetnum < 0) || (targetnum > 63))
  1368. +               return RESULT_SHOWUSAGE;
  1369. +           targetnum = 1 << targetnum;
  1370. +           filtertype = 1;
  1371. +       } else if (!strcasecmp(argv[3], "context")) {
  1372. +           filtertype = 2;
  1373. +       } else {
  1374. +           return RESULT_SHOWUSAGE;
  1375. +       }
  1376. +   }
  1377. +   ast_cli(fd, FORMAT, "Chan", "Variant", "Max ANI", "Max DNIS", "ANI First", "Immediate Accept", "Tx CAS", "Rx CAS");
  1378. +   ast_mutex_lock(&iflock);
  1379. +   p = iflist;
  1380. +   while (p) {
  1381. +       if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
  1382. +           p = p->next;
  1383. +           continue;
  1384. +       }
  1385. +       if (filtertype) {
  1386. +           switch(filtertype) {
  1387. +           case 1: /* mfcr2 show channels group <group> */
  1388. +               if (p->group != targetnum) {
  1389. +                   p = p->next;
  1390. +                   continue;
  1391. +               }
  1392. +               break;
  1393. +           case 2: /* mfcr2 show channels context <context> */
  1394. +               if (strcasecmp(p->context, argv[4])) {
  1395. +                   p= p->next;
  1396. +                   continue;
  1397. +               }
  1398. +               break;
  1399. +           default:
  1400. +               ;
  1401. +           }
  1402. +       }
  1403. +       r2context = openr2_chan_get_context(p->r2chan);
  1404. +       r2variant = openr2_context_get_variant(r2context);
  1405. +       snprintf(channo, sizeof(channo), "%d", p->channel);
  1406. +       snprintf(anino, sizeof(anino), "%d", openr2_context_get_max_ani(r2context));
  1407. +       snprintf(dnisno, sizeof(dnisno), "%d", openr2_context_get_max_dnis(r2context));
  1408. +       ast_cli(fd, FORMAT, channo, openr2_proto_get_variant_string(r2variant),
  1409. +               anino, dnisno, openr2_context_get_ani_first(r2context) ? "Yes" : "No",  
  1410. +               openr2_context_get_immediate_accept(r2context) ? "Yes" : "No",
  1411. +               openr2_chan_get_tx_cas_string(p->r2chan), openr2_chan_get_rx_cas_string(p->r2chan));
  1412. +       p = p->next;
  1413. +   }
  1414. +   ast_mutex_unlock(&iflock);
  1415. +   return RESULT_SUCCESS;
  1416. +#undef FORMAT
  1417. +}
  1418. +
  1419. +static int handle_mfcr2_set_debug(int fd, int argc, char *argv[])
  1420. +{
  1421. +   struct dahdi_pvt *p = NULL;
  1422. +   int channo = 0;
  1423. +   char *toklevel = NULL;
  1424. +   char *saveptr = NULL;
  1425. +   char *logval = NULL;
  1426. +   openr2_log_level_t loglevel = OR2_LOG_NOTHING;
  1427. +   openr2_log_level_t tmplevel = OR2_LOG_NOTHING;
  1428. +   if (argc < 4) {
  1429. +       return RESULT_SHOWUSAGE;
  1430. +   }
  1431. +   channo = (argc == 5) ? atoi(argv[4]) : -1;
  1432. +   logval = ast_strdupa(argv[3]);
  1433. +   toklevel = strtok_r(logval, ",", &saveptr);
  1434. +   if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
  1435. +       ast_cli(fd, "Invalid MFC/R2 logging level '%s'.\n", argv[3]);
  1436. +       return RESULT_FAILURE;
  1437. +   } else if (OR2_LOG_NOTHING == tmplevel) {
  1438. +       loglevel = tmplevel;
  1439. +   } else {
  1440. +       loglevel |= tmplevel;
  1441. +       while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
  1442. +           if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
  1443. +               ast_cli(fd, "Ignoring invalid logging level: '%s'.\n", toklevel);
  1444. +               continue;
  1445. +           }
  1446. +           loglevel |= tmplevel;
  1447. +       }
  1448. +   }
  1449. +   ast_mutex_lock(&iflock);
  1450. +   p = iflist;
  1451. +   while (p) {
  1452. +       if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
  1453. +           p = p->next;
  1454. +           continue;
  1455. +       }
  1456. +       if ((channo != -1) && (p->channel != channo )) {
  1457. +           p = p->next;
  1458. +           continue;
  1459. +       }
  1460. +       openr2_chan_set_log_level(p->r2chan, loglevel);
  1461. +       if (channo != -1) {
  1462. +           ast_cli(fd, "MFC/R2 debugging set to '%s' for channel %d.\n", argv[3], p->channel);
  1463. +           break;
  1464. +       } else {
  1465. +           p = p->next;
  1466. +       }
  1467. +   }
  1468. +   if ((channo != -1) && !p) {
  1469. +       ast_cli(fd, "MFC/R2 channel %d not found.\n", channo);
  1470. +   }
  1471. +   if (channo == -1) {
  1472. +       ast_cli(fd, "MFC/R2 debugging set to '%s' for all channels.\n", argv[3]);
  1473. +   }
  1474. +   ast_mutex_unlock(&iflock);
  1475. +   return RESULT_SUCCESS;
  1476. +}
  1477. +
  1478. +static int handle_mfcr2_call_files(int fd, int argc, char *argv[])
  1479. +{
  1480. +   struct dahdi_pvt *p = NULL;
  1481. +   int channo = 0;
  1482. +   if (argc < 4) {
  1483. +       return RESULT_SHOWUSAGE;
  1484. +   }
  1485. +   channo = (argc == 5) ? atoi(argv[4]) : -1;
  1486. +   ast_mutex_lock(&iflock);
  1487. +   p = iflist;
  1488. +   while (p) {
  1489. +       if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
  1490. +           p = p->next;
  1491. +           continue;
  1492. +       }
  1493. +       if ((channo != -1) && (p->channel != channo )) {
  1494. +           p = p->next;
  1495. +           continue;
  1496. +       }
  1497. +       if (ast_true(argv[3])) {
  1498. +           openr2_chan_enable_call_files(p->r2chan);
  1499. +       } else {
  1500. +           openr2_chan_disable_call_files(p->r2chan);
  1501. +       }
  1502. +       if (channo != -1) {
  1503. +           if (ast_true(argv[3])) {
  1504. +               ast_cli(fd, "MFC/R2 call files enabled for channel %d.\n", p->channel);
  1505. +           } else {
  1506. +               ast_cli(fd, "MFC/R2 call files disabled for channel %d.\n", p->channel);
  1507. +           }
  1508. +           break;
  1509. +       } else {
  1510. +           p = p->next;
  1511. +       }
  1512. +   }
  1513. +   if ((channo != -1) && !p) {
  1514. +       ast_cli(fd, "MFC/R2 channel %d not found.\n", channo);
  1515. +   }
  1516. +   if (channo == -1) {
  1517. +       if (ast_true(argv[3])) {
  1518. +           ast_cli(fd, "MFC/R2 Call files enabled for all channels.\n");
  1519. +       } else {
  1520. +           ast_cli(fd, "MFC/R2 Call files disabled for all channels.\n");
  1521. +       }  
  1522. +   }
  1523. +   ast_mutex_unlock(&iflock);
  1524. +   return RESULT_SUCCESS;
  1525. +} 
  1526. +
  1527. +static int handle_mfcr2_set_idle(int fd, int argc, char *argv[])
  1528. +{
  1529. +   struct dahdi_pvt *p = NULL;
  1530. +   int channo = 0;
  1531. +   channo = (argc == 4) ? atoi(argv[3]) : -1;
  1532. +   ast_mutex_lock(&iflock);
  1533. +   p = iflist;
  1534. +   while (p) {
  1535. +       if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
  1536. +           p = p->next;
  1537. +           continue;
  1538. +       }
  1539. +       if ((channo != -1) && (p->channel != channo )) {
  1540. +           p = p->next;
  1541. +           continue;
  1542. +       }
  1543. +       if (!openr2_chan_set_idle(p->r2chan)) {
  1544. +           ast_mutex_lock(&p->lock);
  1545. +           p->mfcr2call = 0;
  1546. +           p->mfcr2block &= ~DAHDI_R2_LOCAL_BLOCK;
  1547. +           ast_mutex_unlock(&p->lock);
  1548. +       }
  1549. +       if (channo != -1) {
  1550. +           break;
  1551. +       } else {
  1552. +           p = p->next;
  1553. +       }
  1554. +   }
  1555. +   if ((channo != -1) && !p) {
  1556. +       ast_cli(fd, "MFC/R2 channel %d not found.\n", channo);
  1557. +   }
  1558. +   ast_mutex_unlock(&iflock);
  1559. +   return RESULT_SUCCESS;
  1560. +}
  1561. +
  1562. +static int handle_mfcr2_set_blocked(int fd, int argc, char *argv[])
  1563. +{
  1564. +   struct dahdi_pvt *p = NULL;
  1565. +   int channo = 0;
  1566. +   channo = (argc == 4) ? atoi(argv[3]) : -1;
  1567. +   ast_mutex_lock(&iflock);
  1568. +   p = iflist;
  1569. +   while (p) {
  1570. +       if (!(p->sig & SIG_MFCR2) || !p->r2chan) {
  1571. +           p = p->next;
  1572. +           continue;
  1573. +       }
  1574. +       if ((channo != -1) && (p->channel != channo )) {
  1575. +           p = p->next;
  1576. +           continue;
  1577. +       }
  1578. +       if (!openr2_chan_set_blocked(p->r2chan)) {
  1579. +           ast_mutex_lock(&p->lock);
  1580. +           p->mfcr2block |= DAHDI_R2_LOCAL_BLOCK;
  1581. +           ast_mutex_unlock(&p->lock);
  1582. +       } else {
  1583. +           ast_cli(fd, "MFC/R2 channel %d could not be blocked.\n", p->channel);
  1584. +       }
  1585. +       if (channo != -1) {
  1586. +           break;
  1587. +       } else {
  1588. +           p = p->next;
  1589. +       }
  1590. +   }
  1591. +   if ((channo != -1) && !p) {
  1592. +       ast_cli(fd, "MFC/R2 channel %d not found.\n", channo);
  1593. +   }
  1594. +   ast_mutex_unlock(&iflock);
  1595. +   return RESULT_SUCCESS;
  1596. +}
  1597. +
  1598. +static const char dahdi_r2_version_help[] =
  1599. +           "Usage: mfcr2 show version\n"
  1600. +           "       Shows the version of the OpenR2 library being used.\n";
  1601. +static const char dahdi_r2_variants_help[] =
  1602. +           "Usage: mfcr2 show variants\n"
  1603. +           "       Show supported MFC/R2 variants.\n";
  1604. +static const char dahdi_r2_showchannels_help[] =
  1605. +           "Usage: mfcr2 show channels [group <group> | context <context>]\n"
  1606. +           "       Shows the zap channels configured with MFC/R2 signaling.\n";
  1607. +static const char dahdi_r2_setdebug_help[] =
  1608. +           "Usage: mfcr2 set debug <loglevel> <channel>\n"
  1609. +           "       Set a new logging level for the specified channel.\n"
  1610. +           "       If no channel is specified the logging level will be applied to all channels.\n";
  1611. +static const char dahdi_r2_callfiles_help[] =
  1612. +           "Usage: mfcr2 call files [on|off] <channel>\n"
  1613. +           "       Enable call files creation on the specified channel.\n"
  1614. +           "       If no channel is specified call files creation policy will be applied to all channels.\n";
  1615. +static const char dahdi_r2_setidle_help[] =
  1616. +           "Usage: mfcr2 set idle <channel>\n"
  1617. +           "       DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
  1618. +           "       Force the given channel into IDLE state.\n"
  1619. +           "       If no channel is specified, all channels will be set to IDLE.\n";
  1620. +static const char dahdi_r2_setblocked_help[] =
  1621. +           "Usage: mfcr2 set blocked <channel>\n"
  1622. +           "       DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.\n"
  1623. +           "       Force the given channel into BLOCKED state.\n"
  1624. +           "       If no channel is specified, all channels will be set to BLOCKED.\n";
  1625. +
  1626. +static struct ast_cli_entry dahdi_mfcr2_cli[] = {
  1627. +   { { "mfcr2", "show", "version", NULL },
  1628. +   handle_mfcr2_version, "Show OpenR2 library version",
  1629. +   dahdi_r2_version_help },
  1630. +
  1631. +   { { "mfcr2", "show", "variants", NULL },
  1632. +   handle_mfcr2_show_variants, "Show supported MFC/R2 variants",
  1633. +   dahdi_r2_variants_help },
  1634. +
  1635. +   { { "mfcr2", "show", "channels", NULL },
  1636. +   handle_mfcr2_show_channels, "Show MFC/R2 channels",
  1637. +   dahdi_r2_showchannels_help },
  1638. +
  1639. +   { { "mfcr2", "set", "debug", NULL },
  1640. +   handle_mfcr2_set_debug, "Set MFC/R2 channel logging level",
  1641. +   dahdi_r2_setdebug_help },
  1642. +
  1643. +   { { "mfcr2", "call", "files", NULL },
  1644. +   handle_mfcr2_call_files, "Enable/Disable MFC/R2 call files",
  1645. +   dahdi_r2_callfiles_help },
  1646. +
  1647. +   { { "mfcr2", "set", "idle", NULL },
  1648. +   handle_mfcr2_set_idle, "Reset MFC/R2 channel forcing it to IDLE",
  1649. +   dahdi_r2_setidle_help },
  1650. +
  1651. +   { { "mfcr2", "set", "blocked", NULL },
  1652. +   handle_mfcr2_set_blocked, "Reset MFC/R2 channel forcing it to BLOCKED",
  1653. +   dahdi_r2_setblocked_help }
  1654. +
  1655. +};
  1656. +
  1657. +#endif /* HAVE_OPENR2 */
  1658. +
  1659.  static int dahdi_destroy_channel(int fd, int argc, char **argv)
  1660.  {
  1661.     int channel;
  1662. @@ -11573,6 +12989,11 @@
  1663.  static int setup_dahdi(int reload);
  1664.  static int dahdi_restart(void)
  1665.  {
  1666. +
  1667. +#ifdef HAVE_OPENR2
  1668. +   int r;
  1669. +#endif
  1670. +  
  1671.  #if defined(HAVE_PRI)
  1672.     int i, j;
  1673.  #endif
  1674. @@ -11587,6 +13008,18 @@
  1675.     if (option_verbose > 3)
  1676.         ast_verbose("Initial softhangup of all DAHDI channels complete.\n");
  1677.  
  1678. +#ifdef HAVE_OPENR2
  1679. +   for (r = 0; r < NUM_SPANS; r++) {
  1680. +       if (r2links[r].master != AST_PTHREADT_NULL) {
  1681. +           ast_log(LOG_DEBUG, "Killing MFC/R2 monitor thread %p\n", &r2links[r].master);
  1682. +           pthread_cancel(r2links[r].master);
  1683. +           pthread_join(r2links[r].master, NULL);
  1684. +           openr2_context_delete(r2links[r].protocol_context);
  1685. +       }
  1686. +   }
  1687. +   init_mfcr2_globals();
  1688. +#endif
  1689. +  
  1690.     #if defined(HAVE_PRI)
  1691.     for (i = 0; i < NUM_SPANS; i++) {
  1692.         if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) {
  1693. @@ -11821,6 +13254,43 @@
  1694.                 if (tmp->slaves[x])
  1695.                     ast_cli(fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
  1696.             }
  1697. +
  1698. +#ifdef HAVE_OPENR2
  1699. +           if (tmp->mfcr2) {
  1700. +               char calldir[OR2_MAX_PATH];
  1701. +               openr2_context_t *r2context = openr2_chan_get_context(tmp->r2chan);
  1702. +               openr2_variant_t r2variant = openr2_context_get_variant(r2context);
  1703. +               ast_cli(fd, "MFC/R2 Call: %s\n", tmp->mfcr2call ? "Yes" : "No");
  1704. +               ast_cli(fd, "MFC/R2 Blocked: %s\n", tmp->mfcr2block ? "Yes" : "No");
  1705. +               ast_cli(fd, "MFC/R2 MF State: %s\n", openr2_chan_get_mf_state_string(tmp->r2chan));
  1706. +               ast_cli(fd, "MFC/R2 MF Group: %s\n", openr2_chan_get_mf_group_string(tmp->r2chan));
  1707. +               ast_cli(fd, "MFC/R2 State: %s\n", openr2_chan_get_r2_state_string(tmp->r2chan));
  1708. +               ast_cli(fd, "MFC/R2 Call State: %s\n", openr2_chan_get_call_state_string(tmp->r2chan));
  1709. +               ast_cli(fd, "MFC/R2 Call Files Enabled: %s\n", openr2_chan_get_call_files_enabled(tmp->r2chan) ? "Yes" : "No");
  1710. +               ast_cli(fd, "MFC/R2 Variant: %s\n", openr2_proto_get_variant_string(r2variant));
  1711. +               ast_cli(fd, "MFC/R2 Max ANI: %d\n", openr2_context_get_max_ani(r2context));
  1712. +               ast_cli(fd, "MFC/R2 Max DNIS: %d\n", openr2_context_get_max_dnis(r2context));
  1713. +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
  1714. +               ast_cli(fd, "MFC/R2 DTMF Dialing: %s\n", openr2_context_get_dtmf_dialing(r2context, NULL, NULL) ? "Yes" : "No");
  1715. +               ast_cli(fd, "MFC/R2 DTMF Detection: %s\n", openr2_context_get_dtmf_detection(r2context) ? "Yes" : "No");
  1716. +#endif
  1717. +               ast_cli(fd, "MFC/R2 Get ANI First: %s\n", openr2_context_get_ani_first(r2context) ? "Yes" : "No");
  1718. +               ast_cli(fd, "MFC/R2 Skip Category: %s\n", openr2_context_get_skip_category_request(r2context) ? "Yes" : "No");
  1719. +               ast_cli(fd, "MFC/R2 Immediate Accept: %s\n", openr2_context_get_immediate_accept(r2context) ? "Yes" : "No");
  1720. +               ast_cli(fd, "MFC/R2 Accept On Offer: %s\n", tmp->mfcr2_accept_on_offer ? "Yes" : "No");
  1721. +               ast_cli(fd, "MFC/R2 Charge Calls: %s\n", tmp->mfcr2_charge_calls ? "Yes" : "No");
  1722. +               ast_cli(fd, "MFC/R2 Allow Collect Calls: %s\n", tmp->mfcr2_allow_collect_calls ? "Yes" : "No");
  1723. +               ast_cli(fd, "MFC/R2 Forced Release: %s\n", tmp->mfcr2_forced_release ? "Yes" : "No");
  1724. +               ast_cli(fd, "MFC/R2 MF Back Timeout: %dms\n", openr2_context_get_mf_back_timeout(r2context));
  1725. +               ast_cli(fd, "MFC/R2 R2 Metering Pulse Timeout: %dms\n", openr2_context_get_metering_pulse_timeout(r2context));
  1726. +               ast_cli(fd, "MFC/R2 Rx CAS: %s\n", openr2_chan_get_rx_cas_string(tmp->r2chan));
  1727. +               ast_cli(fd, "MFC/R2 Tx CAS : %s\n", openr2_chan_get_tx_cas_string(tmp->r2chan));
  1728. +               ast_cli(fd, "MFC/R2 MF Tx Signal: %d\n", openr2_chan_get_tx_mf_signal(tmp->r2chan));
  1729. +               ast_cli(fd, "MFC/R2 MF Rx Signal: %d\n", openr2_chan_get_rx_mf_signal(tmp->r2chan));
  1730. +               ast_cli(fd, "MFC/R2 Call Files Directory: %s\n", openr2_context_get_log_directory(r2context, calldir, sizeof(calldir)));
  1731. +           }
  1732. +#endif
  1733. +
  1734.  #ifdef HAVE_PRI
  1735.             if (tmp->pri) {
  1736.                 ast_cli(fd, "PRI Flags: ");
  1737. @@ -12303,6 +13773,10 @@
  1738.  {
  1739.     struct dahdi_pvt *p;
  1740.  
  1741. +#ifdef HAVE_OPENR2
  1742. +   int r;
  1743. +#endif
  1744. +
  1745.  #ifdef HAVE_PRI
  1746.     int i, j;
  1747.     for (i = 0; i < NUM_SPANS; i++) {
  1748. @@ -12316,6 +13790,21 @@
  1749.     }
  1750.     ast_unregister_application(zap_send_keypad_facility_app);
  1751.  #endif
  1752. +
  1753. +#ifdef HAVE_OPENR2
  1754. +   for (r = 0; r < NUM_SPANS; r++) {
  1755. +       if (r2links[r].master != AST_PTHREADT_NULL) {
  1756. +           pthread_cancel(r2links[r].master);
  1757. +           pthread_join(r2links[r].master, NULL);
  1758. +       }
  1759. +   }
  1760. +   ast_cli_unregister_multiple(dahdi_mfcr2_cli, sizeof(dahdi_mfcr2_cli) / sizeof(dahdi_mfcr2_cli[0]));
  1761. +   if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
  1762. +       ast_unregister_application(dahdi_accept_r2_call_app);
  1763. +   }
  1764. +   ast_unregister_application(zap_accept_r2_call_app);
  1765. +#endif
  1766. +
  1767.     ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
  1768.     local_astman_unregister("DialOffHook");
  1769.     local_astman_unregister("Hangup");
  1770. @@ -12353,6 +13842,15 @@
  1771.         }
  1772.     }
  1773.  #endif
  1774. +
  1775. +#ifdef HAVE_OPENR2
  1776. +   for (r = 0; r < NUM_SPANS; r++) {
  1777. +       if (r2links[r].protocol_context) {
  1778. +           openr2_context_delete(r2links[r].protocol_context);
  1779. +       }
  1780. +   }
  1781. +#endif
  1782. +
  1783.     ast_cond_destroy(&ss_thread_complete);
  1784.     return 0;
  1785.  }
  1786. @@ -12452,6 +13950,13 @@
  1787.                 return -1;
  1788.             }
  1789.         }
  1790. +
  1791. +#ifdef HAVE_OPENR2
  1792. +       if (reload != 1 && r2links[mfcr2_cur_context_index].protocol_context) {
  1793. +           mfcr2_cur_context_index++;
  1794. +       }  
  1795. +#endif
  1796. +
  1797.     }
  1798.  
  1799.     return 0;
  1800. @@ -12796,6 +14301,11 @@
  1801.                 } else if (!strcasecmp(v->value, "featb")) {
  1802.                     confp->chan.sig = SIG_FEATB;
  1803.                     confp->chan.radio = 0;
  1804. +#ifdef HAVE_OPENR2
  1805. +               } else if (!strcasecmp(v->value, "mfcr2")) {
  1806. +                   confp->chan.sig = SIG_MFCR2;
  1807. +#endif
  1808. +
  1809.  #ifdef HAVE_PRI
  1810.                 } else if (!strcasecmp(v->value, "pri_net")) {
  1811.                     confp->chan.radio = 0;
  1812. @@ -13006,6 +14516,98 @@
  1813.             } else if (!strcasecmp(v->name, "facilityenable")) {
  1814.                 confp->pri.facilityenable = ast_true(v->value);
  1815.  #endif /* HAVE_PRI */
  1816. +
  1817. +#ifdef HAVE_OPENR2
  1818. +           } else if (!strcasecmp(v->name, "mfcr2_advanced_protocol_file")) {
  1819. +               ast_copy_string(mfcr2_cur_r2proto_file, v->value, sizeof(mfcr2_cur_r2proto_file));
  1820. +               ast_log(LOG_WARNING, "MFC/R2 Protocol file '%s' will be used, you only should use this if you *REALLY  KNOW WHAT YOU ARE DOING*.\n", mfcr2_cur_r2proto_file);
  1821. +           } else if (!strcasecmp(v->name, "mfcr2_logdir")) {
  1822. +               ast_copy_string(mfcr2_cur_logdir, v->value, sizeof(mfcr2_cur_logdir));
  1823. +           } else if (!strcasecmp(v->name, "mfcr2_variant")) {
  1824. +               mfcr2_cur_variant = openr2_proto_get_variant(v->value);
  1825. +               if (OR2_VAR_UNKNOWN == mfcr2_cur_variant) {
  1826. +                   ast_log(LOG_WARNING, "Unknown MFC/R2 variant '%s' at line %d.\n", v->value, v->lineno);
  1827. +               }
  1828. +           } else if (!strcasecmp(v->name, "mfcr2_mfback_timeout")) {
  1829. +               mfcr2_cur_mfback_timeout = atoi(v->value);
  1830. +               if (!mfcr2_cur_mfback_timeout) {
  1831. +                   ast_log(LOG_WARNING, "MF timeout of 0? hum, I will protect you from your ignorance. Setting default.\n");
  1832. +                   mfcr2_cur_mfback_timeout = -1;
  1833. +               } else if (mfcr2_cur_mfback_timeout > 0 && mfcr2_cur_mfback_timeout < 500) {
  1834. +                   ast_log(LOG_WARNING, "MF timeout less than 500ms is not recommended, you have been warned!\n");
  1835. +               }
  1836. +           } else if (!strcasecmp(v->name, "mfcr2_metering_pulse_timeout")) {
  1837. +               mfcr2_cur_metering_pulse_timeout = atoi(v->value);
  1838. +               if (mfcr2_cur_metering_pulse_timeout > 500) {
  1839. +                   ast_log(LOG_WARNING, "mfcr2_metering_pulse_timeout greater than 500ms is not recommended, you have been warned!\n");
  1840. +               }
  1841. +#if defined(OR2_LIB_INTERFACE) && OR2_LIB_INTERFACE > 2
  1842. +           } else if (!strcasecmp(v->name, "mfcr2_dtmf_detection")) {
  1843. +               mfcr2_cur_dtmf_detection = ast_true(v->value) ? 1 : 0;
  1844. +           } else if (!strcasecmp(v->name, "mfcr2_dtmf_dialing")) {
  1845. +               mfcr2_cur_dtmf_dialing = ast_true(v->value) ? 1 : 0;
  1846. +           } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_on")) {
  1847. +               mfcr2_cur_dtmf_time_on = atoi(v->value);
  1848. +           } else if (!strcasecmp(v->name, "mfcr2_dtmf_time_off")) {
  1849. +               mfcr2_cur_dtmf_time_off = atoi(v->value);
  1850. +#endif
  1851. +           } else if (!strcasecmp(v->name, "mfcr2_get_ani_first")) {
  1852. +               mfcr2_cur_get_ani_first = ast_true(v->value) ? 1 : 0;
  1853. +           } else if (!strcasecmp(v->name, "mfcr2_skip_category")) {
  1854. +               mfcr2_cur_skip_category = ast_true(v->value) ? 1 : 0;
  1855. +           } else if (!strcasecmp(v->name, "mfcr2_double_answer")) {
  1856. +               mfcr2_cur_double_answer = ast_true(v->value) ? 1 : 0;
  1857. +           } else if (!strcasecmp(v->name, "mfcr2_accept_on_offer")) {
  1858. +               mfcr2_cur_accept_on_offer = ast_true(v->value) ? 1 : 0;
  1859. +           } else if (!strcasecmp(v->name, "mfcr2_charge_calls")) {
  1860. +               mfcr2_cur_charge_calls = ast_true(v->value) ? 1 : 0;
  1861. +           } else if (!strcasecmp(v->name, "mfcr2_allow_collect_calls")) {
  1862. +               mfcr2_cur_allow_collect_calls = ast_true(v->value) ? 1 : 0;
  1863. +           } else if (!strcasecmp(v->name, "mfcr2_forced_release")) {
  1864. +               mfcr2_cur_forced_release= ast_true(v->value) ? 1 : 0;
  1865. +           } else if (!strcasecmp(v->name, "mfcr2_immediate_accept")) {
  1866. +               mfcr2_cur_immediate_accept = ast_true(v->value) ? 1 : 0;
  1867. +           } else if (!strcasecmp(v->name, "mfcr2_call_files")) {
  1868. +               mfcr2_cur_call_files = ast_true(v->value) ? 1 : 0;
  1869. +           } else if (!strcasecmp(v->name, "mfcr2_max_ani")) {
  1870. +               mfcr2_cur_max_ani = atoi(v->value);
  1871. +               if (mfcr2_cur_max_ani >= AST_MAX_EXTENSION) {
  1872. +                   mfcr2_cur_max_ani = AST_MAX_EXTENSION - 1;
  1873. +               }
  1874. +           } else if (!strcasecmp(v->name, "mfcr2_max_dnis")) {
  1875. +               mfcr2_cur_max_dnis = atoi(v->value);
  1876. +               if (mfcr2_cur_max_dnis >= AST_MAX_EXTENSION) {
  1877. +                   mfcr2_cur_max_dnis = AST_MAX_EXTENSION - 1;
  1878. +               }
  1879. +           } else if (!strcasecmp(v->name, "mfcr2_category")) {
  1880. +               mfcr2_cur_category = openr2_proto_get_category(v->value);
  1881. +               if (OR2_CALLING_PARTY_CATEGORY_UNKNOWN == mfcr2_cur_category) {
  1882. +                   mfcr2_cur_category = OR2_CALLING_PARTY_CATEGORY_NATIONAL_SUBSCRIBER;
  1883. +                   ast_log(LOG_WARNING, "Invalid MFC/R2 caller category '%s' at line %d. Using national subscriber as default.\n",
  1884. +                           v->value, v->lineno);
  1885. +               }
  1886. +           } else if (!strcasecmp(v->name, "mfcr2_logging")) {
  1887. +               openr2_log_level_t tmplevel;
  1888. +               char *toklevel = NULL;
  1889. +               char *saveptr = NULL;
  1890. +               char *logval = ast_strdupa(v->value);
  1891. +               toklevel = strtok_r(logval, ",", &saveptr);
  1892. +               if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
  1893. +                   ast_log(LOG_WARNING, "Invalid MFC/R2 logging level '%s' at line %d.\n", v->value, v->lineno);
  1894. +               } else if (OR2_LOG_NOTHING == tmplevel) {
  1895. +                   mfcr2_cur_loglevel = tmplevel;
  1896. +               } else {
  1897. +                   mfcr2_cur_loglevel |= tmplevel;
  1898. +                   while ((toklevel = strtok_r(NULL, ",", &saveptr))) {
  1899. +                       if (-1 == (tmplevel = openr2_log_get_level(toklevel))) {
  1900. +                           ast_log(LOG_WARNING, "Ignoring invalid logging level: '%s' at line %d.\n", toklevel, v->lineno);
  1901. +                           continue;
  1902. +                       }
  1903. +                       mfcr2_cur_loglevel |= tmplevel;
  1904. +                   }
  1905. +               }
  1906. +#endif /* HAVE_OPENR2 */
  1907. +
  1908.             } else if (!strcasecmp(v->name, "cadence")) {
  1909.                 /* setup to scan our argument */
  1910.                 int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  1911. @@ -13305,6 +14907,23 @@
  1912.         }
  1913.     }
  1914.  #endif
  1915. +
  1916. +#ifdef HAVE_OPENR2
  1917. +   if (reload != 1) {
  1918. +       int x;
  1919. +       for (x = 0; x < NUM_SPANS; x++) {
  1920. +           if (r2links[x].protocol_context) {
  1921. +               if (ast_pthread_create(&r2links[x].master, NULL, mfcr2_monitor, &r2links[x])) {
  1922. +                   ast_log(LOG_ERROR, "Unable to start R2 context on span %d\n", x + 1);
  1923. +                   return -1;
  1924. +               } else {
  1925. +                   ast_verbose(VERBOSE_PREFIX_2 "Starting R2 context on span %d\n", x + 1);
  1926. +               }
  1927. +           }
  1928. +       }
  1929. +   }
  1930. +#endif
  1931. +
  1932.     /* And start the monitor for the first time */
  1933.     restart_monitor();
  1934.     return 0;
  1935. @@ -13340,6 +14959,17 @@
  1936.     ast_register_application(zap_send_keypad_facility_app, zap_send_keypad_facility_exec,
  1937.         zap_send_keypad_facility_synopsis, zap_send_keypad_facility_descrip);
  1938.  #endif
  1939. +
  1940. +#ifdef HAVE_OPENR2
  1941. +   init_mfcr2_globals();
  1942. +   if (*dahdi_chan_mode == CHAN_DAHDI_PLUS_ZAP_MODE) {
  1943. +       ast_register_application(dahdi_accept_r2_call_app, dahdi_accept_r2_call_exec,
  1944. +           dahdi_accept_r2_call_synopsis, dahdi_accept_r2_call_descrip);
  1945. +   }
  1946. +   ast_register_application(zap_accept_r2_call_app, zap_accept_r2_call_exec,
  1947. +       zap_accept_r2_call_synopsis, zap_accept_r2_call_descrip);
  1948. +#endif
  1949. +
  1950.     if ((res = setup_dahdi(0))) {
  1951.         return AST_MODULE_LOAD_DECLINE;
  1952.     }
  1953. @@ -13358,6 +14988,11 @@
  1954.     ast_string_field_set(&inuse, name, "GR-303InUse");
  1955.     ast_cli_register_multiple(dahdi_pri_cli, sizeof(dahdi_pri_cli) / sizeof(struct ast_cli_entry));
  1956.  #endif
  1957. +
  1958. +#ifdef HAVE_OPENR2
  1959. +   ast_cli_register_multiple(dahdi_mfcr2_cli, sizeof(dahdi_mfcr2_cli)/sizeof(dahdi_mfcr2_cli[0]));
  1960. +#endif
  1961. +
  1962.     ast_cli_register_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
  1963.    
  1964.     memset(round_robin, 0, sizeof(round_robin));
  1965. ===================================================================
  1966. Index: configure.ac
  1967. ===================================================================
  1968. --- configure.ac    2011-05-02 15:25:07.000000000 -0300
  1969. +++ configure.ac    2011-06-30 16:34:15.000000000 -0300
  1970. @@ -266,6 +266,7 @@
  1971.  AST_EXT_LIB_SETUP_DEPENDENT([PRI_CALL_HOLD], [NOTIFY with call ptr], [PRI], [pri])
  1972.  AST_EXT_LIB_SETUP_DEPENDENT([PRI_VERSION], [ISDN PRI get_version], [PRI], [pri])
  1973.  AST_EXT_LIB_SETUP_DEPENDENT([PRI_INBANDDISCONNECT], [ISDN PRI set_inbanddisconnect], [PRI], [pri])
  1974. +AST_EXT_LIB_SETUP([OPENR2], [MFCR2], [openr2])
  1975.  AST_EXT_LIB_SETUP([PWLIB], [PWlib], [pwlib])
  1976.  AST_EXT_LIB_SETUP([RADIUS], [Radius Client], [radius])
  1977.  AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex])
  1978. @@ -1487,6 +1488,7 @@
  1979.  AST_EXT_LIB_CHECK([PRI_CALL_HOLD], [pri], [pri_hold_enable], [libpri.h])
  1980.  AST_EXT_LIB_CHECK([PRI_VERSION], [pri], [pri_get_version], [libpri.h])
  1981.  AST_EXT_LIB_CHECK([PRI_INBANDDISCONNECT], [pri], [pri_set_inbanddisconnect], [libpri.h])
  1982. +AST_EXT_LIB_CHECK([OPENR2], [openr2], [openr2_chan_new], [openr2.h])
  1983.  
  1984.  if test "${USE_PWLIB}" != "no"; then
  1985.     if test -n "${PWLIB_DIR}"; then
  1986. ===================================================================
  1987. Index: include/asterisk/dahdi_compat.h
  1988. ===================================================================
  1989. --- include/asterisk/dahdi_compat.h 2009-02-13 19:53:16.000000000 -0200
  1990. +++ include/asterisk/dahdi_compat.h 2011-06-30 16:35:47.000000000 -0300
  1991. @@ -320,6 +320,9 @@
  1992.  #if defined(ZT_SETTONEZONE)
  1993.  #define DAHDI_SETTONEZONE ZT_SETTONEZONE
  1994.  #endif
  1995. +#if defined(ZT_SIG_CAS)
  1996. +#define DAHDI_SIG_CAS ZT_SIG_CAS
  1997. +#endif
  1998.  #if defined(ZT_SIG_CLEAR)
  1999.  #define DAHDI_SIG_CLEAR ZT_SIG_CLEAR
  2000.  #endif
  2001. ===================================================================
  2002. Index: makeopts.in
  2003. ===================================================================
  2004. --- makeopts.in 2010-12-17 19:40:56.000000000 -0200
  2005. +++ makeopts.in 2011-06-30 16:36:39.000000000 -0300
  2006. @@ -141,6 +141,9 @@
  2007.  PRI_INCLUDE=@PRI_INCLUDE@
  2008.  PRI_LIB=@PRI_LIB@
  2009.  
  2010. +OPENR2_INCLUDE=@OPENR2_INCLUDE@
  2011. +OPENR2_LIB=@OPENR2_LIB@
  2012. +
  2013.  PWLIB_INCLUDE=@PWLIB_INCLUDE@
  2014.  PWLIB_LIB=@PWLIB_LIB@
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement