[asterisk-commits] rmudgett: branch rmudgett/call_waiting r267179 - in /team/rmudgett/call_waiti...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jun 2 14:30:46 CDT 2010


Author: rmudgett
Date: Wed Jun  2 14:30:39 2010
New Revision: 267179

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=267179
Log:
Merged revisions 266930,267013,267100 via svnmerge from 
https://origsvn.digium.com/svn/asterisk/team/group/CCSS

................
  r266930 | root | 2010-06-02 11:18:06 -0500 (Wed, 02 Jun 2010) | 18 lines
  
  Merged revisions 266926 via svnmerge from 
  file:///srv/subversion/repos/asterisk/trunk
  
  ........
    r266926 | rmudgett | 2010-06-02 11:14:12 -0500 (Wed, 02 Jun 2010) | 11 lines
    
    Add ETSI Explicit Call Transfer (ECT) support.
    
    Added ability to send and receive ETSI Explicit Call Transfer (ECT)
    messages to eliminate tromboned calls.
    
    Note: Asterisk already supported initiating the transfer of calls to
    eliminate tromboned calls to libpri so there was nothing to do for the
    asterisk portion.
    
    Review:	https://reviewboard.asterisk.org/r/520/
  ........
................
  r267013 | root | 2010-06-02 12:18:00 -0500 (Wed, 02 Jun 2010) | 14 lines
  
  Merged revisions 267008 via svnmerge from 
  file:///srv/subversion/repos/asterisk/trunk
  
  ........
    r267008 | rmudgett | 2010-06-02 12:13:53 -0500 (Wed, 02 Jun 2010) | 7 lines
    
    Add ETSI Advice Of Charge (AOC) event reporting.
    
    This feature generates AMI events in the new aoc event class from the
    events passed up by libpri.
    
    Review:	https://reviewboard.asterisk.org/r/537/
  ........
