[asterisk-commits] rmudgett: branch rmudgett/misdn_facility r165957 - in /team/rmudgett/misdn_fa...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Dec 19 12:54:16 CST 2008
Author: rmudgett
Date: Fri Dec 19 12:54:16 2008
New Revision: 165957
URL: http://svn.digium.com/view/asterisk?view=rev&rev=165957
Log:
Merged from:
https://origsvn.digium.com/svn/asterisk/be/branches/C.2...
..........
r165880 | rmudgett | 2008-12-18 21:33:07 -0600 (Thu, 18 Dec 2008) | 10 lines
JIRA AST-123/ABE-1705
* Added CCBS-T/CCNR-T support.
* Added REGISTER message support for CCBS-T/CCNR-T.
* Fixed CCBS/CCNR misdn_command(cc-deactivate) invoke ID
value used.
* Restructured several functions in channel/misdn/isdn_lib.c.
* Fixed process id allocation in
channel/misdn/isdn_lib.c::create_process() that may cause an
issue similar to bug tracker 14030 but for outgoing calls.
Modified:
team/rmudgett/misdn_facility/channels/chan_misdn.c
team/rmudgett/misdn_facility/channels/misdn/isdn_lib.c
team/rmudgett/misdn_facility/channels/misdn/isdn_lib.h
team/rmudgett/misdn_facility/channels/misdn/isdn_lib_intern.h
team/rmudgett/misdn_facility/channels/misdn/isdn_msg_parser.c
Modified: team/rmudgett/misdn_facility/channels/chan_misdn.c
URL: http://svn.digium.com/view/asterisk/team/rmudgett/misdn_facility/channels/chan_misdn.c?view=diff&rev=165957&r1=165956&r2=165957
==============================================================================
--- team/rmudgett/misdn_facility/channels/chan_misdn.c (original)
+++ team/rmudgett/misdn_facility/channels/chan_misdn.c Fri Dec 19 12:54:16 2008
@@ -177,16 +177,37 @@
*/
int port;
- /*! \brief CallLinkageID (valid when port determined) */
- int linkage_id;
-
- /*! \breif CCBSReference (valid when activated) */
- int reference_id;
-
- /*! \brief TRUE if call completion activated (reference_id is valid) */
+ /*! \brief TRUE if point-to-point mode (CCBS-T/CCNR-T mode) */
+ int ptp;
+
+ /*! \brief Mode specific parameters */
+ union {
+ /*! \brief point-to-point specific parameters. */
+ struct {
+ /*!
+ * \brief Call-completion signaling link.
+ * NULL if signaling link not established.
+ */
+ struct misdn_bchannel *bc;
+ } ptp;
+
+ /*! \brief point-to-multi-point specific parameters. */
+ struct {
+ /*! \brief CallLinkageID (valid when port determined) */
+ int linkage_id;
+
+ /*! \breif CCBSReference (valid when activated is TRUE) */
+ int reference_id;
+
+ /*! \brief globalRecall(0), specificRecall(1) */
+ int recall_mode;
+ } ptmp;
+ } mode;
+
+ /*! \brief TRUE if call completion activated */
int activated;
- /*! \brief Outstanding message ID (valid while outstanding_message) */
+ /*! \brief Outstanding message ID (valid when outstanding_message) */
int invoke_id;
/*! \brief TRUE if waiting for a response from a message (invoke_id is valid) */
@@ -195,10 +216,11 @@
/*! \brief TRUE if activation has been requested */
int activation_requested;
- /*! \brief globalRecall(0), specificRecall(1) */
- int recall_mode;
-
- /*! \brief TRUE if User-A is free (Used to answer CCBSStatusRequest) */
+ /*!
+ * \brief TRUE if User-A is free
+ * \note PTMP - Used to answer CCBSStatusRequest.
+ * PTP - Determines how to respond to CCBS_T_RemoteUserFree.
+ */
int party_a_free;
/*! \brief Error code received from last outstanding message. */
@@ -206,10 +228,6 @@
/*! \brief Reject code received from last outstanding message. */
enum FacRejectCode reject_code;
-
- /* Information obtained from CCBSRemoteUserFree or CCBSBFree messages */
- //struct FacAddress Address_Of_B;
- //struct Q931_Bc_Hlc_Llc Q931ie_Of_B;
/*!
* \brief Saved struct misdn_bchannel call information when
@@ -221,6 +239,9 @@
/*! \brief User-B number information */
struct misdn_party_dialing dialed;
+
+ /*! \brief The BC, HLC (optional) and LLC (optional) contents from the SETUP message. */
+ struct Q931_Bc_Hlc_Llc setup_bc_hlc_llc;
/*! \brief SETUP message bearer capability field code value */
int capability;
@@ -856,7 +877,9 @@
struct misdn_cc_record *current;
for (current = misdn_cc_records; current; current = current->next) {
- if (current->port == port && current->linkage_id == linkage_id) {
+ if (current->port == port
+ && !current->ptp
+ && current->mode.ptmp.linkage_id == linkage_id) {
/* Found the record */
break;
}
@@ -924,7 +947,8 @@
for (current = misdn_cc_records; current; current = current->next) {
if (current->activated
&& current->port == port
- && current->reference_id == reference_id) {
+ && !current->ptp
+ && current->mode.ptmp.reference_id == reference_id) {
/* Found the record */
break;
}
@@ -932,6 +956,42 @@
return current;
} /* end misdn_cc_find_by_reference() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Find the call completion record given the B channel pointer
+ *
+ * \param bc B channel control structure pointer.
+ *
+ * \retval pointer to found call completion record
+ * \retval NULL if not found
+ *
+ * \note Assumes the misdn_cc_record_lock is already obtained.
+ */
+static struct misdn_cc_record *misdn_cc_find_by_bc(const struct misdn_bchannel *bc)
+{
+ struct misdn_cc_record *current;
+
+ if (bc) {
+ for (current = misdn_cc_records; current; current = current->next) {
+ if (current->ptp
+ && current->mode.ptp.bc == bc) {
+ /* Found the record */
+ break;
+ }
+ } /* end for */
+ } else {
+ current = NULL;
+ }
+
+ return current;
+} /* end misdn_cc_find_by_bc() */
#endif /* defined(AST_MISDN_ENHANCEMENTS) */
@@ -991,6 +1051,13 @@
prev = &misdn_cc_records;
for (current = misdn_cc_records; current;) {
if (MISDN_CC_RECORD_AGE_MAX < now - current->time_created) {
+ if (current->ptp && current->mode.ptp.bc) {
+ /* Close the old call-completion signaling link */
+ current->mode.ptp.bc->fac_out.Function = Fac_None;
+ current->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
+ misdn_lib_send_event(current->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
+ }
+
/* Remove the old call completion record */
*prev = current->next;
ast_free(current);
@@ -1292,6 +1359,150 @@
return "unknown";
} /* end misdn_to_str_error_code() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Convert the mISDN numbering plan to PartyNumber numbering plan
+ *
+ * \param number_plan mISDN numbering plan
+ *
+ * \return PartyNumber numbering plan
+ */
+static unsigned misdn_to_PartyNumber_plan(enum mISDN_NUMBER_PLAN number_plan)
+{
+ unsigned party_plan;
+
+ switch (number_plan) {
+ default:
+ case NUMPLAN_UNKNOWN:
+ party_plan = 0;/* unknown */
+ break;
+
+ case NUMPLAN_ISDN:
+ party_plan = 1;/* public */
+ break;
+
+ case NUMPLAN_DATA:
+ party_plan = 3;/* data */
+ break;
+
+ case NUMPLAN_TELEX:
+ party_plan = 4;/* telex */
+ break;
+
+ case NUMPLAN_NATIONAL:
+ party_plan = 8;/* nationalStandard */
+ break;
+
+ case NUMPLAN_PRIVATE:
+ party_plan = 5;/* private */
+ break;
+ } /* end switch */
+
+ return party_plan;
+} /* end misdn_to_PartyNumber_plan() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Convert mISDN type-of-number to PartyNumber public type-of-number
+ *
+ * \param ton mISDN type-of-number
+ *
+ * \return PartyNumber public type-of-number
+ */
+static unsigned misdn_to_PartyNumber_ton_public(enum mISDN_NUMBER_TYPE ton)
+{
+ unsigned party_ton;
+
+ switch (ton) {
+ default:
+ case NUMTYPE_UNKNOWN:
+ party_ton = 0;/* unknown */
+ break;
+
+ case NUMTYPE_INTERNATIONAL:
+ party_ton = 1;/* internationalNumber */
+ break;
+
+ case NUMTYPE_NATIONAL:
+ party_ton = 2;/* nationalNumber */
+ break;
+
+ case NUMTYPE_NETWORK_SPECIFIC:
+ party_ton = 3;/* networkSpecificNumber */
+ break;
+
+ case NUMTYPE_SUBSCRIBER:
+ party_ton = 4;/* subscriberNumber */
+ break;
+
+ case NUMTYPE_ABBREVIATED:
+ party_ton = 6;/* abbreviatedNumber */
+ break;
+ } /* end switch */
+
+ return party_ton;
+} /* end misdn_to_PartyNumber_ton_public() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Convert mISDN type-of-number to PartyNumber private type-of-number
+ *
+ * \param ton mISDN type-of-number
+ *
+ * \return PartyNumber private type-of-number
+ */
+static unsigned misdn_to_PartyNumber_ton_private(enum mISDN_NUMBER_TYPE ton)
+{
+ unsigned party_ton;
+
+ switch (ton) {
+ default:
+ case NUMTYPE_UNKNOWN:
+ party_ton = 0;/* unknown */
+ break;
+
+ case NUMTYPE_INTERNATIONAL:
+ party_ton = 1;/* level2RegionalNumber */
+ break;
+
+ case NUMTYPE_NATIONAL:
+ party_ton = 2;/* level1RegionalNumber */
+ break;
+
+ case NUMTYPE_NETWORK_SPECIFIC:
+ party_ton = 3;/* pTNSpecificNumber */
+ break;
+
+ case NUMTYPE_SUBSCRIBER:
+ party_ton = 4;/* localNumber */
+ break;
+
+ case NUMTYPE_ABBREVIATED:
+ party_ton = 6;/* abbreviatedNumber */
+ break;
+ } /* end switch */
+
+ return party_ton;
+} /* end misdn_to_PartyNumber_ton_private() */
#endif /* defined(AST_MISDN_ENHANCEMENTS) */
@@ -1911,6 +2122,63 @@
return "Unknown Bearer";
}
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Fill in facility PartyNumber information
+ *
+ * \param party PartyNumber structure to fill in.
+ * \param id Information to put in PartyNumber structure.
+ *
+ * \return Nothing
+ */
+static void misdn_PartyNumber_fill(struct FacPartyNumber *party, const struct misdn_party_id *id)
+{
+ ast_copy_string((char *) party->Number, id->number, sizeof(party->Number));
+ party->LengthOfNumber = strlen((char *) party->Number);
+ party->Type = misdn_to_PartyNumber_plan(id->number_plan);
+ switch (party->Type) {
+ case 1:/* public */
+ party->TypeOfNumber = misdn_to_PartyNumber_ton_public(id->number_type);
+ break;
+ case 5:/* private */
+ party->TypeOfNumber = misdn_to_PartyNumber_ton_private(id->number_type);
+ break;
+ default:
+ party->TypeOfNumber = 0;/* Dont't care */
+ break;
+ } /* end switch */
+} /* end misdn_PartyNumber_fill() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
+ * \brief Fill in facility Address information
+ *
+ * \param Address Address structure to fill in.
+ * \param id Information to put in Address structure.
+ *
+ * \return Nothing
+ */
+static void misdn_Address_fill(struct FacAddress *Address, const struct misdn_party_id *id)
+{
+ misdn_PartyNumber_fill(&Address->Party, id);
+
+ /* Subaddresses are not supported yet */
+ Address->Subaddress.Length = 0;
+} /* end misdn_Address_fill() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
@@ -3904,6 +4172,23 @@
ast_verbose("test <port> [<msg#>]\n\n");
}
}
+ } else if (strstr(argv[3], "register")) {
+ if (argc < 5) {
+ ast_cli(fd, "register <port>\n\n");
+ return 0;
+ }
+ port = atoi(argv[4]);
+
+ bc = misdn_lib_get_register_bc(port);
+ if (!bc) {
+ ast_cli(fd, "Could not allocate REGISTER bc struct\n\n");
+ return 0;
+ }
+ bc->fac_out = Fac_Msgs[45];
+
+ /* Send message */
+ print_facility(&bc->fac_out, bc);
+ misdn_lib_send_event(bc, EVENT_REGISTER);
#endif /* defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES) */
}
@@ -4674,9 +4959,14 @@
newbc->hdlc = cc_record->redial.hdlc;
newbc->sending_complete = 1;
- newbc->fac_out.Function = Fac_CCBSCall;
- newbc->fac_out.u.CCBSCall.InvokeID = ++misdn_invoke_id;
- newbc->fac_out.u.CCBSCall.CCBSReference = cc_record->reference_id;
+ if (cc_record->ptp) {
+ newbc->fac_out.Function = Fac_CCBS_T_Call;
+ newbc->fac_out.u.CCBS_T_Call.InvokeID = ++misdn_invoke_id;
+ } else {
+ newbc->fac_out.Function = Fac_CCBSCall;
+ newbc->fac_out.u.CCBSCall.InvokeID = ++misdn_invoke_id;
+ newbc->fac_out.u.CCBSCall.CCBSReference = cc_record->mode.ptmp.reference_id;
+ }
ast_mutex_unlock(&misdn_cc_record_lock);
ast_copy_string(ast->exten, newbc->dialed.number, sizeof(ast->exten));
@@ -6697,6 +6987,48 @@
#if defined(AST_MISDN_ENHANCEMENTS)
/*!
* \internal
+ * \brief Handle the FACILITY CCBS_T_RemoteUserFree message.
+ *
+ * \param bc B channel control structure message came in on
+ *
+ * \return Nothing
+ */
+static void misdn_cc_handle_T_remote_user_free(struct misdn_bchannel *bc)
+{
+ struct misdn_cc_record *cc_record;
+ struct misdn_cc_notify notify;
+ int record_id;
+
+ ast_mutex_lock(&misdn_cc_record_lock);
+ cc_record = misdn_cc_find_by_bc(bc);
+ if (cc_record) {
+ if (cc_record->party_a_free) {
+ notify = cc_record->remote_user_free;
+ } else {
+ /* Send CCBS_T_Suspend message */
+ bc->fac_out.Function = Fac_CCBS_T_Suspend;
+ bc->fac_out.u.CCBS_T_Suspend.InvokeID = ++misdn_invoke_id;
+ print_facility(&bc->fac_out, bc);
+ misdn_lib_send_event(bc, EVENT_FACILITY);
+
+ notify = cc_record->b_free;
+ }
+ record_id = cc_record->record_id;
+ ast_mutex_unlock(&misdn_cc_record_lock);
+ misdn_cc_pbx_notify(record_id, ¬ify);
+ } else {
+ ast_mutex_unlock(&misdn_cc_record_lock);
+ }
+} /* end misdn_cc_handle_T_remote_user_free() */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
+
+
+
+/* ******************************************************************* */
+#if defined(AST_MISDN_ENHANCEMENTS)
+/*!
+ * \internal
* \brief Handle the FACILITY CCBSRemoteUserFree message.
*
* \param port Logical port number.
@@ -6886,12 +7218,14 @@
cc_record = misdn_cc_new();
if (cc_record) {
ch->record_id = cc_record->record_id;
+ cc_record->ptp = 0;
cc_record->port = bc->port;
- cc_record->linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
+ cc_record->mode.ptmp.linkage_id = bc->fac_in.u.CallInfoRetain.CallLinkageID;
/* Record call information for possible call-completion attempt. */
cc_record->redial.caller = bc->caller;
cc_record->redial.dialed = bc->dialed;
+ cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
cc_record->redial.capability = bc->capability;
cc_record->redial.hdlc = bc->hdlc;
}
@@ -6910,6 +7244,7 @@
break;
} /* end switch */
break;
+ case Fac_CCBS_T_Call:
case Fac_CCBSCall:
switch (event) {
case EVENT_SETUP:
@@ -6981,11 +7316,11 @@
case FacComponent_Result:
ast_mutex_lock(&misdn_cc_record_lock);
cc_record = misdn_cc_find_by_invoke(bc->port, bc->fac_in.u.CCBSRequest.InvokeID);
- if (cc_record) {
+ if (cc_record && !cc_record->ptp) {
cc_record->outstanding_message = 0;
cc_record->activated = 1;
- cc_record->recall_mode = bc->fac_in.u.CCBSRequest.Component.Result.RecallMode;
- cc_record->reference_id = bc->fac_in.u.CCBSRequest.Component.Result.CCBSReference;
+ cc_record->mode.ptmp.recall_mode = bc->fac_in.u.CCBSRequest.Component.Result.RecallMode;
+ cc_record->mode.ptmp.reference_id = bc->fac_in.u.CCBSRequest.Component.Result.CCBSReference;
}
ast_mutex_unlock(&misdn_cc_record_lock);
break;
@@ -7005,6 +7340,57 @@
/* We don't handle this yet */
break;
#endif /* We don't handle this yet */
+#if 0 /* We don't handle this yet */
+ case Fac_CCBS_T_Suspend:
+ case Fac_CCBS_T_Resume:
+ /* We don't handle this yet */
+ break;
+#endif /* We don't handle this yet */
+ case Fac_CCBS_T_RemoteUserFree:
+ misdn_cc_handle_T_remote_user_free(bc);
+ break;
+ case Fac_CCBS_T_Available:
+ switch (event) {
+ case EVENT_ALERTING:
+ case EVENT_DISCONNECT:
+ /* CCBS-T/CCNR-T is available */
+ if (ch && ch->peer && ch->record_id == -1) {
+ ast_mutex_lock(&misdn_cc_record_lock);
+ cc_record = misdn_cc_new();
+ if (cc_record) {
+ ch->record_id = cc_record->record_id;
+ cc_record->ptp = 1;
+ cc_record->port = bc->port;
+
+ /* Record call information for possible call-completion attempt. */
+ cc_record->redial.caller = bc->caller;
+ cc_record->redial.dialed = bc->dialed;
+ cc_record->redial.setup_bc_hlc_llc = bc->setup_bc_hlc_llc;
+ cc_record->redial.capability = bc->capability;
+ cc_record->redial.hdlc = bc->hdlc;
+ }
+ ast_mutex_unlock(&misdn_cc_record_lock);
+ if (ch->record_id != -1) {
+ /* Set MISDN_CC_RECORD_ID in original channel */
+ snprintf(buf, sizeof(buf), "%d", cc_record->record_id);
+ pbx_builtin_setvar_helper(ch->peer, MISDN_CC_RECORD_ID, buf);
+ }
+ }
+ break;
+ default:
+ chan_misdn_log(0, bc->port,
+ " --> Expected in a DISCONNECT or ALERTING message: facility type:0x%04X\n",
+ bc->fac_in.Function);
+ break;
+ } /* end switch */
+ break;
+#if 0 /* We don't handle this yet */
+ case Fac_CCBS_T_Request:
+ case Fac_CCNR_T_Request:
+ /* We cannot be User-B in ptp mode. */
+ break;
+#endif /* We don't handle this yet */
+
#endif /* defined(AST_MISDN_ENHANCEMENTS) */
case Fac_None:
break;
@@ -7023,6 +7409,9 @@
static enum event_response_e
cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data)
{
+#if defined(AST_MISDN_ENHANCEMENTS)
+ struct misdn_cc_record *cc_record;
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
struct chan_list *ch = find_chan_by_bc(cl_te, bc);
if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) {
@@ -7054,6 +7443,7 @@
case EVENT_RETRIEVE:
case EVENT_NEW_BC:
case EVENT_FACILITY:
+ case EVENT_REGISTER:
break;
case EVENT_RELEASE_COMPLETE:
chan_misdn_log(1, bc->port, " --> no Ch, so we've already released.\n");
@@ -7525,6 +7915,23 @@
}
break;
}
+#if defined(AST_MISDN_ENHANCEMENTS)
+ case EVENT_REGISTER:
+ if (bc->fac_in.Function != Fac_None) {
+ misdn_facility_ie_handler(event, bc, ch);
+ }
+ /*
+ * Shut down this connection immediately.
+ * The current design of chan_misdn data structures
+ * does not allow the proper handling of inbound call records
+ * without an assigned B channel. Therefore, we cannot
+ * be the CCBS User-B party in a point-to-point setup.
+ */
+ bc->fac_out.Function = Fac_None;
+ bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
+ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+ break;
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
case EVENT_SETUP_ACKNOWLEDGE:
{
@@ -7623,8 +8030,6 @@
#if defined(AST_MISDN_ENHANCEMENTS)
if (ch->record_id != -1) {
- struct misdn_cc_record *cc_record;
-
/*
* We will delete the associated call completion
* record since we now have a completed call.
@@ -7634,6 +8039,12 @@
ast_mutex_lock(&misdn_cc_record_lock);
cc_record = misdn_cc_find_by_id(ch->record_id);
if (cc_record) {
+ if (cc_record->ptp && cc_record->mode.ptp.bc) {
+ /* Close the call-completion signaling link */
+ cc_record->mode.ptp.bc->fac_out.Function = Fac_None;
+ cc_record->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
+ misdn_lib_send_event(cc_record->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
+ }
misdn_cc_delete(cc_record);
}
ast_mutex_unlock(&misdn_cc_record_lock);
@@ -7754,6 +8165,21 @@
stop_bc_tones(ch);
hangup_chan(ch);
ch->state = MISDN_CLEANING;
+#if defined(AST_MISDN_ENHANCEMENTS)
+ } else {
+ /*
+ * A call-completion signaling link established with
+ * REGISTER does not have a struct chan_list record
+ * associated with it.
+ */
+ ast_mutex_lock(&misdn_cc_record_lock);
+ cc_record = misdn_cc_find_by_bc(bc);
+ if (cc_record) {
+ /* The call-completion signaling link is closed. */
+ misdn_cc_delete(cc_record);
+ }
+ ast_mutex_unlock(&misdn_cc_record_lock);
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
}
release_chan(bc);
@@ -8325,6 +8751,7 @@
int record_id;
const char *error_str;
struct misdn_cc_record *cc_record;
+ struct misdn_bchannel *bc;
struct misdn_bchannel dummy;
static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID})\n";
@@ -8341,21 +8768,31 @@
cc_record = misdn_cc_find_by_id(record_id);
if (cc_record) {
if (0 <= cc_record->port && cc_record->activated) {
- cc_record->error_code = FacError_None;
- cc_record->reject_code = FacReject_None;
- cc_record->invoke_id = ++misdn_invoke_id;
- cc_record->outstanding_message = 1;
-
- /* Build message */
- misdn_make_dummy(&dummy, cc_record->port, 0, misdn_lib_port_is_nt(cc_record->port), 0);
- dummy.fac_out.Function = Fac_CCBSDeactivate;
- dummy.fac_out.u.CCBSDeactivate.InvokeID = ++misdn_invoke_id;
- dummy.fac_out.u.CCBSDeactivate.ComponentType = FacComponent_Invoke;
- dummy.fac_out.u.CCBSDeactivate.Component.Invoke.CCBSReference = cc_record->reference_id;
-
- /* Send message */
- print_facility(&dummy.fac_out, &dummy);
- misdn_lib_send_event(&dummy, EVENT_FACILITY);
+ if (cc_record->ptp) {
+ /* Send message */
+ bc = cc_record->mode.ptp.bc;/* bc != NULL here because activated is TRUE */
+ bc->fac_out.Function = Fac_None;
+ bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
+ misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
+
+ misdn_cc_delete(cc_record);
+ } else {
+ cc_record->error_code = FacError_None;
+ cc_record->reject_code = FacReject_None;
+ cc_record->invoke_id = ++misdn_invoke_id;
+ cc_record->outstanding_message = 1;
+
+ /* Build message */
+ misdn_make_dummy(&dummy, cc_record->port, 0, misdn_lib_port_is_nt(cc_record->port), 0);
+ dummy.fac_out.Function = Fac_CCBSDeactivate;
+ dummy.fac_out.u.CCBSDeactivate.InvokeID = cc_record->invoke_id;
+ dummy.fac_out.u.CCBSDeactivate.ComponentType = FacComponent_Invoke;
+ dummy.fac_out.u.CCBSDeactivate.Component.Invoke.CCBSReference = cc_record->mode.ptmp.reference_id;
+
+ /* Send message */
+ print_facility(&dummy.fac_out, &dummy);
+ misdn_lib_send_event(&dummy, EVENT_FACILITY);
+ }
}
}
ast_mutex_unlock(&misdn_cc_record_lock);
@@ -8421,6 +8858,7 @@
int record_id;
int party_a_free;
struct misdn_cc_record *cc_record;
+ struct misdn_bchannel *bc;
static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<yes/no>)\n";
@@ -8445,8 +8883,29 @@
ast_mutex_lock(&misdn_cc_record_lock);
cc_record = misdn_cc_find_by_id(record_id);
- if (cc_record) {
+ if (cc_record && cc_record->party_a_free != party_a_free) {
+ /* User-A's status has changed */
cc_record->party_a_free = party_a_free;
+
+ if (cc_record->ptp && cc_record->mode.ptp.bc) {
+ cc_record->error_code = FacError_None;
+ cc_record->reject_code = FacReject_None;
+ cc_record->invoke_id = ++misdn_invoke_id;
+
+ /* Build message */
+ bc = cc_record->mode.ptp.bc;
+ if (cc_record->party_a_free) {
+ bc->fac_out.Function = Fac_CCBS_T_Resume;
+ bc->fac_out.u.CCBS_T_Resume.InvokeID = cc_record->invoke_id;
+ } else {
+ bc->fac_out.Function = Fac_CCBS_T_Suspend;
+ bc->fac_out.u.CCBS_T_Suspend.InvokeID = cc_record->invoke_id;
+ }
+
+ /* Send message */
+ print_facility(&bc->fac_out, bc);
+ misdn_lib_send_event(bc, EVENT_FACILITY);
+ }
}
ast_mutex_unlock(&misdn_cc_record_lock);
@@ -8532,6 +8991,13 @@
+#if defined(AST_MISDN_ENHANCEMENTS)
+struct misdn_cc_request {
+ enum FacFunction ptmp;
+ enum FacFunction ptp;
+};
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+
/* ******************************************************************* */
#if defined(AST_MISDN_ENHANCEMENTS)
/*!
@@ -8546,12 +9012,12 @@
* \param chan Asterisk channel to operate upon.
* \param cmd_name subcommand name to use in error messages
* \param options subcommand options string
- * \param request which facility message to generate
+ * \param request Which call-completion request message to generate.
*
* \retval 0 on success.
* \retval -1 on error.
*/
-static int misdn_command_cc_request(struct ast_channel *chan, const char *cmd_name, char *options, enum FacFunction request)
+static int misdn_command_cc_request(struct ast_channel *chan, const char *cmd_name, char *options, const struct misdn_cc_request *request)
{
char *opt;
char *tail;
@@ -8561,7 +9027,9 @@
char *exten;
const char *error_str;
struct misdn_cc_record *cc_record;
+ struct misdn_bchannel *bc;
struct misdn_bchannel dummy;
+ struct misdn_party_id id;
static const char cmd_help[] = "%s(%s,${MISDN_CC_RECORD_ID},<notify-context>,<user-a-extension>,<priority>)\n";
@@ -8598,27 +9066,68 @@
cc_record = misdn_cc_find_by_id(record_id);
if (cc_record) {
/* Save User-B free information */
- ast_copy_string(cc_record->remote_user_free.context, context, sizeof(cc_record->remote_user_free.context));
- ast_copy_string(cc_record->remote_user_free.exten, exten, sizeof(cc_record->remote_user_free.exten));
+ ast_copy_string(cc_record->remote_user_free.context, context,
+ sizeof(cc_record->remote_user_free.context));
+ ast_copy_string(cc_record->remote_user_free.exten, exten,
+ sizeof(cc_record->remote_user_free.exten));
cc_record->remote_user_free.priority = priority;
if (0 <= cc_record->port) {
cc_record->error_code = FacError_None;
cc_record->reject_code = FacReject_None;
cc_record->invoke_id = ++misdn_invoke_id;
- cc_record->outstanding_message = 1;
cc_record->activation_requested = 1;
- /* Build message */
- misdn_make_dummy(&dummy, cc_record->port, 0, misdn_lib_port_is_nt(cc_record->port), 0);
- dummy.fac_out.Function = request;
- dummy.fac_out.u.CCBSRequest.InvokeID = cc_record->invoke_id;
- dummy.fac_out.u.CCBSRequest.ComponentType = FacComponent_Invoke;
- dummy.fac_out.u.CCBSRequest.Component.Invoke.CallLinkageID = cc_record->linkage_id;
-
- /* Send message */
- print_facility(&dummy.fac_out, &dummy);
- misdn_lib_send_event(&dummy, EVENT_FACILITY);
+ if (cc_record->ptp) {
+ if (!cc_record->mode.ptp.bc) {
+ bc = misdn_lib_get_register_bc(cc_record->port);
+ if (bc) {
+ cc_record->mode.ptp.bc = bc;
+ cc_record->activated = 1;
+
+ /* Build message */
+ bc->fac_out.Function = request->ptp;
+ bc->fac_out.u.CCBS_T_Request.InvokeID = cc_record->invoke_id;
+ bc->fac_out.u.CCBS_T_Request.ComponentType = FacComponent_Invoke;
+ bc->fac_out.u.CCBS_T_Request.Component.Invoke.Q931ie =
+ cc_record->redial.setup_bc_hlc_llc;
+ memset(&id, 0, sizeof(id));
+ id.number_plan = cc_record->redial.dialed.number_plan;
+ id.number_type = cc_record->redial.dialed.number_type;
+ ast_copy_string(id.number, cc_record->redial.dialed.number,
+ sizeof(id.number));
+ misdn_Address_fill(
+ &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Destination,
+ &id);
+ misdn_Address_fill(
+ &bc->fac_out.u.CCBS_T_Request.Component.Invoke.Originating,
+ &cc_record->redial.caller);
+ bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1;
+ bc->fac_out.u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator =
+ (cc_record->redial.caller.presentation != 0) ? 0 : 1;
+ bc->fac_out.u.CCBS_T_Request.Component.Invoke.RetentionSupported = 0;
+
+ /* Send message */
+ print_facility(&bc->fac_out, bc);
+ misdn_lib_send_event(bc, EVENT_REGISTER);
+ }
+ }
+ } else {
+ cc_record->outstanding_message = 1;
+
+ /* Build message */
+ misdn_make_dummy(&dummy, cc_record->port, 0,
+ misdn_lib_port_is_nt(cc_record->port), 0);
+ dummy.fac_out.Function = request->ptmp;
+ dummy.fac_out.u.CCBSRequest.InvokeID = cc_record->invoke_id;
+ dummy.fac_out.u.CCBSRequest.ComponentType = FacComponent_Invoke;
+ dummy.fac_out.u.CCBSRequest.Component.Invoke.CallLinkageID =
+ cc_record->mode.ptmp.linkage_id;
+
+ /* Send message */
+ print_facility(&dummy.fac_out, &dummy);
+ misdn_lib_send_event(&dummy, EVENT_FACILITY);
+ }
}
}
ast_mutex_unlock(&misdn_cc_record_lock);
@@ -8640,6 +9149,8 @@
} else if (cc_record->port < 0) {
/* The network did not tell us that call completion was available. */
error_str = "No port number";
+ } else if (cc_record->ptp && !cc_record->mode.ptp.bc) {
+ error_str = "Could not allocate call-completion signaling link";
} else {
/* Should never happen. */
error_str = "Unexpected error";
@@ -8691,7 +9202,12 @@
*/
static int misdn_command_ccbs_request(struct ast_channel *chan, const char *cmd_name, char *options)
{
- return misdn_command_cc_request(chan, cmd_name, options, Fac_CCBSRequest);
+ static const struct misdn_cc_request request = {
+ .ptmp = Fac_CCBSRequest,
+ .ptp = Fac_CCBS_T_Request
+ };
+
+ return misdn_command_cc_request(chan, cmd_name, options, &request);
} /* end misdn_command_ccbs_request() */
#endif /* defined(AST_MISDN_ENHANCEMENTS) */
@@ -8717,7 +9233,12 @@
*/
static int misdn_command_ccnr_request(struct ast_channel *chan, const char *cmd_name, char *options)
{
- return misdn_command_cc_request(chan, cmd_name, options, Fac_CCNRRequest);
+ static const struct misdn_cc_request request = {
+ .ptmp = Fac_CCNRRequest,
+ .ptp = Fac_CCNR_T_Request
+ };
+
+ return misdn_command_cc_request(chan, cmd_name, options, &request);
} /* end misdn_command_ccnr_request() */
#endif /* defined(AST_MISDN_ENHANCEMENTS) */
Modified: team/rmudgett/misdn_facility/channels/misdn/isdn_lib.c
URL: http://svn.digium.com/view/asterisk/team/rmudgett/misdn_facility/channels/misdn/isdn_lib.c?view=diff&rev=165957&r1=165956&r2=165957
==============================================================================
--- team/rmudgett/misdn_facility/channels/misdn/isdn_lib.c (original)
+++ team/rmudgett/misdn_facility/channels/misdn/isdn_lib.c Fri Dec 19 12:54:16 2008
@@ -25,9 +25,9 @@
#include "isdn_lib_intern.h"
#include "isdn_lib.h"
-enum event_response_e (*cb_event) (enum event_e event, struct misdn_bchannel *bc, void *user_data);
-
-void (*cb_log) (int level, int port, char *tmpl, ...)
+enum event_response_e (*cb_event)(enum event_e event, struct misdn_bchannel *bc, void *user_data);
+
+void (*cb_log)(int level, int port, char *tmpl, ...)
__attribute__ ((format (printf, 3, 4)));
int (*cb_jb_empty)(struct misdn_bchannel *bc, char *buffer, int len);
@@ -48,11 +48,7 @@
int misdn_lib_get_l2_up(struct misdn_stack *stack);
-struct misdn_stack* get_misdn_stack( void );
-
-static int set_chan_in_stack(struct misdn_stack *stack, int channel);
-
-int release_cr(struct misdn_stack *stack, mISDNuser_head_t *hh);
+struct misdn_stack *get_misdn_stack(void);
int misdn_lib_port_is_pri(int port)
{
@@ -268,7 +264,7 @@
#define TONE_BUSY_CNT 20 /* ? */
#define TONE_BUSY_SILENCE_CNT 48 /* ? */
-static int entity;
+static int entity;
static struct misdn_lib *glob_mgr;
@@ -285,7 +281,6 @@
/* from isdn_lib.h */
/* user iface */
-int te_lib_init( void ) ; /* returns midev */
void te_lib_destroy(int midev) ;
struct misdn_bchannel *manager_find_bc_by_pid(int pid);
struct misdn_bchannel *manager_find_bc_holded(struct misdn_bchannel* bc);
@@ -479,9 +474,18 @@
{
int i;
- for (i=0; i <= stack->b_num; i++) {
- cb_log(6, stack->port, "Idx:%d stack->cchan:%d in_use:%d Chan:%d\n",i,stack->channels[i], stack->bc[i].in_use, i+1);
- }
+ for (i = 0; i <= stack->b_num; ++i) {
+ cb_log(6, stack->port, "Idx:%d stack->cchan:%d in_use:%d Chan:%d\n",
+ i, stack->channels[i], stack->bc[i].in_use, i + 1);
+ } /* end for */
+#if defined(AST_MISDN_ENHANCEMENTS)
+ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->bc); ++i) {
+ if (stack->bc[i].in_use) {
+ cb_log(6, stack->port, "Idx:%d stack->cchan:%d REGISTER Chan:%d in_use\n",
+ i, stack->channels[i], i + 1);
+ }
+ } /* end for */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
}
@@ -496,10 +500,9 @@
static int set_chan_in_stack(struct misdn_stack *stack, int channel)
{
-
cb_log(4,stack->port,"set_chan_in_stack: %d\n",channel);
dump_chan_list(stack);
- if (channel >=1 && channel <= MAX_BCHANS) {
+ if (1 <= channel && channel <= ARRAY_LEN(stack->channels)) {
if (!stack->channels[channel-1])
stack->channels[channel-1] = 1;
else {
@@ -519,73 +522,87 @@
static int find_free_chan_in_stack(struct misdn_stack *stack, struct misdn_bchannel *bc, int channel, int dec)
{
int i;
- int chan=0;
- int bnums = stack->pri ? stack->b_num : stack->b_num - 1;
-
- if (bc->channel_found)
+ int chan = 0;
+ int bnums;
+
+ if (bc->channel_found) {
return 0;
-
- bc->channel_found=1;
-
- cb_log(5,stack->port,"find_free_chan: req_chan:%d\n",channel);
-
- if (channel < 0 || channel > MAX_BCHANS) {
- cb_log(0, stack->port, " !! out of bound call to find_free_chan_in_stack! (ch:%d)\n", channel);
- return 0;
- }
-
- channel--;
-
- if (dec) {
- for (i = bnums; i >=0; i--) {
- if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
- if (!stack->channels[i]) {
- cb_log (3, stack->port, " --> found chan%s: %d\n", channel>=0?" (preselected)":"", i+1);
- chan=i+1;
- break;
+ }
+
+ bc->channel_found = 1;
+
+#if defined(AST_MISDN_ENHANCEMENTS)
+ if (bc->is_register_pool) {
+ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->channels); ++i) {
+ if (!stack->channels[i]) {
+ chan = i + 1;
+ cb_log(3, stack->port, " --> found REGISTER chan: %d\n", chan);
+ break;
+ }
+ } /* end for */
+ } else
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ {
+ cb_log(5, stack->port, "find_free_chan: req_chan:%d\n", channel);
+
+ if (channel < 0 || channel > MAX_BCHANS) {
+ cb_log(0, stack->port, " !! out of bound call to find_free_chan_in_stack! (ch:%d)\n", channel);
+ return 0;
+ }
+
+ --channel;
+
+ bnums = stack->pri ? stack->b_num : stack->b_num - 1;
+ if (dec) {
+ for (i = bnums; i >= 0; --i) {
+ if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
+ if (!stack->channels[i]) {
+ chan = i + 1;
+ cb_log(3, stack->port, " --> found chan%s: %d\n", channel >= 0 ? " (preselected)" : "", chan);
+ break;
+ }
}
- }
- }
- } else {
- for (i = 0; i <= bnums; i++) {
- if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
- if (!stack->channels[i]) {
- cb_log (3, stack->port, " --> found chan%s: %d\n", channel>=0?" (preselected)":"", i+1);
- chan=i+1;
- break;
+ } /* end for */
+ } else {
+ for (i = 0; i <= bnums; ++i) {
+ if (i != 15 && (channel < 0 || i == channel)) { /* skip E1 D channel ;) and work with chan preselection */
+ if (!stack->channels[i]) {
+ chan = i + 1;
+ cb_log(3, stack->port, " --> found chan%s: %d\n", channel >= 0 ? " (preselected)" : "", chan);
+ break;
+ }
}
- }
+ } /* end for */
}
}
if (!chan) {
- cb_log (1, stack->port, " !! NO FREE CHAN IN STACK\n");
+ cb_log(1, stack->port, " !! NO FREE CHAN IN STACK\n");
dump_chan_list(stack);
bc->out_cause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
return -1;
- }
-
- if (set_chan_in_stack(stack, chan)<0) {
- cb_log (0, stack->port, "Channel Already in use:%d\n", chan);
+ }
+
+ if (set_chan_in_stack(stack, chan) < 0) {
+ cb_log(0, stack->port, "Channel Already in use:%d\n", chan);
bc->out_cause = AST_CAUSE_REQUESTED_CHAN_UNAVAIL;
return -1;
}
- bc->channel=chan;
+ bc->channel = chan;
return 0;
}
-static int empty_chan_in_stack(struct misdn_stack *stack, int channel)
-{
- if (channel<=0 || channel>MAX_BCHANS) {
- cb_log(0,stack?stack->port:0, "empty_chan_in_stack: cannot empty channel %d\n",channel);
- return -1;
- }
-
- cb_log (4, stack?stack->port:0, "empty_chan_in_stack: %d\n",channel);
- stack->channels[channel-1] = 0;
+static void empty_chan_in_stack(struct misdn_stack *stack, int channel)
+{
+ if (channel < 1 || ARRAY_LEN(stack->channels) < channel) {
+ cb_log(0, stack->port, "empty_chan_in_stack: cannot empty channel %d\n", channel);
+ return;
+ }
+
+ cb_log(4, stack->port, "empty_chan_in_stack: %d\n", channel);
+ stack->channels[channel - 1] = 0;
dump_chan_list(stack);
- return 0;
}
char *bc_state2str(enum bchannel_state state) {
@@ -809,21 +826,25 @@
{
int i;
- for (i=0; i<=stack->b_num; i++) {
- if (global_state == MISDN_INITIALIZED) {
+ if (global_state == MISDN_INITIALIZED) {
+ for (i = 0; i <= stack->b_num; ++i) {
cb_event(EVENT_CLEANUP, &stack->bc[i], NULL);
- empty_chan_in_stack(stack,i+1);
+ empty_chan_in_stack(stack, i + 1);
empty_bc(&stack->bc[i]);
clean_up_bc(&stack->bc[i]);
stack->bc[i].in_use = 0;
- }
-
- }
-}
-
-static int newteid=0;
-
-#define MAXPROCS 0x100
+ } /* end for */
+#if defined(AST_MISDN_ENHANCEMENTS)
+ for (i = MAX_BCHANS + 1; i < ARRAY_LEN(stack->bc); ++i) {
+ empty_chan_in_stack(stack, i + 1);
+ empty_bc(&stack->bc[i]);
+ stack->bc[i].in_use = 0;
+ } /* end for */
+#endif /* defined(AST_MISDN_ENHANCEMENTS) */
+ }
+}
+
+static int new_te_id = 0;
static int misdn_lib_get_l1_down(struct misdn_stack *stack)
{
@@ -937,68 +958,64 @@
-static int create_process (int midev, struct misdn_bchannel *bc) {
+static int create_process(int midev, struct misdn_bchannel *bc)
+{
iframe_t ncr;
int l3_id;
- int i;
- struct misdn_stack *stack=get_stack_by_bc(bc);
-
+ int proc_id;
+ struct misdn_stack *stack;
+
+ stack = get_stack_by_bc(bc);
if (stack->nt) {
- if (find_free_chan_in_stack(stack, bc, bc->channel_preselected?bc->channel:0, 0)<0) return -1;
- cb_log(4,stack->port, " --> found channel: %d\n",bc->channel);
-
- for (i=0; i <= MAXPROCS; i++)
- if (stack->procids[i]==0) break;
-
- if (i== MAXPROCS) {
+ if (find_free_chan_in_stack(stack, bc, bc->channel_preselected ? bc->channel : 0, 0) < 0) {
+ return -1;
+ }
+ cb_log(4, stack->port, " --> found channel: %d\n", bc->channel);
+
+ for (proc_id = 0; proc_id < MAXPROCS; ++proc_id) {
+ if (stack->procids[proc_id] == 0) {
+ break;
+ }
+ } /* end for */
+ if (proc_id == MAXPROCS) {
cb_log(0, stack->port, "Couldn't Create New ProcId.\n");
return -1;
}
- stack->procids[i]=1;
-
- l3_id = 0xff00 | i;
-
- ncr.prim = CC_NEW_CR | REQUEST;
-
- ncr.addr = (stack->upper_id | FLG_MSG_DOWN) ;
-
+
+ stack->procids[proc_id] = 1;
+
+ l3_id = 0xff00 | proc_id;
+ bc->l3_id = l3_id;
+ cb_log(3, stack->port, " --> new_l3id %x\n", l3_id);
+ } else {
+ if (stack->ptp || bc->te_choose_channel) {
+ /* we know exactly which channels are in use */
+ if (find_free_chan_in_stack(stack, bc, bc->channel_preselected ? bc->channel : 0, bc->dec) < 0) {
+ return -1;
+ }
+ cb_log(2, stack->port, " --> found channel: %d\n", bc->channel);
+ } else {
+ /* other phones could have made a call also on this port (ptmp) */
+ bc->channel = 0xff;
+ }
+
+ /* if we are in te-mode, we need to create a process first */
+ if (++new_te_id > 0xffff) {
+ new_te_id = 0x0001;
+ }
+
+ l3_id = (entity << 16) | new_te_id;
+ bc->l3_id = l3_id;
+ cb_log(3, stack->port, "--> new_l3id %x\n", l3_id);
+
+ /* send message */
+ ncr.prim = CC_NEW_CR | REQUEST;
+ ncr.addr = (stack->upper_id | FLG_MSG_DOWN);
ncr.dinfo = l3_id;
ncr.len = 0;
-
- bc->l3_id = l3_id;
- cb_log(3, stack->port, " --> new_l3id %x\n",l3_id);
-
- } else {
- if (stack->ptp || bc->te_choose_channel) {
- /* we know exactly which channels are in use */
- if (find_free_chan_in_stack(stack, bc, bc->channel_preselected?bc->channel:0, bc->dec)<0) return -1;
- cb_log(2,stack->port, " --> found channel: %d\n",bc->channel);
- } else {
- /* other phones could have made a call also on this port (ptmp) */
- bc->channel=0xff;
- }
-
-
- /* if we are in te-mode, we need to create a process first */
- if (newteid++ > 0xffff)
- newteid = 0x0001;
-
- l3_id = (entity<<16) | newteid;
- /* preparing message */
- ncr.prim = CC_NEW_CR | REQUEST;
-
- ncr.addr = (stack->upper_id | FLG_MSG_DOWN) ;
-
- ncr.dinfo =l3_id;
- ncr.len = 0;
[... 2280 lines stripped ...]
More information about the asterisk-commits
mailing list