................
  r267100 | root | 2010-06-02 13:17:56 -0500 (Wed, 02 Jun 2010) | 89 lines
  
  Merged revisions 267041,267065,267093,267096-267097 via svnmerge from 
  file:///srv/subversion/repos/asterisk/trunk
  
  ................
    r267041 | pabelanger | 2010-06-02 12:25:05 -0500 (Wed, 02 Jun 2010) | 14 lines
    
    Merged revisions 267009 via svnmerge from 
    https://origsvn.digium.com/svn/asterisk/branches/1.4
    
    ........
      r267009 | pabelanger | 2010-06-02 13:14:37 -0400 (Wed, 02 Jun 2010) | 7 lines
      
      Cleanup error/warning messages in AEL2 parser
      
      (closes issue #16684)
      Reported by: Silmaril
      Patches:
            patch_ael2_logmsg.diff uploaded by Silmaril (license 979)
    ........
  ................
    r267065 | jpeeler | 2010-06-02 12:29:35 -0500 (Wed, 02 Jun 2010) | 12 lines
    
    Fix infinite loop when loading codec speex
    
    This changes the sample slinear frame data to contain non-zero data so that
    translation calculations for speex works when preprocessing and VAD is turned
    on. The encoder expects samples to be returned, but when attempted with the
    mentioned two options and silent sample frames everything was discarded. 
    
    (closes issue #17240)
    Reported by: seandarcy
    
    Review: https://reviewboard.asterisk.org/r/682/
  ................
    r267093 | russell | 2010-06-02 12:57:39 -0500 (Wed, 02 Jun 2010) | 2 lines
    
    Silence a compiler warning.
  ................
    r267096 | rmudgett | 2010-06-02 13:10:15 -0500 (Wed, 02 Jun 2010) | 38 lines
    
    Generic Advice of Charge.
    
    Asterisk Generic AOC Representation
    - Generic AOC encode/decode routines.
      (Generic AOC must be encoded to be passed on the wire in the AST_CONTROL_AOC frame)
    - AST_CONTROL_AOC frame type to represent generic encoded AOC data
    - Manager events for AOC-S, AOC-D, and AOC-E messages
    
    Asterisk App Support
    - app_dial AOC-S pass-through support on call setup
    - app_queue AOC-S pass-through support on call setup
    
    AOC Unit Tests
    - AOC Unit Tests for encode/decode routines
    - AOC Unit Test for manager event representation.
    
    SIP AOC Support
    - Pass-through of generic AOC-D and AOC-E messages to snom phones via the
      snom AOC specification.
    - Creation of chan_sip page3 flags for the addition of the new
      'snom_aoc_enabled' sip.conf option.
    
    IAX AOC Support
    - Natively supports AOC pass-through through the use of the new
      AST_CONTROL_AOC frame type
    
    DAHDI AOC Support
    - ETSI PRI full AOC Pass-through support
    - 'aoc_enable' chan_dahdi.conf option for independently enabling
      pass-through of AOC-S, AOC-D, AOC-E.
    - 'aoce_delayhangup' option for retrieving AOC-E on disconnect.
    - DAHDI A() dial string option for requesting AOC services.
      example usage:
      ;requests AOC-S, AOC-D, and AOC-E on call setup
      exten=>1111,1,Dial(DAHDI/g1/1112/A(s,d,e))
    
    Review:	https://reviewboard.asterisk.org/r/552/
  ................
    r267097 | mmichelson | 2010-06-02 13:13:18 -0500 (Wed, 02 Jun 2010) | 9 lines
    
    Prevent use of uninitialized values.
    
    Two struct sockaddr_ins are created when applying directmedia
    host access rules. The addresses of these are passed to the RTP
    engine to be filled in. However, the RTP engine inspects the fields
    of the structs before actually taking action. This inspection caused
    valgrind to be a bit unhappy.
  ................
................

Added:
    team/rmudgett/call_waiting/doc/advice_of_charge.txt
      - copied unchanged from r267100, team/group/CCSS/doc/advice_of_charge.txt
    team/rmudgett/call_waiting/include/asterisk/aoc.h
      - copied unchanged from r267100, team/group/CCSS/include/asterisk/aoc.h
    team/rmudgett/call_waiting/main/aoc.c
      - copied unchanged from r267100, team/group/CCSS/main/aoc.c
    team/rmudgett/call_waiting/tests/test_aoc.c
      - copied unchanged from r267100, team/group/CCSS/tests/test_aoc.c
Modified:
    team/rmudgett/call_waiting/   (props changed)
    team/rmudgett/call_waiting/CHANGES
    team/rmudgett/call_waiting/apps/app_dial.c
    team/rmudgett/call_waiting/apps/app_queue.c
    team/rmudgett/call_waiting/apps/app_voicemail.c
    team/rmudgett/call_waiting/channels/chan_dahdi.c
    team/rmudgett/call_waiting/channels/chan_sip.c
    team/rmudgett/call_waiting/channels/sig_pri.c
    team/rmudgett/call_waiting/channels/sig_pri.h
    team/rmudgett/call_waiting/channels/sip/include/sip.h
    team/rmudgett/call_waiting/configs/chan_dahdi.conf.sample
    team/rmudgett/call_waiting/configs/manager.conf.sample
    team/rmudgett/call_waiting/configs/sip.conf.sample
    team/rmudgett/call_waiting/configure
    team/rmudgett/call_waiting/configure.ac
    team/rmudgett/call_waiting/include/asterisk/autoconfig.h.in
    team/rmudgett/call_waiting/include/asterisk/frame.h
    team/rmudgett/call_waiting/include/asterisk/manager.h
    team/rmudgett/call_waiting/include/asterisk/slin.h
    team/rmudgett/call_waiting/main/ast_expr2.y
    team/rmudgett/call_waiting/main/asterisk.c
    team/rmudgett/call_waiting/main/channel.c
    team/rmudgett/call_waiting/main/features.c
    team/rmudgett/call_waiting/main/manager.c

Propchange: team/rmudgett/call_waiting/
------------------------------------------------------------------------------
    automerge = *

Propchange: team/rmudgett/call_waiting/
------------------------------------------------------------------------------
Binary property 'branch-1.4-merged' - no diff available.

Propchange: team/rmudgett/call_waiting/
------------------------------------------------------------------------------
--- call_waiting-integrated (original)
+++ call_waiting-integrated Wed Jun  2 14:30:39 2010
@@ -1,1 +1,1 @@
-/team/group/CCSS:1-266906
+/team/group/CCSS:1-267137

Propchange: team/rmudgett/call_waiting/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Wed Jun  2 14:30:39 2010
@@ -1,1 +1,1 @@
-/trunk:1-266880
+/trunk:1-267099

Modified: team/rmudgett/call_waiting/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/CHANGES?view=diff&rev=267179&r1=267178&r2=267179
==============================================================================
--- team/rmudgett/call_waiting/CHANGES (original)
+++ team/rmudgett/call_waiting/CHANGES Wed Jun  2 14:30:39 2010
@@ -337,6 +337,10 @@
    dialing option.  Dial(DAHDI/g1/[extension]/K(<keypad_digits>))
    Access any received keypad digits in SETUP message by: ${CHANNEL(keypad_digits)}
    (requires latest LibPRI)
+ * Added ability to send and receive ETSI Explicit Call Transfer (ECT) messages
+   to eliminate tromboned calls.  A tromboned call goes out an interface and comes
+   back into the same interface.  Tromboned calls happen because of call routing,
+   call deflection, call forwarding, and call transfer.
  * Added the ability to support call waiting calls.  (The SETUP has no B channel
    assigned.)
 
@@ -367,6 +371,8 @@
    in a MixMonitor recording.
  * The 'iax2 show peers' output is now similar to the expected output of
    'sip show peers'.
+ * Added Advice-Of-Charge events (AOC-S, AOC-D, and AOC-E) in the new
+   aoc event class.
 
 Channel Event Logging
 ---------------------

Modified: team/rmudgett/call_waiting/apps/app_dial.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/apps/app_dial.c?view=diff&rev=267179&r1=267178&r2=267179
==============================================================================
--- team/rmudgett/call_waiting/apps/app_dial.c (original)
+++ team/rmudgett/call_waiting/apps/app_dial.c Wed Jun  2 14:30:39 2010
@@ -62,6 +62,7 @@
 #include "asterisk/global_datastores.h"
 #include "asterisk/dsp.h"
 #include "asterisk/cel.h"
+#include "asterisk/aoc.h"
 #include "asterisk/ccss.h"
 #include "asterisk/indications.h"
 
@@ -638,6 +639,7 @@
 	struct ast_party_connected_line connected;
 	/*! TRUE if an AST_CONTROL_CONNECTED_LINE update was saved to the connected element. */
 	unsigned int pending_connected_update:1;
+	struct ast_aoc_decoded *aoc_s_rate_list;
 };
 
 static int detect_disconnect(struct ast_channel *chan, char code, struct ast_str *featurecode);
@@ -645,6 +647,7 @@
 static void chanlist_free(struct chanlist *outgoing)
 {
 	ast_party_connected_line_free(&outgoing->connected);
+	ast_aoc_destroy_decoded(outgoing->aoc_s_rate_list);
 	ast_free(outgoing);
 }
 
@@ -1053,6 +1056,14 @@
 							ast_party_connected_line_free(&connected_caller);
 						}
 					}
+					if (o->aoc_s_rate_list) {
+						size_t encoded_size;
+						struct ast_aoc_encoded *encoded;
+						if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
+							ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
+							ast_aoc_destroy_encoded(encoded);
+						}
+					}
 					peer = c;
 					ast_copy_flags64(peerflags, o,
 						OPT_CALLEE_TRANSFER | OPT_CALLER_TRANSFER |
@@ -1113,6 +1124,14 @@
 								connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
 								ast_channel_update_connected_line(in, &connected_caller);
 								ast_party_connected_line_free(&connected_caller);
+							}
+						}
+						if (o->aoc_s_rate_list) {
+							size_t encoded_size;
+							struct ast_aoc_encoded *encoded;
+							if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
+								ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
+								ast_aoc_destroy_encoded(encoded);
 							}
 						}
 						peer = c;
@@ -1230,6 +1249,17 @@
 						}
 					}
 					break;
+				case AST_CONTROL_AOC:
+					{
+						struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
+						if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
+							ast_aoc_destroy_decoded(o->aoc_s_rate_list);
+							o->aoc_s_rate_list = decoded;
+						} else {
+							ast_aoc_destroy_decoded(decoded);
+						}
+					}
+					break;
 				case AST_CONTROL_REDIRECTING:
 					if (ast_test_flag64(peerflags, OPT_IGNORE_CONNECTEDLINE)) {
 						ast_verb(3, "Redirecting update to %s prevented.\n", in->name);

Modified: team/rmudgett/call_waiting/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/apps/app_queue.c?view=diff&rev=267179&r1=267178&r2=267179
==============================================================================
--- team/rmudgett/call_waiting/apps/app_queue.c (original)
+++ team/rmudgett/call_waiting/apps/app_queue.c Wed Jun  2 14:30:39 2010
@@ -94,6 +94,7 @@
 #include "asterisk/strings.h"
 #include "asterisk/global_datastores.h"
 #include "asterisk/taskprocessor.h"
+#include "asterisk/aoc.h"
 #include "asterisk/callerid.h"
 #include "asterisk/cel.h"
 #include "asterisk/data.h"
@@ -820,6 +821,7 @@
 	unsigned int pending_connected_update:1;
 	/*! TRUE if caller id is not available for connected line */
 	unsigned int dial_callerid_absent:1;
+	struct ast_aoc_decoded *aoc_s_rate_list;
 };
 
 
@@ -2654,6 +2656,7 @@
 		}
 		oo = outgoing;
 		outgoing = outgoing->q_next;
+		ast_aoc_destroy_decoded(oo->aoc_s_rate_list);
 		callattempt_free(oo);
 	}
 }
@@ -3333,6 +3336,14 @@
 							connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
 							ast_channel_update_connected_line(in, &connected_caller);
 							ast_party_connected_line_free(&connected_caller);
+						}
+					}
+					if (o->aoc_s_rate_list) {
+						size_t encoded_size;
+						struct ast_aoc_encoded *encoded;
+						if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
+							ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
+							ast_aoc_destroy_encoded(encoded);
 						}
 					}
 					peer = o;
@@ -3452,6 +3463,14 @@
 										connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
 										ast_channel_update_connected_line(in, &connected_caller);
 										ast_party_connected_line_free(&connected_caller);
+									}
+								}
+								if (o->aoc_s_rate_list) {
+									size_t encoded_size;
+									struct ast_aoc_encoded *encoded;
+									if ((encoded = ast_aoc_encode(o->aoc_s_rate_list, &encoded_size, o->chan))) {
+										ast_indicate_data(in, AST_CONTROL_AOC, encoded, encoded_size);
+										ast_aoc_destroy_encoded(encoded);
 									}
 								}
 								peer = o;
@@ -3520,6 +3539,17 @@
 							} else {
 								if (ast_channel_connected_line_macro(o->chan, in, f, 1, 1)) {
 									ast_indicate_data(in, AST_CONTROL_CONNECTED_LINE, f->data.ptr, f->datalen);
+								}
+							}
+							break;
+						case AST_CONTROL_AOC:
+							{
+								struct ast_aoc_decoded *decoded = ast_aoc_decode(f->data.ptr, f->datalen, o->chan);
+								if (decoded && (ast_aoc_get_msg_type(decoded) == AST_AOC_S)) {
+									ast_aoc_destroy_decoded(o->aoc_s_rate_list);
+									o->aoc_s_rate_list = decoded;
+								} else {
+									ast_aoc_destroy_decoded(decoded);
 								}
 							}
 							break;

Modified: team/rmudgett/call_waiting/apps/app_voicemail.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/apps/app_voicemail.c?view=diff&rev=267179&r1=267178&r2=267179
==============================================================================
--- team/rmudgett/call_waiting/apps/app_voicemail.c (original)
+++ team/rmudgett/call_waiting/apps/app_voicemail.c Wed Jun  2 14:30:39 2010
@@ -12395,7 +12395,9 @@
 	char attach[] = "/var/lib/asterisk/sounds/en/tt-weasels", attach2[] = "/var/lib/asterisk/sounds/en/tt-somethingwrong";
 	char buf[256] = ""; /* No line should actually be longer than 80 */
 	struct ast_channel *chan = NULL;
-	struct ast_vm_user *vmu, vmus;
+	struct ast_vm_user *vmu, vmus = {
+		.flags = 0,
+	};
 	FILE *file;
 	struct {
 		char *name;

Modified: team/rmudgett/call_waiting/channels/chan_dahdi.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/channels/chan_dahdi.c?view=diff&rev=267179&r1=267178&r2=267179
==============================================================================
--- team/rmudgett/call_waiting/channels/chan_dahdi.c (original)
+++ team/rmudgett/call_waiting/channels/chan_dahdi.c Wed Jun  2 14:30:39 2010
@@ -7002,7 +7002,7 @@
 #ifdef PRI_2BCT
 		if (!triedtopribridge) {
 			triedtopribridge = 1;
-			if (p0->pri && p0->pri == p1->pri && p0->transfer && p1->transfer) {
+			if (p0->pri && p0->pri == p1->pri && p0->pri->transfer) {
 				ast_mutex_lock(&p0->pri->lock);
 				switch (p0->sig) {
 				case SIG_PRI_LIB_HANDLE_CASES:
@@ -11888,7 +11888,12 @@
 						pris[span].pri.allow_call_waiting_calls =
 							conf->pri.pri.allow_call_waiting_calls;
 #endif	/* defined(HAVE_PRI_CALL_WAITING) */
+						pris[span].pri.transfer = conf->chan.transfer;
 						pris[span].pri.facilityenable = conf->pri.pri.facilityenable;
+#if defined(HAVE_PRI_AOC_EVENTS)
+						pris[span].pri.aoc_passthrough_flag = conf->pri.pri.aoc_passthrough_flag;
+						pris[span].pri.aoce_delayhangup = conf->pri.pri.aoce_delayhangup;
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 						ast_copy_string(pris[span].pri.msn_list, conf->pri.pri.msn_list, sizeof(pris[span].pri.msn_list));
 						ast_copy_string(pris[span].pri.idledial, conf->pri.pri.idledial, sizeof(pris[span].pri.idledial));
 						ast_copy_string(pris[span].pri.idleext, conf->pri.pri.idleext, sizeof(pris[span].pri.idleext));
@@ -17388,6 +17393,21 @@
 #endif /* PRI_GETSET_TIMERS */
 			} else if (!strcasecmp(v->name, "facilityenable")) {
 				confp->pri.pri.facilityenable = ast_true(v->value);
+#if defined(HAVE_PRI_AOC_EVENTS)
+			} else if (!strcasecmp(v->name, "aoc_enable")) {
+				confp->pri.pri.aoc_passthrough_flag = 0;
+				if (strchr(v->value, 's') || strchr(v->value, 'S')) {
+					confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_S;
+				}
+				if (strchr(v->value, 'd') || strchr(v->value, 'D')) {
+					confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_D;
+				}
+				if (strchr(v->value, 'e') || strchr(v->value, 'E')) {
+					confp->pri.pri.aoc_passthrough_flag |= SIG_PRI_AOC_GRANT_E;
+				}
+			} else if (!strcasecmp(v->name, "aoce_delayhangup")) {
+				confp->pri.pri.aoce_delayhangup = ast_true(v->value);
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 #if defined(HAVE_PRI_CALL_HOLD)
 			} else if (!strcasecmp(v->name, "hold_disconnect_transfer")) {
 				confp->pri.pri.hold_disconnect_transfer = ast_true(v->value);

Modified: team/rmudgett/call_waiting/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/channels/chan_sip.c?view=diff&rev=267179&r1=267178&r2=267179
==============================================================================
--- team/rmudgett/call_waiting/channels/chan_sip.c (original)
+++ team/rmudgett/call_waiting/channels/chan_sip.c Wed Jun  2 14:30:39 2010
@@ -261,6 +261,7 @@
 #include "asterisk/event.h"
 #include "asterisk/stun.h"
 #include "asterisk/cel.h"
+#include "asterisk/aoc.h"
 #include "sip/include/sip.h"
 #include "sip/include/globals.h"
 #include "sip/include/config_parser.h"
@@ -804,7 +805,7 @@
 static int regobjs = 0;       /*!< Registry objects */
 /* }@ */
 
-static struct ast_flags global_flags[2] = {{0}};  /*!< global SIP_ flags */
+static struct ast_flags global_flags[3] = {{0}};  /*!< global SIP_ flags */
 static int global_t38_maxdatagram;                /*!< global T.38 FaxMaxDatagram override */
 
 static char used_context[AST_MAX_CONTEXT];        /*!< name of automatically created context for unloading */
@@ -1275,6 +1276,7 @@
 static int transmit_publish(struct sip_epa_entry *epa_entry, enum sip_publish_type publish_type, const char * const explicit_uri);
 static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init, const char * const explicit_uri);
 static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int oldsdp);
+static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *decoded);
 static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration);
 static int transmit_info_with_vidupdate(struct sip_pvt *p);
 static int transmit_message_with_text(struct sip_pvt *p, const char *text);
@@ -4702,6 +4704,7 @@
 
 	ast_copy_flags(&dialog->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&dialog->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&dialog->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 	dialog->capability = peer->capability;
 	dialog->prefs = peer->prefs;
 	if (ast_test_flag(&dialog->flags[1], SIP_PAGE2_T38SUPPORT)) {
@@ -6249,6 +6252,41 @@
 	case AST_CONTROL_REDIRECTING:
 		update_redirecting(p, data, datalen);
 		break;
+	case AST_CONTROL_AOC:
+		{
+			struct ast_aoc_decoded *decoded = ast_aoc_decode((struct ast_aoc_encoded *) data, datalen, ast);
+			if (!decoded) {
+				ast_log(LOG_ERROR, "Error decoding indicated AOC data\n");
+				res = -1;
+				break;
+			}
+			switch (ast_aoc_get_msg_type(decoded)) {
+			case AST_AOC_REQUEST:
+				if (ast_aoc_get_termination_request(decoded)) {
+					/* TODO, once there is a way to get AOC-E on hangup, attempt that here
+					 * before hanging up the channel.*/
+
+					/* The other side has already initiated the hangup. This frame
+					 * just says they are waiting to get AOC-E before completely tearing
+					 * the call down.  Since SIP does not support this at the moment go
+					 * ahead and terminate the call here to avoid an unnecessary timeout. */
+					ast_log(LOG_DEBUG, "AOC-E termination request received on %s. This is not yet supported on sip. Continue with hangup \n", p->owner->name);
+					ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_DEV);
+				}
+				break;
+			case AST_AOC_D:
+			case AST_AOC_E:
+				if (ast_test_flag(&p->flags[2], SIP_PAGE3_SNOM_AOC)) {
+					transmit_info_with_aoc(p, decoded);
+				}
+				break;
+			case AST_AOC_S: /* S not supported yet */
+			default:
+				break;
+			}
+			ast_aoc_destroy_decoded(decoded);
+		}
+		break;
 	case -1:
 		res = -1;
 		break;
@@ -6888,6 +6926,7 @@
 	/* Copy global flags to this PVT at setup. */
 	ast_copy_flags(&p->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 
 	p->do_history = recordhistory;
 
@@ -11856,6 +11895,53 @@
 	*/
 }
 
+/*! \brief Send SIP INFO advice of charge message */
+static int transmit_info_with_aoc(struct sip_pvt *p, struct ast_aoc_decoded *decoded)
+{
+	struct sip_request req;
+	struct ast_str *str = ast_str_alloca(512);
+	const struct ast_aoc_unit_entry *unit_entry = ast_aoc_get_unit_info(decoded, 0);
+	enum ast_aoc_charge_type charging = ast_aoc_get_charge_type(decoded);
+
+	reqprep(&req, p, SIP_INFO, 0, 1);
+
+	if (ast_aoc_get_msg_type(decoded) == AST_AOC_D) {
+		ast_str_append(&str, 0, "type=active;");
+	} else if (ast_aoc_get_msg_type(decoded) == AST_AOC_E) {
+		ast_str_append(&str, 0, "type=terminated;");
+	} else {
+		/* unsupported message type */
+		return -1;
+	}
+
+	switch (charging) {
+	case AST_AOC_CHARGE_FREE:
+		ast_str_append(&str, 0, "free-of-charge;");
+		break;
+	case AST_AOC_CHARGE_CURRENCY:
+		ast_str_append(&str, 0, "charging;");
+		ast_str_append(&str, 0, "charging-info=currency;");
+		ast_str_append(&str, 0, "amount=%u;", ast_aoc_get_currency_amount(decoded));
+		ast_str_append(&str, 0, "multiplier=%s;", ast_aoc_get_currency_multiplier_decimal(decoded));
+		if (!ast_strlen_zero(ast_aoc_get_currency_name(decoded))) {
+			ast_str_append(&str, 0, "currency=%s;", ast_aoc_get_currency_name(decoded));
+		}
+		break;
+	case AST_AOC_CHARGE_UNIT:
+		ast_str_append(&str, 0, "charging;");
+		ast_str_append(&str, 0, "charging-info=pulse;");
+		if (unit_entry) {
+			ast_str_append(&str, 0, "recorded-units=%u;", unit_entry->amount);
+		}
+		break;
+	default:
+		ast_str_append(&str, 0, "not-available;");
+	};
+
+	add_header(&req, "AOC", ast_str_buffer(str));
+
+	return send_request(p, &req, XMIT_RELIABLE, p->ocseq);
+}
 
 /*! \brief Send SIP INFO dtmf message, see Cisco documentation on cisco.com */
 static int transmit_info_with_digit(struct sip_pvt *p, const char digit, unsigned int duration)
@@ -14037,6 +14123,7 @@
 	/* Take the peer */
 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 
 	if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->udptl) {
 		p->t38_maxdatagram = peer->t38_maxdatagram;
@@ -14081,6 +14168,7 @@
 	if (!(res = check_auth(p, req, peer->name, p->peersecret, p->peermd5secret, sipmethod, uri2, reliable, req->ignore))) {
 		ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 		ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+		ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 		/* If we have a call limit, set flag */
 		if (peer->call_limit)
 			ast_set_flag(&p->flags[0], SIP_CALL_LIMIT);
@@ -24000,6 +24088,7 @@
 	copy_socket_data(&p->socket, &peer->socket);
 	ast_copy_flags(&p->flags[0], &peer->flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&p->flags[1], &peer->flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&p->flags[2], &peer->flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 
 	/* Send OPTIONs to peer's fullcontact */
 	if (!ast_strlen_zero(peer->fullcontact))
@@ -24757,6 +24846,7 @@
 	peer->type = SIP_TYPE_PEER;
 	ast_copy_flags(&peer->flags[0], &global_flags[0], SIP_FLAGS_TO_COPY);
 	ast_copy_flags(&peer->flags[1], &global_flags[1], SIP_PAGE2_FLAGS_TO_COPY);
+	ast_copy_flags(&peer->flags[2], &global_flags[2], SIP_PAGE3_FLAGS_TO_COPY);
 	ast_string_field_set(peer, context, sip_cfg.default_context);
 	ast_string_field_set(peer, subscribecontext, sip_cfg.default_subscribecontext);
 	ast_string_field_set(peer, language, default_language);
@@ -24863,8 +24953,8 @@
 	int format = 0;		/* Ama flags */
 	int timerb_set = 0, timert1_set = 0;
 	time_t regseconds = 0;
-	struct ast_flags peerflags[2] = {{(0)}};
-	struct ast_flags mask[2] = {{(0)}};
+	struct ast_flags peerflags[3] = {{(0)}};
+	struct ast_flags mask[3] = {{(0)}};
 	char callback[256] = "";
 	struct sip_peer tmp_peer;
 	const char *srvlookup = NULL;
@@ -25255,6 +25345,8 @@
 				ast_string_field_set(peer, unsolicited_mailbox, v->value);
 			} else if (!strcasecmp(v->name, "use_q850_reason")) {
 				ast_set2_flag(&peer->flags[1], ast_true(v->value), SIP_PAGE2_Q850_REASON);
+			} else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
+				ast_set2_flag(&peer->flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
 			}
 		}
 
@@ -25424,6 +25516,7 @@
 
 	ast_copy_flags(&peer->flags[0], &peerflags[0], mask[0].flags);
 	ast_copy_flags(&peer->flags[1], &peerflags[1], mask[1].flags);
+	ast_copy_flags(&peer->flags[2], &peerflags[2], mask[2].flags);
 	if (ast_test_flag(&peer->flags[1], SIP_PAGE2_ALLOWSUBSCRIBE)) {
 		sip_cfg.allowsubscribe = TRUE;	/* No global ban any more */
 	}
@@ -26163,6 +26256,8 @@
 			}
 		} else if (!strcasecmp(v->name, "use_q850_reason")) {
 			ast_set2_flag(&global_flags[1], ast_true(v->value), SIP_PAGE2_Q850_REASON);
+		} else if (!strcasecmp(v->name, "snom_aoc_enabled")) {
+				ast_set2_flag(&global_flags[2], ast_true(v->value), SIP_PAGE3_SNOM_AOC);
 		}
 	}
 
@@ -26442,7 +26537,7 @@
 
 static int apply_directmedia_ha(struct sip_pvt *p, const char *op)
 {
-	struct sockaddr_in us, them;
+	struct sockaddr_in us = {0,}, them = {0,};
 	int res;
 
 	ast_rtp_instance_get_remote_address(p->rtp, &them);

Modified: team/rmudgett/call_waiting/channels/sig_pri.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/call_waiting/channels/sig_pri.c?view=diff&rev=267179&r1=267178&r2=267179
==============================================================================
--- team/rmudgett/call_waiting/channels/sig_pri.c (original)
+++ team/rmudgett/call_waiting/channels/sig_pri.c Wed Jun  2 14:30:39 2010
@@ -46,6 +46,7 @@
 #include "asterisk/cli.h"
 #include "asterisk/transcap.h"
 #include "asterisk/features.h"
+#include "asterisk/aoc.h"
 
 #include "sig_pri.h"
 #ifndef PRI_EVENT_FACILITY
@@ -1099,6 +1100,11 @@
 		old_chan->call = NULL;
 
 		/* Transfer flags from the old channel. */
+#if defined(HAVE_PRI_AOC_EVENTS)
+		new_chan->aoc_s_request_invoke_id_valid = old_chan->aoc_s_request_invoke_id_valid;
+		new_chan->waiting_for_aoce = old_chan->waiting_for_aoce;
+		new_chan->holding_aoce = old_chan->holding_aoce;
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 		new_chan->alerting = old_chan->alerting;
 		new_chan->alreadyhungup = old_chan->alreadyhungup;
 		new_chan->isidlecall = old_chan->isidlecall;
@@ -1109,8 +1115,13 @@
 		new_chan->digital = old_chan->digital;
 #if defined(HAVE_PRI_CALL_WAITING)
 		new_chan->is_call_waiting = old_chan->is_call_waiting;
-		old_chan->is_call_waiting = 0;
 #endif	/* defined(HAVE_PRI_CALL_WAITING) */
+
+#if defined(HAVE_PRI_AOC_EVENTS)
+		old_chan->aoc_s_request_invoke_id_valid = 0;
+		old_chan->waiting_for_aoce = 0;
+		old_chan->holding_aoce = 0;
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 		old_chan->alerting = 0;
 		old_chan->alreadyhungup = 0;
 		old_chan->isidlecall = 0;
@@ -1119,6 +1130,9 @@
 		old_chan->setup_ack = 0;
 		old_chan->outgoing = 0;
 		old_chan->digital = 0;
+#if defined(HAVE_PRI_CALL_WAITING)
+		old_chan->is_call_waiting = 0;
+#endif	/* defined(HAVE_PRI_CALL_WAITING) */
 
 		/* More stuff to transfer to the new channel. */
 #if defined(HAVE_PRI_REVERSE_CHARGE)
@@ -1127,6 +1141,10 @@
 #if defined(HAVE_PRI_SETUP_KEYPAD)
 		strcpy(new_chan->keypad_digits, old_chan->keypad_digits);
 #endif	/* defined(HAVE_PRI_SETUP_KEYPAD) */
+#if defined(HAVE_PRI_AOC_EVENTS)
+		new_chan->aoc_s_request_invoke_id = old_chan->aoc_s_request_invoke_id;
+		new_chan->aoc_e = old_chan->aoc_e;
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
 
 		if (new_chan->no_b_channel) {
 			/* Copy the real channel configuration to the no B channel interface. */
@@ -1626,6 +1644,106 @@
 	return 0;
 }
 
+#if defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER)
+/*!
+ * \internal
+ * \brief Attempt to transfer the two calls to each other.
+ * \since 1.8
+ *
+ * \param pri sig_pri PRI control structure.
+ * \param call_1 First call involved in the transfer.
+ * \param call_1_held TRUE if call_1 is on hold.
+ * \param call_2 Second call involved in the transfer.
+ * \param call_2_held TRUE if call_2 is on hold.
+ *
+ * \note Assumes the pri->lock is already obtained.
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+static int sig_pri_attempt_transfer(struct sig_pri_pri *pri, q931_call *call_1, int call_1_held, q931_call *call_2, int call_2_held)
+{
+	int retval;
+	int call_1_chanpos;
+	int call_2_chanpos;
+	struct ast_channel *call_1_ast;
+	struct ast_channel *call_2_ast;
+	struct ast_channel *bridged;
+
+	call_1_chanpos = pri_find_pri_call(pri, call_1);
+	call_2_chanpos = pri_find_pri_call(pri, call_2);
+	if (call_1_chanpos < 0 || call_2_chanpos < 0) {
+		return -1;
+	}
+
+	/* Deadlock avoidance is attempted. */
+	sig_pri_lock_private(pri->pvts[call_1_chanpos]);
+	sig_pri_lock_owner(pri, call_1_chanpos);
+	sig_pri_lock_private(pri->pvts[call_2_chanpos]);
+	sig_pri_lock_owner(pri, call_2_chanpos);
+
+	call_1_ast = pri->pvts[call_1_chanpos]->owner;
+	call_2_ast = pri->pvts[call_2_chanpos]->owner;
+	if (!call_1_ast || !call_2_ast) {
+		if (call_1_ast) {
+			ast_channel_unlock(call_1_ast);
+		}
+		if (call_2_ast) {
+			ast_channel_unlock(call_2_ast);
+		}
+		sig_pri_unlock_private(pri->pvts[call_1_chanpos]);
+		sig_pri_unlock_private(pri->pvts[call_2_chanpos]);
+		return -1;
+	}
+
+	bridged = ast_bridged_channel(call_2_ast);
+	if (bridged) {
+		if (call_1_held) {
+			ast_queue_control(call_1_ast, AST_CONTROL_UNHOLD);
+		}
+		if (call_2_held) {
+			ast_queue_control(call_2_ast, AST_CONTROL_UNHOLD);
+		}
+
+		ast_verb(3, "TRANSFERRING %s to %s\n", call_2_ast->name, call_1_ast->name);
+		retval = ast_channel_masquerade(call_1_ast, bridged);
+	} else {
+		/* Try masquerading the other way. */
+		bridged = ast_bridged_channel(call_1_ast);
+		if (bridged) {
+			if (call_1_held) {
+				ast_queue_control(call_1_ast, AST_CONTROL_UNHOLD);
+			}
+			if (call_2_held) {
+				ast_queue_control(call_2_ast, AST_CONTROL_UNHOLD);
+			}
+
+			ast_verb(3, "TRANSFERRING %s to %s\n", call_1_ast->name, call_2_ast->name);
+			retval = ast_channel_masquerade(call_2_ast, bridged);
+		} else {
+			/* Could not transfer. */
+			retval = -1;
+		}
+	}
+	if (bridged && retval) {
+		/* Restore HOLD on held calls because masquerade failed. */
+		if (call_1_held) {
+			ast_queue_control(call_1_ast, AST_CONTROL_HOLD);
+		}
+		if (call_2_held) {
+			ast_queue_control(call_2_ast, AST_CONTROL_HOLD);
+		}
+	}
+
+	ast_channel_unlock(call_1_ast);
+	ast_channel_unlock(call_2_ast);
+	sig_pri_unlock_private(pri->pvts[call_1_chanpos]);
+	sig_pri_unlock_private(pri->pvts[call_2_chanpos]);
+
+	return retval;
+}
+#endif	/* defined(HAVE_PRI_CALL_HOLD) || defined(HAVE_PRI_TRANSFER) */
+
 #if defined(HAVE_PRI_CCSS)
 /*!
  * \internal
@@ -2010,6 +2128,940 @@
 	}
 }
 #endif	/* defined(HAVE_PRI_CCSS) */
+
+#if defined(HAVE_PRI_AOC_EVENTS)
+/*!
+ * \internal
+ * \brief Convert ast_aoc_charged_item to PRI_AOC_CHARGED_ITEM .
+ * \since 1.8
+ *
+ * \param value Value to convert to string.
+ *
+ * \return PRI_AOC_CHARGED_ITEM
+ */
+static enum PRI_AOC_CHARGED_ITEM sig_pri_aoc_charged_item_to_pri(enum PRI_AOC_CHARGED_ITEM value)
+{
+	switch (value) {
+	case AST_AOC_CHARGED_ITEM_NA:
+		return PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
+	case AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
+		return PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
+	case AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
+		return PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
+	case AST_AOC_CHARGED_ITEM_CALL_ATTEMPT:
+		return PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT;
+	case AST_AOC_CHARGED_ITEM_CALL_SETUP:
+		return PRI_AOC_CHARGED_ITEM_CALL_SETUP;
+	case AST_AOC_CHARGED_ITEM_USER_USER_INFO:
+		return PRI_AOC_CHARGED_ITEM_USER_USER_INFO;
+	case AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
+		return PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
+	}
+	return PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE;
+}
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+
+#if defined(HAVE_PRI_AOC_EVENTS)
+/*!
+ * \internal
+ * \brief Convert PRI_AOC_CHARGED_ITEM to ast_aoc_charged_item.
+ * \since 1.8
+ *
+ * \param value Value to convert to string.
+ *
+ * \return ast_aoc_charged_item
+ */
+static enum ast_aoc_s_charged_item sig_pri_aoc_charged_item_to_ast(enum PRI_AOC_CHARGED_ITEM value)
+{
+	switch (value) {
+	case PRI_AOC_CHARGED_ITEM_NOT_AVAILABLE:
+		return AST_AOC_CHARGED_ITEM_NA;
+	case PRI_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT:
+		return AST_AOC_CHARGED_ITEM_SPECIAL_ARRANGEMENT;
+	case PRI_AOC_CHARGED_ITEM_BASIC_COMMUNICATION:
+		return AST_AOC_CHARGED_ITEM_BASIC_COMMUNICATION;
+	case PRI_AOC_CHARGED_ITEM_CALL_ATTEMPT:
+		return AST_AOC_CHARGED_ITEM_CALL_ATTEMPT;
+	case PRI_AOC_CHARGED_ITEM_CALL_SETUP:
+		return AST_AOC_CHARGED_ITEM_CALL_SETUP;
+	case PRI_AOC_CHARGED_ITEM_USER_USER_INFO:
+		return AST_AOC_CHARGED_ITEM_USER_USER_INFO;
+	case PRI_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE:
+		return AST_AOC_CHARGED_ITEM_SUPPLEMENTARY_SERVICE;
+	}
+	return AST_AOC_CHARGED_ITEM_NA;
+}
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+
+#if defined(HAVE_PRI_AOC_EVENTS)
+/*!
+ * \internal
+ * \brief Convert AST_AOC_MULTIPLER to PRI_AOC_MULTIPLIER.
+ * \since 1.8
+ *
+ * \return pri enum equivalent.
+ */
+static int sig_pri_aoc_multiplier_from_ast(enum ast_aoc_currency_multiplier mult)
+{
+	switch (mult) {
+	case AST_AOC_MULT_ONETHOUSANDTH:
+		return PRI_AOC_MULTIPLIER_THOUSANDTH;
+	case AST_AOC_MULT_ONEHUNDREDTH:
+		return PRI_AOC_MULTIPLIER_HUNDREDTH;
+	case AST_AOC_MULT_ONETENTH:
+		return PRI_AOC_MULTIPLIER_TENTH;
+	case AST_AOC_MULT_ONE:
+		return PRI_AOC_MULTIPLIER_ONE;
+	case AST_AOC_MULT_TEN:
+		return PRI_AOC_MULTIPLIER_TEN;
+	case AST_AOC_MULT_HUNDRED:
+		return PRI_AOC_MULTIPLIER_HUNDRED;
+	case AST_AOC_MULT_THOUSAND:
+		return PRI_AOC_MULTIPLIER_THOUSAND;
+	default:
+		return PRI_AOC_MULTIPLIER_ONE;
+	}
+}
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+
+#if defined(HAVE_PRI_AOC_EVENTS)
+/*!
+ * \internal
+ * \brief Convert PRI_AOC_MULTIPLIER to AST_AOC_MULTIPLIER
+ * \since 1.8
+ *
+ * \return ast enum equivalent.
+ */
+static int sig_pri_aoc_multiplier_from_pri(const int mult)
+{
+	switch (mult) {
+	case PRI_AOC_MULTIPLIER_THOUSANDTH:
+		return AST_AOC_MULT_ONETHOUSANDTH;
+	case PRI_AOC_MULTIPLIER_HUNDREDTH:
+		return AST_AOC_MULT_ONEHUNDREDTH;
+	case PRI_AOC_MULTIPLIER_TENTH:
+		return AST_AOC_MULT_ONETENTH;
+	case PRI_AOC_MULTIPLIER_ONE:
+		return AST_AOC_MULT_ONE;
+	case PRI_AOC_MULTIPLIER_TEN:
+		return AST_AOC_MULT_TEN;
+	case PRI_AOC_MULTIPLIER_HUNDRED:
+		return AST_AOC_MULT_HUNDRED;
+	case PRI_AOC_MULTIPLIER_THOUSAND:
+		return AST_AOC_MULT_THOUSAND;
+	default:
+		return AST_AOC_MULT_ONE;
+	}
+}
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+
+#if defined(HAVE_PRI_AOC_EVENTS)
+/*!
+ * \internal
+ * \brief Convert ast_aoc_time_scale representation to PRI_AOC_TIME_SCALE
+ * \since 1.8
+ *
+ * \param value Value to convert to ast representation
+ *
+ * \return PRI_AOC_TIME_SCALE
+ */
+static enum PRI_AOC_TIME_SCALE sig_pri_aoc_scale_to_pri(enum ast_aoc_time_scale value)
+{
+	switch (value) {
+	default:
+	case AST_AOC_TIME_SCALE_HUNDREDTH_SECOND:
+		return PRI_AOC_TIME_SCALE_HUNDREDTH_SECOND;
+	case AST_AOC_TIME_SCALE_TENTH_SECOND:
+		return PRI_AOC_TIME_SCALE_TENTH_SECOND;
+	case AST_AOC_TIME_SCALE_SECOND:
+		return PRI_AOC_TIME_SCALE_SECOND;
+	case AST_AOC_TIME_SCALE_TEN_SECOND:
+		return PRI_AOC_TIME_SCALE_TEN_SECOND;
+	case AST_AOC_TIME_SCALE_MINUTE:
+		return PRI_AOC_TIME_SCALE_MINUTE;
+	case AST_AOC_TIME_SCALE_HOUR:
+		return PRI_AOC_TIME_SCALE_HOUR;
+	case AST_AOC_TIME_SCALE_DAY:
+		return PRI_AOC_TIME_SCALE_DAY;
+	}
+}
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+
+#if defined(HAVE_PRI_AOC_EVENTS)
+/*!
+ * \internal
+ * \brief Convert PRI_AOC_TIME_SCALE to ast aoc representation
+ * \since 1.8
+ *
+ * \param value Value to convert to ast representation
+ *
+ * \return ast aoc time scale
+ */
+static enum ast_aoc_time_scale sig_pri_aoc_scale_to_ast(enum PRI_AOC_TIME_SCALE value)
+{
+	switch (value) {
+	default:
+	case PRI_AOC_TIME_SCALE_HUNDREDTH_SECOND:
+		return AST_AOC_TIME_SCALE_HUNDREDTH_SECOND;
+	case PRI_AOC_TIME_SCALE_TENTH_SECOND:
+		return AST_AOC_TIME_SCALE_TENTH_SECOND;
+	case PRI_AOC_TIME_SCALE_SECOND:
+		return AST_AOC_TIME_SCALE_SECOND;
+	case PRI_AOC_TIME_SCALE_TEN_SECOND:
+		return AST_AOC_TIME_SCALE_TEN_SECOND;
+	case PRI_AOC_TIME_SCALE_MINUTE:
+		return AST_AOC_TIME_SCALE_MINUTE;
+	case PRI_AOC_TIME_SCALE_HOUR:
+		return AST_AOC_TIME_SCALE_HOUR;
+	case PRI_AOC_TIME_SCALE_DAY:
+		return AST_AOC_TIME_SCALE_DAY;
+	}
+	return AST_AOC_TIME_SCALE_HUNDREDTH_SECOND;
+}
+#endif	/* defined(HAVE_PRI_AOC_EVENTS) */
+
+#if defined(HAVE_PRI_AOC_EVENTS)
+/*!
+ * \internal
+ * \brief Handle AOC-S control frame
+ * \since 1.8
+ *
+ * \param aoc_s AOC-S event parameters.
+ * \param owner Asterisk channel associated with the call.
+ * \param passthrough indicating if this message should be queued on the ast channel
+ *
+ * \note Assumes the pri->lock is already obtained.
+ * \note Assumes the sig_pri private is locked
+ * \note Assumes the owner channel lock is already obtained.
+ *
+ * \return Nothing
+ */
+static void sig_pri_aoc_s_from_pri(const struct pri_subcmd_aoc_s *aoc_s, struct ast_channel *owner, int passthrough)
+{
+	struct ast_aoc_decoded *decoded = NULL;
+	struct ast_aoc_encoded *encoded = NULL;
+	size_t encoded_size = 0;
+	int idx;
+
+	if (!owner || !aoc_s) {
+		return;
+	}
+
+	if (!(decoded = ast_aoc_create(AST_AOC_S, 0, 0))) {
+		return;
+	}
+
+	for (idx = 0; idx < aoc_s->num_items; ++idx) {
+		enum ast_aoc_s_charged_item charged_item;
+
+		charged_item = sig_pri_aoc_charged_item_to_ast(aoc_s->item[idx].chargeable);
+		if (charged_item == AST_AOC_CHARGED_ITEM_NA) {
+			/* Delete the unknown charged item from the list. */
+			continue;
+		}
+		switch (aoc_s->item[idx].rate_type) {
+		case PRI_AOC_RATE_TYPE_DURATION:
+			ast_aoc_s_add_rate_duration(decoded,
+				charged_item,
+				aoc_s->item[idx].rate.duration.amount.cost,
+				sig_pri_aoc_multiplier_from_pri(aoc_s->item[idx].rate.duration.amount.multiplier),
+				aoc_s->item[idx].rate.duration.currency,
+				aoc_s->item[idx].rate.duration.time.length,

[... 2126 lines stripped ...]



More information about the asterisk-commits mailing list